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