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