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 *--------------------------------------------------------------
243 TkWindow
*winPtr
/* Newly-created top-level window. */
246 register WmInfo
*wmPtr
;
248 wmPtr
= (WmInfo
*) ckalloc(sizeof(WmInfo
));
249 wmPtr
->winPtr
= winPtr
;
250 wmPtr
->reparent
= None
;
251 wmPtr
->titleUid
= NULL
;
252 wmPtr
->iconName
= NULL
;
253 wmPtr
->master
= None
;
254 wmPtr
->hints
.flags
= InputHint
| StateHint
;
255 wmPtr
->hints
.input
= True
;
256 wmPtr
->hints
.initial_state
= NormalState
;
257 wmPtr
->hints
.icon_pixmap
= None
;
258 wmPtr
->hints
.icon_window
= None
;
259 wmPtr
->hints
.icon_x
= wmPtr
->hints
.icon_y
= 0;
260 wmPtr
->hints
.icon_mask
= None
;
261 wmPtr
->hints
.window_group
= None
;
262 wmPtr
->leaderName
= NULL
;
263 wmPtr
->iconWindowName
= NULL
;
264 wmPtr
->masterWindowName
= NULL
;
265 wmPtr
->sizeHintsFlags
= 0;
266 wmPtr
->minWidth
= wmPtr
->minHeight
= 0;
267 wmPtr
->maxWidth
= wmPtr
->maxHeight
= 10000;
268 wmPtr
->widthInc
= wmPtr
->heightInc
= 1;
269 wmPtr
->minAspect
.x
= wmPtr
->minAspect
.y
= 1;
270 wmPtr
->maxAspect
.x
= wmPtr
->maxAspect
.y
= 1;
271 wmPtr
->reqGridWidth
= wmPtr
->reqGridHeight
= -1;
272 wmPtr
->prevReqWidth
= wmPtr
->prevReqHeight
= -1;
273 wmPtr
->gravity
= NorthWestGravity
;
276 wmPtr
->x
= winPtr
->changes
.x
;
277 wmPtr
->y
= winPtr
->changes
.y
;
278 wmPtr
->parentWidth
= winPtr
->changes
.width
279 + 2*winPtr
->changes
.border_width
;
280 wmPtr
->parentHeight
= winPtr
->changes
.height
281 + 2*winPtr
->changes
.border_width
;
282 wmPtr
->xInParent
= wmPtr
->yInParent
= 0;
283 wmPtr
->configRequest
= 0;
284 wmPtr
->configWidth
= -1;
285 wmPtr
->configHeight
= -1;
286 wmPtr
->flags
= WM_NEVER_MAPPED
;
287 wmPtr
->deleteCmd
= (char *)0;
288 wmPtr
->nextPtr
= firstWmPtr
;
290 winPtr
->wmInfoPtr
= wmPtr
;
293 * Tk must monitor certain events for top-level windows:
294 * (a) structure events, in order to detect size and position changes
295 * caused by window managers.
296 * (b) enter/level events, in order to perform focussing correctly.
299 Tk_CreateEventHandler((Tk_Window
) winPtr
,
300 StructureNotifyMask
|EnterWindowMask
|LeaveWindowMask
,
301 TopLevelEventProc
, (ClientData
) winPtr
);
304 * Arrange for geometry requests to be reflected from the window
305 * to the window manager.
308 Tk_ManageGeometry((Tk_Window
) winPtr
, TopLevelReqProc
, (ClientData
) 0);
312 *--------------------------------------------------------------
316 * This procedure is invoked just before a top-level window
317 * is mapped. It gives this module a chance to update all
318 * window-manager-related information in properties before
319 * the window manager sees the map event and checks the
323 * Returns non-zero if it's OK for the window to be mapped, 0
324 * if the caller shouldn't map the window after all (e.g. because
325 * it has been withdrawn).
328 * Properties of winPtr may get updated to provide up-to-date
329 * information to the window manager.
331 *--------------------------------------------------------------
336 TkWindow
*winPtr
/* Top-level window that's about to
340 register WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
342 XTextProperty textProp
;
346 * Set the MAPPED flag if the window is going to appear in its normal
347 * state: if it's going to be iconified or withdrawn then it won't
351 if (wmPtr
->hints
.initial_state
== NormalState
) {
352 winPtr
->flags
|= TK_MAPPED
;
354 if (wmPtr
->flags
& WM_NEVER_MAPPED
) {
355 wmPtr
->flags
&= ~WM_NEVER_MAPPED
;
358 * This is the first time this window has ever been mapped.
359 * Store all the window-manager-related information for the
364 if (wmPtr
->titleUid
== NULL
) {
365 wmPtr
->titleUid
= winPtr
->nameUid
;
367 if (XStringListToTextProperty(&wmPtr
->titleUid
, 1, &textProp
) != 0) {
368 XSetWMName(winPtr
->display
, winPtr
->window
, &textProp
);
369 XFree((char *) textProp
.value
);
373 TkWmSetClass(winPtr
);
374 TkWmSetWmProtocols(winPtr
);
376 if (wmPtr
->iconName
!= NULL
) {
377 XSetIconName(winPtr
->display
, winPtr
->window
, wmPtr
->iconName
);
380 if (wmPtr
->master
!= None
) {
381 XSetTransientForHint(winPtr
->display
, winPtr
->window
, wmPtr
->master
);
385 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
386 UpdateGeometryInfo((ClientData
) winPtr
);
388 if (wmPtr
->hints
.initial_state
== WithdrawnState
) {
395 *--------------------------------------------------------------
399 * This procedure is invoked when a top-level window is
400 * about to be deleted. It cleans up the wm-related data
401 * structures for the window.
407 * The WmInfo structure for winPtr gets freed up.
409 *--------------------------------------------------------------
414 TkWindow
*winPtr
/* Newly-created top-level window. */
417 register WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
422 if (firstWmPtr
== wmPtr
) {
423 firstWmPtr
= wmPtr
->nextPtr
;
425 register WmInfo
*prevPtr
;
427 for (prevPtr
= firstWmPtr
; ; prevPtr
= prevPtr
->nextPtr
) {
428 if (prevPtr
== NULL
) {
429 panic("couldn't unlink window in TkWmDeadWindow");
431 if (prevPtr
->nextPtr
== wmPtr
) {
432 prevPtr
->nextPtr
= wmPtr
->nextPtr
;
437 if (wmPtr
->hints
.flags
& IconPixmapHint
) {
438 Tk_FreeBitmap(wmPtr
->hints
.icon_pixmap
);
440 if (wmPtr
->hints
.flags
& IconMaskHint
) {
441 Tk_FreeBitmap(wmPtr
->hints
.icon_mask
);
443 if (wmPtr
->flags
& WM_UPDATE_PENDING
) {
444 Tk_CancelIdleCall(UpdateGeometryInfo
, (ClientData
) winPtr
);
446 if (wmPtr
->deleteCmd
) {
447 ckfree(wmPtr
->deleteCmd
);
449 ckfree((char *) wmPtr
);
450 winPtr
->wmInfoPtr
= NULL
;
454 *--------------------------------------------------------------
458 * This procedure is invoked whenever a top-level window's
459 * class is changed. If the window has been mapped then this
460 * procedure updates the window manager property for the
461 * class. If the window hasn't been mapped, the update is
462 * deferred until just before the first mapping.
468 * A window property may get updated.
470 *--------------------------------------------------------------
475 TkWindow
*winPtr
/* Newly-created top-level window. */
478 if (winPtr
->wmInfoPtr
->flags
& WM_NEVER_MAPPED
) {
483 if (winPtr
->classUid
!= NULL
) {
484 XClassHint
*classPtr
;
486 classPtr
= XAllocClassHint();
487 classPtr
->res_name
= winPtr
->nameUid
;
488 classPtr
->res_class
= winPtr
->classUid
;
489 XSetClassHint(winPtr
->display
, winPtr
->window
, classPtr
);
490 XFree((char *) classPtr
);
496 *----------------------------------------------------------------------
500 * This procedure is invoked to process the "wm" Tcl command.
501 * See the user documentation for details on what it does.
504 * A standard Tcl result.
507 * See the user documentation.
509 *----------------------------------------------------------------------
515 ClientData clientData
, /* Main window associated with
517 Tcl_Interp
*interp
, /* Current interpreter. */
518 int argc
, /* Number of arguments. */
519 char **argv
/* Argument strings. */
522 Tk_Window tkwin
= (Tk_Window
) clientData
;
524 register WmInfo
*wmPtr
;
529 Tcl_AppendResult(interp
, "wrong # args: should be \"",
530 argv
[0], " option window ?arg ...?\"", (char *) NULL
);
533 winPtr
= (TkWindow
*) Tk_NameToWindow(interp
, argv
[2], tkwin
);
534 if (winPtr
== NULL
) {
537 if (!(winPtr
->flags
& TK_TOP_LEVEL
)) {
538 Tcl_AppendResult(interp
, "window \"", winPtr
->pathName
,
539 "\" isn't a top-level window", (char *) NULL
);
542 wmPtr
= winPtr
->wmInfoPtr
;
544 length
= strlen(argv
[1]);
545 if ((c
== 'a') && (strncmp(argv
[1], "aspect", length
) == 0)) {
546 int numer1
, denom1
, numer2
, denom2
;
548 if ((argc
!= 3) && (argc
!= 7)) {
549 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
550 argv
[0], " aspect window ?minNumer minDenom ",
551 "maxNumer maxDenom?\"", (char *) NULL
);
555 if (wmPtr
->sizeHintsFlags
& PAspect
) {
556 sprintf(interp
->result
, "%d %d %d %d", wmPtr
->minAspect
.x
,
557 wmPtr
->minAspect
.y
, wmPtr
->maxAspect
.x
,
562 if (*argv
[3] == '\0') {
563 wmPtr
->sizeHintsFlags
&= ~PAspect
;
565 if ((Tcl_GetInt(interp
, argv
[3], &numer1
) != TCL_OK
)
566 || (Tcl_GetInt(interp
, argv
[4], &denom1
) != TCL_OK
)
567 || (Tcl_GetInt(interp
, argv
[5], &numer2
) != TCL_OK
)
568 || (Tcl_GetInt(interp
, argv
[6], &denom2
) != TCL_OK
)) {
571 if ((numer1
<= 0) || (denom1
<= 0) || (numer2
<= 0) ||
573 interp
->result
= "aspect number can't be <= 0";
576 wmPtr
->minAspect
.x
= numer1
;
577 wmPtr
->minAspect
.y
= denom1
;
578 wmPtr
->maxAspect
.x
= numer2
;
579 wmPtr
->maxAspect
.y
= denom2
;
580 wmPtr
->sizeHintsFlags
|= PAspect
;
582 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
584 } else if ((c
== 'd') && (strncmp(argv
[1], "deiconify", length
) == 0)) {
586 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
587 argv
[0], " deiconify window\"", (char *) NULL
);
590 wmPtr
->hints
.initial_state
= NormalState
;
591 if (wmPtr
->flags
& WM_NEVER_MAPPED
) {
594 Tk_MapWindow((Tk_Window
) winPtr
);
595 } else if ((c
== 'f') && (strncmp(argv
[1], "focusmodel", length
) == 0)) {
596 if ((argc
!= 3) && (argc
!= 4)) {
597 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
598 argv
[0], " focusmodel window ?active|passive?\"",
603 interp
->result
= wmPtr
->hints
.input
? "passive" : "active";
607 length
= strlen(argv
[3]);
608 if ((c
== 'a') && (strncmp(argv
[3], "active", length
) == 0)) {
609 wmPtr
->hints
.input
= False
;
610 } else if ((c
== 'p') && (strncmp(argv
[3], "passive", length
) == 0)) {
611 wmPtr
->hints
.input
= True
;
613 Tcl_AppendResult(interp
, "bad argument \"", argv
[3],
614 "\": must be active or passive", (char *) NULL
);
618 } else if ((c
== 'f') && (strncmp(argv
[1], "fullscreen", length
) == 0)) {
620 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
621 argv
[0], " fullscreen window on|off\"",
626 length
= strlen(argv
[3]);
627 if (strncmp(argv
[3], "on", length
) == 0) {
628 wmPtr
->flags
&= ~WM_FULL_SCREEN
;
629 } else if (strncmp(argv
[3], "off", length
) == 0) {
630 wmPtr
->flags
|= WM_FULL_SCREEN
;
632 Tcl_AppendResult(interp
, "bad argument \"", argv
[3],
633 "\": must be on or off", (char *) NULL
);
637 static Atom _NET_WM_STATE
;
638 static Atom _NET_WM_STATE_REMOVE
;
639 static Atom _NET_WM_STATE_ADD
;
640 static Atom _NET_WM_STATE_FULLSCREEN
;
642 if (!_NET_WM_STATE
) {
644 Atom
*atom_ptr
[MAX_ATOMS
];
645 char *names
[MAX_ATOMS
];
647 #define atom(a,b) atom_ptr[i] = &a; names[i] = b; i++
648 atom(_NET_WM_STATE
, "_NET_WM_STATE");
649 atom(_NET_WM_STATE_REMOVE
, "_NET_WM_STATE_REMOVE");
650 atom(_NET_WM_STATE_ADD
, "_NET_WM_STATE_ADD");
651 atom(_NET_WM_STATE_FULLSCREEN
, "_NET_WM_STATE_FULLSCREEN");
653 Atom atoms
[MAX_ATOMS
];
654 XInternAtoms(winPtr
->display
, names
, i
, 0, atoms
);
656 *atom_ptr
[i
] = atoms
[i
];
661 e
.xany
.type
= ClientMessage
;
662 e
.xany
.window
= winPtr
->window
;
663 e
.xclient
.message_type
= _NET_WM_STATE
;
664 e
.xclient
.format
= 32;
665 e
.xclient
.data
.l
[0] =
666 (wmPtr
->flags
& WM_FULL_SCREEN
)
668 : _NET_WM_STATE_REMOVE
;
669 e
.xclient
.data
.l
[1] = (long)_NET_WM_STATE_FULLSCREEN
;
670 e
.xclient
.data
.l
[2] = (long)0;
671 e
.xclient
.data
.l
[3] = (long)0;
672 e
.xclient
.data
.l
[4] = (long)0;
673 XSendEvent(winPtr
->display
, RootWindow(winPtr
->display
, winPtr
->screenNum
), 0,
674 SubstructureNotifyMask
|SubstructureRedirectMask
, &e
);
676 } else if ((c
== 'g') && (strncmp(argv
[1], "geometry", length
) == 0)
681 if ((argc
!= 3) && (argc
!= 4)) {
682 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
683 argv
[0], " geometry window ?newGeometry?\"",
688 xSign
= (wmPtr
->flags
& WM_NEGATIVE_X
) ? '-' : '+';
689 ySign
= (wmPtr
->flags
& WM_NEGATIVE_Y
) ? '-' : '+';
690 if (wmPtr
->width
!= -1) {
691 width
= wmPtr
->width
;
692 height
= wmPtr
->height
;
693 } else if (IS_GRIDDED(wmPtr
)) {
694 width
= wmPtr
->reqGridWidth
;
695 height
= wmPtr
->reqGridHeight
;
697 width
= winPtr
->reqWidth
;
698 height
= winPtr
->reqHeight
;
700 sprintf(interp
->result
, "%dx%d%c%d%c%d", width
, height
,
701 xSign
, wmPtr
->x
, ySign
, wmPtr
->y
);
704 if (*argv
[3] == '\0') {
709 return ParseGeometry(interp
, argv
[3], winPtr
);
710 } else if ((c
== 'g') && (strncmp(argv
[1], "grid", length
) == 0)
712 int reqWidth
, reqHeight
, widthInc
, heightInc
;
714 if ((argc
!= 3) && (argc
!= 7)) {
715 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
716 argv
[0], " reqsize window ?baseWidth baseHeight ",
717 "widthInc heightInc?\"", (char *) NULL
);
721 if (wmPtr
->sizeHintsFlags
& PBaseSize
) {
722 sprintf(interp
->result
, "%d %d %d %d", wmPtr
->reqGridWidth
,
723 wmPtr
->reqGridHeight
, wmPtr
->widthInc
,
728 if (*argv
[3] == '\0') {
730 * Turn off gridding and reset the width and height
731 * to make sense as ungridded numbers.
734 wmPtr
->sizeHintsFlags
&= ~(PBaseSize
|PResizeInc
);
736 wmPtr
->heightInc
= 1;
737 if (wmPtr
->width
!= -1) {
738 wmPtr
->width
= winPtr
->reqWidth
+ (wmPtr
->width
739 - wmPtr
->reqGridWidth
)*wmPtr
->widthInc
;
740 wmPtr
->height
= winPtr
->reqHeight
+ (wmPtr
->height
741 - wmPtr
->reqGridHeight
)*wmPtr
->heightInc
;
744 if ((Tcl_GetInt(interp
, argv
[3], &reqWidth
) != TCL_OK
)
745 || (Tcl_GetInt(interp
, argv
[4], &reqHeight
) != TCL_OK
)
746 || (Tcl_GetInt(interp
, argv
[5], &widthInc
) != TCL_OK
)
747 || (Tcl_GetInt(interp
, argv
[6], &heightInc
) != TCL_OK
)) {
751 interp
->result
= "baseWidth can't be < 0";
755 interp
->result
= "baseHeight can't be < 0";
759 interp
->result
= "widthInc can't be < 0";
763 interp
->result
= "heightInc can't be < 0";
766 Tk_SetGrid((Tk_Window
) tkwin
, reqWidth
, reqHeight
, widthInc
,
769 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
771 } else if ((c
== 'g') && (strncmp(argv
[1], "group", length
) == 0)
775 if ((argc
!= 3) && (argc
!= 4)) {
776 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
777 argv
[0], " group window ?pathName?\"",
782 if (wmPtr
->hints
.flags
& WindowGroupHint
) {
783 interp
->result
= wmPtr
->leaderName
;
787 if (*argv
[3] == '\0') {
788 wmPtr
->hints
.flags
&= ~WindowGroupHint
;
789 wmPtr
->leaderName
= NULL
;
791 tkwin2
= Tk_NameToWindow(interp
, argv
[3], tkwin
);
792 if (tkwin2
== NULL
) {
795 Tk_MakeWindowExist(tkwin2
);
796 wmPtr
->hints
.window_group
= Tk_WindowId(tkwin2
);
797 wmPtr
->hints
.flags
|= WindowGroupHint
;
798 wmPtr
->leaderName
= Tk_PathName(tkwin2
);
801 } else if ((c
== 'i') && (strncmp(argv
[1], "iconbitmap", length
) == 0)
805 if ((argc
!= 3) && (argc
!= 4)) {
806 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
807 argv
[0], " iconbitmap window ?bitmap?\"",
812 if (wmPtr
->hints
.flags
& IconPixmapHint
) {
813 interp
->result
= Tk_NameOfBitmap(wmPtr
->hints
.icon_pixmap
);
817 if (*argv
[3] == '\0') {
818 if (wmPtr
->hints
.icon_pixmap
!= None
) {
819 Tk_FreeBitmap(wmPtr
->hints
.icon_pixmap
);
821 wmPtr
->hints
.flags
&= ~IconPixmapHint
;
823 pixmap
= Tk_GetBitmap(interp
, tkwin
, Tk_GetUid(argv
[3]));
824 if (pixmap
== None
) {
827 wmPtr
->hints
.icon_pixmap
= pixmap
;
828 wmPtr
->hints
.flags
|= IconPixmapHint
;
831 } else if ((c
== 'i') && (strncmp(argv
[1], "iconify", length
) == 0)
834 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
835 argv
[0], " iconify window\"", (char *) NULL
);
838 wmPtr
->hints
.initial_state
= IconicState
;
839 if (wmPtr
->flags
& WM_NEVER_MAPPED
) {
843 if (XIconifyWindow(winPtr
->display
, winPtr
->window
,
844 winPtr
->screenNum
) == 0) {
846 "couldn't send iconify message to window manager";
850 interp
->result
= "can't iconify under X11R3";
853 } else if ((c
== 'i') && (strncmp(argv
[1], "iconmask", length
) == 0)
857 if ((argc
!= 3) && (argc
!= 4)) {
858 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
859 argv
[0], " iconmask window ?bitmap?\"",
864 if (wmPtr
->hints
.flags
& IconMaskHint
) {
865 interp
->result
= Tk_NameOfBitmap(wmPtr
->hints
.icon_mask
);
869 if (*argv
[3] == '\0') {
870 if (wmPtr
->hints
.icon_mask
!= None
) {
871 Tk_FreeBitmap(wmPtr
->hints
.icon_mask
);
873 wmPtr
->hints
.flags
&= ~IconMaskHint
;
875 pixmap
= Tk_GetBitmap(interp
, tkwin
, Tk_GetUid(argv
[3]));
876 if (pixmap
== None
) {
879 wmPtr
->hints
.icon_mask
= pixmap
;
880 wmPtr
->hints
.flags
|= IconMaskHint
;
883 } else if ((c
== 'i') && (strncmp(argv
[1], "iconname", length
) == 0)
886 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
887 argv
[0], " iconname window ?newName?\"", (char *) NULL
);
891 interp
->result
= (wmPtr
->iconName
!= NULL
) ? wmPtr
->iconName
: "";
894 wmPtr
->iconName
= Tk_GetUid(argv
[3]);
895 if (!(wmPtr
->flags
& WM_NEVER_MAPPED
)) {
896 XSetIconName(winPtr
->display
, winPtr
->window
, wmPtr
->iconName
);
899 } else if ((c
== 'i') && (strncmp(argv
[1], "iconposition", length
) == 0)
903 if ((argc
!= 3) && (argc
!= 5)) {
904 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
905 argv
[0], " iconposition window ?x y?\"",
910 if (wmPtr
->hints
.flags
& IconPositionHint
) {
911 sprintf(interp
->result
, "%d %d", wmPtr
->hints
.icon_x
,
912 wmPtr
->hints
.icon_y
);
916 if (*argv
[3] == '\0') {
917 wmPtr
->hints
.flags
&= ~IconPositionHint
;
919 if ((Tcl_GetInt(interp
, argv
[3], &x
) != TCL_OK
)
920 || (Tcl_GetInt(interp
, argv
[4], &y
) != TCL_OK
)){
923 wmPtr
->hints
.icon_x
= x
;
924 wmPtr
->hints
.icon_y
= y
;
925 wmPtr
->hints
.flags
|= IconPositionHint
;
928 } else if ((c
== 'i') && (strncmp(argv
[1], "iconwindow", length
) == 0)
932 if ((argc
!= 3) && (argc
!= 4)) {
933 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
934 argv
[0], " iconwindow window ?pathName?\"",
939 if (wmPtr
->hints
.flags
& IconWindowHint
) {
940 interp
->result
= wmPtr
->iconWindowName
;
944 if (*argv
[3] == '\0') {
945 wmPtr
->hints
.flags
&= ~IconWindowHint
;
946 wmPtr
->iconWindowName
= NULL
;
948 tkwin2
= Tk_NameToWindow(interp
, argv
[3], tkwin
);
949 if (tkwin2
== NULL
) {
952 Tk_MakeWindowExist(tkwin2
);
953 wmPtr
->hints
.icon_window
= Tk_WindowId(tkwin2
);
954 wmPtr
->hints
.flags
|= IconWindowHint
;
955 wmPtr
->iconWindowName
= Tk_PathName(tkwin2
);
958 } else if ((c
== 'm') && (strncmp(argv
[1], "maxsize", length
) == 0)
961 if ((argc
!= 3) && (argc
!= 5)) {
962 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
963 argv
[0], " maxsize window ?width height?\"", (char *) NULL
);
967 if (wmPtr
->sizeHintsFlags
& PMaxSize
) {
968 sprintf(interp
->result
, "%d %d", wmPtr
->maxWidth
,
973 if (*argv
[3] == '\0') {
974 wmPtr
->sizeHintsFlags
&= ~PMaxSize
;
976 if ((Tcl_GetInt(interp
, argv
[3], &width
) != TCL_OK
)
977 || (Tcl_GetInt(interp
, argv
[4], &height
) != TCL_OK
)) {
980 wmPtr
->maxWidth
= width
;
981 wmPtr
->maxHeight
= height
;
982 wmPtr
->sizeHintsFlags
|= PMaxSize
;
984 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
986 } else if ((c
== 'm') && (strncmp(argv
[1], "minsize", length
) == 0)
989 if ((argc
!= 3) && (argc
!= 5)) {
990 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
991 argv
[0], " minsize window ?width height?\"", (char *) NULL
);
995 if (wmPtr
->sizeHintsFlags
& PMinSize
) {
996 sprintf(interp
->result
, "%d %d", wmPtr
->minWidth
,
1001 if (*argv
[3] == '\0') {
1002 wmPtr
->sizeHintsFlags
&= ~PMinSize
;
1004 if ((Tcl_GetInt(interp
, argv
[3], &width
) != TCL_OK
)
1005 || (Tcl_GetInt(interp
, argv
[4], &height
) != TCL_OK
)) {
1008 wmPtr
->minWidth
= width
;
1009 wmPtr
->minHeight
= height
;
1010 wmPtr
->sizeHintsFlags
|= PMinSize
;
1012 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1014 } else if ((c
== 'p') && (strncmp(argv
[1], "positionfrom", length
) == 0)) {
1015 if ((argc
!= 3) && (argc
!= 4)) {
1016 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1017 argv
[0], " positionfrom window ?user/program?\"",
1022 if (wmPtr
->sizeHintsFlags
& USPosition
) {
1023 interp
->result
= "user";
1024 } else if (wmPtr
->sizeHintsFlags
& PPosition
) {
1025 interp
->result
= "program";
1029 if (*argv
[3] == '\0') {
1030 wmPtr
->sizeHintsFlags
&= ~(USPosition
|PPosition
);
1033 length
= strlen(argv
[3]);
1034 if ((c
== 'u') && (strncmp(argv
[3], "user", length
) == 0)) {
1035 wmPtr
->sizeHintsFlags
&= ~PPosition
;
1036 wmPtr
->sizeHintsFlags
|= USPosition
;
1037 } else if ((c
== 'p') && (strncmp(argv
[3], "program", length
) == 0)) {
1038 wmPtr
->sizeHintsFlags
&= ~USPosition
;
1039 wmPtr
->sizeHintsFlags
|= PPosition
;
1041 Tcl_AppendResult(interp
, "bad argument \"", argv
[3],
1042 "\": must be program or user", (char *) NULL
);
1046 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1048 } else if ((c
== 'r') && (strncmp(argv
[1], "raise", length
) == 0)) {
1050 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1051 argv
[0], " raise window\"", (char *) NULL
);
1054 Tk_MakeWindowExist((Tk_Window
) winPtr
);
1055 XRaiseWindow(Tk_Display(winPtr
), Tk_WindowId(winPtr
));
1056 } else if ((c
== 's') && (strncmp(argv
[1], "sizefrom", length
) == 0)) {
1057 if ((argc
!= 3) && (argc
!= 4)) {
1058 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1059 argv
[0], " sizefrom window ?user|program?\"",
1064 if (wmPtr
->sizeHintsFlags
& USSize
) {
1065 interp
->result
= "user";
1066 } else if (wmPtr
->sizeHintsFlags
& PSize
) {
1067 interp
->result
= "program";
1071 if (*argv
[3] == '\0') {
1072 wmPtr
->sizeHintsFlags
&= ~(USSize
|PSize
);
1075 length
= strlen(argv
[3]);
1076 if ((c
== 'u') && (strncmp(argv
[3], "user", length
) == 0)) {
1077 wmPtr
->sizeHintsFlags
&= ~PSize
;
1078 wmPtr
->sizeHintsFlags
|= USSize
;
1079 } else if ((c
== 'p')
1080 && (strncmp(argv
[3], "program", length
) == 0)) {
1081 wmPtr
->sizeHintsFlags
&= ~USSize
;
1082 wmPtr
->sizeHintsFlags
|= PSize
;
1084 Tcl_AppendResult(interp
, "bad argument \"", argv
[3],
1085 "\": must be program or user", (char *) NULL
);
1089 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1091 } else if ((c
== 't') && (strncmp(argv
[1], "title", length
) == 0)
1094 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1095 argv
[0], " title window ?newTitle?\"", (char *) NULL
);
1099 interp
->result
= (wmPtr
->titleUid
!= NULL
) ? wmPtr
->titleUid
1103 wmPtr
->titleUid
= Tk_GetUid(argv
[3]);
1105 if (!(wmPtr
->flags
& WM_NEVER_MAPPED
)) {
1106 XTextProperty textProp
;
1108 if (XStringListToTextProperty(&wmPtr
->titleUid
, 1,
1110 XSetWMName(winPtr
->display
, winPtr
->window
, &textProp
);
1111 XFree((char *) textProp
.value
);
1117 } else if ((c
== 't') && (strncmp(argv
[1], "transient", length
) == 0)
1121 if ((argc
!= 3) && (argc
!= 4)) {
1122 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1123 argv
[0], " transient window ?master?\"", (char *) NULL
);
1127 if (wmPtr
->master
!= None
) {
1128 interp
->result
= wmPtr
->masterWindowName
;
1132 if (argv
[3][0] == '\0') {
1133 wmPtr
->master
= None
;
1134 wmPtr
->masterWindowName
= NULL
;
1136 master
= Tk_NameToWindow(interp
, argv
[3], tkwin
);
1137 if (master
== NULL
) {
1140 Tk_MakeWindowExist(master
);
1141 wmPtr
->master
= Tk_WindowId(master
);
1142 wmPtr
->masterWindowName
= Tk_PathName(master
);
1144 if (!(wmPtr
->flags
& WM_NEVER_MAPPED
)) {
1145 XSetTransientForHint(winPtr
->display
, winPtr
->window
,
1148 } else if ((c
== 'w') && (strncmp(argv
[1], "withdraw", length
) == 0)) {
1150 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1151 argv
[0], " withdraw window\"", (char *) NULL
);
1154 wmPtr
->hints
.initial_state
= WithdrawnState
;
1155 if (wmPtr
->flags
& WM_NEVER_MAPPED
) {
1158 if (XWithdrawWindow(winPtr
->display
, winPtr
->window
,
1159 winPtr
->screenNum
) == 0) {
1161 "couldn't send withdraw message to window manager";
1164 winPtr
->flags
&= ~TK_MAPPED
;
1165 } else if ((c
== 'p') && (strncmp(argv
[1], "protocol", length
) == 0)) {
1167 * handle various ICCCM WM_PROTOCOL attributes
1170 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1171 argv
[0], " protocol window type..\"", (char *) NULL
);
1174 if (!strcmp(argv
[3], "delete")) {
1175 return WmProtocolCmd(interp
, &(wmPtr
->deleteCmd
), argc
, argv
);
1177 Tcl_AppendResult(interp
, argv
[0],
1178 ": bad argument ", argv
[3], " must be: ",
1179 "delete", (char *) NULL
);
1184 Tcl_AppendResult(interp
, "unknown or ambiguous option \"", argv
[1],
1185 "\": must be aspect, deiconify, focusmodel, ",
1186 "fullscreen, geometry, grid, group, iconbitmap, ",
1187 "iconify, iconmask, iconname, iconposition, ",
1188 "iconwindow, maxsize, minsize, positionfrom, raise, ",
1189 "sizefrom, title, transient, withdraw, or protocol",
1196 if (!(wmPtr
->flags
& (WM_UPDATE_PENDING
|WM_NEVER_MAPPED
))) {
1197 Tk_DoWhenIdle(UpdateGeometryInfo
, (ClientData
) winPtr
);
1198 wmPtr
->flags
|= WM_UPDATE_PENDING
;
1204 *----------------------------------------------------------------------
1208 * This procedure is invoked by a widget when it wishes to set a grid
1209 * coordinate system that controls the size of a top-level window.
1210 * It provides a C interface equivalent to the "wm grid" command and
1211 * is usually asscoiated with the -setgrid option.
1217 * Grid-related information will be passed to the window manager, so
1218 * that the top-level window associated with tkwin will resize on
1221 *----------------------------------------------------------------------
1226 Tk_Window tkwin
, /* Token for window. New window mgr info
1227 * will be posted for the top-level window
1228 * associated with this window. */
1229 int reqWidth
, /* Width (in grid units) corresponding to
1230 * the requested geometry for tkwin. */
1231 int reqHeight
, /* Height (in grid units) corresponding to
1232 * the requested geometry for tkwin. */
1234 int heightInc
/* Pixel increments corresponding to a
1235 * change of one grid unit. */
1238 TkWindow
*winPtr
= (TkWindow
*) tkwin
;
1239 register WmInfo
*wmPtr
;
1242 * Find the top-level window for tkwin, plus the window manager
1246 while (!(winPtr
->flags
& TK_TOP_LEVEL
)) {
1247 winPtr
= winPtr
->parentPtr
;
1249 wmPtr
= winPtr
->wmInfoPtr
;
1251 if ((wmPtr
->reqGridWidth
== reqWidth
)
1252 && (wmPtr
->reqGridHeight
!= reqHeight
)
1253 && (wmPtr
->widthInc
!= widthInc
)
1254 && (wmPtr
->heightInc
!= heightInc
)
1255 && ((wmPtr
->sizeHintsFlags
& (PBaseSize
|PResizeInc
))
1256 == PBaseSize
|PResizeInc
)) {
1261 * If gridding was previously off, then forget about any window
1262 * size requests made by the user or via "wm geometry": these are
1263 * in pixel units and there's no easy way to translate them to
1264 * grid units since the new requested size of the top-level window in
1265 * pixels may not yet have been registered yet (it may filter up
1266 * the hierarchy in DoWhenIdle handlers).
1269 if (!(wmPtr
->sizeHintsFlags
& PBaseSize
)) {
1275 * Set the new gridding information, and start the process of passing
1276 * all of this information to the window manager.
1279 wmPtr
->reqGridWidth
= reqWidth
;
1280 wmPtr
->reqGridHeight
= reqHeight
;
1281 wmPtr
->widthInc
= widthInc
;
1282 wmPtr
->heightInc
= heightInc
;
1283 wmPtr
->sizeHintsFlags
|= PBaseSize
|PResizeInc
;
1284 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1285 if (!(wmPtr
->flags
& (WM_UPDATE_PENDING
|WM_NEVER_MAPPED
))) {
1286 Tk_DoWhenIdle(UpdateGeometryInfo
, (ClientData
) winPtr
);
1287 wmPtr
->flags
|= WM_UPDATE_PENDING
;
1292 *----------------------------------------------------------------------
1294 * TopLevelEventProc --
1296 * This procedure is invoked when a top-level (or other externally-
1297 * managed window) is restructured in any way.
1303 * Tk's internal data structures for the window get modified to
1304 * reflect the structural change.
1306 *----------------------------------------------------------------------
1311 ClientData clientData
, /* Window for which event occurred. */
1312 XEvent
*eventPtr
/* Event that just happened. */
1315 register TkWindow
*winPtr
= (TkWindow
*) clientData
;
1317 if (eventPtr
->type
== DestroyNotify
) {
1318 if (!(winPtr
->flags
& TK_ALREADY_DEAD
)) {
1319 Tk_DestroyWindow((Tk_Window
) winPtr
);
1321 } else if (eventPtr
->type
== ConfigureNotify
) {
1322 register WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1326 * A top-level window has been reconfigured. Problem #1:
1327 * discard stale information. If the application has recently
1328 * tried to reconfigure itself, ignore all events until the
1329 * response to that reconfiguration arrives (the response is
1330 * assumed to be the first ConfigureNotify that arrives after
1331 * the server has seen the request; this suffers from potential
1332 * races with user actions, but it's the best I can think of
1336 diff
= eventPtr
->xconfigure
.serial
- wmPtr
->configRequest
;
1342 * Problem #2: reparenting window managers. If the window
1343 * manager reparents a top-level window then the x and y
1344 * information that comes in events for the window is wrong:
1345 * it gives the location of the window inside its decorative
1346 * parent, rather than the location of the window in root
1347 * coordinates, which is what we want. Window managers
1348 * are supposed to send synthetic events with the correct
1349 * information, but ICCCM doesn't require them to do this
1350 * under all conditions, and the information provided doesn't
1351 * include everything we need here. So, the code below
1352 * maintains a bunch of information about the parent window.
1353 * If the window hasn't been reparented, we pretend that
1354 * there is a parent shrink-wrapped around the window.
1357 if (wmPtr
->reparent
== None
) {
1359 winPtr
->changes
.x
= eventPtr
->xconfigure
.x
;
1360 winPtr
->changes
.y
= eventPtr
->xconfigure
.y
;
1361 wmPtr
->parentWidth
= eventPtr
->xconfigure
.width
1362 + 2*eventPtr
->xconfigure
.border_width
;
1363 wmPtr
->parentHeight
= eventPtr
->xconfigure
.height
1364 + 2*eventPtr
->xconfigure
.border_width
;
1366 unsigned int width
, height
, bd
, dummy
;
1369 Tk_ErrorHandler handler
;
1371 handler
= Tk_CreateErrorHandler(winPtr
->display
, BadDrawable
, -1,
1372 -1, (Tk_ErrorProc
*) NULL
, (ClientData
) NULL
);
1373 status
= XGetGeometry(winPtr
->display
, wmPtr
->reparent
,
1374 &dummy2
, &x
, &y
, &width
, &height
, &bd
, &dummy
);
1375 Tk_DeleteErrorHandler(handler
);
1378 * It appears that the reparented parent went away and
1379 * no-one told us. Reset the window to indicate that
1380 * it's not reparented, then handle it as a non-reparented
1383 wmPtr
->reparent
= None
;
1384 wmPtr
->flags
&= ~WM_NESTED_REPARENT
;
1385 wmPtr
->xInParent
= wmPtr
->yInParent
= 0;
1388 wmPtr
->parentWidth
= width
+ 2*bd
;
1389 wmPtr
->parentHeight
= height
+ 2*bd
;
1390 winPtr
->changes
.x
= x
;
1391 winPtr
->changes
.y
= y
;
1392 if (wmPtr
->flags
& WM_NESTED_REPARENT
) {
1393 int xOffset
, yOffset
;
1395 (void) XTranslateCoordinates(winPtr
->display
, winPtr
->window
,
1396 wmPtr
->reparent
, 0, 0, &xOffset
, &yOffset
, &dummy2
);
1397 wmPtr
->xInParent
= xOffset
+ bd
- winPtr
->changes
.border_width
;
1398 wmPtr
->yInParent
= yOffset
+ bd
- winPtr
->changes
.border_width
;
1400 if (!eventPtr
->xconfigure
.send_event
) {
1401 wmPtr
->xInParent
= eventPtr
->xconfigure
.x
+ bd
;
1402 wmPtr
->yInParent
= eventPtr
->xconfigure
.y
+ bd
;
1405 winPtr
->changes
.x
= x
+ wmPtr
->xInParent
;
1406 winPtr
->changes
.y
= y
+ wmPtr
->yInParent
;
1410 * Problem #3: if the window size or location was changed
1411 * externally, update the geometry information in wmPtr to make
1412 * it look just as if the user had typed a "wm geometry" command
1413 * to make the change. There are many tricky situations to deal
1415 * (a) the event is simply a reflection of an internal geometry
1416 * request from the window's widgets (must leave width and
1417 * height alone in this case).
1418 * (b) the window manager might respond to a size request from
1419 * us with a different size than requested (e.g. it might
1420 * have a minimum allowable window size). Because of this,
1421 * can't just compare new size with requested size to determine
1422 * whether this event is a reflection of an internal request
1423 * from within the application. Use WM_CONFIG_PENDING flag
1425 * (c) ConfigureNotify events also arise if the window has been
1426 * moved, even if its size hasn't changed. Must distinguish
1427 * between the user moving the window and the user resizing
1431 if (wmPtr
->flags
& WM_CONFIG_PENDING
) {
1434 * Size change is just a reflection of something coming from
1438 diff
= eventPtr
->xconfigure
.serial
- wmPtr
->configRequest
;
1440 if (wmPtr
->flags
& WM_CONFIG_AGAIN
) {
1441 if (!(wmPtr
->flags
& WM_UPDATE_PENDING
)) {
1442 Tk_DoWhenIdle(UpdateGeometryInfo
, (ClientData
) winPtr
);
1443 wmPtr
->flags
|= WM_UPDATE_PENDING
;
1446 wmPtr
->flags
&= ~(WM_CONFIG_PENDING
|WM_CONFIG_AGAIN
);
1448 } else if ((winPtr
->changes
.width
!= eventPtr
->xconfigure
.width
)
1449 || (winPtr
->changes
.height
!= eventPtr
->xconfigure
.height
)) {
1450 wmPtr
->configWidth
= -1;
1451 wmPtr
->configHeight
= -1;
1452 if (IS_GRIDDED(wmPtr
)) {
1453 wmPtr
->width
= wmPtr
->reqGridWidth
1454 + (eventPtr
->xconfigure
.width
1455 - winPtr
->reqWidth
)/wmPtr
->widthInc
;
1456 if (wmPtr
->width
< 0) {
1459 wmPtr
->height
= wmPtr
->reqGridHeight
1460 + (eventPtr
->xconfigure
.height
1461 - winPtr
->reqHeight
)/wmPtr
->heightInc
;
1462 if (wmPtr
->height
< 0) {
1465 } else if ((eventPtr
->xconfigure
.width
!= winPtr
->changes
.width
)
1466 || (eventPtr
->xconfigure
.height
1467 != winPtr
->changes
.height
)) {
1469 * The check above is needed so we don't think the user
1470 * requested a new size when all he/she did was to move
1474 wmPtr
->width
= eventPtr
->xconfigure
.width
;
1475 wmPtr
->height
= eventPtr
->xconfigure
.height
;
1479 winPtr
->changes
.width
= eventPtr
->xconfigure
.width
;
1480 winPtr
->changes
.height
= eventPtr
->xconfigure
.height
;
1481 winPtr
->changes
.border_width
= eventPtr
->xconfigure
.border_width
;
1482 winPtr
->changes
.sibling
= eventPtr
->xconfigure
.above
;
1483 winPtr
->changes
.stack_mode
= Above
;
1485 x
= winPtr
->changes
.x
- wmPtr
->xInParent
;
1486 if (wmPtr
->flags
& WM_NEGATIVE_X
) {
1487 x
= DisplayWidth(winPtr
->display
, winPtr
->screenNum
)
1488 - (x
+ wmPtr
->parentWidth
);
1490 y
= winPtr
->changes
.y
- wmPtr
->yInParent
;
1491 if (wmPtr
->flags
& WM_NEGATIVE_Y
) {
1492 y
= DisplayHeight(winPtr
->display
, winPtr
->screenNum
)
1493 - (y
+ wmPtr
->parentHeight
);
1495 if ((x
!= wmPtr
->x
) || (y
!= wmPtr
->y
)) {
1499 } else if (eventPtr
->type
== MapNotify
) {
1500 winPtr
->flags
|= TK_MAPPED
;
1501 } else if (eventPtr
->type
== UnmapNotify
) {
1502 winPtr
->flags
&= ~TK_MAPPED
;
1503 } else if (eventPtr
->type
== ReparentNotify
) {
1504 WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1505 Window root
, *children
, dummy2
, *virtualRootPtr
;
1506 Atom virtualRootAtom
, actualType
;
1508 unsigned long numItems
, bytesAfter
;
1512 * Locate the ancestor of this window that is just below the
1513 * root window for the screen (could be the window itself).
1514 * This code is a bit tricky because it allows for the
1515 * possibility of a virtual root window, which is identified
1516 * with a property named __SWM_VROOT.
1519 virtualRootAtom
= Tk_InternAtom((Tk_Window
) winPtr
, "__SWM_VROOT");
1520 wmPtr
->flags
&= ~WM_NESTED_REPARENT
;
1521 wmPtr
->reparent
= None
;
1522 root
= eventPtr
->xreparent
.parent
;
1523 while (root
!= RootWindow(winPtr
->display
, winPtr
->screenNum
)) {
1524 Tk_ErrorHandler handler1
, handler2
;
1527 virtualRootPtr
= NULL
;
1530 Tk_CreateErrorHandler(winPtr
->display
, BadDrawable
,
1531 -1, -1, (Tk_ErrorProc
*) NULL
,
1534 Tk_CreateErrorHandler(winPtr
->display
, BadWindow
,
1535 -1, -1, (Tk_ErrorProc
*) NULL
,
1538 status
= XGetWindowProperty(winPtr
->display
, root
,
1540 0, (long) 1, False
, XA_WINDOW
,
1541 &actualType
, &actualFormat
,
1542 &numItems
, &bytesAfter
,
1543 (unsigned char **) &virtualRootPtr
);
1545 Tk_DeleteErrorHandler(handler1
);
1546 Tk_DeleteErrorHandler(handler2
);
1548 if (status
== Success
) {
1549 if (virtualRootPtr
!= NULL
) {
1550 if (*virtualRootPtr
!= root
) {
1551 panic("TopLevelEventProc confused over virtual root");
1553 XFree((char *) virtualRootPtr
);
1557 wmPtr
->reparent
= root
;
1558 (void) XQueryTree(winPtr
->display
, root
, &dummy2
, &root
,
1560 XFree((char *) children
);
1564 * The ancestor just below the (virtual) root is in wmPtr->reparent
1565 * now, and the (virtual) root is in root.
1569 if (eventPtr
->xreparent
.parent
== root
) {
1570 wmPtr
->reparent
= None
;
1571 wmPtr
->flags
&= ~WM_NESTED_REPARENT
;
1572 wmPtr
->parentWidth
= winPtr
->changes
.width
1573 + 2*winPtr
->changes
.border_width
;
1574 wmPtr
->parentHeight
= winPtr
->changes
.height
1575 + 2*winPtr
->changes
.border_width
;
1576 wmPtr
->xInParent
= wmPtr
->yInParent
= 0;
1577 winPtr
->changes
.x
= eventPtr
->xreparent
.x
;
1578 winPtr
->changes
.y
= eventPtr
->xreparent
.y
;
1580 int x
, y
, xOffset
, yOffset
;
1581 unsigned int width
, height
, bd
;
1583 if (wmPtr
->reparent
!= eventPtr
->xreparent
.parent
) {
1584 wmPtr
->flags
|= WM_NESTED_REPARENT
;
1586 wmPtr
->flags
&= ~WM_NESTED_REPARENT
;
1590 * Compute and save information about reparent and about
1591 * the window's position in reparent.
1594 (void) XGetGeometry(winPtr
->display
, wmPtr
->reparent
,
1595 &dummy2
, &x
, &y
, &width
, &height
, &bd
, &dummy
);
1596 wmPtr
->parentWidth
= width
+ 2*bd
;
1597 wmPtr
->parentHeight
= height
+ 2*bd
;
1598 (void) XTranslateCoordinates(winPtr
->display
, winPtr
->window
,
1599 wmPtr
->reparent
, 0, 0, &xOffset
, &yOffset
, &dummy2
);
1600 wmPtr
->xInParent
= xOffset
+ bd
- winPtr
->changes
.border_width
;
1601 wmPtr
->yInParent
= yOffset
+ bd
- winPtr
->changes
.border_width
;
1602 winPtr
->changes
.x
= x
+ xOffset
;
1603 winPtr
->changes
.y
= y
+ yOffset
;
1605 } else if ((eventPtr
->type
== EnterNotify
)
1606 || (eventPtr
->type
== LeaveNotify
)) {
1607 TkFocusEventProc(winPtr
, eventPtr
);
1612 *----------------------------------------------------------------------
1614 * TopLevelReqProc --
1616 * This procedure is invoked by the geometry manager whenever
1617 * the requested size for a top-level window is changed.
1623 * Arrange for the window to be resized to satisfy the request
1624 * (this happens as a when-idle action).
1626 *----------------------------------------------------------------------
1632 ClientData dummy
, /* Not used. */
1633 Tk_Window tkwin
/* Information about window. */
1636 TkWindow
*winPtr
= (TkWindow
*) tkwin
;
1639 wmPtr
= winPtr
->wmInfoPtr
;
1640 if ((wmPtr
->prevReqWidth
== winPtr
->reqWidth
)
1641 && (wmPtr
->prevReqHeight
== winPtr
->reqHeight
)) {
1644 wmPtr
->prevReqWidth
= winPtr
->reqWidth
;
1645 wmPtr
->prevReqHeight
= winPtr
->reqHeight
;
1646 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1647 if (!(wmPtr
->flags
& (WM_UPDATE_PENDING
|WM_NEVER_MAPPED
))) {
1648 Tk_DoWhenIdle(UpdateGeometryInfo
, (ClientData
) winPtr
);
1649 wmPtr
->flags
|= WM_UPDATE_PENDING
;
1654 *----------------------------------------------------------------------
1656 * UpdateGeometryInfo --
1658 * This procedure is invoked when a top-level window is first
1659 * mapped, and also as a when-idle procedure, to bring the
1660 * geometry and/or position of a top-level window back into
1661 * line with what has been requested by the user and/or widgets.
1667 * The window's size and location may change, unless the WM prevents
1668 * that from happening.
1670 *----------------------------------------------------------------------
1674 UpdateGeometryInfo (
1675 ClientData clientData
/* Pointer to the window's record. */
1678 register TkWindow
*winPtr
= (TkWindow
*) clientData
;
1679 register WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1680 int x
, y
, width
, height
;
1683 * It isn't safe to issue a new reconfigure request while there is
1684 * another reconfigure request outstanding. If this happens, skip
1685 * the second reconfigure operation but set a flag so it will get
1686 * done with the first one finishes.
1689 wmPtr
->flags
&= ~WM_UPDATE_PENDING
;
1690 if (wmPtr
->flags
& WM_CONFIG_PENDING
) {
1691 wmPtr
->flags
|= WM_CONFIG_AGAIN
;
1696 * Compute the new size for the top-level window. See the
1697 * user documentation for details on this, but the size
1698 * requested depends on (a) the size requested internally
1699 * by the window's widgets, (b) the size requested by the
1700 * user in a "wm geometry" command or via wm-based interactive
1701 * resizing (if any), and (c) whether or not the window
1702 * gridded. Don't permit sizes <= 0 because this upsets
1706 if (wmPtr
->width
== -1) {
1707 width
= winPtr
->reqWidth
;
1708 height
= winPtr
->reqHeight
;
1709 } else if (IS_GRIDDED(wmPtr
)) {
1710 width
= winPtr
->reqWidth
1711 + (wmPtr
->width
- wmPtr
->reqGridWidth
)*wmPtr
->widthInc
;
1712 height
= winPtr
->reqHeight
1713 + (wmPtr
->height
- wmPtr
->reqGridHeight
)*wmPtr
->heightInc
;
1715 width
= wmPtr
->width
;
1716 height
= wmPtr
->height
;
1726 * Compute the new position for the window. This is tricky, because
1727 * we need to include the border widths supplied by a reparented
1728 * parent in this calculation, but can't use the parent's current
1729 * overall size since that may change as a result of this code.
1732 if (wmPtr
->flags
& WM_NEGATIVE_X
) {
1733 x
= DisplayWidth(winPtr
->display
, winPtr
->screenNum
) - wmPtr
->x
1734 - (width
+ (wmPtr
->parentWidth
- winPtr
->changes
.width
))
1737 x
= wmPtr
->x
+ wmPtr
->xInParent
;
1739 if (wmPtr
->flags
& WM_NEGATIVE_Y
) {
1740 y
= DisplayHeight(winPtr
->display
, winPtr
->screenNum
) - wmPtr
->y
1741 - (height
+ (wmPtr
->parentHeight
- winPtr
->changes
.height
))
1744 y
= wmPtr
->y
+ wmPtr
->yInParent
;
1748 * If the window's size is going to change and the window is
1749 * supposed to not be resizable by the user, then we have to
1750 * update the size hints. There may also be a size-hint-update
1751 * request pending from somewhere else, too.
1754 if (((width
!= winPtr
->changes
.width
) || (width
!= winPtr
->changes
.width
))
1755 && !IS_GRIDDED(wmPtr
)
1756 && ((wmPtr
->sizeHintsFlags
& (PMinSize
|PMaxSize
)) == 0)) {
1757 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1759 if (wmPtr
->flags
& WM_UPDATE_SIZE_HINTS
) {
1760 UpdateSizeHints(winPtr
);
1764 * If the geometry hasn't changed, be careful to use only a
1765 * resize operation. This is because of bugs in some window
1766 * managers (e.g. twm, as of 4/24/91) where they don't interpret
1767 * coordinates according to ICCCM.
1770 if ((x
!= winPtr
->changes
.x
) || (y
!= winPtr
->changes
.y
)) {
1771 wmPtr
->configRequest
= XNextRequest(winPtr
->display
);
1772 wmPtr
->configWidth
= width
;
1773 wmPtr
->configHeight
= height
;
1774 Tk_MoveResizeWindow((Tk_Window
) winPtr
, x
, y
, (unsigned) width
,
1776 wmPtr
->flags
|= WM_CONFIG_PENDING
;
1777 } else if ((width
!= wmPtr
->configWidth
)
1778 || (height
!= wmPtr
->configHeight
)) {
1779 wmPtr
->configRequest
= XNextRequest(winPtr
->display
);
1780 wmPtr
->configWidth
= width
;
1781 wmPtr
->configHeight
= height
;
1782 Tk_ResizeWindow((Tk_Window
) winPtr
, (unsigned) width
,
1784 wmPtr
->flags
|= WM_CONFIG_PENDING
;
1789 *--------------------------------------------------------------
1791 * UpdateSizeHints --
1793 * This procedure is called to update the window manager's
1794 * size hints information from the information in a WmInfo
1801 * Properties get changed for winPtr.
1803 *--------------------------------------------------------------
1807 UpdateSizeHints (TkWindow
*winPtr
)
1809 register WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1810 XSizeHints
*hintsPtr
;
1812 wmPtr
->flags
&= ~WM_UPDATE_SIZE_HINTS
;
1815 hintsPtr
= XAllocSizeHints();
1816 if (hintsPtr
== NULL
) {
1821 * Compute the pixel-based sizes for the various fields in the
1822 * size hints structure, based on the grid-based sizes in
1826 if (IS_GRIDDED(wmPtr
)) {
1827 hintsPtr
->base_width
= winPtr
->reqWidth
1828 - (wmPtr
->reqGridWidth
* wmPtr
->widthInc
);
1829 if (hintsPtr
->base_width
< 0) {
1830 hintsPtr
->base_width
= 0;
1832 hintsPtr
->base_height
= winPtr
->reqHeight
1833 - (wmPtr
->reqGridHeight
* wmPtr
->heightInc
);
1834 if (hintsPtr
->base_height
< 0) {
1835 hintsPtr
->base_height
= 0;
1837 hintsPtr
->min_width
= hintsPtr
->base_width
1838 + (wmPtr
->minWidth
* wmPtr
->widthInc
);
1839 hintsPtr
->min_height
= hintsPtr
->base_height
1840 + (wmPtr
->minHeight
* wmPtr
->heightInc
);
1841 hintsPtr
->max_width
= hintsPtr
->base_width
1842 + (wmPtr
->maxWidth
* wmPtr
->widthInc
);
1843 hintsPtr
->max_height
= hintsPtr
->base_height
1844 + (wmPtr
->maxHeight
* wmPtr
->heightInc
);
1846 hintsPtr
->min_width
= wmPtr
->minWidth
;
1847 hintsPtr
->min_height
= wmPtr
->minHeight
;
1848 hintsPtr
->max_width
= wmPtr
->maxWidth
;
1849 hintsPtr
->max_height
= wmPtr
->maxHeight
;
1850 hintsPtr
->base_width
= 0;
1851 hintsPtr
->base_height
= 0;
1853 hintsPtr
->width_inc
= wmPtr
->widthInc
;
1854 hintsPtr
->height_inc
= wmPtr
->heightInc
;
1855 hintsPtr
->min_aspect
.x
= wmPtr
->minAspect
.x
;
1856 hintsPtr
->min_aspect
.y
= wmPtr
->minAspect
.y
;
1857 hintsPtr
->max_aspect
.x
= wmPtr
->maxAspect
.x
;
1858 hintsPtr
->max_aspect
.y
= wmPtr
->maxAspect
.y
;
1859 hintsPtr
->win_gravity
= wmPtr
->gravity
;
1860 hintsPtr
->flags
= wmPtr
->sizeHintsFlags
;
1863 * If a window is non-gridded and no minimum or maximum size has
1864 * been specified, don't let the window be resized at all.
1867 if (!IS_GRIDDED(wmPtr
)
1868 && ((wmPtr
->sizeHintsFlags
& (PMinSize
|PMaxSize
)) == 0)) {
1871 width
= wmPtr
->width
;
1872 height
= wmPtr
->height
;
1874 width
= winPtr
->reqWidth
;
1875 height
= winPtr
->reqHeight
;
1877 hintsPtr
->min_width
= hintsPtr
->max_width
= width
;
1878 hintsPtr
->min_height
= hintsPtr
->max_height
= height
;
1879 hintsPtr
->flags
|= PMinSize
|PMaxSize
;
1883 * If min or max size isn't specified, fill in with extreme values
1884 * rather than leaving unspecified. Otherwise window manager may
1885 * do someting counter-intuitive like the last value ever specified.
1888 if (!(hintsPtr
->flags
& PMinSize
)) {
1889 hintsPtr
->min_width
= hintsPtr
->min_height
= 0;
1890 hintsPtr
->flags
|= PMinSize
;
1892 if (!(hintsPtr
->flags
& PMaxSize
)) {
1893 hintsPtr
->max_width
= hintsPtr
->max_height
= 1000000;
1894 hintsPtr
->flags
|= PMaxSize
;
1897 XSetWMNormalHints(winPtr
->display
, winPtr
->window
, hintsPtr
);
1899 XFree((char *) hintsPtr
);
1904 *--------------------------------------------------------------
1908 * This procedure is called to update the window manager's
1909 * hints information from the information in a WmInfo
1916 * Properties get changed for winPtr.
1918 *--------------------------------------------------------------
1922 UpdateHints (TkWindow
*winPtr
)
1924 WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1926 if (wmPtr
->flags
& WM_NEVER_MAPPED
) {
1929 XSetWMHints(winPtr
->display
, winPtr
->window
, &wmPtr
->hints
);
1933 *--------------------------------------------------------------
1937 * This procedure parses a geometry string and updates
1938 * information used to control the geometry of a top-level
1942 * A standard Tcl return value, plus an error message in
1943 * interp->result if an error occurs.
1946 * The size and/or location of winPtr may change.
1948 *--------------------------------------------------------------
1953 Tcl_Interp
*interp
, /* Used for error reporting. */
1954 char *string
, /* String containing new geometry. Has the
1955 * standard form "=wxh+x+y". */
1956 TkWindow
*winPtr
/* Pointer to top-level window whose
1957 * geometry is to be changed. */
1960 register WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1961 int x
, y
, width
, height
, flags
;
1963 register char *p
= string
;
1966 * The leading "=" is optional.
1974 * Parse the width and height, if they are present. Don't
1975 * actually update any of the fields of wmPtr until we've
1976 * successfully parsed the entire geometry string.
1979 width
= wmPtr
->width
;
1980 height
= wmPtr
->height
;
1983 flags
= wmPtr
->flags
;
1985 width
= strtoul(p
, &end
, 10);
1994 height
= strtoul(p
, &end
, 10);
1999 * Parse the X and Y coordinates, if they are present.
2003 flags
&= ~(WM_NEGATIVE_X
| WM_NEGATIVE_Y
);
2005 flags
|= WM_NEGATIVE_X
;
2006 } else if (*p
!= '+') {
2009 x
= strtol(p
+1, &end
, 10);
2012 flags
|= WM_NEGATIVE_Y
;
2013 } else if (*p
!= '+') {
2016 y
= strtol(p
+1, &end
, 10);
2022 * Assume that the geometry information came from the user,
2023 * unless an explicit source has been specified. Otherwise
2024 * most window managers assume that the size hints were
2025 * program-specified and they ignore them.
2028 if ((wmPtr
->sizeHintsFlags
& (USPosition
|PPosition
)) == 0) {
2029 wmPtr
->sizeHintsFlags
|= USPosition
;
2030 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
2035 * Everything was parsed OK. Update the fields of *wmPtr and
2036 * arrange for the appropriate information to be percolated out
2037 * to the window manager at the next idle moment.
2040 wmPtr
->width
= width
;
2041 wmPtr
->height
= height
;
2044 wmPtr
->flags
= flags
;
2046 if (!(wmPtr
->flags
& (WM_UPDATE_PENDING
|WM_NEVER_MAPPED
))) {
2047 Tk_DoWhenIdle(UpdateGeometryInfo
, (ClientData
) winPtr
);
2048 wmPtr
->flags
|= WM_UPDATE_PENDING
;
2053 Tcl_AppendResult(interp
, "bad geometry specifier \"",
2054 string
, "\"", (char *) NULL
);
2059 *----------------------------------------------------------------------
2061 * Tk_GetRootCoords --
2063 * Given a token for a window, this procedure traces through the
2064 * window's lineage to find the root-window coordinates corresponding
2065 * to point (0,0) in the window.
2068 * The locations pointed to by xPtr and yPtr are filled in with
2069 * the root coordinates of the (0,0) point in tkwin.
2074 *----------------------------------------------------------------------
2079 Tk_Window tkwin
, /* Token for window. */
2080 int *xPtr
, /* Where to store x-displacement of (0,0). */
2081 int *yPtr
/* Where to store y-displacement of (0,0). */
2085 register TkWindow
*winPtr
= (TkWindow
*) tkwin
;
2088 * Search back through this window's parents all the way to a
2089 * top-level window, combining the offsets of each window within
2095 x
+= winPtr
->changes
.x
+ winPtr
->changes
.border_width
;
2096 y
+= winPtr
->changes
.y
+ winPtr
->changes
.border_width
;
2097 if (winPtr
->flags
& TK_TOP_LEVEL
) {
2100 winPtr
= winPtr
->parentPtr
;
2109 *--------------------------------------------------------------
2111 * TkWmSetWmProtocols --
2112 * Set the ICCCM WM_PROTOCOLS to be honored by this window.
2113 * Currently, it is just WM_DELETE_WINDOW.
2119 * A window property may get updated.
2121 *--------------------------------------------------------------
2125 TkWmSetWmProtocols (
2126 TkWindow
*winPtr
/* Newly-created top-level window. */
2129 if (winPtr
->wmInfoPtr
->flags
& WM_NEVER_MAPPED
) {
2134 /* assemble the WM_PROTOCOLS that we honor */
2137 atomlist
[count
++] = Tk_InternAtom((Tk_Window
) winPtr
,
2138 "WM_DELETE_WINDOW");
2140 * other WM_PROTOCOLS go here -- e.g...
2141 * atomlist[count++] = Tk_InternAtom((Tk_Window) winPtr,
2142 * "WM_SAVE_YOURSELF");
2146 * assign the honor list to the window not all X11R4's have
2147 * XSetWmProtocols() so use XChangeProperty()
2150 /* XSetWmProtocols(winPtr->display, winPtr->window, atomlist, count); */
2152 XChangeProperty(winPtr
->display
,
2154 Tk_InternAtom((Tk_Window
) winPtr
, "WM_PROTOCOLS"),
2157 (unsigned char *)atomlist
,
2168 *----------------------------------------------------------------------
2170 * TkWmProtocolEventProc --
2172 * Handle a WM_PROTOCOL ICCCM event sent by the window manager to
2175 * The WM_PROTOCOL's currently handled are:
2177 * WM_DELETE_PROTOCOL:
2182 * for WM_DELETE_WINDOW:
2183 * - window may be deleted if specified earlier by a
2185 * - a tcl command may be executed if sepcified earlier by a
2191 TkWmProtocolEventProc (TkWindow
*winPtr
, XEvent
*eventPtr
)
2193 if ((Atom
)(eventPtr
->xclient
.data
.l
)[0] ==
2194 Tk_InternAtom((Tk_Window
) winPtr
, "WM_DELETE_WINDOW")) {
2196 WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
2198 if (wmPtr
->deleteCmd
) {
2199 if (*(wmPtr
->deleteCmd
) == '\0') {
2200 /* callback is empty, just delete the window */
2201 Tk_DestroyWindow((Tk_Window
) winPtr
);
2203 /* there is a callback so run it */
2204 (void) Tcl_Eval(winPtr
->mainPtr
->interp
,
2205 wmPtr
->deleteCmd
, 0, (char **)0);
2208 Tk_DestroyWindow((Tk_Window
) winPtr
);
2212 * else { .. other WM_<ETC> cases go here ... }
2219 *----------------------------------------------------------------------
2225 * wm protocol <window> delete [command_str]
2227 * right now just delete is supported for OPTION
2229 * Kind of artificial, But makes it easier to merge into new
2230 * versions of Stock Tk.
2233 WmProtocolCmd (Tcl_Interp
*interp
, char **CmdPtr
, int argc
, char **argv
)
2235 #define Cmd (*CmdPtr)
2240 * return current command
2242 if (!Cmd
|| *Cmd
== '\0') {
2246 * chop off the <blank><window_name>
2247 * and return just the cmd
2249 int x
= strlen(Cmd
) - strlen(argv
[2]) - 1;
2253 /* maybe should just have them put the window in the cmd */
2254 Tcl_AppendResult(interp
, Cmd
, (char *)NULL
);
2257 * tack the blank and window name back on
2270 if (*argv
[4] != '\0') {
2271 int x
= strlen(argv
[4]) + strlen(argv
[2]) + 2;
2272 if (!(Cmd
= ckalloc(x
))) {
2273 perror("wm protocol:");
2275 sprintf(Cmd
, "%s %s", argv
[4], argv
[2]);
2280 Tcl_AppendResult(interp
, "wrong # of arguments: must be \"",
2281 argv
[0], " protocol window <attribute> [cmd]\"", (char *) NULL
);
2290 *----------------------------------------------------------------------
2292 * Tk_CoordsToWindow --
2294 * Given the root coordinates of a point, this procedure
2295 * returns the token for the top-most window covering that point,
2296 * if there exists such a window in this application.
2299 * The return result is either a token for the window corresponding
2300 * to rootX and rootY, or else NULL to indicate that there is no such
2306 *----------------------------------------------------------------------
2312 int rootY
, /* Coordinates of point in root window. */
2313 Tk_Window tkwin
/* Token for any window in application;
2314 * used to identify the application. */
2317 Window rootChild
, dummy3
, dummy4
;
2318 int i
, dummy1
, dummy2
;
2319 register WmInfo
*wmPtr
;
2320 register TkWindow
*winPtr
, *childPtr
;
2321 TkWindow
*nextPtr
; /* Coordinates of highest child found so
2322 * far that contains point. */
2323 int x
, y
; /* Coordinates in winPtr. */
2325 Window
*children
; /* Children of winPtr, or NULL. */
2326 unsigned int numChildren
; /* Size of children array. */
2329 * Step 1: find the top-level window that contains the desired
2333 if (XTranslateCoordinates(Tk_Display(tkwin
),
2334 RootWindowOfScreen(Tk_Screen(tkwin
)),
2335 RootWindowOfScreen(Tk_Screen(tkwin
)), rootX
, rootY
, &dummy1
,
2336 &dummy2
, &rootChild
) == False
) {
2337 panic("Tk_CoordsToWindow get False return from XTranslateCoordinates");
2339 for (wmPtr
= firstWmPtr
; ; wmPtr
= wmPtr
->nextPtr
) {
2340 if (wmPtr
== NULL
) {
2343 if ((wmPtr
->reparent
== rootChild
) || ((wmPtr
->reparent
== None
)
2344 && (wmPtr
->winPtr
->window
== rootChild
))) {
2348 winPtr
= wmPtr
->winPtr
;
2349 if (winPtr
->mainPtr
!= ((TkWindow
*) tkwin
)->mainPtr
) {
2354 * Step 2: work down through the hierarchy underneath this window.
2355 * At each level, scan through all the children to see if any contain
2356 * the point. If none do, then we're done. If one does, then do the
2357 * same thing on that child. If two or more do, then fetch enough
2358 * information from the window server to figure out which is on top,
2359 * and repeat on that child.
2365 x
-= winPtr
->changes
.x
;
2366 y
-= winPtr
->changes
.y
;
2369 for (childPtr
= winPtr
->childList
; childPtr
!= NULL
;
2370 childPtr
= childPtr
->nextPtr
) {
2371 if (!Tk_IsMapped(childPtr
) || (childPtr
->flags
& TK_TOP_LEVEL
)) {
2374 tmpx
= x
- childPtr
->changes
.x
;
2375 tmpy
= y
- childPtr
->changes
.y
;
2376 bd
= childPtr
->changes
.border_width
;
2377 if ((tmpx
< -bd
) || (tmpy
< -bd
)
2378 || (tmpx
>= (childPtr
->changes
.width
+ bd
))
2379 || (tmpy
>= (childPtr
->changes
.height
+ bd
))) {
2382 if (nextPtr
== NULL
) {
2388 * More than one child of same parent overlaps point. Must
2389 * figure out which is on top. Keep a cache of the stacking
2390 * order for winPtr to help with this, in case there are >2
2391 * children overlapping.
2394 if (children
== NULL
) {
2395 if (XQueryTree(winPtr
->display
, winPtr
->window
, &dummy3
,
2396 &dummy4
, &children
, &numChildren
) == 0) {
2397 panic("Tk_CoordsToWindow get error return from XQueryTree");
2400 for (i
= 0; i
< numChildren
; i
++) {
2401 if (children
[i
] == childPtr
->window
) {
2404 if (children
[i
] == nextPtr
->window
) {
2410 if (children
!= NULL
) {
2411 XFree((char *) children
);
2413 if (nextPtr
== NULL
) {
2418 return (Tk_Window
) winPtr
;