1 /*
2 * tkWinWm.c --
3 *
4 * This module takes care of the interactions between a Tk-based
5 * application and the window manager. Among other things, it implements
6 * the "wm" command and passes geometry information to the window
7 * manager.
8 *
9 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
10 * Copyright (c) 1998-2000 by Scriptics Corporation.
11 *
12 * See the file "license.terms" for information on usage and redistribution of
13 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 */
15
16 #include "tkWinInt.h"
17 #include <shellapi.h>
18
19 /*
20 * These next two defines are only valid on Win2K/XP+.
21 */
22
23 #ifndef WS_EX_LAYERED
24 #define WS_EX_LAYERED 0x00080000
25 #endif
26 #ifndef LWA_COLORKEY
27 #define LWA_COLORKEY 0x00000001
28 #endif
29 #ifndef LWA_ALPHA
30 #define LWA_ALPHA 0x00000002
31 #endif
32
33 /*
34 * Event structure for synthetic activation events. These events are placed on
35 * the event queue whenever a toplevel gets a WM_MOUSEACTIVATE message or
36 * a WM_ACTIVATE. If the window is being moved (*flagPtr will be true)
37 * then the handling of this event must be delayed until the operation
38 * has completed to avoid a premature WM_EXITSIZEMOVE event.
39 */
40
41 typedef struct ActivateEvent {
42 Tcl_Event ev;
43 TkWindow *winPtr;
44 const int *flagPtr;
45 HWND hwnd;
46 } ActivateEvent;
47
48 /*
49 * A data structure of the following type holds information for each window
50 * manager protocol (such as WM_DELETE_WINDOW) for which a handler (i.e. a Tcl
51 * command) has been defined for a particular top-level window.
52 */
53
54 typedef struct ProtocolHandler {
55 Atom protocol; /* Identifies the protocol. */
56 struct ProtocolHandler *nextPtr;
57 /* Next in list of protocol handlers for the
58 * same top-level window, or NULL for end of
59 * list. */
60 Tcl_Interp *interp; /* Interpreter in which to invoke command. */
61 char command[TKFLEXARRAY]; /* Tcl command to invoke when a client message
62 * for this protocol arrives. The actual size
63 * of the structure varies to accommodate the
64 * needs of the actual command. THIS MUST BE
65 * THE LAST FIELD OF THE STRUCTURE. */
66 } ProtocolHandler;
67
68 #define HANDLER_SIZE(cmdLength) \
69 ((Tk_Offset(ProtocolHandler, command) + 1) + cmdLength)
70
71 /*
72 * Helper type passed via lParam to TkWmStackorderToplevelEnumProc
73 */
74
75 typedef struct TkWmStackorderToplevelPair {
76 Tcl_HashTable *table;
77 TkWindow **windowPtr;
78 } TkWmStackorderToplevelPair;
79
80 /*
81 * This structure represents the contents of a icon, in terms of its image.
82 * The HICON is an internal Windows format. Most of these icon-specific
83 * structures originated with the Winico extension. We stripped out unused
84 * parts of that code, and integrated the code more naturally with Tcl.
85 */
86
87 typedef struct {
88 UINT Width, Height, Colors; /* Width, Height and bpp */
89 LPBYTE lpBits; /* Ptr to DIB bits */
90 DWORD dwNumBytes; /* How many bytes? */
91 LPBITMAPINFO lpbi; /* Ptr to header */
92 LPBYTE lpXOR; /* Ptr to XOR image bits */
93 LPBYTE lpAND; /* Ptr to AND image bits */
94 HICON hIcon; /* DAS ICON */
95 } ICONIMAGE, *LPICONIMAGE;
96
97 /*
98 * This structure is how we represent a block of the above items. We will
99 * reallocate these structures according to how many images they need to
100 * contain.
101 */
102
103 typedef struct {
104 int nNumImages; /* How many images? */
105 ICONIMAGE IconImages[1]; /* Image entries */
106 } BlockOfIconImages, *BlockOfIconImagesPtr;
107
108 /*
109 * These two structures are used to read in icons from an 'icon directory'
110 * (i.e. the contents of a .icr file, say). We only use these structures
111 * temporarily, since we copy the information we want into a
112 * BlockOfIconImages.
113 */
114
115 typedef struct {
116 BYTE bWidth; /* Width of the image */
117 BYTE bHeight; /* Height of the image (times 2) */
118 BYTE bColorCount; /* Number of colors in image (0 if >=8bpp) */
119 BYTE bReserved; /* Reserved */
120 WORD wPlanes; /* Color Planes */
121 WORD wBitCount; /* Bits per pixel */
122 DWORD dwBytesInRes; /* How many bytes in this resource? */
123 DWORD dwImageOffset; /* Where in the file is this image */
124 } ICONDIRENTRY, *LPICONDIRENTRY;
125
126 typedef struct {
127 WORD idReserved; /* Reserved */
128 WORD idType; /* Resource type (1 for icons) */
129 WORD idCount; /* How many images? */
130 ICONDIRENTRY idEntries[1]; /* The entries for each image */
131 } ICONDIR, *LPICONDIR;
132
133 /*
134 * A pointer to one of these strucutures is associated with each toplevel.
135 * This allows us to free up all memory associated with icon resources when a
136 * window is deleted or if the window's icon is changed. They are simply
137 * reference counted according to:
138 *
139 * (1) How many WmInfo structures point to this object
140 * (2) Whether the ThreadSpecificData defined in this file contains a pointer
141 * to this object.
142 *
143 * The former count is for windows whose icons are individually set, and the
144 * latter is for the global default icon choice.
145 *
146 * Icons loaded from .icr/.icr use the iconBlock field, icons loaded from
147 * .exe/.dll use the hIcon field.
148 */
149
150 typedef struct WinIconInstance {
151 size_t refCount; /* Number of instances that share this data
152 * structure. */
153 BlockOfIconImagesPtr iconBlock;
154 /* Pointer to icon resource data for image */
155 } WinIconInstance;
156
157 typedef struct WinIconInstance *WinIconPtr;
158
159 /*
160 * A data structure of the following type holds window-manager-related
161 * information for each top-level window in an application.
162 */
163
164 typedef struct TkWmInfo {
165 TkWindow *winPtr; /* Pointer to main Tk information for this
166 * window. */
167 HWND wrapper; /* This is the decorative frame window created
168 * by the window manager to wrap a toplevel
169 * window. This window is a direct child of
170 * the root window. */
171 char *title; /* Title to display in window caption. If
172 * NULL, use name of widget. Malloced. */
173 char *iconName; /* Name to display in icon. Malloced. */
174 XWMHints hints; /* Various pieces of information for window
175 * manager. */
176 char *leaderName; /* Path name of leader of window group
177 * (corresponds to hints.window_group).
178 * Malloc-ed. Note: this field doesn't get
179 * updated if leader is destroyed. */
180 TkWindow *containerPtr; /* Container window for TRANSIENT_FOR property,
181 * or NULL. */
182 Tk_Window icon; /* Window to use as icon for this window, or
183 * NULL. */
184 Tk_Window iconFor; /* Window for which this window is icon, or
185 * NULL if this isn't an icon for anyone. */
186
187 /*
188 * Information used to construct an XSizeHints structure for the window
189 * manager:
190 */
191
192 int defMinWidth, defMinHeight, defMaxWidth, defMaxHeight;
193 /* Default resize limits given by system. */
194 int sizeHintsFlags; /* Flags word for XSizeHints structure. If the
195 * PBaseSize flag is set then the window is
196 * gridded; otherwise it isn't gridded. */
197 int minWidth, minHeight; /* Minimum dimensions of window, in pixels or
198 * grid units. */
199 int maxWidth, maxHeight; /* Maximum dimensions of window, in pixels or
200 * grid units. 0 to default. */
201 Tk_Window gridWin; /* Identifies the window that controls
202 * gridding for this top-level, or NULL if the
203 * top-level isn't currently gridded. */
204 int widthInc, heightInc; /* Increments for size changes (# pixels per
205 * step). */
206 struct {
207 int x; /* numerator */
208 int y; /* denominator */
209 } minAspect, maxAspect; /* Min/max aspect ratios for window. */
210 int reqGridWidth, reqGridHeight;
211 /* The dimensions of the window (in grid
212 * units) requested through the geometry
213 * manager. */
214 int gravity; /* Desired window gravity. */
215
216 /*
217 * Information used to manage the size and location of a window.
218 */
219
220 int width, height; /* Desired dimensions of window, specified in
221 * pixels or grid units. These values are set
222 * by the "wm geometry" command and by
223 * ConfigureNotify events (for when wm resizes
224 * window). -1 means user hasn't requested
225 * dimensions. */
226 int x, y; /* Desired X and Y coordinates for window.
227 * These values are set by "wm geometry", plus
228 * by ConfigureNotify events (when wm moves
229 * window). These numbers are different than
230 * the numbers stored in winPtr->changes
231 * because (a) they could be measured from the
232 * right or bottom edge of the screen (see
233 * WM_NEGATIVE_X and WM_NEGATIVE_Y flags) and
234 * (b) if the window has been reparented then
235 * they refer to the parent rather than the
236 * window itself. */
237 int borderWidth, borderHeight;
238 /* Width and height of window dressing, in
239 * pixels for the current style/exStyle. This
240 * includes the border on both sides of the
241 * window. */
242 int configX, configY; /* x,y position of toplevel when window is
243 * switched into fullscreen state, */
244 int configWidth, configHeight;
245 /* Dimensions passed to last request that we
246 * issued to change geometry of window. Used
247 * to eliminate redundant resize operations */
248 HMENU hMenu; /* the hMenu associated with this menu */
249 DWORD style, exStyle; /* Style flags for the wrapper window. */
250 LONG styleConfig; /* Extra user requested style bits */
251 LONG exStyleConfig; /* Extra user requested extended style bits */
252 Tcl_Obj *crefObj; /* COLORREF object for transparent handling */
253 COLORREF colorref; /* COLORREF for transparent handling */
254 double alpha; /* Alpha transparency level 0.0 (fully
255 * transparent) .. 1.0 (opaque) */
256
257 /*
258 * List of children of the toplevel which have private colormaps.
259 */
260
261 TkWindow **cmapList; /* Array of window with private colormaps. */
262 int cmapCount; /* Number of windows in array. */
263
264 /*
265 * Miscellaneous information.
266 */
267
268 ProtocolHandler *protPtr; /* First in list of protocol handlers for this
269 * window (NULL means none). */
270 int cmdArgc; /* Number of elements in cmdArgv below. */
271 const char **cmdArgv; /* Array of strings to store in the WM_COMMAND
272 * property. NULL means nothing available. */
273 char *clientMachine; /* String to store in WM_CLIENT_MACHINE
274 * property, or NULL. */
275 int flags; /* Miscellaneous flags, defined below. */
276 int numTransients; /* Number of transients on this window */
277 WinIconPtr iconPtr; /* Pointer to titlebar icon structure for this
278 * window, or NULL. */
279 struct TkWmInfo *nextPtr; /* Next in list of all top-level windows. */
280 } WmInfo;
281
282 /*
283 * Flag values for WmInfo structures:
284 *
285 * WM_NEVER_MAPPED - Non-zero means window has never been mapped;
286 * need to update all info when window is first
287 * mapped.
288 * WM_UPDATE_PENDING - Non-zero means a call to UpdateGeometryInfo
289 * has already been scheduled for this window;
290 * no need to schedule another one.
291 * WM_NEGATIVE_X - Non-zero means x-coordinate is measured in
292 * pixels from right edge of screen, rather than
293 * from left edge.
294 * WM_NEGATIVE_Y - Non-zero means y-coordinate is measured in
295 * pixels up from bottom of screen, rather than
296 * down from top.
297 * WM_UPDATE_SIZE_HINTS - Non-zero means that new size hints need to be
298 * propagated to window manager. Not used on Win.
299 * WM_SYNC_PENDING - Set to non-zero while waiting for the window
300 * manager to respond to some state change.
301 * WM_MOVE_PENDING - Non-zero means the application has requested a
302 * new position for the window, but it hasn't
303 * been reflected through the window manager yet.
304 * WM_COLORMAPS_EXPLICIT - Non-zero means the colormap windows were set
305 * explicitly via "wm colormapwindows".
306 * WM_ADDED_TOPLEVEL_COLORMAP - Non-zero means that when "wm colormapwindows"
307 * was called the top-level itself wasn't
308 * specified, so we added it implicitly at the
309 * end of the list.
310 * WM_WIDTH_NOT_RESIZABLE - Non-zero means that we're not supposed to
311 * allow the user to change the width of the
312 * window (controlled by "wm resizable" command).
313 * WM_HEIGHT_NOT_RESIZABLE - Non-zero means that we're not supposed to
314 * allow the user to change the height of the
315 * window (controlled by "wm resizable" command).
316 * WM_WITHDRAWN - Non-zero means that this window has explicitly
317 * been withdrawn. If it's a transient, it should
318 * not mirror state changes in the container.
319 * WM_FULLSCREEN - Non-zero means that this window has been placed
320 * in the full screen mode. It should be mapped at
321 * 0,0 and be the width and height of the screen.
322 */
323
324 #define WM_NEVER_MAPPED (1<<0)
325 #define WM_UPDATE_PENDING (1<<1)
326 #define WM_NEGATIVE_X (1<<2)
327 #define WM_NEGATIVE_Y (1<<3)
328 #define WM_UPDATE_SIZE_HINTS (1<<4)
329 #define WM_SYNC_PENDING (1<<5)
330 #define WM_CREATE_PENDING (1<<6)
331 #define WM_MOVE_PENDING (1<<7)
332 #define WM_COLORMAPS_EXPLICIT (1<<8)
333 #define WM_ADDED_TOPLEVEL_COLORMAP (1<<9)
334 #define WM_WIDTH_NOT_RESIZABLE (1<<10)
335 #define WM_HEIGHT_NOT_RESIZABLE (1<<11)
336 #define WM_WITHDRAWN (1<<12)
337 #define WM_FULLSCREEN (1<<13)
338
339 /*
340 * Window styles for various types of toplevel windows.
341 */
342
343 #define WM_OVERRIDE_STYLE (WS_CLIPCHILDREN|WS_CLIPSIBLINGS|CS_DBLCLKS)
344 #define EX_OVERRIDE_STYLE (WS_EX_TOOLWINDOW)
345
346 #define WM_FULLSCREEN_STYLE (WS_POPUP|WM_OVERRIDE_STYLE)
347 #define EX_FULLSCREEN_STYLE (WS_EX_APPWINDOW)
348
349 #define WM_TOPLEVEL_STYLE (WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|CS_DBLCLKS)
350 #define EX_TOPLEVEL_STYLE (0)
351
352 #define WM_TRANSIENT_STYLE \
353 (WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_CLIPSIBLINGS|CS_DBLCLKS)
354 #define EX_TRANSIENT_STYLE (WS_EX_DLGMODALFRAME)
355
356 /*
357 * The following structure is the official type record for geometry management
358 * of top-level windows.
359 */
360
361 static void TopLevelReqProc(void *, Tk_Window);
362 static void RemapWindows(TkWindow *winPtr, HWND parentHWND);
363
364 static const Tk_GeomMgr wmMgrType = {
365 "wm", /* name */
366 TopLevelReqProc, /* requestProc */
367 NULL, /* lostSlaveProc */
368 };
369
370 typedef struct {
371 HPALETTE systemPalette; /* System palette; refers to the currently
372 * installed foreground logical palette. */
373 TkWindow *createWindow; /* Window that is being constructed. This
374 * value is set immediately before a call to
375 * CreateWindowEx, and is used by SetLimits.
376 * This is a gross hack needed to work around
377 * Windows brain damage where it sends the
378 * WM_GETMINMAXINFO message before the
379 * WM_CREATE window. */
380 int initialized; /* Flag indicating whether thread-specific
381 * elements of module have been
382 * initialized. */
383 int firstWindow; /* Flag, cleared when the first window is
384 * mapped in a non-iconic state. */
385 WinIconPtr iconPtr; /* IconPtr being used as default for all
386 * toplevels, or NULL. */
387 } ThreadSpecificData;
388 static Tcl_ThreadDataKey dataKey;
389
390 /*
391 * The following variables cannot be placed in thread local storage because
392 * they must be shared across threads.
393 */
394
395 static int initialized; /* Flag indicating whether module has been
396 * initialized. */
397
398 TCL_DECLARE_MUTEX(winWmMutex)
399
400 /*
401 * Forward declarations for functions defined in this file:
402 */
403
404 static int ActivateWindow(Tcl_Event *evPtr, int flags);
405 static void ConfigureTopLevel(WINDOWPOS *pos);
406 static void GenerateConfigureNotify(TkWindow *winPtr);
407 static void GenerateActivateEvent(TkWindow *winPtr, const int *flagPtr);
408 static void GetMaxSize(WmInfo *wmPtr,
409 int *maxWidthPtr, int *maxHeightPtr);
410 static void GetMinSize(WmInfo *wmPtr,
411 int *minWidthPtr, int *minHeightPtr);
412 static TkWindow * GetTopLevel(HWND hwnd);
413 static void InitWm(void);
414 static int InstallColormaps(HWND hwnd, int message,
415 int isForemost);
416 static void InvalidateSubTree(TkWindow *winPtr, Colormap colormap);
417 static void InvalidateSubTreeDepth(TkWindow *winPtr);
418 static int ParseGeometry(Tcl_Interp *interp, const char *string,
419 TkWindow *winPtr);
420 static void RefreshColormap(Colormap colormap, TkDisplay *dispPtr);
421 static void SetLimits(HWND hwnd, MINMAXINFO *info);
422 static void TkWmStackorderToplevelWrapperMap(TkWindow *winPtr,
423 Display *display, Tcl_HashTable *table);
424 static LRESULT CALLBACK TopLevelProc(HWND hwnd, UINT message,
425 WPARAM wParam, LPARAM lParam);
426 static void TopLevelEventProc(ClientData clientData,
427 XEvent *eventPtr);
428 static void TopLevelReqProc(ClientData dummy, Tk_Window tkwin);
429 static void UpdateGeometryInfo(ClientData clientData);
430 static void UpdateWrapper(TkWindow *winPtr);
431 static LRESULT CALLBACK WmProc(HWND hwnd, UINT message,
432 WPARAM wParam, LPARAM lParam);
433 static void WmWaitVisibilityOrMapProc(ClientData clientData,
434 XEvent *eventPtr);
435 static BlockOfIconImagesPtr ReadIconOrCursorFromFile(Tcl_Interp *interp,
436 Tcl_Obj* fileName, BOOL isIcon);
437 static WinIconPtr ReadIconFromFile(Tcl_Interp *interp,
438 Tcl_Obj *fileName);
439 static BOOL AdjustIconImagePointers(LPICONIMAGE lpImage);
440 static WinIconPtr GetIconFromPixmap(Display *dsPtr, Pixmap pixmap);
441 static int ReadICOHeader(Tcl_Channel channel);
442 static HICON MakeIconOrCursorFromResource(LPICONIMAGE lpIcon,
443 BOOL isIcon);
444 static HICON GetIcon(WinIconPtr titlebaricon, int icon_size);
445 static int WinSetIcon(Tcl_Interp *interp,
446 WinIconPtr titlebaricon, Tk_Window tkw);
447 static void FreeIconBlock(BlockOfIconImagesPtr lpIR);
448 static void DecrIconRefCount(WinIconPtr titlebaricon);
449
450 static int WmAspectCmd(Tk_Window tkwin,
451 TkWindow *winPtr, Tcl_Interp *interp, int objc,
452 Tcl_Obj *const objv[]);
453 static int WmAttributesCmd(Tk_Window tkwin,
454 TkWindow *winPtr, Tcl_Interp *interp, int objc,
455 Tcl_Obj *const objv[]);
456 static int WmClientCmd(Tk_Window tkwin,
457 TkWindow *winPtr, Tcl_Interp *interp, int objc,
458 Tcl_Obj *const objv[]);
459 static int WmColormapwindowsCmd(Tk_Window tkwin,
460 TkWindow *winPtr, Tcl_Interp *interp, int objc,
461 Tcl_Obj *const objv[]);
462 static int WmCommandCmd(Tk_Window tkwin,
463 TkWindow *winPtr, Tcl_Interp *interp, int objc,
464 Tcl_Obj *const objv[]);
465 static int WmDeiconifyCmd(Tk_Window tkwin,
466 TkWindow *winPtr, Tcl_Interp *interp, int objc,
467 Tcl_Obj *const objv[]);
468 static int WmFocusmodelCmd(Tk_Window tkwin,
469 TkWindow *winPtr, Tcl_Interp *interp, int objc,
470 Tcl_Obj *const objv[]);
471 static int WmForgetCmd(Tk_Window tkwin,
472 TkWindow *winPtr, Tcl_Interp *interp, int objc,
473 Tcl_Obj *const objv[]);
474 static int WmFrameCmd(Tk_Window tkwin,
475 TkWindow *winPtr, Tcl_Interp *interp, int objc,
476 Tcl_Obj *const objv[]);
477 static int WmGeometryCmd(Tk_Window tkwin,
478 TkWindow *winPtr, Tcl_Interp *interp, int objc,
479 Tcl_Obj *const objv[]);
480 static int WmGridCmd(Tk_Window tkwin,
481 TkWindow *winPtr, Tcl_Interp *interp, int objc,
482 Tcl_Obj *const objv[]);
483 static int WmGroupCmd(Tk_Window tkwin,
484 TkWindow *winPtr, Tcl_Interp *interp, int objc,
485 Tcl_Obj *const objv[]);
486 static int WmIconbitmapCmd(Tk_Window tkwin,
487 TkWindow *winPtr, Tcl_Interp *interp, int objc,
488 Tcl_Obj *const objv[]);
489 static int WmIconifyCmd(Tk_Window tkwin,
490 TkWindow *winPtr, Tcl_Interp *interp, int objc,
491 Tcl_Obj *const objv[]);
492 static int WmIconmaskCmd(Tk_Window tkwin,
493 TkWindow *winPtr, Tcl_Interp *interp, int objc,
494 Tcl_Obj *const objv[]);
495 static int WmIconnameCmd(Tk_Window tkwin,
496 TkWindow *winPtr, Tcl_Interp *interp, int objc,
497 Tcl_Obj *const objv[]);
498 static int WmIconphotoCmd(Tk_Window tkwin,
499 TkWindow *winPtr, Tcl_Interp *interp, int objc,
500 Tcl_Obj *const objv[]);
501 static int WmIconpositionCmd(Tk_Window tkwin,
502 TkWindow *winPtr, Tcl_Interp *interp, int objc,
503 Tcl_Obj *const objv[]);
504 static int WmIconwindowCmd(Tk_Window tkwin,
505 TkWindow *winPtr, Tcl_Interp *interp, int objc,
506 Tcl_Obj *const objv[]);
507 static int WmManageCmd(Tk_Window tkwin,
508 TkWindow *winPtr, Tcl_Interp *interp, int objc,
509 Tcl_Obj *const objv[]);
510 static int WmMaxsizeCmd(Tk_Window tkwin,
511 TkWindow *winPtr, Tcl_Interp *interp, int objc,
512 Tcl_Obj *const objv[]);
513 static int WmMinsizeCmd(Tk_Window tkwin,
514 TkWindow *winPtr, Tcl_Interp *interp, int objc,
515 Tcl_Obj *const objv[]);
516 static int WmOverrideredirectCmd(Tk_Window tkwin,
517 TkWindow *winPtr, Tcl_Interp *interp, int objc,
518 Tcl_Obj *const objv[]);
519 static int WmPositionfromCmd(Tk_Window tkwin,
520 TkWindow *winPtr, Tcl_Interp *interp, int objc,
521 Tcl_Obj *const objv[]);
522 static int WmProtocolCmd(Tk_Window tkwin,
523 TkWindow *winPtr, Tcl_Interp *interp, int objc,
524 Tcl_Obj *const objv[]);
525 static int WmResizableCmd(Tk_Window tkwin,
526 TkWindow *winPtr, Tcl_Interp *interp, int objc,
527 Tcl_Obj *const objv[]);
528 static int WmSizefromCmd(Tk_Window tkwin,
529 TkWindow *winPtr, Tcl_Interp *interp, int objc,
530 Tcl_Obj *const objv[]);
531 static int WmStackorderCmd(Tk_Window tkwin,
532 TkWindow *winPtr, Tcl_Interp *interp, int objc,
533 Tcl_Obj *const objv[]);
534 static int WmStateCmd(Tk_Window tkwin,
535 TkWindow *winPtr, Tcl_Interp *interp, int objc,
536 Tcl_Obj *const objv[]);
537 static int WmTitleCmd(Tk_Window tkwin,
538 TkWindow *winPtr, Tcl_Interp *interp, int objc,
539 Tcl_Obj *const objv[]);
540 static int WmTransientCmd(Tk_Window tkwin,
541 TkWindow *winPtr, Tcl_Interp *interp, int objc,
542 Tcl_Obj *const objv[]);
543 static int WmWithdrawCmd(Tk_Window tkwin,
544 TkWindow *winPtr, Tcl_Interp *interp, int objc,
545 Tcl_Obj *const objv[]);
546 static void WmUpdateGeom(WmInfo *wmPtr, TkWindow *winPtr);
547
548 /*
549 * Used in BytesPerLine
550 */
551
552 #define WIDTHBYTES(bits) ((((bits) + 31)>>5)<<2)
553
554 /*
555 *----------------------------------------------------------------------
556 *
557 * DIBNumColors --
558 *
559 * Calculates the number of entries in the color table, given by LPSTR
560 * lpbi - pointer to the CF_DIB memory block. Used by titlebar icon code.
561 *
562 * Results:
563 * WORD - Number of entries in the color table.
564 *
565 *----------------------------------------------------------------------
566 */
567
568 static WORD
DIBNumColors(LPSTR lpbi)569 DIBNumColors(
570 LPSTR lpbi)
571 {
572 WORD wBitCount;
573 DWORD dwClrUsed;
574
575 dwClrUsed = ((LPBITMAPINFOHEADER) lpbi)->biClrUsed;
576
577 if (dwClrUsed) {
578 return (WORD) dwClrUsed;
579 }
580
581 wBitCount = ((LPBITMAPINFOHEADER) lpbi)->biBitCount;
582
583 switch (wBitCount) {
584 case 1:
585 return 2;
586 case 4:
587 return 16;
588 case 8:
589 return 256;
590 default:
591 return 0;
592 }
593 }
594
595 /*
596 *----------------------------------------------------------------------
597 *
598 * PaletteSize --
599 *
600 * Calculates the number of bytes in the color table, as given by LPSTR
601 * lpbi - pointer to the CF_DIB memory block. Used by titlebar icon code.
602 *
603 * Results:
604 * Number of bytes in the color table
605 *
606 *----------------------------------------------------------------------
607 */
608 static WORD
PaletteSize(LPSTR lpbi)609 PaletteSize(
610 LPSTR lpbi)
611 {
612 return (WORD) (DIBNumColors(lpbi) * sizeof(RGBQUAD));
613 }
614
615 /*
616 *----------------------------------------------------------------------
617 *
618 * FindDIBits --
619 *
620 * Locate the image bits in a CF_DIB format DIB, as given by LPSTR lpbi -
621 * pointer to the CF_DIB memory block. Used by titlebar icon code.
622 *
623 * Results:
624 * pointer to the image bits
625 *
626 * Side effects: None
627 *
628 *
629 *----------------------------------------------------------------------
630 */
631
632 static LPSTR
FindDIBBits(LPSTR lpbi)633 FindDIBBits(
634 LPSTR lpbi)
635 {
636 return lpbi + *((LPDWORD) lpbi) + PaletteSize(lpbi);
637 }
638
639 /*
640 *----------------------------------------------------------------------
641 *
642 * BytesPerLine --
643 *
644 * Calculates the number of bytes in one scan line, as given by
645 * LPBITMAPINFOHEADER lpBMIH - pointer to the BITMAPINFOHEADER that
646 * begins the CF_DIB block. Used by titlebar icon code.
647 *
648 * Results:
649 * number of bytes in one scan line (DWORD aligned)
650 *
651 *----------------------------------------------------------------------
652 */
653
654 static DWORD
BytesPerLine(LPBITMAPINFOHEADER lpBMIH)655 BytesPerLine(
656 LPBITMAPINFOHEADER lpBMIH)
657 {
658 return WIDTHBYTES(lpBMIH->biWidth * lpBMIH->biPlanes * lpBMIH->biBitCount);
659 }
660
661 /*
662 *----------------------------------------------------------------------
663 *
664 * AdjustIconImagePointers --
665 *
666 * Adjusts internal pointers in icon resource struct, as given by
667 * LPICONIMAGE lpImage - the resource to handle. Used by titlebar icon
668 * code.
669 *
670 * Results:
671 * BOOL - TRUE for success, FALSE for failure
672 *
673 *----------------------------------------------------------------------
674 */
675
676 static BOOL
AdjustIconImagePointers(LPICONIMAGE lpImage)677 AdjustIconImagePointers(
678 LPICONIMAGE lpImage)
679 {
680 /*
681 * Sanity check.
682 */
683
684 if (lpImage == NULL) {
685 return FALSE;
686 }
687
688 /*
689 * BITMAPINFO is at beginning of bits.
690 */
691
692 lpImage->lpbi = (LPBITMAPINFO) lpImage->lpBits;
693
694 /*
695 * Width - simple enough.
696 */
697
698 lpImage->Width = lpImage->lpbi->bmiHeader.biWidth;
699
700 /*
701 * Icons are stored in funky format where height is doubled so account for
702 * that.
703 */
704
705 lpImage->Height = (lpImage->lpbi->bmiHeader.biHeight)/2;
706
707 /*
708 * How many colors?
709 */
710
711 lpImage->Colors = lpImage->lpbi->bmiHeader.biPlanes
712 * lpImage->lpbi->bmiHeader.biBitCount;
713
714 /*
715 * XOR bits follow the header and color table.
716 */
717
718 lpImage->lpXOR = (LPBYTE) FindDIBBits((LPSTR) lpImage->lpbi);
719
720 /*
721 * AND bits follow the XOR bits.
722 */
723
724 lpImage->lpAND = lpImage->lpXOR +
725 lpImage->Height*BytesPerLine((LPBITMAPINFOHEADER) lpImage->lpbi);
726 return TRUE;
727 }
728
729 /*
730 *----------------------------------------------------------------------
731 *
732 * MakeIconOrCursorFromResource --
733 *
734 * Construct an actual HICON structure from the information in a
735 * resource.
736 *
737 * Results:
738 * Icon
739 *
740 *----------------------------------------------------------------------
741 */
742
743 static HICON
MakeIconOrCursorFromResource(LPICONIMAGE lpIcon,BOOL isIcon)744 MakeIconOrCursorFromResource(
745 LPICONIMAGE lpIcon,
746 BOOL isIcon)
747 {
748 HICON hIcon;
749
750 /*
751 * Sanity Check
752 */
753
754 if (lpIcon == NULL || lpIcon->lpBits == NULL) {
755 return NULL;
756 }
757
758 /*
759 * Let the OS do the real work :)
760 */
761
762 hIcon = (HICON) CreateIconFromResourceEx(lpIcon->lpBits,
763 lpIcon->dwNumBytes, isIcon, 0x00030000,
764 (*(LPBITMAPINFOHEADER) lpIcon->lpBits).biWidth,
765 (*(LPBITMAPINFOHEADER) lpIcon->lpBits).biHeight/2, 0);
766
767 /*
768 * It failed, odds are good we're on NT so try the non-Ex way.
769 */
770
771 if (hIcon == NULL) {
772 /*
773 * We would break on NT if we try with a 16bpp image.
774 */
775
776 if (lpIcon->lpbi->bmiHeader.biBitCount != 16) {
777 hIcon = CreateIconFromResource(lpIcon->lpBits, lpIcon->dwNumBytes,
778 isIcon, 0x00030000);
779 }
780 }
781 return hIcon;
782 }
783
784 /*
785 *----------------------------------------------------------------------
786 *
787 * ReadICOHeader --
788 *
789 * Reads the header from an ICO file, as specfied by channel.
790 *
791 * Results:
792 * UINT - Number of images in file, -1 for failure. If this succeeds,
793 * there is a decent chance this is a valid icon file.
794 *
795 *----------------------------------------------------------------------
796 */
797
798 static int
ReadICOHeader(Tcl_Channel channel)799 ReadICOHeader(
800 Tcl_Channel channel)
801 {
802 union {
803 WORD word;
804 char bytes[sizeof(WORD)];
805 } input;
806
807 /*
808 * Read the 'reserved' WORD, which should be a zero word.
809 */
810
811 if (Tcl_Read(channel, input.bytes, sizeof(WORD)) != sizeof(WORD)) {
812 return -1;
813 }
814 if (input.word != 0) {
815 return -1;
816 }
817
818 /*
819 * Read the type WORD, which should be of type 1.
820 */
821
822 if (Tcl_Read(channel, input.bytes, sizeof(WORD)) != sizeof(WORD)) {
823 return -1;
824 }
825 if (input.word != 1) {
826 return -1;
827 }
828
829 /*
830 * Get and return the count of images.
831 */
832
833 if (Tcl_Read(channel, input.bytes, sizeof(WORD)) != sizeof(WORD)) {
834 return -1;
835 }
836 return (int) input.word;
837 }
838
839 /*
840 *----------------------------------------------------------------------
841 *
842 * InitWindowClass --
843 *
844 * This routine creates the Wm toplevel decorative frame class.
845 *
846 * Results:
847 * None.
848 *
849 * Side effects:
850 * Registers a new window class.
851 *
852 *----------------------------------------------------------------------
853 */
854
855 static int
InitWindowClass(WinIconPtr titlebaricon)856 InitWindowClass(
857 WinIconPtr titlebaricon)
858 {
859 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
860 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
861
862 if (!tsdPtr->initialized) {
863 tsdPtr->initialized = 1;
864 tsdPtr->firstWindow = 1;
865 tsdPtr->iconPtr = NULL;
866 }
867 if (!initialized) {
868 Tcl_MutexLock(&winWmMutex);
869 if (!initialized) {
870 WNDCLASSW windowClass;
871
872 initialized = 1;
873
874 ZeroMemory(&windowClass, sizeof(WNDCLASSW));
875
876 windowClass.style = CS_HREDRAW | CS_VREDRAW;
877 windowClass.hInstance = Tk_GetHINSTANCE();
878 windowClass.lpszClassName = TK_WIN_TOPLEVEL_CLASS_NAME;
879 windowClass.lpfnWndProc = WmProc;
880 if (titlebaricon == NULL) {
881 windowClass.hIcon = LoadIconW(Tk_GetHINSTANCE(), L"tk");
882 } else {
883 windowClass.hIcon = GetIcon(titlebaricon, ICON_BIG);
884 if (windowClass.hIcon == NULL) {
885 return TCL_ERROR;
886 }
887
888 /*
889 * Store pointer to default icon so we know when we need to
890 * free that information
891 */
892
893 tsdPtr->iconPtr = titlebaricon;
894 }
895 windowClass.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
896
897 if (!RegisterClassW(&windowClass)) {
898 Tcl_Panic("Unable to register TkTopLevel class");
899 }
900 }
901 Tcl_MutexUnlock(&winWmMutex);
902 }
903 return TCL_OK;
904 }
905
906 /*
907 *----------------------------------------------------------------------
908 *
909 * InitWm --
910 *
911 * This initialises the window manager
912 *
913 * Results:
914 * None.
915 *
916 * Side effects:
917 * Registers a new window class.
918 *
919 *----------------------------------------------------------------------
920 */
921
922 static void
InitWm(void)923 InitWm(void)
924 {
925 /* Ignore return result */
926 (void) InitWindowClass(NULL);
927 }
928
929 /*
930 *----------------------------------------------------------------------
931 *
932 * WinSetIcon --
933 *
934 * Sets either the default toplevel titlebar icon, or the icon for a
935 * specific toplevel (if tkw is given, then only that window is used).
936 *
937 * The ref-count of the titlebaricon is NOT changed. If this function
938 * returns successfully, the caller should assume the icon was used (and
939 * therefore the ref-count should be adjusted to reflect that fact). If
940 * the function returned an error, the caller should assume the icon was
941 * not used (and may wish to free the memory associated with it).
942 *
943 * Results:
944 * A standard Tcl return code.
945 *
946 * Side effects:
947 * One or all windows may have their icon changed. The Tcl result may be
948 * modified. The window-manager will be initialised if it wasn't already.
949 * The given window will be forced into existence.
950 *
951 *----------------------------------------------------------------------
952 */
953
954 static int
WinSetIcon(Tcl_Interp * interp,WinIconPtr titlebaricon,Tk_Window tkw)955 WinSetIcon(
956 Tcl_Interp *interp,
957 WinIconPtr titlebaricon,
958 Tk_Window tkw)
959 {
960 WmInfo *wmPtr;
961 HWND hwnd;
962 int application = 0;
963
964 if (tkw == NULL) {
965 tkw = Tk_MainWindow(interp);
966 application = 1;
967 }
968
969 if (!(Tk_IsTopLevel(tkw))) {
970 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
971 "window \"%s\" isn't a top-level window", Tk_PathName(tkw)));
972 Tcl_SetErrorCode(interp, "TK", "LOOKUP", "TOPLEVEL", Tk_PathName(tkw),
973 NULL);
974 return TCL_ERROR;
975 }
976 if (Tk_WindowId(tkw) == None) {
977 Tk_MakeWindowExist(tkw);
978 }
979
980 /*
981 * We must get the window's wrapper, not the window itself.
982 */
983
984 wmPtr = ((TkWindow *) tkw)->wmInfoPtr;
985 hwnd = wmPtr->wrapper;
986
987 if (application) {
988 if (hwnd == NULL) {
989 /*
990 * I don't actually think this is ever the correct thing, unless
991 * perhaps the window doesn't have a wrapper. But I believe all
992 * windows have wrappers.
993 */
994
995 hwnd = Tk_GetHWND(Tk_WindowId(tkw));
996 }
997
998 /*
999 * If we aren't initialised, then just initialise with the user's
1000 * icon. Otherwise our icon choice will be ignored moments later when
1001 * Tk finishes initialising.
1002 */
1003
1004 if (!initialized) {
1005 if (InitWindowClass(titlebaricon) != TCL_OK) {
1006 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1007 "Unable to set icon", -1));
1008 Tcl_SetErrorCode(interp, "TK", "WM", "ICON", "FAILED", NULL);
1009 return TCL_ERROR;
1010 }
1011 } else {
1012 ThreadSpecificData *tsdPtr;
1013
1014 /*
1015 * Don't check return result of SetClassLong() or
1016 * SetClassLongPtrW() since they return the previously set value
1017 * which is zero on the initial call or in an error case. The MSDN
1018 * documentation does not indicate that the result needs to be
1019 * checked.
1020 */
1021
1022 SetClassLongPtrW(hwnd, GCLP_HICONSM,
1023 (LPARAM) GetIcon(titlebaricon, ICON_SMALL));
1024 SetClassLongPtrW(hwnd, GCLP_HICON,
1025 (LPARAM) GetIcon(titlebaricon, ICON_BIG));
1026 tsdPtr = (ThreadSpecificData *)
1027 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1028 if (tsdPtr->iconPtr != NULL) {
1029 DecrIconRefCount(tsdPtr->iconPtr);
1030 }
1031 tsdPtr->iconPtr = titlebaricon;
1032 }
1033 } else {
1034 if (!initialized) {
1035 /*
1036 * Need to initialise the wm otherwise we will fail on code which
1037 * tries to set a toplevel's icon before that happens. Ignore
1038 * return result.
1039 */
1040
1041 (void) InitWindowClass(NULL);
1042 }
1043
1044 /*
1045 * The following code is exercised if you do
1046 *
1047 * toplevel .t ; wm titlebaricon .t foo.icr
1048 *
1049 * i.e. the wm hasn't had time to properly create the '.t' window
1050 * before you set the icon.
1051 */
1052
1053 if (hwnd == NULL) {
1054 /*
1055 * This little snippet is copied from the 'Map' function, and
1056 * should probably be placed in one proper location.
1057 */
1058
1059 UpdateWrapper(wmPtr->winPtr);
1060 wmPtr = ((TkWindow *) tkw)->wmInfoPtr;
1061 hwnd = wmPtr->wrapper;
1062 if (hwnd == NULL) {
1063 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1064 "Can't set icon; window has no wrapper.", -1));
1065 Tcl_SetErrorCode(interp, "TK", "WM", "ICON", "WRAPPER", NULL);
1066 return TCL_ERROR;
1067 }
1068 }
1069 SendMessageW(hwnd, WM_SETICON, ICON_SMALL,
1070 (LPARAM) GetIcon(titlebaricon, ICON_SMALL));
1071 SendMessageW(hwnd, WM_SETICON, ICON_BIG,
1072 (LPARAM) GetIcon(titlebaricon, ICON_BIG));
1073
1074 /*
1075 * Update the iconPtr we keep for each WmInfo structure.
1076 */
1077
1078 if (wmPtr->iconPtr != NULL) {
1079 /*
1080 * Free any old icon ptr which is associated with this window.
1081 */
1082
1083 DecrIconRefCount(wmPtr->iconPtr);
1084 }
1085
1086 /*
1087 * We do not need to increment the ref count for the titlebaricon,
1088 * because it was already incremented when we retrieved it.
1089 */
1090
1091 wmPtr->iconPtr = titlebaricon;
1092 }
1093 return TCL_OK;
1094 }
1095
1096 /*
1097 *----------------------------------------------------------------------
1098 *
1099 * TkWinGetIcon --
1100 *
1101 * Gets either the default toplevel titlebar icon, or the icon for a
1102 * specific toplevel (ICON_SMALL or ICON_BIG).
1103 *
1104 * Results:
1105 * A Windows HICON.
1106 *
1107 * Side effects:
1108 * The given window will be forced into existence.
1109 *
1110 *----------------------------------------------------------------------
1111 */
1112
1113 HICON
TkWinGetIcon(Tk_Window tkwin,DWORD iconsize)1114 TkWinGetIcon(
1115 Tk_Window tkwin,
1116 DWORD iconsize)
1117 {
1118 WmInfo *wmPtr;
1119 HICON icon;
1120 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1121 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1122
1123 if (tsdPtr->iconPtr != NULL) {
1124 /*
1125 * return default toplevel icon
1126 */
1127
1128 return GetIcon(tsdPtr->iconPtr, (int) iconsize);
1129 }
1130
1131 /*
1132 * Ensure we operate on the toplevel, that has the icon refs.
1133 */
1134
1135 while (!Tk_IsTopLevel(tkwin)) {
1136 tkwin = Tk_Parent(tkwin);
1137 if (tkwin == NULL) {
1138 return NULL;
1139 }
1140 }
1141
1142 if (Tk_WindowId(tkwin) == None) {
1143 Tk_MakeWindowExist(tkwin);
1144 }
1145
1146 wmPtr = ((TkWindow *) tkwin)->wmInfoPtr;
1147 if (wmPtr->iconPtr != NULL) {
1148 /*
1149 * return window toplevel icon
1150 */
1151
1152 return GetIcon(wmPtr->iconPtr, (int) iconsize);
1153 }
1154
1155 /*
1156 * Find the icon otherwise associated with the toplevel, or finally with
1157 * the window class.
1158 */
1159
1160 icon = (HICON) SendMessageW(wmPtr->wrapper, WM_GETICON, iconsize,
1161 (LPARAM) NULL);
1162 if (icon == (HICON) NULL) {
1163 icon = (HICON) GetClassLongPtrW(wmPtr->wrapper,
1164 (iconsize == ICON_BIG) ? GCLP_HICON : GCLP_HICONSM);
1165 }
1166 return icon;
1167 }
1168
1169 /*
1170 *----------------------------------------------------------------------
1171 *
1172 * ReadIconFromFile --
1173 *
1174 * Read the contents of a file (usually .ico, .icr) and extract an icon
1175 * resource, if possible, otherwise check if the shell has an icon
1176 * assigned to the given file and use that. If both of those fail, then
1177 * NULL is returned, and an error message will already be in the
1178 * interpreter.
1179 *
1180 * Results:
1181 * A WinIconPtr structure containing the icons in the file, with its ref
1182 * count already incremented. The calling function should either place
1183 * this structure inside a WmInfo structure, or it should pass it on to
1184 * DecrIconRefCount() to ensure no memory leaks occur.
1185 *
1186 * If the given fileName did not contain a valid icon structure,
1187 * return NULL.
1188 *
1189 * Side effects:
1190 * Memory is allocated for the returned structure and the icons it
1191 * contains. If the structure is not wanted, it should be passed to
1192 * DecrIconRefCount, and in any case a valid ref count should be ensured
1193 * to avoid memory leaks.
1194 *
1195 * Currently icon resources are not shared, so the ref count of one of
1196 * these structures will always be 0 or 1. However all we need do is
1197 * implement some sort of lookup function between filenames and
1198 * WinIconPtr structures and no other code will need to be changed. The
1199 * pseudo-code for this is implemented below in the 'if (0)' branch. It
1200 * did not seem necessary to implement this optimisation here, since
1201 * moving to icon<->image conversions will probably make it obsolete.
1202 *
1203 *----------------------------------------------------------------------
1204 */
1205
1206 static WinIconPtr
ReadIconFromFile(Tcl_Interp * interp,Tcl_Obj * fileName)1207 ReadIconFromFile(
1208 Tcl_Interp *interp,
1209 Tcl_Obj *fileName)
1210 {
1211 WinIconPtr titlebaricon = NULL;
1212 BlockOfIconImagesPtr lpIR;
1213
1214 #if 0 /* TODO: Dead code? */
1215 if (0 /* If we already have an icon for this filename */) {
1216 titlebaricon = NULL; /* Get the real value from a lookup */
1217 titlebaricon->refCount++;
1218 return titlebaricon;
1219 }
1220 #endif
1221
1222 /*
1223 * First check if it is a .ico file.
1224 */
1225
1226 lpIR = ReadIconOrCursorFromFile(interp, fileName, TRUE);
1227
1228 /*
1229 * Then see if we can ask the shell for the icon for this file. We
1230 * want both the regular and small icons so that the Alt-Tab (task-
1231 * switching) display uses the right icon.
1232 */
1233
1234 if (lpIR == NULL) {
1235 SHFILEINFOW sfiSM;
1236 Tcl_DString ds, ds2;
1237 DWORD *res;
1238 const char *file;
1239
1240 file = Tcl_TranslateFileName(interp, Tcl_GetString(fileName), &ds);
1241 if (file == NULL) {
1242 return NULL;
1243 }
1244 Tcl_DStringInit(&ds2);
1245 res = (DWORD *)SHGetFileInfoW(Tcl_UtfToWCharDString(file, -1, &ds2), 0, &sfiSM,
1246 sizeof(SHFILEINFO), SHGFI_SMALLICON|SHGFI_ICON);
1247 Tcl_DStringFree(&ds);
1248
1249 if (res != 0) {
1250 SHFILEINFOW sfi;
1251 unsigned size;
1252
1253 Tcl_ResetResult(interp);
1254 res = (DWORD *)SHGetFileInfoW((WCHAR *)Tcl_DStringValue(&ds2), 0, &sfi,
1255 sizeof(SHFILEINFO), SHGFI_ICON);
1256
1257 /*
1258 * Account for extra icon, if necessary.
1259 */
1260
1261 size = sizeof(BlockOfIconImages)
1262 + ((res != 0) ? sizeof(ICONIMAGE) : 0);
1263 lpIR = (BlockOfIconImagesPtr)ckalloc(size);
1264 if (lpIR == NULL) {
1265 if (res != 0) {
1266 DestroyIcon(sfi.hIcon);
1267 }
1268 DestroyIcon(sfiSM.hIcon);
1269 Tcl_DStringFree(&ds2);
1270 return NULL;
1271 }
1272 ZeroMemory(lpIR, size);
1273
1274 lpIR->nNumImages = ((res != 0) ? 2 : 1);
1275 lpIR->IconImages[0].Width = 16;
1276 lpIR->IconImages[0].Height = 16;
1277 lpIR->IconImages[0].Colors = 4;
1278 lpIR->IconImages[0].hIcon = sfiSM.hIcon;
1279
1280 /*
1281 * All other IconImages fields are ignored.
1282 */
1283
1284 if (res != 0) {
1285 lpIR->IconImages[1].Width = 32;
1286 lpIR->IconImages[1].Height = 32;
1287 lpIR->IconImages[1].Colors = 4;
1288 lpIR->IconImages[1].hIcon = sfi.hIcon;
1289 }
1290 }
1291 Tcl_DStringFree(&ds2);
1292 }
1293 if (lpIR != NULL) {
1294 titlebaricon = (WinIconPtr)ckalloc(sizeof(WinIconInstance));
1295 titlebaricon->iconBlock = lpIR;
1296 titlebaricon->refCount = 1;
1297 }
1298 return titlebaricon;
1299 }
1300
1301 /*
1302 *----------------------------------------------------------------------
1303 *
1304 * GetIconFromPixmap --
1305 *
1306 * Turn a Tk Pixmap (i.e. a bitmap) into an icon resource, if possible,
1307 * otherwise NULL is returned.
1308 *
1309 * Results:
1310 * A WinIconPtr structure containing a conversion of the given bitmap
1311 * into an icon, with its ref count already incremented. The calling
1312 * function should either place this structure inside a WmInfo structure,
1313 * or it should pass it on to DecrIconRefCount() to ensure no memory
1314 * leaks occur.
1315 *
1316 * If the given pixmap did not contain a valid icon structure, return
1317 * NULL.
1318 *
1319 * Side effects:
1320 * Memory is allocated for the returned structure and the icons it
1321 * contains. If the structure is not wanted, it should be passed to
1322 * DecrIconRefCount, and in any case a valid ref count should be ensured
1323 * to avoid memory leaks.
1324 *
1325 * Currently icon resources are not shared, so the ref count of one of
1326 * these structures will always be 0 or 1. However all we need do is
1327 * implement some sort of lookup function between pixmaps and WinIconPtr
1328 * structures and no other code will need to be changed.
1329 *
1330 *----------------------------------------------------------------------
1331 */
1332
1333 static WinIconPtr
GetIconFromPixmap(Display * dsPtr,Pixmap pixmap)1334 GetIconFromPixmap(
1335 Display *dsPtr,
1336 Pixmap pixmap)
1337 {
1338 WinIconPtr titlebaricon = NULL;
1339 TkWinDrawable *twdPtr = (TkWinDrawable *) pixmap;
1340 BlockOfIconImagesPtr lpIR;
1341 ICONINFO icon;
1342 HICON hIcon;
1343 int width, height;
1344
1345 if (twdPtr == NULL) {
1346 return NULL;
1347 }
1348
1349 #if 0 /* TODO: Dead code?*/
1350 if (0 /* If we already have an icon for this pixmap */) {
1351 titlebaricon = NULL; /* Get the real value from a lookup */
1352 titlebaricon->refCount++;
1353 return titlebaricon;
1354 }
1355 #endif
1356
1357 Tk_SizeOfBitmap(dsPtr, pixmap, &width, &height);
1358
1359 icon.fIcon = TRUE;
1360 icon.xHotspot = 0;
1361 icon.yHotspot = 0;
1362 icon.hbmMask = twdPtr->bitmap.handle;
1363 icon.hbmColor = twdPtr->bitmap.handle;
1364
1365 hIcon = CreateIconIndirect(&icon);
1366 if (hIcon == NULL) {
1367 return NULL;
1368 }
1369
1370 lpIR = (BlockOfIconImagesPtr)ckalloc(sizeof(BlockOfIconImages));
1371 if (lpIR == NULL) {
1372 DestroyIcon(hIcon);
1373 return NULL;
1374 }
1375
1376 lpIR->nNumImages = 1;
1377 lpIR->IconImages[0].Width = width;
1378 lpIR->IconImages[0].Height = height;
1379 lpIR->IconImages[0].Colors = 1 << twdPtr->bitmap.depth;
1380 lpIR->IconImages[0].hIcon = hIcon;
1381
1382 /*
1383 * These fields are ignored.
1384 */
1385
1386 lpIR->IconImages[0].lpBits = 0;
1387 lpIR->IconImages[0].dwNumBytes = 0;
1388 lpIR->IconImages[0].lpXOR = 0;
1389 lpIR->IconImages[0].lpAND = 0;
1390
1391 titlebaricon = (WinIconPtr)ckalloc(sizeof(WinIconInstance));
1392 titlebaricon->iconBlock = lpIR;
1393 titlebaricon->refCount = 1;
1394 return titlebaricon;
1395 }
1396
1397 /*
1398 *----------------------------------------------------------------------
1399 *
1400 * DecrIconRefCount --
1401 *
1402 * Reduces the reference count.
1403 *
1404 * Results:
1405 * None.
1406 *
1407 * Side effects:
1408 * If the ref count falls to zero, free the memory associated with the
1409 * icon resource structures. In this case the pointer passed into this
1410 * function is no longer valid.
1411 *
1412 *----------------------------------------------------------------------
1413 */
1414
1415 static void
DecrIconRefCount(WinIconPtr titlebaricon)1416 DecrIconRefCount(
1417 WinIconPtr titlebaricon)
1418 {
1419 if (titlebaricon->refCount-- <= 1) {
1420 if (titlebaricon->iconBlock != NULL) {
1421 FreeIconBlock(titlebaricon->iconBlock);
1422 }
1423 titlebaricon->iconBlock = NULL;
1424
1425 ckfree(titlebaricon);
1426 }
1427 }
1428
1429 /*
1430 *----------------------------------------------------------------------
1431 *
1432 * FreeIconBlock --
1433 *
1434 * Frees all memory associated with a previously loaded titlebaricon.
1435 * The icon block pointer is no longer valid once this function returns.
1436 *
1437 * Results:
1438 * None.
1439 *
1440 * Side effects:
1441 *
1442 *
1443 *----------------------------------------------------------------------
1444 */
1445
1446 static void
FreeIconBlock(BlockOfIconImagesPtr lpIR)1447 FreeIconBlock(
1448 BlockOfIconImagesPtr lpIR)
1449 {
1450 int i;
1451
1452 /*
1453 * Free all the bits.
1454 */
1455
1456 for (i=0 ; i<lpIR->nNumImages ; i++) {
1457 if (lpIR->IconImages[i].lpBits != NULL) {
1458 ckfree(lpIR->IconImages[i].lpBits);
1459 }
1460 if (lpIR->IconImages[i].hIcon != NULL) {
1461 DestroyIcon(lpIR->IconImages[i].hIcon);
1462 }
1463 }
1464 ckfree(lpIR);
1465 }
1466
1467 /*
1468 *----------------------------------------------------------------------
1469 *
1470 * GetIcon --
1471 *
1472 * Extracts an icon of a given size from an icon resource
1473 *
1474 * Results:
1475 * Returns the icon, if found, else NULL.
1476 *
1477 *----------------------------------------------------------------------
1478 */
1479
1480 static HICON
GetIcon(WinIconPtr titlebaricon,int icon_size)1481 GetIcon(
1482 WinIconPtr titlebaricon,
1483 int icon_size)
1484 {
1485 BlockOfIconImagesPtr lpIR;
1486 unsigned int size = (icon_size == 0 ? 16 : 32);
1487 int i;
1488
1489 if (titlebaricon == NULL) {
1490 return NULL;
1491 }
1492
1493 lpIR = titlebaricon->iconBlock;
1494 if (lpIR == NULL) {
1495 return NULL;
1496 }
1497
1498 for (i=0 ; i<lpIR->nNumImages ; i++) {
1499 /*
1500 * Take the first or a 32x32 16 color icon
1501 */
1502
1503 if ((lpIR->IconImages[i].Height == size)
1504 && (lpIR->IconImages[i].Width == size)
1505 && (lpIR->IconImages[i].Colors >= 4)) {
1506 return lpIR->IconImages[i].hIcon;
1507 }
1508 }
1509
1510 /*
1511 * If we get here, then just return the first one, it will have to do!
1512 */
1513
1514 if (lpIR->nNumImages >= 1) {
1515 return lpIR->IconImages[0].hIcon;
1516 }
1517 return NULL;
1518 }
1519
1520 #if 0 /* UNUSED */
1521 static HCURSOR
1522 TclWinReadCursorFromFile(
1523 Tcl_Interp* interp,
1524 Tcl_Obj* fileName)
1525 {
1526 BlockOfIconImagesPtr lpIR;
1527 HICON res = NULL;
1528
1529 lpIR = ReadIconOrCursorFromFile(interp, fileName, FALSE);
1530 if (lpIR == NULL) {
1531 return NULL;
1532 }
1533 if (lpIR->nNumImages >= 1) {
1534 res = CopyImage(lpIR->IconImages[0].hIcon, IMAGE_CURSOR, 0, 0, 0);
1535 }
1536 FreeIconBlock(lpIR);
1537 return res;
1538 }
1539 #endif
1540
1541 /*
1542 *----------------------------------------------------------------------
1543 *
1544 * ReadIconOrCursorFromFile --
1545 *
1546 * Reads an Icon Resource from an ICO file, as given by char* fileName -
1547 * Name of the ICO file. This name should be in Utf format.
1548 *
1549 * Results:
1550 * Returns an icon resource, if found, else NULL.
1551 *
1552 * Side effects:
1553 * May leave error messages in the Tcl interpreter.
1554 *
1555 *----------------------------------------------------------------------
1556 */
1557
1558 static BlockOfIconImagesPtr
ReadIconOrCursorFromFile(Tcl_Interp * interp,Tcl_Obj * fileName,BOOL isIcon)1559 ReadIconOrCursorFromFile(
1560 Tcl_Interp *interp,
1561 Tcl_Obj *fileName,
1562 BOOL isIcon)
1563 {
1564 BlockOfIconImagesPtr lpIR;
1565 Tcl_Channel channel;
1566 int i;
1567 DWORD dwBytesRead;
1568 LPICONDIRENTRY lpIDE;
1569
1570 /*
1571 * Open the file.
1572 */
1573
1574 channel = Tcl_FSOpenFileChannel(interp, fileName, "r", 0);
1575 if (channel == NULL) {
1576 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1577 "error opening file \"%s\" for reading: %s",
1578 Tcl_GetString(fileName), Tcl_PosixError(interp)));
1579 return NULL;
1580 }
1581 if (Tcl_SetChannelOption(interp, channel, "-translation", "binary")
1582 != TCL_OK) {
1583 Tcl_Close(NULL, channel);
1584 return NULL;
1585 }
1586 if (Tcl_SetChannelOption(interp, channel, "-encoding", "binary")
1587 != TCL_OK) {
1588 Tcl_Close(NULL, channel);
1589 return NULL;
1590 }
1591
1592 /*
1593 * Allocate memory for the resource structure
1594 */
1595
1596 lpIR = (BlockOfIconImagesPtr)ckalloc(sizeof(BlockOfIconImages));
1597
1598 /*
1599 * Read in the header
1600 */
1601
1602 lpIR->nNumImages = ReadICOHeader(channel);
1603 if (lpIR->nNumImages == -1) {
1604 Tcl_SetObjResult(interp, Tcl_NewStringObj("Invalid file header", -1));
1605 Tcl_Close(NULL, channel);
1606 ckfree(lpIR);
1607 return NULL;
1608 }
1609
1610 /*
1611 * Adjust the size of the struct to account for the images.
1612 */
1613
1614 lpIR = (BlockOfIconImagesPtr)ckrealloc(lpIR, sizeof(BlockOfIconImages)
1615 + (lpIR->nNumImages - 1) * sizeof(ICONIMAGE));
1616
1617 /*
1618 * Allocate enough memory for the icon directory entries.
1619 */
1620
1621 lpIDE = (LPICONDIRENTRY)ckalloc(lpIR->nNumImages * sizeof(ICONDIRENTRY));
1622
1623 /*
1624 * Read in the icon directory entries.
1625 */
1626
1627 dwBytesRead = Tcl_Read(channel, (char *) lpIDE,
1628 (int) (lpIR->nNumImages * sizeof(ICONDIRENTRY)));
1629 if (dwBytesRead != lpIR->nNumImages * sizeof(ICONDIRENTRY)) {
1630 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1631 "error reading file: %s", Tcl_PosixError(interp)));
1632 Tcl_SetErrorCode(interp, "TK", "WM", "ICON", "READ", NULL);
1633 Tcl_Close(NULL, channel);
1634 ckfree(lpIDE);
1635 ckfree(lpIR);
1636 return NULL;
1637 }
1638
1639 /*
1640 * NULL-out everything to make memory management easier.
1641 */
1642
1643 for (i = 0; i < lpIR->nNumImages; i++) {
1644 lpIR->IconImages[i].lpBits = NULL;
1645 }
1646
1647 /*
1648 * Loop through and read in each image.
1649 */
1650
1651 for (i=0 ; i<lpIR->nNumImages ; i++) {
1652 /*
1653 * Allocate memory for the resource.
1654 */
1655
1656 lpIR->IconImages[i].lpBits = (LPBYTE)ckalloc(lpIDE[i].dwBytesInRes);
1657 lpIR->IconImages[i].dwNumBytes = lpIDE[i].dwBytesInRes;
1658
1659 /*
1660 * Seek to beginning of this image.
1661 */
1662
1663 if (Tcl_Seek(channel, lpIDE[i].dwImageOffset, FILE_BEGIN) == -1) {
1664 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1665 "error seeking in file: %s", Tcl_PosixError(interp)));
1666 goto readError;
1667 }
1668
1669 /*
1670 * Read it in.
1671 */
1672
1673 dwBytesRead = Tcl_Read(channel, (char *)lpIR->IconImages[i].lpBits,
1674 (int) lpIDE[i].dwBytesInRes);
1675 if (dwBytesRead != lpIDE[i].dwBytesInRes) {
1676 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1677 "error reading file: %s", Tcl_PosixError(interp)));
1678 goto readError;
1679 }
1680
1681 /*
1682 * Set the internal pointers appropriately.
1683 */
1684
1685 if (!AdjustIconImagePointers(&lpIR->IconImages[i])) {
1686 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1687 "Error converting to internal format", -1));
1688 Tcl_SetErrorCode(interp, "TK", "WM", "ICON", "FORMAT", NULL);
1689 goto readError;
1690 }
1691 lpIR->IconImages[i].hIcon =
1692 MakeIconOrCursorFromResource(&lpIR->IconImages[i], isIcon);
1693 }
1694
1695 /*
1696 * Clean up
1697 */
1698
1699 ckfree(lpIDE);
1700 Tcl_Close(NULL, channel);
1701 return lpIR;
1702
1703 readError:
1704 Tcl_Close(NULL, channel);
1705 for (i = 0; i < lpIR->nNumImages; i++) {
1706 if (lpIR->IconImages[i].lpBits != NULL) {
1707 ckfree(lpIR->IconImages[i].lpBits);
1708 }
1709 }
1710 ckfree(lpIDE);
1711 ckfree(lpIR);
1712 return NULL;
1713 }
1714
1715 /*
1716 *----------------------------------------------------------------------
1717 *
1718 * GetTopLevel --
1719 *
1720 * This function retrieves the TkWindow associated with the given HWND.
1721 *
1722 * Results:
1723 * Returns the matching TkWindow.
1724 *
1725 * Side effects:
1726 * None.
1727 *
1728 *----------------------------------------------------------------------
1729 */
1730
1731 static TkWindow *
GetTopLevel(HWND hwnd)1732 GetTopLevel(
1733 HWND hwnd)
1734 {
1735 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1736 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1737
1738 /*
1739 * If this function is called before the CreateWindowEx call has
1740 * completed, then the user data slot will not have been set yet, so we
1741 * use the global createWindow variable.
1742 */
1743
1744 if (tsdPtr->createWindow) {
1745 return tsdPtr->createWindow;
1746 }
1747 return (TkWindow *) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1748 }
1749
1750 /*
1751 *----------------------------------------------------------------------
1752 *
1753 * SetLimits --
1754 *
1755 * Updates the minimum and maximum window size constraints.
1756 *
1757 * Results:
1758 * None.
1759 *
1760 * Side effects:
1761 * Changes the values of the info pointer to reflect the current minimum
1762 * and maximum size values.
1763 *
1764 *----------------------------------------------------------------------
1765 */
1766
1767 static void
SetLimits(HWND hwnd,MINMAXINFO * info)1768 SetLimits(
1769 HWND hwnd,
1770 MINMAXINFO *info)
1771 {
1772 WmInfo *wmPtr;
1773 int maxWidth, maxHeight;
1774 int minWidth, minHeight;
1775 int base;
1776 TkWindow *winPtr = GetTopLevel(hwnd);
1777
1778 if (winPtr == NULL) {
1779 return;
1780 }
1781
1782 wmPtr = winPtr->wmInfoPtr;
1783
1784 /*
1785 * Copy latest constraint info.
1786 */
1787
1788 wmPtr->defMinWidth = info->ptMinTrackSize.x;
1789 wmPtr->defMinHeight = info->ptMinTrackSize.y;
1790 wmPtr->defMaxWidth = info->ptMaxTrackSize.x;
1791 wmPtr->defMaxHeight = info->ptMaxTrackSize.y;
1792
1793 GetMaxSize(wmPtr, &maxWidth, &maxHeight);
1794 GetMinSize(wmPtr, &minWidth, &minHeight);
1795
1796 if (wmPtr->gridWin != NULL) {
1797 base = winPtr->reqWidth - (wmPtr->reqGridWidth * wmPtr->widthInc);
1798 if (base < 0) {
1799 base = 0;
1800 }
1801 base += wmPtr->borderWidth;
1802 info->ptMinTrackSize.x = base + (minWidth * wmPtr->widthInc);
1803 info->ptMaxTrackSize.x = base + (maxWidth * wmPtr->widthInc);
1804
1805 base = winPtr->reqHeight - (wmPtr->reqGridHeight * wmPtr->heightInc);
1806 if (base < 0) {
1807 base = 0;
1808 }
1809 base += wmPtr->borderHeight;
1810 info->ptMinTrackSize.y = base + (minHeight * wmPtr->heightInc);
1811 info->ptMaxTrackSize.y = base + (maxHeight * wmPtr->heightInc);
1812 } else {
1813 info->ptMaxTrackSize.x = maxWidth + wmPtr->borderWidth;
1814 info->ptMaxTrackSize.y = maxHeight + wmPtr->borderHeight;
1815 info->ptMinTrackSize.x = minWidth + wmPtr->borderWidth;
1816 info->ptMinTrackSize.y = minHeight + wmPtr->borderHeight;
1817 }
1818
1819 /*
1820 * If the window isn't supposed to be resizable, then set the minimum and
1821 * maximum dimensions to be the same as the current size.
1822 */
1823
1824 if (!(wmPtr->flags & WM_SYNC_PENDING)) {
1825 if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) {
1826 info->ptMinTrackSize.x = winPtr->changes.width
1827 + wmPtr->borderWidth;
1828 info->ptMaxTrackSize.x = info->ptMinTrackSize.x;
1829 }
1830 if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) {
1831 info->ptMinTrackSize.y = winPtr->changes.height
1832 + wmPtr->borderHeight;
1833 info->ptMaxTrackSize.y = info->ptMinTrackSize.y;
1834 }
1835 }
1836 }
1837
1838 /*
1839 *----------------------------------------------------------------------
1840 *
1841 * TkWinWmCleanup --
1842 *
1843 * Unregisters classes registered by the window manager. This is called
1844 * from the DLL main entry point when the DLL is unloaded.
1845 *
1846 * Results:
1847 * None.
1848 *
1849 * Side effects:
1850 * The window classes are discarded.
1851 *
1852 *----------------------------------------------------------------------
1853 */
1854
1855 void
TkWinWmCleanup(HINSTANCE hInstance)1856 TkWinWmCleanup(
1857 HINSTANCE hInstance)
1858 {
1859 ThreadSpecificData *tsdPtr;
1860
1861 /*
1862 * If we're using stubs to access the Tcl library, and they haven't been
1863 * initialized, we can't call Tcl_GetThreadData.
1864 */
1865
1866 #ifdef USE_TCL_STUBS
1867 if (tclStubsPtr == NULL) {
1868 return;
1869 }
1870 #endif
1871
1872 if (!initialized) {
1873 return;
1874 }
1875 initialized = 0;
1876
1877 tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1878
1879 if (!tsdPtr->initialized) {
1880 return;
1881 }
1882 tsdPtr->initialized = 0;
1883
1884 UnregisterClassW(TK_WIN_TOPLEVEL_CLASS_NAME, hInstance);
1885 }
1886
1887 /*
1888 *--------------------------------------------------------------
1889 *
1890 * TkWmNewWindow --
1891 *
1892 * This function is invoked whenever a new top-level window is created.
1893 * Its job is to initialize the WmInfo structure for the window.
1894 *
1895 * Results:
1896 * None.
1897 *
1898 * Side effects:
1899 * A WmInfo structure gets allocated and initialized.
1900 *
1901 *--------------------------------------------------------------
1902 */
1903
1904 void
TkWmNewWindow(TkWindow * winPtr)1905 TkWmNewWindow(
1906 TkWindow *winPtr) /* Newly-created top-level window. */
1907 {
1908 WmInfo *wmPtr = (WmInfo *)ckalloc(sizeof(WmInfo));
1909
1910 /*
1911 * Initialize full structure, then set what isn't NULL
1912 */
1913
1914 ZeroMemory(wmPtr, sizeof(WmInfo));
1915 winPtr->wmInfoPtr = wmPtr;
1916 wmPtr->winPtr = winPtr;
1917 wmPtr->hints.flags = InputHint | StateHint;
1918 wmPtr->hints.input = True;
1919 wmPtr->hints.initial_state = NormalState;
1920 wmPtr->hints.icon_pixmap = None;
1921 wmPtr->hints.icon_window = None;
1922 wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0;
1923 wmPtr->hints.icon_mask = None;
1924 wmPtr->hints.window_group = None;
1925
1926 /*
1927 * Default the maximum dimensions to the size of the display.
1928 */
1929
1930 wmPtr->defMinWidth = wmPtr->defMinHeight = 0;
1931 wmPtr->defMaxWidth = DisplayWidth(winPtr->display, winPtr->screenNum);
1932 wmPtr->defMaxHeight = DisplayHeight(winPtr->display, winPtr->screenNum);
1933 wmPtr->minWidth = wmPtr->minHeight = 1;
1934 wmPtr->maxWidth = wmPtr->maxHeight = 0;
1935 wmPtr->widthInc = wmPtr->heightInc = 1;
1936 wmPtr->minAspect.x = wmPtr->minAspect.y = 1;
1937 wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1;
1938 wmPtr->reqGridWidth = wmPtr->reqGridHeight = -1;
1939 wmPtr->gravity = NorthWestGravity;
1940 wmPtr->width = -1;
1941 wmPtr->height = -1;
1942 wmPtr->x = winPtr->changes.x;
1943 wmPtr->y = winPtr->changes.y;
1944 wmPtr->crefObj = NULL;
1945 wmPtr->colorref = (COLORREF) 0;
1946 wmPtr->alpha = 1.0;
1947
1948 wmPtr->configWidth = -1;
1949 wmPtr->configHeight = -1;
1950 wmPtr->flags = WM_NEVER_MAPPED;
1951 wmPtr->nextPtr = winPtr->dispPtr->firstWmPtr;
1952 winPtr->dispPtr->firstWmPtr = wmPtr;
1953
1954 /*
1955 * Tk must monitor structure events for top-level windows, in order to
1956 * detect size and position changes caused by window managers.
1957 */
1958
1959 Tk_CreateEventHandler((Tk_Window) winPtr, StructureNotifyMask,
1960 TopLevelEventProc, winPtr);
1961
1962 /*
1963 * Arrange for geometry requests to be reflected from the window to the
1964 * window manager.
1965 */
1966
1967 Tk_ManageGeometry((Tk_Window) winPtr, &wmMgrType, NULL);
1968 }
1969
1970 /*
1971 *----------------------------------------------------------------------
1972 *
1973 * UpdateWrapper --
1974 *
1975 * This function creates the wrapper window that contains the window
1976 * decorations and menus for a toplevel. This function may be called
1977 * after a window is mapped to change the window style.
1978 *
1979 * Results:
1980 * None.
1981 *
1982 * Side effects:
1983 * Destroys any old wrapper window and replaces it with a newly created
1984 * wrapper.
1985 *
1986 *----------------------------------------------------------------------
1987 */
1988
1989 static void
UpdateWrapper(TkWindow * winPtr)1990 UpdateWrapper(
1991 TkWindow *winPtr) /* Top-level window to redecorate. */
1992 {
1993 WmInfo *wmPtr = winPtr->wmInfoPtr;
1994 HWND parentHWND, oldWrapper = wmPtr->wrapper;
1995 HWND child, nextHWND, focusHWND;
1996 int x, y, width, height, state;
1997 WINDOWPLACEMENT place;
1998 HICON hSmallIcon = NULL;
1999 HICON hBigIcon = NULL;
2000 Tcl_DString titleString;
2001 int *childStateInfo = NULL;
2002 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
2003 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
2004
2005 if (winPtr->window == None) {
2006 /*
2007 * Ensure existence of the window to update the wrapper for.
2008 */
2009
2010 Tk_MakeWindowExist((Tk_Window) winPtr);
2011 }
2012
2013 child = TkWinGetHWND(winPtr->window);
2014 parentHWND = NULL;
2015
2016 /*
2017 * nextHWND will help us maintain Z order. focusHWND will help us maintain
2018 * focus, if we had it.
2019 */
2020
2021 nextHWND = NULL;
2022 focusHWND = GetFocus();
2023 if ((oldWrapper == NULL) || (oldWrapper != GetForegroundWindow())) {
2024 focusHWND = NULL;
2025 }
2026
2027 if (winPtr->flags & TK_EMBEDDED) {
2028 wmPtr->wrapper = (HWND) winPtr->privatePtr;
2029 if (wmPtr->wrapper == NULL) {
2030 Tcl_Panic("UpdateWrapper: Cannot find container window");
2031 }
2032 if (!IsWindow(wmPtr->wrapper)) {
2033 Tcl_Panic("UpdateWrapper: Container was destroyed");
2034 }
2035 } else {
2036 /*
2037 * Pick the decorative frame style. Override redirect windows get
2038 * created as undecorated popups if they have no transient parent,
2039 * otherwise they are children. This allows splash screens to operate
2040 * as an independent window, while having dropdowns (like for a
2041 * combobox) not grab focus away from their parent. Transient windows
2042 * get a modal dialog frame. Neither override, nor transient windows
2043 * appear in the Windows taskbar. Note that a transient window does
2044 * not resize by default, so we need to explicitly add the
2045 * WS_THICKFRAME style if we want it to be resizeable.
2046 */
2047
2048 if (winPtr->atts.override_redirect) {
2049 wmPtr->style = WM_OVERRIDE_STYLE;
2050 wmPtr->exStyle = EX_OVERRIDE_STYLE;
2051
2052 /*
2053 * Parent must be desktop even if we have a transient parent.
2054 */
2055
2056 parentHWND = GetDesktopWindow();
2057 if (wmPtr->containerPtr) {
2058 wmPtr->style |= WS_CHILD;
2059 } else {
2060 wmPtr->style |= WS_POPUP;
2061 }
2062 } else if (wmPtr->flags & WM_FULLSCREEN) {
2063 wmPtr->style = WM_FULLSCREEN_STYLE;
2064 wmPtr->exStyle = EX_FULLSCREEN_STYLE;
2065 } else if (wmPtr->containerPtr) {
2066 wmPtr->style = WM_TRANSIENT_STYLE;
2067 wmPtr->exStyle = EX_TRANSIENT_STYLE;
2068 parentHWND = Tk_GetHWND(Tk_WindowId(wmPtr->containerPtr));
2069 if (! ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE)
2070 && (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE))) {
2071 wmPtr->style |= WS_THICKFRAME;
2072 }
2073 } else {
2074 wmPtr->style = WM_TOPLEVEL_STYLE;
2075 wmPtr->exStyle = EX_TOPLEVEL_STYLE;
2076 }
2077
2078 wmPtr->style |= wmPtr->styleConfig;
2079 wmPtr->exStyle |= wmPtr->exStyleConfig;
2080
2081 if ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE)
2082 && (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE)) {
2083 wmPtr->style &= ~ (WS_MAXIMIZEBOX | WS_SIZEBOX);
2084 }
2085
2086 /*
2087 * Compute the geometry of the parent and child windows.
2088 */
2089
2090 wmPtr->flags |= WM_CREATE_PENDING|WM_MOVE_PENDING;
2091 UpdateGeometryInfo(winPtr);
2092 wmPtr->flags &= ~(WM_CREATE_PENDING|WM_MOVE_PENDING);
2093
2094 width = wmPtr->borderWidth + winPtr->changes.width;
2095 height = wmPtr->borderHeight + winPtr->changes.height;
2096
2097 /*
2098 * Set the initial position from the user or program specified
2099 * location. If nothing has been specified, then let the system pick a
2100 * location. In full screen mode the x,y origin is 0,0 and the window
2101 * width and height match that of the screen.
2102 */
2103
2104 if (wmPtr->flags & WM_FULLSCREEN) {
2105 x = 0;
2106 y = 0;
2107 width = WidthOfScreen(Tk_Screen(winPtr));
2108 height = HeightOfScreen(Tk_Screen(winPtr));
2109 } else if (!(wmPtr->sizeHintsFlags & (USPosition | PPosition))
2110 && (wmPtr->flags & WM_NEVER_MAPPED)) {
2111 x = CW_USEDEFAULT;
2112 y = CW_USEDEFAULT;
2113 } else {
2114 x = winPtr->changes.x;
2115 y = winPtr->changes.y;
2116 }
2117
2118 /*
2119 * Create the containing window, and set the user data to point to the
2120 * TkWindow.
2121 */
2122
2123 tsdPtr->createWindow = winPtr;
2124 Tcl_DStringInit(&titleString);
2125 Tcl_UtfToWCharDString(((wmPtr->title != NULL) ?
2126 wmPtr->title : winPtr->nameUid), -1, &titleString);
2127
2128 wmPtr->wrapper = CreateWindowExW(wmPtr->exStyle,
2129 TK_WIN_TOPLEVEL_CLASS_NAME,
2130 (LPCWSTR) Tcl_DStringValue(&titleString),
2131 wmPtr->style, x, y, width, height,
2132 parentHWND, NULL, Tk_GetHINSTANCE(), NULL);
2133 Tcl_DStringFree(&titleString);
2134 SetWindowLongPtrW(wmPtr->wrapper, GWLP_USERDATA, (LONG_PTR) winPtr);
2135 tsdPtr->createWindow = NULL;
2136
2137 if (wmPtr->exStyleConfig & WS_EX_LAYERED) {
2138 /*
2139 * The user supplies a double from [0..1], but Windows wants an
2140 * int (transparent) 0..255 (opaque), so do the translation. Add
2141 * the 0.5 to round the value.
2142 */
2143
2144 SetLayeredWindowAttributes((HWND) wmPtr->wrapper,
2145 wmPtr->colorref, (BYTE) (wmPtr->alpha * 255 + 0.5),
2146 (unsigned)(LWA_ALPHA | (wmPtr->crefObj?LWA_COLORKEY:0)));
2147 } else {
2148 /*
2149 * Layering not used or supported.
2150 */
2151
2152 wmPtr->alpha = 1.0;
2153 if (wmPtr->crefObj) {
2154 Tcl_DecrRefCount(wmPtr->crefObj);
2155 wmPtr->crefObj = NULL;
2156 }
2157 }
2158
2159 place.length = sizeof(WINDOWPLACEMENT);
2160 GetWindowPlacement(wmPtr->wrapper, &place);
2161 wmPtr->x = place.rcNormalPosition.left;
2162 wmPtr->y = place.rcNormalPosition.top;
2163
2164 if (!(winPtr->flags & TK_ALREADY_DEAD)) {
2165 TkInstallFrameMenu((Tk_Window) winPtr);
2166 }
2167
2168 if (oldWrapper && (oldWrapper != wmPtr->wrapper)
2169 && !(wmPtr->exStyle & WS_EX_TOPMOST)) {
2170 /*
2171 * We will adjust wrapper to have the same Z order as oldWrapper
2172 * if it isn't a TOPMOST window.
2173 */
2174
2175 nextHWND = GetNextWindow(oldWrapper, GW_HWNDPREV);
2176 }
2177 }
2178
2179 /*
2180 * Now we need to reparent the contained window and set its style
2181 * appropriately. Be sure to update the style first so that Windows
2182 * doesn't try to set the focus to the child window.
2183 */
2184
2185 SetWindowLongPtrW(child, GWL_STYLE,
2186 WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
2187
2188 if (winPtr->flags & TK_EMBEDDED) {
2189 SetWindowLongPtrW(child, GWLP_WNDPROC, (LONG_PTR) TopLevelProc);
2190 }
2191
2192 SetParent(child, wmPtr->wrapper);
2193 if (oldWrapper) {
2194 hSmallIcon = (HICON)
2195 SendMessageW(oldWrapper, WM_GETICON, ICON_SMALL, (LPARAM)NULL);
2196 hBigIcon = (HICON)
2197 SendMessageW(oldWrapper, WM_GETICON, ICON_BIG, (LPARAM) NULL);
2198 }
2199
2200 if (oldWrapper && (oldWrapper != wmPtr->wrapper)
2201 && (oldWrapper != GetDesktopWindow())) {
2202 SetWindowLongPtrW(oldWrapper, GWLP_USERDATA, (LONG_PTR) 0);
2203
2204 if (wmPtr->numTransients > 0) {
2205 /*
2206 * Unset the current wrapper as the parent for all transient
2207 * children for whom this is the container
2208 */
2209
2210 WmInfo *wmPtr2;
2211
2212 childStateInfo = (int *)ckalloc(wmPtr->numTransients * sizeof(int));
2213 state = 0;
2214 for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL;
2215 wmPtr2 = wmPtr2->nextPtr) {
2216 if (wmPtr2->containerPtr == winPtr
2217 && !(wmPtr2->flags & WM_NEVER_MAPPED)) {
2218 childStateInfo[state++] = wmPtr2->hints.initial_state;
2219 SetParent(TkWinGetHWND(wmPtr2->winPtr->window), NULL);
2220 }
2221 }
2222 }
2223
2224 /*
2225 * Remove the menubar before destroying the window so the menubar
2226 * isn't destroyed.
2227 */
2228
2229 SetMenu(oldWrapper, NULL);
2230 DestroyWindow(oldWrapper);
2231 }
2232
2233 wmPtr->flags &= ~WM_NEVER_MAPPED;
2234 if (winPtr->flags & TK_EMBEDDED &&
2235 SendMessageW(wmPtr->wrapper, TK_ATTACHWINDOW, (WPARAM) child, 0)) {
2236 SendMessageW(wmPtr->wrapper, TK_GEOMETRYREQ,
2237 Tk_ReqWidth((Tk_Window) winPtr),
2238 Tk_ReqHeight((Tk_Window) winPtr));
2239 SendMessageW(wmPtr->wrapper, TK_SETMENU, (WPARAM) wmPtr->hMenu,
2240 (LPARAM) Tk_GetMenuHWND((Tk_Window) winPtr));
2241 }
2242
2243 /*
2244 * Force an initial transition from withdrawn to the real initial state.
2245 * Set the Z order based on previous wrapper before we set the state.
2246 */
2247
2248 state = wmPtr->hints.initial_state;
2249 wmPtr->hints.initial_state = WithdrawnState;
2250 if (nextHWND) {
2251 SetWindowPos(wmPtr->wrapper, nextHWND, 0, 0, 0, 0,
2252 SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOSENDCHANGING
2253 |SWP_NOOWNERZORDER);
2254 }
2255 TkpWmSetState(winPtr, state);
2256 wmPtr->hints.initial_state = state;
2257
2258 if (hSmallIcon != NULL) {
2259 SendMessageW(wmPtr->wrapper, WM_SETICON, ICON_SMALL,
2260 (LPARAM) hSmallIcon);
2261 }
2262 if (hBigIcon != NULL) {
2263 SendMessageW(wmPtr->wrapper, WM_SETICON, ICON_BIG, (LPARAM) hBigIcon);
2264 }
2265
2266 /*
2267 * If we are embedded then force a mapping of the window now, because we
2268 * do not necessarily own the wrapper and may not get another opportunity
2269 * to map ourselves. We should not be in either iconified or zoomed states
2270 * when we get here, so it is safe to just check for TK_EMBEDDED without
2271 * checking what state we are supposed to be in (default to NormalState).
2272 */
2273
2274 if (winPtr->flags & TK_EMBEDDED) {
2275 if (state+1 != SendMessageW(wmPtr->wrapper, TK_STATE, state, 0)) {
2276 TkpWmSetState(winPtr, NormalState);
2277 wmPtr->hints.initial_state = NormalState;
2278 }
2279 XMapWindow(winPtr->display, winPtr->window);
2280 }
2281
2282 /*
2283 * Set up menus on the wrapper if required.
2284 */
2285
2286 if (wmPtr->hMenu != NULL) {
2287 wmPtr->flags |= WM_SYNC_PENDING;
2288 SetMenu(wmPtr->wrapper, wmPtr->hMenu);
2289 wmPtr->flags &= ~WM_SYNC_PENDING;
2290 }
2291
2292 if (childStateInfo) {
2293 if (wmPtr->numTransients > 0) {
2294 /*
2295 * Reset all transient children for whom this is the container.
2296 */
2297
2298 WmInfo *wmPtr2;
2299
2300 state = 0;
2301 for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL;
2302 wmPtr2 = wmPtr2->nextPtr) {
2303 if (wmPtr2->containerPtr == winPtr
2304 && !(wmPtr2->flags & WM_NEVER_MAPPED)) {
2305 UpdateWrapper(wmPtr2->winPtr);
2306 TkpWmSetState(wmPtr2->winPtr, childStateInfo[state++]);
2307 }
2308 }
2309 }
2310
2311 ckfree(childStateInfo);
2312 }
2313
2314 /*
2315 * If this is the first window created by the application, then we should
2316 * activate the initial window. Otherwise, if this had the focus, we need
2317 * to restore that.
2318 * XXX: Rewrapping generates a <FocusOut> and <FocusIn> that would best be
2319 * XXX: avoided, if we could safely mask them.
2320 */
2321
2322 if (tsdPtr->firstWindow) {
2323 tsdPtr->firstWindow = 0;
2324 SetActiveWindow(wmPtr->wrapper);
2325 } else if (focusHWND) {
2326 SetFocus(focusHWND);
2327 }
2328 }
2329
2330 /*
2331 *--------------------------------------------------------------
2332 *
2333 * TkWmMapWindow --
2334 *
2335 * This function is invoked to map a top-level window. This module gets a
2336 * chance to update all window-manager-related information in properties
2337 * before the window manager sees the map event and checks the
2338 * properties. It also gets to decide whether or not to even map the
2339 * window after all.
2340 *
2341 * Results:
2342 * None.
2343 *
2344 * Side effects:
2345 * Properties of winPtr may get updated to provide up-to-date information
2346 * to the window manager. The window may also get mapped, but it may not
2347 * be if this function decides that isn't appropriate (e.g. because the
2348 * window is withdrawn).
2349 *
2350 *--------------------------------------------------------------
2351 */
2352
2353 void
TkWmMapWindow(TkWindow * winPtr)2354 TkWmMapWindow(
2355 TkWindow *winPtr) /* Top-level window that's about to be
2356 * mapped. */
2357 {
2358 WmInfo *wmPtr = winPtr->wmInfoPtr;
2359 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
2360 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
2361
2362 if (!tsdPtr->initialized) {
2363 InitWm();
2364 }
2365
2366 if (wmPtr->flags & WM_NEVER_MAPPED) {
2367 /*
2368 * Don't map a transient if the container is not mapped.
2369 */
2370
2371 if (wmPtr->containerPtr != NULL && !Tk_IsMapped(wmPtr->containerPtr)) {
2372 wmPtr->hints.initial_state = WithdrawnState;
2373 return;
2374 }
2375 } else {
2376 if (wmPtr->hints.initial_state == WithdrawnState) {
2377 return;
2378 }
2379
2380 /*
2381 * Map the window in either the iconified or normal state. Note that
2382 * we only send a map event if the window is in the normal state.
2383 */
2384
2385 TkpWmSetState(winPtr, wmPtr->hints.initial_state);
2386 }
2387
2388 /*
2389 * This is the first time this window has ever been mapped. Store all the
2390 * window-manager-related information for the window.
2391 */
2392
2393 UpdateWrapper(winPtr);
2394 }
2395
2396 /*
2397 *--------------------------------------------------------------
2398 *
2399 * TkWmUnmapWindow --
2400 *
2401 * This function is invoked to unmap a top-level window. The only thing
2402 * it does special is unmap the decorative frame before unmapping the
2403 * toplevel window.
2404 *
2405 * Results:
2406 * None.
2407 *
2408 * Side effects:
2409 * Unmaps the decorative frame and the window.
2410 *
2411 *--------------------------------------------------------------
2412 */
2413
2414 void
TkWmUnmapWindow(TkWindow * winPtr)2415 TkWmUnmapWindow(
2416 TkWindow *winPtr) /* Top-level window that's about to be
2417 * unmapped. */
2418 {
2419 TkpWmSetState(winPtr, WithdrawnState);
2420 }
2421
2422 /*
2423 *----------------------------------------------------------------------
2424 *
2425 * TkpWmSetState --
2426 *
2427 * Sets the window manager state for the wrapper window of a given
2428 * toplevel window.
2429 *
2430 * Results:
2431 * None.
2432 *
2433 * Side effects:
2434 * May maximize, minimize, restore, or withdraw a window.
2435 *
2436 *----------------------------------------------------------------------
2437 */
2438
2439 int
TkpWmSetState(TkWindow * winPtr,int state)2440 TkpWmSetState(
2441 TkWindow *winPtr, /* Toplevel window to operate on. */
2442 int state) /* One of IconicState, ZoomState, NormalState,
2443 * or WithdrawnState. */
2444 {
2445 WmInfo *wmPtr = winPtr->wmInfoPtr;
2446 int cmd;
2447
2448 if (wmPtr->flags & WM_NEVER_MAPPED) {
2449 wmPtr->hints.initial_state = state;
2450 goto setStateEnd;
2451 }
2452
2453 wmPtr->flags |= WM_SYNC_PENDING;
2454 if (state == WithdrawnState) {
2455 cmd = SW_HIDE;
2456 } else if (state == IconicState) {
2457 cmd = SW_SHOWMINNOACTIVE;
2458 } else if (state == NormalState) {
2459 cmd = SW_SHOWNOACTIVATE;
2460 } else if (state == ZoomState) {
2461 cmd = SW_SHOWMAXIMIZED;
2462 } else {
2463 goto setStateEnd;
2464 }
2465
2466 ShowWindow(wmPtr->wrapper, cmd);
2467 wmPtr->flags &= ~WM_SYNC_PENDING;
2468 setStateEnd:
2469 return 1;
2470 }
2471
2472 /*
2473 *----------------------------------------------------------------------
2474 *
2475 * TkpWmSetFullScreen --
2476 *
2477 * Sets the fullscreen state for a toplevel window.
2478 *
2479 * Results:
2480 * The WM_FULLSCREEN flag is updated.
2481 *
2482 * Side effects:
2483 * May create a new wrapper window and raise it.
2484 *
2485 *----------------------------------------------------------------------
2486 */
2487
2488 static void
TkpWmSetFullScreen(TkWindow * winPtr,int full_screen_state)2489 TkpWmSetFullScreen(
2490 TkWindow *winPtr, /* Toplevel window to operate on. */
2491 int full_screen_state) /* True if window should be full screen */
2492 {
2493 int changed = 0;
2494 int full_screen = False;
2495 WmInfo *wmPtr = winPtr->wmInfoPtr;
2496
2497 if (full_screen_state) {
2498 if (! (wmPtr->flags & WM_FULLSCREEN)) {
2499 full_screen = True;
2500 changed = 1;
2501 }
2502 } else {
2503 if (wmPtr->flags & WM_FULLSCREEN) {
2504 full_screen = False;
2505 changed = 1;
2506 }
2507 }
2508
2509 if (changed) {
2510 if (full_screen) {
2511 wmPtr->flags |= WM_FULLSCREEN;
2512 wmPtr->configX = wmPtr->x;
2513 wmPtr->configY = wmPtr->y;
2514 } else {
2515 wmPtr->flags &= ~WM_FULLSCREEN;
2516 wmPtr->x = wmPtr->configX;
2517 wmPtr->y = wmPtr->configY;
2518 }
2519
2520 /*
2521 * If the window has been mapped, then we need to update the native
2522 * wrapper window, and reset the focus to the widget that had it
2523 * before.
2524 */
2525
2526 if (!(wmPtr->flags & (WM_NEVER_MAPPED)
2527 && !(winPtr->flags & TK_EMBEDDED))) {
2528 TkWindow *focusWinPtr;
2529
2530 UpdateWrapper(winPtr);
2531
2532 focusWinPtr = TkGetFocusWin(winPtr);
2533 if (focusWinPtr) {
2534 TkSetFocusWin(focusWinPtr, 1);
2535 }
2536 }
2537 }
2538 }
2539
2540 /*
2541 *----------------------------------------------------------------------
2542 *
2543 * TkpWinGetState --
2544 *
2545 * This function returns state value of a toplevel window.
2546 *
2547 * Results:
2548 * none
2549 *
2550 * Side effects:
2551 * May deiconify the toplevel window.
2552 *
2553 *----------------------------------------------------------------------
2554 */
2555
2556 int
TkpWmGetState(TkWindow * winPtr)2557 TkpWmGetState(
2558 TkWindow *winPtr)
2559 {
2560 return winPtr->wmInfoPtr->hints.initial_state;
2561 }
2562
2563 /*
2564 *--------------------------------------------------------------
2565 *
2566 * TkWmDeadWindow --
2567 *
2568 * This function is invoked when a top-level window is about to be
2569 * deleted. It cleans up the wm-related data structures for the window.
2570 *
2571 * Results:
2572 * None.
2573 *
2574 * Side effects:
2575 * The WmInfo structure for winPtr gets freed up.
2576 *
2577 *--------------------------------------------------------------
2578 */
2579
2580 void
TkWmDeadWindow(TkWindow * winPtr)2581 TkWmDeadWindow(
2582 TkWindow *winPtr) /* Top-level window that's being deleted. */
2583 {
2584 WmInfo *wmPtr = winPtr->wmInfoPtr;
2585 WmInfo *wmPtr2;
2586
2587 if (wmPtr == NULL) {
2588 return;
2589 }
2590
2591 /*
2592 * Clean up event related window info.
2593 */
2594
2595 if (winPtr->dispPtr->firstWmPtr == wmPtr) {
2596 winPtr->dispPtr->firstWmPtr = wmPtr->nextPtr;
2597 } else {
2598 WmInfo *prevPtr;
2599
2600 for (prevPtr = winPtr->dispPtr->firstWmPtr; ;
2601 prevPtr = prevPtr->nextPtr) {
2602 if (prevPtr == NULL) {
2603 Tcl_Panic("couldn't unlink window in TkWmDeadWindow");
2604 }
2605 if (prevPtr->nextPtr == wmPtr) {
2606 prevPtr->nextPtr = wmPtr->nextPtr;
2607 break;
2608 }
2609 }
2610 }
2611
2612 /*
2613 * Reset all transient windows whose container is the dead window.
2614 */
2615
2616 for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL;
2617 wmPtr2 = wmPtr2->nextPtr) {
2618 if (wmPtr2->containerPtr == winPtr) {
2619 wmPtr->numTransients--;
2620 Tk_DeleteEventHandler((Tk_Window) wmPtr2->containerPtr,
2621 VisibilityChangeMask|StructureNotifyMask,
2622 WmWaitVisibilityOrMapProc, wmPtr2->winPtr);
2623 wmPtr2->containerPtr = NULL;
2624 if ((wmPtr2->wrapper != NULL)
2625 && !(wmPtr2->flags & (WM_NEVER_MAPPED))) {
2626 UpdateWrapper(wmPtr2->winPtr);
2627 }
2628 }
2629 }
2630 if (wmPtr->numTransients != 0)
2631 Tcl_Panic("numTransients should be 0");
2632
2633 if (wmPtr->title != NULL) {
2634 ckfree(wmPtr->title);
2635 }
2636 if (wmPtr->iconName != NULL) {
2637 ckfree(wmPtr->iconName);
2638 }
2639 if (wmPtr->hints.flags & IconPixmapHint) {
2640 Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
2641 }
2642 if (wmPtr->hints.flags & IconMaskHint) {
2643 Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
2644 }
2645 if (wmPtr->leaderName != NULL) {
2646 ckfree(wmPtr->leaderName);
2647 }
2648 if (wmPtr->icon != NULL) {
2649 wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
2650 wmPtr2->iconFor = NULL;
2651 }
2652 if (wmPtr->iconFor != NULL) {
2653 wmPtr2 = ((TkWindow *) wmPtr->iconFor)->wmInfoPtr;
2654 wmPtr2->icon = NULL;
2655 wmPtr2->hints.flags &= ~IconWindowHint;
2656 }
2657 while (wmPtr->protPtr != NULL) {
2658 ProtocolHandler *protPtr;
2659
2660 protPtr = wmPtr->protPtr;
2661 wmPtr->protPtr = protPtr->nextPtr;
2662 Tcl_EventuallyFree(protPtr, TCL_DYNAMIC);
2663 }
2664 if (wmPtr->cmdArgv != NULL) {
2665 ckfree(wmPtr->cmdArgv);
2666 }
2667 if (wmPtr->clientMachine != NULL) {
2668 ckfree(wmPtr->clientMachine);
2669 }
2670 if (wmPtr->flags & WM_UPDATE_PENDING) {
2671 Tcl_CancelIdleCall(UpdateGeometryInfo, winPtr);
2672 }
2673 if (wmPtr->containerPtr != NULL) {
2674 wmPtr2 = wmPtr->containerPtr->wmInfoPtr;
2675
2676 /*
2677 * If we had a container, tell them that we aren't tied to them anymore.
2678 */
2679
2680 if (wmPtr2 != NULL) {
2681 wmPtr2->numTransients--;
2682 }
2683 Tk_DeleteEventHandler((Tk_Window) wmPtr->containerPtr,
2684 VisibilityChangeMask|StructureNotifyMask,
2685 WmWaitVisibilityOrMapProc, winPtr);
2686 wmPtr->containerPtr = NULL;
2687 }
2688 if (wmPtr->crefObj != NULL) {
2689 Tcl_DecrRefCount(wmPtr->crefObj);
2690 wmPtr->crefObj = NULL;
2691 }
2692
2693 /*
2694 * Destroy the decorative frame window.
2695 */
2696
2697 if (!(winPtr->flags & TK_EMBEDDED)) {
2698 if (wmPtr->wrapper != NULL) {
2699 DestroyWindow(wmPtr->wrapper);
2700 } else if (winPtr->window) {
2701 DestroyWindow(Tk_GetHWND(winPtr->window));
2702 }
2703 } else {
2704 if (wmPtr->wrapper != NULL) {
2705 SendMessageW(wmPtr->wrapper, TK_DETACHWINDOW, 0, 0);
2706 }
2707 }
2708 if (wmPtr->iconPtr != NULL) {
2709 /*
2710 * This may delete the icon resource data. I believe we should do this
2711 * after destroying the decorative frame, because the decorative frame
2712 * is using this icon.
2713 */
2714
2715 DecrIconRefCount(wmPtr->iconPtr);
2716 }
2717
2718 ckfree(wmPtr);
2719 winPtr->wmInfoPtr = NULL;
2720 }
2721
2722 /*
2723 *--------------------------------------------------------------
2724 *
2725 * TkWmSetClass --
2726 *
2727 * This function is invoked whenever a top-level window's class is
2728 * changed. If the window has been mapped then this function updates the
2729 * window manager property for the class. If the window hasn't been
2730 * mapped, the update is deferred until just before the first mapping.
2731 *
2732 * Results:
2733 * None.
2734 *
2735 * Side effects:
2736 * A window property may get updated.
2737 *
2738 *--------------------------------------------------------------
2739 */
2740
2741 void
TkWmSetClass(TCL_UNUSED (TkWindow *))2742 TkWmSetClass(
2743 TCL_UNUSED(TkWindow *)) /* Newly-created top-level window. */
2744 {
2745 /* Do nothing */
2746 return;
2747 }
2748
2749 /*
2750 *----------------------------------------------------------------------
2751 *
2752 * Tk_WmObjCmd --
2753 *
2754 * This function is invoked to process the "wm" Tcl command. See the user
2755 * documentation for details on what it does.
2756 *
2757 * Results:
2758 * A standard Tcl result.
2759 *
2760 * Side effects:
2761 * See the user documentation.
2762 *
2763 *----------------------------------------------------------------------
2764 */
2765
2766 int
Tk_WmObjCmd(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])2767 Tk_WmObjCmd(
2768 ClientData clientData, /* Main window associated with interpreter. */
2769 Tcl_Interp *interp, /* Current interpreter. */
2770 int objc, /* Number of arguments. */
2771 Tcl_Obj *const objv[]) /* Argument objects. */
2772 {
2773 Tk_Window tkwin = (Tk_Window)clientData;
2774 static const char *const optionStrings[] = {
2775 "aspect", "attributes", "client", "colormapwindows",
2776 "command", "deiconify", "focusmodel", "forget", "frame",
2777 "geometry", "grid", "group", "iconbitmap",
2778 "iconify", "iconmask", "iconname",
2779 "iconphoto", "iconposition",
2780 "iconwindow", "manage", "maxsize", "minsize", "overrideredirect",
2781 "positionfrom", "protocol", "resizable", "sizefrom",
2782 "stackorder", "state", "title", "transient",
2783 "withdraw", NULL
2784 };
2785 enum options {
2786 WMOPT_ASPECT, WMOPT_ATTRIBUTES, WMOPT_CLIENT, WMOPT_COLORMAPWINDOWS,
2787 WMOPT_COMMAND, WMOPT_DEICONIFY, WMOPT_FOCUSMODEL, WMOPT_FORGET,
2788 WMOPT_FRAME,
2789 WMOPT_GEOMETRY, WMOPT_GRID, WMOPT_GROUP, WMOPT_ICONBITMAP,
2790 WMOPT_ICONIFY, WMOPT_ICONMASK, WMOPT_ICONNAME,
2791 WMOPT_ICONPHOTO, WMOPT_ICONPOSITION,
2792 WMOPT_ICONWINDOW, WMOPT_MANAGE, WMOPT_MAXSIZE, WMOPT_MINSIZE,
2793 WMOPT_OVERRIDEREDIRECT,
2794 WMOPT_POSITIONFROM, WMOPT_PROTOCOL, WMOPT_RESIZABLE, WMOPT_SIZEFROM,
2795 WMOPT_STACKORDER, WMOPT_STATE, WMOPT_TITLE, WMOPT_TRANSIENT,
2796 WMOPT_WITHDRAW
2797 };
2798 int index;
2799 int length;
2800 const char *argv1;
2801 TkWindow *winPtr, **winPtrPtr = &winPtr;
2802 TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
2803
2804 if (objc < 2) {
2805 wrongNumArgs:
2806 Tcl_WrongNumArgs(interp, 1, objv, "option window ?arg ...?");
2807 return TCL_ERROR;
2808 }
2809
2810 argv1 = Tcl_GetStringFromObj(objv[1], &length);
2811 if ((argv1[0] == 't') && !strncmp(argv1, "tracing", length)
2812 && (length >= 3)) {
2813 int wmTracing;
2814
2815 if ((objc != 2) && (objc != 3)) {
2816 Tcl_WrongNumArgs(interp, 2, objv, "?boolean?");
2817 return TCL_ERROR;
2818 }
2819 if (objc == 2) {
2820 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
2821 dispPtr->flags & TK_DISPLAY_WM_TRACING));
2822 return TCL_OK;
2823 }
2824 if (Tcl_GetBooleanFromObj(interp, objv[2], &wmTracing) != TCL_OK) {
2825 return TCL_ERROR;
2826 }
2827 if (wmTracing) {
2828 dispPtr->flags |= TK_DISPLAY_WM_TRACING;
2829 } else {
2830 dispPtr->flags &= ~TK_DISPLAY_WM_TRACING;
2831 }
2832 return TCL_OK;
2833 }
2834
2835 if (Tcl_GetIndexFromObjStruct(interp, objv[1], optionStrings,
2836 sizeof(char *), "option", 0, &index) != TCL_OK) {
2837 return TCL_ERROR;
2838 }
2839
2840 if (objc < 3) {
2841 goto wrongNumArgs;
2842 }
2843
2844 if (TkGetWindowFromObj(interp, tkwin, objv[2], (Tk_Window *) winPtrPtr)
2845 != TCL_OK) {
2846 return TCL_ERROR;
2847 }
2848 if (!Tk_IsTopLevel(winPtr) && (index != WMOPT_MANAGE)
2849 && (index != WMOPT_FORGET)) {
2850 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
2851 "window \"%s\" isn't a top-level window", winPtr->pathName));
2852 Tcl_SetErrorCode(interp, "TK", "LOOKUP", "TOPLEVEL", winPtr->pathName,
2853 NULL);
2854 return TCL_ERROR;
2855 }
2856
2857 switch ((enum options) index) {
2858 case WMOPT_ASPECT:
2859 return WmAspectCmd(tkwin, winPtr, interp, objc, objv);
2860 case WMOPT_ATTRIBUTES:
2861 return WmAttributesCmd(tkwin, winPtr, interp, objc, objv);
2862 case WMOPT_CLIENT:
2863 return WmClientCmd(tkwin, winPtr, interp, objc, objv);
2864 case WMOPT_COLORMAPWINDOWS:
2865 return WmColormapwindowsCmd(tkwin, winPtr, interp, objc, objv);
2866 case WMOPT_COMMAND:
2867 return WmCommandCmd(tkwin, winPtr, interp, objc, objv);
2868 case WMOPT_DEICONIFY:
2869 return WmDeiconifyCmd(tkwin, winPtr, interp, objc, objv);
2870 case WMOPT_FOCUSMODEL:
2871 return WmFocusmodelCmd(tkwin, winPtr, interp, objc, objv);
2872 case WMOPT_FORGET:
2873 return WmForgetCmd(tkwin, winPtr, interp, objc, objv);
2874 case WMOPT_FRAME:
2875 return WmFrameCmd(tkwin, winPtr, interp, objc, objv);
2876 case WMOPT_GEOMETRY:
2877 return WmGeometryCmd(tkwin, winPtr, interp, objc, objv);
2878 case WMOPT_GRID:
2879 return WmGridCmd(tkwin, winPtr, interp, objc, objv);
2880 case WMOPT_GROUP:
2881 return WmGroupCmd(tkwin, winPtr, interp, objc, objv);
2882 case WMOPT_ICONBITMAP:
2883 return WmIconbitmapCmd(tkwin, winPtr, interp, objc, objv);
2884 case WMOPT_ICONIFY:
2885 return WmIconifyCmd(tkwin, winPtr, interp, objc, objv);
2886 case WMOPT_ICONMASK:
2887 return WmIconmaskCmd(tkwin, winPtr, interp, objc, objv);
2888 case WMOPT_ICONNAME:
2889 return WmIconnameCmd(tkwin, winPtr, interp, objc, objv);
2890 case WMOPT_ICONPHOTO:
2891 return WmIconphotoCmd(tkwin, winPtr, interp, objc, objv);
2892 case WMOPT_ICONPOSITION:
2893 return WmIconpositionCmd(tkwin, winPtr, interp, objc, objv);
2894 case WMOPT_ICONWINDOW:
2895 return WmIconwindowCmd(tkwin, winPtr, interp, objc, objv);
2896 case WMOPT_MANAGE:
2897 return WmManageCmd(tkwin, winPtr, interp, objc, objv);
2898 case WMOPT_MAXSIZE:
2899 return WmMaxsizeCmd(tkwin, winPtr, interp, objc, objv);
2900 case WMOPT_MINSIZE:
2901 return WmMinsizeCmd(tkwin, winPtr, interp, objc, objv);
2902 case WMOPT_OVERRIDEREDIRECT:
2903 return WmOverrideredirectCmd(tkwin, winPtr, interp, objc, objv);
2904 case WMOPT_POSITIONFROM:
2905 return WmPositionfromCmd(tkwin, winPtr, interp, objc, objv);
2906 case WMOPT_PROTOCOL:
2907 return WmProtocolCmd(tkwin, winPtr, interp, objc, objv);
2908 case WMOPT_RESIZABLE:
2909 return WmResizableCmd(tkwin, winPtr, interp, objc, objv);
2910 case WMOPT_SIZEFROM:
2911 return WmSizefromCmd(tkwin, winPtr, interp, objc, objv);
2912 case WMOPT_STACKORDER:
2913 return WmStackorderCmd(tkwin, winPtr, interp, objc, objv);
2914 case WMOPT_STATE:
2915 return WmStateCmd(tkwin, winPtr, interp, objc, objv);
2916 case WMOPT_TITLE:
2917 return WmTitleCmd(tkwin, winPtr, interp, objc, objv);
2918 case WMOPT_TRANSIENT:
2919 return WmTransientCmd(tkwin, winPtr, interp, objc, objv);
2920 case WMOPT_WITHDRAW:
2921 return WmWithdrawCmd(tkwin, winPtr, interp, objc, objv);
2922 }
2923
2924 /* This should not happen */
2925 return TCL_ERROR;
2926 }
2927
2928 /*
2929 *----------------------------------------------------------------------
2930 *
2931 * WmAspectCmd --
2932 *
2933 * This function is invoked to process the "wm aspect" Tcl command. See
2934 * the user documentation for details on what it does.
2935 *
2936 * Results:
2937 * A standard Tcl result.
2938 *
2939 * Side effects:
2940 * See the user documentation.
2941 *
2942 *----------------------------------------------------------------------
2943 */
2944
2945 static int
WmAspectCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])2946 WmAspectCmd(
2947 TCL_UNUSED(Tk_Window), /* Main window of the application. */
2948 TkWindow *winPtr, /* Toplevel to work with */
2949 Tcl_Interp *interp, /* Current interpreter. */
2950 int objc, /* Number of arguments. */
2951 Tcl_Obj *const objv[]) /* Argument objects. */
2952 {
2953 WmInfo *wmPtr = winPtr->wmInfoPtr;
2954 int numer1, denom1, numer2, denom2;
2955
2956 if ((objc != 3) && (objc != 7)) {
2957 Tcl_WrongNumArgs(interp, 2, objv,
2958 "window ?minNumer minDenom maxNumer maxDenom?");
2959 return TCL_ERROR;
2960 }
2961 if (objc == 3) {
2962 if (wmPtr->sizeHintsFlags & PAspect) {
2963 Tcl_Obj *results[4];
2964
2965 results[0] = Tcl_NewIntObj(wmPtr->minAspect.x);
2966 results[1] = Tcl_NewIntObj(wmPtr->minAspect.y);
2967 results[2] = Tcl_NewIntObj(wmPtr->maxAspect.x);
2968 results[3] = Tcl_NewIntObj(wmPtr->maxAspect.y);
2969 Tcl_SetObjResult(interp, Tcl_NewListObj(4, results));
2970 }
2971 return TCL_OK;
2972 }
2973 if (*Tcl_GetString(objv[3]) == '\0') {
2974 wmPtr->sizeHintsFlags &= ~PAspect;
2975 } else {
2976 if ((Tcl_GetIntFromObj(interp, objv[3], &numer1) != TCL_OK)
2977 || (Tcl_GetIntFromObj(interp, objv[4], &denom1) != TCL_OK)
2978 || (Tcl_GetIntFromObj(interp, objv[5], &numer2) != TCL_OK)
2979 || (Tcl_GetIntFromObj(interp, objv[6], &denom2) != TCL_OK)) {
2980 return TCL_ERROR;
2981 }
2982 if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) || (denom2 <= 0)) {
2983 Tcl_SetObjResult(interp, Tcl_NewStringObj(
2984 "aspect number can't be <= 0", -1));
2985 Tcl_SetErrorCode(interp, "TK", "VALUE", "ASPECT", NULL);
2986 return TCL_ERROR;
2987 }
2988 wmPtr->minAspect.x = numer1;
2989 wmPtr->minAspect.y = denom1;
2990 wmPtr->maxAspect.x = numer2;
2991 wmPtr->maxAspect.y = denom2;
2992 wmPtr->sizeHintsFlags |= PAspect;
2993 }
2994 WmUpdateGeom(wmPtr, winPtr);
2995 return TCL_OK;
2996 }
2997
2998 /*
2999 *----------------------------------------------------------------------
3000 *
3001 * WmAttributesCmd --
3002 *
3003 * This function is invoked to process the "wm attributes" Tcl command.
3004 * See the user documentation for details on what it does.
3005 *
3006 * Results:
3007 * A standard Tcl result.
3008 *
3009 * Side effects:
3010 * See the user documentation.
3011 *
3012 *----------------------------------------------------------------------
3013 */
3014
3015 static int
WmAttributesCmd(Tk_Window tkwin,TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])3016 WmAttributesCmd(
3017 Tk_Window tkwin, /* Main window of the application. */
3018 TkWindow *winPtr, /* Toplevel to work with */
3019 Tcl_Interp *interp, /* Current interpreter. */
3020 int objc, /* Number of arguments. */
3021 Tcl_Obj *const objv[]) /* Argument objects. */
3022 {
3023 WmInfo *wmPtr = winPtr->wmInfoPtr;
3024 LONG style, exStyle, styleBit, *stylePtr = NULL;
3025 const char *string;
3026 int i, boolean;
3027 int length;
3028 int config_fullscreen = 0, updatewrapper = 0;
3029 int fullscreen_attr_changed = 0, fullscreen_attr = 0;
3030
3031 if ((objc < 3) || ((objc > 5) && ((objc%2) == 0))) {
3032 configArgs:
3033 Tcl_WrongNumArgs(interp, 2, objv,
3034 "window"
3035 " ?-alpha ?double??"
3036 " ?-transparentcolor ?color??"
3037 " ?-disabled ?bool??"
3038 " ?-fullscreen ?bool??"
3039 " ?-toolwindow ?bool??"
3040 " ?-topmost ?bool??");
3041 return TCL_ERROR;
3042 }
3043 exStyle = wmPtr->exStyleConfig;
3044 style = wmPtr->styleConfig;
3045 if (objc == 3) {
3046 Tcl_Obj *objPtr = Tcl_NewObj();
3047 Tcl_ListObjAppendElement(NULL, objPtr,
3048 Tcl_NewStringObj("-alpha", -1));
3049 Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewDoubleObj(wmPtr->alpha));
3050 Tcl_ListObjAppendElement(NULL, objPtr,
3051 Tcl_NewStringObj("-transparentcolor", -1));
3052 Tcl_ListObjAppendElement(NULL, objPtr,
3053 wmPtr->crefObj ? wmPtr->crefObj : Tcl_NewObj());
3054 Tcl_ListObjAppendElement(NULL, objPtr,
3055 Tcl_NewStringObj("-disabled", -1));
3056 Tcl_ListObjAppendElement(NULL, objPtr,
3057 Tcl_NewBooleanObj((style & WS_DISABLED)));
3058 Tcl_ListObjAppendElement(NULL, objPtr,
3059 Tcl_NewStringObj("-fullscreen", -1));
3060 Tcl_ListObjAppendElement(NULL, objPtr,
3061 Tcl_NewBooleanObj((wmPtr->flags & WM_FULLSCREEN)));
3062 Tcl_ListObjAppendElement(NULL, objPtr,
3063 Tcl_NewStringObj("-toolwindow", -1));
3064 Tcl_ListObjAppendElement(NULL, objPtr,
3065 Tcl_NewBooleanObj((exStyle & WS_EX_TOOLWINDOW)));
3066 Tcl_ListObjAppendElement(NULL, objPtr,
3067 Tcl_NewStringObj("-topmost", -1));
3068 Tcl_ListObjAppendElement(NULL, objPtr,
3069 Tcl_NewBooleanObj((exStyle & WS_EX_TOPMOST)));
3070 Tcl_SetObjResult(interp, objPtr);
3071 return TCL_OK;
3072 }
3073 for (i = 3; i < objc; i += 2) {
3074 string = Tcl_GetStringFromObj(objv[i], &length);
3075 if (strncmp(string, "-disabled", length) == 0) {
3076 stylePtr = &style;
3077 styleBit = WS_DISABLED;
3078 } else if ((strncmp(string, "-alpha", length) == 0)
3079 || ((length > 2) && (strncmp(string, "-transparentcolor",
3080 length) == 0))) {
3081 stylePtr = &exStyle;
3082 styleBit = WS_EX_LAYERED;
3083 } else if (strncmp(string, "-fullscreen", length) == 0) {
3084 config_fullscreen = 1;
3085 styleBit = 0;
3086 } else if ((length > 3)
3087 && (strncmp(string, "-toolwindow", length) == 0)) {
3088 stylePtr = &exStyle;
3089 styleBit = WS_EX_TOOLWINDOW;
3090 if (objc != 4) {
3091 /*
3092 * Changes to toolwindow style require an update
3093 */
3094 updatewrapper = 1;
3095 }
3096 } else if ((length > 3)
3097 && (strncmp(string, "-topmost", length) == 0)) {
3098 stylePtr = &exStyle;
3099 styleBit = WS_EX_TOPMOST;
3100 if ((i < objc-1) && (winPtr->flags & TK_EMBEDDED)) {
3101 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
3102 "can't set topmost flag on %s: it is an embedded window",
3103 winPtr->pathName));
3104 Tcl_SetErrorCode(interp, "TK", "WM", "ATTR", "TOPMOST", NULL);
3105 return TCL_ERROR;
3106 }
3107 } else if (i == 3) {
3108 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
3109 "bad attribute \"%s\": must be -alpha, -transparentcolor, -disabled, -fullscreen, -toolwindow, or -topmost",
3110 string));
3111 Tcl_SetErrorCode(interp, "TK", "WM", "ATTR", "UNRECOGNIZED", NULL);
3112 return TCL_ERROR;
3113 } else {
3114 goto configArgs;
3115 }
3116 if (styleBit == WS_EX_LAYERED) {
3117 if (objc == 4) {
3118 if (string[1] == 'a') { /* -alpha */
3119 Tcl_SetObjResult(interp, Tcl_NewDoubleObj(wmPtr->alpha));
3120 } else { /* -transparentcolor */
3121 Tcl_SetObjResult(interp,
3122 wmPtr->crefObj ? wmPtr->crefObj : Tcl_NewObj());
3123 }
3124 } else {
3125 if (string[1] == 'a') { /* -alpha */
3126 double dval;
3127
3128 if (Tcl_GetDoubleFromObj(interp, objv[i+1], &dval)
3129 != TCL_OK) {
3130 return TCL_ERROR;
3131 }
3132
3133 /*
3134 * The user should give (transparent) 0 .. 1.0 (opaque),
3135 * but we ignore the setting of this (it will always be 1)
3136 * in the case that the API is not available.
3137 */
3138 if (dval < 0.0) {
3139 dval = 0;
3140 } else if (dval > 1.0) {
3141 dval = 1;
3142 }
3143 wmPtr->alpha = dval;
3144 } else { /* -transparentcolor */
3145 const char *crefstr = Tcl_GetStringFromObj(objv[i+1], &length);
3146
3147 if (length == 0) {
3148 /* reset to no transparent color */
3149 if (wmPtr->crefObj) {
3150 Tcl_DecrRefCount(wmPtr->crefObj);
3151 wmPtr->crefObj = NULL;
3152 }
3153 } else {
3154 XColor *cPtr =
3155 Tk_GetColor(interp, tkwin, Tk_GetUid(crefstr));
3156 if (cPtr == NULL) {
3157 return TCL_ERROR;
3158 }
3159
3160 if (wmPtr->crefObj) {
3161 Tcl_DecrRefCount(wmPtr->crefObj);
3162 }
3163 wmPtr->crefObj = objv[i+1];
3164 Tcl_IncrRefCount(wmPtr->crefObj);
3165 wmPtr->colorref = RGB((BYTE) (cPtr->red >> 8),
3166 (BYTE) (cPtr->green >> 8),
3167 (BYTE) (cPtr->blue >> 8));
3168 Tk_FreeColor(cPtr);
3169 }
3170 }
3171
3172 /*
3173 * Only ever add the WS_EX_LAYERED bit, as it can cause
3174 * flashing to change this window style. This allows things
3175 * like fading tooltips to avoid flash ugliness without
3176 * forcing all window to be layered.
3177 */
3178
3179 if ((wmPtr->alpha < 1.0) || (wmPtr->crefObj != NULL)) {
3180 *stylePtr |= styleBit;
3181 }
3182 if (wmPtr->wrapper != NULL) {
3183 /*
3184 * Set the window directly regardless of UpdateWrapper.
3185 * The user supplies a double from [0..1], but Windows
3186 * wants an int (transparent) 0..255 (opaque), so do the
3187 * translation. Add the 0.5 to round the value.
3188 */
3189
3190 if (!(wmPtr->exStyleConfig & WS_EX_LAYERED)) {
3191 SetWindowLongPtrW(wmPtr->wrapper, GWL_EXSTYLE,
3192 *stylePtr);
3193 }
3194 SetLayeredWindowAttributes((HWND) wmPtr->wrapper,
3195 wmPtr->colorref, (BYTE) (wmPtr->alpha * 255 + 0.5),
3196 (unsigned) (LWA_ALPHA |
3197 (wmPtr->crefObj ? LWA_COLORKEY : 0)));
3198 }
3199 }
3200 } else {
3201 if ((i < objc-1)
3202 && Tcl_GetBooleanFromObj(interp, objv[i+1], &boolean)
3203 != TCL_OK) {
3204 return TCL_ERROR;
3205 }
3206 if (config_fullscreen) {
3207 if (objc == 4) {
3208 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
3209 wmPtr->flags & WM_FULLSCREEN));
3210 } else {
3211 fullscreen_attr_changed = 1;
3212 fullscreen_attr = boolean;
3213 }
3214 config_fullscreen = 0;
3215 } else if (objc == 4) {
3216 Tcl_SetObjResult(interp,
3217 Tcl_NewBooleanObj(*stylePtr & styleBit));
3218 } else if (boolean) {
3219 *stylePtr |= styleBit;
3220 } else {
3221 *stylePtr &= ~styleBit;
3222 }
3223 }
3224 if ((styleBit == WS_EX_TOPMOST) && (wmPtr->wrapper != NULL)) {
3225 /*
3226 * Force the topmost position aspect to ensure that switching
3227 * between (no)topmost reflects properly when rewrapped.
3228 */
3229
3230 SetWindowPos(wmPtr->wrapper,
3231 ((exStyle & WS_EX_TOPMOST) ?
3232 HWND_TOPMOST : HWND_NOTOPMOST), 0, 0, 0, 0,
3233 SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOSENDCHANGING
3234 |SWP_NOOWNERZORDER);
3235 }
3236 }
3237 if (wmPtr->styleConfig != style) {
3238 /*
3239 * Currently this means only WS_DISABLED changed, which we can effect
3240 * with EnableWindow.
3241 */
3242
3243 wmPtr->styleConfig = style;
3244 if ((wmPtr->exStyleConfig == exStyle)
3245 && !(wmPtr->flags & WM_NEVER_MAPPED)) {
3246 EnableWindow(wmPtr->wrapper, (style & WS_DISABLED) ? 0 : 1);
3247 }
3248 }
3249 if (wmPtr->exStyleConfig != exStyle) {
3250 wmPtr->exStyleConfig = exStyle;
3251 if (updatewrapper) {
3252 /*
3253 * UpdateWrapper ensure that all effects are properly handled,
3254 * such as TOOLWINDOW disappearing from the taskbar.
3255 */
3256
3257 if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
3258 UpdateWrapper(winPtr);
3259 }
3260 }
3261 }
3262 if (fullscreen_attr_changed) {
3263 if (fullscreen_attr) {
3264 if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
3265 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
3266 "can't set fullscreen attribute for \"%s\":"
3267 " override-redirect flag is set", winPtr->pathName));
3268 Tcl_SetErrorCode(interp, "TK", "WM", "ATTR",
3269 "OVERRIDE_REDIRECT", NULL);
3270 return TCL_ERROR;
3271 }
3272
3273 /*
3274 * Check max width and height if set by the user, don't worry
3275 * about the default values since they will likely be smaller than
3276 * screen width/height.
3277 */
3278
3279 if (((wmPtr->maxWidth > 0) &&
3280 (WidthOfScreen(Tk_Screen(winPtr)) > wmPtr->maxWidth)) ||
3281 ((wmPtr->maxHeight > 0) &&
3282 (HeightOfScreen(Tk_Screen(winPtr)) > wmPtr->maxHeight))) {
3283 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
3284 "can't set fullscreen attribute for \"%s\":"
3285 " max width/height is too small", winPtr->pathName));
3286 Tcl_SetErrorCode(interp, "TK", "WM", "ATTR", "SMALL_MAX", NULL);
3287 return TCL_ERROR;
3288 }
3289 }
3290
3291 TkpWmSetFullScreen(winPtr, fullscreen_attr);
3292 }
3293
3294 return TCL_OK;
3295 }
3296
3297 /*
3298 *----------------------------------------------------------------------
3299 *
3300 * WmClientCmd --
3301 *
3302 * This function is invoked to process the "wm client" Tcl command. See
3303 * the user documentation for details on what it does.
3304 *
3305 * Results:
3306 * A standard Tcl result.
3307 *
3308 * Side effects:
3309 * See the user documentation.
3310 *
3311 *----------------------------------------------------------------------
3312 */
3313
3314 static int
WmClientCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])3315 WmClientCmd(
3316 TCL_UNUSED(Tk_Window), /* Main window of the application. */
3317 TkWindow *winPtr, /* Toplevel to work with */
3318 Tcl_Interp *interp, /* Current interpreter. */
3319 int objc, /* Number of arguments. */
3320 Tcl_Obj *const objv[]) /* Argument objects. */
3321 {
3322 WmInfo *wmPtr = winPtr->wmInfoPtr;
3323 const char *argv3;
3324 int length;
3325
3326 if ((objc != 3) && (objc != 4)) {
3327 Tcl_WrongNumArgs(interp, 2, objv, "window ?name?");
3328 return TCL_ERROR;
3329 }
3330 if (objc == 3) {
3331 if (wmPtr->clientMachine != NULL) {
3332 Tcl_SetObjResult(interp,
3333 Tcl_NewStringObj(wmPtr->clientMachine, -1));
3334 }
3335 return TCL_OK;
3336 }
3337 argv3 = Tcl_GetStringFromObj(objv[3], &length);
3338 if (argv3[0] == 0) {
3339 if (wmPtr->clientMachine != NULL) {
3340 ckfree(wmPtr->clientMachine);
3341 wmPtr->clientMachine = NULL;
3342 if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
3343 XDeleteProperty(winPtr->display, winPtr->window,
3344 Tk_InternAtom((Tk_Window) winPtr,"WM_CLIENT_MACHINE"));
3345 }
3346 }
3347 return TCL_OK;
3348 }
3349 if (wmPtr->clientMachine != NULL) {
3350 ckfree(wmPtr->clientMachine);
3351 }
3352 wmPtr->clientMachine = (char *)ckalloc(length + 1);
3353 memcpy(wmPtr->clientMachine, argv3, length + 1);
3354 if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
3355 XTextProperty textProp;
3356
3357 if (XStringListToTextProperty(&wmPtr->clientMachine, 1, &textProp)
3358 != 0) {
3359 XSetWMClientMachine(winPtr->display, winPtr->window,
3360 &textProp);
3361 XFree((char *) textProp.value);
3362 }
3363 }
3364 return TCL_OK;
3365 }
3366
3367 /*
3368 *----------------------------------------------------------------------
3369 *
3370 * WmColormapwindowsCmd --
3371 *
3372 * This function is invoked to process the "wm colormapwindows" Tcl
3373 * command. See the user documentation for details on what it does.
3374 *
3375 * Results:
3376 * A standard Tcl result.
3377 *
3378 * Side effects:
3379 * See the user documentation.
3380 *
3381 *----------------------------------------------------------------------
3382 */
3383
3384 static int
WmColormapwindowsCmd(Tk_Window tkwin,TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])3385 WmColormapwindowsCmd(
3386 Tk_Window tkwin, /* Main window of the application. */
3387 TkWindow *winPtr, /* Toplevel to work with */
3388 Tcl_Interp *interp, /* Current interpreter. */
3389 int objc, /* Number of arguments. */
3390 Tcl_Obj *const objv[]) /* Argument objects. */
3391 {
3392 WmInfo *wmPtr = winPtr->wmInfoPtr;
3393 TkWindow **cmapList, *winPtr2, **winPtr2Ptr = &winPtr2;
3394 int i, windowObjc, gotToplevel;
3395 Tcl_Obj **windowObjv, *resultObj;
3396
3397 if ((objc != 3) && (objc != 4)) {
3398 Tcl_WrongNumArgs(interp, 2, objv, "window ?windowList?");
3399 return TCL_ERROR;
3400 }
3401 if (objc == 3) {
3402 Tk_MakeWindowExist((Tk_Window) winPtr);
3403 resultObj = Tcl_NewObj();
3404 for (i = 0; i < wmPtr->cmapCount; i++) {
3405 if ((i == (wmPtr->cmapCount-1))
3406 && (wmPtr->flags & WM_ADDED_TOPLEVEL_COLORMAP)) {
3407 break;
3408 }
3409 Tcl_ListObjAppendElement(NULL, resultObj,
3410 TkNewWindowObj((Tk_Window) wmPtr->cmapList[i]));
3411 }
3412 Tcl_SetObjResult(interp, resultObj);
3413 return TCL_OK;
3414 }
3415 if (Tcl_ListObjGetElements(interp, objv[3], &windowObjc, &windowObjv)
3416 != TCL_OK) {
3417 return TCL_ERROR;
3418 }
3419 cmapList = (TkWindow**)ckalloc((windowObjc + 1) * sizeof(TkWindow*));
3420 gotToplevel = 0;
3421 for (i = 0; i < windowObjc; i++) {
3422 if (TkGetWindowFromObj(interp, tkwin, windowObjv[i],
3423 (Tk_Window *) winPtr2Ptr) != TCL_OK) {
3424 ckfree(cmapList);
3425 return TCL_ERROR;
3426 }
3427 if (winPtr2 == winPtr) {
3428 gotToplevel = 1;
3429 }
3430 if (winPtr2->window == None) {
3431 Tk_MakeWindowExist((Tk_Window) winPtr2);
3432 }
3433 cmapList[i] = winPtr2;
3434 }
3435 if (!gotToplevel) {
3436 wmPtr->flags |= WM_ADDED_TOPLEVEL_COLORMAP;
3437 cmapList[windowObjc] = winPtr;
3438 windowObjc++;
3439 } else {
3440 wmPtr->flags &= ~WM_ADDED_TOPLEVEL_COLORMAP;
3441 }
3442 wmPtr->flags |= WM_COLORMAPS_EXPLICIT;
3443 if (wmPtr->cmapList != NULL) {
3444 ckfree(wmPtr->cmapList);
3445 }
3446 wmPtr->cmapList = cmapList;
3447 wmPtr->cmapCount = windowObjc;
3448
3449 /*
3450 * Now we need to force the updated colormaps to be installed.
3451 */
3452
3453 if (wmPtr == winPtr->dispPtr->foregroundWmPtr) {
3454 InstallColormaps(wmPtr->wrapper, WM_QUERYNEWPALETTE, 1);
3455 } else {
3456 InstallColormaps(wmPtr->wrapper, WM_PALETTECHANGED, 0);
3457 }
3458 return TCL_OK;
3459 }
3460
3461 /*
3462 *----------------------------------------------------------------------
3463 *
3464 * WmCommandCmd --
3465 *
3466 * This function is invoked to process the "wm command" Tcl command. See
3467 * the user documentation for details on what it does.
3468 *
3469 * Results:
3470 * A standard Tcl result.
3471 *
3472 * Side effects:
3473 * See the user documentation.
3474 *
3475 *----------------------------------------------------------------------
3476 */
3477
3478 static int
WmCommandCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])3479 WmCommandCmd(
3480 TCL_UNUSED(Tk_Window), /* Main window of the application. */
3481 TkWindow *winPtr, /* Toplevel to work with */
3482 Tcl_Interp *interp, /* Current interpreter. */
3483 int objc, /* Number of arguments. */
3484 Tcl_Obj *const objv[]) /* Argument objects. */
3485 {
3486 WmInfo *wmPtr = winPtr->wmInfoPtr;
3487 const char *argv3;
3488 int cmdArgc;
3489 const char **cmdArgv;
3490
3491 if ((objc != 3) && (objc != 4)) {
3492 Tcl_WrongNumArgs(interp, 2, objv, "window ?value?");
3493 return TCL_ERROR;
3494 }
3495 if (objc == 3) {
3496 if (wmPtr->cmdArgv != NULL) {
3497 char *merged = Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv);
3498
3499 Tcl_SetObjResult(interp, Tcl_NewStringObj(merged, -1));
3500 ckfree(merged);
3501 }
3502 return TCL_OK;
3503 }
3504 argv3 = Tcl_GetString(objv[3]);
3505 if (argv3[0] == 0) {
3506 if (wmPtr->cmdArgv != NULL) {
3507 ckfree(wmPtr->cmdArgv);
3508 wmPtr->cmdArgv = NULL;
3509 if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
3510 XDeleteProperty(winPtr->display, winPtr->window,
3511 Tk_InternAtom((Tk_Window) winPtr, "WM_COMMAND"));
3512 }
3513 }
3514 return TCL_OK;
3515 }
3516 if (Tcl_SplitList(interp, argv3, &cmdArgc, &cmdArgv) != TCL_OK) {
3517 return TCL_ERROR;
3518 }
3519 if (wmPtr->cmdArgv != NULL) {
3520 ckfree(wmPtr->cmdArgv);
3521 }
3522 wmPtr->cmdArgc = cmdArgc;
3523 wmPtr->cmdArgv = cmdArgv;
3524 if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
3525 XSetCommand(winPtr->display, winPtr->window, (char **) cmdArgv, cmdArgc);
3526 }
3527 return TCL_OK;
3528 }
3529
3530 /*
3531 *----------------------------------------------------------------------
3532 *
3533 * WmDeiconifyCmd --
3534 *
3535 * This function is invoked to process the "wm deiconify" Tcl command.
3536 * See the user documentation for details on what it does.
3537 *
3538 * Results:
3539 * A standard Tcl result.
3540 *
3541 * Side effects:
3542 * See the user documentation.
3543 *
3544 *----------------------------------------------------------------------
3545 */
3546
3547 static int
WmDeiconifyCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])3548 WmDeiconifyCmd(
3549 TCL_UNUSED(Tk_Window), /* Main window of the application. */
3550 TkWindow *winPtr, /* Toplevel to work with */
3551 Tcl_Interp *interp, /* Current interpreter. */
3552 int objc, /* Number of arguments. */
3553 Tcl_Obj *const objv[]) /* Argument objects. */
3554 {
3555 WmInfo *wmPtr = winPtr->wmInfoPtr;
3556
3557 if (objc != 3) {
3558 Tcl_WrongNumArgs(interp, 2, objv, "window");
3559 return TCL_ERROR;
3560 }
3561 if (wmPtr->iconFor != NULL) {
3562 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
3563 "can't deiconify %s: it is an icon for %s",
3564 Tcl_GetString(objv[2]), Tk_PathName(wmPtr->iconFor)));
3565 Tcl_SetErrorCode(interp, "TK", "WM", "DEICONIFY", "ICON", NULL);
3566 return TCL_ERROR;
3567 }
3568 if (winPtr->flags & TK_EMBEDDED) {
3569 if (!SendMessageW(wmPtr->wrapper, TK_DEICONIFY, 0, 0)) {
3570 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
3571 "can't deiconify %s: the container does not support the request",
3572 winPtr->pathName));
3573 Tcl_SetErrorCode(interp, "TK", "WM", "COMMUNICATION", NULL);
3574 return TCL_ERROR;
3575 }
3576 return TCL_OK;
3577 }
3578 TkpWinToplevelDeiconify(winPtr);
3579 return TCL_OK;
3580 }
3581
3582 /*
3583 *----------------------------------------------------------------------
3584 *
3585 * WmFocusmodelCmd --
3586 *
3587 * This function is invoked to process the "wm focusmodel" Tcl command.
3588 * See the user documentation for details on what it does.
3589 *
3590 * Results:
3591 * A standard Tcl result.
3592 *
3593 * Side effects:
3594 * See the user documentation.
3595 *
3596 *----------------------------------------------------------------------
3597 */
3598
3599 static int
WmFocusmodelCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])3600 WmFocusmodelCmd(
3601 TCL_UNUSED(Tk_Window), /* Main window of the application. */
3602 TkWindow *winPtr, /* Toplevel to work with */
3603 Tcl_Interp *interp, /* Current interpreter. */
3604 int objc, /* Number of arguments. */
3605 Tcl_Obj *const objv[]) /* Argument objects. */
3606 {
3607 WmInfo *wmPtr = winPtr->wmInfoPtr;
3608 static const char *const optionStrings[] = {
3609 "active", "passive", NULL
3610 };
3611 enum options {
3612 OPT_ACTIVE, OPT_PASSIVE
3613 };
3614 int index;
3615
3616 if ((objc != 3) && (objc != 4)) {
3617 Tcl_WrongNumArgs(interp, 2, objv, "window ?active|passive?");
3618 return TCL_ERROR;
3619 }
3620 if (objc == 3) {
3621 Tcl_SetObjResult(interp, Tcl_NewStringObj(
3622 wmPtr->hints.input ? "passive" : "active", -1));
3623 return TCL_OK;
3624 }
3625
3626 if (Tcl_GetIndexFromObjStruct(interp, objv[3], optionStrings,
3627 sizeof(char *), "argument", 0,&index) != TCL_OK) {
3628 return TCL_ERROR;
3629 }
3630 if (index == OPT_ACTIVE) {
3631 wmPtr->hints.input = False;
3632 } else { /* OPT_PASSIVE */
3633 wmPtr->hints.input = True;
3634 }
3635 return TCL_OK;
3636 }
3637
3638 /*
3639 *----------------------------------------------------------------------
3640 *
3641 * WmForgetCmd --
3642 *
3643 * This procedure is invoked to process the "wm forget" Tcl command.
3644 * See the user documentation for details on what it does.
3645 *
3646 * Results:
3647 * A standard Tcl result.
3648 *
3649 * Side effects:
3650 * See the user documentation.
3651 *
3652 *----------------------------------------------------------------------
3653 */
3654
3655 static int
WmForgetCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,TCL_UNUSED (int),TCL_UNUSED (Tcl_Obj * const *))3656 WmForgetCmd(
3657 TCL_UNUSED(Tk_Window), /* Main window of the application. */
3658 TkWindow *winPtr, /* Toplevel or Frame to work with */
3659 Tcl_Interp *interp, /* Current interpreter. */
3660 TCL_UNUSED(int), /* Number of arguments. */
3661 TCL_UNUSED(Tcl_Obj *const *)) /* Argument objects. */
3662 {
3663 Tk_Window frameWin = (Tk_Window) winPtr;
3664
3665 if (Tk_IsTopLevel(frameWin)) {
3666 Tk_UnmapWindow(frameWin);
3667 winPtr->flags &= ~(TK_TOP_HIERARCHY|TK_TOP_LEVEL|TK_HAS_WRAPPER|TK_WIN_MANAGED);
3668 Tk_MakeWindowExist((Tk_Window)winPtr->parentPtr);
3669 RemapWindows(winPtr, Tk_GetHWND(winPtr->parentPtr->window));
3670
3671 /*
3672 * Make sure wm no longer manages this window
3673 */
3674 Tk_ManageGeometry(frameWin, NULL, NULL);
3675
3676 TkWmDeadWindow(winPtr);
3677 /* flags (above) must be cleared before calling */
3678 /* TkMapTopFrame (below) */
3679 TkMapTopFrame(frameWin);
3680 } else {
3681 /* Already not managed by wm - ignore it */
3682 }
3683 return TCL_OK;
3684 }
3685
3686 /*
3687 *----------------------------------------------------------------------
3688 *
3689 * WmFrameCmd --
3690 *
3691 * This function is invoked to process the "wm frame" Tcl command. See
3692 * the user documentation for details on what it does.
3693 *
3694 * Results:
3695 * A standard Tcl result.
3696 *
3697 * Side effects:
3698 * See the user documentation.
3699 *
3700 *----------------------------------------------------------------------
3701 */
3702
3703 static int
WmFrameCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])3704 WmFrameCmd(
3705 TCL_UNUSED(Tk_Window), /* Main window of the application. */
3706 TkWindow *winPtr, /* Toplevel to work with */
3707 Tcl_Interp *interp, /* Current interpreter. */
3708 int objc, /* Number of arguments. */
3709 Tcl_Obj *const objv[]) /* Argument objects. */
3710 {
3711 WmInfo *wmPtr = winPtr->wmInfoPtr;
3712 HWND hwnd;
3713 char buf[TCL_INTEGER_SPACE];
3714
3715 if (objc != 3) {
3716 Tcl_WrongNumArgs(interp, 2, objv, "window");
3717 return TCL_ERROR;
3718 }
3719 if (Tk_WindowId((Tk_Window) winPtr) == None) {
3720 Tk_MakeWindowExist((Tk_Window) winPtr);
3721 }
3722 hwnd = wmPtr->wrapper;
3723 if (hwnd == NULL) {
3724 hwnd = Tk_GetHWND(Tk_WindowId((Tk_Window) winPtr));
3725 }
3726 sprintf(buf, "0x%" TCL_Z_MODIFIER "x", (size_t)hwnd);
3727 Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, -1));
3728 return TCL_OK;
3729 }
3730
3731 /*
3732 *----------------------------------------------------------------------
3733 *
3734 * WmGeometryCmd --
3735 *
3736 * This function is invoked to process the "wm geometry" Tcl command.
3737 * See the user documentation for details on what it does.
3738 *
3739 * Results:
3740 * A standard Tcl result.
3741 *
3742 * Side effects:
3743 * See the user documentation.
3744 *
3745 *----------------------------------------------------------------------
3746 */
3747
3748 static int
WmGeometryCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])3749 WmGeometryCmd(
3750 TCL_UNUSED(Tk_Window), /* Main window of the application. */
3751 TkWindow *winPtr, /* Toplevel to work with */
3752 Tcl_Interp *interp, /* Current interpreter. */
3753 int objc, /* Number of arguments. */
3754 Tcl_Obj *const objv[]) /* Argument objects. */
3755 {
3756 WmInfo *wmPtr = winPtr->wmInfoPtr;
3757 char xSign, ySign;
3758 int width, height;
3759 const char *argv3;
3760
3761 if ((objc != 3) && (objc != 4)) {
3762 Tcl_WrongNumArgs(interp, 2, objv, "window ?newGeometry?");
3763 return TCL_ERROR;
3764 }
3765
3766 if (objc == 3) {
3767 xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+';
3768 ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+';
3769 if (wmPtr->gridWin != NULL) {
3770 width = wmPtr->reqGridWidth + (winPtr->changes.width
3771 - winPtr->reqWidth)/wmPtr->widthInc;
3772 height = wmPtr->reqGridHeight + (winPtr->changes.height
3773 - winPtr->reqHeight)/wmPtr->heightInc;
3774 } else {
3775 width = winPtr->changes.width;
3776 height = winPtr->changes.height;
3777 }
3778 if (winPtr->flags & TK_EMBEDDED) {
3779 int result = SendMessageW(wmPtr->wrapper, TK_MOVEWINDOW, -1, -1);
3780
3781 wmPtr->x = result >> 16;
3782 wmPtr->y = result & 0x0000ffff;
3783 }
3784 Tcl_SetObjResult(interp, Tcl_ObjPrintf("%dx%d%c%d%c%d",
3785 width, height, xSign, wmPtr->x, ySign, wmPtr->y));
3786 return TCL_OK;
3787 }
3788
3789 argv3 = Tcl_GetString(objv[3]);
3790 if (*argv3 == '\0') {
3791 wmPtr->width = -1;
3792 wmPtr->height = -1;
3793 WmUpdateGeom(wmPtr, winPtr);
3794 return TCL_OK;
3795 }
3796 return ParseGeometry(interp, argv3, winPtr);
3797 }
3798
3799 /*
3800 *----------------------------------------------------------------------
3801 *
3802 * WmGridCmd --
3803 *
3804 * This function is invoked to process the "wm grid" Tcl command. See the
3805 * user documentation for details on what it does.
3806 *
3807 * Results:
3808 * A standard Tcl result.
3809 *
3810 * Side effects:
3811 * See the user documentation.
3812 *
3813 *----------------------------------------------------------------------
3814 */
3815
3816 static int
WmGridCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])3817 WmGridCmd(
3818 TCL_UNUSED(Tk_Window), /* Main window of the application. */
3819 TkWindow *winPtr, /* Toplevel to work with */
3820 Tcl_Interp *interp, /* Current interpreter. */
3821 int objc, /* Number of arguments. */
3822 Tcl_Obj *const objv[]) /* Argument objects. */
3823 {
3824 WmInfo *wmPtr = winPtr->wmInfoPtr;
3825 int reqWidth, reqHeight, widthInc, heightInc;
3826
3827 if ((objc != 3) && (objc != 7)) {
3828 Tcl_WrongNumArgs(interp, 2, objv,
3829 "window ?baseWidth baseHeight widthInc heightInc?");
3830 return TCL_ERROR;
3831 }
3832 if (objc == 3) {
3833 if (wmPtr->sizeHintsFlags & PBaseSize) {
3834 Tcl_Obj *results[4];
3835
3836 results[0] = Tcl_NewIntObj(wmPtr->reqGridWidth);
3837 results[1] = Tcl_NewIntObj(wmPtr->reqGridHeight);
3838 results[2] = Tcl_NewIntObj(wmPtr->widthInc);
3839 results[3] = Tcl_NewIntObj(wmPtr->heightInc);
3840 Tcl_SetObjResult(interp, Tcl_NewListObj(4, results));
3841 }
3842 return TCL_OK;
3843 }
3844 if (*Tcl_GetString(objv[3]) == '\0') {
3845 /*
3846 * Turn off gridding and reset the width and height to make sense as
3847 * ungridded numbers.
3848 */
3849
3850 wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
3851 if (wmPtr->width != -1) {
3852 wmPtr->width = winPtr->reqWidth + (wmPtr->width
3853 - wmPtr->reqGridWidth)*wmPtr->widthInc;
3854 wmPtr->height = winPtr->reqHeight + (wmPtr->height
3855 - wmPtr->reqGridHeight)*wmPtr->heightInc;
3856 }
3857 wmPtr->widthInc = 1;
3858 wmPtr->heightInc = 1;
3859 } else {
3860 if ((Tcl_GetIntFromObj(interp, objv[3], &reqWidth) != TCL_OK)
3861 || (Tcl_GetIntFromObj(interp, objv[4], &reqHeight) != TCL_OK)
3862 || (Tcl_GetIntFromObj(interp, objv[5], &widthInc) != TCL_OK)
3863 || (Tcl_GetIntFromObj(interp, objv[6], &heightInc) != TCL_OK)) {
3864 return TCL_ERROR;
3865 }
3866 if (reqWidth < 0) {
3867 Tcl_SetObjResult(interp, Tcl_NewStringObj(
3868 "baseWidth can't be < 0", -1));
3869 Tcl_SetErrorCode(interp, "TK", "VALUE", "GRID", NULL);
3870 return TCL_ERROR;
3871 }
3872 if (reqHeight < 0) {
3873 Tcl_SetObjResult(interp, Tcl_NewStringObj(
3874 "baseHeight can't be < 0", -1));
3875 Tcl_SetErrorCode(interp, "TK", "VALUE", "GRID", NULL);
3876 return TCL_ERROR;
3877 }
3878 if (widthInc <= 0) {
3879 Tcl_SetObjResult(interp, Tcl_NewStringObj(
3880 "widthInc can't be <= 0", -1));
3881 Tcl_SetErrorCode(interp, "TK", "VALUE", "GRID", NULL);
3882 return TCL_ERROR;
3883 }
3884 if (heightInc <= 0) {
3885 Tcl_SetObjResult(interp, Tcl_NewStringObj(
3886 "heightInc can't be <= 0", -1));
3887 Tcl_SetErrorCode(interp, "TK", "VALUE", "GRID", NULL);
3888 return TCL_ERROR;
3889 }
3890 Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc,
3891 heightInc);
3892 }
3893 WmUpdateGeom(wmPtr, winPtr);
3894 return TCL_OK;
3895 }
3896
3897 /*
3898 *----------------------------------------------------------------------
3899 *
3900 * WmGroupCmd --
3901 *
3902 * This function is invoked to process the "wm group" Tcl command. See
3903 * the user documentation for details on what it does.
3904 *
3905 * Results:
3906 * A standard Tcl result.
3907 *
3908 * Side effects:
3909 * See the user documentation.
3910 *
3911 *----------------------------------------------------------------------
3912 */
3913
3914 static int
WmGroupCmd(Tk_Window tkwin,TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])3915 WmGroupCmd(
3916 Tk_Window tkwin, /* Main window of the application. */
3917 TkWindow *winPtr, /* Toplevel to work with */
3918 Tcl_Interp *interp, /* Current interpreter. */
3919 int objc, /* Number of arguments. */
3920 Tcl_Obj *const objv[]) /* Argument objects. */
3921 {
3922 WmInfo *wmPtr = winPtr->wmInfoPtr;
3923 Tk_Window tkwin2;
3924 const char *argv3;
3925 int length;
3926
3927 if ((objc != 3) && (objc != 4)) {
3928 Tcl_WrongNumArgs(interp, 2, objv, "window ?pathName?");
3929 return TCL_ERROR;
3930 }
3931 if (objc == 3) {
3932 if (wmPtr->hints.flags & WindowGroupHint) {
3933 Tcl_SetObjResult(interp, Tcl_NewStringObj(wmPtr->leaderName, -1));
3934 }
3935 return TCL_OK;
3936 }
3937 argv3 = Tcl_GetStringFromObj(objv[3], &length);
3938 if (*argv3 == '\0') {
3939 wmPtr->hints.flags &= ~WindowGroupHint;
3940 if (wmPtr->leaderName != NULL) {
3941 ckfree(wmPtr->leaderName);
3942 }
3943 wmPtr->leaderName = NULL;
3944 } else {
3945 if (TkGetWindowFromObj(interp, tkwin, objv[3], &tkwin2) != TCL_OK) {
3946 return TCL_ERROR;
3947 }
3948 Tk_MakeWindowExist(tkwin2);
3949 if (wmPtr->leaderName != NULL) {
3950 ckfree(wmPtr->leaderName);
3951 }
3952 wmPtr->hints.window_group = Tk_WindowId(tkwin2);
3953 wmPtr->hints.flags |= WindowGroupHint;
3954 wmPtr->leaderName = (char *)ckalloc(length + 1);
3955 memcpy(wmPtr->leaderName, argv3, length + 1);
3956 }
3957 return TCL_OK;
3958 }
3959
3960 /*
3961 *----------------------------------------------------------------------
3962 *
3963 * WmIconbitmapCmd --
3964 *
3965 * This function is invoked to process the "wm iconbitmap" Tcl command.
3966 * See the user documentation for details on what it does.
3967 *
3968 * Results:
3969 * A standard Tcl result.
3970 *
3971 * Side effects:
3972 * See the user documentation.
3973 *
3974 *----------------------------------------------------------------------
3975 */
3976
3977 static int
WmIconbitmapCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])3978 WmIconbitmapCmd(
3979 TCL_UNUSED(Tk_Window), /* Main window of the application. */
3980 TkWindow *winPtr, /* Toplevel to work with */
3981 Tcl_Interp *interp, /* Current interpreter. */
3982 int objc, /* Number of arguments. */
3983 Tcl_Obj *const objv[]) /* Argument objects. */
3984 {
3985 WmInfo *wmPtr = winPtr->wmInfoPtr;
3986 TkWindow *useWinPtr = winPtr; /* window to apply to (NULL if -default) */
3987 const char *string;
3988
3989 if ((objc < 3) || (objc > 5)) {
3990 Tcl_WrongNumArgs(interp, 2, objv, "window ?-default? ?image?");
3991 return TCL_ERROR;
3992 } else if (objc == 5) {
3993 /*
3994 * If we have 5 arguments, we must have a '-default' flag.
3995 */
3996
3997 const char *argv3 = Tcl_GetString(objv[3]);
3998
3999 if (strcmp(argv3, "-default")) {
4000 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
4001 "illegal option \"%s\" must be \"-default\"", argv3));
4002 Tcl_SetErrorCode(interp, "TK", "WM", "ICONBITMAP", "OPTION",NULL);
4003 return TCL_ERROR;
4004 }
4005 useWinPtr = NULL;
4006 } else if (objc == 3) {
4007 /*
4008 * No arguments were given.
4009 */
4010
4011 if (wmPtr->hints.flags & IconPixmapHint) {
4012 Tcl_SetObjResult(interp, Tcl_NewStringObj(
4013 Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_pixmap),
4014 -1));
4015 }
4016 return TCL_OK;
4017 }
4018
4019 string = Tcl_GetString(objv[objc-1]);
4020 if (*string == '\0') {
4021 if (wmPtr->hints.icon_pixmap != None) {
4022 Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
4023 wmPtr->hints.icon_pixmap = None;
4024 }
4025 wmPtr->hints.flags &= ~IconPixmapHint;
4026 if (WinSetIcon(interp, NULL, (Tk_Window) useWinPtr) != TCL_OK) {
4027 return TCL_ERROR;
4028 }
4029 } else {
4030 /*
4031 * In the future this block of code will use Tk's 'image'
4032 * functionality to allow all supported image formats. However, this
4033 * will require a change to the way icons are handled. We will need to
4034 * add icon<->image conversions routines.
4035 *
4036 * Until that happens we simply try to find an icon in the given
4037 * argument, and if that fails, we use the older bitmap code. We do
4038 * things this way round (icon then bitmap), because the bitmap code
4039 * actually seems to have no visible effect, so we want to give the
4040 * icon code the first try at doing something.
4041 */
4042
4043 /*
4044 * Either return NULL, or return a valid titlebaricon with its ref
4045 * count already incremented.
4046 */
4047
4048 WinIconPtr titlebaricon = ReadIconFromFile(interp, objv[objc-1]);
4049 if (titlebaricon != NULL) {
4050 /*
4051 * Try to set the icon for the window. If it is a '-default' icon,
4052 * we must pass in NULL
4053 */
4054
4055 if (WinSetIcon(interp, titlebaricon, (Tk_Window) useWinPtr)
4056 != TCL_OK) {
4057 /*
4058 * We didn't use the titlebaricon after all.
4059 */
4060
4061 DecrIconRefCount(titlebaricon);
4062 titlebaricon = NULL;
4063 }
4064 }
4065 if (titlebaricon == NULL) {
4066 /*
4067 * We didn't manage to handle the argument as a valid icon. Try as
4068 * a bitmap. First we must clear the error message which was
4069 * placed in the interpreter.
4070 */
4071
4072 Pixmap pixmap;
4073
4074 Tcl_ResetResult(interp);
4075 pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr, string);
4076 if (pixmap == None) {
4077 return TCL_ERROR;
4078 }
4079 wmPtr->hints.icon_pixmap = pixmap;
4080 wmPtr->hints.flags |= IconPixmapHint;
4081 titlebaricon = GetIconFromPixmap(Tk_Display(winPtr), pixmap);
4082 if (titlebaricon != NULL && WinSetIcon(interp, titlebaricon,
4083 (Tk_Window) useWinPtr) != TCL_OK) {
4084 /*
4085 * We didn't use the titlebaricon after all.
4086 */
4087
4088 DecrIconRefCount(titlebaricon);
4089 titlebaricon = NULL;
4090 }
4091 }
4092 }
4093 return TCL_OK;
4094 }
4095
4096 /*
4097 *----------------------------------------------------------------------
4098 *
4099 * WmIconifyCmd --
4100 *
4101 * This function is invoked to process the "wm iconify" Tcl command. See
4102 * the user documentation for details on what it does.
4103 *
4104 * Results:
4105 * A standard Tcl result.
4106 *
4107 * Side effects:
4108 * See the user documentation.
4109 *
4110 *----------------------------------------------------------------------
4111 */
4112
4113 static int
WmIconifyCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])4114 WmIconifyCmd(
4115 TCL_UNUSED(Tk_Window), /* Main window of the application. */
4116 TkWindow *winPtr, /* Toplevel to work with */
4117 Tcl_Interp *interp, /* Current interpreter. */
4118 int objc, /* Number of arguments. */
4119 Tcl_Obj *const objv[]) /* Argument objects. */
4120 {
4121 WmInfo *wmPtr = winPtr->wmInfoPtr;
4122
4123 if (objc != 3) {
4124 Tcl_WrongNumArgs(interp, 2, objv, "window");
4125 return TCL_ERROR;
4126 }
4127 if (winPtr->flags & TK_EMBEDDED) {
4128 if (!SendMessageW(wmPtr->wrapper, TK_ICONIFY, 0, 0)) {
4129 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
4130 "can't iconify %s: the container does not support the request",
4131 winPtr->pathName));
4132 Tcl_SetErrorCode(interp, "TK", "WM", "ICONIFY", "EMBEDDED", NULL);
4133 return TCL_ERROR;
4134 }
4135 }
4136 if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
4137 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
4138 "can't iconify \"%s\": override-redirect flag is set",
4139 winPtr->pathName));
4140 Tcl_SetErrorCode(interp, "TK", "WM", "ICONIFY", "OVERRIDE_REDIRECT",
4141 NULL);
4142 return TCL_ERROR;
4143 }
4144 if (wmPtr->containerPtr != NULL) {
4145 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
4146 "can't iconify \"%s\": it is a transient",
4147 winPtr->pathName));
4148 Tcl_SetErrorCode(interp, "TK", "WM", "ICONIFY", "TRANSIENT", NULL);
4149 return TCL_ERROR;
4150 }
4151 if (wmPtr->iconFor != NULL) {
4152 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
4153 "can't iconify %s: it is an icon for %s",
4154 winPtr->pathName, Tk_PathName(wmPtr->iconFor)));
4155 Tcl_SetErrorCode(interp, "TK", "WM", "ICONIFY", "ICON", NULL);
4156 return TCL_ERROR;
4157 }
4158 TkpWmSetState(winPtr, IconicState);
4159 return TCL_OK;
4160 }
4161
4162 /*
4163 *----------------------------------------------------------------------
4164 *
4165 * WmIconmaskCmd --
4166 *
4167 * This function is invoked to process the "wm iconmask" Tcl command.
4168 * See the user documentation for details on what it does.
4169 *
4170 * Results:
4171 * A standard Tcl result.
4172 *
4173 * Side effects:
4174 * See the user documentation.
4175 *
4176 *----------------------------------------------------------------------
4177 */
4178
4179 static int
WmIconmaskCmd(Tk_Window tkwin,TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])4180 WmIconmaskCmd(
4181 Tk_Window tkwin, /* Main window of the application. */
4182 TkWindow *winPtr, /* Toplevel to work with */
4183 Tcl_Interp *interp, /* Current interpreter. */
4184 int objc, /* Number of arguments. */
4185 Tcl_Obj *const objv[]) /* Argument objects. */
4186 {
4187 WmInfo *wmPtr = winPtr->wmInfoPtr;
4188 Pixmap pixmap;
4189 const char *argv3;
4190
4191 if ((objc != 3) && (objc != 4)) {
4192 Tcl_WrongNumArgs(interp, 2, objv, "window ?bitmap?");
4193 return TCL_ERROR;
4194 }
4195 if (objc == 3) {
4196 if (wmPtr->hints.flags & IconMaskHint) {
4197 Tcl_SetObjResult(interp, Tcl_NewStringObj(
4198 Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_mask),
4199 -1));
4200 }
4201 return TCL_OK;
4202 }
4203 argv3 = Tcl_GetString(objv[3]);
4204 if (*argv3 == '\0') {
4205 if (wmPtr->hints.icon_mask != None) {
4206 Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
4207 }
4208 wmPtr->hints.flags &= ~IconMaskHint;
4209 } else {
4210 pixmap = Tk_GetBitmap(interp, tkwin, argv3);
4211 if (pixmap == None) {
4212 return TCL_ERROR;
4213 }
4214 wmPtr->hints.icon_mask = pixmap;
4215 wmPtr->hints.flags |= IconMaskHint;
4216 }
4217 return TCL_OK;
4218 }
4219
4220 /*
4221 *----------------------------------------------------------------------
4222 *
4223 * WmIconnameCmd --
4224 *
4225 * This function is invoked to process the "wm iconname" Tcl command.
4226 * See the user documentation for details on what it does.
4227 *
4228 * Results:
4229 * A standard Tcl result.
4230 *
4231 * Side effects:
4232 * See the user documentation.
4233 *
4234 *----------------------------------------------------------------------
4235 */
4236
4237 static int
WmIconnameCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])4238 WmIconnameCmd(
4239 TCL_UNUSED(Tk_Window), /* Main window of the application. */
4240 TkWindow *winPtr, /* Toplevel to work with */
4241 Tcl_Interp *interp, /* Current interpreter. */
4242 int objc, /* Number of arguments. */
4243 Tcl_Obj *const objv[]) /* Argument objects. */
4244 {
4245 WmInfo *wmPtr = winPtr->wmInfoPtr;
4246 const char *argv3;
4247 int length;
4248
4249 if (objc > 4) {
4250 Tcl_WrongNumArgs(interp, 2, objv, "window ?newName?");
4251 return TCL_ERROR;
4252 }
4253 if (objc == 3) {
4254 Tcl_SetObjResult(interp, Tcl_NewStringObj(
4255 (wmPtr->iconName ? wmPtr->iconName : ""), -1));
4256 return TCL_OK;
4257 } else {
4258 if (wmPtr->iconName != NULL) {
4259 ckfree(wmPtr->iconName);
4260 }
4261 argv3 = Tcl_GetStringFromObj(objv[3], &length);
4262 wmPtr->iconName = (char *)ckalloc(length + 1);
4263 memcpy(wmPtr->iconName, argv3, length + 1);
4264 if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
4265 XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
4266 }
4267 }
4268 return TCL_OK;
4269 }
4270
4271 /*
4272 *----------------------------------------------------------------------
4273 *
4274 * WmIconphotoCmd --
4275 *
4276 * This function is invoked to process the "wm iconphoto" Tcl command.
4277 * See the user documentation for details on what it does.
4278 *
4279 * Results:
4280 * A standard Tcl result.
4281 *
4282 * Side effects:
4283 * See the user documentation.
4284 *
4285 *----------------------------------------------------------------------
4286 */
4287
4288 static int
WmIconphotoCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])4289 WmIconphotoCmd(
4290 TCL_UNUSED(Tk_Window), /* Main window of the application. */
4291 TkWindow *winPtr, /* Toplevel to work with */
4292 Tcl_Interp *interp, /* Current interpreter. */
4293 int objc, /* Number of arguments. */
4294 Tcl_Obj *const objv[]) /* Argument objects. */
4295 {
4296 TkWindow *useWinPtr = winPtr; /* window to apply to (NULL if -default) */
4297 Tk_PhotoHandle photo;
4298 Tk_PhotoImageBlock block;
4299 int i, width, height, idx, bufferSize, startObj = 3;
4300 union {unsigned char *ptr; void *voidPtr;} bgraPixel;
4301 union {unsigned char *ptr; void *voidPtr;} bgraMask;
4302 BlockOfIconImagesPtr lpIR;
4303 WinIconPtr titlebaricon = NULL;
4304 HICON hIcon;
4305 unsigned size;
4306 BITMAPINFO bmInfo;
4307 ICONINFO iconInfo;
4308
4309 if (objc < 4) {
4310 Tcl_WrongNumArgs(interp, 2, objv,
4311 "window ?-default? image1 ?image2 ...?");
4312 return TCL_ERROR;
4313 }
4314
4315 /*
4316 * Iterate over all images to validate their existence.
4317 */
4318
4319 if (strcmp(Tcl_GetString(objv[3]), "-default") == 0) {
4320 useWinPtr = NULL;
4321 startObj = 4;
4322 if (objc == 4) {
4323 Tcl_WrongNumArgs(interp, 2, objv,
4324 "window ?-default? image1 ?image2 ...?");
4325 return TCL_ERROR;
4326 }
4327 }
4328 for (i = startObj; i < objc; i++) {
4329 photo = Tk_FindPhoto(interp, Tcl_GetString(objv[i]));
4330 if (photo == NULL) {
4331 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
4332 "can't use \"%s\" as iconphoto: not a photo image",
4333 Tcl_GetString(objv[i])));
4334 Tcl_SetErrorCode(interp, "TK", "WM", "ICONPHOTO", "PHOTO", NULL);
4335 return TCL_ERROR;
4336 }
4337 }
4338
4339 /*
4340 * We have calculated the size of the data. Try to allocate the needed
4341 * memory space.
4342 */
4343
4344 size = sizeof(BlockOfIconImages) + (sizeof(ICONIMAGE) * (objc-startObj-1));
4345 lpIR = (BlockOfIconImagesPtr)attemptckalloc(size);
4346 if (lpIR == NULL) {
4347 return TCL_ERROR;
4348 }
4349 ZeroMemory(lpIR, size);
4350
4351 lpIR->nNumImages = objc - startObj;
4352
4353 for (i = startObj; i < objc; i++) {
4354 photo = Tk_FindPhoto(interp, Tcl_GetString(objv[i]));
4355 Tk_PhotoGetSize(photo, &width, &height);
4356 Tk_PhotoGetImage(photo, &block);
4357
4358 /*
4359 * Don't use CreateIcon to create the icon, as it requires color
4360 * bitmap data in device-dependent format. Instead we use
4361 * CreateIconIndirect which takes device-independent bitmaps and
4362 * converts them as required. Initialise icon info structure.
4363 */
4364
4365 ZeroMemory(&iconInfo, sizeof(iconInfo));
4366 iconInfo.fIcon = TRUE;
4367
4368 /*
4369 * Create device-independent color bitmap.
4370 */
4371
4372 ZeroMemory(&bmInfo, sizeof bmInfo);
4373 bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
4374 bmInfo.bmiHeader.biWidth = width;
4375 bmInfo.bmiHeader.biHeight = -height;
4376 bmInfo.bmiHeader.biPlanes = 1;
4377 bmInfo.bmiHeader.biBitCount = 32;
4378 bmInfo.bmiHeader.biCompression = BI_RGB;
4379
4380 iconInfo.hbmColor = CreateDIBSection(NULL, &bmInfo, DIB_RGB_COLORS,
4381 &bgraPixel.voidPtr, NULL, 0);
4382 if (!iconInfo.hbmColor) {
4383 ckfree(lpIR);
4384 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
4385 "failed to create an iconphoto with image \"%s\"",
4386 Tcl_GetString(objv[i])));
4387 Tcl_SetErrorCode(interp, "TK", "WM", "ICONPHOTO", "IMAGE", NULL);
4388 return TCL_ERROR;
4389 }
4390
4391 /*
4392 * Convert the photo image data into BGRA format (RGBQUAD).
4393 */
4394
4395 bufferSize = height * width * 4;
4396 for (idx = 0 ; idx < bufferSize ; idx += 4) {
4397 bgraPixel.ptr[idx] = block.pixelPtr[idx+2];
4398 bgraPixel.ptr[idx+1] = block.pixelPtr[idx+1];
4399 bgraPixel.ptr[idx+2] = block.pixelPtr[idx+0];
4400 bgraPixel.ptr[idx+3] = block.pixelPtr[idx+3];
4401 }
4402
4403 /*
4404 * Create a dummy mask bitmap. The contents of this don't appear to
4405 * matter, as CreateIconIndirect will setup the icon mask based on the
4406 * alpha channel in our color bitmap.
4407 */
4408
4409 bmInfo.bmiHeader.biBitCount = 1;
4410
4411 iconInfo.hbmMask = CreateDIBSection(NULL, &bmInfo, DIB_RGB_COLORS,
4412 &bgraMask.voidPtr, NULL, 0);
4413 if (!iconInfo.hbmMask) {
4414 DeleteObject(iconInfo.hbmColor);
4415 ckfree(lpIR);
4416 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
4417 "failed to create mask bitmap for \"%s\"",
4418 Tcl_GetString(objv[i])));
4419 Tcl_SetErrorCode(interp, "TK", "WM", "ICONPHOTO", "MASK", NULL);
4420 return TCL_ERROR;
4421 }
4422
4423 ZeroMemory(bgraMask.ptr, width*height/8);
4424
4425 /*
4426 * Create an icon from the bitmaps.
4427 */
4428
4429 hIcon = CreateIconIndirect(&iconInfo);
4430 DeleteObject(iconInfo.hbmColor);
4431 DeleteObject(iconInfo.hbmMask);
4432 if (hIcon == NULL) {
4433 /*
4434 * XXX should free up created icons.
4435 */
4436
4437 ckfree(lpIR);
4438 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
4439 "failed to create icon for \"%s\"",
4440 Tcl_GetString(objv[i])));
4441 Tcl_SetErrorCode(interp, "TK", "WM", "ICONPHOTO", "ICON", NULL);
4442 return TCL_ERROR;
4443 }
4444 lpIR->IconImages[i-startObj].Width = width;
4445 lpIR->IconImages[i-startObj].Height = height;
4446 lpIR->IconImages[i-startObj].Colors = 4;
4447 lpIR->IconImages[i-startObj].hIcon = hIcon;
4448 }
4449
4450 titlebaricon = (WinIconPtr)ckalloc(sizeof(WinIconInstance));
4451 titlebaricon->iconBlock = lpIR;
4452 titlebaricon->refCount = 1;
4453 if (WinSetIcon(interp, titlebaricon, (Tk_Window) useWinPtr) != TCL_OK) {
4454 /*
4455 * We didn't use the titlebaricon after all.
4456 */
4457
4458 DecrIconRefCount(titlebaricon);
4459 return TCL_ERROR;
4460 }
4461 return TCL_OK;
4462 }
4463
4464 /*
4465 *----------------------------------------------------------------------
4466 *
4467 * WmIconpositionCmd --
4468 *
4469 * This function is invoked to process the "wm iconposition" Tcl command.
4470 * See the user documentation for details on what it does.
4471 *
4472 * Results:
4473 * A standard Tcl result.
4474 *
4475 * Side effects:
4476 * See the user documentation.
4477 *
4478 *----------------------------------------------------------------------
4479 */
4480
4481 static int
WmIconpositionCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])4482 WmIconpositionCmd(
4483 TCL_UNUSED(Tk_Window), /* Main window of the application. */
4484 TkWindow *winPtr, /* Toplevel to work with */
4485 Tcl_Interp *interp, /* Current interpreter. */
4486 int objc, /* Number of arguments. */
4487 Tcl_Obj *const objv[]) /* Argument objects. */
4488 {
4489 WmInfo *wmPtr = winPtr->wmInfoPtr;
4490 int x, y;
4491
4492 if ((objc != 3) && (objc != 5)) {
4493 Tcl_WrongNumArgs(interp, 2, objv, "window ?x y?");
4494 return TCL_ERROR;
4495 }
4496 if (objc == 3) {
4497 if (wmPtr->hints.flags & IconPositionHint) {
4498 Tcl_Obj *results[2];
4499
4500 results[0] = Tcl_NewIntObj(wmPtr->hints.icon_x);
4501 results[1] = Tcl_NewIntObj(wmPtr->hints.icon_y);
4502 Tcl_SetObjResult(interp, Tcl_NewListObj(2, results));
4503 }
4504 return TCL_OK;
4505 }
4506 if (*Tcl_GetString(objv[3]) == '\0') {
4507 wmPtr->hints.flags &= ~IconPositionHint;
4508 } else {
4509 if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK)
4510 || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)) {
4511 return TCL_ERROR;
4512 }
4513 wmPtr->hints.icon_x = x;
4514 wmPtr->hints.icon_y = y;
4515 wmPtr->hints.flags |= IconPositionHint;
4516 }
4517 return TCL_OK;
4518 }
4519
4520 /*
4521 *----------------------------------------------------------------------
4522 *
4523 * WmIconwindowCmd --
4524 *
4525 * This function is invoked to process the "wm iconwindow" Tcl command.
4526 * See the user documentation for details on what it does.
4527 *
4528 * Results:
4529 * A standard Tcl result.
4530 *
4531 * Side effects:
4532 * See the user documentation.
4533 *
4534 *----------------------------------------------------------------------
4535 */
4536
4537 static int
WmIconwindowCmd(Tk_Window tkwin,TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])4538 WmIconwindowCmd(
4539 Tk_Window tkwin, /* Main window of the application. */
4540 TkWindow *winPtr, /* Toplevel to work with */
4541 Tcl_Interp *interp, /* Current interpreter. */
4542 int objc, /* Number of arguments. */
4543 Tcl_Obj *const objv[]) /* Argument objects. */
4544 {
4545 WmInfo *wmPtr = winPtr->wmInfoPtr;
4546 Tk_Window tkwin2;
4547 WmInfo *wmPtr2;
4548 XSetWindowAttributes atts;
4549
4550 if ((objc != 3) && (objc != 4)) {
4551 Tcl_WrongNumArgs(interp, 2, objv, "window ?pathName?");
4552 return TCL_ERROR;
4553 }
4554 if (objc == 3) {
4555 if (wmPtr->icon != NULL) {
4556 Tcl_SetObjResult(interp, TkNewWindowObj(wmPtr->icon));
4557 }
4558 return TCL_OK;
4559 }
4560 if (*Tcl_GetString(objv[3]) == '\0') {
4561 wmPtr->hints.flags &= ~IconWindowHint;
4562 if (wmPtr->icon != NULL) {
4563 /*
4564 * Let the window use button events again, then remove it as icon
4565 * window.
4566 */
4567
4568 atts.event_mask = Tk_Attributes(wmPtr->icon)->event_mask
4569 | ButtonPressMask;
4570 Tk_ChangeWindowAttributes(wmPtr->icon, CWEventMask, &atts);
4571 wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
4572 wmPtr2->iconFor = NULL;
4573 wmPtr2->hints.initial_state = WithdrawnState;
4574 }
4575 wmPtr->icon = NULL;
4576 } else {
4577 if (TkGetWindowFromObj(interp, tkwin, objv[3], &tkwin2) != TCL_OK) {
4578 return TCL_ERROR;
4579 }
4580 if (!Tk_IsTopLevel(tkwin2)) {
4581 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
4582 "can't use %s as icon window: not at top level",
4583 Tcl_GetString(objv[3])));
4584 Tcl_SetErrorCode(interp, "TK", "WM", "ICONWINDOW", "INNER", NULL);
4585 return TCL_ERROR;
4586 }
4587 wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr;
4588 if (wmPtr2->iconFor != NULL) {
4589 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
4590 "%s is already an icon for %s",
4591 Tcl_GetString(objv[3]), Tk_PathName(wmPtr2->iconFor)));
4592 Tcl_SetErrorCode(interp, "TK", "WM", "ICONWINDOW", "ICON", NULL);
4593 return TCL_ERROR;
4594 }
4595 if (wmPtr->icon != NULL) {
4596 WmInfo *wmPtr3 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
4597 wmPtr3->iconFor = NULL;
4598
4599 /*
4600 * Let the window use button events again.
4601 */
4602
4603 atts.event_mask = Tk_Attributes(wmPtr->icon)->event_mask
4604 | ButtonPressMask;
4605 Tk_ChangeWindowAttributes(wmPtr->icon, CWEventMask, &atts);
4606 }
4607
4608 /*
4609 * Disable button events in the icon window: some window managers
4610 * (like olvwm) want to get the events themselves, but X only allows
4611 * one application at a time to receive button events for a window.
4612 */
4613
4614 atts.event_mask = Tk_Attributes(tkwin2)->event_mask
4615 & ~ButtonPressMask;
4616 Tk_ChangeWindowAttributes(tkwin2, CWEventMask, &atts);
4617 Tk_MakeWindowExist(tkwin2);
4618 wmPtr->hints.icon_window = Tk_WindowId(tkwin2);
4619 wmPtr->hints.flags |= IconWindowHint;
4620 wmPtr->icon = tkwin2;
4621 wmPtr2->iconFor = (Tk_Window) winPtr;
4622 if (!(wmPtr2->flags & WM_NEVER_MAPPED)) {
4623 wmPtr2->flags |= WM_WITHDRAWN;
4624 TkpWmSetState(((TkWindow *) tkwin2), WithdrawnState);
4625 }
4626 }
4627 return TCL_OK;
4628 }
4629
4630 /*
4631 *----------------------------------------------------------------------
4632 *
4633 * WmManageCmd --
4634 *
4635 * This procedure is invoked to process the "wm manage" Tcl command.
4636 * See the user documentation for details on what it does.
4637 *
4638 * Results:
4639 * A standard Tcl result.
4640 *
4641 * Side effects:
4642 * See the user documentation.
4643 *
4644 *----------------------------------------------------------------------
4645 */
4646
4647 static int
WmManageCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,TCL_UNUSED (int),TCL_UNUSED (Tcl_Obj * const *))4648 WmManageCmd(
4649 TCL_UNUSED(Tk_Window), /* Main window of the application. */
4650 TkWindow *winPtr, /* Toplevel or Frame to work with */
4651 Tcl_Interp *interp, /* Current interpreter. */
4652 TCL_UNUSED(int), /* Number of arguments. */
4653 TCL_UNUSED(Tcl_Obj *const *)) /* Argument objects. */
4654 {
4655 Tk_Window frameWin = (Tk_Window) winPtr;
4656 WmInfo *wmPtr = winPtr->wmInfoPtr;
4657
4658 if (!Tk_IsTopLevel(frameWin)) {
4659 if (!Tk_IsManageable(frameWin)) {
4660 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
4661 "window \"%s\" is not manageable: must be a frame,"
4662 " labelframe or toplevel", Tk_PathName(frameWin)));
4663 Tcl_SetErrorCode(interp, "TK", "WM", "MANAGE", NULL);
4664 return TCL_ERROR;
4665 }
4666 TkFocusSplit(winPtr);
4667 Tk_UnmapWindow(frameWin);
4668 winPtr->flags |= TK_TOP_HIERARCHY|TK_TOP_LEVEL|TK_HAS_WRAPPER|TK_WIN_MANAGED;
4669 RemapWindows(winPtr, NULL);
4670 if (wmPtr == NULL) {
4671 TkWmNewWindow(winPtr);
4672 }
4673 wmPtr = winPtr->wmInfoPtr;
4674 winPtr->flags &= ~TK_MAPPED;
4675 /* flags (above) must be set before calling */
4676 /* TkMapTopFrame (below) */
4677 TkMapTopFrame (frameWin);
4678 } else if (Tk_IsTopLevel(frameWin)) {
4679 /* Already managed by wm - ignore it */
4680 }
4681 return TCL_OK;
4682 }
4683
4684 /*
4685 *----------------------------------------------------------------------
4686 *
4687 * WmMaxsizeCmd --
4688 *
4689 * This function is invoked to process the "wm maxsize" Tcl command. See
4690 * the user documentation for details on what it does.
4691 *
4692 * Results:
4693 * A standard Tcl result.
4694 *
4695 * Side effects:
4696 * See the user documentation.
4697 *
4698 *----------------------------------------------------------------------
4699 */
4700
4701 static int
WmMaxsizeCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])4702 WmMaxsizeCmd(
4703 TCL_UNUSED(Tk_Window), /* Main window of the application. */
4704 TkWindow *winPtr, /* Toplevel to work with */
4705 Tcl_Interp *interp, /* Current interpreter. */
4706 int objc, /* Number of arguments. */
4707 Tcl_Obj *const objv[]) /* Argument objects. */
4708 {
4709 WmInfo *wmPtr = winPtr->wmInfoPtr;
4710 int width, height;
4711
4712 if ((objc != 3) && (objc != 5)) {
4713 Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?");
4714 return TCL_ERROR;
4715 }
4716 if (objc == 3) {
4717 Tcl_Obj *results[2];
4718
4719 GetMaxSize(wmPtr, &width, &height);
4720 results[0] = Tcl_NewIntObj(width);
4721 results[1] = Tcl_NewIntObj(height);
4722 Tcl_SetObjResult(interp, Tcl_NewListObj(2, results));
4723 return TCL_OK;
4724 }
4725 if ((Tcl_GetIntFromObj(interp, objv[3], &width) != TCL_OK)
4726 || (Tcl_GetIntFromObj(interp, objv[4], &height) != TCL_OK)) {
4727 return TCL_ERROR;
4728 }
4729 wmPtr->maxWidth = width;
4730 wmPtr->maxHeight = height;
4731 WmUpdateGeom(wmPtr, winPtr);
4732 return TCL_OK;
4733 }
4734
4735 /*
4736 *----------------------------------------------------------------------
4737 *
4738 * WmMinsizeCmd --
4739 *
4740 * This function is invoked to process the "wm minsize" Tcl command. See
4741 * the user documentation for details on what it does.
4742 *
4743 * Results:
4744 * A standard Tcl result.
4745 *
4746 * Side effects:
4747 * See the user documentation.
4748 *
4749 *----------------------------------------------------------------------
4750 */
4751
4752 static int
WmMinsizeCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])4753 WmMinsizeCmd(
4754 TCL_UNUSED(Tk_Window), /* Main window of the application. */
4755 TkWindow *winPtr, /* Toplevel to work with */
4756 Tcl_Interp *interp, /* Current interpreter. */
4757 int objc, /* Number of arguments. */
4758 Tcl_Obj *const objv[]) /* Argument objects. */
4759 {
4760 WmInfo *wmPtr = winPtr->wmInfoPtr;
4761 int width, height;
4762
4763 if ((objc != 3) && (objc != 5)) {
4764 Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?");
4765 return TCL_ERROR;
4766 }
4767 if (objc == 3) {
4768 Tcl_Obj *results[2];
4769
4770 GetMinSize(wmPtr, &width, &height);
4771 results[0] = Tcl_NewIntObj(width);
4772 results[1] = Tcl_NewIntObj(height);
4773 Tcl_SetObjResult(interp, Tcl_NewListObj(2, results));
4774 return TCL_OK;
4775 }
4776 if ((Tcl_GetIntFromObj(interp, objv[3], &width) != TCL_OK)
4777 || (Tcl_GetIntFromObj(interp, objv[4], &height) != TCL_OK)) {
4778 return TCL_ERROR;
4779 }
4780 wmPtr->minWidth = width;
4781 wmPtr->minHeight = height;
4782 WmUpdateGeom(wmPtr, winPtr);
4783 return TCL_OK;
4784 }
4785
4786 /*
4787 *----------------------------------------------------------------------
4788 *
4789 * WmOverrideredirectCmd --
4790 *
4791 * This function is invoked to process the "wm overrideredirect" Tcl
4792 * command. See the user documentation for details on what it does.
4793 *
4794 * Results:
4795 * A standard Tcl result.
4796 *
4797 * Side effects:
4798 * See the user documentation.
4799 *
4800 *----------------------------------------------------------------------
4801 */
4802
4803 static int
WmOverrideredirectCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])4804 WmOverrideredirectCmd(
4805 TCL_UNUSED(Tk_Window), /* Main window of the application. */
4806 TkWindow *winPtr, /* Toplevel to work with */
4807 Tcl_Interp *interp, /* Current interpreter. */
4808 int objc, /* Number of arguments. */
4809 Tcl_Obj *const objv[]) /* Argument objects. */
4810 {
4811 WmInfo *wmPtr = winPtr->wmInfoPtr;
4812 int boolean, curValue;
4813 XSetWindowAttributes atts;
4814
4815 if ((objc != 3) && (objc != 4)) {
4816 Tcl_WrongNumArgs(interp, 2, objv, "window ?boolean?");
4817 return TCL_ERROR;
4818 }
4819 if (winPtr->flags & TK_EMBEDDED) {
4820 curValue = SendMessageW(wmPtr->wrapper, TK_OVERRIDEREDIRECT, -1, -1)-1;
4821 if (curValue < 0) {
4822 Tcl_SetObjResult(interp, Tcl_NewStringObj(
4823 "Container does not support overrideredirect", -1));
4824 Tcl_SetErrorCode(interp, "TK", "WM", "COMMUNICATION", NULL);
4825 return TCL_ERROR;
4826 }
4827 } else {
4828 curValue = Tk_Attributes((Tk_Window) winPtr)->override_redirect;
4829 }
4830 if (objc == 3) {
4831 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(curValue));
4832 return TCL_OK;
4833 }
4834 if (Tcl_GetBooleanFromObj(interp, objv[3], &boolean) != TCL_OK) {
4835 return TCL_ERROR;
4836 }
4837 if (curValue != boolean) {
4838 if (winPtr->flags & TK_EMBEDDED) {
4839 SendMessageW(wmPtr->wrapper, TK_OVERRIDEREDIRECT, boolean, 0);
4840 } else {
4841 /*
4842 * Only do this if we are really changing value, because it causes
4843 * some funky stuff to occur.
4844 */
4845
4846 atts.override_redirect = (boolean) ? True : False;
4847 Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect,
4848 &atts);
4849 if (!(wmPtr->flags & (WM_NEVER_MAPPED))
4850 && !(winPtr->flags & TK_EMBEDDED)) {
4851 UpdateWrapper(winPtr);
4852 }
4853 }
4854 }
4855 return TCL_OK;
4856 }
4857
4858 /*
4859 *----------------------------------------------------------------------
4860 *
4861 * WmPositionfromCmd --
4862 *
4863 * This function is invoked to process the "wm positionfrom" Tcl command.
4864 * See the user documentation for details on what it does.
4865 *
4866 * Results:
4867 * A standard Tcl result.
4868 *
4869 * Side effects:
4870 * See the user documentation.
4871 *
4872 *----------------------------------------------------------------------
4873 */
4874
4875 static int
WmPositionfromCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])4876 WmPositionfromCmd(
4877 TCL_UNUSED(Tk_Window), /* Main window of the application. */
4878 TkWindow *winPtr, /* Toplevel to work with */
4879 Tcl_Interp *interp, /* Current interpreter. */
4880 int objc, /* Number of arguments. */
4881 Tcl_Obj *const objv[]) /* Argument objects. */
4882 {
4883 WmInfo *wmPtr = winPtr->wmInfoPtr;
4884 static const char *const optionStrings[] = {
4885 "program", "user", NULL
4886 };
4887 enum options {
4888 OPT_PROGRAM, OPT_USER
4889 };
4890 int index;
4891
4892 if ((objc != 3) && (objc != 4)) {
4893 Tcl_WrongNumArgs(interp, 2, objv, "window ?user/program?");
4894 return TCL_ERROR;
4895 }
4896 if (objc == 3) {
4897 const char *sourceStr = "";
4898
4899 if (wmPtr->sizeHintsFlags & USPosition) {
4900 sourceStr = "user";
4901 } else if (wmPtr->sizeHintsFlags & PPosition) {
4902 sourceStr = "program";
4903 }
4904 Tcl_SetObjResult(interp, Tcl_NewStringObj(sourceStr, -1));
4905 return TCL_OK;
4906 }
4907 if (*Tcl_GetString(objv[3]) == '\0') {
4908 wmPtr->sizeHintsFlags &= ~(USPosition|PPosition);
4909 } else {
4910 if (Tcl_GetIndexFromObjStruct(interp, objv[3], optionStrings,
4911 sizeof(char *), "argument", 0, &index) != TCL_OK) {
4912 return TCL_ERROR;
4913 }
4914 if (index == OPT_USER) {
4915 wmPtr->sizeHintsFlags &= ~PPosition;
4916 wmPtr->sizeHintsFlags |= USPosition;
4917 } else {
4918 wmPtr->sizeHintsFlags &= ~USPosition;
4919 wmPtr->sizeHintsFlags |= PPosition;
4920 }
4921 }
4922 WmUpdateGeom(wmPtr, winPtr);
4923 return TCL_OK;
4924 }
4925
4926 /*
4927 *----------------------------------------------------------------------
4928 *
4929 * WmProtocolCmd --
4930 *
4931 * This function is invoked to process the "wm protocol" Tcl command.
4932 * See the user documentation for details on what it does.
4933 *
4934 * Results:
4935 * A standard Tcl result.
4936 *
4937 * Side effects:
4938 * See the user documentation.
4939 *
4940 *----------------------------------------------------------------------
4941 */
4942
4943 static int
WmProtocolCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])4944 WmProtocolCmd(
4945 TCL_UNUSED(Tk_Window), /* Main window of the application. */
4946 TkWindow *winPtr, /* Toplevel to work with */
4947 Tcl_Interp *interp, /* Current interpreter. */
4948 int objc, /* Number of arguments. */
4949 Tcl_Obj *const objv[]) /* Argument objects. */
4950 {
4951 WmInfo *wmPtr = winPtr->wmInfoPtr;
4952 ProtocolHandler *protPtr, *prevPtr;
4953 Atom protocol;
4954 const char *cmd;
4955 int cmdLength;
4956 Tcl_Obj *resultObj;
4957
4958 if ((objc < 3) || (objc > 5)) {
4959 Tcl_WrongNumArgs(interp, 2, objv, "window ?name? ?command?");
4960 return TCL_ERROR;
4961 }
4962 if (objc == 3) {
4963 /*
4964 * Return a list of all defined protocols for the window.
4965 */
4966
4967 resultObj = Tcl_NewObj();
4968 for (protPtr = wmPtr->protPtr; protPtr != NULL;
4969 protPtr = protPtr->nextPtr) {
4970 Tcl_ListObjAppendElement(NULL, resultObj, Tcl_NewStringObj(
4971 Tk_GetAtomName((Tk_Window)winPtr, protPtr->protocol), -1));
4972 }
4973 Tcl_SetObjResult(interp, resultObj);
4974 return TCL_OK;
4975 }
4976 protocol = Tk_InternAtom((Tk_Window) winPtr, Tcl_GetString(objv[3]));
4977 if (objc == 4) {
4978 /*
4979 * Return the command to handle a given protocol.
4980 */
4981
4982 for (protPtr = wmPtr->protPtr; protPtr != NULL;
4983 protPtr = protPtr->nextPtr) {
4984 if (protPtr->protocol == protocol) {
4985 Tcl_SetObjResult(interp,
4986 Tcl_NewStringObj(protPtr->command, -1));
4987 return TCL_OK;
4988 }
4989 }
4990 return TCL_OK;
4991 }
4992
4993 /*
4994 * Delete any current protocol handler, then create a new one with the
4995 * specified command, unless the command is empty.
4996 */
4997
4998 for (protPtr = wmPtr->protPtr, prevPtr = NULL; protPtr != NULL;
4999 prevPtr = protPtr, protPtr = protPtr->nextPtr) {
5000 if (protPtr->protocol == protocol) {
5001 if (prevPtr == NULL) {
5002 wmPtr->protPtr = protPtr->nextPtr;
5003 } else {
5004 prevPtr->nextPtr = protPtr->nextPtr;
5005 }
5006 Tcl_EventuallyFree(protPtr, TCL_DYNAMIC);
5007 break;
5008 }
5009 }
5010 cmd = Tcl_GetStringFromObj(objv[4], &cmdLength);
5011 if (cmdLength > 0) {
5012 protPtr = (ProtocolHandler *)ckalloc(HANDLER_SIZE(cmdLength));
5013 protPtr->protocol = protocol;
5014 protPtr->nextPtr = wmPtr->protPtr;
5015 wmPtr->protPtr = protPtr;
5016 protPtr->interp = interp;
5017 memcpy(protPtr->command, cmd, cmdLength + 1);
5018 }
5019 return TCL_OK;
5020 }
5021
5022 /*
5023 *----------------------------------------------------------------------
5024 *
5025 * WmResizableCmd --
5026 *
5027 * This function is invoked to process the "wm resizable" Tcl command.
5028 * See the user documentation for details on what it does.
5029 *
5030 * Results:
5031 * A standard Tcl result.
5032 *
5033 * Side effects:
5034 * See the user documentation.
5035 *
5036 *----------------------------------------------------------------------
5037 */
5038
5039 static int
WmResizableCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])5040 WmResizableCmd(
5041 TCL_UNUSED(Tk_Window), /* Main window of the application. */
5042 TkWindow *winPtr, /* Toplevel to work with */
5043 Tcl_Interp *interp, /* Current interpreter. */
5044 int objc, /* Number of arguments. */
5045 Tcl_Obj *const objv[]) /* Argument objects. */
5046 {
5047 WmInfo *wmPtr = winPtr->wmInfoPtr;
5048 int width, height;
5049
5050 if ((objc != 3) && (objc != 5)) {
5051 Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?");
5052 return TCL_ERROR;
5053 }
5054 if (objc == 3) {
5055 Tcl_Obj *results[2];
5056
5057 results[0] = Tcl_NewBooleanObj(!(wmPtr->flags&WM_WIDTH_NOT_RESIZABLE));
5058 results[1] = Tcl_NewBooleanObj(!(wmPtr->flags&WM_HEIGHT_NOT_RESIZABLE));
5059 Tcl_SetObjResult(interp, Tcl_NewListObj(2, results));
5060 return TCL_OK;
5061 }
5062 if ((Tcl_GetBooleanFromObj(interp, objv[3], &width) != TCL_OK)
5063 || (Tcl_GetBooleanFromObj(interp, objv[4], &height) != TCL_OK)) {
5064 return TCL_ERROR;
5065 }
5066 if (width) {
5067 wmPtr->flags &= ~WM_WIDTH_NOT_RESIZABLE;
5068 } else {
5069 wmPtr->flags |= WM_WIDTH_NOT_RESIZABLE;
5070 }
5071 if (height) {
5072 wmPtr->flags &= ~WM_HEIGHT_NOT_RESIZABLE;
5073 } else {
5074 wmPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
5075 }
5076 if (!((wmPtr->flags & WM_NEVER_MAPPED)
5077 && !(winPtr->flags & TK_EMBEDDED))) {
5078 UpdateWrapper(winPtr);
5079 }
5080 WmUpdateGeom(wmPtr, winPtr);
5081 return TCL_OK;
5082 }
5083
5084 /*
5085 *----------------------------------------------------------------------
5086 *
5087 * WmSizefromCmd --
5088 *
5089 * This function is invoked to process the "wm sizefrom" Tcl command.
5090 * See the user documentation for details on what it does.
5091 *
5092 * Results:
5093 * A standard Tcl result.
5094 *
5095 * Side effects:
5096 * See the user documentation.
5097 *
5098 *----------------------------------------------------------------------
5099 */
5100
5101 static int
WmSizefromCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])5102 WmSizefromCmd(
5103 TCL_UNUSED(Tk_Window), /* Main window of the application. */
5104 TkWindow *winPtr, /* Toplevel to work with */
5105 Tcl_Interp *interp, /* Current interpreter. */
5106 int objc, /* Number of arguments. */
5107 Tcl_Obj *const objv[]) /* Argument objects. */
5108 {
5109 WmInfo *wmPtr = winPtr->wmInfoPtr;
5110 static const char *const optionStrings[] = {
5111 "program", "user", NULL
5112 };
5113 enum options {
5114 OPT_PROGRAM, OPT_USER
5115 };
5116 int index;
5117
5118 if ((objc != 3) && (objc != 4)) {
5119 Tcl_WrongNumArgs(interp, 2, objv, "window ?user|program?");
5120 return TCL_ERROR;
5121 }
5122 if (objc == 3) {
5123 const char *sourceStr = "";
5124
5125 if (wmPtr->sizeHintsFlags & USSize) {
5126 sourceStr = "user";
5127 } else if (wmPtr->sizeHintsFlags & PSize) {
5128 sourceStr = "program";
5129 }
5130 Tcl_SetObjResult(interp, Tcl_NewStringObj(sourceStr, -1));
5131 return TCL_OK;
5132 }
5133
5134 if (*Tcl_GetString(objv[3]) == '\0') {
5135 wmPtr->sizeHintsFlags &= ~(USSize|PSize);
5136 } else {
5137 if (Tcl_GetIndexFromObjStruct(interp, objv[3], optionStrings,
5138 sizeof(char *), "argument", 0, &index) != TCL_OK) {
5139 return TCL_ERROR;
5140 }
5141 if (index == OPT_USER) {
5142 wmPtr->sizeHintsFlags &= ~PSize;
5143 wmPtr->sizeHintsFlags |= USSize;
5144 } else { /* OPT_PROGRAM */
5145 wmPtr->sizeHintsFlags &= ~USSize;
5146 wmPtr->sizeHintsFlags |= PSize;
5147 }
5148 }
5149 WmUpdateGeom(wmPtr, winPtr);
5150 return TCL_OK;
5151 }
5152
5153 /*
5154 *----------------------------------------------------------------------
5155 *
5156 * WmStackorderCmd --
5157 *
5158 * This function is invoked to process the "wm stackorder" Tcl command.
5159 * See the user documentation for details on what it does.
5160 *
5161 * Results:
5162 * A standard Tcl result.
5163 *
5164 * Side effects:
5165 * See the user documentation.
5166 *
5167 *----------------------------------------------------------------------
5168 */
5169
5170 static int
WmStackorderCmd(Tk_Window tkwin,TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])5171 WmStackorderCmd(
5172 Tk_Window tkwin, /* Main window of the application. */
5173 TkWindow *winPtr, /* Toplevel to work with */
5174 Tcl_Interp *interp, /* Current interpreter. */
5175 int objc, /* Number of arguments. */
5176 Tcl_Obj *const objv[]) /* Argument objects. */
5177 {
5178 TkWindow **windows, **windowPtr;
5179 static const char *const optionStrings[] = {
5180 "isabove", "isbelow", NULL
5181 };
5182 enum options {
5183 OPT_ISABOVE, OPT_ISBELOW
5184 };
5185 Tcl_Obj *resultObj;
5186 int index;
5187
5188 if ((objc != 3) && (objc != 5)) {
5189 Tcl_WrongNumArgs(interp, 2, objv, "window ?isabove|isbelow window?");
5190 return TCL_ERROR;
5191 }
5192
5193 if (objc == 3) {
5194 windows = TkWmStackorderToplevel(winPtr);
5195 if (windows != NULL) {
5196 resultObj = Tcl_NewObj();
5197 for (windowPtr = windows; *windowPtr ; windowPtr++) {
5198 Tcl_ListObjAppendElement(NULL, resultObj,
5199 TkNewWindowObj((Tk_Window) *windowPtr));
5200 }
5201 Tcl_SetObjResult(interp, resultObj);
5202 ckfree(windows);
5203 return TCL_OK;
5204 } else {
5205 return TCL_ERROR;
5206 }
5207 } else {
5208 TkWindow *winPtr2, **winPtr2Ptr = &winPtr2;
5209 int index1 = -1, index2 = -1, result;
5210
5211 if (TkGetWindowFromObj(interp, tkwin, objv[4],
5212 (Tk_Window *) winPtr2Ptr) != TCL_OK) {
5213 return TCL_ERROR;
5214 }
5215
5216 if (!Tk_IsTopLevel(winPtr2)) {
5217 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
5218 "window \"%s\" isn't a top-level window",
5219 winPtr2->pathName));
5220 Tcl_SetErrorCode(interp, "TK", "WM", "STACK", "TOPLEVEL", NULL);
5221 return TCL_ERROR;
5222 }
5223
5224 if (!Tk_IsMapped(winPtr)) {
5225 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
5226 "window \"%s\" isn't mapped", winPtr->pathName));
5227 Tcl_SetErrorCode(interp, "TK", "WM", "STACK", "MAPPED", NULL);
5228 return TCL_ERROR;
5229 }
5230
5231 if (!Tk_IsMapped(winPtr2)) {
5232 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
5233 "window \"%s\" isn't mapped", winPtr2->pathName));
5234 Tcl_SetErrorCode(interp, "TK", "WM", "STACK", "MAPPED", NULL);
5235 return TCL_ERROR;
5236 }
5237
5238 /*
5239 * Lookup stacking order of all toplevels that are children of "." and
5240 * find the position of winPtr and winPtr2 in the stacking order.
5241 */
5242
5243 windows = TkWmStackorderToplevel(winPtr->mainPtr->winPtr);
5244 if (windows == NULL) {
5245 Tcl_SetObjResult(interp, Tcl_NewStringObj(
5246 "TkWmStackorderToplevel failed", -1));
5247 Tcl_SetErrorCode(interp, "TK", "WM", "COMMUNICATION", NULL);
5248 return TCL_ERROR;
5249 }
5250
5251 for (windowPtr = windows; *windowPtr ; windowPtr++) {
5252 if (*windowPtr == winPtr) {
5253 index1 = (windowPtr - windows);
5254 }
5255 if (*windowPtr == winPtr2) {
5256 index2 = (windowPtr - windows);
5257 }
5258 }
5259 if (index1 == -1) {
5260 Tcl_Panic("winPtr window not found");
5261 } else if (index2 == -1) {
5262 Tcl_Panic("winPtr2 window not found");
5263 }
5264
5265 ckfree(windows);
5266
5267 if (Tcl_GetIndexFromObjStruct(interp, objv[3], optionStrings,
5268 sizeof(char *), "argument", 0, &index) != TCL_OK) {
5269 return TCL_ERROR;
5270 }
5271 if (index == OPT_ISABOVE) {
5272 result = index1 > index2;
5273 } else { /* OPT_ISBELOW */
5274 result = index1 < index2;
5275 }
5276 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(result));
5277 return TCL_OK;
5278 }
5279 }
5280
5281 /*
5282 *----------------------------------------------------------------------
5283 *
5284 * WmStateCmd --
5285 *
5286 * This function is invoked to process the "wm state" Tcl command. See
5287 * the user documentation for details on what it does.
5288 *
5289 * Results:
5290 * A standard Tcl result.
5291 *
5292 * Side effects:
5293 * See the user documentation.
5294 *
5295 *----------------------------------------------------------------------
5296 */
5297
5298 static int
WmStateCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])5299 WmStateCmd(
5300 TCL_UNUSED(Tk_Window), /* Main window of the application. */
5301 TkWindow *winPtr, /* Toplevel to work with */
5302 Tcl_Interp *interp, /* Current interpreter. */
5303 int objc, /* Number of arguments. */
5304 Tcl_Obj *const objv[]) /* Argument objects. */
5305 {
5306 WmInfo *wmPtr = winPtr->wmInfoPtr;
5307 static const char *const optionStrings[] = {
5308 "normal", "iconic", "withdrawn", "zoomed", NULL
5309 };
5310 enum options {
5311 OPT_NORMAL, OPT_ICONIC, OPT_WITHDRAWN, OPT_ZOOMED
5312 };
5313 int index;
5314
5315 if ((objc < 3) || (objc > 4)) {
5316 Tcl_WrongNumArgs(interp, 2, objv, "window ?state?");
5317 return TCL_ERROR;
5318 }
5319 if (objc == 4) {
5320 if (wmPtr->iconFor != NULL) {
5321 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
5322 "can't change state of %s: it is an icon for %s",
5323 Tcl_GetString(objv[2]), Tk_PathName(wmPtr->iconFor)));
5324 Tcl_SetErrorCode(interp, "TK", "WM", "STATE", "ICON", NULL);
5325 return TCL_ERROR;
5326 }
5327 if (Tcl_GetIndexFromObjStruct(interp, objv[3], optionStrings,
5328 sizeof(char *), "argument", 0, &index) != TCL_OK) {
5329 return TCL_ERROR;
5330 }
5331
5332 if (winPtr->flags & TK_EMBEDDED) {
5333 int state = 0;
5334
5335 switch (index) {
5336 case OPT_NORMAL:
5337 state = NormalState;
5338 break;
5339 case OPT_ICONIC:
5340 state = IconicState;
5341 break;
5342 case OPT_WITHDRAWN:
5343 state = WithdrawnState;
5344 break;
5345 case OPT_ZOOMED:
5346 state = ZoomState;
5347 break;
5348 default:
5349 Tcl_Panic("unexpected index");
5350 }
5351
5352 if (state+1 != SendMessageW(wmPtr->wrapper, TK_STATE, state, 0)) {
5353 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
5354 "can't change state of %s: the container does not support the request",
5355 winPtr->pathName));
5356 Tcl_SetErrorCode(interp, "TK", "WM", "COMMUNICATION", NULL);
5357 return TCL_ERROR;
5358 }
5359 return TCL_OK;
5360 }
5361
5362 if (index == OPT_NORMAL) {
5363 wmPtr->flags &= ~WM_WITHDRAWN;
5364 TkpWmSetState(winPtr, NormalState);
5365
5366 /*
5367 * This varies from 'wm deiconify' because it does not force the
5368 * window to be raised and receive focus.
5369 */
5370 } else if (index == OPT_ICONIC) {
5371 if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
5372 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
5373 "can't iconify \"%s\": override-redirect flag is set",
5374 winPtr->pathName));
5375 Tcl_SetErrorCode(interp, "TK", "WM", "STATE",
5376 "OVERRIDE_REDIRECT", NULL);
5377 return TCL_ERROR;
5378 }
5379 if (wmPtr->containerPtr != NULL) {
5380 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
5381 "can't iconify \"%s\": it is a transient",
5382 winPtr->pathName));
5383 Tcl_SetErrorCode(interp, "TK", "WM", "STATE", "TRANSIENT",
5384 NULL);
5385 return TCL_ERROR;
5386 }
5387 TkpWmSetState(winPtr, IconicState);
5388 } else if (index == OPT_WITHDRAWN) {
5389 wmPtr->flags |= WM_WITHDRAWN;
5390 TkpWmSetState(winPtr, WithdrawnState);
5391 } else if (index == OPT_ZOOMED) {
5392 TkpWmSetState(winPtr, ZoomState);
5393 } else {
5394 Tcl_Panic("wm state not matched");
5395 }
5396 } else {
5397 const char *stateStr = "";
5398
5399 if (wmPtr->iconFor != NULL) {
5400 stateStr = "icon";
5401 } else {
5402 int state;
5403
5404 if (winPtr->flags & TK_EMBEDDED) {
5405 state = SendMessageW(wmPtr->wrapper, TK_STATE, -1, -1) - 1;
5406 } else {
5407 state = wmPtr->hints.initial_state;
5408 }
5409 switch (state) {
5410 case NormalState: stateStr = "normal"; break;
5411 case IconicState: stateStr = "iconic"; break;
5412 case WithdrawnState: stateStr = "withdrawn"; break;
5413 case ZoomState: stateStr = "zoomed"; break;
5414 }
5415 }
5416 Tcl_SetObjResult(interp, Tcl_NewStringObj(stateStr, -1));
5417 }
5418 return TCL_OK;
5419 }
5420
5421 /*
5422 *----------------------------------------------------------------------
5423 *
5424 * WmTitleCmd --
5425 *
5426 * This function is invoked to process the "wm title" Tcl command. See
5427 * the user documentation for details on what it does.
5428 *
5429 * Results:
5430 * A standard Tcl result.
5431 *
5432 * Side effects:
5433 * See the user documentation.
5434 *
5435 *----------------------------------------------------------------------
5436 */
5437
5438 static int
WmTitleCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])5439 WmTitleCmd(
5440 TCL_UNUSED(Tk_Window), /* Main window of the application. */
5441 TkWindow *winPtr, /* Toplevel to work with */
5442 Tcl_Interp *interp, /* Current interpreter. */
5443 int objc, /* Number of arguments. */
5444 Tcl_Obj *const objv[]) /* Argument objects. */
5445 {
5446 WmInfo *wmPtr = winPtr->wmInfoPtr;
5447 const char *argv3;
5448 int length;
5449 HWND wrapper;
5450
5451 if (objc > 4) {
5452 Tcl_WrongNumArgs(interp, 2, objv, "window ?newTitle?");
5453 return TCL_ERROR;
5454 }
5455
5456 if (winPtr->flags & TK_EMBEDDED) {
5457 wrapper = (HWND) SendMessageW(wmPtr->wrapper, TK_GETFRAMEWID, 0, 0);
5458 } else {
5459 wrapper = wmPtr->wrapper;
5460 }
5461 if (objc == 3) {
5462 if (wrapper) {
5463 WCHAR buf[256];
5464 Tcl_DString titleString;
5465 int size = 256;
5466
5467 GetWindowTextW(wrapper, buf, size);
5468 Tcl_DStringInit(&titleString);
5469 Tcl_WCharToUtfDString(buf, wcslen(buf), &titleString);
5470 Tcl_SetObjResult(interp, Tcl_NewStringObj(
5471 Tcl_DStringValue(&titleString),
5472 Tcl_DStringLength(&titleString)));
5473 Tcl_DStringFree(&titleString);
5474 } else {
5475 Tcl_SetObjResult(interp, Tcl_NewStringObj(
5476 (wmPtr->title ? wmPtr->title : winPtr->nameUid), -1));
5477 }
5478 } else {
5479 if (wmPtr->title != NULL) {
5480 ckfree(wmPtr->title);
5481 }
5482 argv3 = Tcl_GetStringFromObj(objv[3], &length);
5483 wmPtr->title = (char *)ckalloc(length + 1);
5484 memcpy(wmPtr->title, argv3, length + 1);
5485
5486 if (!(wmPtr->flags & WM_NEVER_MAPPED) && wmPtr->wrapper != NULL) {
5487 Tcl_DString titleString;
5488
5489 Tcl_DStringInit(&titleString);
5490 Tcl_UtfToWCharDString(wmPtr->title, -1, &titleString);
5491 SetWindowTextW(wrapper, (LPCWSTR) Tcl_DStringValue(&titleString));
5492 Tcl_DStringFree(&titleString);
5493 }
5494 }
5495 return TCL_OK;
5496 }
5497
5498 /*
5499 *----------------------------------------------------------------------
5500 *
5501 * WmTransientCmd --
5502 *
5503 * This function is invoked to process the "wm transient" Tcl command.
5504 * See the user documentation for details on what it does.
5505 *
5506 * Results:
5507 * A standard Tcl result.
5508 *
5509 * Side effects:
5510 * See the user documentation.
5511 *
5512 *----------------------------------------------------------------------
5513 */
5514
5515 static int
WmTransientCmd(Tk_Window tkwin,TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])5516 WmTransientCmd(
5517 Tk_Window tkwin, /* Main window of the application. */
5518 TkWindow *winPtr, /* Toplevel to work with */
5519 Tcl_Interp *interp, /* Current interpreter. */
5520 int objc, /* Number of arguments. */
5521 Tcl_Obj *const objv[]) /* Argument objects. */
5522 {
5523 WmInfo *wmPtr = winPtr->wmInfoPtr;
5524 TkWindow *containerPtr = wmPtr->containerPtr, **containerPtrPtr = &containerPtr, *w;
5525 WmInfo *wmPtr2;
5526
5527 if ((objc != 3) && (objc != 4)) {
5528 Tcl_WrongNumArgs(interp, 2, objv, "window ?master?");
5529 return TCL_ERROR;
5530 }
5531 if (objc == 3) {
5532 if (containerPtr != NULL) {
5533 Tcl_SetObjResult(interp, TkNewWindowObj((Tk_Window) containerPtr));
5534 }
5535 return TCL_OK;
5536 }
5537 if (Tcl_GetString(objv[3])[0] == '\0') {
5538 if (containerPtr != NULL) {
5539 /*
5540 * If we had a container, tell them that we aren't tied to them
5541 * anymore.
5542 */
5543
5544 containerPtr->wmInfoPtr->numTransients--;
5545 Tk_DeleteEventHandler((Tk_Window) containerPtr,
5546 VisibilityChangeMask|StructureNotifyMask,
5547 WmWaitVisibilityOrMapProc, winPtr);
5548 }
5549
5550 wmPtr->containerPtr = NULL;
5551 } else {
5552 if (TkGetWindowFromObj(interp, tkwin, objv[3],
5553 (Tk_Window *) containerPtrPtr) != TCL_OK) {
5554 return TCL_ERROR;
5555 }
5556 while (!Tk_TopWinHierarchy(containerPtr)) {
5557 /*
5558 * Ensure that the container window is actually a Tk toplevel.
5559 */
5560
5561 containerPtr = containerPtr->parentPtr;
5562 }
5563 Tk_MakeWindowExist((Tk_Window) containerPtr);
5564
5565 if (wmPtr->iconFor != NULL) {
5566 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
5567 "can't make \"%s\" a transient: it is an icon for %s",
5568 Tcl_GetString(objv[2]), Tk_PathName(wmPtr->iconFor)));
5569 Tcl_SetErrorCode(interp, "TK", "WM", "TRANSIENT", "ICON", NULL);
5570 return TCL_ERROR;
5571 }
5572
5573 wmPtr2 = containerPtr->wmInfoPtr;
5574
5575 if (wmPtr2->iconFor != NULL) {
5576 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
5577 "can't make \"%s\" a master: it is an icon for %s",
5578 Tcl_GetString(objv[3]), Tk_PathName(wmPtr2->iconFor)));
5579 Tcl_SetErrorCode(interp, "TK", "WM", "TRANSIENT", "ICON", NULL);
5580 return TCL_ERROR;
5581 }
5582 for (w = containerPtr; w != NULL && w->wmInfoPtr != NULL;
5583 w = (TkWindow *)w->wmInfoPtr->containerPtr) {
5584 if (w == winPtr) {
5585 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
5586 "setting \"%s\" as master creates a transient/master cycle",
5587 Tk_PathName(containerPtr)));
5588 Tcl_SetErrorCode(interp, "TK", "WM", "TRANSIENT", "SELF", NULL);
5589 return TCL_ERROR;
5590 }
5591 }
5592 if (containerPtr != wmPtr->containerPtr) {
5593 /*
5594 * Remove old container map/unmap binding before setting the new
5595 * container. The event handler will ensure that transient states
5596 * reflect the state of the container.
5597 */
5598
5599 if (wmPtr->containerPtr != NULL) {
5600 wmPtr->containerPtr->wmInfoPtr->numTransients--;
5601 Tk_DeleteEventHandler((Tk_Window) wmPtr->containerPtr,
5602 VisibilityChangeMask|StructureNotifyMask,
5603 WmWaitVisibilityOrMapProc, winPtr);
5604 }
5605
5606 containerPtr->wmInfoPtr->numTransients++;
5607 Tk_CreateEventHandler((Tk_Window) containerPtr,
5608 VisibilityChangeMask|StructureNotifyMask,
5609 WmWaitVisibilityOrMapProc, winPtr);
5610
5611 wmPtr->containerPtr = containerPtr;
5612 }
5613 }
5614 if (!((wmPtr->flags & WM_NEVER_MAPPED)
5615 && !(winPtr->flags & TK_EMBEDDED))) {
5616 if (wmPtr->containerPtr != NULL
5617 && !Tk_IsMapped(wmPtr->containerPtr)) {
5618 TkpWmSetState(winPtr, WithdrawnState);
5619 } else {
5620 UpdateWrapper(winPtr);
5621 }
5622 }
5623 return TCL_OK;
5624 }
5625
5626 /*
5627 *----------------------------------------------------------------------
5628 *
5629 * WmWithdrawCmd --
5630 *
5631 * This function is invoked to process the "wm withdraw" Tcl command.
5632 * See the user documentation for details on what it does.
5633 *
5634 * Results:
5635 * A standard Tcl result.
5636 *
5637 * Side effects:
5638 * See the user documentation.
5639 *
5640 *----------------------------------------------------------------------
5641 */
5642
5643 static int
WmWithdrawCmd(TCL_UNUSED (Tk_Window),TkWindow * winPtr,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])5644 WmWithdrawCmd(
5645 TCL_UNUSED(Tk_Window), /* Main window of the application. */
5646 TkWindow *winPtr, /* Toplevel to work with */
5647 Tcl_Interp *interp, /* Current interpreter. */
5648 int objc, /* Number of arguments. */
5649 Tcl_Obj *const objv[]) /* Argument objects. */
5650 {
5651 WmInfo *wmPtr = winPtr->wmInfoPtr;
5652
5653 if (objc != 3) {
5654 Tcl_WrongNumArgs(interp, 2, objv, "window");
5655 return TCL_ERROR;
5656 }
5657 if (wmPtr->iconFor != NULL) {
5658 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
5659 "can't withdraw %s: it is an icon for %s",
5660 Tcl_GetString(objv[2]), Tk_PathName(wmPtr->iconFor)));
5661 Tcl_SetErrorCode(interp, "TK", "WM", "WITHDRAW", "ICON", NULL);
5662 return TCL_ERROR;
5663 }
5664
5665 if (winPtr->flags & TK_EMBEDDED) {
5666 if (SendMessageW(wmPtr->wrapper, TK_WITHDRAW, 0, 0) < 0) {
5667 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
5668 "can't withdraw %s: the container does not support the request",
5669 Tcl_GetString(objv[2])));
5670 Tcl_SetErrorCode(interp, "TK", "WM", "COMMUNICATION", NULL);
5671 return TCL_ERROR;
5672 }
5673 } else {
5674 wmPtr->flags |= WM_WITHDRAWN;
5675 TkpWmSetState(winPtr, WithdrawnState);
5676 }
5677 return TCL_OK;
5678 }
5679
5680 /*
5681 * Invoked by those wm subcommands that affect geometry. Schedules a geometry
5682 * update.
5683 */
5684
5685 static void
WmUpdateGeom(WmInfo * wmPtr,TkWindow * winPtr)5686 WmUpdateGeom(
5687 WmInfo *wmPtr,
5688 TkWindow *winPtr)
5689 {
5690 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
5691 Tcl_DoWhenIdle(UpdateGeometryInfo, winPtr);
5692 wmPtr->flags |= WM_UPDATE_PENDING;
5693 }
5694 }
5695
5696 static void
WmWaitVisibilityOrMapProc(ClientData clientData,XEvent * eventPtr)5697 WmWaitVisibilityOrMapProc(
5698 ClientData clientData, /* Pointer to window. */
5699 XEvent *eventPtr) /* Information about event. */
5700 {
5701 TkWindow *winPtr = (TkWindow *)clientData;
5702 TkWindow *containerPtr = winPtr->wmInfoPtr->containerPtr;
5703
5704 if (containerPtr == NULL)
5705 return;
5706
5707 if (eventPtr->type == MapNotify) {
5708 if (!(winPtr->wmInfoPtr->flags & WM_WITHDRAWN)) {
5709 TkpWmSetState(winPtr, NormalState);
5710 }
5711 } else if (eventPtr->type == UnmapNotify) {
5712 TkpWmSetState(winPtr, WithdrawnState);
5713 }
5714
5715 if (eventPtr->type == VisibilityNotify) {
5716 int state = containerPtr->wmInfoPtr->hints.initial_state;
5717
5718 if ((state == NormalState) || (state == ZoomState)) {
5719 state = winPtr->wmInfoPtr->hints.initial_state;
5720 if ((state == NormalState) || (state == ZoomState)) {
5721 UpdateWrapper(winPtr);
5722 }
5723 }
5724 }
5725 }
5726
5727 /*
5728 *----------------------------------------------------------------------
5729 *
5730 * Tk_SetGrid --
5731 *
5732 * This function is invoked by a widget when it wishes to set a grid
5733 * coordinate system that controls the size of a top-level window. It
5734 * provides a C interface equivalent to the "wm grid" command and is
5735 * usually associated with the -setgrid option.
5736 *
5737 * Results:
5738 * None.
5739 *
5740 * Side effects:
5741 * Grid-related information will be passed to the window manager, so that
5742 * the top-level window associated with tkwin will resize on even grid
5743 * units. If some other window already controls gridding for the
5744 * top-level window then this function call has no effect.
5745 *
5746 *----------------------------------------------------------------------
5747 */
5748
5749 void
Tk_SetGrid(Tk_Window tkwin,int reqWidth,int reqHeight,int widthInc,int heightInc)5750 Tk_SetGrid(
5751 Tk_Window tkwin, /* Token for window. New window mgr info will
5752 * be posted for the top-level window
5753 * associated with this window. */
5754 int reqWidth, /* Width (in grid units) corresponding to the
5755 * requested geometry for tkwin. */
5756 int reqHeight, /* Height (in grid units) corresponding to the
5757 * requested geometry for tkwin. */
5758 int widthInc, int heightInc)/* Pixel increments corresponding to a change
5759 * of one grid unit. */
5760 {
5761 TkWindow *winPtr = (TkWindow *) tkwin;
5762 WmInfo *wmPtr;
5763
5764 /*
5765 * Ensure widthInc and heightInc are greater than 0
5766 */
5767
5768 if (widthInc <= 0) {
5769 widthInc = 1;
5770 }
5771 if (heightInc <= 0) {
5772 heightInc = 1;
5773 }
5774
5775 /*
5776 * Find the top-level window for tkwin, plus the window manager
5777 * information.
5778 */
5779
5780 while (!(winPtr->flags & TK_TOP_HIERARCHY)) {
5781 winPtr = winPtr->parentPtr;
5782 }
5783 wmPtr = winPtr->wmInfoPtr;
5784 if (wmPtr == NULL) {
5785 return;
5786 }
5787
5788 if ((wmPtr->gridWin != NULL) && (wmPtr->gridWin != tkwin)) {
5789 return;
5790 }
5791
5792 if ((wmPtr->reqGridWidth == reqWidth)
5793 && (wmPtr->reqGridHeight == reqHeight)
5794 && (wmPtr->widthInc == widthInc)
5795 && (wmPtr->heightInc == heightInc)
5796 && ((wmPtr->sizeHintsFlags & (PBaseSize|PResizeInc))
5797 == (PBaseSize|PResizeInc))) {
5798 return;
5799 }
5800
5801 /*
5802 * If gridding was previously off, then forget about any window size
5803 * requests made by the user or via "wm geometry": these are in pixel
5804 * units and there's no easy way to translate them to grid units since the
5805 * new requested size of the top-level window in pixels may not yet have
5806 * been registered yet (it may filter up the hierarchy in DoWhenIdle
5807 * handlers). However, if the window has never been mapped yet then just
5808 * leave the window size alone: assume that it is intended to be in grid
5809 * units but just happened to have been specified before this function was
5810 * called.
5811 */
5812
5813 if ((wmPtr->gridWin == NULL) && !(wmPtr->flags & WM_NEVER_MAPPED)) {
5814 wmPtr->width = -1;
5815 wmPtr->height = -1;
5816 }
5817
5818 /*
5819 * Set the new gridding information, and start the process of passing all
5820 * of this information to the window manager.
5821 */
5822
5823 wmPtr->gridWin = tkwin;
5824 wmPtr->reqGridWidth = reqWidth;
5825 wmPtr->reqGridHeight = reqHeight;
5826 wmPtr->widthInc = widthInc;
5827 wmPtr->heightInc = heightInc;
5828 wmPtr->sizeHintsFlags |= PBaseSize|PResizeInc;
5829 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
5830 Tcl_DoWhenIdle(UpdateGeometryInfo, winPtr);
5831 wmPtr->flags |= WM_UPDATE_PENDING;
5832 }
5833 }
5834
5835 /*
5836 *----------------------------------------------------------------------
5837 *
5838 * Tk_UnsetGrid --
5839 *
5840 * This function cancels the effect of a previous call to Tk_SetGrid.
5841 *
5842 * Results:
5843 * None.
5844 *
5845 * Side effects:
5846 * If tkwin currently controls gridding for its top-level window,
5847 * gridding is cancelled for that top-level window; if some other window
5848 * controls gridding then this function has no effect.
5849 *
5850 *----------------------------------------------------------------------
5851 */
5852
5853 void
Tk_UnsetGrid(Tk_Window tkwin)5854 Tk_UnsetGrid(
5855 Tk_Window tkwin) /* Token for window that is currently
5856 * controlling gridding. */
5857 {
5858 TkWindow *winPtr = (TkWindow *) tkwin;
5859 WmInfo *wmPtr;
5860
5861 /*
5862 * Find the top-level window for tkwin, plus the window manager
5863 * information.
5864 */
5865
5866 while (!(winPtr->flags & TK_TOP_HIERARCHY)) {
5867 winPtr = winPtr->parentPtr;
5868 }
5869 wmPtr = winPtr->wmInfoPtr;
5870 if (wmPtr == NULL) {
5871 return;
5872 }
5873
5874 if (tkwin != wmPtr->gridWin) {
5875 return;
5876 }
5877
5878 wmPtr->gridWin = NULL;
5879 wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
5880 if (wmPtr->width != -1) {
5881 wmPtr->width = winPtr->reqWidth + (wmPtr->width
5882 - wmPtr->reqGridWidth)*wmPtr->widthInc;
5883 wmPtr->height = winPtr->reqHeight + (wmPtr->height
5884 - wmPtr->reqGridHeight)*wmPtr->heightInc;
5885 }
5886 wmPtr->widthInc = 1;
5887 wmPtr->heightInc = 1;
5888
5889 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
5890 Tcl_DoWhenIdle(UpdateGeometryInfo, winPtr);
5891 wmPtr->flags |= WM_UPDATE_PENDING;
5892 }
5893 }
5894
5895 /*
5896 *----------------------------------------------------------------------
5897 *
5898 * TopLevelEventProc --
5899 *
5900 * This function is invoked when a top-level (or other externally-managed
5901 * window) is restructured in any way.
5902 *
5903 * Results:
5904 * None.
5905 *
5906 * Side effects:
5907 * Tk's internal data structures for the window get modified to reflect
5908 * the structural change.
5909 *
5910 *----------------------------------------------------------------------
5911 */
5912
5913 static void
TopLevelEventProc(ClientData clientData,XEvent * eventPtr)5914 TopLevelEventProc(
5915 ClientData clientData, /* Window for which event occurred. */
5916 XEvent *eventPtr) /* Event that just happened. */
5917 {
5918 TkWindow *winPtr = (TkWindow *)clientData;
5919
5920 if (eventPtr->type == DestroyNotify) {
5921 Tk_ErrorHandler handler;
5922
5923 if (!(winPtr->flags & TK_ALREADY_DEAD)) {
5924 /*
5925 * A top-level window was deleted externally (e.g., by the window
5926 * manager). This is probably not a good thing, but cleanup as
5927 * best we can. The error handler is needed because
5928 * Tk_DestroyWindow will try to destroy the window, but of course
5929 * it's already gone.
5930 */
5931
5932 handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
5933 NULL, NULL);
5934 Tk_DestroyWindow((Tk_Window) winPtr);
5935 Tk_DeleteErrorHandler(handler);
5936 }
5937 }
5938 }
5939
5940 /*
5941 *----------------------------------------------------------------------
5942 *
5943 * TopLevelReqProc --
5944 *
5945 * This function is invoked by the geometry manager whenever the
5946 * requested size for a top-level window is changed.
5947 *
5948 * Results:
5949 * None.
5950 *
5951 * Side effects:
5952 * Arrange for the window to be resized to satisfy the request (this
5953 * happens as a when-idle action).
5954 *
5955 *----------------------------------------------------------------------
5956 */
5957
5958 static void
TopLevelReqProc(TCL_UNUSED (void *),Tk_Window tkwin)5959 TopLevelReqProc(
5960 TCL_UNUSED(void *),
5961 Tk_Window tkwin) /* Information about window. */
5962 {
5963 TkWindow *winPtr = (TkWindow *) tkwin;
5964 WmInfo *wmPtr;
5965
5966 wmPtr = winPtr->wmInfoPtr;
5967 if (wmPtr) {
5968 if ((winPtr->flags & TK_EMBEDDED) && (wmPtr->wrapper != NULL)) {
5969 SendMessageW(wmPtr->wrapper, TK_GEOMETRYREQ, Tk_ReqWidth(tkwin),
5970 Tk_ReqHeight(tkwin));
5971 }
5972 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
5973 Tcl_DoWhenIdle(UpdateGeometryInfo, winPtr);
5974 wmPtr->flags |= WM_UPDATE_PENDING;
5975 }
5976 }
5977 }
5978
5979 /*
5980 *----------------------------------------------------------------------
5981 *
5982 * UpdateGeometryInfo --
5983 *
5984 * This function is invoked when a top-level window is first mapped, and
5985 * also as a when-idle function, to bring the geometry and/or position of
5986 * a top-level window back into line with what has been requested by the
5987 * user and/or widgets. This function doesn't return until the system has
5988 * responded to the geometry change.
5989 *
5990 * Results:
5991 * None.
5992 *
5993 * Side effects:
5994 * The window's size and location may change, unless the WM prevents that
5995 * from happening.
5996 *
5997 *----------------------------------------------------------------------
5998 */
5999
6000 static void
UpdateGeometryInfo(ClientData clientData)6001 UpdateGeometryInfo(
6002 ClientData clientData) /* Pointer to the window's record. */
6003 {
6004 int x, y; /* Position of border on desktop. */
6005 int width, height; /* Size of client area. */
6006 int min, max;
6007 RECT rect;
6008 TkWindow *winPtr = (TkWindow *)clientData;
6009 WmInfo *wmPtr = winPtr->wmInfoPtr;
6010
6011 wmPtr->flags &= ~WM_UPDATE_PENDING;
6012
6013 /*
6014 * If the window is minimized or maximized, we should not update our
6015 * geometry since it will end up with the wrong values. ConfigureToplevel
6016 * will reschedule UpdateGeometryInfo when the state of the window
6017 * changes.
6018 */
6019
6020 if (wmPtr->wrapper && (IsIconic(wmPtr->wrapper) ||
6021 IsZoomed(wmPtr->wrapper) || (wmPtr->flags & WM_FULLSCREEN))) {
6022 return;
6023 }
6024
6025 /*
6026 * Compute the border size for the current window style. This size will
6027 * include the resize handles, the title bar and the menubar. Note that
6028 * this size will not be correct if the menubar spans multiple lines. The
6029 * height will be off by a multiple of the menubar height. It really only
6030 * measures the minimum size of the border.
6031 */
6032
6033 rect.left = rect.right = rect.top = rect.bottom = 0;
6034 AdjustWindowRectEx(&rect, wmPtr->style, wmPtr->hMenu != NULL,
6035 wmPtr->exStyle);
6036 wmPtr->borderWidth = rect.right - rect.left;
6037 wmPtr->borderHeight = rect.bottom - rect.top;
6038
6039 /*
6040 * Compute the new size for the top-level window. See the user
6041 * documentation for details on this, but the size requested depends on
6042 * (a) the size requested internally by the window's widgets, (b) the size
6043 * requested by the user in a "wm geometry" command or via wm-based
6044 * interactive resizing (if any), (c) whether or not the window is
6045 * gridded, and (d) the current min or max size for the toplevel. Don't
6046 * permit sizes <= 0 because this upsets the X server.
6047 */
6048
6049 if (wmPtr->width == -1) {
6050 width = winPtr->reqWidth;
6051 } else if (wmPtr->gridWin != NULL) {
6052 width = winPtr->reqWidth
6053 + (wmPtr->width - wmPtr->reqGridWidth)*wmPtr->widthInc;
6054 } else {
6055 width = wmPtr->width;
6056 }
6057 if (width <= 0) {
6058 width = 1;
6059 }
6060
6061 /*
6062 * Account for window max/min width
6063 */
6064
6065 if (wmPtr->gridWin != NULL) {
6066 min = winPtr->reqWidth
6067 + (wmPtr->minWidth - wmPtr->reqGridWidth)*wmPtr->widthInc;
6068 if (wmPtr->maxWidth > 0) {
6069 max = winPtr->reqWidth
6070 + (wmPtr->maxWidth - wmPtr->reqGridWidth)*wmPtr->widthInc;
6071 } else {
6072 max = 0;
6073 }
6074 } else {
6075 min = wmPtr->minWidth;
6076 max = wmPtr->maxWidth;
6077 }
6078 if (width < min) {
6079 width = min;
6080 } else if ((max > 0) && (width > max)) {
6081 width = max;
6082 }
6083
6084 if (wmPtr->height == -1) {
6085 height = winPtr->reqHeight;
6086 } else if (wmPtr->gridWin != NULL) {
6087 height = winPtr->reqHeight
6088 + (wmPtr->height - wmPtr->reqGridHeight)*wmPtr->heightInc;
6089 } else {
6090 height = wmPtr->height;
6091 }
6092 if (height <= 0) {
6093 height = 1;
6094 }
6095
6096 /*
6097 * Account for window max/min height
6098 */
6099
6100 if (wmPtr->gridWin != NULL) {
6101 min = winPtr->reqHeight
6102 + (wmPtr->minHeight - wmPtr->reqGridHeight)*wmPtr->heightInc;
6103 if (wmPtr->maxHeight > 0) {
6104 max = winPtr->reqHeight
6105 + (wmPtr->maxHeight-wmPtr->reqGridHeight)*wmPtr->heightInc;
6106 } else {
6107 max = 0;
6108 }
6109 } else {
6110 min = wmPtr->minHeight;
6111 max = wmPtr->maxHeight;
6112 }
6113 if (height < min) {
6114 height = min;
6115 } else if ((max > 0) && (height > max)) {
6116 height = max;
6117 }
6118
6119 /*
6120 * Compute the new position for the upper-left pixel of the window's
6121 * decorative frame. This is tricky, because we need to include the border
6122 * widths supplied by a reparented parent in this calculation, but can't
6123 * use the parent's current overall size since that may change as a result
6124 * of this code.
6125 */
6126
6127 if (wmPtr->flags & WM_NEGATIVE_X) {
6128 x = DisplayWidth(winPtr->display, winPtr->screenNum) - wmPtr->x
6129 - (width + wmPtr->borderWidth);
6130 } else {
6131 x = wmPtr->x;
6132 }
6133 if (wmPtr->flags & WM_NEGATIVE_Y) {
6134 y = DisplayHeight(winPtr->display, winPtr->screenNum) - wmPtr->y
6135 - (height + wmPtr->borderHeight);
6136 } else {
6137 y = wmPtr->y;
6138 }
6139
6140 /*
6141 * Reconfigure the window if it isn't already configured correctly. Base
6142 * the size check on what we *asked for* last time, not what we got.
6143 * Return immediately if there have been no changes in the requested
6144 * geometry of the toplevel.
6145 */
6146
6147 /* TODO: need to add flag for possible menu size change */
6148
6149 if (!(wmPtr->flags & WM_MOVE_PENDING)
6150 && (width == wmPtr->configWidth)
6151 && (height == wmPtr->configHeight)) {
6152 return;
6153 }
6154 wmPtr->flags &= ~WM_MOVE_PENDING;
6155
6156 wmPtr->configWidth = width;
6157 wmPtr->configHeight = height;
6158
6159 /*
6160 * Don't bother moving the window if we are in the process of creating it.
6161 * Just update the geometry info based on what we asked for.
6162 */
6163
6164 if (wmPtr->flags & WM_CREATE_PENDING) {
6165 winPtr->changes.x = x;
6166 winPtr->changes.y = y;
6167 winPtr->changes.width = width;
6168 winPtr->changes.height = height;
6169 return;
6170 }
6171
6172 wmPtr->flags |= WM_SYNC_PENDING;
6173 if (winPtr->flags & TK_EMBEDDED) {
6174 /*
6175 * The wrapper window is in a different process, so we need to send it
6176 * a geometry request. This protocol assumes that the other process
6177 * understands this Tk message, otherwise our requested geometry will
6178 * be ignored.
6179 */
6180
6181 SendMessageW(wmPtr->wrapper, TK_MOVEWINDOW, x, y);
6182 SendMessageW(wmPtr->wrapper, TK_GEOMETRYREQ, width, height);
6183 } else {
6184 int reqHeight, reqWidth;
6185 RECT windowRect;
6186 int menuInc = GetSystemMetrics(SM_CYMENU);
6187 int newHeight;
6188
6189 /*
6190 * We have to keep resizing the window until we get the requested
6191 * height in the client area. If the client area has zero height, then
6192 * the window rect is too small by definition. Try increasing the
6193 * border height and try again. Once we have a positive size, then we
6194 * can adjust the height exactly. If the window rect comes back
6195 * smaller than we requested, we have hit the maximum constraints that
6196 * Windows imposes. Once we find a positive client size, the next size
6197 * is the one we try no matter what.
6198 */
6199
6200 reqHeight = height + wmPtr->borderHeight;
6201 reqWidth = width + wmPtr->borderWidth;
6202
6203 while (1) {
6204 MoveWindow(wmPtr->wrapper, x, y, reqWidth, reqHeight, TRUE);
6205 GetWindowRect(wmPtr->wrapper, &windowRect);
6206 newHeight = windowRect.bottom - windowRect.top;
6207
6208 /*
6209 * If the request wasn't satisfied, we have hit an external
6210 * constraint and must stop.
6211 */
6212
6213 if (newHeight < reqHeight) {
6214 break;
6215 }
6216
6217 /*
6218 * Now check the size of the client area against our ideal.
6219 */
6220
6221 GetClientRect(wmPtr->wrapper, &windowRect);
6222 newHeight = windowRect.bottom - windowRect.top;
6223
6224 if (newHeight == height) {
6225 /*
6226 * We're done.
6227 */
6228
6229 break;
6230 } else if (newHeight > height) {
6231 /*
6232 * One last resize to get rid of the extra space.
6233 */
6234
6235 menuInc = newHeight - height;
6236 reqHeight -= menuInc;
6237 if (wmPtr->flags & WM_NEGATIVE_Y) {
6238 y += menuInc;
6239 }
6240 MoveWindow(wmPtr->wrapper, x, y, reqWidth, reqHeight, TRUE);
6241 break;
6242 }
6243
6244 /*
6245 * We didn't get enough space to satisfy our requested height, so
6246 * the menu must have wrapped. Increase the size of the window by
6247 * one menu height and move the window if it is positioned
6248 * relative to the lower right corner of the screen.
6249 */
6250
6251 reqHeight += menuInc;
6252 if (wmPtr->flags & WM_NEGATIVE_Y) {
6253 y -= menuInc;
6254 }
6255 }
6256 if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
6257 DrawMenuBar(wmPtr->wrapper);
6258 }
6259 }
6260 wmPtr->flags &= ~WM_SYNC_PENDING;
6261 }
6262
6263 /*
6264 *--------------------------------------------------------------
6265 *
6266 * ParseGeometry --
6267 *
6268 * This function parses a geometry string and updates information used to
6269 * control the geometry of a top-level window.
6270 *
6271 * Results:
6272 * A standard Tcl return value, plus an error message in the interp's
6273 * result if an error occurs.
6274 *
6275 * Side effects:
6276 * The size and/or location of winPtr may change.
6277 *
6278 *--------------------------------------------------------------
6279 */
6280
6281 static int
ParseGeometry(Tcl_Interp * interp,const char * string,TkWindow * winPtr)6282 ParseGeometry(
6283 Tcl_Interp *interp, /* Used for error reporting. */
6284 const char *string, /* String containing new geometry. Has the
6285 * standard form "=wxh+x+y". */
6286 TkWindow *winPtr) /* Pointer to top-level window whose geometry
6287 * is to be changed. */
6288 {
6289 WmInfo *wmPtr = winPtr->wmInfoPtr;
6290 int x, y, width, height, flags;
6291 char *end;
6292 const char *p = string;
6293
6294 /*
6295 * The leading "=" is optional.
6296 */
6297
6298 if (*p == '=') {
6299 p++;
6300 }
6301
6302 /*
6303 * Parse the width and height, if they are present. Don't actually update
6304 * any of the fields of wmPtr until we've successfully parsed the entire
6305 * geometry string.
6306 */
6307
6308 width = wmPtr->width;
6309 height = wmPtr->height;
6310 x = wmPtr->x;
6311 y = wmPtr->y;
6312 flags = wmPtr->flags;
6313 if (isdigit(UCHAR(*p))) {
6314 width = strtoul(p, &end, 10);
6315 p = end;
6316 if (*p != 'x') {
6317 goto error;
6318 }
6319 p++;
6320 if (!isdigit(UCHAR(*p))) {
6321 goto error;
6322 }
6323 height = strtoul(p, &end, 10);
6324 p = end;
6325 }
6326
6327 /*
6328 * Parse the X and Y coordinates, if they are present.
6329 */
6330
6331 if (*p != '\0') {
6332 flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
6333 if (*p == '-') {
6334 flags |= WM_NEGATIVE_X;
6335 } else if (*p != '+') {
6336 goto error;
6337 }
6338 p++;
6339 if (!isdigit(UCHAR(*p)) && (*p != '-')) {
6340 goto error;
6341 }
6342 x = strtol(p, &end, 10);
6343 p = end;
6344 if (*p == '-') {
6345 flags |= WM_NEGATIVE_Y;
6346 } else if (*p != '+') {
6347 goto error;
6348 }
6349 p++;
6350 if (!isdigit(UCHAR(*p)) && (*p != '-')) {
6351 goto error;
6352 }
6353 y = strtol(p, &end, 10);
6354 if (*end != '\0') {
6355 goto error;
6356 }
6357
6358 /*
6359 * Assume that the geometry information came from the user, unless an
6360 * explicit source has been specified. Otherwise most window managers
6361 * assume that the size hints were program-specified and they ignore
6362 * them.
6363 */
6364
6365 if (!(wmPtr->sizeHintsFlags & (USPosition|PPosition))) {
6366 wmPtr->sizeHintsFlags |= USPosition;
6367 }
6368 }
6369
6370 /*
6371 * Everything was parsed OK. Update the fields of *wmPtr and arrange for
6372 * the appropriate information to be percolated out to the window manager
6373 * at the next idle moment.
6374 */
6375
6376 wmPtr->width = width;
6377 wmPtr->height = height;
6378 wmPtr->x = x;
6379 wmPtr->y = y;
6380 flags |= WM_MOVE_PENDING;
6381 wmPtr->flags = flags;
6382
6383 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
6384 Tcl_DoWhenIdle(UpdateGeometryInfo, winPtr);
6385 wmPtr->flags |= WM_UPDATE_PENDING;
6386 }
6387 return TCL_OK;
6388
6389 error:
6390 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
6391 "bad geometry specifier \"%s\"", string));
6392 Tcl_SetErrorCode(interp, "TK", "VALUE", "GEOMETRY", NULL);
6393 return TCL_ERROR;
6394 }
6395
6396 /*
6397 *----------------------------------------------------------------------
6398 *
6399 * Tk_GetRootCoords --
6400 *
6401 * Given a token for a window, this function traces through the window's
6402 * lineage to find the (virtual) root-window coordinates corresponding to
6403 * point (0,0) in the window.
6404 *
6405 * Results:
6406 * The locations pointed to by xPtr and yPtr are filled in with the root
6407 * coordinates of the (0,0) point in tkwin.
6408 *
6409 * Side effects:
6410 * None.
6411 *
6412 *----------------------------------------------------------------------
6413 */
6414
6415 void
Tk_GetRootCoords(Tk_Window tkwin,int * xPtr,int * yPtr)6416 Tk_GetRootCoords(
6417 Tk_Window tkwin, /* Token for window. */
6418 int *xPtr, /* Where to store x-displacement of (0,0). */
6419 int *yPtr) /* Where to store y-displacement of (0,0). */
6420 {
6421 TkWindow *winPtr = (TkWindow *) tkwin;
6422
6423 /*
6424 * If the window is mapped, let Windows figure out the translation.
6425 */
6426
6427 if (winPtr->window != None) {
6428 HWND hwnd = Tk_GetHWND(winPtr->window);
6429 POINT point;
6430
6431 point.x = 0;
6432 point.y = 0;
6433
6434 ClientToScreen(hwnd, &point);
6435
6436 *xPtr = point.x;
6437 *yPtr = point.y;
6438 } else {
6439 *xPtr = 0;
6440 *yPtr = 0;
6441 }
6442 }
6443
6444 /*
6445 *----------------------------------------------------------------------
6446 *
6447 * Tk_CoordsToWindow --
6448 *
6449 * Given the (virtual) root coordinates of a point, this function returns
6450 * the token for the top-most window covering that point, if there exists
6451 * such a window in this application.
6452 *
6453 * Results:
6454 * The return result is either a token for the window corresponding to
6455 * rootX and rootY, or else NULL to indicate that there is no such
6456 * window.
6457 *
6458 * Side effects:
6459 * None.
6460 *
6461 *----------------------------------------------------------------------
6462 */
6463
6464 Tk_Window
Tk_CoordsToWindow(int rootX,int rootY,Tk_Window tkwin)6465 Tk_CoordsToWindow(
6466 int rootX, int rootY, /* Coordinates of point in root window. If a
6467 * virtual-root window manager is in use,
6468 * these coordinates refer to the virtual
6469 * root, not the real root. */
6470 Tk_Window tkwin) /* Token for any window in application; used
6471 * to identify the display. */
6472 {
6473 POINT pos;
6474 HWND hwnd;
6475 TkWindow *winPtr;
6476
6477 pos.x = rootX;
6478 pos.y = rootY;
6479 hwnd = WindowFromPoint(pos);
6480
6481 winPtr = (TkWindow *) Tk_HWNDToWindow(hwnd);
6482 if (winPtr && (winPtr->mainPtr == ((TkWindow *) tkwin)->mainPtr)) {
6483 return (Tk_Window) winPtr;
6484 }
6485 return NULL;
6486 }
6487
6488 /*
6489 *----------------------------------------------------------------------
6490 *
6491 * Tk_GetVRootGeometry --
6492 *
6493 * This function returns information about the virtual root window
6494 * corresponding to a particular Tk window.
6495 *
6496 * Results:
6497 * The values at xPtr, yPtr, widthPtr, and heightPtr are set with the
6498 * offset and dimensions of the root window corresponding to tkwin. If
6499 * tkwin is being managed by a virtual root window manager these values
6500 * correspond to the virtual root window being used for tkwin; otherwise
6501 * the offsets will be 0 and the dimensions will be those of the screen.
6502 *
6503 * Side effects:
6504 * Vroot window information is refreshed if it is out of date.
6505 *
6506 *----------------------------------------------------------------------
6507 */
6508
6509 void
Tk_GetVRootGeometry(TCL_UNUSED (Tk_Window),int * xPtr,int * yPtr,int * widthPtr,int * heightPtr)6510 Tk_GetVRootGeometry(
6511 TCL_UNUSED(Tk_Window), /* Window whose virtual root is to be
6512 * queried. */
6513 int *xPtr, int *yPtr, /* Store x and y offsets of virtual root
6514 * here. */
6515 int *widthPtr, int *heightPtr)
6516 /* Store dimensions of virtual root here. */
6517 {
6518 *xPtr = GetSystemMetrics(SM_XVIRTUALSCREEN);
6519 *yPtr = GetSystemMetrics(SM_YVIRTUALSCREEN);
6520 *widthPtr = GetSystemMetrics(SM_CXVIRTUALSCREEN);
6521 *heightPtr = GetSystemMetrics(SM_CYVIRTUALSCREEN);
6522 }
6523
6524 /*
6525 *----------------------------------------------------------------------
6526 *
6527 * Tk_MoveToplevelWindow --
6528 *
6529 * This function is called instead of Tk_MoveWindow to adjust the x-y
6530 * location of a top-level window. It delays the actual move to a later
6531 * time and keeps window-manager information up-to-date with the move
6532 *
6533 * Results:
6534 * None.
6535 *
6536 * Side effects:
6537 * The window is eventually moved so that its upper-left corner
6538 * (actually, the upper-left corner of the window's decorative frame, if
6539 * there is one) is at (x,y).
6540 *
6541 *----------------------------------------------------------------------
6542 */
6543
6544 void
Tk_MoveToplevelWindow(Tk_Window tkwin,int x,int y)6545 Tk_MoveToplevelWindow(
6546 Tk_Window tkwin, /* Window to move. */
6547 int x, int y) /* New location for window (within parent). */
6548 {
6549 TkWindow *winPtr = (TkWindow *) tkwin;
6550 WmInfo *wmPtr = winPtr->wmInfoPtr;
6551
6552 if (!(winPtr->flags & TK_TOP_LEVEL)) {
6553 Tcl_Panic("Tk_MoveToplevelWindow called with non-toplevel window");
6554 }
6555 wmPtr->x = x;
6556 wmPtr->y = y;
6557 wmPtr->flags |= WM_MOVE_PENDING;
6558 wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
6559 if (!(wmPtr->sizeHintsFlags & (USPosition|PPosition))) {
6560 wmPtr->sizeHintsFlags |= USPosition;
6561 }
6562
6563 /*
6564 * If the window has already been mapped, must bring its geometry
6565 * up-to-date immediately, otherwise an event might arrive from the server
6566 * that would overwrite wmPtr->x and wmPtr->y and lose the new position.
6567 */
6568
6569 if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
6570 if (wmPtr->flags & WM_UPDATE_PENDING) {
6571 Tcl_CancelIdleCall(UpdateGeometryInfo, winPtr);
6572 }
6573 UpdateGeometryInfo(winPtr);
6574 }
6575 }
6576
6577 /*
6578 *----------------------------------------------------------------------
6579 *
6580 * TkWmProtocolEventProc --
6581 *
6582 * This function is called by the Tk_HandleEvent whenever a ClientMessage
6583 * event arrives whose type is "WM_PROTOCOLS". This function handles the
6584 * message from the window manager in an appropriate fashion.
6585 *
6586 * Results:
6587 * None.
6588 *
6589 * Side effects:
6590 * Depends on what sort of handler, if any, was set up for the protocol.
6591 *
6592 *----------------------------------------------------------------------
6593 */
6594
6595 void
TkWmProtocolEventProc(TkWindow * winPtr,XEvent * eventPtr)6596 TkWmProtocolEventProc(
6597 TkWindow *winPtr, /* Window to which the event was sent. */
6598 XEvent *eventPtr) /* X event. */
6599 {
6600 WmInfo *wmPtr;
6601 ProtocolHandler *protPtr;
6602 Atom protocol;
6603 int result;
6604 Tcl_Interp *interp;
6605
6606 wmPtr = winPtr->wmInfoPtr;
6607 if (wmPtr == NULL) {
6608 return;
6609 }
6610 protocol = (Atom) eventPtr->xclient.data.l[0];
6611 for (protPtr = wmPtr->protPtr; protPtr != NULL;
6612 protPtr = protPtr->nextPtr) {
6613 if (protocol == protPtr->protocol) {
6614 /*
6615 * Cache atom name, as we might destroy the window as a result of
6616 * the eval.
6617 */
6618
6619 const char *name = Tk_GetAtomName((Tk_Window) winPtr, protocol);
6620
6621 Tcl_Preserve(protPtr);
6622 interp = protPtr->interp;
6623 Tcl_Preserve(interp);
6624 result = Tcl_EvalEx(interp, protPtr->command, -1, TCL_EVAL_GLOBAL);
6625 if (result != TCL_OK) {
6626 Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
6627 "\n (command for \"%s\" window manager protocol)",
6628 name));
6629 Tcl_BackgroundException(interp, result);
6630 }
6631 Tcl_Release(interp);
6632 Tcl_Release(protPtr);
6633 return;
6634 }
6635 }
6636
6637 /*
6638 * No handler was present for this protocol. If this is a WM_DELETE_WINDOW
6639 * message then just destroy the window.
6640 */
6641
6642 if (protocol == Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW")) {
6643 Tk_DestroyWindow((Tk_Window) winPtr);
6644 }
6645 }
6646
6647 /*
6648 *----------------------------------------------------------------------
6649 *
6650 * TkWmStackorderToplevelEnumProc --
6651 *
6652 * This function is invoked once for each HWND Window on the display as a
6653 * result of calling EnumWindows from TkWmStackorderToplevel.
6654 *
6655 * Results:
6656 * TRUE to request further iteration.
6657 *
6658 * Side effects:
6659 * Adds entries to the passed array of TkWindows.
6660 *
6661 *----------------------------------------------------------------------
6662 */
6663
6664 BOOL CALLBACK
TkWmStackorderToplevelEnumProc(HWND hwnd,LPARAM lParam)6665 TkWmStackorderToplevelEnumProc(
6666 HWND hwnd, /* Handle to parent window */
6667 LPARAM lParam) /* Application-defined value */
6668 {
6669 Tcl_HashEntry *hPtr;
6670 TkWindow *childWinPtr;
6671
6672 TkWmStackorderToplevelPair *pair =
6673 (TkWmStackorderToplevelPair *) lParam;
6674
6675 /*fprintf(stderr, "Looking up HWND %d\n", hwnd);*/
6676
6677 hPtr = Tcl_FindHashEntry(pair->table, (char *) hwnd);
6678 if (hPtr != NULL) {
6679 childWinPtr = (TkWindow *)Tcl_GetHashValue(hPtr);
6680
6681 /*
6682 * Double check that same HWND does not get passed twice.
6683 */
6684
6685 if (childWinPtr == NULL) {
6686 Tcl_Panic("duplicate HWND in TkWmStackorderToplevelEnumProc");
6687 } else {
6688 Tcl_SetHashValue(hPtr, NULL);
6689 }
6690 /*
6691 fprintf(stderr, "Found mapped HWND %d -> %x (%s)\n", hwnd,
6692 childWinPtr, childWinPtr->pathName);
6693 */
6694 *(pair->windowPtr)-- = childWinPtr;
6695 }
6696 return TRUE;
6697 }
6698
6699 /*
6700 *----------------------------------------------------------------------
6701 *
6702 * TkWmStackorderToplevelWrapperMap --
6703 *
6704 * This function will create a table that maps the wrapper HWND id for a
6705 * toplevel to the TkWindow structure that is wraps.
6706 *
6707 * Results:
6708 * None.
6709 *
6710 * Side effects:
6711 * Adds entries to the passed hashtable.
6712 *
6713 *----------------------------------------------------------------------
6714 */
6715
6716 static void
TkWmStackorderToplevelWrapperMap(TkWindow * winPtr,Display * display,Tcl_HashTable * table)6717 TkWmStackorderToplevelWrapperMap(
6718 TkWindow *winPtr, /* TkWindow to recurse on */
6719 Display *display, /* X display of parent window */
6720 Tcl_HashTable *table) /* Table to maps HWND to TkWindow */
6721 {
6722 TkWindow *childPtr;
6723 Tcl_HashEntry *hPtr;
6724 HWND wrapper;
6725 int newEntry;
6726
6727 if (Tk_IsMapped(winPtr) && Tk_IsTopLevel(winPtr)
6728 && !Tk_IsEmbedded(winPtr) && (winPtr->display == display)) {
6729 wrapper = TkWinGetWrapperWindow((Tk_Window) winPtr);
6730
6731 /*
6732 fprintf(stderr, "Mapped HWND %d to %x (%s)\n", wrapper,
6733 winPtr, winPtr->pathName);
6734 */
6735
6736 hPtr = Tcl_CreateHashEntry(table, (char *) wrapper, &newEntry);
6737 Tcl_SetHashValue(hPtr, winPtr);
6738 }
6739
6740 for (childPtr = winPtr->childList; childPtr != NULL;
6741 childPtr = childPtr->nextPtr) {
6742 TkWmStackorderToplevelWrapperMap(childPtr, display, table);
6743 }
6744 }
6745 /*
6746 *----------------------------------------------------------------------
6747 *
6748 * TkWmStackorderToplevel --
6749 *
6750 * This function returns the stack order of toplevel windows.
6751 *
6752 * Results:
6753 * An array of pointers to tk window objects in stacking order or else
6754 * NULL if there was an error.
6755 *
6756 * Side effects:
6757 * None.
6758 *
6759 *----------------------------------------------------------------------
6760 */
6761
6762 TkWindow **
TkWmStackorderToplevel(TkWindow * parentPtr)6763 TkWmStackorderToplevel(
6764 TkWindow *parentPtr) /* Parent toplevel window. */
6765 {
6766 TkWmStackorderToplevelPair pair;
6767 TkWindow **windows;
6768 Tcl_HashTable table;
6769 Tcl_HashEntry *hPtr;
6770 Tcl_HashSearch search;
6771
6772 /*
6773 * Map HWND ids to a TkWindow of the wrapped toplevel.
6774 */
6775
6776 Tcl_InitHashTable(&table, TCL_ONE_WORD_KEYS);
6777 TkWmStackorderToplevelWrapperMap(parentPtr, parentPtr->display, &table);
6778
6779 windows = (TkWindow **)ckalloc((table.numEntries+1) * sizeof(TkWindow *));
6780
6781 /*
6782 * Special cases: If zero or one toplevels were mapped there is no need to
6783 * call EnumWindows.
6784 */
6785
6786 switch (table.numEntries) {
6787 case 0:
6788 windows[0] = NULL;
6789 goto done;
6790 case 1:
6791 hPtr = Tcl_FirstHashEntry(&table, &search);
6792 windows[0] = (TkWindow *)Tcl_GetHashValue(hPtr);
6793 windows[1] = NULL;
6794 goto done;
6795 }
6796
6797 /*
6798 * We will be inserting into the array starting at the end and working our
6799 * way to the beginning since EnumWindows returns windows in highest to
6800 * lowest order.
6801 */
6802
6803 pair.table = &table;
6804 pair.windowPtr = windows + table.numEntries;
6805 *pair.windowPtr-- = NULL;
6806
6807 if (EnumWindows((WNDENUMPROC) TkWmStackorderToplevelEnumProc,
6808 (LPARAM) &pair) == 0) {
6809 ckfree(windows);
6810 windows = NULL;
6811 }
6812
6813 done:
6814 Tcl_DeleteHashTable(&table);
6815 return windows;
6816 }
6817
6818 /*
6819 *----------------------------------------------------------------------
6820 *
6821 * TkWmRestackToplevel --
6822 *
6823 * This function restacks a top-level window.
6824 *
6825 * Results:
6826 * None.
6827 *
6828 * Side effects:
6829 * WinPtr gets restacked as specified by aboveBelow and otherPtr. This
6830 * function doesn't return until the restack has taken effect and the
6831 * ConfigureNotify event for it has been received.
6832 *
6833 *----------------------------------------------------------------------
6834 */
6835
6836 void
TkWmRestackToplevel(TkWindow * winPtr,int aboveBelow,TkWindow * otherPtr)6837 TkWmRestackToplevel(
6838 TkWindow *winPtr, /* Window to restack. */
6839 int aboveBelow, /* Gives relative position for restacking;
6840 * must be Above or Below. */
6841 TkWindow *otherPtr) /* Window relative to which to restack; if
6842 * NULL, then winPtr gets restacked above or
6843 * below *all* siblings. */
6844 {
6845 HWND hwnd, insertAfter;
6846
6847 /*
6848 * Can't set stacking order properly until the window is on the screen
6849 * (mapping it may give it a reparent window).
6850 */
6851
6852 if (winPtr->window == None) {
6853 Tk_MakeWindowExist((Tk_Window) winPtr);
6854 }
6855 if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
6856 TkWmMapWindow(winPtr);
6857 }
6858 hwnd = (winPtr->wmInfoPtr->wrapper != NULL)
6859 ? winPtr->wmInfoPtr->wrapper : Tk_GetHWND(winPtr->window);
6860
6861 if (otherPtr != NULL) {
6862 if (otherPtr->window == None) {
6863 Tk_MakeWindowExist((Tk_Window) otherPtr);
6864 }
6865 if (otherPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
6866 TkWmMapWindow(otherPtr);
6867 }
6868 insertAfter = (otherPtr->wmInfoPtr->wrapper != NULL)
6869 ? otherPtr->wmInfoPtr->wrapper : Tk_GetHWND(otherPtr->window);
6870 } else {
6871 insertAfter = NULL;
6872 }
6873
6874 if (winPtr->flags & TK_EMBEDDED) {
6875 SendMessageW(winPtr->wmInfoPtr->wrapper, TK_RAISEWINDOW,
6876 (WPARAM) insertAfter, aboveBelow);
6877 } else {
6878 TkWinSetWindowPos(hwnd, insertAfter, aboveBelow);
6879 }
6880 }
6881
6882 /*
6883 *----------------------------------------------------------------------
6884 *
6885 * TkWmAddToColormapWindows --
6886 *
6887 * This function is called to add a given window to the
6888 * WM_COLORMAP_WINDOWS property for its top-level, if it isn't already
6889 * there. It is invoked by the Tk code that creates a new colormap, in
6890 * order to make sure that colormap information is propagated to the
6891 * window manager by default.
6892 *
6893 * Results:
6894 * None.
6895 *
6896 * Side effects:
6897 * WinPtr's window gets added to the WM_COLORMAP_WINDOWS property of its
6898 * nearest top-level ancestor, unless the colormaps have been set
6899 * explicitly with the "wm colormapwindows" command.
6900 *
6901 *----------------------------------------------------------------------
6902 */
6903
6904 void
TkWmAddToColormapWindows(TkWindow * winPtr)6905 TkWmAddToColormapWindows(
6906 TkWindow *winPtr) /* Window with a non-default colormap. Should
6907 * not be a top-level window. */
6908 {
6909 TkWindow *topPtr;
6910 TkWindow **oldPtr, **newPtr;
6911 int count, i;
6912
6913 if (winPtr->window == None) {
6914 return;
6915 }
6916
6917 for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
6918 if (topPtr == NULL) {
6919 /*
6920 * Window is being deleted. Skip the whole operation.
6921 */
6922
6923 return;
6924 }
6925 if (topPtr->flags & TK_TOP_HIERARCHY) {
6926 break;
6927 }
6928 }
6929 if (topPtr->wmInfoPtr == NULL) {
6930 return;
6931 }
6932
6933 if (topPtr->wmInfoPtr->flags & WM_COLORMAPS_EXPLICIT) {
6934 return;
6935 }
6936
6937 /*
6938 * Make sure that the window isn't already in the list.
6939 */
6940
6941 count = topPtr->wmInfoPtr->cmapCount;
6942 oldPtr = topPtr->wmInfoPtr->cmapList;
6943
6944 for (i = 0; i < count; i++) {
6945 if (oldPtr[i] == winPtr) {
6946 return;
6947 }
6948 }
6949
6950 /*
6951 * Make a new bigger array and use it to reset the property.
6952 * Automatically add the toplevel itself as the last element of the list.
6953 */
6954
6955 newPtr = (TkWindow **)ckalloc((count+2) * sizeof(TkWindow *));
6956 if (count > 0) {
6957 memcpy(newPtr, oldPtr, count * sizeof(TkWindow*));
6958 }
6959 if (count == 0) {
6960 count++;
6961 }
6962 newPtr[count-1] = winPtr;
6963 newPtr[count] = topPtr;
6964 if (oldPtr != NULL) {
6965 ckfree(oldPtr);
6966 }
6967
6968 topPtr->wmInfoPtr->cmapList = newPtr;
6969 topPtr->wmInfoPtr->cmapCount = count+1;
6970
6971 /*
6972 * Now we need to force the updated colormaps to be installed.
6973 */
6974
6975 if (topPtr->wmInfoPtr == winPtr->dispPtr->foregroundWmPtr) {
6976 InstallColormaps(topPtr->wmInfoPtr->wrapper, WM_QUERYNEWPALETTE, 1);
6977 } else {
6978 InstallColormaps(topPtr->wmInfoPtr->wrapper, WM_PALETTECHANGED, 0);
6979 }
6980 }
6981
6982 /*
6983 *----------------------------------------------------------------------
6984 *
6985 * TkWmRemoveFromColormapWindows --
6986 *
6987 * This function is called to remove a given window from the
6988 * WM_COLORMAP_WINDOWS property for its top-level. It is invoked when
6989 * windows are deleted.
6990 *
6991 * Results:
6992 * None.
6993 *
6994 * Side effects:
6995 * WinPtr's window gets removed from the WM_COLORMAP_WINDOWS property of
6996 * its nearest top-level ancestor, unless the top-level itself is being
6997 * deleted too.
6998 *
6999 *----------------------------------------------------------------------
7000 */
7001
7002 void
TkWmRemoveFromColormapWindows(TkWindow * winPtr)7003 TkWmRemoveFromColormapWindows(
7004 TkWindow *winPtr) /* Window that may be present in
7005 * WM_COLORMAP_WINDOWS property for its
7006 * top-level. Should not be a top-level
7007 * window. */
7008 {
7009 TkWindow *topPtr;
7010 TkWindow **oldPtr;
7011 int count, i, j;
7012
7013 for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
7014 if (topPtr == NULL) {
7015 /*
7016 * Ancestors have been deleted, so skip the whole operation.
7017 * Seems like this can't ever happen?
7018 */
7019
7020 return;
7021 }
7022 if (topPtr->flags & TK_TOP_LEVEL) {
7023 break;
7024 }
7025 }
7026 if (topPtr->flags & TK_ALREADY_DEAD) {
7027 /*
7028 * Top-level is being deleted, so there's no need to cleanup the
7029 * WM_COLORMAP_WINDOWS property.
7030 */
7031
7032 return;
7033 }
7034
7035 if (topPtr->wmInfoPtr == NULL) {
7036 return;
7037 }
7038
7039 /*
7040 * Find the window and slide the following ones down to cover it up.
7041 */
7042
7043 count = topPtr->wmInfoPtr->cmapCount;
7044 oldPtr = topPtr->wmInfoPtr->cmapList;
7045 for (i = 0; i < count; i++) {
7046 if (oldPtr[i] == winPtr) {
7047 for (j = i ; j < count-1; j++) {
7048 oldPtr[j] = oldPtr[j+1];
7049 }
7050 topPtr->wmInfoPtr->cmapCount = count-1;
7051 break;
7052 }
7053 }
7054 }
7055
7056 /*
7057 *----------------------------------------------------------------------
7058 *
7059 * TkWinSetMenu--
7060 *
7061 * Associcates a given HMENU to a window.
7062 *
7063 * Results:
7064 * None.
7065 *
7066 * Side effects:
7067 * The menu will end up being drawn in the window, and the geometry of
7068 * the window will have to be changed.
7069 *
7070 *----------------------------------------------------------------------
7071 */
7072
7073 void
TkWinSetMenu(Tk_Window tkwin,HMENU hMenu)7074 TkWinSetMenu(
7075 Tk_Window tkwin, /* the window to put the menu in */
7076 HMENU hMenu) /* the menu to set */
7077 {
7078 TkWindow *winPtr = (TkWindow *) tkwin;
7079 WmInfo *wmPtr = winPtr->wmInfoPtr;
7080
7081 /* Could be a Frame (i.e. not a Toplevel) */
7082 if (wmPtr == NULL)
7083 return;
7084
7085 wmPtr->hMenu = hMenu;
7086 if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
7087 int syncPending = wmPtr->flags & WM_SYNC_PENDING;
7088
7089 wmPtr->flags |= WM_SYNC_PENDING;
7090 SetMenu(wmPtr->wrapper, hMenu);
7091 if (!syncPending) {
7092 wmPtr->flags &= ~WM_SYNC_PENDING;
7093 }
7094 }
7095 if (!(winPtr->flags & TK_EMBEDDED)) {
7096 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
7097 Tcl_DoWhenIdle(UpdateGeometryInfo, winPtr);
7098 wmPtr->flags |= WM_UPDATE_PENDING|WM_MOVE_PENDING;
7099 }
7100 } else {
7101 SendMessageW(wmPtr->wrapper, TK_SETMENU, (WPARAM) hMenu,
7102 (LPARAM) Tk_GetMenuHWND(tkwin));
7103 }
7104 }
7105
7106 /*
7107 *----------------------------------------------------------------------
7108 *
7109 * ConfigureTopLevel --
7110 *
7111 * Generate a ConfigureNotify event based on the current position
7112 * information. This function is called by TopLevelProc.
7113 *
7114 * Results:
7115 * None.
7116 *
7117 * Side effects:
7118 * Queues a new event.
7119 *
7120 *----------------------------------------------------------------------
7121 */
7122
7123 static void
ConfigureTopLevel(WINDOWPOS * pos)7124 ConfigureTopLevel(
7125 WINDOWPOS *pos)
7126 {
7127 TkWindow *winPtr = GetTopLevel(pos->hwnd);
7128 WmInfo *wmPtr;
7129 int state; /* Current window state. */
7130 RECT rect;
7131 WINDOWPLACEMENT windowPos;
7132
7133 if (winPtr == NULL) {
7134 return;
7135 }
7136
7137 wmPtr = winPtr->wmInfoPtr;
7138
7139 /*
7140 * Determine the current window state.
7141 */
7142
7143 if (!IsWindowVisible(wmPtr->wrapper)) {
7144 state = WithdrawnState;
7145 } else {
7146 windowPos.length = sizeof(WINDOWPLACEMENT);
7147 GetWindowPlacement(wmPtr->wrapper, &windowPos);
7148 switch (windowPos.showCmd) {
7149 case SW_SHOWMAXIMIZED:
7150 state = ZoomState;
7151 break;
7152 case SW_SHOWMINIMIZED:
7153 state = IconicState;
7154 break;
7155 case SW_SHOWNORMAL:
7156 default:
7157 state = NormalState;
7158 break;
7159 }
7160 }
7161
7162 /*
7163 * If the state of the window just changed, be sure to update the
7164 * child window information.
7165 */
7166
7167 if (wmPtr->hints.initial_state != state) {
7168 wmPtr->hints.initial_state = state;
7169 switch (state) {
7170 case WithdrawnState:
7171 case IconicState:
7172 XUnmapWindow(winPtr->display, winPtr->window);
7173 break;
7174
7175 case NormalState:
7176 /*
7177 * Schedule a geometry update. Since we ignore geometry requests
7178 * while in any other state, the geometry info may be stale.
7179 */
7180
7181 if (!(wmPtr->flags & WM_UPDATE_PENDING)) {
7182 Tcl_DoWhenIdle(UpdateGeometryInfo, winPtr);
7183 wmPtr->flags |= WM_UPDATE_PENDING;
7184 }
7185 /* fall through */
7186 case ZoomState:
7187 XMapWindow(winPtr->display, winPtr->window);
7188 pos->flags |= SWP_NOMOVE | SWP_NOSIZE;
7189 break;
7190 }
7191 }
7192
7193 /*
7194 * Don't report geometry changes in the Iconic or Withdrawn states.
7195 */
7196
7197 if (state == WithdrawnState || state == IconicState) {
7198 return;
7199 }
7200
7201
7202 /*
7203 * Compute the current geometry of the client area, reshape the Tk window
7204 * and generate a ConfigureNotify event.
7205 */
7206
7207 GetClientRect(wmPtr->wrapper, &rect);
7208 winPtr->changes.x = pos->x;
7209 winPtr->changes.y = pos->y;
7210 winPtr->changes.width = rect.right - rect.left;
7211 winPtr->changes.height = rect.bottom - rect.top;
7212 wmPtr->borderHeight = pos->cy - winPtr->changes.height;
7213 MoveWindow(Tk_GetHWND(winPtr->window), 0, 0,
7214 winPtr->changes.width, winPtr->changes.height, TRUE);
7215 GenerateConfigureNotify(winPtr);
7216
7217 /*
7218 * Update window manager geometry info if needed.
7219 */
7220
7221 if (state == NormalState) {
7222
7223 /*
7224 * Update size information from the event. There are a couple of
7225 * tricky points here:
7226 *
7227 * 1. If the user changed the size externally then set wmPtr->width
7228 * and wmPtr->height just as if a "wm geometry" command had been
7229 * invoked with the same information.
7230 * 2. However, if the size is changing in response to a request coming
7231 * from us (sync is set), then don't set wmPtr->width or
7232 * wmPtr->height (otherwise the window will stop tracking geometry
7233 * manager requests).
7234 */
7235
7236 if (!(wmPtr->flags & WM_SYNC_PENDING)) {
7237 if (!(pos->flags & SWP_NOSIZE)) {
7238 if ((wmPtr->width == -1)
7239 && (winPtr->changes.width == winPtr->reqWidth)) {
7240 /*
7241 * Don't set external width, since the user didn't change
7242 * it from what the widgets asked for.
7243 */
7244 } else {
7245 if (wmPtr->gridWin != NULL) {
7246 wmPtr->width = wmPtr->reqGridWidth
7247 + (winPtr->changes.width - winPtr->reqWidth)
7248 / wmPtr->widthInc;
7249 if (wmPtr->width < 0) {
7250 wmPtr->width = 0;
7251 }
7252 } else {
7253 wmPtr->width = winPtr->changes.width;
7254 }
7255 }
7256 if ((wmPtr->height == -1)
7257 && (winPtr->changes.height == winPtr->reqHeight)) {
7258 /*
7259 * Don't set external height, since the user didn't change
7260 * it from what the widgets asked for.
7261 */
7262 } else {
7263 if (wmPtr->gridWin != NULL) {
7264 wmPtr->height = wmPtr->reqGridHeight
7265 + (winPtr->changes.height - winPtr->reqHeight)
7266 / wmPtr->heightInc;
7267 if (wmPtr->height < 0) {
7268 wmPtr->height = 0;
7269 }
7270 } else {
7271 wmPtr->height = winPtr->changes.height;
7272 }
7273 }
7274 wmPtr->configWidth = winPtr->changes.width;
7275 wmPtr->configHeight = winPtr->changes.height;
7276 }
7277
7278 /*
7279 * If the user moved the window, we should switch back to normal
7280 * coordinates.
7281 */
7282
7283 if (!(pos->flags & SWP_NOMOVE)) {
7284 wmPtr->flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
7285 }
7286 }
7287
7288 /*
7289 * Update the wrapper window location information.
7290 */
7291
7292 if (wmPtr->flags & WM_NEGATIVE_X) {
7293 wmPtr->x = DisplayWidth(winPtr->display, winPtr->screenNum)
7294 - winPtr->changes.x - (winPtr->changes.width
7295 + wmPtr->borderWidth);
7296 } else {
7297 wmPtr->x = winPtr->changes.x;
7298 }
7299 if (wmPtr->flags & WM_NEGATIVE_Y) {
7300 wmPtr->y = DisplayHeight(winPtr->display, winPtr->screenNum)
7301 - winPtr->changes.y - (winPtr->changes.height
7302 + wmPtr->borderHeight);
7303 } else {
7304 wmPtr->y = winPtr->changes.y;
7305 }
7306 }
7307 }
7308
7309 /*
7310 *----------------------------------------------------------------------
7311 *
7312 * GenerateConfigureNotify --
7313 *
7314 * Generate a ConfigureNotify event from the current geometry information
7315 * for the specified toplevel window.
7316 *
7317 * Results:
7318 * None.
7319 *
7320 * Side effects:
7321 * Sends an X event.
7322 *
7323 *----------------------------------------------------------------------
7324 */
7325
7326 static void
GenerateConfigureNotify(TkWindow * winPtr)7327 GenerateConfigureNotify(
7328 TkWindow *winPtr)
7329 {
7330 XEvent event;
7331
7332 /*
7333 * Generate a ConfigureNotify event.
7334 */
7335
7336 event.type = ConfigureNotify;
7337 event.xconfigure.serial = winPtr->display->request;
7338 event.xconfigure.send_event = False;
7339 event.xconfigure.display = winPtr->display;
7340 event.xconfigure.event = winPtr->window;
7341 event.xconfigure.window = winPtr->window;
7342 event.xconfigure.border_width = winPtr->changes.border_width;
7343 event.xconfigure.override_redirect = winPtr->atts.override_redirect;
7344 event.xconfigure.x = winPtr->changes.x;
7345 event.xconfigure.y = winPtr->changes.y;
7346 event.xconfigure.width = winPtr->changes.width;
7347 event.xconfigure.height = winPtr->changes.height;
7348 event.xconfigure.above = None;
7349 Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
7350 }
7351
7352 /*
7353 *----------------------------------------------------------------------
7354 *
7355 * InstallColormaps --
7356 *
7357 * Installs the colormaps associated with the toplevel which is currently
7358 * active.
7359 *
7360 * Results:
7361 * None.
7362 *
7363 * Side effects:
7364 * May change the system palette and generate damage.
7365 *
7366 *----------------------------------------------------------------------
7367 */
7368
7369 static int
InstallColormaps(HWND hwnd,int message,int isForemost)7370 InstallColormaps(
7371 HWND hwnd, /* Toplevel wrapper window whose colormaps
7372 * should be installed. */
7373 int message, /* Either WM_PALETTECHANGED or
7374 * WM_QUERYNEWPALETTE */
7375 int isForemost) /* 1 if window is foremost, else 0 */
7376 {
7377 int i;
7378 HDC dc;
7379 HPALETTE oldPalette;
7380 TkWindow *winPtr = GetTopLevel(hwnd);
7381 WmInfo *wmPtr;
7382 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
7383 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
7384
7385 if (winPtr == NULL || (winPtr->flags & TK_ALREADY_DEAD)) {
7386 return 0;
7387 }
7388
7389 wmPtr = winPtr->wmInfoPtr;
7390
7391 if (message == WM_QUERYNEWPALETTE) {
7392 /*
7393 * Case 1: This window is about to become the foreground window, so we
7394 * need to install the primary palette. If the system palette was
7395 * updated, then Windows will generate a WM_PALETTECHANGED message.
7396 * Otherwise, we have to synthesize one in order to ensure that the
7397 * secondary palettes are installed properly.
7398 */
7399
7400 winPtr->dispPtr->foregroundWmPtr = wmPtr;
7401
7402 if (wmPtr->cmapCount > 0) {
7403 winPtr = wmPtr->cmapList[0];
7404 }
7405
7406 tsdPtr->systemPalette = TkWinGetPalette(winPtr->atts.colormap);
7407 dc = GetDC(hwnd);
7408 oldPalette = SelectPalette(dc, tsdPtr->systemPalette, FALSE);
7409 if (RealizePalette(dc)) {
7410 RefreshColormap(winPtr->atts.colormap, winPtr->dispPtr);
7411 } else if (wmPtr->cmapCount > 1) {
7412 SelectPalette(dc, oldPalette, TRUE);
7413 RealizePalette(dc);
7414 ReleaseDC(hwnd, dc);
7415 SendMessageW(hwnd, WM_PALETTECHANGED, (WPARAM) hwnd, (LPARAM) NULL);
7416 return TRUE;
7417 }
7418 } else {
7419 /*
7420 * Window is being notified of a change in the system palette. If this
7421 * window is the foreground window, then we should only install the
7422 * secondary palettes, since the primary was installed in response to
7423 * the WM_QUERYPALETTE message. Otherwise, install all of the
7424 * palettes.
7425 */
7426
7427
7428 if (!isForemost) {
7429 if (wmPtr->cmapCount > 0) {
7430 winPtr = wmPtr->cmapList[0];
7431 }
7432 i = 1;
7433 } else {
7434 if (wmPtr->cmapCount <= 1) {
7435 return TRUE;
7436 }
7437 winPtr = wmPtr->cmapList[1];
7438 i = 2;
7439 }
7440 dc = GetDC(hwnd);
7441 oldPalette = SelectPalette(dc,
7442 TkWinGetPalette(winPtr->atts.colormap), TRUE);
7443 if (RealizePalette(dc)) {
7444 RefreshColormap(winPtr->atts.colormap, winPtr->dispPtr);
7445 }
7446 for (; i < wmPtr->cmapCount; i++) {
7447 winPtr = wmPtr->cmapList[i];
7448 SelectPalette(dc, TkWinGetPalette(winPtr->atts.colormap), TRUE);
7449 if (RealizePalette(dc)) {
7450 RefreshColormap(winPtr->atts.colormap, winPtr->dispPtr);
7451 }
7452 }
7453 }
7454
7455 SelectPalette(dc, oldPalette, TRUE);
7456 RealizePalette(dc);
7457 ReleaseDC(hwnd, dc);
7458 return TRUE;
7459 }
7460
7461 /*
7462 *----------------------------------------------------------------------
7463 *
7464 * RefreshColormap --
7465 *
7466 * This function is called to force all of the windows that use a given
7467 * colormap to redraw themselves. The quickest way to do this is to
7468 * iterate over the toplevels, looking in the cmapList for matches. This
7469 * will quickly eliminate subtrees that don't use a given colormap.
7470 *
7471 * Results:
7472 * None.
7473 *
7474 * Side effects:
7475 * Causes damage events to be generated.
7476 *
7477 *----------------------------------------------------------------------
7478 */
7479
7480 static void
RefreshColormap(Colormap colormap,TkDisplay * dispPtr)7481 RefreshColormap(
7482 Colormap colormap,
7483 TkDisplay *dispPtr)
7484 {
7485 WmInfo *wmPtr;
7486 int i;
7487
7488 for (wmPtr = dispPtr->firstWmPtr; wmPtr != NULL; wmPtr = wmPtr->nextPtr) {
7489 if (wmPtr->cmapCount > 0) {
7490 for (i = 0; i < wmPtr->cmapCount; i++) {
7491 if ((wmPtr->cmapList[i]->atts.colormap == colormap)
7492 && Tk_IsMapped(wmPtr->cmapList[i])) {
7493 InvalidateSubTree(wmPtr->cmapList[i], colormap);
7494 }
7495 }
7496 } else if ((wmPtr->winPtr->atts.colormap == colormap)
7497 && Tk_IsMapped(wmPtr->winPtr)) {
7498 InvalidateSubTree(wmPtr->winPtr, colormap);
7499 }
7500 }
7501 }
7502
7503 /*
7504 *----------------------------------------------------------------------
7505 *
7506 * InvalidateSubTree --
7507 *
7508 * This function recursively generates damage for a window and all of its
7509 * mapped children that belong to the same toplevel and are using the
7510 * specified colormap.
7511 *
7512 * Results:
7513 * None.
7514 *
7515 * Side effects:
7516 * Generates damage for the specified subtree.
7517 *
7518 *----------------------------------------------------------------------
7519 */
7520
7521 static void
InvalidateSubTree(TkWindow * winPtr,Colormap colormap)7522 InvalidateSubTree(
7523 TkWindow *winPtr,
7524 Colormap colormap)
7525 {
7526 TkWindow *childPtr;
7527
7528 /*
7529 * Generate damage for the current window if it is using the specified
7530 * colormap.
7531 */
7532
7533 if (winPtr->atts.colormap == colormap) {
7534 InvalidateRect(Tk_GetHWND(winPtr->window), NULL, FALSE);
7535 }
7536
7537 for (childPtr = winPtr->childList; childPtr != NULL;
7538 childPtr = childPtr->nextPtr) {
7539 /*
7540 * We can stop the descent when we hit an unmapped or toplevel window.
7541 */
7542
7543 if (!Tk_TopWinHierarchy(childPtr) && Tk_IsMapped(childPtr)) {
7544 InvalidateSubTree(childPtr, colormap);
7545 }
7546 }
7547 }
7548
7549 /*
7550 *----------------------------------------------------------------------
7551 *
7552 * InvalidateSubTreeDepth --
7553 *
7554 * This function recursively updates depth info for a window and all of
7555 * its children that belong to the same toplevel.
7556 *
7557 * Results:
7558 * None.
7559 *
7560 * Side effects:
7561 * Sets the depth of each window to that of the display.
7562 *
7563 *----------------------------------------------------------------------
7564 */
7565
7566 static void
InvalidateSubTreeDepth(TkWindow * winPtr)7567 InvalidateSubTreeDepth(
7568 TkWindow *winPtr)
7569 {
7570 Display *display = Tk_Display(winPtr);
7571 int screenNum = Tk_ScreenNumber(winPtr);
7572 TkWindow *childPtr;
7573
7574 winPtr->depth = DefaultDepth(display, screenNum);
7575
7576 #if 0
7577 /*
7578 * XXX: What other elements may require changes? Changing just the depth
7579 * works for standard windows and 16/24/32-bpp changes. I suspect 8-bit
7580 * (palettized) displays may require colormap and/or visual changes as
7581 * well.
7582 */
7583
7584 if (winPtr->window) {
7585 InvalidateRect(Tk_GetHWND(winPtr->window), NULL, FALSE);
7586 }
7587 winPtr->visual = DefaultVisual(display, screenNum);
7588 winPtr->atts.colormap = DefaultColormap(display, screenNum);
7589 winPtr->dirtyAtts |= CWColormap;
7590 #endif
7591
7592 for (childPtr = winPtr->childList; childPtr != NULL;
7593 childPtr = childPtr->nextPtr) {
7594 /*
7595 * We can stop the descent when we hit a non-embedded toplevel window,
7596 * as it should get its own message.
7597 */
7598
7599 if (childPtr->flags & TK_EMBEDDED || !Tk_TopWinHierarchy(childPtr)) {
7600 InvalidateSubTreeDepth(childPtr);
7601 }
7602 }
7603 }
7604
7605 /*
7606 *----------------------------------------------------------------------
7607 *
7608 * TkWinGetSystemPalette --
7609 *
7610 * Retrieves the currently installed foreground palette.
7611 *
7612 * Results:
7613 * Returns the global foreground palette, if there is one. Otherwise,
7614 * returns NULL.
7615 *
7616 * Side effects:
7617 * None.
7618 *
7619 *----------------------------------------------------------------------
7620 */
7621
7622 HPALETTE
TkWinGetSystemPalette(void)7623 TkWinGetSystemPalette(void)
7624 {
7625 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
7626 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
7627
7628 return tsdPtr->systemPalette;
7629 }
7630
7631 /*
7632 *----------------------------------------------------------------------
7633 *
7634 * GetMinSize --
7635 *
7636 * This function computes the current minWidth and minHeight values for a
7637 * window, taking into account the possibility that they may be
7638 * defaulted.
7639 *
7640 * Results:
7641 * The values at *minWidthPtr and *minHeightPtr are filled in with the
7642 * minimum allowable dimensions of wmPtr's window, in grid units. If the
7643 * requested minimum is smaller than the system required minimum, then
7644 * this function computes the smallest size that will satisfy both the
7645 * system and the grid constraints.
7646 *
7647 * Side effects:
7648 * None.
7649 *
7650 *----------------------------------------------------------------------
7651 */
7652
7653 static void
GetMinSize(WmInfo * wmPtr,int * minWidthPtr,int * minHeightPtr)7654 GetMinSize(
7655 WmInfo *wmPtr, /* Window manager information for the
7656 * window. */
7657 int *minWidthPtr, /* Where to store the current minimum width of
7658 * the window. */
7659 int *minHeightPtr) /* Where to store the current minimum height
7660 * of the window. */
7661 {
7662 int tmp, base;
7663 TkWindow *winPtr = wmPtr->winPtr;
7664
7665 /*
7666 * Compute the minimum width by taking the default client size and
7667 * rounding it up to the nearest grid unit. Return the greater of the
7668 * default minimum and the specified minimum.
7669 */
7670
7671 tmp = wmPtr->defMinWidth - wmPtr->borderWidth;
7672 if (tmp < 0) {
7673 tmp = 0;
7674 }
7675 if (wmPtr->gridWin != NULL) {
7676 base = winPtr->reqWidth - (wmPtr->reqGridWidth * wmPtr->widthInc);
7677 if (base < 0) {
7678 base = 0;
7679 }
7680 tmp = ((tmp - base) + wmPtr->widthInc - 1)/wmPtr->widthInc;
7681 }
7682 if (tmp < wmPtr->minWidth) {
7683 tmp = wmPtr->minWidth;
7684 }
7685 *minWidthPtr = tmp;
7686
7687 /*
7688 * Compute the minimum height in a similar fashion.
7689 */
7690
7691 tmp = wmPtr->defMinHeight - wmPtr->borderHeight;
7692 if (tmp < 0) {
7693 tmp = 0;
7694 }
7695 if (wmPtr->gridWin != NULL) {
7696 base = winPtr->reqHeight - (wmPtr->reqGridHeight * wmPtr->heightInc);
7697 if (base < 0) {
7698 base = 0;
7699 }
7700 tmp = ((tmp - base) + wmPtr->heightInc - 1)/wmPtr->heightInc;
7701 }
7702 if (tmp < wmPtr->minHeight) {
7703 tmp = wmPtr->minHeight;
7704 }
7705 *minHeightPtr = tmp;
7706 }
7707
7708 /*
7709 *----------------------------------------------------------------------
7710 *
7711 * GetMaxSize --
7712 *
7713 * This function computes the current maxWidth and maxHeight values for a
7714 * window, taking into account the possibility that they may be
7715 * defaulted.
7716 *
7717 * Results:
7718 * The values at *maxWidthPtr and *maxHeightPtr are filled in with the
7719 * maximum allowable dimensions of wmPtr's window, in grid units. If no
7720 * maximum has been specified for the window, then this function computes
7721 * the largest sizes that will fit on the screen.
7722 *
7723 * Side effects:
7724 * None.
7725 *
7726 *----------------------------------------------------------------------
7727 */
7728
7729 static void
GetMaxSize(WmInfo * wmPtr,int * maxWidthPtr,int * maxHeightPtr)7730 GetMaxSize(
7731 WmInfo *wmPtr, /* Window manager information for the
7732 * window. */
7733 int *maxWidthPtr, /* Where to store the current maximum width of
7734 * the window. */
7735 int *maxHeightPtr) /* Where to store the current maximum height
7736 * of the window. */
7737 {
7738 int tmp;
7739
7740 if (wmPtr->maxWidth > 0) {
7741 *maxWidthPtr = wmPtr->maxWidth;
7742 } else {
7743 /*
7744 * Must compute a default width. Fill up the display, leaving a bit of
7745 * extra space for the window manager's borders.
7746 */
7747
7748 tmp = wmPtr->defMaxWidth - wmPtr->borderWidth;
7749 if (wmPtr->gridWin != NULL) {
7750 /*
7751 * Gridding is turned on; convert from pixels to grid units.
7752 */
7753
7754 tmp = wmPtr->reqGridWidth
7755 + (tmp - wmPtr->winPtr->reqWidth)/wmPtr->widthInc;
7756 }
7757 *maxWidthPtr = tmp;
7758 }
7759 if (wmPtr->maxHeight > 0) {
7760 *maxHeightPtr = wmPtr->maxHeight;
7761 } else {
7762 tmp = wmPtr->defMaxHeight - wmPtr->borderHeight;
7763 if (wmPtr->gridWin != NULL) {
7764 tmp = wmPtr->reqGridHeight
7765 + (tmp - wmPtr->winPtr->reqHeight)/wmPtr->heightInc;
7766 }
7767 *maxHeightPtr = tmp;
7768 }
7769 }
7770
7771 /*
7772 *----------------------------------------------------------------------
7773 *
7774 * TopLevelProc --
7775 *
7776 * Callback from Windows whenever an event occurs on a top level window.
7777 *
7778 * Results:
7779 * Standard Windows return value.
7780 *
7781 * Side effects:
7782 * Default window behavior.
7783 *
7784 *----------------------------------------------------------------------
7785 */
7786
7787 static LRESULT CALLBACK
TopLevelProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)7788 TopLevelProc(
7789 HWND hwnd,
7790 UINT message,
7791 WPARAM wParam,
7792 LPARAM lParam)
7793 {
7794 if (message == WM_WINDOWPOSCHANGED || message == WM_WINDOWPOSCHANGING) {
7795 WINDOWPOS *pos = (WINDOWPOS *) lParam;
7796 TkWindow *winPtr = (TkWindow *) Tk_HWNDToWindow(pos->hwnd);
7797
7798 if (winPtr == NULL) {
7799 return 0;
7800 }
7801
7802 /*
7803 * Update the shape of the contained window.
7804 */
7805
7806 if (!(pos->flags & SWP_NOSIZE)) {
7807 winPtr->changes.width = pos->cx;
7808 winPtr->changes.height = pos->cy;
7809 }
7810 if (!(pos->flags & SWP_NOMOVE)) {
7811 long result = SendMessageW(winPtr->wmInfoPtr->wrapper,
7812 TK_MOVEWINDOW, -1, -1);
7813 winPtr->wmInfoPtr->x = winPtr->changes.x = result >> 16;
7814 winPtr->wmInfoPtr->y = winPtr->changes.y = result & 0xffff;
7815 }
7816
7817 GenerateConfigureNotify(winPtr);
7818
7819 Tcl_ServiceAll();
7820 return 0;
7821 }
7822 return TkWinChildProc(hwnd, message, wParam, lParam);
7823 }
7824
7825 /*
7826 *----------------------------------------------------------------------
7827 *
7828 * WmProc --
7829 *
7830 * Callback from Windows whenever an event occurs on the decorative
7831 * frame.
7832 *
7833 * Results:
7834 * Standard Windows return value.
7835 *
7836 * Side effects:
7837 * Default window behavior.
7838 *
7839 *----------------------------------------------------------------------
7840 */
7841
7842 static LRESULT CALLBACK
WmProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)7843 WmProc(
7844 HWND hwnd,
7845 UINT message,
7846 WPARAM wParam,
7847 LPARAM lParam)
7848 {
7849 static int inMoveSize = 0;
7850 static int oldMode; /* This static is set upon entering move/size
7851 * mode and is used to reset the service mode
7852 * after leaving move/size mode. Note that
7853 * this mechanism assumes move/size is only
7854 * one level deep. */
7855 LRESULT result = 0;
7856 TkWindow *winPtr = NULL;
7857
7858 switch (message) {
7859 case WM_KILLFOCUS:
7860 case WM_ERASEBKGND:
7861 result = 0;
7862 goto done;
7863
7864 case WM_ENTERSIZEMOVE:
7865 inMoveSize = 1;
7866
7867 /*
7868 * Cancel any current mouse timer. If the mouse timer fires during the
7869 * size/move mouse capture, it will release the capture, which is
7870 * wrong.
7871 */
7872
7873 TkWinCancelMouseTimer();
7874
7875 oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
7876 break;
7877
7878 case WM_ACTIVATE:
7879 if (WA_ACTIVE == LOWORD(wParam)) {
7880 winPtr = GetTopLevel(hwnd);
7881 if (winPtr && (TkGrabState(winPtr) == TK_GRAB_EXCLUDED)) {
7882 /*
7883 * There is a grab in progress so queue an Activate event
7884 */
7885
7886 GenerateActivateEvent(winPtr, &inMoveSize);
7887 result = 0;
7888 goto done;
7889 }
7890 }
7891 /* fall through */
7892
7893 case WM_EXITSIZEMOVE:
7894 if (inMoveSize) {
7895 inMoveSize = 0;
7896 Tcl_SetServiceMode(oldMode);
7897 }
7898 break;
7899
7900 case WM_GETMINMAXINFO:
7901 SetLimits(hwnd, (MINMAXINFO *) lParam);
7902 result = 0;
7903 goto done;
7904
7905 case WM_DISPLAYCHANGE:
7906 /*
7907 * Display and/or color resolution changed.
7908 */
7909
7910 winPtr = GetTopLevel(hwnd);
7911 if (winPtr) {
7912 Screen *screen = Tk_Screen(winPtr);
7913 if (screen->root_depth != (int) wParam) {
7914 /*
7915 * Color resolution changed, so do extensive rebuild of
7916 * display parameters. This will affect the display for all Tk
7917 * windows. We will receive this event for each toplevel, but
7918 * this check makes us update only once, for the first
7919 * toplevel that receives the message.
7920 */
7921
7922 TkWinDisplayChanged(Tk_Display(winPtr));
7923 } else {
7924 HDC dc = GetDC(NULL);
7925
7926 screen->width = LOWORD(lParam); /* horizontal res */
7927 screen->height = HIWORD(lParam); /* vertical res */
7928 screen->mwidth = MulDiv(screen->width, 254,
7929 GetDeviceCaps(dc, LOGPIXELSX) * 10);
7930 screen->mheight = MulDiv(screen->height, 254,
7931 GetDeviceCaps(dc, LOGPIXELSY) * 10);
7932 ReleaseDC(NULL, dc);
7933 }
7934 if (Tk_Depth(winPtr) != (int) wParam) {
7935 /*
7936 * Defer the window depth check to here so that each toplevel
7937 * will properly update depth info.
7938 */
7939
7940 InvalidateSubTreeDepth(winPtr);
7941 }
7942 }
7943 result = 0;
7944 goto done;
7945
7946 case WM_SYSCOLORCHANGE:
7947 /*
7948 * XXX: Called when system color changes. We need to update any
7949 * widgets that use a system color.
7950 */
7951
7952 break;
7953
7954 case WM_PALETTECHANGED:
7955 result = InstallColormaps(hwnd, WM_PALETTECHANGED,
7956 hwnd == (HWND) wParam);
7957 goto done;
7958
7959 case WM_QUERYNEWPALETTE:
7960 result = InstallColormaps(hwnd, WM_QUERYNEWPALETTE, TRUE);
7961 goto done;
7962
7963 case WM_SETTINGCHANGE:
7964 if (wParam == SPI_SETNONCLIENTMETRICS) {
7965 winPtr = GetTopLevel(hwnd);
7966 TkWinSetupSystemFonts(winPtr->mainPtr);
7967 result = 0;
7968 goto done;
7969 }
7970 break;
7971
7972 case WM_WINDOWPOSCHANGED:
7973 ConfigureTopLevel((WINDOWPOS *) lParam);
7974 result = 0;
7975 goto done;
7976
7977 case WM_NCHITTEST: {
7978 winPtr = GetTopLevel(hwnd);
7979 if (winPtr && (TkGrabState(winPtr) == TK_GRAB_EXCLUDED)) {
7980 /*
7981 * This window is outside the grab heirarchy, so don't let any of
7982 * the normal non-client processing occur. Note that this
7983 * implementation is not strictly correct because the grab might
7984 * change between now and when the event would have been processed
7985 * by Tk, but it's close enough.
7986 */
7987
7988 result = HTCLIENT;
7989 goto done;
7990 }
7991 break;
7992 }
7993
7994 case WM_MOUSEACTIVATE: {
7995 winPtr = GetTopLevel((HWND) wParam);
7996 if (winPtr && (TkGrabState(winPtr) != TK_GRAB_EXCLUDED)) {
7997 /*
7998 * This allows us to pass the message onto the native menus [Bug:
7999 * 2272]
8000 */
8001
8002 result = DefWindowProcW(hwnd, message, wParam, lParam);
8003 goto done;
8004 }
8005
8006 /*
8007 * Don't activate the window yet since there is a grab that takes
8008 * precedence. Instead we need to queue an event so we can check the
8009 * grab state right before we handle the mouse event.
8010 */
8011
8012 if (winPtr) {
8013 GenerateActivateEvent(winPtr, &inMoveSize);
8014 }
8015 result = MA_NOACTIVATE;
8016 goto done;
8017 }
8018
8019 case WM_QUERYENDSESSION: {
8020 XEvent event;
8021
8022 /*
8023 * Synthesize WM_SAVE_YOURSELF wm protocol message on Windows logout
8024 * or restart.
8025 */
8026 winPtr = GetTopLevel(hwnd);
8027 event.xclient.message_type =
8028 Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS");
8029 event.xclient.data.l[0] =
8030 Tk_InternAtom((Tk_Window) winPtr, "WM_SAVE_YOURSELF");
8031 TkWmProtocolEventProc(winPtr, &event);
8032 break;
8033 }
8034
8035 default:
8036 break;
8037 }
8038
8039 winPtr = GetTopLevel(hwnd);
8040 switch(message) {
8041 case WM_SYSCOMMAND:
8042 /*
8043 * If there is a grab in effect then ignore the minimize command
8044 * unless the grab is on the main window (.). This is to permit
8045 * applications that leave a grab on . to work normally.
8046 * All other toplevels are deemed non-minimizable when a grab is
8047 * present.
8048 * If there is a grab in effect and this window is outside the
8049 * grab tree then ignore all system commands. [Bug 1847002]
8050 */
8051
8052 if (winPtr) {
8053 int cmd = wParam & 0xfff0;
8054 int grab = TkGrabState(winPtr);
8055 if ((SC_MINIMIZE == cmd)
8056 && (grab == TK_GRAB_IN_TREE || grab == TK_GRAB_ANCESTOR)
8057 && (winPtr != winPtr->mainPtr->winPtr)) {
8058 goto done;
8059 }
8060 if (grab == TK_GRAB_EXCLUDED
8061 && !(SC_MOVE == cmd || SC_SIZE == cmd)) {
8062 goto done;
8063 }
8064 }
8065 /* fall through */
8066
8067 case WM_INITMENU:
8068 case WM_COMMAND:
8069 case WM_MENUCHAR:
8070 case WM_MEASUREITEM:
8071 case WM_DRAWITEM:
8072 case WM_MENUSELECT:
8073 case WM_ENTERIDLE:
8074 case WM_INITMENUPOPUP:
8075 if (winPtr) {
8076 HWND hMenuHWnd = Tk_GetEmbeddedMenuHWND((Tk_Window) winPtr);
8077
8078 if (hMenuHWnd) {
8079 if (SendMessageW(hMenuHWnd, message, wParam, lParam)) {
8080 goto done;
8081 }
8082 } else if (TkWinHandleMenuEvent(&hwnd, &message, &wParam, &lParam,
8083 &result)) {
8084 goto done;
8085 }
8086 }
8087 break;
8088 }
8089
8090 if (winPtr && winPtr->window) {
8091 HWND child = Tk_GetHWND(winPtr->window);
8092
8093 if (message == WM_SETFOCUS) {
8094 SetFocus(child);
8095 result = 0;
8096 } else if (!Tk_TranslateWinEvent(child, message, wParam, lParam,
8097 &result)) {
8098 result = DefWindowProcW(hwnd, message, wParam, lParam);
8099 }
8100 } else {
8101 result = DefWindowProcW(hwnd, message, wParam, lParam);
8102 }
8103
8104 done:
8105 Tcl_ServiceAll();
8106 return result;
8107 }
8108
8109 /*
8110 *----------------------------------------------------------------------
8111 *
8112 * TkpMakeMenuWindow --
8113 *
8114 * Configure the window to be either a pull-down (or pop-up) menu, or as
8115 * a toplevel (torn-off) menu or palette.
8116 *
8117 * Results:
8118 * None.
8119 *
8120 * Side effects:
8121 * Changes the style bit used to create a new toplevel.
8122 *
8123 *----------------------------------------------------------------------
8124 */
8125
8126 void
TkpMakeMenuWindow(Tk_Window tkwin,int transient)8127 TkpMakeMenuWindow(
8128 Tk_Window tkwin, /* New window. */
8129 int transient) /* 1 means menu is only posted briefly as a
8130 * popup or pulldown or cascade. 0 means menu
8131 * is always visible, e.g. as a torn-off menu.
8132 * Determines whether save_under and
8133 * override_redirect should be set. */
8134 {
8135 XSetWindowAttributes atts;
8136
8137 if (transient) {
8138 atts.override_redirect = True;
8139 atts.save_under = True;
8140 } else {
8141 atts.override_redirect = False;
8142 atts.save_under = False;
8143 }
8144
8145 if ((atts.override_redirect != Tk_Attributes(tkwin)->override_redirect)
8146 || (atts.save_under != Tk_Attributes(tkwin)->save_under)) {
8147 Tk_ChangeWindowAttributes(tkwin, CWOverrideRedirect|CWSaveUnder,
8148 &atts);
8149 }
8150
8151 }
8152
8153 /*
8154 *----------------------------------------------------------------------
8155 *
8156 * TkWinGetWrapperWindow --
8157 *
8158 * Gets the Windows HWND for a given window.
8159 *
8160 * Results:
8161 * Returns the wrapper window for a Tk window.
8162 *
8163 * Side effects:
8164 * None.
8165 *
8166 *----------------------------------------------------------------------
8167 */
8168
8169 HWND
TkWinGetWrapperWindow(Tk_Window tkwin)8170 TkWinGetWrapperWindow(
8171 Tk_Window tkwin) /* The window we need the wrapper from */
8172 {
8173 TkWindow *winPtr = (TkWindow *) tkwin;
8174
8175 return winPtr->wmInfoPtr->wrapper;
8176 }
8177
8178 /*
8179 *----------------------------------------------------------------------
8180 *
8181 * TkWmFocusToplevel --
8182 *
8183 * This is a utility function invoked by focus-management code. It exists
8184 * because of the extra wrapper windows that exist under Unix; its job is
8185 * to map from wrapper windows to the corresponding toplevel windows. On
8186 * PCs and Macs there are no wrapper windows so no mapping is necessary;
8187 * this function just determines whether a window is a toplevel or not.
8188 *
8189 * Results:
8190 * If winPtr is a toplevel window, returns the pointer to the window;
8191 * otherwise returns NULL.
8192 *
8193 * Side effects:
8194 * None.
8195 *
8196 *----------------------------------------------------------------------
8197 */
8198
8199 TkWindow *
TkWmFocusToplevel(TkWindow * winPtr)8200 TkWmFocusToplevel(
8201 TkWindow *winPtr) /* Window that received a focus-related
8202 * event. */
8203 {
8204 if (!(winPtr->flags & TK_TOP_HIERARCHY)) {
8205 return NULL;
8206 }
8207 return winPtr;
8208 }
8209
8210 /*
8211 *----------------------------------------------------------------------
8212 *
8213 * TkpGetWrapperWindow --
8214 *
8215 * This is a utility function invoked by focus-management code. It maps
8216 * to the wrapper for a top-level, which is just the same as the
8217 * top-level on Macs and PCs.
8218 *
8219 * Results:
8220 * If winPtr is a toplevel window, returns the pointer to the window;
8221 * otherwise returns NULL.
8222 *
8223 * Side effects:
8224 * None.
8225 *
8226 *----------------------------------------------------------------------
8227 */
8228
8229 TkWindow *
TkpGetWrapperWindow(TkWindow * winPtr)8230 TkpGetWrapperWindow(
8231 TkWindow *winPtr) /* Window that received a focus-related
8232 * event. */
8233 {
8234 if (!(winPtr->flags & TK_TOP_HIERARCHY)) {
8235 return NULL;
8236 }
8237 return winPtr;
8238 }
8239
8240 /*
8241 *----------------------------------------------------------------------
8242 *
8243 * GenerateActivateEvent --
8244 *
8245 * This function is called to activate a Tk window.
8246 */
8247
8248 static void
GenerateActivateEvent(TkWindow * winPtr,const int * flagPtr)8249 GenerateActivateEvent(TkWindow * winPtr, const int *flagPtr)
8250 {
8251 ActivateEvent *eventPtr = (ActivateEvent *)ckalloc(sizeof(ActivateEvent));
8252
8253 eventPtr->ev.proc = ActivateWindow;
8254 eventPtr->winPtr = winPtr;
8255 eventPtr->flagPtr = flagPtr;
8256 eventPtr->hwnd = Tk_GetHWND(winPtr->window);
8257 Tcl_QueueEvent((Tcl_Event *)eventPtr, TCL_QUEUE_TAIL);
8258 }
8259
8260 /*
8261 *----------------------------------------------------------------------
8262 *
8263 * ActivateWindow --
8264 *
8265 * This function is called when an ActivateEvent is processed.
8266 *
8267 * Results:
8268 * Returns 1 to indicate that the event was handled, else 0.
8269 *
8270 * Side effects:
8271 * May activate the toplevel window associated with the event.
8272 *
8273 *----------------------------------------------------------------------
8274 */
8275
8276 static int
ActivateWindow(Tcl_Event * evPtr,int flags)8277 ActivateWindow(
8278 Tcl_Event *evPtr, /* Pointer to ActivateEvent. */
8279 int flags) /* Notifier event mask. */
8280 {
8281 ActivateEvent *eventPtr = (ActivateEvent *)evPtr;
8282 TkWindow *winPtr = eventPtr->winPtr;
8283
8284 if (! (flags & TCL_WINDOW_EVENTS)) {
8285 return 0;
8286 }
8287
8288 /*
8289 * Ensure the window has not been destroyed while we delayed
8290 * processing the WM_ACTIVATE message [Bug 2899949].
8291 */
8292
8293 if (!IsWindow(eventPtr->hwnd)) {
8294 return 1;
8295 }
8296
8297 /*
8298 * If the toplevel is in the middle of a move or size operation then
8299 * we must delay handling of this event to avoid stealing the focus
8300 * while the window manage is in control.
8301 */
8302
8303 if (eventPtr->flagPtr && *eventPtr->flagPtr) {
8304 return 0;
8305 }
8306
8307 /*
8308 * If the window is excluded by a grab, call SetFocus on the grabbed
8309 * window instead. [Bug 220908]
8310 */
8311
8312 if (winPtr) {
8313 Window window;
8314 if (TkGrabState(winPtr) != TK_GRAB_EXCLUDED) {
8315 window = winPtr->window;
8316 } else {
8317 window = winPtr->dispPtr->grabWinPtr->window;
8318 }
8319
8320 /*
8321 * Ensure the window was not destroyed while we were postponing
8322 * the activation [Bug 2799589]
8323 */
8324
8325 if (window) {
8326 SetFocus(Tk_GetHWND(window));
8327 }
8328 }
8329
8330 return 1;
8331 }
8332
8333 /*
8334 *----------------------------------------------------------------------
8335 *
8336 * TkWinSetForegroundWindow --
8337 *
8338 * This function is a wrapper for SetForegroundWindow, calling it on the
8339 * wrapper window because it has no affect on child windows.
8340 *
8341 * Results:
8342 * none
8343 *
8344 * Side effects:
8345 * May activate the toplevel window.
8346 *
8347 *----------------------------------------------------------------------
8348 */
8349
8350 void
TkWinSetForegroundWindow(TkWindow * winPtr)8351 TkWinSetForegroundWindow(
8352 TkWindow *winPtr)
8353 {
8354 WmInfo *wmPtr = winPtr->wmInfoPtr;
8355
8356 if (wmPtr->wrapper != NULL) {
8357 SetForegroundWindow(wmPtr->wrapper);
8358 } else {
8359 SetForegroundWindow(Tk_GetHWND(winPtr->window));
8360 }
8361 }
8362
8363 /*
8364 *----------------------------------------------------------------------
8365 *
8366 * TkpWinToplevelWithdraw --
8367 *
8368 * This function is to be used by a window manage to withdraw a toplevel
8369 * window.
8370 *
8371 * Results:
8372 * none
8373 *
8374 * Side effects:
8375 * May withdraw the toplevel window.
8376 *
8377 *----------------------------------------------------------------------
8378 */
8379
8380 void
TkpWinToplevelWithDraw(TkWindow * winPtr)8381 TkpWinToplevelWithDraw(
8382 TkWindow *winPtr)
8383 {
8384 WmInfo *wmPtr = winPtr->wmInfoPtr;
8385
8386 wmPtr->flags |= WM_WITHDRAWN;
8387 TkpWmSetState(winPtr, WithdrawnState);
8388 }
8389
8390 /*
8391 *----------------------------------------------------------------------
8392 *
8393 * TkpWinToplevelIconify --
8394 *
8395 * This function is to be used by a window manage to iconify a toplevel
8396 * window.
8397 *
8398 * Results:
8399 * none
8400 *
8401 * Side effects:
8402 * May iconify the toplevel window.
8403 *
8404 *----------------------------------------------------------------------
8405 */
8406
8407 void
TkpWinToplevelIconify(TkWindow * winPtr)8408 TkpWinToplevelIconify(
8409 TkWindow *winPtr)
8410 {
8411 TkpWmSetState(winPtr, IconicState);
8412 }
8413
8414 /*
8415 *----------------------------------------------------------------------
8416 *
8417 * TkpWinToplevelDeiconify --
8418 *
8419 * This function is to be used by a window manage to deiconify a toplevel
8420 * window.
8421 *
8422 * Results:
8423 * none
8424 *
8425 * Side effects:
8426 * May deiconify the toplevel window.
8427 *
8428 *----------------------------------------------------------------------
8429 */
8430
8431 void
TkpWinToplevelDeiconify(TkWindow * winPtr)8432 TkpWinToplevelDeiconify(
8433 TkWindow *winPtr)
8434 {
8435 WmInfo *wmPtr = winPtr->wmInfoPtr;
8436
8437 wmPtr->flags &= ~WM_WITHDRAWN;
8438
8439 /*
8440 * If WM_UPDATE_PENDING is true, a pending UpdateGeometryInfo may need to
8441 * be called first to update a withdrawn toplevel's geometry before it is
8442 * deiconified by TkpWmSetState. Don't bother if we've never been mapped.
8443 */
8444
8445 if ((wmPtr->flags & WM_UPDATE_PENDING)
8446 && !(wmPtr->flags & WM_NEVER_MAPPED)) {
8447 Tcl_CancelIdleCall(UpdateGeometryInfo, winPtr);
8448 UpdateGeometryInfo(winPtr);
8449 }
8450
8451 /*
8452 * If we were in the ZoomState (maximized), 'wm deiconify' should not
8453 * cause the window to shrink
8454 */
8455
8456 if (wmPtr->hints.initial_state == ZoomState) {
8457 TkpWmSetState(winPtr, ZoomState);
8458 } else {
8459 TkpWmSetState(winPtr, NormalState);
8460 }
8461
8462 /*
8463 * An unmapped window will be mapped at idle time by a call to MapFrame.
8464 * That calls CreateWrapper which sets the focus and raises the window.
8465 */
8466
8467 if (wmPtr->flags & WM_NEVER_MAPPED) {
8468 return;
8469 }
8470
8471 /*
8472 * Follow Windows-like style here, raising the window to the top.
8473 */
8474
8475 TkWmRestackToplevel(winPtr, Above, NULL);
8476 if (!(Tk_Attributes((Tk_Window) winPtr)->override_redirect)) {
8477 TkSetFocusWin(winPtr, 1);
8478 }
8479 }
8480
8481 /*
8482 *----------------------------------------------------------------------
8483 *
8484 * TkpWinGeometryIsControlledByWm --
8485 *
8486 * This function is to be used by a window manage to see if wm has
8487 * canceled geometry control.
8488 *
8489 * Results:
8490 * 0 - if the window manager has canceled its control
8491 * 1 - if the window manager controls the geometry
8492 *
8493 * Side effects:
8494 * None.
8495 *
8496 *----------------------------------------------------------------------
8497 */
8498
8499 long
TkpWinToplevelIsControlledByWm(TkWindow * winPtr)8500 TkpWinToplevelIsControlledByWm(
8501 TkWindow *winPtr)
8502 {
8503 WmInfo *wmPtr = winPtr->wmInfoPtr;
8504
8505 if (!wmPtr) {
8506 return 0;
8507 }
8508 return ((wmPtr->width != -1) && (wmPtr->height != -1)) ? 1 : 0;
8509 }
8510
8511 /*
8512 *----------------------------------------------------------------------
8513 *
8514 * TkpWinToplevelMove --
8515 *
8516 * This function is to be used by a container to move an embedded window.
8517 *
8518 * Results:
8519 * position of the upper left frame in a 32-bit long:
8520 * 16-MSBits - x; 16-LSBits - y
8521 *
8522 * Side effects:
8523 * May move the embedded window.
8524 *
8525 *----------------------------------------------------------------------
8526 */
8527
8528 long
TkpWinToplevelMove(TkWindow * winPtr,int x,int y)8529 TkpWinToplevelMove(
8530 TkWindow *winPtr,
8531 int x, int y)
8532 {
8533 WmInfo *wmPtr = winPtr->wmInfoPtr;
8534
8535 if (wmPtr && x >= 0 && y >= 0 && !TkpWinToplevelIsControlledByWm(winPtr)) {
8536 Tk_MoveToplevelWindow((Tk_Window) winPtr, x, y);
8537 }
8538 return ((winPtr->changes.x << 16) & 0xffff0000)
8539 | (winPtr->changes.y & 0xffff);
8540 }
8541
8542 /*
8543 *----------------------------------------------------------------------
8544 *
8545 * TkpWinToplevelOverrideRedirect --
8546 *
8547 * This function is to be used by a container to overrideredirect the
8548 * contaner's frame window.
8549 *
8550 * Results:
8551 * The current overrideredirect value
8552 *
8553 * Side effects:
8554 * May change the overrideredirect value of the container window
8555 *
8556 *----------------------------------------------------------------------
8557 */
8558
8559 long
TkpWinToplevelOverrideRedirect(TkWindow * winPtr,int reqValue)8560 TkpWinToplevelOverrideRedirect(
8561 TkWindow *winPtr,
8562 int reqValue)
8563 {
8564 int curValue;
8565 WmInfo *wmPtr = winPtr->wmInfoPtr;
8566
8567 curValue = Tk_Attributes((Tk_Window) winPtr)->override_redirect;
8568 if (reqValue < 0) {
8569 return curValue;
8570 }
8571
8572 if (curValue != reqValue) {
8573 XSetWindowAttributes atts;
8574
8575 /*
8576 * Only do this if we are really changing value, because it causes
8577 * some funky stuff to occur
8578 */
8579
8580 atts.override_redirect = reqValue ? True : False;
8581 Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect,
8582 &atts);
8583 if (!(wmPtr->flags & (WM_NEVER_MAPPED))
8584 && !(winPtr->flags & TK_EMBEDDED)) {
8585 UpdateWrapper(winPtr);
8586 }
8587 }
8588 return reqValue;
8589 }
8590
8591 /*
8592 *----------------------------------------------------------------------
8593 *
8594 * TkpWinToplevelDetachWindow --
8595 *
8596 * This function is to be usd for changing a toplevel's wrapper or
8597 * container.
8598 *
8599 * Results:
8600 * The window's wrapper/container is removed.
8601 *
8602 * Side effects:
8603 * None.
8604 *
8605 *----------------------------------------------------------------------
8606 */
8607
8608 void
TkpWinToplevelDetachWindow(TkWindow * winPtr)8609 TkpWinToplevelDetachWindow(
8610 TkWindow *winPtr)
8611 {
8612 WmInfo *wmPtr = winPtr->wmInfoPtr;
8613
8614 if (winPtr->flags & TK_EMBEDDED) {
8615 int state = SendMessageW(wmPtr->wrapper, TK_STATE, -1, -1) - 1;
8616
8617 SendMessageW(wmPtr->wrapper, TK_SETMENU, 0, 0);
8618 SendMessageW(wmPtr->wrapper, TK_DETACHWINDOW, 0, 0);
8619 winPtr->flags &= ~TK_EMBEDDED;
8620 winPtr->privatePtr = NULL;
8621 wmPtr->wrapper = NULL;
8622 if (state >= 0 && state <= 3) {
8623 wmPtr->hints.initial_state = state;
8624 }
8625 }
8626 if (winPtr->flags & TK_TOP_LEVEL) {
8627 TkpWinToplevelOverrideRedirect(winPtr, 1);
8628 }
8629 }
8630
8631 /*
8632 *----------------------------------------------------------------------
8633 *
8634 * RemapWindows
8635 *
8636 * Adjust parent/child relation ships of the given window hierarchy.
8637 *
8638 * Results:
8639 * none
8640 *
8641 * Side effects:
8642 * keeps windowing system happy
8643 *
8644 *----------------------------------------------------------------------
8645 */
8646
8647 static void
RemapWindows(TkWindow * winPtr,HWND parentHWND)8648 RemapWindows(
8649 TkWindow *winPtr,
8650 HWND parentHWND)
8651 {
8652 TkWindow *childPtr;
8653 const char *className = Tk_Class(winPtr);
8654
8655 /*
8656 * Skip menus as they are handled differently.
8657 */
8658
8659 if (className != NULL && strcmp(className, "Menu") == 0) {
8660 return;
8661 }
8662 if (winPtr->window) {
8663 SetParent(Tk_GetHWND(winPtr->window), parentHWND);
8664 }
8665
8666 /*
8667 * Repeat for all the children.
8668 */
8669
8670 for (childPtr = winPtr->childList; childPtr != NULL;
8671 childPtr = childPtr->nextPtr) {
8672 RemapWindows(childPtr,
8673 winPtr->window ? Tk_GetHWND(winPtr->window) : NULL);
8674 }
8675 }
8676
8677 /*
8678 * Local Variables:
8679 * mode: c
8680 * c-basic-offset: 4
8681 * fill-column: 78
8682 * End:
8683 */
8684