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