diff options
author | mdejong <mdejong> | 2002-06-12 19:02:47 (GMT) |
---|---|---|
committer | mdejong <mdejong> | 2002-06-12 19:02:47 (GMT) |
commit | d0a1bb90be7ff13f1f6e4726a619d023aed98e71 (patch) | |
tree | b9d5c6efdc426faf7948a35e387669270af7514d /unix/tkUnixWm.c | |
parent | 72d83b662b05709150ca4d85040a0d35313a669d (diff) | |
download | tk-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.
Diffstat (limited to 'unix/tkUnixWm.c')
-rw-r--r-- | unix/tkUnixWm.c | 129 |
1 files changed, 122 insertions, 7 deletions
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); + } +} /* *---------------------------------------------------------------------- |