summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormdejong <mdejong>2002-06-12 19:02:47 (GMT)
committermdejong <mdejong>2002-06-12 19:02:47 (GMT)
commitd0a1bb90be7ff13f1f6e4726a619d023aed98e71 (patch)
treeb9d5c6efdc426faf7948a35e387669270af7514d
parent72d83b662b05709150ca4d85040a0d35313a669d (diff)
downloadtk-d0a1bb90be7ff13f1f6e4726a619d023aed98e71.zip
tk-d0a1bb90be7ff13f1f6e4726a619d023aed98e71.tar.gz
tk-d0a1bb90be7ff13f1f6e4726a619d023aed98e71.tar.bz2
* changes: Add note about new transient behavior.
* tests/unixWm.test: Check that the WM_TRANSIENT_FOR property for a transient window is being cleared when the master is destroyed. * tests/wm.test: Source defs.tcl instead of using tcltest to match the rest of Tk's test files. Add new tests that ensure that a transient's state mirrors the state of the master. * unix/tkUnixWm.c (WmInfo, TkWmNewWindow, TkWmMapWindow, TkWmDeadWindow, Tk_WmCmd, WmWaitMapProc): Add numTransients member to WmInfo structure. Keep state of master and transient in sync using a callback that tracks MapNotify and UnmapNotify events. When the master is mapped, map the transient. When the master is unmapped or iconified, withdraw the transient. * win/tkWinWm.c (TkWmMapWindow, TkpWmSetState, TkWmDeadWindow, Tk_WmCmd, WmWaitVisibilityOrMapProc): Keep state of master and transient in sync using a callback that tracks MapNotify and UnmapNotify events. Move masterPtr check from TkpWmSetState into TkWmMapWindow to deal with WM_NEVER_MAPPED transients. Cleanup numTransients and the callback in TkWmDeadWindow. Cleanup numTransients and the callback only after deleting a master in wm transient command to avoid deleting the callback when an error is raised. Add support for MapNotify and UnmapNotify events to the master callback.
-rw-r--r--ChangeLog31
-rw-r--r--changes8
-rw-r--r--tests/unixWm.test15
-rw-r--r--tests/wm.test133
-rw-r--r--unix/tkUnixWm.c129
-rw-r--r--win/tkWinWm.c98
6 files changed, 370 insertions, 44 deletions
diff --git a/ChangeLog b/ChangeLog
index c74e70e..0d92bfe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,35 @@
+2002-06-12 Mo DeJong <mdejong@users.sourceforge.net>
+
+ * changes: Add note about new transient behavior.
+ * tests/unixWm.test: Check that the WM_TRANSIENT_FOR
+ property for a transient window is being cleared
+ when the master is destroyed.
+ * tests/wm.test: Source defs.tcl instead of using
+ tcltest to match the rest of Tk's test files.
+ Add new tests that ensure that a transient's state
+ mirrors the state of the master.
+ * unix/tkUnixWm.c (WmInfo, TkWmNewWindow, TkWmMapWindow,
+ TkWmDeadWindow, Tk_WmCmd, WmWaitMapProc): Add numTransients
+ member to WmInfo structure. Keep state of master and
+ transient in sync using a callback that tracks MapNotify
+ and UnmapNotify events. When the master is mapped, map
+ the transient. When the master is unmapped or iconified,
+ withdraw the transient.
+ * win/tkWinWm.c (TkWmMapWindow, TkpWmSetState,
+ TkWmDeadWindow, Tk_WmCmd, WmWaitVisibilityOrMapProc):
+ Keep state of master and transient in sync using a
+ callback that tracks MapNotify and UnmapNotify events.
+ Move masterPtr check from TkpWmSetState into TkWmMapWindow
+ to deal with WM_NEVER_MAPPED transients. Cleanup
+ numTransients and the callback in TkWmDeadWindow.
+ Cleanup numTransients and the callback only after
+ deleting a master in wm transient command to avoid
+ deleting the callback when an error is raised.
+ Add support for MapNotify and UnmapNotify events
+ to the master callback.
+
2002-06-11 Joe English <jenglish@users.sf.net>
+
* library/menu.tcl: fix for bug report #530212 "Bad Window Path
Name in tkMenuFind"
diff --git a/changes b/changes
index 28f17ba..6d36b05 100644
--- a/changes
+++ b/changes
@@ -2,7 +2,7 @@ This file summarizes all changes made to Tk since version 1.0 was
released on March 13, 1991. Changes that aren't backward compatible
are marked specially.
-RCS: @(#) $Id: changes,v 1.52 2002/05/27 22:54:42 mdejong Exp $
+RCS: @(#) $Id: changes,v 1.53 2002/06/12 19:02:48 mdejong Exp $
3/16/91 (bug fix) Modified tkWindow.c to remove Tk's Tcl commands from
the interpreter when the main window is deleted (otherwise there will
@@ -5184,4 +5184,8 @@ address TIP 72 changes (64-bit) in Tcl (fellows)
--- Released 8.4a4, March 5, 2002 --- See ChangeLog for details ---
-2002-05-27 (feature change) [wm transient .t .t] now raises an error
+2002-05-27 (feature change) [wm transient .t .t] now raises an error (dejong)
+
+2002-06-12 (feature change) A transient toplevel now mirrors state
+changes in the master. (dejong)
+
diff --git a/tests/unixWm.test b/tests/unixWm.test
index ae675a4..f22ab67 100644
--- a/tests/unixWm.test
+++ b/tests/unixWm.test
@@ -7,7 +7,7 @@
# Copyright (c) 1998-1999 by Scriptics Corporation.
# All rights reserved.
#
-# RCS: @(#) $Id: unixWm.test,v 1.15 2002/05/24 09:50:11 mdejong Exp $
+# RCS: @(#) $Id: unixWm.test,v 1.16 2002/06/12 19:02:49 mdejong Exp $
if {[lsearch [namespace children] ::tcltest] == -1} {
source [file join [pwd] [file dirname [info script]] defs.tcl]
@@ -1279,7 +1279,18 @@ test unixWm-37.3 {Tk_WmCmd procedure, "transient" option} {unixOnly} {
destroy .t2
set result
} {{} {} .t 0 {} 0x0}
-test unixWm-37.4 {Tk_WmCmd procedure, "transient" option, create master wrapper} {unixOnly} {
+test unixWm-37.4 {TkWmDeadWindow, destroy on master should clear transient} {unixOnly} {
+ catch {destroy .t2}
+ toplevel .t2
+ catch {destroy .t3}
+ toplevel .t3
+ wm transient .t2 .t3
+ update
+ destroy .t3
+ update
+ list [wm transient .t2] [testprop [testwrapper .t2] WM_TRANSIENT_FOR]
+} {{} 0x0}
+test unixWm-37.5 {Tk_WmCmd procedure, "transient" option, create master wrapper} {unixOnly} {
catch {destroy .t2}
catch {destroy .t3}
toplevel .t2 -width 120 -height 300
diff --git a/tests/wm.test b/tests/wm.test
index 14cce6b..f6df2ab 100644
--- a/tests/wm.test
+++ b/tests/wm.test
@@ -7,15 +7,14 @@
# Copyright (c) 1998-1999 by Scriptics Corporation.
# All rights reserved.
#
-# RCS: @(#) $Id: wm.test,v 1.8 2002/05/27 22:54:42 mdejong Exp $
+# RCS: @(#) $Id: wm.test,v 1.9 2002/06/12 19:02:49 mdejong Exp $
# This file tests window manager interactions that work across
# platforms. Window manager tests that only work on a specific
# platform should be placed in unixWm.test or winWm.test.
if {[lsearch [namespace children] ::tcltest] == -1} {
- package require tcltest
- namespace import -force ::tcltest::*
+ source [file join [pwd] [file dirname [info script]] defs.tcl]
}
proc deleteWindows {} {
@@ -381,6 +380,134 @@ test wm-transient-2.2 { first toplevel parent of
wm transient .subject
} {.master}
+test wm-transient-3.1 { transient toplevel is withdrawn
+ when mapped if master is withdrawn } {
+ deleteWindows
+ toplevel .master
+ wm withdraw .master
+ update
+ toplevel .subject
+ wm transient .subject .master
+ update
+ list [wm state .subject] [winfo ismapped .subject]
+} {withdrawn 0}
+
+test wm-transient-3.2 { already mapped transient toplevel
+ takes on withdrawn state of master } {
+ deleteWindows
+ toplevel .master
+ wm withdraw .master
+ update
+ toplevel .subject
+ update
+ wm transient .subject .master
+ update
+ list [wm state .subject] [winfo ismapped .subject]
+} {withdrawn 0}
+
+test wm-transient-3.3 { withdraw/deiconify on the master
+ also does a withdraw/deiconify on the transient } {
+ deleteWindows
+ set results [list]
+ toplevel .master
+ toplevel .subject
+ update
+ wm transient .subject .master
+ wm withdraw .master
+ update
+ lappend results [wm state .subject] \
+ [winfo ismapped .subject]
+ wm deiconify .master
+ update
+ lappend results [wm state .subject] \
+ [winfo ismapped .subject]
+ set results
+} {withdrawn 0 normal 1}
+
+test wm-transient-4.1 { transient toplevel is withdrawn
+ when mapped if master is iconic } {
+ deleteWindows
+ toplevel .master
+ wm iconify .master
+ update
+ toplevel .subject
+ wm transient .subject .master
+ update
+ list [wm state .subject] [winfo ismapped .subject]
+} {withdrawn 0}
+
+test wm-transient-4.2 { already mapped transient toplevel
+ is withdrawn if master is iconic } {
+ deleteWindows
+ toplevel .master
+ wm iconify .master
+ update
+ toplevel .subject
+ update
+ wm transient .subject .master
+ update
+ list [wm state .subject] [winfo ismapped .subject]
+} {withdrawn 0}
+
+test wm-transient-4.3 { iconify/deiconify on the master
+ does a withdraw/deiconify on the transient } {
+ deleteWindows
+ set results [list]
+ toplevel .master
+ toplevel .subject
+ update
+ wm transient .subject .master
+ wm iconify .master
+ update
+ lappend results [wm state .subject] \
+ [winfo ismapped .subject]
+ wm deiconify .master
+ update
+ lappend results [wm state .subject] \
+ [winfo ismapped .subject]
+ set results
+} {withdrawn 0 normal 1}
+
+test wm-transient-5.1 { an error during transient command should not
+ cause the map/unmap binding to be deleted } {
+ deleteWindows
+ set results [list]
+ toplevel .master
+ toplevel .subject
+ update
+ wm transient .subject .master
+ # Expect a bad window path error here
+ lappend results [catch {wm transient .subject .bad}]
+ wm withdraw .master
+ update
+ lappend results [wm state .subject]
+ wm deiconify .master
+ update
+ lappend results [wm state .subject]
+ set results
+} {1 withdrawn normal}
+
+test wm-transient-5.2 { remove transient property when master
+ is destroyed } {
+ deleteWindows
+ toplevel .master
+ toplevel .subject
+ wm transient .subject .master
+ update
+ destroy .master
+ update
+ wm transient .subject
+} {}
+
+test wm-transient-5.3 { remove transient property from window
+ that had never been mapped when master is destroyed } {
+ deleteWindows
+ toplevel .master
+ toplevel .subject
+ wm transient .subject .master
+ destroy .master
+ wm transient .subject
+} {}
test wm-state-1.1 {usage} {
diff --git a/unix/tkUnixWm.c b/unix/tkUnixWm.c
index 50bd41a..8ab742b 100644
--- a/unix/tkUnixWm.c
+++ b/unix/tkUnixWm.c
@@ -12,7 +12,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkUnixWm.c,v 1.20 2002/05/27 22:54:42 mdejong Exp $
+ * RCS: @(#) $Id: tkUnixWm.c,v 1.21 2002/06/12 19:02:49 mdejong Exp $
*/
#include "tkPort.h"
@@ -197,6 +197,7 @@ typedef struct TkWmInfo {
char *clientMachine; /* String to store in WM_CLIENT_MACHINE
* property, or NULL. */
int flags; /* Miscellaneous flags, defined below. */
+ int numTransients; /* number of transients on this window */
struct TkWmInfo *nextPtr; /* Next in list of all top-level windows. */
} WmInfo;
@@ -341,6 +342,8 @@ static Tk_RestrictAction
XEvent *eventPtr));
static void WrapperEventProc _ANSI_ARGS_((ClientData clientData,
XEvent *eventPtr));
+static void WmWaitMapProc _ANSI_ARGS_((
+ ClientData clientData, XEvent *eventPtr));
/*
*--------------------------------------------------------------
@@ -431,6 +434,7 @@ TkWmNewWindow(winPtr)
wmPtr->winPtr = winPtr;
wmPtr->reparent = None;
wmPtr->masterPtr = NULL;
+ wmPtr->numTransients = 0;
wmPtr->hints.flags = InputHint | StateHint;
wmPtr->hints.input = True;
wmPtr->hints.initial_state = NormalState;
@@ -549,8 +553,17 @@ TkWmMapWindow(winPtr)
}
if (wmPtr->masterPtr != NULL) {
- XSetTransientForHint(winPtr->display, wmPtr->wrapperPtr->window,
- wmPtr->masterPtr->wmInfoPtr->wrapperPtr->window);
+ /*
+ * Don't map a transient if the master is not mapped.
+ */
+
+ if (!Tk_IsMapped(wmPtr->masterPtr)) {
+ wmPtr->withdrawn = 1;
+ wmPtr->hints.initial_state = WithdrawnState;
+ } else {
+ XSetTransientForHint(winPtr->display, wmPtr->wrapperPtr->window,
+ wmPtr->masterPtr->wmInfoPtr->wrapperPtr->window);
+ }
}
wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
@@ -743,6 +756,44 @@ TkWmDeadWindow(winPtr)
if (wmPtr->flags & WM_UPDATE_PENDING) {
Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
}
+ /*
+ * Reset all transient windows whose master is the dead window.
+ */
+
+ for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL;
+ wmPtr2 = wmPtr2->nextPtr) {
+ if (wmPtr2->masterPtr == winPtr) {
+ wmPtr->numTransients--;
+ Tk_DeleteEventHandler((Tk_Window) wmPtr2->masterPtr,
+ StructureNotifyMask,
+ WmWaitMapProc, (ClientData) wmPtr2->winPtr);
+ wmPtr2->masterPtr = NULL;
+ if (!(wmPtr2->flags & WM_NEVER_MAPPED)) {
+ XSetTransientForHint(wmPtr2->winPtr->display,
+ wmPtr2->wrapperPtr->window, None);
+ /* FIXME: Need a call like Win32's UpdateWrapper() so
+ we can recreate the wrapper and get rid of the
+ transient window decorations. */
+ }
+ }
+ }
+ if (wmPtr->numTransients != 0)
+ panic("numTransients should be 0");
+
+ if (wmPtr->masterPtr != NULL) {
+ wmPtr2 = wmPtr->masterPtr->wmInfoPtr;
+ /*
+ * If we had a master, tell them that we aren't tied
+ * to them anymore
+ */
+ if (wmPtr2 != NULL) {
+ wmPtr2->numTransients--;
+ }
+ Tk_DeleteEventHandler((Tk_Window) wmPtr->masterPtr,
+ StructureNotifyMask,
+ WmWaitMapProc, (ClientData) winPtr);
+ wmPtr->masterPtr = NULL;
+ }
ckfree((char *) wmPtr);
winPtr->wmInfoPtr = NULL;
}
@@ -1978,6 +2029,21 @@ Tk_WmCmd(clientData, interp, argc, argv)
return TCL_OK;
}
if (argv[3][0] == '\0') {
+ if (masterPtr != NULL) {
+ /*
+ * If we had a master, tell them that we aren't tied
+ * to them anymore
+ */
+ masterPtr->wmInfoPtr->numTransients--;
+ Tk_DeleteEventHandler((Tk_Window) masterPtr,
+ StructureNotifyMask,
+ WmWaitMapProc, (ClientData) winPtr);
+
+ /* FIXME: Need a call like Win32's UpdateWrapper() so
+ we can recreate the wrapper and get rid of the
+ transient window decorations. */
+ }
+
wmPtr->masterPtr = NULL;
} else {
masterPtr = (TkWindow *) Tk_NameToWindow(interp, argv[3], tkwin);
@@ -2020,14 +2086,41 @@ Tk_WmCmd(clientData, interp, argc, argv)
(char *) NULL);
return TCL_ERROR;
} else if (masterPtr != wmPtr->masterPtr) {
+ /*
+ * Remove old master map/unmap binding before setting
+ * the new master. The event handler will ensure that
+ * transient states reflect the state of the master.
+ */
+
+ if (wmPtr->masterPtr == NULL) {
+ masterPtr->wmInfoPtr->numTransients++;
+ } else {
+ Tk_DeleteEventHandler((Tk_Window) wmPtr->masterPtr,
+ StructureNotifyMask,
+ WmWaitMapProc, (ClientData) winPtr);
+ }
+
+ Tk_CreateEventHandler((Tk_Window) masterPtr,
+ StructureNotifyMask,
+ WmWaitMapProc, (ClientData) winPtr);
+
wmPtr->masterPtr = masterPtr;
}
}
if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
- Window xwin = (wmPtr->masterPtr == NULL) ? None :
- wmPtr->masterPtr->wmInfoPtr->wrapperPtr->window;
- XSetTransientForHint(winPtr->display, wmPtr->wrapperPtr->window,
- xwin);
+ if (wmPtr->masterPtr != NULL && !Tk_IsMapped(wmPtr->masterPtr)) {
+ if (TkpWmSetState(winPtr, WithdrawnState) == 0) {
+ Tcl_SetResult(interp,
+ "couldn't send withdraw message to window manager",
+ TCL_STATIC);
+ return TCL_ERROR;
+ }
+ } else {
+ Window xwin = (wmPtr->masterPtr == NULL) ? None :
+ wmPtr->masterPtr->wmInfoPtr->wrapperPtr->window;
+ XSetTransientForHint(winPtr->display, wmPtr->wrapperPtr->window,
+ xwin);
+ }
}
} else if ((c == 'w') && (strncmp(argv[1], "withdraw", length) == 0)
&& (length >= 2)) {
@@ -2068,6 +2161,28 @@ Tk_WmCmd(clientData, interp, argc, argv)
}
return TCL_OK;
}
+
+/*
+ * Invoked when a MapNotify or UnmapNotify event is delivered for a
+ * toplevel that is the master of a transient toplevel.
+ */
+static void
+WmWaitMapProc(clientData, eventPtr)
+ ClientData clientData; /* Pointer to window. */
+ XEvent *eventPtr; /* Information about event. */
+{
+ TkWindow *winPtr = (TkWindow *) clientData;
+ TkWindow *masterPtr = winPtr->wmInfoPtr->masterPtr;
+
+ if (masterPtr == NULL)
+ return;
+
+ if (eventPtr->type == MapNotify) {
+ (void) TkpWmSetState(winPtr, NormalState);
+ } else if (eventPtr->type == UnmapNotify) {
+ (void) TkpWmSetState(winPtr, WithdrawnState);
+ }
+}
/*
*----------------------------------------------------------------------
diff --git a/win/tkWinWm.c b/win/tkWinWm.c
index 207dc4f..1fd42a8 100644
--- a/win/tkWinWm.c
+++ b/win/tkWinWm.c
@@ -12,7 +12,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkWinWm.c,v 1.38 2002/05/27 22:54:42 mdejong Exp $
+ * RCS: @(#) $Id: tkWinWm.c,v 1.39 2002/06/12 19:02:50 mdejong Exp $
*/
#include "tkWinInt.h"
@@ -392,7 +392,7 @@ static void UpdateGeometryInfo _ANSI_ARGS_((
static void UpdateWrapper _ANSI_ARGS_((TkWindow *winPtr));
static LRESULT CALLBACK WmProc _ANSI_ARGS_((HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam));
-static void WmWaitVisibilityProc _ANSI_ARGS_((
+static void WmWaitVisibilityOrMapProc _ANSI_ARGS_((
ClientData clientData, XEvent *eventPtr));
static BlockOfIconImagesPtr ReadIconFromICOFile _ANSI_ARGS_((
Tcl_Interp *interp, char* fileName));
@@ -1521,10 +1521,10 @@ UpdateWrapper(winPtr)
if (winPtr->flags & TK_EMBEDDED) {
wmPtr->wrapper = (HWND) winPtr->privatePtr;
if (wmPtr->wrapper == NULL) {
- panic("TkWmMapWindow: Cannot find container window");
+ panic("UpdateWrapper: Cannot find container window");
}
if (!IsWindow(wmPtr->wrapper)) {
- panic("TkWmMapWindow: Container was destroyed");
+ panic("UpdateWrapper: Container was destroyed");
}
} else {
@@ -1790,7 +1790,17 @@ TkWmMapWindow(winPtr)
InitWm();
}
- if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
+ if (wmPtr->flags & WM_NEVER_MAPPED) {
+ /*
+ * Don't map a transient if the master is not mapped.
+ */
+
+ if (wmPtr->masterPtr != NULL &&
+ !Tk_IsMapped(wmPtr->masterPtr)) {
+ wmPtr->hints.initial_state = WithdrawnState;
+ return;
+ }
+ } else {
if (wmPtr->hints.initial_state == WithdrawnState) {
return;
}
@@ -1867,8 +1877,7 @@ TkpWmSetState(winPtr, state)
WmInfo *wmPtr = winPtr->wmInfoPtr;
int cmd;
- if ((wmPtr->flags & WM_NEVER_MAPPED) ||
- (wmPtr->masterPtr && !Tk_IsMapped(wmPtr->masterPtr))) {
+ if (wmPtr->flags & WM_NEVER_MAPPED) {
wmPtr->hints.initial_state = state;
return;
}
@@ -1944,6 +1953,10 @@ TkWmDeadWindow(winPtr)
for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL;
wmPtr2 = wmPtr2->nextPtr) {
if (wmPtr2->masterPtr == winPtr) {
+ wmPtr->numTransients--;
+ Tk_DeleteEventHandler((Tk_Window) wmPtr2->masterPtr,
+ VisibilityChangeMask|StructureNotifyMask,
+ WmWaitVisibilityOrMapProc, (ClientData) wmPtr2->winPtr);
wmPtr2->masterPtr = NULL;
if ((wmPtr2->wrapper != None)
&& !(wmPtr2->flags & (WM_NEVER_MAPPED))) {
@@ -1951,6 +1964,8 @@ TkWmDeadWindow(winPtr)
}
}
}
+ if (wmPtr->numTransients != 0)
+ panic("numTransients should be 0");
if (wmPtr->hints.flags & IconPixmapHint) {
Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
@@ -1996,8 +2011,8 @@ TkWmDeadWindow(winPtr)
wmPtr2->numTransients--;
}
Tk_DeleteEventHandler((Tk_Window) wmPtr->masterPtr,
- VisibilityChangeMask,
- WmWaitVisibilityProc, (ClientData) winPtr);
+ VisibilityChangeMask|StructureNotifyMask,
+ WmWaitVisibilityOrMapProc, (ClientData) winPtr);
wmPtr->masterPtr = NULL;
}
@@ -3274,17 +3289,19 @@ Tk_WmCmd(clientData, interp, argc, argv)
}
return TCL_OK;
}
- if (masterPtr != NULL) {
- /*
- * If we had a master, tell them that we aren't tied
- * to them anymore
- */
- masterPtr->wmInfoPtr->numTransients--;
- Tk_DeleteEventHandler((Tk_Window) masterPtr,
- VisibilityChangeMask,
- WmWaitVisibilityProc, (ClientData) winPtr);
- }
if (argv[3][0] == '\0') {
+ if (masterPtr != NULL) {
+ /*
+ * If we had a master, tell them that we aren't tied
+ * to them anymore
+ */
+
+ masterPtr->wmInfoPtr->numTransients--;
+ Tk_DeleteEventHandler((Tk_Window) masterPtr,
+ VisibilityChangeMask|StructureNotifyMask,
+ WmWaitVisibilityOrMapProc, (ClientData) winPtr);
+ }
+
wmPtr->masterPtr = NULL;
} else {
masterPtr = (TkWindow*) Tk_NameToWindow(interp, argv[3], tkwin);
@@ -3324,23 +3341,35 @@ Tk_WmCmd(clientData, interp, argc, argv)
(char *) NULL);
return TCL_ERROR;
} else if (masterPtr != wmPtr->masterPtr) {
- wmPtr->masterPtr = masterPtr;
- masterPtr->wmInfoPtr->numTransients++;
-
/*
- * Bind a visibility event handler to the master window,
- * to ensure that when it is mapped, the children will
- * have their state set properly.
+ * Remove old master map/unmap binding before setting
+ * the new master. The event handler will ensure that
+ * transient states reflect the state of the master.
*/
+ if (wmPtr->masterPtr == NULL) {
+ masterPtr->wmInfoPtr->numTransients++;
+ } else {
+ Tk_DeleteEventHandler((Tk_Window) wmPtr->masterPtr,
+ VisibilityChangeMask|StructureNotifyMask,
+ WmWaitVisibilityOrMapProc, (ClientData) winPtr);
+ }
+
Tk_CreateEventHandler((Tk_Window) masterPtr,
- VisibilityChangeMask,
- WmWaitVisibilityProc, (ClientData) winPtr);
+ VisibilityChangeMask|StructureNotifyMask,
+ WmWaitVisibilityOrMapProc, (ClientData) winPtr);
+
+ wmPtr->masterPtr = masterPtr;
}
}
if (!((wmPtr->flags & WM_NEVER_MAPPED)
&& !(winPtr->flags & TK_EMBEDDED))) {
- UpdateWrapper(winPtr);
+ if (wmPtr->masterPtr != NULL &&
+ !Tk_IsMapped(wmPtr->masterPtr)) {
+ TkpWmSetState(winPtr, WithdrawnState);
+ } else {
+ UpdateWrapper(winPtr);
+ }
}
} else if ((c == 'w') && (strncmp(argv[1], "withdraw", length) == 0)) {
if (argc != 3) {
@@ -3377,14 +3406,23 @@ Tk_WmCmd(clientData, interp, argc, argv)
}
/*ARGSUSED*/
static void
-WmWaitVisibilityProc(clientData, eventPtr)
+WmWaitVisibilityOrMapProc(clientData, eventPtr)
ClientData clientData; /* Pointer to window. */
XEvent *eventPtr; /* Information about event. */
{
TkWindow *winPtr = (TkWindow *) clientData;
TkWindow *masterPtr = winPtr->wmInfoPtr->masterPtr;
- if ((eventPtr->type == VisibilityNotify) && (masterPtr != NULL)) {
+ if (masterPtr == NULL)
+ return;
+
+ if (eventPtr->type == MapNotify) {
+ TkpWmSetState(winPtr, NormalState);
+ } else if (eventPtr->type == UnmapNotify) {
+ TkpWmSetState(winPtr, WithdrawnState);
+ }
+
+ if (eventPtr->type == VisibilityNotify) {
int state = masterPtr->wmInfoPtr->hints.initial_state;
if ((state == NormalState) || (state == ZoomState)) {