4 * This module takes care of the interactions between a Tk-based
5 * application and the window manager. Among other things, it
6 * implements the "wm" command and passes geometry information
7 * to the window manager.
9 * Copyright 1991 Regents of the University of California.
10 * Permission to use, copy, modify, and distribute this
11 * software and its documentation for any purpose and without
12 * fee is hereby granted, provided that the above copyright
13 * notice appear in all copies. The University of California
14 * makes no representations about the suitability of this
15 * software for any purpose. It is provided "as is" without
16 * express or implied warranty.
20 static char rcsid
[] = "$Header: /user6/ouster/wish/RCS/tkWm.c,v 1.32 92/08/21 16:26:31 ouster Exp $ SPRITE (Berkeley)";
28 * The definitions below compensate for the lack of some definitions
33 #define PBaseSize (1L<<8)
37 * A data structure of the following type holds window-manager-related
38 * information for each top-level window in an application.
41 typedef struct TkWmInfo
{
42 TkWindow
*winPtr
; /* Pointer to main Tk information for
44 Window reparent
; /* If the window has been reparented, this
45 * gives the ID of the ancestor of the window
46 * that is a child of the root window (may
47 * not be window's immediate parent). If
48 * the window isn't reparented, this has the
50 Tk_Uid titleUid
; /* Title to display in window caption. If
51 * NULL, use name of widget. */
52 Tk_Uid iconName
; /* Name to display in icon. */
53 Window master
; /* Master window for TRANSIENT_FOR property,
55 XWMHints hints
; /* Various pieces of information for
57 Tk_Uid leaderName
; /* Path name of leader of window group
58 * (corresponds to hints.window_group).
59 * Note: this field doesn't get updated
60 * if leader is destroyed. */
61 Tk_Uid iconWindowName
; /* Path name of window specified as icon
62 * window for this window, or NULL. Note:
63 * this field doesn't get updated if
64 * iconWindowName is destroyed. */
65 Tk_Uid masterWindowName
; /* Path name of window specified as master
66 * in "wm transient" command, or NULL.
67 * Note: this field doesn't get updated if
68 * masterWindowName is destroyed. */
71 * Information used to construct an XSizeHints structure for
75 int sizeHintsFlags
; /* Flags word for XSizeHints structure.
76 * If the PBaseSize flag is set then the
77 * window is gridded; otherwise it isn't
79 int minWidth
, minHeight
; /* Minimum dimensions of window, in
80 * grid units, not pixels. */
81 int maxWidth
, maxHeight
; /* Maximum dimensions of window, in
82 * grid units, not pixels. */
83 int widthInc
, heightInc
; /* Increments for size changes (# pixels
86 int x
; /* numerator */
87 int y
; /* denominator */
88 } minAspect
, maxAspect
; /* Min/max aspect ratios for window. */
89 int reqGridWidth
, reqGridHeight
;
90 /* The dimensions of the window (in
91 * grid units) requested through
92 * the geometry manager. */
93 int gravity
; /* Desired window gravity. */
96 * Information used to manage the size and location of a window.
99 int prevReqWidth
, prevReqHeight
;
100 /* Last known size preferences, as specified
101 * to Tk_GeometryRequest. Used to tell when
102 * the preferred dimensions have changed. */
103 int width
, height
; /* Desired dimensions of window, specified
104 * in grid units. These values are
105 * set by the "wm geometry" command and by
106 * ConfigureNotify events (for when wm
107 * resizes window). -1 means user hasn't
108 * requested dimensions. */
109 int x
, y
; /* Desired X and Y coordinates for window.
110 * These values are set by "wm geometry",
111 * plus by ConfigureNotify events (when wm
112 * moves window). These numbers are
113 * different than the numbers stored in
114 * winPtr->changes because (a) they could be
115 * measured from the right or bottom edge
116 * of the screen (see WM_NEGATIVE_X and
117 * WM_NEGATIVE_Y flags) and (b) if the window
118 * has been reparented then they refer to the
119 * parent rather than the window itself. */
120 int parentWidth
, parentHeight
;
121 /* Width and height of reparent, in pixels
122 * *including border*. If window hasn't been
123 * reparented then these will be the outer
124 * dimensions of the window, including
126 int xInParent
, yInParent
; /* Offset of window within reparent, measured
127 * from upper-left outer corner of parent's
128 * border. If not reparented then these are
130 unsigned long configRequest
;/* Serial number of last request that we
131 * issued to change geometry of window.
132 * Used to discard configure events that
133 * we know will be superceded. */
134 int configWidth
, configHeight
;
135 /* Dimensions passed to last request that we
136 * issued to change geometry of window. Used
137 * to eliminate redundant resize operations. */
139 int flags
; /* Miscellaneous flags, defined below. */
141 char *deleteCmd
; /* Command to execute when a WM_DELETE_WINDOW
142 * ICCCM ClientMessage arrives for this window.
144 * If it is the empty string "" or has never
145 * been set (is char *)NULL) via the "wm" tcl
146 * command the window is destroyed.
148 * If it is a non-empty string, the name of
149 * the window is appended on to the end
150 * of the string and it is executed
151 * within the interpreter associated with
152 * the top level window.
154 struct TkWmInfo
*nextPtr
; /* Next in list of all top-level windows. */
158 * Flag values for WmInfo structures:
160 * WM_NEVER_MAPPED - non-zero means window has never been
161 * mapped; need to update all info when
162 * window is first mapped.
163 * WM_UPDATE_PENDING - non-zero means a call to UpdateGeometryInfo
164 * has already been scheduled for this
165 * window; no need to schedule another one.
166 * WM_NEGATIVE_X - non-zero means x-coordinate is measured in
167 * pixels from right edge of screen, rather
168 * than from left edge.
169 * WM_NEGATIVE_Y - non-zero means y-coordinate is measured in
170 * pixels up from bottom of screen, rather than
172 * WM_UPDATE_SIZE_HINTS - non-zero means that new size hints need to be
173 * propagated to window manager.
174 * WM_NESTED_REPARENT - non-zero means that the window has been
175 * reparented several levels deep in a hierarchy
176 * (i.e. reparent isn't the window's immediate
178 * WM_CONFIG_PENDING - non-zero means we've asked for the top-level
179 * window to be resized but haven't seen a
180 * ConfigureNotify event to indicate that the
182 * WM_CONFIG_AGAIN - non-zero means we need to reconfigure the
183 * window again as soon as the current configure
184 * request has been processed by the window
186 * WM_FULL_SCREEN - non-zero means that the window is in full screen mode.
189 #define WM_NEVER_MAPPED 1
190 #define WM_UPDATE_PENDING 2
191 #define WM_NEGATIVE_X 4
192 #define WM_NEGATIVE_Y 8
193 #define WM_UPDATE_SIZE_HINTS 0x10
194 #define WM_NESTED_REPARENT 0x20
195 #define WM_CONFIG_PENDING 0x40
196 #define WM_CONFIG_AGAIN 0x100
197 #define WM_FULL_SCREEN 0x200
200 * This module keeps a list of all top-level windows, primarily to
201 * simplify the job of Tk_CoordsToWindow.
204 static WmInfo
*firstWmPtr
= NULL
; /* Points to first top-level window. */
206 #define IS_GRIDDED(wmPtr) ((wmPtr)->sizeHintsFlags & PBaseSize)
209 * Forward declarations for procedures defined in this file:
212 static int ParseGeometry
_ANSI_ARGS_ ((Tcl_Interp
*interp
,
213 char *string
, TkWindow
*winPtr
));
214 static void TopLevelEventProc
_ANSI_ARGS_((ClientData clientData
,
216 static void TopLevelReqProc
_ANSI_ARGS_((ClientData dummy
,
218 static void UpdateGeometryInfo
_ANSI_ARGS_((
219 ClientData clientData
));
220 static void UpdateHints
_ANSI_ARGS_((TkWindow
*winPtr
));
221 static void UpdateSizeHints
_ANSI_ARGS_((TkWindow
*winPtr
));
224 *--------------------------------------------------------------
228 * This procedure is invoked whenever a new top-level
229 * window is created. Its job is to initialize the WmInfo
230 * structure for the window.
236 * A WmInfo structure gets allocated and initialized.
238 *--------------------------------------------------------------
242 TkWmNewWindow(winPtr
)
243 TkWindow
*winPtr
; /* Newly-created top-level window. */
245 register WmInfo
*wmPtr
;
247 wmPtr
= (WmInfo
*) ckalloc(sizeof(WmInfo
));
248 wmPtr
->winPtr
= winPtr
;
249 wmPtr
->reparent
= None
;
250 wmPtr
->titleUid
= NULL
;
251 wmPtr
->iconName
= NULL
;
252 wmPtr
->master
= None
;
253 wmPtr
->hints
.flags
= InputHint
| StateHint
;
254 wmPtr
->hints
.input
= True
;
255 wmPtr
->hints
.initial_state
= NormalState
;
256 wmPtr
->hints
.icon_pixmap
= None
;
257 wmPtr
->hints
.icon_window
= None
;
258 wmPtr
->hints
.icon_x
= wmPtr
->hints
.icon_y
= 0;
259 wmPtr
->hints
.icon_mask
= None
;
260 wmPtr
->hints
.window_group
= None
;
261 wmPtr
->leaderName
= NULL
;
262 wmPtr
->iconWindowName
= NULL
;
263 wmPtr
->masterWindowName
= NULL
;
264 wmPtr
->sizeHintsFlags
= 0;
265 wmPtr
->minWidth
= wmPtr
->minHeight
= 0;
266 wmPtr
->maxWidth
= wmPtr
->maxHeight
= 10000;
267 wmPtr
->widthInc
= wmPtr
->heightInc
= 1;
268 wmPtr
->minAspect
.x
= wmPtr
->minAspect
.y
= 1;
269 wmPtr
->maxAspect
.x
= wmPtr
->maxAspect
.y
= 1;
270 wmPtr
->reqGridWidth
= wmPtr
->reqGridHeight
= -1;
271 wmPtr
->prevReqWidth
= wmPtr
->prevReqHeight
= -1;
272 wmPtr
->gravity
= NorthWestGravity
;
275 wmPtr
->x
= winPtr
->changes
.x
;
276 wmPtr
->y
= winPtr
->changes
.y
;
277 wmPtr
->parentWidth
= winPtr
->changes
.width
278 + 2*winPtr
->changes
.border_width
;
279 wmPtr
->parentHeight
= winPtr
->changes
.height
280 + 2*winPtr
->changes
.border_width
;
281 wmPtr
->xInParent
= wmPtr
->yInParent
= 0;
282 wmPtr
->configRequest
= 0;
283 wmPtr
->configWidth
= -1;
284 wmPtr
->configHeight
= -1;
285 wmPtr
->flags
= WM_NEVER_MAPPED
;
286 wmPtr
->deleteCmd
= (char *)0;
287 wmPtr
->nextPtr
= firstWmPtr
;
289 winPtr
->wmInfoPtr
= wmPtr
;
292 * Tk must monitor certain events for top-level windows:
293 * (a) structure events, in order to detect size and position changes
294 * caused by window managers.
295 * (b) enter/level events, in order to perform focussing correctly.
298 Tk_CreateEventHandler((Tk_Window
) winPtr
,
299 StructureNotifyMask
|EnterWindowMask
|LeaveWindowMask
,
300 TopLevelEventProc
, (ClientData
) winPtr
);
303 * Arrange for geometry requests to be reflected from the window
304 * to the window manager.
307 Tk_ManageGeometry((Tk_Window
) winPtr
, TopLevelReqProc
, (ClientData
) 0);
311 *--------------------------------------------------------------
315 * This procedure is invoked just before a top-level window
316 * is mapped. It gives this module a chance to update all
317 * window-manager-related information in properties before
318 * the window manager sees the map event and checks the
322 * Returns non-zero if it's OK for the window to be mapped, 0
323 * if the caller shouldn't map the window after all (e.g. because
324 * it has been withdrawn).
327 * Properties of winPtr may get updated to provide up-to-date
328 * information to the window manager.
330 *--------------------------------------------------------------
334 TkWmMapWindow(winPtr
)
335 TkWindow
*winPtr
; /* Top-level window that's about to
338 register WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
340 XTextProperty textProp
;
344 * Set the MAPPED flag if the window is going to appear in its normal
345 * state: if it's going to be iconified or withdrawn then it won't
349 if (wmPtr
->hints
.initial_state
== NormalState
) {
350 winPtr
->flags
|= TK_MAPPED
;
352 if (wmPtr
->flags
& WM_NEVER_MAPPED
) {
353 wmPtr
->flags
&= ~WM_NEVER_MAPPED
;
356 * This is the first time this window has ever been mapped.
357 * Store all the window-manager-related information for the
362 if (wmPtr
->titleUid
== NULL
) {
363 wmPtr
->titleUid
= winPtr
->nameUid
;
365 if (XStringListToTextProperty(&wmPtr
->titleUid
, 1, &textProp
) != 0) {
366 XSetWMName(winPtr
->display
, winPtr
->window
, &textProp
);
367 XFree((char *) textProp
.value
);
371 TkWmSetClass(winPtr
);
372 TkWmSetWmProtocols(winPtr
);
374 if (wmPtr
->iconName
!= NULL
) {
375 XSetIconName(winPtr
->display
, winPtr
->window
, wmPtr
->iconName
);
378 if (wmPtr
->master
!= None
) {
379 XSetTransientForHint(winPtr
->display
, winPtr
->window
, wmPtr
->master
);
383 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
384 UpdateGeometryInfo((ClientData
) winPtr
);
386 if (wmPtr
->hints
.initial_state
== WithdrawnState
) {
393 *--------------------------------------------------------------
397 * This procedure is invoked when a top-level window is
398 * about to be deleted. It cleans up the wm-related data
399 * structures for the window.
405 * The WmInfo structure for winPtr gets freed up.
407 *--------------------------------------------------------------
411 TkWmDeadWindow(winPtr
)
412 TkWindow
*winPtr
; /* Newly-created top-level window. */
414 register WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
419 if (firstWmPtr
== wmPtr
) {
420 firstWmPtr
= wmPtr
->nextPtr
;
422 register WmInfo
*prevPtr
;
424 for (prevPtr
= firstWmPtr
; ; prevPtr
= prevPtr
->nextPtr
) {
425 if (prevPtr
== NULL
) {
426 panic("couldn't unlink window in TkWmDeadWindow");
428 if (prevPtr
->nextPtr
== wmPtr
) {
429 prevPtr
->nextPtr
= wmPtr
->nextPtr
;
434 if (wmPtr
->hints
.flags
& IconPixmapHint
) {
435 Tk_FreeBitmap(wmPtr
->hints
.icon_pixmap
);
437 if (wmPtr
->hints
.flags
& IconMaskHint
) {
438 Tk_FreeBitmap(wmPtr
->hints
.icon_mask
);
440 if (wmPtr
->flags
& WM_UPDATE_PENDING
) {
441 Tk_CancelIdleCall(UpdateGeometryInfo
, (ClientData
) winPtr
);
443 if (wmPtr
->deleteCmd
) {
444 ckfree(wmPtr
->deleteCmd
);
446 ckfree((char *) wmPtr
);
447 winPtr
->wmInfoPtr
= NULL
;
451 *--------------------------------------------------------------
455 * This procedure is invoked whenever a top-level window's
456 * class is changed. If the window has been mapped then this
457 * procedure updates the window manager property for the
458 * class. If the window hasn't been mapped, the update is
459 * deferred until just before the first mapping.
465 * A window property may get updated.
467 *--------------------------------------------------------------
472 TkWindow
*winPtr
; /* Newly-created top-level window. */
474 if (winPtr
->wmInfoPtr
->flags
& WM_NEVER_MAPPED
) {
479 if (winPtr
->classUid
!= NULL
) {
480 XClassHint
*classPtr
;
482 classPtr
= XAllocClassHint();
483 classPtr
->res_name
= winPtr
->nameUid
;
484 classPtr
->res_class
= winPtr
->classUid
;
485 XSetClassHint(winPtr
->display
, winPtr
->window
, classPtr
);
486 XFree((char *) classPtr
);
492 *----------------------------------------------------------------------
496 * This procedure is invoked to process the "wm" Tcl command.
497 * See the user documentation for details on what it does.
500 * A standard Tcl result.
503 * See the user documentation.
505 *----------------------------------------------------------------------
510 Tk_WmCmd(clientData
, interp
, argc
, argv
)
511 ClientData clientData
; /* Main window associated with
513 Tcl_Interp
*interp
; /* Current interpreter. */
514 int argc
; /* Number of arguments. */
515 char **argv
; /* Argument strings. */
517 Tk_Window tkwin
= (Tk_Window
) clientData
;
519 register WmInfo
*wmPtr
;
524 Tcl_AppendResult(interp
, "wrong # args: should be \"",
525 argv
[0], " option window ?arg ...?\"", (char *) NULL
);
528 winPtr
= (TkWindow
*) Tk_NameToWindow(interp
, argv
[2], tkwin
);
529 if (winPtr
== NULL
) {
532 if (!(winPtr
->flags
& TK_TOP_LEVEL
)) {
533 Tcl_AppendResult(interp
, "window \"", winPtr
->pathName
,
534 "\" isn't a top-level window", (char *) NULL
);
537 wmPtr
= winPtr
->wmInfoPtr
;
539 length
= strlen(argv
[1]);
540 if ((c
== 'a') && (strncmp(argv
[1], "aspect", length
) == 0)) {
541 int numer1
, denom1
, numer2
, denom2
;
543 if ((argc
!= 3) && (argc
!= 7)) {
544 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
545 argv
[0], " aspect window ?minNumer minDenom ",
546 "maxNumer maxDenom?\"", (char *) NULL
);
550 if (wmPtr
->sizeHintsFlags
& PAspect
) {
551 sprintf(interp
->result
, "%d %d %d %d", wmPtr
->minAspect
.x
,
552 wmPtr
->minAspect
.y
, wmPtr
->maxAspect
.x
,
557 if (*argv
[3] == '\0') {
558 wmPtr
->sizeHintsFlags
&= ~PAspect
;
560 if ((Tcl_GetInt(interp
, argv
[3], &numer1
) != TCL_OK
)
561 || (Tcl_GetInt(interp
, argv
[4], &denom1
) != TCL_OK
)
562 || (Tcl_GetInt(interp
, argv
[5], &numer2
) != TCL_OK
)
563 || (Tcl_GetInt(interp
, argv
[6], &denom2
) != TCL_OK
)) {
566 if ((numer1
<= 0) || (denom1
<= 0) || (numer2
<= 0) ||
568 interp
->result
= "aspect number can't be <= 0";
571 wmPtr
->minAspect
.x
= numer1
;
572 wmPtr
->minAspect
.y
= denom1
;
573 wmPtr
->maxAspect
.x
= numer2
;
574 wmPtr
->maxAspect
.y
= denom2
;
575 wmPtr
->sizeHintsFlags
|= PAspect
;
577 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
579 } else if ((c
== 'd') && (strncmp(argv
[1], "deiconify", length
) == 0)) {
581 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
582 argv
[0], " deiconify window\"", (char *) NULL
);
585 wmPtr
->hints
.initial_state
= NormalState
;
586 if (wmPtr
->flags
& WM_NEVER_MAPPED
) {
589 Tk_MapWindow((Tk_Window
) winPtr
);
590 } else if ((c
== 'f') && (strncmp(argv
[1], "focusmodel", length
) == 0)) {
591 if ((argc
!= 3) && (argc
!= 4)) {
592 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
593 argv
[0], " focusmodel window ?active|passive?\"",
598 interp
->result
= wmPtr
->hints
.input
? "passive" : "active";
602 length
= strlen(argv
[3]);
603 if ((c
== 'a') && (strncmp(argv
[3], "active", length
) == 0)) {
604 wmPtr
->hints
.input
= False
;
605 } else if ((c
== 'p') && (strncmp(argv
[3], "passive", length
) == 0)) {
606 wmPtr
->hints
.input
= True
;
608 Tcl_AppendResult(interp
, "bad argument \"", argv
[3],
609 "\": must be active or passive", (char *) NULL
);
613 } else if ((c
== 'f') && (strncmp(argv
[1], "fullscreen", length
) == 0)) {
615 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
616 argv
[0], " fullscreen window on|off\"",
621 length
= strlen(argv
[3]);
622 if (strncmp(argv
[3], "on", length
) == 0) {
623 wmPtr
->flags
&= ~WM_FULL_SCREEN
;
624 } else if (strncmp(argv
[3], "off", length
) == 0) {
625 wmPtr
->flags
|= WM_FULL_SCREEN
;
627 Tcl_AppendResult(interp
, "bad argument \"", argv
[3],
628 "\": must be on or off", (char *) NULL
);
632 static Atom _NET_WM_STATE
;
633 static Atom _NET_WM_STATE_REMOVE
;
634 static Atom _NET_WM_STATE_ADD
;
635 static Atom _NET_WM_STATE_FULLSCREEN
;
637 if (!_NET_WM_STATE
) {
639 Atom
*atom_ptr
[MAX_ATOMS
];
640 char *names
[MAX_ATOMS
];
642 #define atom(a,b) atom_ptr[i] = &a; names[i] = b; i++
643 atom(_NET_WM_STATE
, "_NET_WM_STATE");
644 atom(_NET_WM_STATE_REMOVE
, "_NET_WM_STATE_REMOVE");
645 atom(_NET_WM_STATE_ADD
, "_NET_WM_STATE_ADD");
646 atom(_NET_WM_STATE_FULLSCREEN
, "_NET_WM_STATE_FULLSCREEN");
648 Atom atoms
[MAX_ATOMS
];
649 XInternAtoms(winPtr
->display
, names
, i
, 0, atoms
);
651 *atom_ptr
[i
] = atoms
[i
];
656 e
.xany
.type
= ClientMessage
;
657 e
.xany
.window
= winPtr
->window
;
658 e
.xclient
.message_type
= _NET_WM_STATE
;
659 e
.xclient
.format
= 32;
660 e
.xclient
.data
.l
[0] =
661 (wmPtr
->flags
& WM_FULL_SCREEN
)
663 : _NET_WM_STATE_REMOVE
;
664 e
.xclient
.data
.l
[1] = (long)_NET_WM_STATE_FULLSCREEN
;
665 e
.xclient
.data
.l
[2] = (long)0;
666 e
.xclient
.data
.l
[3] = (long)0;
667 e
.xclient
.data
.l
[4] = (long)0;
668 XSendEvent(winPtr
->display
, RootWindow(winPtr
->display
, winPtr
->screenNum
), 0,
669 SubstructureNotifyMask
|SubstructureRedirectMask
, &e
);
671 } else if ((c
== 'g') && (strncmp(argv
[1], "geometry", length
) == 0)
676 if ((argc
!= 3) && (argc
!= 4)) {
677 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
678 argv
[0], " geometry window ?newGeometry?\"",
683 xSign
= (wmPtr
->flags
& WM_NEGATIVE_X
) ? '-' : '+';
684 ySign
= (wmPtr
->flags
& WM_NEGATIVE_Y
) ? '-' : '+';
685 if (wmPtr
->width
!= -1) {
686 width
= wmPtr
->width
;
687 height
= wmPtr
->height
;
688 } else if (IS_GRIDDED(wmPtr
)) {
689 width
= wmPtr
->reqGridWidth
;
690 height
= wmPtr
->reqGridHeight
;
692 width
= winPtr
->reqWidth
;
693 height
= winPtr
->reqHeight
;
695 sprintf(interp
->result
, "%dx%d%c%d%c%d", width
, height
,
696 xSign
, wmPtr
->x
, ySign
, wmPtr
->y
);
699 if (*argv
[3] == '\0') {
704 return ParseGeometry(interp
, argv
[3], winPtr
);
705 } else if ((c
== 'g') && (strncmp(argv
[1], "grid", length
) == 0)
707 int reqWidth
, reqHeight
, widthInc
, heightInc
;
709 if ((argc
!= 3) && (argc
!= 7)) {
710 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
711 argv
[0], " reqsize window ?baseWidth baseHeight ",
712 "widthInc heightInc?\"", (char *) NULL
);
716 if (wmPtr
->sizeHintsFlags
& PBaseSize
) {
717 sprintf(interp
->result
, "%d %d %d %d", wmPtr
->reqGridWidth
,
718 wmPtr
->reqGridHeight
, wmPtr
->widthInc
,
723 if (*argv
[3] == '\0') {
725 * Turn off gridding and reset the width and height
726 * to make sense as ungridded numbers.
729 wmPtr
->sizeHintsFlags
&= ~(PBaseSize
|PResizeInc
);
731 wmPtr
->heightInc
= 1;
732 if (wmPtr
->width
!= -1) {
733 wmPtr
->width
= winPtr
->reqWidth
+ (wmPtr
->width
734 - wmPtr
->reqGridWidth
)*wmPtr
->widthInc
;
735 wmPtr
->height
= winPtr
->reqHeight
+ (wmPtr
->height
736 - wmPtr
->reqGridHeight
)*wmPtr
->heightInc
;
739 if ((Tcl_GetInt(interp
, argv
[3], &reqWidth
) != TCL_OK
)
740 || (Tcl_GetInt(interp
, argv
[4], &reqHeight
) != TCL_OK
)
741 || (Tcl_GetInt(interp
, argv
[5], &widthInc
) != TCL_OK
)
742 || (Tcl_GetInt(interp
, argv
[6], &heightInc
) != TCL_OK
)) {
746 interp
->result
= "baseWidth can't be < 0";
750 interp
->result
= "baseHeight can't be < 0";
754 interp
->result
= "widthInc can't be < 0";
758 interp
->result
= "heightInc can't be < 0";
761 Tk_SetGrid((Tk_Window
) tkwin
, reqWidth
, reqHeight
, widthInc
,
764 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
766 } else if ((c
== 'g') && (strncmp(argv
[1], "group", length
) == 0)
770 if ((argc
!= 3) && (argc
!= 4)) {
771 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
772 argv
[0], " group window ?pathName?\"",
777 if (wmPtr
->hints
.flags
& WindowGroupHint
) {
778 interp
->result
= wmPtr
->leaderName
;
782 if (*argv
[3] == '\0') {
783 wmPtr
->hints
.flags
&= ~WindowGroupHint
;
784 wmPtr
->leaderName
= NULL
;
786 tkwin2
= Tk_NameToWindow(interp
, argv
[3], tkwin
);
787 if (tkwin2
== NULL
) {
790 Tk_MakeWindowExist(tkwin2
);
791 wmPtr
->hints
.window_group
= Tk_WindowId(tkwin2
);
792 wmPtr
->hints
.flags
|= WindowGroupHint
;
793 wmPtr
->leaderName
= Tk_PathName(tkwin2
);
796 } else if ((c
== 'i') && (strncmp(argv
[1], "iconbitmap", length
) == 0)
800 if ((argc
!= 3) && (argc
!= 4)) {
801 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
802 argv
[0], " iconbitmap window ?bitmap?\"",
807 if (wmPtr
->hints
.flags
& IconPixmapHint
) {
808 interp
->result
= Tk_NameOfBitmap(wmPtr
->hints
.icon_pixmap
);
812 if (*argv
[3] == '\0') {
813 if (wmPtr
->hints
.icon_pixmap
!= None
) {
814 Tk_FreeBitmap(wmPtr
->hints
.icon_pixmap
);
816 wmPtr
->hints
.flags
&= ~IconPixmapHint
;
818 pixmap
= Tk_GetBitmap(interp
, tkwin
, Tk_GetUid(argv
[3]));
819 if (pixmap
== None
) {
822 wmPtr
->hints
.icon_pixmap
= pixmap
;
823 wmPtr
->hints
.flags
|= IconPixmapHint
;
826 } else if ((c
== 'i') && (strncmp(argv
[1], "iconify", length
) == 0)
829 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
830 argv
[0], " iconify window\"", (char *) NULL
);
833 wmPtr
->hints
.initial_state
= IconicState
;
834 if (wmPtr
->flags
& WM_NEVER_MAPPED
) {
838 if (XIconifyWindow(winPtr
->display
, winPtr
->window
,
839 winPtr
->screenNum
) == 0) {
841 "couldn't send iconify message to window manager";
845 interp
->result
= "can't iconify under X11R3";
848 } else if ((c
== 'i') && (strncmp(argv
[1], "iconmask", length
) == 0)
852 if ((argc
!= 3) && (argc
!= 4)) {
853 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
854 argv
[0], " iconmask window ?bitmap?\"",
859 if (wmPtr
->hints
.flags
& IconMaskHint
) {
860 interp
->result
= Tk_NameOfBitmap(wmPtr
->hints
.icon_mask
);
864 if (*argv
[3] == '\0') {
865 if (wmPtr
->hints
.icon_mask
!= None
) {
866 Tk_FreeBitmap(wmPtr
->hints
.icon_mask
);
868 wmPtr
->hints
.flags
&= ~IconMaskHint
;
870 pixmap
= Tk_GetBitmap(interp
, tkwin
, Tk_GetUid(argv
[3]));
871 if (pixmap
== None
) {
874 wmPtr
->hints
.icon_mask
= pixmap
;
875 wmPtr
->hints
.flags
|= IconMaskHint
;
878 } else if ((c
== 'i') && (strncmp(argv
[1], "iconname", length
) == 0)
881 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
882 argv
[0], " iconname window ?newName?\"", (char *) NULL
);
886 interp
->result
= (wmPtr
->iconName
!= NULL
) ? wmPtr
->iconName
: "";
889 wmPtr
->iconName
= Tk_GetUid(argv
[3]);
890 if (!(wmPtr
->flags
& WM_NEVER_MAPPED
)) {
891 XSetIconName(winPtr
->display
, winPtr
->window
, wmPtr
->iconName
);
894 } else if ((c
== 'i') && (strncmp(argv
[1], "iconposition", length
) == 0)
898 if ((argc
!= 3) && (argc
!= 5)) {
899 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
900 argv
[0], " iconposition window ?x y?\"",
905 if (wmPtr
->hints
.flags
& IconPositionHint
) {
906 sprintf(interp
->result
, "%d %d", wmPtr
->hints
.icon_x
,
907 wmPtr
->hints
.icon_y
);
911 if (*argv
[3] == '\0') {
912 wmPtr
->hints
.flags
&= ~IconPositionHint
;
914 if ((Tcl_GetInt(interp
, argv
[3], &x
) != TCL_OK
)
915 || (Tcl_GetInt(interp
, argv
[4], &y
) != TCL_OK
)){
918 wmPtr
->hints
.icon_x
= x
;
919 wmPtr
->hints
.icon_y
= y
;
920 wmPtr
->hints
.flags
|= IconPositionHint
;
923 } else if ((c
== 'i') && (strncmp(argv
[1], "iconwindow", length
) == 0)
927 if ((argc
!= 3) && (argc
!= 4)) {
928 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
929 argv
[0], " iconwindow window ?pathName?\"",
934 if (wmPtr
->hints
.flags
& IconWindowHint
) {
935 interp
->result
= wmPtr
->iconWindowName
;
939 if (*argv
[3] == '\0') {
940 wmPtr
->hints
.flags
&= ~IconWindowHint
;
941 wmPtr
->iconWindowName
= NULL
;
943 tkwin2
= Tk_NameToWindow(interp
, argv
[3], tkwin
);
944 if (tkwin2
== NULL
) {
947 Tk_MakeWindowExist(tkwin2
);
948 wmPtr
->hints
.icon_window
= Tk_WindowId(tkwin2
);
949 wmPtr
->hints
.flags
|= IconWindowHint
;
950 wmPtr
->iconWindowName
= Tk_PathName(tkwin2
);
953 } else if ((c
== 'm') && (strncmp(argv
[1], "maxsize", length
) == 0)
956 if ((argc
!= 3) && (argc
!= 5)) {
957 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
958 argv
[0], " maxsize window ?width height?\"", (char *) NULL
);
962 if (wmPtr
->sizeHintsFlags
& PMaxSize
) {
963 sprintf(interp
->result
, "%d %d", wmPtr
->maxWidth
,
968 if (*argv
[3] == '\0') {
969 wmPtr
->sizeHintsFlags
&= ~PMaxSize
;
971 if ((Tcl_GetInt(interp
, argv
[3], &width
) != TCL_OK
)
972 || (Tcl_GetInt(interp
, argv
[4], &height
) != TCL_OK
)) {
975 wmPtr
->maxWidth
= width
;
976 wmPtr
->maxHeight
= height
;
977 wmPtr
->sizeHintsFlags
|= PMaxSize
;
979 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
981 } else if ((c
== 'm') && (strncmp(argv
[1], "minsize", length
) == 0)
984 if ((argc
!= 3) && (argc
!= 5)) {
985 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
986 argv
[0], " minsize window ?width height?\"", (char *) NULL
);
990 if (wmPtr
->sizeHintsFlags
& PMinSize
) {
991 sprintf(interp
->result
, "%d %d", wmPtr
->minWidth
,
996 if (*argv
[3] == '\0') {
997 wmPtr
->sizeHintsFlags
&= ~PMinSize
;
999 if ((Tcl_GetInt(interp
, argv
[3], &width
) != TCL_OK
)
1000 || (Tcl_GetInt(interp
, argv
[4], &height
) != TCL_OK
)) {
1003 wmPtr
->minWidth
= width
;
1004 wmPtr
->minHeight
= height
;
1005 wmPtr
->sizeHintsFlags
|= PMinSize
;
1007 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1009 } else if ((c
== 'p') && (strncmp(argv
[1], "positionfrom", length
) == 0)) {
1010 if ((argc
!= 3) && (argc
!= 4)) {
1011 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1012 argv
[0], " positionfrom window ?user/program?\"",
1017 if (wmPtr
->sizeHintsFlags
& USPosition
) {
1018 interp
->result
= "user";
1019 } else if (wmPtr
->sizeHintsFlags
& PPosition
) {
1020 interp
->result
= "program";
1024 if (*argv
[3] == '\0') {
1025 wmPtr
->sizeHintsFlags
&= ~(USPosition
|PPosition
);
1028 length
= strlen(argv
[3]);
1029 if ((c
== 'u') && (strncmp(argv
[3], "user", length
) == 0)) {
1030 wmPtr
->sizeHintsFlags
&= ~PPosition
;
1031 wmPtr
->sizeHintsFlags
|= USPosition
;
1032 } else if ((c
== 'p') && (strncmp(argv
[3], "program", length
) == 0)) {
1033 wmPtr
->sizeHintsFlags
&= ~USPosition
;
1034 wmPtr
->sizeHintsFlags
|= PPosition
;
1036 Tcl_AppendResult(interp
, "bad argument \"", argv
[3],
1037 "\": must be program or user", (char *) NULL
);
1041 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1043 } else if ((c
== 'r') && (strncmp(argv
[1], "raise", length
) == 0)) {
1045 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1046 argv
[0], " raise window\"", (char *) NULL
);
1049 Tk_MakeWindowExist((Tk_Window
) winPtr
);
1050 XRaiseWindow(Tk_Display(winPtr
), Tk_WindowId(winPtr
));
1051 } else if ((c
== 's') && (strncmp(argv
[1], "sizefrom", length
) == 0)) {
1052 if ((argc
!= 3) && (argc
!= 4)) {
1053 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1054 argv
[0], " sizefrom window ?user|program?\"",
1059 if (wmPtr
->sizeHintsFlags
& USSize
) {
1060 interp
->result
= "user";
1061 } else if (wmPtr
->sizeHintsFlags
& PSize
) {
1062 interp
->result
= "program";
1066 if (*argv
[3] == '\0') {
1067 wmPtr
->sizeHintsFlags
&= ~(USSize
|PSize
);
1070 length
= strlen(argv
[3]);
1071 if ((c
== 'u') && (strncmp(argv
[3], "user", length
) == 0)) {
1072 wmPtr
->sizeHintsFlags
&= ~PSize
;
1073 wmPtr
->sizeHintsFlags
|= USSize
;
1074 } else if ((c
== 'p')
1075 && (strncmp(argv
[3], "program", length
) == 0)) {
1076 wmPtr
->sizeHintsFlags
&= ~USSize
;
1077 wmPtr
->sizeHintsFlags
|= PSize
;
1079 Tcl_AppendResult(interp
, "bad argument \"", argv
[3],
1080 "\": must be program or user", (char *) NULL
);
1084 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1086 } else if ((c
== 't') && (strncmp(argv
[1], "title", length
) == 0)
1089 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1090 argv
[0], " title window ?newTitle?\"", (char *) NULL
);
1094 interp
->result
= (wmPtr
->titleUid
!= NULL
) ? wmPtr
->titleUid
1098 wmPtr
->titleUid
= Tk_GetUid(argv
[3]);
1100 if (!(wmPtr
->flags
& WM_NEVER_MAPPED
)) {
1101 XTextProperty textProp
;
1103 if (XStringListToTextProperty(&wmPtr
->titleUid
, 1,
1105 XSetWMName(winPtr
->display
, winPtr
->window
, &textProp
);
1106 XFree((char *) textProp
.value
);
1112 } else if ((c
== 't') && (strncmp(argv
[1], "transient", length
) == 0)
1116 if ((argc
!= 3) && (argc
!= 4)) {
1117 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1118 argv
[0], " transient window ?master?\"", (char *) NULL
);
1122 if (wmPtr
->master
!= None
) {
1123 interp
->result
= wmPtr
->masterWindowName
;
1127 if (argv
[3][0] == '\0') {
1128 wmPtr
->master
= None
;
1129 wmPtr
->masterWindowName
= NULL
;
1131 master
= Tk_NameToWindow(interp
, argv
[3], tkwin
);
1132 if (master
== NULL
) {
1135 Tk_MakeWindowExist(master
);
1136 wmPtr
->master
= Tk_WindowId(master
);
1137 wmPtr
->masterWindowName
= Tk_PathName(master
);
1139 if (!(wmPtr
->flags
& WM_NEVER_MAPPED
)) {
1140 XSetTransientForHint(winPtr
->display
, winPtr
->window
,
1143 } else if ((c
== 'w') && (strncmp(argv
[1], "withdraw", length
) == 0)) {
1145 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1146 argv
[0], " withdraw window\"", (char *) NULL
);
1149 wmPtr
->hints
.initial_state
= WithdrawnState
;
1150 if (wmPtr
->flags
& WM_NEVER_MAPPED
) {
1153 if (XWithdrawWindow(winPtr
->display
, winPtr
->window
,
1154 winPtr
->screenNum
) == 0) {
1156 "couldn't send withdraw message to window manager";
1159 winPtr
->flags
&= ~TK_MAPPED
;
1160 } else if ((c
== 'p') && (strncmp(argv
[1], "protocol", length
) == 0)) {
1162 * handle various ICCCM WM_PROTOCOL attributes
1165 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1166 argv
[0], " protocol window type..\"", (char *) NULL
);
1169 if (!strcmp(argv
[3], "delete")) {
1170 return WmProtocolCmd(interp
, &(wmPtr
->deleteCmd
), argc
, argv
);
1172 Tcl_AppendResult(interp
, argv
[0],
1173 ": bad argument ", argv
[3], " must be: ",
1174 "delete", (char *) NULL
);
1179 Tcl_AppendResult(interp
, "unknown or ambiguous option \"", argv
[1],
1180 "\": must be aspect, deiconify, focusmodel, ",
1181 "fullscreen, geometry, grid, group, iconbitmap, ",
1182 "iconify, iconmask, iconname, iconposition, ",
1183 "iconwindow, maxsize, minsize, positionfrom, raise, ",
1184 "sizefrom, title, transient, withdraw, or protocol",
1191 if (!(wmPtr
->flags
& (WM_UPDATE_PENDING
|WM_NEVER_MAPPED
))) {
1192 Tk_DoWhenIdle(UpdateGeometryInfo
, (ClientData
) winPtr
);
1193 wmPtr
->flags
|= WM_UPDATE_PENDING
;
1199 *----------------------------------------------------------------------
1203 * This procedure is invoked by a widget when it wishes to set a grid
1204 * coordinate system that controls the size of a top-level window.
1205 * It provides a C interface equivalent to the "wm grid" command and
1206 * is usually asscoiated with the -setgrid option.
1212 * Grid-related information will be passed to the window manager, so
1213 * that the top-level window associated with tkwin will resize on
1216 *----------------------------------------------------------------------
1220 Tk_SetGrid(tkwin
, reqWidth
, reqHeight
, widthInc
, heightInc
)
1221 Tk_Window tkwin
; /* Token for window. New window mgr info
1222 * will be posted for the top-level window
1223 * associated with this window. */
1224 int reqWidth
; /* Width (in grid units) corresponding to
1225 * the requested geometry for tkwin. */
1226 int reqHeight
; /* Height (in grid units) corresponding to
1227 * the requested geometry for tkwin. */
1228 int widthInc
, heightInc
; /* Pixel increments corresponding to a
1229 * change of one grid unit. */
1231 TkWindow
*winPtr
= (TkWindow
*) tkwin
;
1232 register WmInfo
*wmPtr
;
1235 * Find the top-level window for tkwin, plus the window manager
1239 while (!(winPtr
->flags
& TK_TOP_LEVEL
)) {
1240 winPtr
= winPtr
->parentPtr
;
1242 wmPtr
= winPtr
->wmInfoPtr
;
1244 if ((wmPtr
->reqGridWidth
== reqWidth
)
1245 && (wmPtr
->reqGridHeight
!= reqHeight
)
1246 && (wmPtr
->widthInc
!= widthInc
)
1247 && (wmPtr
->heightInc
!= heightInc
)
1248 && ((wmPtr
->sizeHintsFlags
& (PBaseSize
|PResizeInc
))
1249 == PBaseSize
|PResizeInc
)) {
1254 * If gridding was previously off, then forget about any window
1255 * size requests made by the user or via "wm geometry": these are
1256 * in pixel units and there's no easy way to translate them to
1257 * grid units since the new requested size of the top-level window in
1258 * pixels may not yet have been registered yet (it may filter up
1259 * the hierarchy in DoWhenIdle handlers).
1262 if (!(wmPtr
->sizeHintsFlags
& PBaseSize
)) {
1268 * Set the new gridding information, and start the process of passing
1269 * all of this information to the window manager.
1272 wmPtr
->reqGridWidth
= reqWidth
;
1273 wmPtr
->reqGridHeight
= reqHeight
;
1274 wmPtr
->widthInc
= widthInc
;
1275 wmPtr
->heightInc
= heightInc
;
1276 wmPtr
->sizeHintsFlags
|= PBaseSize
|PResizeInc
;
1277 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1278 if (!(wmPtr
->flags
& (WM_UPDATE_PENDING
|WM_NEVER_MAPPED
))) {
1279 Tk_DoWhenIdle(UpdateGeometryInfo
, (ClientData
) winPtr
);
1280 wmPtr
->flags
|= WM_UPDATE_PENDING
;
1285 *----------------------------------------------------------------------
1287 * TopLevelEventProc --
1289 * This procedure is invoked when a top-level (or other externally-
1290 * managed window) is restructured in any way.
1296 * Tk's internal data structures for the window get modified to
1297 * reflect the structural change.
1299 *----------------------------------------------------------------------
1303 TopLevelEventProc(clientData
, eventPtr
)
1304 ClientData clientData
; /* Window for which event occurred. */
1305 XEvent
*eventPtr
; /* Event that just happened. */
1307 register TkWindow
*winPtr
= (TkWindow
*) clientData
;
1309 if (eventPtr
->type
== DestroyNotify
) {
1310 if (!(winPtr
->flags
& TK_ALREADY_DEAD
)) {
1311 Tk_DestroyWindow((Tk_Window
) winPtr
);
1313 } else if (eventPtr
->type
== ConfigureNotify
) {
1314 register WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1318 * A top-level window has been reconfigured. Problem #1:
1319 * discard stale information. If the application has recently
1320 * tried to reconfigure itself, ignore all events until the
1321 * response to that reconfiguration arrives (the response is
1322 * assumed to be the first ConfigureNotify that arrives after
1323 * the server has seen the request; this suffers from potential
1324 * races with user actions, but it's the best I can think of
1328 diff
= eventPtr
->xconfigure
.serial
- wmPtr
->configRequest
;
1334 * Problem #2: reparenting window managers. If the window
1335 * manager reparents a top-level window then the x and y
1336 * information that comes in events for the window is wrong:
1337 * it gives the location of the window inside its decorative
1338 * parent, rather than the location of the window in root
1339 * coordinates, which is what we want. Window managers
1340 * are supposed to send synthetic events with the correct
1341 * information, but ICCCM doesn't require them to do this
1342 * under all conditions, and the information provided doesn't
1343 * include everything we need here. So, the code below
1344 * maintains a bunch of information about the parent window.
1345 * If the window hasn't been reparented, we pretend that
1346 * there is a parent shrink-wrapped around the window.
1349 if (wmPtr
->reparent
== None
) {
1351 winPtr
->changes
.x
= eventPtr
->xconfigure
.x
;
1352 winPtr
->changes
.y
= eventPtr
->xconfigure
.y
;
1353 wmPtr
->parentWidth
= eventPtr
->xconfigure
.width
1354 + 2*eventPtr
->xconfigure
.border_width
;
1355 wmPtr
->parentHeight
= eventPtr
->xconfigure
.height
1356 + 2*eventPtr
->xconfigure
.border_width
;
1358 unsigned int width
, height
, bd
, dummy
;
1361 Tk_ErrorHandler handler
;
1363 handler
= Tk_CreateErrorHandler(winPtr
->display
, BadDrawable
, -1,
1364 -1, (Tk_ErrorProc
*) NULL
, (ClientData
) NULL
);
1365 status
= XGetGeometry(winPtr
->display
, wmPtr
->reparent
,
1366 &dummy2
, &x
, &y
, &width
, &height
, &bd
, &dummy
);
1367 Tk_DeleteErrorHandler(handler
);
1370 * It appears that the reparented parent went away and
1371 * no-one told us. Reset the window to indicate that
1372 * it's not reparented, then handle it as a non-reparented
1375 wmPtr
->reparent
= None
;
1376 wmPtr
->flags
&= ~WM_NESTED_REPARENT
;
1377 wmPtr
->xInParent
= wmPtr
->yInParent
= 0;
1380 wmPtr
->parentWidth
= width
+ 2*bd
;
1381 wmPtr
->parentHeight
= height
+ 2*bd
;
1382 winPtr
->changes
.x
= x
;
1383 winPtr
->changes
.y
= y
;
1384 if (wmPtr
->flags
& WM_NESTED_REPARENT
) {
1385 int xOffset
, yOffset
;
1387 (void) XTranslateCoordinates(winPtr
->display
, winPtr
->window
,
1388 wmPtr
->reparent
, 0, 0, &xOffset
, &yOffset
, &dummy2
);
1389 wmPtr
->xInParent
= xOffset
+ bd
- winPtr
->changes
.border_width
;
1390 wmPtr
->yInParent
= yOffset
+ bd
- winPtr
->changes
.border_width
;
1392 if (!eventPtr
->xconfigure
.send_event
) {
1393 wmPtr
->xInParent
= eventPtr
->xconfigure
.x
+ bd
;
1394 wmPtr
->yInParent
= eventPtr
->xconfigure
.y
+ bd
;
1397 winPtr
->changes
.x
= x
+ wmPtr
->xInParent
;
1398 winPtr
->changes
.y
= y
+ wmPtr
->yInParent
;
1402 * Problem #3: if the window size or location was changed
1403 * externally, update the geometry information in wmPtr to make
1404 * it look just as if the user had typed a "wm geometry" command
1405 * to make the change. There are many tricky situations to deal
1407 * (a) the event is simply a reflection of an internal geometry
1408 * request from the window's widgets (must leave width and
1409 * height alone in this case).
1410 * (b) the window manager might respond to a size request from
1411 * us with a different size than requested (e.g. it might
1412 * have a minimum allowable window size). Because of this,
1413 * can't just compare new size with requested size to determine
1414 * whether this event is a reflection of an internal request
1415 * from within the application. Use WM_CONFIG_PENDING flag
1417 * (c) ConfigureNotify events also arise if the window has been
1418 * moved, even if its size hasn't changed. Must distinguish
1419 * between the user moving the window and the user resizing
1423 if (wmPtr
->flags
& WM_CONFIG_PENDING
) {
1426 * Size change is just a reflection of something coming from
1430 diff
= eventPtr
->xconfigure
.serial
- wmPtr
->configRequest
;
1432 if (wmPtr
->flags
& WM_CONFIG_AGAIN
) {
1433 if (!(wmPtr
->flags
& WM_UPDATE_PENDING
)) {
1434 Tk_DoWhenIdle(UpdateGeometryInfo
, (ClientData
) winPtr
);
1435 wmPtr
->flags
|= WM_UPDATE_PENDING
;
1438 wmPtr
->flags
&= ~(WM_CONFIG_PENDING
|WM_CONFIG_AGAIN
);
1440 } else if ((winPtr
->changes
.width
!= eventPtr
->xconfigure
.width
)
1441 || (winPtr
->changes
.height
!= eventPtr
->xconfigure
.height
)) {
1442 wmPtr
->configWidth
= -1;
1443 wmPtr
->configHeight
= -1;
1444 if (IS_GRIDDED(wmPtr
)) {
1445 wmPtr
->width
= wmPtr
->reqGridWidth
1446 + (eventPtr
->xconfigure
.width
1447 - winPtr
->reqWidth
)/wmPtr
->widthInc
;
1448 if (wmPtr
->width
< 0) {
1451 wmPtr
->height
= wmPtr
->reqGridHeight
1452 + (eventPtr
->xconfigure
.height
1453 - winPtr
->reqHeight
)/wmPtr
->heightInc
;
1454 if (wmPtr
->height
< 0) {
1457 } else if ((eventPtr
->xconfigure
.width
!= winPtr
->changes
.width
)
1458 || (eventPtr
->xconfigure
.height
1459 != winPtr
->changes
.height
)) {
1461 * The check above is needed so we don't think the user
1462 * requested a new size when all he/she did was to move
1466 wmPtr
->width
= eventPtr
->xconfigure
.width
;
1467 wmPtr
->height
= eventPtr
->xconfigure
.height
;
1471 winPtr
->changes
.width
= eventPtr
->xconfigure
.width
;
1472 winPtr
->changes
.height
= eventPtr
->xconfigure
.height
;
1473 winPtr
->changes
.border_width
= eventPtr
->xconfigure
.border_width
;
1474 winPtr
->changes
.sibling
= eventPtr
->xconfigure
.above
;
1475 winPtr
->changes
.stack_mode
= Above
;
1477 x
= winPtr
->changes
.x
- wmPtr
->xInParent
;
1478 if (wmPtr
->flags
& WM_NEGATIVE_X
) {
1479 x
= DisplayWidth(winPtr
->display
, winPtr
->screenNum
)
1480 - (x
+ wmPtr
->parentWidth
);
1482 y
= winPtr
->changes
.y
- wmPtr
->yInParent
;
1483 if (wmPtr
->flags
& WM_NEGATIVE_Y
) {
1484 y
= DisplayHeight(winPtr
->display
, winPtr
->screenNum
)
1485 - (y
+ wmPtr
->parentHeight
);
1487 if ((x
!= wmPtr
->x
) || (y
!= wmPtr
->y
)) {
1491 } else if (eventPtr
->type
== MapNotify
) {
1492 winPtr
->flags
|= TK_MAPPED
;
1493 } else if (eventPtr
->type
== UnmapNotify
) {
1494 winPtr
->flags
&= ~TK_MAPPED
;
1495 } else if (eventPtr
->type
== ReparentNotify
) {
1496 WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1497 Window root
, *children
, dummy2
, *virtualRootPtr
;
1498 Atom virtualRootAtom
, actualType
;
1500 unsigned long numItems
, bytesAfter
;
1504 * Locate the ancestor of this window that is just below the
1505 * root window for the screen (could be the window itself).
1506 * This code is a bit tricky because it allows for the
1507 * possibility of a virtual root window, which is identified
1508 * with a property named __SWM_VROOT.
1511 virtualRootAtom
= Tk_InternAtom((Tk_Window
) winPtr
, "__SWM_VROOT");
1512 wmPtr
->flags
&= ~WM_NESTED_REPARENT
;
1513 wmPtr
->reparent
= None
;
1514 root
= eventPtr
->xreparent
.parent
;
1515 while (root
!= RootWindow(winPtr
->display
, winPtr
->screenNum
)) {
1516 Tk_ErrorHandler handler1
, handler2
;
1519 virtualRootPtr
= NULL
;
1522 Tk_CreateErrorHandler(winPtr
->display
, BadDrawable
,
1523 -1, -1, (Tk_ErrorProc
*) NULL
,
1526 Tk_CreateErrorHandler(winPtr
->display
, BadWindow
,
1527 -1, -1, (Tk_ErrorProc
*) NULL
,
1530 status
= XGetWindowProperty(winPtr
->display
, root
,
1532 0, (long) 1, False
, XA_WINDOW
,
1533 &actualType
, &actualFormat
,
1534 &numItems
, &bytesAfter
,
1535 (unsigned char **) &virtualRootPtr
);
1537 Tk_DeleteErrorHandler(handler1
);
1538 Tk_DeleteErrorHandler(handler2
);
1540 if (status
== Success
) {
1541 if (virtualRootPtr
!= NULL
) {
1542 if (*virtualRootPtr
!= root
) {
1543 panic("TopLevelEventProc confused over virtual root");
1545 XFree((char *) virtualRootPtr
);
1549 wmPtr
->reparent
= root
;
1550 (void) XQueryTree(winPtr
->display
, root
, &dummy2
, &root
,
1552 XFree((char *) children
);
1556 * The ancestor just below the (virtual) root is in wmPtr->reparent
1557 * now, and the (virtual) root is in root.
1561 if (eventPtr
->xreparent
.parent
== root
) {
1562 wmPtr
->reparent
= None
;
1563 wmPtr
->flags
&= ~WM_NESTED_REPARENT
;
1564 wmPtr
->parentWidth
= winPtr
->changes
.width
1565 + 2*winPtr
->changes
.border_width
;
1566 wmPtr
->parentHeight
= winPtr
->changes
.height
1567 + 2*winPtr
->changes
.border_width
;
1568 wmPtr
->xInParent
= wmPtr
->yInParent
= 0;
1569 winPtr
->changes
.x
= eventPtr
->xreparent
.x
;
1570 winPtr
->changes
.y
= eventPtr
->xreparent
.y
;
1572 int x
, y
, xOffset
, yOffset
;
1573 unsigned int width
, height
, bd
;
1575 if (wmPtr
->reparent
!= eventPtr
->xreparent
.parent
) {
1576 wmPtr
->flags
|= WM_NESTED_REPARENT
;
1578 wmPtr
->flags
&= ~WM_NESTED_REPARENT
;
1582 * Compute and save information about reparent and about
1583 * the window's position in reparent.
1586 (void) XGetGeometry(winPtr
->display
, wmPtr
->reparent
,
1587 &dummy2
, &x
, &y
, &width
, &height
, &bd
, &dummy
);
1588 wmPtr
->parentWidth
= width
+ 2*bd
;
1589 wmPtr
->parentHeight
= height
+ 2*bd
;
1590 (void) XTranslateCoordinates(winPtr
->display
, winPtr
->window
,
1591 wmPtr
->reparent
, 0, 0, &xOffset
, &yOffset
, &dummy2
);
1592 wmPtr
->xInParent
= xOffset
+ bd
- winPtr
->changes
.border_width
;
1593 wmPtr
->yInParent
= yOffset
+ bd
- winPtr
->changes
.border_width
;
1594 winPtr
->changes
.x
= x
+ xOffset
;
1595 winPtr
->changes
.y
= y
+ yOffset
;
1597 } else if ((eventPtr
->type
== EnterNotify
)
1598 || (eventPtr
->type
== LeaveNotify
)) {
1599 TkFocusEventProc(winPtr
, eventPtr
);
1604 *----------------------------------------------------------------------
1606 * TopLevelReqProc --
1608 * This procedure is invoked by the geometry manager whenever
1609 * the requested size for a top-level window is changed.
1615 * Arrange for the window to be resized to satisfy the request
1616 * (this happens as a when-idle action).
1618 *----------------------------------------------------------------------
1623 TopLevelReqProc(dummy
, tkwin
)
1624 ClientData dummy
; /* Not used. */
1625 Tk_Window tkwin
; /* Information about window. */
1627 TkWindow
*winPtr
= (TkWindow
*) tkwin
;
1630 wmPtr
= winPtr
->wmInfoPtr
;
1631 if ((wmPtr
->prevReqWidth
== winPtr
->reqWidth
)
1632 && (wmPtr
->prevReqHeight
== winPtr
->reqHeight
)) {
1635 wmPtr
->prevReqWidth
= winPtr
->reqWidth
;
1636 wmPtr
->prevReqHeight
= winPtr
->reqHeight
;
1637 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1638 if (!(wmPtr
->flags
& (WM_UPDATE_PENDING
|WM_NEVER_MAPPED
))) {
1639 Tk_DoWhenIdle(UpdateGeometryInfo
, (ClientData
) winPtr
);
1640 wmPtr
->flags
|= WM_UPDATE_PENDING
;
1645 *----------------------------------------------------------------------
1647 * UpdateGeometryInfo --
1649 * This procedure is invoked when a top-level window is first
1650 * mapped, and also as a when-idle procedure, to bring the
1651 * geometry and/or position of a top-level window back into
1652 * line with what has been requested by the user and/or widgets.
1658 * The window's size and location may change, unless the WM prevents
1659 * that from happening.
1661 *----------------------------------------------------------------------
1665 UpdateGeometryInfo(clientData
)
1666 ClientData clientData
; /* Pointer to the window's record. */
1668 register TkWindow
*winPtr
= (TkWindow
*) clientData
;
1669 register WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1670 int x
, y
, width
, height
;
1673 * It isn't safe to issue a new reconfigure request while there is
1674 * another reconfigure request outstanding. If this happens, skip
1675 * the second reconfigure operation but set a flag so it will get
1676 * done with the first one finishes.
1679 wmPtr
->flags
&= ~WM_UPDATE_PENDING
;
1680 if (wmPtr
->flags
& WM_CONFIG_PENDING
) {
1681 wmPtr
->flags
|= WM_CONFIG_AGAIN
;
1686 * Compute the new size for the top-level window. See the
1687 * user documentation for details on this, but the size
1688 * requested depends on (a) the size requested internally
1689 * by the window's widgets, (b) the size requested by the
1690 * user in a "wm geometry" command or via wm-based interactive
1691 * resizing (if any), and (c) whether or not the window
1692 * gridded. Don't permit sizes <= 0 because this upsets
1696 if (wmPtr
->width
== -1) {
1697 width
= winPtr
->reqWidth
;
1698 height
= winPtr
->reqHeight
;
1699 } else if (IS_GRIDDED(wmPtr
)) {
1700 width
= winPtr
->reqWidth
1701 + (wmPtr
->width
- wmPtr
->reqGridWidth
)*wmPtr
->widthInc
;
1702 height
= winPtr
->reqHeight
1703 + (wmPtr
->height
- wmPtr
->reqGridHeight
)*wmPtr
->heightInc
;
1705 width
= wmPtr
->width
;
1706 height
= wmPtr
->height
;
1716 * Compute the new position for the window. This is tricky, because
1717 * we need to include the border widths supplied by a reparented
1718 * parent in this calculation, but can't use the parent's current
1719 * overall size since that may change as a result of this code.
1722 if (wmPtr
->flags
& WM_NEGATIVE_X
) {
1723 x
= DisplayWidth(winPtr
->display
, winPtr
->screenNum
) - wmPtr
->x
1724 - (width
+ (wmPtr
->parentWidth
- winPtr
->changes
.width
))
1727 x
= wmPtr
->x
+ wmPtr
->xInParent
;
1729 if (wmPtr
->flags
& WM_NEGATIVE_Y
) {
1730 y
= DisplayHeight(winPtr
->display
, winPtr
->screenNum
) - wmPtr
->y
1731 - (height
+ (wmPtr
->parentHeight
- winPtr
->changes
.height
))
1734 y
= wmPtr
->y
+ wmPtr
->yInParent
;
1738 * If the window's size is going to change and the window is
1739 * supposed to not be resizable by the user, then we have to
1740 * update the size hints. There may also be a size-hint-update
1741 * request pending from somewhere else, too.
1744 if (((width
!= winPtr
->changes
.width
) || (width
!= winPtr
->changes
.width
))
1745 && !IS_GRIDDED(wmPtr
)
1746 && ((wmPtr
->sizeHintsFlags
& (PMinSize
|PMaxSize
)) == 0)) {
1747 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1749 if (wmPtr
->flags
& WM_UPDATE_SIZE_HINTS
) {
1750 UpdateSizeHints(winPtr
);
1754 * If the geometry hasn't changed, be careful to use only a
1755 * resize operation. This is because of bugs in some window
1756 * managers (e.g. twm, as of 4/24/91) where they don't interpret
1757 * coordinates according to ICCCM.
1760 if ((x
!= winPtr
->changes
.x
) || (y
!= winPtr
->changes
.y
)) {
1761 wmPtr
->configRequest
= XNextRequest(winPtr
->display
);
1762 wmPtr
->configWidth
= width
;
1763 wmPtr
->configHeight
= height
;
1764 Tk_MoveResizeWindow((Tk_Window
) winPtr
, x
, y
, (unsigned) width
,
1766 wmPtr
->flags
|= WM_CONFIG_PENDING
;
1767 } else if ((width
!= wmPtr
->configWidth
)
1768 || (height
!= wmPtr
->configHeight
)) {
1769 wmPtr
->configRequest
= XNextRequest(winPtr
->display
);
1770 wmPtr
->configWidth
= width
;
1771 wmPtr
->configHeight
= height
;
1772 Tk_ResizeWindow((Tk_Window
) winPtr
, (unsigned) width
,
1774 wmPtr
->flags
|= WM_CONFIG_PENDING
;
1779 *--------------------------------------------------------------
1781 * UpdateSizeHints --
1783 * This procedure is called to update the window manager's
1784 * size hints information from the information in a WmInfo
1791 * Properties get changed for winPtr.
1793 *--------------------------------------------------------------
1797 UpdateSizeHints(winPtr
)
1800 register WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1801 XSizeHints
*hintsPtr
;
1803 wmPtr
->flags
&= ~WM_UPDATE_SIZE_HINTS
;
1806 hintsPtr
= XAllocSizeHints();
1807 if (hintsPtr
== NULL
) {
1812 * Compute the pixel-based sizes for the various fields in the
1813 * size hints structure, based on the grid-based sizes in
1817 if (IS_GRIDDED(wmPtr
)) {
1818 hintsPtr
->base_width
= winPtr
->reqWidth
1819 - (wmPtr
->reqGridWidth
* wmPtr
->widthInc
);
1820 if (hintsPtr
->base_width
< 0) {
1821 hintsPtr
->base_width
= 0;
1823 hintsPtr
->base_height
= winPtr
->reqHeight
1824 - (wmPtr
->reqGridHeight
* wmPtr
->heightInc
);
1825 if (hintsPtr
->base_height
< 0) {
1826 hintsPtr
->base_height
= 0;
1828 hintsPtr
->min_width
= hintsPtr
->base_width
1829 + (wmPtr
->minWidth
* wmPtr
->widthInc
);
1830 hintsPtr
->min_height
= hintsPtr
->base_height
1831 + (wmPtr
->minHeight
* wmPtr
->heightInc
);
1832 hintsPtr
->max_width
= hintsPtr
->base_width
1833 + (wmPtr
->maxWidth
* wmPtr
->widthInc
);
1834 hintsPtr
->max_height
= hintsPtr
->base_height
1835 + (wmPtr
->maxHeight
* wmPtr
->heightInc
);
1837 hintsPtr
->min_width
= wmPtr
->minWidth
;
1838 hintsPtr
->min_height
= wmPtr
->minHeight
;
1839 hintsPtr
->max_width
= wmPtr
->maxWidth
;
1840 hintsPtr
->max_height
= wmPtr
->maxHeight
;
1841 hintsPtr
->base_width
= 0;
1842 hintsPtr
->base_height
= 0;
1844 hintsPtr
->width_inc
= wmPtr
->widthInc
;
1845 hintsPtr
->height_inc
= wmPtr
->heightInc
;
1846 hintsPtr
->min_aspect
.x
= wmPtr
->minAspect
.x
;
1847 hintsPtr
->min_aspect
.y
= wmPtr
->minAspect
.y
;
1848 hintsPtr
->max_aspect
.x
= wmPtr
->maxAspect
.x
;
1849 hintsPtr
->max_aspect
.y
= wmPtr
->maxAspect
.y
;
1850 hintsPtr
->win_gravity
= wmPtr
->gravity
;
1851 hintsPtr
->flags
= wmPtr
->sizeHintsFlags
;
1854 * If a window is non-gridded and no minimum or maximum size has
1855 * been specified, don't let the window be resized at all.
1858 if (!IS_GRIDDED(wmPtr
)
1859 && ((wmPtr
->sizeHintsFlags
& (PMinSize
|PMaxSize
)) == 0)) {
1862 width
= wmPtr
->width
;
1863 height
= wmPtr
->height
;
1865 width
= winPtr
->reqWidth
;
1866 height
= winPtr
->reqHeight
;
1868 hintsPtr
->min_width
= hintsPtr
->max_width
= width
;
1869 hintsPtr
->min_height
= hintsPtr
->max_height
= height
;
1870 hintsPtr
->flags
|= PMinSize
|PMaxSize
;
1874 * If min or max size isn't specified, fill in with extreme values
1875 * rather than leaving unspecified. Otherwise window manager may
1876 * do someting counter-intuitive like the last value ever specified.
1879 if (!(hintsPtr
->flags
& PMinSize
)) {
1880 hintsPtr
->min_width
= hintsPtr
->min_height
= 0;
1881 hintsPtr
->flags
|= PMinSize
;
1883 if (!(hintsPtr
->flags
& PMaxSize
)) {
1884 hintsPtr
->max_width
= hintsPtr
->max_height
= 1000000;
1885 hintsPtr
->flags
|= PMaxSize
;
1888 XSetWMNormalHints(winPtr
->display
, winPtr
->window
, hintsPtr
);
1890 XFree((char *) hintsPtr
);
1895 *--------------------------------------------------------------
1899 * This procedure is called to update the window manager's
1900 * hints information from the information in a WmInfo
1907 * Properties get changed for winPtr.
1909 *--------------------------------------------------------------
1916 WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1918 if (wmPtr
->flags
& WM_NEVER_MAPPED
) {
1921 XSetWMHints(winPtr
->display
, winPtr
->window
, &wmPtr
->hints
);
1925 *--------------------------------------------------------------
1929 * This procedure parses a geometry string and updates
1930 * information used to control the geometry of a top-level
1934 * A standard Tcl return value, plus an error message in
1935 * interp->result if an error occurs.
1938 * The size and/or location of winPtr may change.
1940 *--------------------------------------------------------------
1944 ParseGeometry(interp
, string
, winPtr
)
1945 Tcl_Interp
*interp
; /* Used for error reporting. */
1946 char *string
; /* String containing new geometry. Has the
1947 * standard form "=wxh+x+y". */
1948 TkWindow
*winPtr
; /* Pointer to top-level window whose
1949 * geometry is to be changed. */
1951 register WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1952 int x
, y
, width
, height
, flags
;
1954 register char *p
= string
;
1957 * The leading "=" is optional.
1965 * Parse the width and height, if they are present. Don't
1966 * actually update any of the fields of wmPtr until we've
1967 * successfully parsed the entire geometry string.
1970 width
= wmPtr
->width
;
1971 height
= wmPtr
->height
;
1974 flags
= wmPtr
->flags
;
1976 width
= strtoul(p
, &end
, 10);
1985 height
= strtoul(p
, &end
, 10);
1990 * Parse the X and Y coordinates, if they are present.
1994 flags
&= ~(WM_NEGATIVE_X
| WM_NEGATIVE_Y
);
1996 flags
|= WM_NEGATIVE_X
;
1997 } else if (*p
!= '+') {
2000 x
= strtol(p
+1, &end
, 10);
2003 flags
|= WM_NEGATIVE_Y
;
2004 } else if (*p
!= '+') {
2007 y
= strtol(p
+1, &end
, 10);
2013 * Assume that the geometry information came from the user,
2014 * unless an explicit source has been specified. Otherwise
2015 * most window managers assume that the size hints were
2016 * program-specified and they ignore them.
2019 if ((wmPtr
->sizeHintsFlags
& (USPosition
|PPosition
)) == 0) {
2020 wmPtr
->sizeHintsFlags
|= USPosition
;
2021 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
2026 * Everything was parsed OK. Update the fields of *wmPtr and
2027 * arrange for the appropriate information to be percolated out
2028 * to the window manager at the next idle moment.
2031 wmPtr
->width
= width
;
2032 wmPtr
->height
= height
;
2035 wmPtr
->flags
= flags
;
2037 if (!(wmPtr
->flags
& (WM_UPDATE_PENDING
|WM_NEVER_MAPPED
))) {
2038 Tk_DoWhenIdle(UpdateGeometryInfo
, (ClientData
) winPtr
);
2039 wmPtr
->flags
|= WM_UPDATE_PENDING
;
2044 Tcl_AppendResult(interp
, "bad geometry specifier \"",
2045 string
, "\"", (char *) NULL
);
2050 *----------------------------------------------------------------------
2052 * Tk_GetRootCoords --
2054 * Given a token for a window, this procedure traces through the
2055 * window's lineage to find the root-window coordinates corresponding
2056 * to point (0,0) in the window.
2059 * The locations pointed to by xPtr and yPtr are filled in with
2060 * the root coordinates of the (0,0) point in tkwin.
2065 *----------------------------------------------------------------------
2069 Tk_GetRootCoords(tkwin
, xPtr
, yPtr
)
2070 Tk_Window tkwin
; /* Token for window. */
2071 int *xPtr
; /* Where to store x-displacement of (0,0). */
2072 int *yPtr
; /* Where to store y-displacement of (0,0). */
2075 register TkWindow
*winPtr
= (TkWindow
*) tkwin
;
2078 * Search back through this window's parents all the way to a
2079 * top-level window, combining the offsets of each window within
2085 x
+= winPtr
->changes
.x
+ winPtr
->changes
.border_width
;
2086 y
+= winPtr
->changes
.y
+ winPtr
->changes
.border_width
;
2087 if (winPtr
->flags
& TK_TOP_LEVEL
) {
2090 winPtr
= winPtr
->parentPtr
;
2099 *--------------------------------------------------------------
2101 * TkWmSetWmProtocols --
2102 * Set the ICCCM WM_PROTOCOLS to be honored by this window.
2103 * Currently, it is just WM_DELETE_WINDOW.
2109 * A window property may get updated.
2111 *--------------------------------------------------------------
2115 TkWmSetWmProtocols(winPtr
)
2116 TkWindow
*winPtr
; /* Newly-created top-level window. */
2118 if (winPtr
->wmInfoPtr
->flags
& WM_NEVER_MAPPED
) {
2123 /* assemble the WM_PROTOCOLS that we honor */
2126 atomlist
[count
++] = Tk_InternAtom((Tk_Window
) winPtr
,
2127 "WM_DELETE_WINDOW");
2129 * other WM_PROTOCOLS go here -- e.g...
2130 * atomlist[count++] = Tk_InternAtom((Tk_Window) winPtr,
2131 * "WM_SAVE_YOURSELF");
2135 * assign the honor list to the window not all X11R4's have
2136 * XSetWmProtocols() so use XChangeProperty()
2139 /* XSetWmProtocols(winPtr->display, winPtr->window, atomlist, count); */
2141 XChangeProperty(winPtr
->display
,
2143 Tk_InternAtom((Tk_Window
) winPtr
, "WM_PROTOCOLS"),
2146 (unsigned char *)atomlist
,
2157 *----------------------------------------------------------------------
2159 * TkWmProtocolEventProc --
2161 * Handle a WM_PROTOCOL ICCCM event sent by the window manager to
2164 * The WM_PROTOCOL's currently handled are:
2166 * WM_DELETE_PROTOCOL:
2171 * for WM_DELETE_WINDOW:
2172 * - window may be deleted if specified earlier by a
2174 * - a tcl command may be executed if sepcified earlier by a
2180 TkWmProtocolEventProc(winPtr
, eventPtr
)
2184 if ((Atom
)(eventPtr
->xclient
.data
.l
)[0] ==
2185 Tk_InternAtom((Tk_Window
) winPtr
, "WM_DELETE_WINDOW")) {
2187 WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
2189 if (wmPtr
->deleteCmd
) {
2190 if (*(wmPtr
->deleteCmd
) == '\0') {
2191 /* callback is empty, just delete the window */
2192 Tk_DestroyWindow((Tk_Window
) winPtr
);
2194 /* there is a callback so run it */
2195 (void) Tcl_Eval(winPtr
->mainPtr
->interp
,
2196 wmPtr
->deleteCmd
, 0, (char **)0);
2199 Tk_DestroyWindow((Tk_Window
) winPtr
);
2203 * else { .. other WM_<ETC> cases go here ... }
2210 *----------------------------------------------------------------------
2216 * wm protocol <window> delete [command_str]
2218 * right now just delete is supported for OPTION
2220 * Kind of artificial, But makes it easier to merge into new
2221 * versions of Stock Tk.
2224 WmProtocolCmd(interp
, CmdPtr
, argc
, argv
)
2230 #define Cmd (*CmdPtr)
2235 * return current command
2237 if (!Cmd
|| *Cmd
== '\0') {
2241 * chop off the <blank><window_name>
2242 * and return just the cmd
2244 int x
= strlen(Cmd
) - strlen(argv
[2]) - 1;
2248 /* maybe should just have them put the window in the cmd */
2249 Tcl_AppendResult(interp
, Cmd
, (char *)NULL
);
2252 * tack the blank and window name back on
2265 if (*argv
[4] != '\0') {
2266 int x
= strlen(argv
[4]) + strlen(argv
[2]) + 2;
2267 if (!(Cmd
= ckalloc(x
))) {
2268 perror("wm protocol:");
2270 sprintf(Cmd
, "%s %s", argv
[4], argv
[2]);
2275 Tcl_AppendResult(interp
, "wrong # of arguments: must be \"",
2276 argv
[0], " protocol window <attribute> [cmd]\"", (char *) NULL
);
2285 *----------------------------------------------------------------------
2287 * Tk_CoordsToWindow --
2289 * Given the root coordinates of a point, this procedure
2290 * returns the token for the top-most window covering that point,
2291 * if there exists such a window in this application.
2294 * The return result is either a token for the window corresponding
2295 * to rootX and rootY, or else NULL to indicate that there is no such
2301 *----------------------------------------------------------------------
2305 Tk_CoordsToWindow(rootX
, rootY
, tkwin
)
2306 int rootX
, rootY
; /* Coordinates of point in root window. */
2307 Tk_Window tkwin
; /* Token for any window in application;
2308 * used to identify the application. */
2310 Window rootChild
, dummy3
, dummy4
;
2311 int i
, dummy1
, dummy2
;
2312 register WmInfo
*wmPtr
;
2313 register TkWindow
*winPtr
, *childPtr
;
2314 TkWindow
*nextPtr
; /* Coordinates of highest child found so
2315 * far that contains point. */
2316 int x
, y
; /* Coordinates in winPtr. */
2318 Window
*children
; /* Children of winPtr, or NULL. */
2319 unsigned int numChildren
; /* Size of children array. */
2322 * Step 1: find the top-level window that contains the desired
2326 if (XTranslateCoordinates(Tk_Display(tkwin
),
2327 RootWindowOfScreen(Tk_Screen(tkwin
)),
2328 RootWindowOfScreen(Tk_Screen(tkwin
)), rootX
, rootY
, &dummy1
,
2329 &dummy2
, &rootChild
) == False
) {
2330 panic("Tk_CoordsToWindow get False return from XTranslateCoordinates");
2332 for (wmPtr
= firstWmPtr
; ; wmPtr
= wmPtr
->nextPtr
) {
2333 if (wmPtr
== NULL
) {
2336 if ((wmPtr
->reparent
== rootChild
) || ((wmPtr
->reparent
== None
)
2337 && (wmPtr
->winPtr
->window
== rootChild
))) {
2341 winPtr
= wmPtr
->winPtr
;
2342 if (winPtr
->mainPtr
!= ((TkWindow
*) tkwin
)->mainPtr
) {
2347 * Step 2: work down through the hierarchy underneath this window.
2348 * At each level, scan through all the children to see if any contain
2349 * the point. If none do, then we're done. If one does, then do the
2350 * same thing on that child. If two or more do, then fetch enough
2351 * information from the window server to figure out which is on top,
2352 * and repeat on that child.
2358 x
-= winPtr
->changes
.x
;
2359 y
-= winPtr
->changes
.y
;
2362 for (childPtr
= winPtr
->childList
; childPtr
!= NULL
;
2363 childPtr
= childPtr
->nextPtr
) {
2364 if (!Tk_IsMapped(childPtr
) || (childPtr
->flags
& TK_TOP_LEVEL
)) {
2367 tmpx
= x
- childPtr
->changes
.x
;
2368 tmpy
= y
- childPtr
->changes
.y
;
2369 bd
= childPtr
->changes
.border_width
;
2370 if ((tmpx
< -bd
) || (tmpy
< -bd
)
2371 || (tmpx
>= (childPtr
->changes
.width
+ bd
))
2372 || (tmpy
>= (childPtr
->changes
.height
+ bd
))) {
2375 if (nextPtr
== NULL
) {
2381 * More than one child of same parent overlaps point. Must
2382 * figure out which is on top. Keep a cache of the stacking
2383 * order for winPtr to help with this, in case there are >2
2384 * children overlapping.
2387 if (children
== NULL
) {
2388 if (XQueryTree(winPtr
->display
, winPtr
->window
, &dummy3
,
2389 &dummy4
, &children
, &numChildren
) == 0) {
2390 panic("Tk_CoordsToWindow get error return from XQueryTree");
2393 for (i
= 0; i
< numChildren
; i
++) {
2394 if (children
[i
] == childPtr
->window
) {
2397 if (children
[i
] == nextPtr
->window
) {
2403 if (children
!= NULL
) {
2404 XFree((char *) children
);
2406 if (nextPtr
== NULL
) {
2411 return (Tk_Window
) winPtr
;