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