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
)) {
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
);
384 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
385 UpdateGeometryInfo((ClientData
) winPtr
);
387 if (wmPtr
->hints
.initial_state
== WithdrawnState
) {
394 *--------------------------------------------------------------
398 * This procedure is invoked when a top-level window is
399 * about to be deleted. It cleans up the wm-related data
400 * structures for the window.
406 * The WmInfo structure for winPtr gets freed up.
408 *--------------------------------------------------------------
412 TkWmDeadWindow(winPtr
)
413 TkWindow
*winPtr
; /* Newly-created top-level window. */
415 register WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
420 if (firstWmPtr
== wmPtr
) {
421 firstWmPtr
= wmPtr
->nextPtr
;
423 register WmInfo
*prevPtr
;
425 for (prevPtr
= firstWmPtr
; ; prevPtr
= prevPtr
->nextPtr
) {
426 if (prevPtr
== NULL
) {
427 panic("couldn't unlink window in TkWmDeadWindow");
429 if (prevPtr
->nextPtr
== wmPtr
) {
430 prevPtr
->nextPtr
= wmPtr
->nextPtr
;
435 if (wmPtr
->hints
.flags
& IconPixmapHint
) {
436 Tk_FreeBitmap(wmPtr
->hints
.icon_pixmap
);
438 if (wmPtr
->hints
.flags
& IconMaskHint
) {
439 Tk_FreeBitmap(wmPtr
->hints
.icon_mask
);
441 if (wmPtr
->flags
& WM_UPDATE_PENDING
) {
442 Tk_CancelIdleCall(UpdateGeometryInfo
, (ClientData
) winPtr
);
444 if (wmPtr
->deleteCmd
) {
445 ckfree(wmPtr
->deleteCmd
);
447 ckfree((char *) wmPtr
);
448 winPtr
->wmInfoPtr
= NULL
;
452 *--------------------------------------------------------------
456 * This procedure is invoked whenever a top-level window's
457 * class is changed. If the window has been mapped then this
458 * procedure updates the window manager property for the
459 * class. If the window hasn't been mapped, the update is
460 * deferred until just before the first mapping.
466 * A window property may get updated.
468 *--------------------------------------------------------------
473 TkWindow
*winPtr
; /* Newly-created top-level window. */
475 if (winPtr
->wmInfoPtr
->flags
& WM_NEVER_MAPPED
) {
480 if (winPtr
->classUid
!= NULL
) {
481 XClassHint
*classPtr
;
483 classPtr
= XAllocClassHint();
484 classPtr
->res_name
= winPtr
->nameUid
;
485 classPtr
->res_class
= winPtr
->classUid
;
486 XSetClassHint(winPtr
->display
, winPtr
->window
, classPtr
);
487 XFree((char *) classPtr
);
493 *----------------------------------------------------------------------
497 * This procedure is invoked to process the "wm" Tcl command.
498 * See the user documentation for details on what it does.
501 * A standard Tcl result.
504 * See the user documentation.
506 *----------------------------------------------------------------------
511 Tk_WmCmd(clientData
, interp
, argc
, argv
)
512 ClientData clientData
; /* Main window associated with
514 Tcl_Interp
*interp
; /* Current interpreter. */
515 int argc
; /* Number of arguments. */
516 char **argv
; /* Argument strings. */
518 Tk_Window tkwin
= (Tk_Window
) clientData
;
520 register WmInfo
*wmPtr
;
525 Tcl_AppendResult(interp
, "wrong # args: should be \"",
526 argv
[0], " option window ?arg ...?\"", (char *) NULL
);
529 winPtr
= (TkWindow
*) Tk_NameToWindow(interp
, argv
[2], tkwin
);
530 if (winPtr
== NULL
) {
533 if (!(winPtr
->flags
& TK_TOP_LEVEL
)) {
534 Tcl_AppendResult(interp
, "window \"", winPtr
->pathName
,
535 "\" isn't a top-level window", (char *) NULL
);
538 wmPtr
= winPtr
->wmInfoPtr
;
540 length
= strlen(argv
[1]);
541 if ((c
== 'a') && (strncmp(argv
[1], "aspect", length
) == 0)) {
542 int numer1
, denom1
, numer2
, denom2
;
544 if ((argc
!= 3) && (argc
!= 7)) {
545 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
546 argv
[0], " aspect window ?minNumer minDenom ",
547 "maxNumer maxDenom?\"", (char *) NULL
);
551 if (wmPtr
->sizeHintsFlags
& PAspect
) {
552 sprintf(interp
->result
, "%d %d %d %d", wmPtr
->minAspect
.x
,
553 wmPtr
->minAspect
.y
, wmPtr
->maxAspect
.x
,
558 if (*argv
[3] == '\0') {
559 wmPtr
->sizeHintsFlags
&= ~PAspect
;
561 if ((Tcl_GetInt(interp
, argv
[3], &numer1
) != TCL_OK
)
562 || (Tcl_GetInt(interp
, argv
[4], &denom1
) != TCL_OK
)
563 || (Tcl_GetInt(interp
, argv
[5], &numer2
) != TCL_OK
)
564 || (Tcl_GetInt(interp
, argv
[6], &denom2
) != TCL_OK
)) {
567 if ((numer1
<= 0) || (denom1
<= 0) || (numer2
<= 0) ||
569 interp
->result
= "aspect number can't be <= 0";
572 wmPtr
->minAspect
.x
= numer1
;
573 wmPtr
->minAspect
.y
= denom1
;
574 wmPtr
->maxAspect
.x
= numer2
;
575 wmPtr
->maxAspect
.y
= denom2
;
576 wmPtr
->sizeHintsFlags
|= PAspect
;
578 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
580 } else if ((c
== 'd') && (strncmp(argv
[1], "deiconify", length
) == 0)) {
582 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
583 argv
[0], " deiconify window\"", (char *) NULL
);
586 wmPtr
->hints
.initial_state
= NormalState
;
587 if (wmPtr
->flags
& WM_NEVER_MAPPED
) {
590 Tk_MapWindow((Tk_Window
) winPtr
);
591 } else if ((c
== 'f') && (strncmp(argv
[1], "focusmodel", length
) == 0)) {
592 if ((argc
!= 3) && (argc
!= 4)) {
593 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
594 argv
[0], " focusmodel window ?active|passive?\"",
599 interp
->result
= wmPtr
->hints
.input
? "passive" : "active";
603 length
= strlen(argv
[3]);
604 if ((c
== 'a') && (strncmp(argv
[3], "active", length
) == 0)) {
605 wmPtr
->hints
.input
= False
;
606 } else if ((c
== 'p') && (strncmp(argv
[3], "passive", length
) == 0)) {
607 wmPtr
->hints
.input
= True
;
609 Tcl_AppendResult(interp
, "bad argument \"", argv
[3],
610 "\": must be active or passive", (char *) NULL
);
614 } else if ((c
== 'f') && (strncmp(argv
[1], "fullscreen", length
) == 0)) {
616 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
617 argv
[0], " fullscreen window on|off\"",
622 length
= strlen(argv
[3]);
623 if (strncmp(argv
[3], "on", length
) == 0) {
624 wmPtr
->flags
&= ~WM_FULL_SCREEN
;
625 } else if (strncmp(argv
[3], "off", length
) == 0) {
626 wmPtr
->flags
|= WM_FULL_SCREEN
;
628 Tcl_AppendResult(interp
, "bad argument \"", argv
[3],
629 "\": must be on or off", (char *) NULL
);
633 static Atom _NET_WM_STATE
;
634 static Atom _NET_WM_STATE_REMOVE
;
635 static Atom _NET_WM_STATE_ADD
;
636 static Atom _NET_WM_STATE_FULLSCREEN
;
638 if (!_NET_WM_STATE
) {
640 Atom
*atom_ptr
[MAX_ATOMS
];
641 char *names
[MAX_ATOMS
];
643 #define atom(a,b) atom_ptr[i] = &a; names[i] = b; i++
644 atom(_NET_WM_STATE
, "_NET_WM_STATE");
645 atom(_NET_WM_STATE_REMOVE
, "_NET_WM_STATE_REMOVE");
646 atom(_NET_WM_STATE_ADD
, "_NET_WM_STATE_ADD");
647 atom(_NET_WM_STATE_FULLSCREEN
, "_NET_WM_STATE_FULLSCREEN");
649 Atom atoms
[MAX_ATOMS
];
650 XInternAtoms(winPtr
->display
, names
, i
, 0, atoms
);
652 *atom_ptr
[i
] = atoms
[i
];
657 e
.xany
.type
= ClientMessage
;
658 e
.xany
.window
= winPtr
->window
;
659 e
.xclient
.message_type
= _NET_WM_STATE
;
660 e
.xclient
.format
= 32;
661 e
.xclient
.data
.l
[0] =
662 (wmPtr
->flags
& WM_FULL_SCREEN
)
664 : _NET_WM_STATE_REMOVE
;
665 e
.xclient
.data
.l
[1] = (long)_NET_WM_STATE_FULLSCREEN
;
666 e
.xclient
.data
.l
[2] = (long)0;
667 e
.xclient
.data
.l
[3] = (long)0;
668 e
.xclient
.data
.l
[4] = (long)0;
669 XSendEvent(winPtr
->display
, RootWindow(winPtr
->display
, winPtr
->screenNum
), 0,
670 SubstructureNotifyMask
|SubstructureRedirectMask
, &e
);
672 } else if ((c
== 'g') && (strncmp(argv
[1], "geometry", length
) == 0)
677 if ((argc
!= 3) && (argc
!= 4)) {
678 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
679 argv
[0], " geometry window ?newGeometry?\"",
684 xSign
= (wmPtr
->flags
& WM_NEGATIVE_X
) ? '-' : '+';
685 ySign
= (wmPtr
->flags
& WM_NEGATIVE_Y
) ? '-' : '+';
686 if (wmPtr
->width
!= -1) {
687 width
= wmPtr
->width
;
688 height
= wmPtr
->height
;
689 } else if (IS_GRIDDED(wmPtr
)) {
690 width
= wmPtr
->reqGridWidth
;
691 height
= wmPtr
->reqGridHeight
;
693 width
= winPtr
->reqWidth
;
694 height
= winPtr
->reqHeight
;
696 sprintf(interp
->result
, "%dx%d%c%d%c%d", width
, height
,
697 xSign
, wmPtr
->x
, ySign
, wmPtr
->y
);
700 if (*argv
[3] == '\0') {
705 return ParseGeometry(interp
, argv
[3], winPtr
);
706 } else if ((c
== 'g') && (strncmp(argv
[1], "grid", length
) == 0)
708 int reqWidth
, reqHeight
, widthInc
, heightInc
;
710 if ((argc
!= 3) && (argc
!= 7)) {
711 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
712 argv
[0], " reqsize window ?baseWidth baseHeight ",
713 "widthInc heightInc?\"", (char *) NULL
);
717 if (wmPtr
->sizeHintsFlags
& PBaseSize
) {
718 sprintf(interp
->result
, "%d %d %d %d", wmPtr
->reqGridWidth
,
719 wmPtr
->reqGridHeight
, wmPtr
->widthInc
,
724 if (*argv
[3] == '\0') {
726 * Turn off gridding and reset the width and height
727 * to make sense as ungridded numbers.
730 wmPtr
->sizeHintsFlags
&= ~(PBaseSize
|PResizeInc
);
732 wmPtr
->heightInc
= 1;
733 if (wmPtr
->width
!= -1) {
734 wmPtr
->width
= winPtr
->reqWidth
+ (wmPtr
->width
735 - wmPtr
->reqGridWidth
)*wmPtr
->widthInc
;
736 wmPtr
->height
= winPtr
->reqHeight
+ (wmPtr
->height
737 - wmPtr
->reqGridHeight
)*wmPtr
->heightInc
;
740 if ((Tcl_GetInt(interp
, argv
[3], &reqWidth
) != TCL_OK
)
741 || (Tcl_GetInt(interp
, argv
[4], &reqHeight
) != TCL_OK
)
742 || (Tcl_GetInt(interp
, argv
[5], &widthInc
) != TCL_OK
)
743 || (Tcl_GetInt(interp
, argv
[6], &heightInc
) != TCL_OK
)) {
747 interp
->result
= "baseWidth can't be < 0";
751 interp
->result
= "baseHeight can't be < 0";
755 interp
->result
= "widthInc can't be < 0";
759 interp
->result
= "heightInc can't be < 0";
762 Tk_SetGrid((Tk_Window
) tkwin
, reqWidth
, reqHeight
, widthInc
,
765 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
767 } else if ((c
== 'g') && (strncmp(argv
[1], "group", length
) == 0)
771 if ((argc
!= 3) && (argc
!= 4)) {
772 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
773 argv
[0], " group window ?pathName?\"",
778 if (wmPtr
->hints
.flags
& WindowGroupHint
) {
779 interp
->result
= wmPtr
->leaderName
;
783 if (*argv
[3] == '\0') {
784 wmPtr
->hints
.flags
&= ~WindowGroupHint
;
785 wmPtr
->leaderName
= NULL
;
787 tkwin2
= Tk_NameToWindow(interp
, argv
[3], tkwin
);
788 if (tkwin2
== NULL
) {
791 Tk_MakeWindowExist(tkwin2
);
792 wmPtr
->hints
.window_group
= Tk_WindowId(tkwin2
);
793 wmPtr
->hints
.flags
|= WindowGroupHint
;
794 wmPtr
->leaderName
= Tk_PathName(tkwin2
);
797 } else if ((c
== 'i') && (strncmp(argv
[1], "iconbitmap", length
) == 0)
801 if ((argc
!= 3) && (argc
!= 4)) {
802 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
803 argv
[0], " iconbitmap window ?bitmap?\"",
808 if (wmPtr
->hints
.flags
& IconPixmapHint
) {
809 interp
->result
= Tk_NameOfBitmap(wmPtr
->hints
.icon_pixmap
);
813 if (*argv
[3] == '\0') {
814 if (wmPtr
->hints
.icon_pixmap
!= None
) {
815 Tk_FreeBitmap(wmPtr
->hints
.icon_pixmap
);
817 wmPtr
->hints
.flags
&= ~IconPixmapHint
;
819 pixmap
= Tk_GetBitmap(interp
, tkwin
, Tk_GetUid(argv
[3]));
820 if (pixmap
== None
) {
823 wmPtr
->hints
.icon_pixmap
= pixmap
;
824 wmPtr
->hints
.flags
|= IconPixmapHint
;
827 } else if ((c
== 'i') && (strncmp(argv
[1], "iconify", length
) == 0)
830 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
831 argv
[0], " iconify window\"", (char *) NULL
);
834 wmPtr
->hints
.initial_state
= IconicState
;
835 if (wmPtr
->flags
& WM_NEVER_MAPPED
) {
839 if (XIconifyWindow(winPtr
->display
, winPtr
->window
,
840 winPtr
->screenNum
) == 0) {
842 "couldn't send iconify message to window manager";
846 interp
->result
= "can't iconify under X11R3";
849 } else if ((c
== 'i') && (strncmp(argv
[1], "iconmask", length
) == 0)
853 if ((argc
!= 3) && (argc
!= 4)) {
854 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
855 argv
[0], " iconmask window ?bitmap?\"",
860 if (wmPtr
->hints
.flags
& IconMaskHint
) {
861 interp
->result
= Tk_NameOfBitmap(wmPtr
->hints
.icon_mask
);
865 if (*argv
[3] == '\0') {
866 if (wmPtr
->hints
.icon_mask
!= None
) {
867 Tk_FreeBitmap(wmPtr
->hints
.icon_mask
);
869 wmPtr
->hints
.flags
&= ~IconMaskHint
;
871 pixmap
= Tk_GetBitmap(interp
, tkwin
, Tk_GetUid(argv
[3]));
872 if (pixmap
== None
) {
875 wmPtr
->hints
.icon_mask
= pixmap
;
876 wmPtr
->hints
.flags
|= IconMaskHint
;
879 } else if ((c
== 'i') && (strncmp(argv
[1], "iconname", length
) == 0)
882 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
883 argv
[0], " iconname window ?newName?\"", (char *) NULL
);
887 interp
->result
= (wmPtr
->iconName
!= NULL
) ? wmPtr
->iconName
: "";
890 wmPtr
->iconName
= Tk_GetUid(argv
[3]);
891 if (!(wmPtr
->flags
& WM_NEVER_MAPPED
)) {
892 XSetIconName(winPtr
->display
, winPtr
->window
, wmPtr
->iconName
);
895 } else if ((c
== 'i') && (strncmp(argv
[1], "iconposition", length
) == 0)
899 if ((argc
!= 3) && (argc
!= 5)) {
900 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
901 argv
[0], " iconposition window ?x y?\"",
906 if (wmPtr
->hints
.flags
& IconPositionHint
) {
907 sprintf(interp
->result
, "%d %d", wmPtr
->hints
.icon_x
,
908 wmPtr
->hints
.icon_y
);
912 if (*argv
[3] == '\0') {
913 wmPtr
->hints
.flags
&= ~IconPositionHint
;
915 if ((Tcl_GetInt(interp
, argv
[3], &x
) != TCL_OK
)
916 || (Tcl_GetInt(interp
, argv
[4], &y
) != TCL_OK
)){
919 wmPtr
->hints
.icon_x
= x
;
920 wmPtr
->hints
.icon_y
= y
;
921 wmPtr
->hints
.flags
|= IconPositionHint
;
924 } else if ((c
== 'i') && (strncmp(argv
[1], "iconwindow", length
) == 0)
928 if ((argc
!= 3) && (argc
!= 4)) {
929 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
930 argv
[0], " iconwindow window ?pathName?\"",
935 if (wmPtr
->hints
.flags
& IconWindowHint
) {
936 interp
->result
= wmPtr
->iconWindowName
;
940 if (*argv
[3] == '\0') {
941 wmPtr
->hints
.flags
&= ~IconWindowHint
;
942 wmPtr
->iconWindowName
= NULL
;
944 tkwin2
= Tk_NameToWindow(interp
, argv
[3], tkwin
);
945 if (tkwin2
== NULL
) {
948 Tk_MakeWindowExist(tkwin2
);
949 wmPtr
->hints
.icon_window
= Tk_WindowId(tkwin2
);
950 wmPtr
->hints
.flags
|= IconWindowHint
;
951 wmPtr
->iconWindowName
= Tk_PathName(tkwin2
);
954 } else if ((c
== 'm') && (strncmp(argv
[1], "maxsize", length
) == 0)
957 if ((argc
!= 3) && (argc
!= 5)) {
958 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
959 argv
[0], " maxsize window ?width height?\"", (char *) NULL
);
963 if (wmPtr
->sizeHintsFlags
& PMaxSize
) {
964 sprintf(interp
->result
, "%d %d", wmPtr
->maxWidth
,
969 if (*argv
[3] == '\0') {
970 wmPtr
->sizeHintsFlags
&= ~PMaxSize
;
972 if ((Tcl_GetInt(interp
, argv
[3], &width
) != TCL_OK
)
973 || (Tcl_GetInt(interp
, argv
[4], &height
) != TCL_OK
)) {
976 wmPtr
->maxWidth
= width
;
977 wmPtr
->maxHeight
= height
;
978 wmPtr
->sizeHintsFlags
|= PMaxSize
;
980 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
982 } else if ((c
== 'm') && (strncmp(argv
[1], "minsize", length
) == 0)
985 if ((argc
!= 3) && (argc
!= 5)) {
986 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
987 argv
[0], " minsize window ?width height?\"", (char *) NULL
);
991 if (wmPtr
->sizeHintsFlags
& PMinSize
) {
992 sprintf(interp
->result
, "%d %d", wmPtr
->minWidth
,
997 if (*argv
[3] == '\0') {
998 wmPtr
->sizeHintsFlags
&= ~PMinSize
;
1000 if ((Tcl_GetInt(interp
, argv
[3], &width
) != TCL_OK
)
1001 || (Tcl_GetInt(interp
, argv
[4], &height
) != TCL_OK
)) {
1004 wmPtr
->minWidth
= width
;
1005 wmPtr
->minHeight
= height
;
1006 wmPtr
->sizeHintsFlags
|= PMinSize
;
1008 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1010 } else if ((c
== 'p') && (strncmp(argv
[1], "positionfrom", length
) == 0)) {
1011 if ((argc
!= 3) && (argc
!= 4)) {
1012 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1013 argv
[0], " positionfrom window ?user/program?\"",
1018 if (wmPtr
->sizeHintsFlags
& USPosition
) {
1019 interp
->result
= "user";
1020 } else if (wmPtr
->sizeHintsFlags
& PPosition
) {
1021 interp
->result
= "program";
1025 if (*argv
[3] == '\0') {
1026 wmPtr
->sizeHintsFlags
&= ~(USPosition
|PPosition
);
1029 length
= strlen(argv
[3]);
1030 if ((c
== 'u') && (strncmp(argv
[3], "user", length
) == 0)) {
1031 wmPtr
->sizeHintsFlags
&= ~PPosition
;
1032 wmPtr
->sizeHintsFlags
|= USPosition
;
1033 } else if ((c
== 'p') && (strncmp(argv
[3], "program", length
) == 0)) {
1034 wmPtr
->sizeHintsFlags
&= ~USPosition
;
1035 wmPtr
->sizeHintsFlags
|= PPosition
;
1037 Tcl_AppendResult(interp
, "bad argument \"", argv
[3],
1038 "\": must be program or user", (char *) NULL
);
1042 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1044 } else if ((c
== 'r') && (strncmp(argv
[1], "raise", length
) == 0)) {
1046 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1047 argv
[0], " raise window\"", (char *) NULL
);
1050 Tk_MakeWindowExist((Tk_Window
) winPtr
);
1051 XRaiseWindow(Tk_Display(winPtr
), Tk_WindowId(winPtr
));
1052 } else if ((c
== 's') && (strncmp(argv
[1], "sizefrom", length
) == 0)) {
1053 if ((argc
!= 3) && (argc
!= 4)) {
1054 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1055 argv
[0], " sizefrom window ?user|program?\"",
1060 if (wmPtr
->sizeHintsFlags
& USSize
) {
1061 interp
->result
= "user";
1062 } else if (wmPtr
->sizeHintsFlags
& PSize
) {
1063 interp
->result
= "program";
1067 if (*argv
[3] == '\0') {
1068 wmPtr
->sizeHintsFlags
&= ~(USSize
|PSize
);
1071 length
= strlen(argv
[3]);
1072 if ((c
== 'u') && (strncmp(argv
[3], "user", length
) == 0)) {
1073 wmPtr
->sizeHintsFlags
&= ~PSize
;
1074 wmPtr
->sizeHintsFlags
|= USSize
;
1075 } else if ((c
== 'p')
1076 && (strncmp(argv
[3], "program", length
) == 0)) {
1077 wmPtr
->sizeHintsFlags
&= ~USSize
;
1078 wmPtr
->sizeHintsFlags
|= PSize
;
1080 Tcl_AppendResult(interp
, "bad argument \"", argv
[3],
1081 "\": must be program or user", (char *) NULL
);
1085 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1087 } else if ((c
== 't') && (strncmp(argv
[1], "title", length
) == 0)
1090 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1091 argv
[0], " title window ?newTitle?\"", (char *) NULL
);
1095 interp
->result
= (wmPtr
->titleUid
!= NULL
) ? wmPtr
->titleUid
1099 wmPtr
->titleUid
= Tk_GetUid(argv
[3]);
1101 if (!(wmPtr
->flags
& WM_NEVER_MAPPED
)) {
1102 XTextProperty textProp
;
1104 if (XStringListToTextProperty(&wmPtr
->titleUid
, 1,
1106 XSetWMName(winPtr
->display
, winPtr
->window
, &textProp
);
1107 XFree((char *) textProp
.value
);
1113 } else if ((c
== 't') && (strncmp(argv
[1], "transient", length
) == 0)
1117 if ((argc
!= 3) && (argc
!= 4)) {
1118 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1119 argv
[0], " transient window ?master?\"", (char *) NULL
);
1123 if (wmPtr
->master
!= None
) {
1124 interp
->result
= wmPtr
->masterWindowName
;
1128 if (argv
[3][0] == '\0') {
1129 wmPtr
->master
= None
;
1130 wmPtr
->masterWindowName
= NULL
;
1132 master
= Tk_NameToWindow(interp
, argv
[3], tkwin
);
1133 if (master
== NULL
) {
1136 Tk_MakeWindowExist(master
);
1137 wmPtr
->master
= Tk_WindowId(master
);
1138 wmPtr
->masterWindowName
= Tk_PathName(master
);
1140 if (!(wmPtr
->flags
& WM_NEVER_MAPPED
)) {
1141 XSetTransientForHint(winPtr
->display
, winPtr
->window
,
1144 } else if ((c
== 'w') && (strncmp(argv
[1], "withdraw", length
) == 0)) {
1146 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1147 argv
[0], " withdraw window\"", (char *) NULL
);
1150 wmPtr
->hints
.initial_state
= WithdrawnState
;
1151 if (wmPtr
->flags
& WM_NEVER_MAPPED
) {
1154 if (XWithdrawWindow(winPtr
->display
, winPtr
->window
,
1155 winPtr
->screenNum
) == 0) {
1157 "couldn't send withdraw message to window manager";
1160 winPtr
->flags
&= ~TK_MAPPED
;
1161 } else if ((c
== 'p') && (strncmp(argv
[1], "protocol", length
) == 0)) {
1163 * handle various ICCCM WM_PROTOCOL attributes
1166 Tcl_AppendResult(interp
, "wrong # arguments: must be \"",
1167 argv
[0], " protocol window type..\"", (char *) NULL
);
1170 if (!strcmp(argv
[3], "delete")) {
1171 return WmProtocolCmd(interp
, &(wmPtr
->deleteCmd
), argc
, argv
);
1173 Tcl_AppendResult(interp
, argv
[0],
1174 ": bad argument ", argv
[3], " must be: ",
1175 "delete", (char *) NULL
);
1180 Tcl_AppendResult(interp
, "unknown or ambiguous option \"", argv
[1],
1181 "\": must be aspect, deiconify, focusmodel, ",
1182 "fullscreen, geometry, grid, group, iconbitmap, ",
1183 "iconify, iconmask, iconname, iconposition, ",
1184 "iconwindow, maxsize, minsize, positionfrom, raise, ",
1185 "sizefrom, title, transient, withdraw, or protocol",
1192 if (!(wmPtr
->flags
& (WM_UPDATE_PENDING
|WM_NEVER_MAPPED
))) {
1193 Tk_DoWhenIdle(UpdateGeometryInfo
, (ClientData
) winPtr
);
1194 wmPtr
->flags
|= WM_UPDATE_PENDING
;
1200 *----------------------------------------------------------------------
1204 * This procedure is invoked by a widget when it wishes to set a grid
1205 * coordinate system that controls the size of a top-level window.
1206 * It provides a C interface equivalent to the "wm grid" command and
1207 * is usually asscoiated with the -setgrid option.
1213 * Grid-related information will be passed to the window manager, so
1214 * that the top-level window associated with tkwin will resize on
1217 *----------------------------------------------------------------------
1221 Tk_SetGrid(tkwin
, reqWidth
, reqHeight
, widthInc
, heightInc
)
1222 Tk_Window tkwin
; /* Token for window. New window mgr info
1223 * will be posted for the top-level window
1224 * associated with this window. */
1225 int reqWidth
; /* Width (in grid units) corresponding to
1226 * the requested geometry for tkwin. */
1227 int reqHeight
; /* Height (in grid units) corresponding to
1228 * the requested geometry for tkwin. */
1229 int widthInc
, heightInc
; /* Pixel increments corresponding to a
1230 * change of one grid unit. */
1232 TkWindow
*winPtr
= (TkWindow
*) tkwin
;
1233 register WmInfo
*wmPtr
;
1236 * Find the top-level window for tkwin, plus the window manager
1240 while (!(winPtr
->flags
& TK_TOP_LEVEL
)) {
1241 winPtr
= winPtr
->parentPtr
;
1243 wmPtr
= winPtr
->wmInfoPtr
;
1245 if ((wmPtr
->reqGridWidth
== reqWidth
)
1246 && (wmPtr
->reqGridHeight
!= reqHeight
)
1247 && (wmPtr
->widthInc
!= widthInc
)
1248 && (wmPtr
->heightInc
!= heightInc
)
1249 && ((wmPtr
->sizeHintsFlags
& (PBaseSize
|PResizeInc
))
1250 == PBaseSize
|PResizeInc
)) {
1255 * If gridding was previously off, then forget about any window
1256 * size requests made by the user or via "wm geometry": these are
1257 * in pixel units and there's no easy way to translate them to
1258 * grid units since the new requested size of the top-level window in
1259 * pixels may not yet have been registered yet (it may filter up
1260 * the hierarchy in DoWhenIdle handlers).
1263 if (!(wmPtr
->sizeHintsFlags
& PBaseSize
)) {
1269 * Set the new gridding information, and start the process of passing
1270 * all of this information to the window manager.
1273 wmPtr
->reqGridWidth
= reqWidth
;
1274 wmPtr
->reqGridHeight
= reqHeight
;
1275 wmPtr
->widthInc
= widthInc
;
1276 wmPtr
->heightInc
= heightInc
;
1277 wmPtr
->sizeHintsFlags
|= PBaseSize
|PResizeInc
;
1278 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1279 if (!(wmPtr
->flags
& (WM_UPDATE_PENDING
|WM_NEVER_MAPPED
))) {
1280 Tk_DoWhenIdle(UpdateGeometryInfo
, (ClientData
) winPtr
);
1281 wmPtr
->flags
|= WM_UPDATE_PENDING
;
1286 *----------------------------------------------------------------------
1288 * TopLevelEventProc --
1290 * This procedure is invoked when a top-level (or other externally-
1291 * managed window) is restructured in any way.
1297 * Tk's internal data structures for the window get modified to
1298 * reflect the structural change.
1300 *----------------------------------------------------------------------
1304 TopLevelEventProc(clientData
, eventPtr
)
1305 ClientData clientData
; /* Window for which event occurred. */
1306 XEvent
*eventPtr
; /* Event that just happened. */
1308 register TkWindow
*winPtr
= (TkWindow
*) clientData
;
1310 if (eventPtr
->type
== DestroyNotify
) {
1311 if (!(winPtr
->flags
& TK_ALREADY_DEAD
)) {
1312 Tk_DestroyWindow((Tk_Window
) winPtr
);
1314 } else if (eventPtr
->type
== ConfigureNotify
) {
1315 register WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1319 * A top-level window has been reconfigured. Problem #1:
1320 * discard stale information. If the application has recently
1321 * tried to reconfigure itself, ignore all events until the
1322 * response to that reconfiguration arrives (the response is
1323 * assumed to be the first ConfigureNotify that arrives after
1324 * the server has seen the request; this suffers from potential
1325 * races with user actions, but it's the best I can think of
1329 diff
= eventPtr
->xconfigure
.serial
- wmPtr
->configRequest
;
1335 * Problem #2: reparenting window managers. If the window
1336 * manager reparents a top-level window then the x and y
1337 * information that comes in events for the window is wrong:
1338 * it gives the location of the window inside its decorative
1339 * parent, rather than the location of the window in root
1340 * coordinates, which is what we want. Window managers
1341 * are supposed to send synthetic events with the correct
1342 * information, but ICCCM doesn't require them to do this
1343 * under all conditions, and the information provided doesn't
1344 * include everything we need here. So, the code below
1345 * maintains a bunch of information about the parent window.
1346 * If the window hasn't been reparented, we pretend that
1347 * there is a parent shrink-wrapped around the window.
1350 if (wmPtr
->reparent
== None
) {
1352 winPtr
->changes
.x
= eventPtr
->xconfigure
.x
;
1353 winPtr
->changes
.y
= eventPtr
->xconfigure
.y
;
1354 wmPtr
->parentWidth
= eventPtr
->xconfigure
.width
1355 + 2*eventPtr
->xconfigure
.border_width
;
1356 wmPtr
->parentHeight
= eventPtr
->xconfigure
.height
1357 + 2*eventPtr
->xconfigure
.border_width
;
1359 unsigned int width
, height
, bd
, dummy
;
1362 Tk_ErrorHandler handler
;
1364 handler
= Tk_CreateErrorHandler(winPtr
->display
, BadDrawable
, -1,
1365 -1, (Tk_ErrorProc
*) NULL
, (ClientData
) NULL
);
1366 status
= XGetGeometry(winPtr
->display
, wmPtr
->reparent
,
1367 &dummy2
, &x
, &y
, &width
, &height
, &bd
, &dummy
);
1368 Tk_DeleteErrorHandler(handler
);
1371 * It appears that the reparented parent went away and
1372 * no-one told us. Reset the window to indicate that
1373 * it's not reparented, then handle it as a non-reparented
1376 wmPtr
->reparent
= None
;
1377 wmPtr
->flags
&= ~WM_NESTED_REPARENT
;
1378 wmPtr
->xInParent
= wmPtr
->yInParent
= 0;
1381 wmPtr
->parentWidth
= width
+ 2*bd
;
1382 wmPtr
->parentHeight
= height
+ 2*bd
;
1383 winPtr
->changes
.x
= x
;
1384 winPtr
->changes
.y
= y
;
1385 if (wmPtr
->flags
& WM_NESTED_REPARENT
) {
1386 int xOffset
, yOffset
;
1388 (void) XTranslateCoordinates(winPtr
->display
, winPtr
->window
,
1389 wmPtr
->reparent
, 0, 0, &xOffset
, &yOffset
, &dummy2
);
1390 wmPtr
->xInParent
= xOffset
+ bd
- winPtr
->changes
.border_width
;
1391 wmPtr
->yInParent
= yOffset
+ bd
- winPtr
->changes
.border_width
;
1393 if (!eventPtr
->xconfigure
.send_event
) {
1394 wmPtr
->xInParent
= eventPtr
->xconfigure
.x
+ bd
;
1395 wmPtr
->yInParent
= eventPtr
->xconfigure
.y
+ bd
;
1398 winPtr
->changes
.x
= x
+ wmPtr
->xInParent
;
1399 winPtr
->changes
.y
= y
+ wmPtr
->yInParent
;
1403 * Problem #3: if the window size or location was changed
1404 * externally, update the geometry information in wmPtr to make
1405 * it look just as if the user had typed a "wm geometry" command
1406 * to make the change. There are many tricky situations to deal
1408 * (a) the event is simply a reflection of an internal geometry
1409 * request from the window's widgets (must leave width and
1410 * height alone in this case).
1411 * (b) the window manager might respond to a size request from
1412 * us with a different size than requested (e.g. it might
1413 * have a minimum allowable window size). Because of this,
1414 * can't just compare new size with requested size to determine
1415 * whether this event is a reflection of an internal request
1416 * from within the application. Use WM_CONFIG_PENDING flag
1418 * (c) ConfigureNotify events also arise if the window has been
1419 * moved, even if its size hasn't changed. Must distinguish
1420 * between the user moving the window and the user resizing
1424 if (wmPtr
->flags
& WM_CONFIG_PENDING
) {
1427 * Size change is just a reflection of something coming from
1431 diff
= eventPtr
->xconfigure
.serial
- wmPtr
->configRequest
;
1433 if (wmPtr
->flags
& WM_CONFIG_AGAIN
) {
1434 if (!(wmPtr
->flags
& WM_UPDATE_PENDING
)) {
1435 Tk_DoWhenIdle(UpdateGeometryInfo
, (ClientData
) winPtr
);
1436 wmPtr
->flags
|= WM_UPDATE_PENDING
;
1439 wmPtr
->flags
&= ~(WM_CONFIG_PENDING
|WM_CONFIG_AGAIN
);
1441 } else if ((winPtr
->changes
.width
!= eventPtr
->xconfigure
.width
)
1442 || (winPtr
->changes
.height
!= eventPtr
->xconfigure
.height
)) {
1443 wmPtr
->configWidth
= -1;
1444 wmPtr
->configHeight
= -1;
1445 if (IS_GRIDDED(wmPtr
)) {
1446 wmPtr
->width
= wmPtr
->reqGridWidth
1447 + (eventPtr
->xconfigure
.width
1448 - winPtr
->reqWidth
)/wmPtr
->widthInc
;
1449 if (wmPtr
->width
< 0) {
1452 wmPtr
->height
= wmPtr
->reqGridHeight
1453 + (eventPtr
->xconfigure
.height
1454 - winPtr
->reqHeight
)/wmPtr
->heightInc
;
1455 if (wmPtr
->height
< 0) {
1458 } else if ((eventPtr
->xconfigure
.width
!= winPtr
->changes
.width
)
1459 || (eventPtr
->xconfigure
.height
1460 != winPtr
->changes
.height
)) {
1462 * The check above is needed so we don't think the user
1463 * requested a new size when all he/she did was to move
1467 wmPtr
->width
= eventPtr
->xconfigure
.width
;
1468 wmPtr
->height
= eventPtr
->xconfigure
.height
;
1472 winPtr
->changes
.width
= eventPtr
->xconfigure
.width
;
1473 winPtr
->changes
.height
= eventPtr
->xconfigure
.height
;
1474 winPtr
->changes
.border_width
= eventPtr
->xconfigure
.border_width
;
1475 winPtr
->changes
.sibling
= eventPtr
->xconfigure
.above
;
1476 winPtr
->changes
.stack_mode
= Above
;
1478 x
= winPtr
->changes
.x
- wmPtr
->xInParent
;
1479 if (wmPtr
->flags
& WM_NEGATIVE_X
) {
1480 x
= DisplayWidth(winPtr
->display
, winPtr
->screenNum
)
1481 - (x
+ wmPtr
->parentWidth
);
1483 y
= winPtr
->changes
.y
- wmPtr
->yInParent
;
1484 if (wmPtr
->flags
& WM_NEGATIVE_Y
) {
1485 y
= DisplayHeight(winPtr
->display
, winPtr
->screenNum
)
1486 - (y
+ wmPtr
->parentHeight
);
1488 if ((x
!= wmPtr
->x
) || (y
!= wmPtr
->y
)) {
1492 } else if (eventPtr
->type
== MapNotify
) {
1493 winPtr
->flags
|= TK_MAPPED
;
1494 } else if (eventPtr
->type
== UnmapNotify
) {
1495 winPtr
->flags
&= ~TK_MAPPED
;
1496 } else if (eventPtr
->type
== ReparentNotify
) {
1497 WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1498 Window root
, *children
, dummy2
, *virtualRootPtr
;
1499 Atom virtualRootAtom
, actualType
;
1501 unsigned long numItems
, bytesAfter
;
1505 * Locate the ancestor of this window that is just below the
1506 * root window for the screen (could be the window itself).
1507 * This code is a bit tricky because it allows for the
1508 * possibility of a virtual root window, which is identified
1509 * with a property named __SWM_VROOT.
1512 virtualRootAtom
= Tk_InternAtom((Tk_Window
) winPtr
, "__SWM_VROOT");
1513 wmPtr
->flags
&= ~WM_NESTED_REPARENT
;
1514 wmPtr
->reparent
= None
;
1515 root
= eventPtr
->xreparent
.parent
;
1516 while (root
!= RootWindow(winPtr
->display
, winPtr
->screenNum
)) {
1517 Tk_ErrorHandler handler1
, handler2
;
1520 virtualRootPtr
= NULL
;
1523 Tk_CreateErrorHandler(winPtr
->display
, BadDrawable
,
1524 -1, -1, (Tk_ErrorProc
*) NULL
,
1527 Tk_CreateErrorHandler(winPtr
->display
, BadWindow
,
1528 -1, -1, (Tk_ErrorProc
*) NULL
,
1531 status
= XGetWindowProperty(winPtr
->display
, root
,
1533 0, (long) 1, False
, XA_WINDOW
,
1534 &actualType
, &actualFormat
,
1535 &numItems
, &bytesAfter
,
1536 (unsigned char **) &virtualRootPtr
);
1538 Tk_DeleteErrorHandler(handler1
);
1539 Tk_DeleteErrorHandler(handler2
);
1541 if (status
== Success
) {
1542 if (virtualRootPtr
!= NULL
) {
1543 if (*virtualRootPtr
!= root
) {
1544 panic("TopLevelEventProc confused over virtual root");
1546 XFree((char *) virtualRootPtr
);
1550 wmPtr
->reparent
= root
;
1551 (void) XQueryTree(winPtr
->display
, root
, &dummy2
, &root
,
1553 XFree((char *) children
);
1557 * The ancestor just below the (virtual) root is in wmPtr->reparent
1558 * now, and the (virtual) root is in root.
1562 if (eventPtr
->xreparent
.parent
== root
) {
1563 wmPtr
->reparent
= None
;
1564 wmPtr
->flags
&= ~WM_NESTED_REPARENT
;
1565 wmPtr
->parentWidth
= winPtr
->changes
.width
1566 + 2*winPtr
->changes
.border_width
;
1567 wmPtr
->parentHeight
= winPtr
->changes
.height
1568 + 2*winPtr
->changes
.border_width
;
1569 wmPtr
->xInParent
= wmPtr
->yInParent
= 0;
1570 winPtr
->changes
.x
= eventPtr
->xreparent
.x
;
1571 winPtr
->changes
.y
= eventPtr
->xreparent
.y
;
1573 int x
, y
, xOffset
, yOffset
;
1574 unsigned int width
, height
, bd
;
1576 if (wmPtr
->reparent
!= eventPtr
->xreparent
.parent
) {
1577 wmPtr
->flags
|= WM_NESTED_REPARENT
;
1579 wmPtr
->flags
&= ~WM_NESTED_REPARENT
;
1583 * Compute and save information about reparent and about
1584 * the window's position in reparent.
1587 (void) XGetGeometry(winPtr
->display
, wmPtr
->reparent
,
1588 &dummy2
, &x
, &y
, &width
, &height
, &bd
, &dummy
);
1589 wmPtr
->parentWidth
= width
+ 2*bd
;
1590 wmPtr
->parentHeight
= height
+ 2*bd
;
1591 (void) XTranslateCoordinates(winPtr
->display
, winPtr
->window
,
1592 wmPtr
->reparent
, 0, 0, &xOffset
, &yOffset
, &dummy2
);
1593 wmPtr
->xInParent
= xOffset
+ bd
- winPtr
->changes
.border_width
;
1594 wmPtr
->yInParent
= yOffset
+ bd
- winPtr
->changes
.border_width
;
1595 winPtr
->changes
.x
= x
+ xOffset
;
1596 winPtr
->changes
.y
= y
+ yOffset
;
1598 } else if ((eventPtr
->type
== EnterNotify
)
1599 || (eventPtr
->type
== LeaveNotify
)) {
1600 TkFocusEventProc(winPtr
, eventPtr
);
1605 *----------------------------------------------------------------------
1607 * TopLevelReqProc --
1609 * This procedure is invoked by the geometry manager whenever
1610 * the requested size for a top-level window is changed.
1616 * Arrange for the window to be resized to satisfy the request
1617 * (this happens as a when-idle action).
1619 *----------------------------------------------------------------------
1624 TopLevelReqProc(dummy
, tkwin
)
1625 ClientData dummy
; /* Not used. */
1626 Tk_Window tkwin
; /* Information about window. */
1628 TkWindow
*winPtr
= (TkWindow
*) tkwin
;
1631 wmPtr
= winPtr
->wmInfoPtr
;
1632 if ((wmPtr
->prevReqWidth
== winPtr
->reqWidth
)
1633 && (wmPtr
->prevReqHeight
== winPtr
->reqHeight
)) {
1636 wmPtr
->prevReqWidth
= winPtr
->reqWidth
;
1637 wmPtr
->prevReqHeight
= winPtr
->reqHeight
;
1638 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1639 if (!(wmPtr
->flags
& (WM_UPDATE_PENDING
|WM_NEVER_MAPPED
))) {
1640 Tk_DoWhenIdle(UpdateGeometryInfo
, (ClientData
) winPtr
);
1641 wmPtr
->flags
|= WM_UPDATE_PENDING
;
1646 *----------------------------------------------------------------------
1648 * UpdateGeometryInfo --
1650 * This procedure is invoked when a top-level window is first
1651 * mapped, and also as a when-idle procedure, to bring the
1652 * geometry and/or position of a top-level window back into
1653 * line with what has been requested by the user and/or widgets.
1659 * The window's size and location may change, unless the WM prevents
1660 * that from happening.
1662 *----------------------------------------------------------------------
1666 UpdateGeometryInfo(clientData
)
1667 ClientData clientData
; /* Pointer to the window's record. */
1669 register TkWindow
*winPtr
= (TkWindow
*) clientData
;
1670 register WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1671 int x
, y
, width
, height
;
1674 * It isn't safe to issue a new reconfigure request while there is
1675 * another reconfigure request outstanding. If this happens, skip
1676 * the second reconfigure operation but set a flag so it will get
1677 * done with the first one finishes.
1680 wmPtr
->flags
&= ~WM_UPDATE_PENDING
;
1681 if (wmPtr
->flags
& WM_CONFIG_PENDING
) {
1682 wmPtr
->flags
|= WM_CONFIG_AGAIN
;
1687 * Compute the new size for the top-level window. See the
1688 * user documentation for details on this, but the size
1689 * requested depends on (a) the size requested internally
1690 * by the window's widgets, (b) the size requested by the
1691 * user in a "wm geometry" command or via wm-based interactive
1692 * resizing (if any), and (c) whether or not the window
1693 * gridded. Don't permit sizes <= 0 because this upsets
1697 if (wmPtr
->width
== -1) {
1698 width
= winPtr
->reqWidth
;
1699 height
= winPtr
->reqHeight
;
1700 } else if (IS_GRIDDED(wmPtr
)) {
1701 width
= winPtr
->reqWidth
1702 + (wmPtr
->width
- wmPtr
->reqGridWidth
)*wmPtr
->widthInc
;
1703 height
= winPtr
->reqHeight
1704 + (wmPtr
->height
- wmPtr
->reqGridHeight
)*wmPtr
->heightInc
;
1706 width
= wmPtr
->width
;
1707 height
= wmPtr
->height
;
1717 * Compute the new position for the window. This is tricky, because
1718 * we need to include the border widths supplied by a reparented
1719 * parent in this calculation, but can't use the parent's current
1720 * overall size since that may change as a result of this code.
1723 if (wmPtr
->flags
& WM_NEGATIVE_X
) {
1724 x
= DisplayWidth(winPtr
->display
, winPtr
->screenNum
) - wmPtr
->x
1725 - (width
+ (wmPtr
->parentWidth
- winPtr
->changes
.width
))
1728 x
= wmPtr
->x
+ wmPtr
->xInParent
;
1730 if (wmPtr
->flags
& WM_NEGATIVE_Y
) {
1731 y
= DisplayHeight(winPtr
->display
, winPtr
->screenNum
) - wmPtr
->y
1732 - (height
+ (wmPtr
->parentHeight
- winPtr
->changes
.height
))
1735 y
= wmPtr
->y
+ wmPtr
->yInParent
;
1739 * If the window's size is going to change and the window is
1740 * supposed to not be resizable by the user, then we have to
1741 * update the size hints. There may also be a size-hint-update
1742 * request pending from somewhere else, too.
1745 if (((width
!= winPtr
->changes
.width
) || (width
!= winPtr
->changes
.width
))
1746 && !IS_GRIDDED(wmPtr
)
1747 && ((wmPtr
->sizeHintsFlags
& (PMinSize
|PMaxSize
)) == 0)) {
1748 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
1750 if (wmPtr
->flags
& WM_UPDATE_SIZE_HINTS
) {
1751 UpdateSizeHints(winPtr
);
1755 * If the geometry hasn't changed, be careful to use only a
1756 * resize operation. This is because of bugs in some window
1757 * managers (e.g. twm, as of 4/24/91) where they don't interpret
1758 * coordinates according to ICCCM.
1761 if ((x
!= winPtr
->changes
.x
) || (y
!= winPtr
->changes
.y
)) {
1762 wmPtr
->configRequest
= XNextRequest(winPtr
->display
);
1763 wmPtr
->configWidth
= width
;
1764 wmPtr
->configHeight
= height
;
1765 Tk_MoveResizeWindow((Tk_Window
) winPtr
, x
, y
, (unsigned) width
,
1767 wmPtr
->flags
|= WM_CONFIG_PENDING
;
1768 } else if ((width
!= wmPtr
->configWidth
)
1769 || (height
!= wmPtr
->configHeight
)) {
1770 wmPtr
->configRequest
= XNextRequest(winPtr
->display
);
1771 wmPtr
->configWidth
= width
;
1772 wmPtr
->configHeight
= height
;
1773 Tk_ResizeWindow((Tk_Window
) winPtr
, (unsigned) width
,
1775 wmPtr
->flags
|= WM_CONFIG_PENDING
;
1780 *--------------------------------------------------------------
1782 * UpdateSizeHints --
1784 * This procedure is called to update the window manager's
1785 * size hints information from the information in a WmInfo
1792 * Properties get changed for winPtr.
1794 *--------------------------------------------------------------
1798 UpdateSizeHints(winPtr
)
1801 register WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1802 XSizeHints
*hintsPtr
;
1804 wmPtr
->flags
&= ~WM_UPDATE_SIZE_HINTS
;
1807 hintsPtr
= XAllocSizeHints();
1808 if (hintsPtr
== NULL
) {
1813 * Compute the pixel-based sizes for the various fields in the
1814 * size hints structure, based on the grid-based sizes in
1818 if (IS_GRIDDED(wmPtr
)) {
1819 hintsPtr
->base_width
= winPtr
->reqWidth
1820 - (wmPtr
->reqGridWidth
* wmPtr
->widthInc
);
1821 if (hintsPtr
->base_width
< 0) {
1822 hintsPtr
->base_width
= 0;
1824 hintsPtr
->base_height
= winPtr
->reqHeight
1825 - (wmPtr
->reqGridHeight
* wmPtr
->heightInc
);
1826 if (hintsPtr
->base_height
< 0) {
1827 hintsPtr
->base_height
= 0;
1829 hintsPtr
->min_width
= hintsPtr
->base_width
1830 + (wmPtr
->minWidth
* wmPtr
->widthInc
);
1831 hintsPtr
->min_height
= hintsPtr
->base_height
1832 + (wmPtr
->minHeight
* wmPtr
->heightInc
);
1833 hintsPtr
->max_width
= hintsPtr
->base_width
1834 + (wmPtr
->maxWidth
* wmPtr
->widthInc
);
1835 hintsPtr
->max_height
= hintsPtr
->base_height
1836 + (wmPtr
->maxHeight
* wmPtr
->heightInc
);
1838 hintsPtr
->min_width
= wmPtr
->minWidth
;
1839 hintsPtr
->min_height
= wmPtr
->minHeight
;
1840 hintsPtr
->max_width
= wmPtr
->maxWidth
;
1841 hintsPtr
->max_height
= wmPtr
->maxHeight
;
1842 hintsPtr
->base_width
= 0;
1843 hintsPtr
->base_height
= 0;
1845 hintsPtr
->width_inc
= wmPtr
->widthInc
;
1846 hintsPtr
->height_inc
= wmPtr
->heightInc
;
1847 hintsPtr
->min_aspect
.x
= wmPtr
->minAspect
.x
;
1848 hintsPtr
->min_aspect
.y
= wmPtr
->minAspect
.y
;
1849 hintsPtr
->max_aspect
.x
= wmPtr
->maxAspect
.x
;
1850 hintsPtr
->max_aspect
.y
= wmPtr
->maxAspect
.y
;
1851 hintsPtr
->win_gravity
= wmPtr
->gravity
;
1852 hintsPtr
->flags
= wmPtr
->sizeHintsFlags
;
1855 * If a window is non-gridded and no minimum or maximum size has
1856 * been specified, don't let the window be resized at all.
1859 if (!IS_GRIDDED(wmPtr
)
1860 && ((wmPtr
->sizeHintsFlags
& (PMinSize
|PMaxSize
)) == 0)) {
1863 width
= wmPtr
->width
;
1864 height
= wmPtr
->height
;
1866 width
= winPtr
->reqWidth
;
1867 height
= winPtr
->reqHeight
;
1869 hintsPtr
->min_width
= hintsPtr
->max_width
= width
;
1870 hintsPtr
->min_height
= hintsPtr
->max_height
= height
;
1871 hintsPtr
->flags
|= PMinSize
|PMaxSize
;
1875 * If min or max size isn't specified, fill in with extreme values
1876 * rather than leaving unspecified. Otherwise window manager may
1877 * do someting counter-intuitive like the last value ever specified.
1880 if (!(hintsPtr
->flags
& PMinSize
)) {
1881 hintsPtr
->min_width
= hintsPtr
->min_height
= 0;
1882 hintsPtr
->flags
|= PMinSize
;
1884 if (!(hintsPtr
->flags
& PMaxSize
)) {
1885 hintsPtr
->max_width
= hintsPtr
->max_height
= 1000000;
1886 hintsPtr
->flags
|= PMaxSize
;
1889 XSetWMNormalHints(winPtr
->display
, winPtr
->window
, hintsPtr
);
1891 XFree((char *) hintsPtr
);
1896 *--------------------------------------------------------------
1900 * This procedure is called to update the window manager's
1901 * hints information from the information in a WmInfo
1908 * Properties get changed for winPtr.
1910 *--------------------------------------------------------------
1917 WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1919 if (wmPtr
->flags
& WM_NEVER_MAPPED
) {
1922 XSetWMHints(winPtr
->display
, winPtr
->window
, &wmPtr
->hints
);
1926 *--------------------------------------------------------------
1930 * This procedure parses a geometry string and updates
1931 * information used to control the geometry of a top-level
1935 * A standard Tcl return value, plus an error message in
1936 * interp->result if an error occurs.
1939 * The size and/or location of winPtr may change.
1941 *--------------------------------------------------------------
1945 ParseGeometry(interp
, string
, winPtr
)
1946 Tcl_Interp
*interp
; /* Used for error reporting. */
1947 char *string
; /* String containing new geometry. Has the
1948 * standard form "=wxh+x+y". */
1949 TkWindow
*winPtr
; /* Pointer to top-level window whose
1950 * geometry is to be changed. */
1952 register WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
1953 int x
, y
, width
, height
, flags
;
1955 register char *p
= string
;
1958 * The leading "=" is optional.
1966 * Parse the width and height, if they are present. Don't
1967 * actually update any of the fields of wmPtr until we've
1968 * successfully parsed the entire geometry string.
1971 width
= wmPtr
->width
;
1972 height
= wmPtr
->height
;
1975 flags
= wmPtr
->flags
;
1977 width
= strtoul(p
, &end
, 10);
1986 height
= strtoul(p
, &end
, 10);
1991 * Parse the X and Y coordinates, if they are present.
1995 flags
&= ~(WM_NEGATIVE_X
| WM_NEGATIVE_Y
);
1997 flags
|= WM_NEGATIVE_X
;
1998 } else if (*p
!= '+') {
2001 x
= strtol(p
+1, &end
, 10);
2004 flags
|= WM_NEGATIVE_Y
;
2005 } else if (*p
!= '+') {
2008 y
= strtol(p
+1, &end
, 10);
2014 * Assume that the geometry information came from the user,
2015 * unless an explicit source has been specified. Otherwise
2016 * most window managers assume that the size hints were
2017 * program-specified and they ignore them.
2020 if ((wmPtr
->sizeHintsFlags
& (USPosition
|PPosition
)) == 0) {
2021 wmPtr
->sizeHintsFlags
|= USPosition
;
2022 wmPtr
->flags
|= WM_UPDATE_SIZE_HINTS
;
2027 * Everything was parsed OK. Update the fields of *wmPtr and
2028 * arrange for the appropriate information to be percolated out
2029 * to the window manager at the next idle moment.
2032 wmPtr
->width
= width
;
2033 wmPtr
->height
= height
;
2036 wmPtr
->flags
= flags
;
2038 if (!(wmPtr
->flags
& (WM_UPDATE_PENDING
|WM_NEVER_MAPPED
))) {
2039 Tk_DoWhenIdle(UpdateGeometryInfo
, (ClientData
) winPtr
);
2040 wmPtr
->flags
|= WM_UPDATE_PENDING
;
2045 Tcl_AppendResult(interp
, "bad geometry specifier \"",
2046 string
, "\"", (char *) NULL
);
2051 *----------------------------------------------------------------------
2053 * Tk_GetRootCoords --
2055 * Given a token for a window, this procedure traces through the
2056 * window's lineage to find the root-window coordinates corresponding
2057 * to point (0,0) in the window.
2060 * The locations pointed to by xPtr and yPtr are filled in with
2061 * the root coordinates of the (0,0) point in tkwin.
2066 *----------------------------------------------------------------------
2070 Tk_GetRootCoords(tkwin
, xPtr
, yPtr
)
2071 Tk_Window tkwin
; /* Token for window. */
2072 int *xPtr
; /* Where to store x-displacement of (0,0). */
2073 int *yPtr
; /* Where to store y-displacement of (0,0). */
2076 register TkWindow
*winPtr
= (TkWindow
*) tkwin
;
2079 * Search back through this window's parents all the way to a
2080 * top-level window, combining the offsets of each window within
2086 x
+= winPtr
->changes
.x
+ winPtr
->changes
.border_width
;
2087 y
+= winPtr
->changes
.y
+ winPtr
->changes
.border_width
;
2088 if (winPtr
->flags
& TK_TOP_LEVEL
) {
2091 winPtr
= winPtr
->parentPtr
;
2100 *--------------------------------------------------------------
2102 * TkWmSetWmProtocols --
2103 * Set the ICCCM WM_PROTOCOLS to be honored by this window.
2104 * Currently, it is just WM_DELETE_WINDOW.
2110 * A window property may get updated.
2112 *--------------------------------------------------------------
2116 TkWmSetWmProtocols(winPtr
)
2117 TkWindow
*winPtr
; /* Newly-created top-level window. */
2119 if (winPtr
->wmInfoPtr
->flags
& WM_NEVER_MAPPED
) {
2124 /* assemble the WM_PROTOCOLS that we honor */
2127 atomlist
[count
++] = Tk_InternAtom((Tk_Window
) winPtr
,
2128 "WM_DELETE_WINDOW");
2130 * other WM_PROTOCOLS go here -- e.g...
2131 * atomlist[count++] = Tk_InternAtom((Tk_Window) winPtr,
2132 * "WM_SAVE_YOURSELF");
2136 * assign the honor list to the window not all X11R4's have
2137 * XSetWmProtocols() so use XChangeProperty()
2140 /* XSetWmProtocols(winPtr->display, winPtr->window, atomlist, count); */
2142 XChangeProperty(winPtr
->display
,
2144 Tk_InternAtom((Tk_Window
) winPtr
, "WM_PROTOCOLS"),
2147 (unsigned char *)atomlist
,
2158 *----------------------------------------------------------------------
2160 * TkWmProtocolEventProc --
2162 * Handle a WM_PROTOCOL ICCCM event sent by the window manager to
2165 * The WM_PROTOCOL's currently handled are:
2167 * WM_DELETE_PROTOCOL:
2172 * for WM_DELETE_WINDOW:
2173 * - window may be deleted if specified earlier by a
2175 * - a tcl command may be executed if sepcified earlier by a
2181 TkWmProtocolEventProc(winPtr
, eventPtr
)
2185 if ((Atom
)(eventPtr
->xclient
.data
.l
)[0] ==
2186 Tk_InternAtom((Tk_Window
) winPtr
, "WM_DELETE_WINDOW")) {
2188 WmInfo
*wmPtr
= winPtr
->wmInfoPtr
;
2190 if (wmPtr
->deleteCmd
) {
2191 if (*(wmPtr
->deleteCmd
) == '\0') {
2192 /* callback is empty, just delete the window */
2193 Tk_DestroyWindow((Tk_Window
) winPtr
);
2195 /* there is a callback so run it */
2196 (void) Tcl_Eval(winPtr
->mainPtr
->interp
,
2197 wmPtr
->deleteCmd
, 0, (char **)0);
2200 Tk_DestroyWindow((Tk_Window
) winPtr
);
2204 * else { .. other WM_<ETC> cases go here ... }
2211 *----------------------------------------------------------------------
2217 * wm protocol <window> delete [command_str]
2219 * right now just delete is supported for OPTION
2221 * Kind of artificial, But makes it easier to merge into new
2222 * versions of Stock Tk.
2225 WmProtocolCmd(interp
, CmdPtr
, argc
, argv
)
2231 #define Cmd (*CmdPtr)
2236 * return current command
2238 if (!Cmd
|| *Cmd
== '\0') {
2242 * chop off the <blank><window_name>
2243 * and return just the cmd
2245 int x
= strlen(Cmd
) - strlen(argv
[2]) - 1;
2249 /* maybe should just have them put the window in the cmd */
2250 Tcl_AppendResult(interp
, Cmd
, (char *)NULL
);
2253 * tack the blank and window name back on
2266 if (*argv
[4] != '\0') {
2267 int x
= strlen(argv
[4]) + strlen(argv
[2]) + 2;
2268 if (!(Cmd
= ckalloc(x
))) {
2269 perror("wm protocol:");
2271 sprintf(Cmd
, "%s %s", argv
[4], argv
[2]);
2276 Tcl_AppendResult(interp
, "wrong # of arguments: must be \"",
2277 argv
[0], " protocol window <attribute> [cmd]\"", (char *) NULL
);
2286 *----------------------------------------------------------------------
2288 * Tk_CoordsToWindow --
2290 * Given the root coordinates of a point, this procedure
2291 * returns the token for the top-most window covering that point,
2292 * if there exists such a window in this application.
2295 * The return result is either a token for the window corresponding
2296 * to rootX and rootY, or else NULL to indicate that there is no such
2302 *----------------------------------------------------------------------
2306 Tk_CoordsToWindow(rootX
, rootY
, tkwin
)
2307 int rootX
, rootY
; /* Coordinates of point in root window. */
2308 Tk_Window tkwin
; /* Token for any window in application;
2309 * used to identify the application. */
2311 Window rootChild
, dummy3
, dummy4
;
2312 int i
, dummy1
, dummy2
;
2313 register WmInfo
*wmPtr
;
2314 register TkWindow
*winPtr
, *childPtr
;
2315 TkWindow
*nextPtr
; /* Coordinates of highest child found so
2316 * far that contains point. */
2317 int x
, y
; /* Coordinates in winPtr. */
2319 Window
*children
; /* Children of winPtr, or NULL. */
2320 unsigned int numChildren
; /* Size of children array. */
2323 * Step 1: find the top-level window that contains the desired
2327 if (XTranslateCoordinates(Tk_Display(tkwin
),
2328 RootWindowOfScreen(Tk_Screen(tkwin
)),
2329 RootWindowOfScreen(Tk_Screen(tkwin
)), rootX
, rootY
, &dummy1
,
2330 &dummy2
, &rootChild
) == False
) {
2331 panic("Tk_CoordsToWindow get False return from XTranslateCoordinates");
2333 for (wmPtr
= firstWmPtr
; ; wmPtr
= wmPtr
->nextPtr
) {
2334 if (wmPtr
== NULL
) {
2337 if ((wmPtr
->reparent
== rootChild
) || ((wmPtr
->reparent
== None
)
2338 && (wmPtr
->winPtr
->window
== rootChild
))) {
2342 winPtr
= wmPtr
->winPtr
;
2343 if (winPtr
->mainPtr
!= ((TkWindow
*) tkwin
)->mainPtr
) {
2348 * Step 2: work down through the hierarchy underneath this window.
2349 * At each level, scan through all the children to see if any contain
2350 * the point. If none do, then we're done. If one does, then do the
2351 * same thing on that child. If two or more do, then fetch enough
2352 * information from the window server to figure out which is on top,
2353 * and repeat on that child.
2359 x
-= winPtr
->changes
.x
;
2360 y
-= winPtr
->changes
.y
;
2363 for (childPtr
= winPtr
->childList
; childPtr
!= NULL
;
2364 childPtr
= childPtr
->nextPtr
) {
2365 if (!Tk_IsMapped(childPtr
) || (childPtr
->flags
& TK_TOP_LEVEL
)) {
2368 tmpx
= x
- childPtr
->changes
.x
;
2369 tmpy
= y
- childPtr
->changes
.y
;
2370 bd
= childPtr
->changes
.border_width
;
2371 if ((tmpx
< -bd
) || (tmpy
< -bd
)
2372 || (tmpx
>= (childPtr
->changes
.width
+ bd
))
2373 || (tmpy
>= (childPtr
->changes
.height
+ bd
))) {
2376 if (nextPtr
== NULL
) {
2382 * More than one child of same parent overlaps point. Must
2383 * figure out which is on top. Keep a cache of the stacking
2384 * order for winPtr to help with this, in case there are >2
2385 * children overlapping.
2388 if (children
== NULL
) {
2389 if (XQueryTree(winPtr
->display
, winPtr
->window
, &dummy3
,
2390 &dummy4
, &children
, &numChildren
) == 0) {
2391 panic("Tk_CoordsToWindow get error return from XQueryTree");
2394 for (i
= 0; i
< numChildren
; i
++) {
2395 if (children
[i
] == childPtr
->window
) {
2398 if (children
[i
] == nextPtr
->window
) {
2404 if (children
!= NULL
) {
2405 XFree((char *) children
);
2407 if (nextPtr
== NULL
) {
2412 return (Tk_Window
) winPtr
;