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