diff options
-rw-r--r-- | generic/tkWindow.c | 53 | ||||
-rw-r--r-- | macosx/tkMacOSXInit.c | 12 | ||||
-rw-r--r-- | macosx/tkMacOSXMouseEvent.c | 5 | ||||
-rw-r--r-- | macosx/tkMacOSXSubwindows.c | 2 | ||||
-rw-r--r-- | macosx/tkMacOSXTest.c | 2 | ||||
-rw-r--r-- | macosx/tkMacOSXWindowEvent.c | 6 | ||||
-rw-r--r-- | macosx/tkMacOSXWm.c | 104 | ||||
-rw-r--r-- | tests/event.test | 478 | ||||
-rw-r--r-- | tests/font.test | 13 | ||||
-rw-r--r-- | tests/pack.test | 14 | ||||
-rw-r--r-- | tests/ttk/ttk.test | 5 | ||||
-rw-r--r-- | tests/unixWm.test | 11 | ||||
-rw-r--r-- | tests/winfo.test | 2 | ||||
-rw-r--r-- | tests/wm.test | 2 | ||||
-rw-r--r-- | tests/xmfbox.test | 7 | ||||
-rw-r--r-- | win/tkWinWm.c | 36 |
16 files changed, 601 insertions, 151 deletions
diff --git a/generic/tkWindow.c b/generic/tkWindow.c index 68f3406..64f6ce0 100644 --- a/generic/tkWindow.c +++ b/generic/tkWindow.c @@ -215,6 +215,17 @@ static int Initialize(Tcl_Interp *interp); static int NameWindow(Tcl_Interp *interp, TkWindow *winPtr, TkWindow *parentPtr, const char *name); static void UnlinkWindow(TkWindow *winPtr); + +/* + * This static variable only makes sense for macOS and Windows, which never + * have more than one display. It is set by TkCloseDisplay, and when set + * prevents sending Enter and Leave events when all of the windows in the + * display are being destroyed. Tk does not send those events on X11; that + * job is handled by the X server. + */ + +static int displayBeingClosed = 0; + /* *---------------------------------------------------------------------- @@ -239,6 +250,7 @@ static void TkCloseDisplay( TkDisplay *dispPtr) { + displayBeingClosed = 1; TkClipCleanup(dispPtr); if (dispPtr->name != NULL) { @@ -1334,6 +1346,39 @@ Tk_CreateWindowFromPath( *-------------------------------------------------------------- */ +#if defined(MAC_OSX_TK) || defined(_WIN32) +static void SendEnterLeaveForDestroy( + Tk_Window tkwin) +{ + int x, y; + unsigned int state; + Tk_Window pointerWin; + TkWindow *containerPtr; + + if (displayBeingClosed) { + return; + } + XQueryPointer(Tk_Display(tkwin), None, NULL, NULL, &x, &y, + NULL, NULL, &state); + pointerWin = Tk_CoordsToWindow(x, y, tkwin); + if (pointerWin == tkwin) { + if (!Tk_IsTopLevel(tkwin)) { + containerPtr = TkGetContainer((TkWindow *)pointerWin); + Tk_UpdatePointer((Tk_Window) containerPtr, x, y, state); + } + } + + if (pointerWin && (tkwin == Tk_Parent(pointerWin))) { + Tk_UpdatePointer(Tk_Parent(tkwin), x, y, state); + } +} +#else +static void SendEnterLeaveForDestroy( + TCL_UNUSED(Tk_Window)) +{ +} +#endif + void Tk_DestroyWindow( Tk_Window tkwin) /* Window to destroy. */ @@ -1353,6 +1398,10 @@ Tk_DestroyWindow( return; } + if ((winPtr->flags & TK_DONT_DESTROY_WINDOW) == 0) { + SendEnterLeaveForDestroy(tkwin); + } + winPtr->flags |= TK_ALREADY_DEAD; /* @@ -1523,7 +1572,7 @@ Tk_DestroyWindow( * Cleanup the data structures associated with this window. */ - if (winPtr->flags & TK_WIN_MANAGED) { + if (winPtr->wmInfoPtr && (winPtr->flags & TK_WIN_MANAGED)) { TkWmDeadWindow(winPtr); } else if (winPtr->flags & TK_WM_COLORMAP_WINDOW) { TkWmRemoveFromColormapWindows(winPtr); @@ -2612,7 +2661,7 @@ Tk_RestackWindow( TkWindow *otherPtr = (TkWindow *) other; /* - * Special case: if winPtr is a top-level window then just find the + * Special case: if winPtr is a toplevel window then just find the * top-level ancestor of otherPtr and restack winPtr above otherPtr * without changing any of Tk's childLists. */ diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index 185d923..b1f6855 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -423,6 +423,18 @@ TCL_NORETURN void TkpExitProc( } /* + * At this point it is too late to be looking up the Tk window associated + * to any NSWindows, but it can happen. This makes sure the answer is None + * if such a query is attempted. + */ + + for (TKWindow *w in [NSApp orderedWindows]) { + if ([w respondsToSelector: @selector (tkWindow)]) { + [w setTkWindow: None]; + } + } + + /* * Tcl_Exit does not call Tcl_Finalize if there is an exit proc installed. */ diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 83d2cd2..9eca985 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -504,8 +504,9 @@ enum { state |= Tk_GetButtonMask(Button1); } if (eventType == NSMouseEntered) { - Tk_UpdatePointer((Tk_Window) [NSApp tkPointerWindow], - global.x, global.y, state); + Tk_Window new_win = Tk_CoordsToWindow(global.x, global.y, + (Tk_Window) [NSApp tkPointerWindow]); + Tk_UpdatePointer(new_win, global.x, global.y, state); } else if (eventType == NSMouseExited) { if ([NSApp tkDragTarget]) { Tk_UpdatePointer((Tk_Window) [NSApp tkDragTarget], diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index 0c4e4e4..2ba8568 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -65,8 +65,8 @@ XDestroyWindow( * deleting is being tracked by the grab code. */ - TkPointerDeadWindow(macWin->winPtr); TkMacOSXSelDeadWindow(macWin->winPtr); + TkPointerDeadWindow(macWin->winPtr); macWin->toplevel->referenceCount--; if (!Tk_IsTopLevel(macWin->winPtr)) { diff --git a/macosx/tkMacOSXTest.c b/macosx/tkMacOSXTest.c index f6a1f0c..19feb8d 100644 --- a/macosx/tkMacOSXTest.c +++ b/macosx/tkMacOSXTest.c @@ -140,6 +140,8 @@ MenuBarHeightObjCmd( * Returns true if and only if the NSView of the drawable is the * current focusView, which on 10.14 and newer systems can only be the * case when within [NSView drawRect]. + * NOTE: This is no longer needed when we use updateLayer instead + * of drawRect. Now it always returns True. * * Side effects: * None diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index bd5e2e6..bd5ea2d 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -256,7 +256,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification; TkWindow *winPtr = TkMacOSXGetTkWindow(w); if (winPtr) { - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {} + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {} } } @@ -284,9 +284,11 @@ extern NSString *NSWindowDidOrderOffScreenNotification; NSWindow *w = [notification object]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); +#if 0 if (winPtr) { - //Tk_UnmapWindow((Tk_Window)winPtr); + Tk_UnmapWindow((Tk_Window)winPtr); } +#endif } #endif /* TK_MAC_DEBUG_NOTIFICATIONS */ diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index 4d5ea7e..c01d506 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -826,7 +826,6 @@ FrontWindowAtPoint( for (NSWindow *w in windows) { winPtr = TkMacOSXGetTkWindow(w); if (winPtr) { - WmInfo *wmPtr = winPtr->wmInfoPtr; NSRect windowFrame = [w frame]; NSRect contentFrame = [w frame]; @@ -837,13 +836,15 @@ FrontWindowAtPoint( * window. */ - if ((wmPtr->hints.initial_state == NormalState || - wmPtr->hints.initial_state == ZoomState)) { - if (NSMouseInRect(p, contentFrame, NO)) { - return winPtr; - } else if (NSMouseInRect(p, windowFrame, NO)) { - return NULL; - } + if (NSMouseInRect(p, contentFrame, NO)) { + return winPtr; + } else if (NSMouseInRect(p, windowFrame, NO)) { + /* + * The pointer is in the title bar of the highest NSWindow + * containing it, and therefore is should not be considered + * to be contained in any Tk window. + */ + return NULL; } } } @@ -1102,12 +1103,15 @@ TkWmUnmapWindow( * * This procedure is invoked when a top-level window is about to be * deleted. It cleans up the wm-related data structures for the window. + * If the dead window contains the pointer, TkUpdatePointer is called + * to tell Tk which window will be the new pointer window. * * Results: * None. * * Side effects: - * The WmInfo structure for winPtr gets freed up. + * The WmInfo structure for winPtr gets freed. Tk's cached pointer + * window may change. * *---------------------------------------------------------------------- */ @@ -1116,13 +1120,14 @@ void TkWmDeadWindow( TkWindow *winPtr) /* Top-level window that's being deleted. */ { + TkWindow *winPtr2; + NSWindow *w; WmInfo *wmPtr = winPtr->wmInfoPtr, *wmPtr2; - TKWindow *deadNSWindow; - - if (wmPtr == NULL) { + TKWindow *deadNSWindow = (TKWindow *)TkMacOSXGetNSWindowForDrawable( + Tk_WindowId(winPtr)); + if (deadNSWindow == NULL) { return; } - /* *If the dead window is a transient, remove it from the container's list. */ @@ -1174,11 +1179,10 @@ TkWmDeadWindow( for (Transient *transientPtr = wmPtr->transientPtr; transientPtr != NULL; transientPtr = transientPtr->nextPtr) { - TkWindow *winPtr2 = transientPtr->winPtr; - TkWindow *containerPtr = (TkWindow *)TkMacOSXGetContainer(winPtr2); - + TkWindow *containerPtr = (TkWindow *)TkMacOSXGetContainer( + transientPtr->winPtr); if (containerPtr == winPtr) { - wmPtr2 = winPtr2->wmInfoPtr; + wmPtr2 = transientPtr->winPtr->wmInfoPtr; wmPtr2->container = NULL; } } @@ -1190,29 +1194,48 @@ TkWmDeadWindow( ckfree(transientPtr); } - deadNSWindow = (TKWindow *)wmPtr->window; - /* * Remove references to the Tk window from the mouse event processing - * state which is recorded in the NSApplication object. + * state which is recorded in the NSApplication object and notify Tk + * of the new pointer window. */ - if (winPtr == [NSApp tkPointerWindow]) { - NSWindow *w; - NSPoint mouse = [NSEvent mouseLocation]; - [NSApp setTkPointerWindow:nil]; - for (w in [NSApp orderedWindows]) { - if (w == deadNSWindow) { - continue; - } - if (NSPointInRect(mouse, [w frame])) { - TkWindow *winPtr2 = TkMacOSXGetTkWindow(w); - int x = mouse.x, y = TkMacOSXZeroScreenHeight() - mouse.y; - [NSApp setTkPointerWindow:winPtr2]; - Tk_UpdatePointer((Tk_Window) winPtr2, x, y, - [NSApp tkButtonState]); - break; - } + NSPoint mouse = [NSEvent mouseLocation]; + [NSApp setTkPointerWindow:nil]; + winPtr2 = NULL; + + for (w in [NSApp orderedWindows]) { + if (w == deadNSWindow || w == NULL) { + continue; + } + winPtr2 = TkMacOSXGetTkWindow(w); + if (winPtr2 == NULL) { + continue; + } + if (NSPointInRect(mouse, [w frame])) { + [NSApp setTkPointerWindow: winPtr2]; + break; + } + } + if (winPtr2) { + /* + * We now know which toplevel will contain the pointer when the window + * is destroyed. We need to know which Tk window within the + * toplevel will contain the pointer. + */ + NSPoint local = [w tkConvertPointFromScreen: mouse]; + int top_x = floor(local.x), + top_y = floor(w.frame.size.height - local.y); + int root_x = floor(mouse.x), + root_y = floor(TkMacOSXZeroScreenHeight() - mouse.y); + int win_x, win_y; + Tk_Window target = Tk_TopCoordsToWindow((Tk_Window) winPtr2, top_x, top_y, &win_x, &win_y); + /* + * A non-toplevel window can have a NULL parent while it is in the process of + * being destroyed. We should not call Tk_UpdatePointer in that case. + */ + if (Tk_Parent(target) != NULL || Tk_IsTopLevel(target)) { + Tk_UpdatePointer(target, root_x, root_y, [NSApp tkButtonState]); } } @@ -1264,9 +1287,10 @@ TkWmDeadWindow( * set tkEventTarget to NULL when there is no window to send Tk events to. */ TkWindow *newTkEventTarget = NULL; + winPtr2 = NULL; - for (NSWindow *w in [NSApp orderedWindows]) { - TkWindow *winPtr2 = TkMacOSXGetTkWindow(w); + for (w in [NSApp orderedWindows]) { + winPtr2 = TkMacOSXGetTkWindow(w); BOOL isOnScreen; if (!winPtr2 || !winPtr2->wmInfoPtr) { @@ -2543,7 +2567,6 @@ WmForgetCmd( macWin->toplevel->referenceCount++; macWin->flags &= ~TK_HOST_EXISTS; - TkWmDeadWindow(winPtr); RemapWindows(winPtr, (MacDrawable *)winPtr->parentPtr->window); /* @@ -3490,6 +3513,7 @@ WmManageCmd( } else if (Tk_IsTopLevel(frameWin)) { /* Already managed by wm - ignore it */ } + Tk_ManageGeometry((Tk_Window)winPtr, &wmMgrType, NULL); return TCL_OK; } @@ -6029,7 +6053,7 @@ Tk_Window TkMacOSXGetContainer( TkWindow *winPtr) { - if (winPtr->wmInfoPtr != NULL) { + if (Tk_PathName(winPtr)) { return (Tk_Window)winPtr->wmInfoPtr->container; } return NULL; diff --git a/tests/event.test b/tests/event.test index c56d4d8..8058069 100644 --- a/tests/event.test +++ b/tests/event.test @@ -1,9 +1,9 @@ # This file is a Tcl script to test the code in tkEvent.c. It is # organized in the standard fashion for Tcl tests. # -# Copyright © 1994 The Regents of the University of California. -# Copyright © 1994-1995 Sun Microsystems, Inc. -# Copyright © 1998-1999 Scriptics Corporation. +# Copyright (c) 1994 The Regents of the University of California. +# Copyright (c) 1994-1995 Sun Microsystems, Inc. +# Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. package require tcltest 2.2 @@ -20,10 +20,57 @@ namespace import -force tcltest::test proc _init_keypress_lookup {} { global keypress_lookup + scan A %c start + scan Z %c finish + + for {set i $start} {$i <= $finish} {incr i} { + set l [format %c $i] + set keypress_lookup($l) $l + } + + scan a %c start + scan z %c finish + + for {set i $start} {$i <= $finish} {incr i} { + set l [format %c $i] + set keypress_lookup($l) $l + } + + scan 0 %c start + scan 9 %c finish + + for {set i $start} {$i <= $finish} {incr i} { + set l [format %c $i] + set keypress_lookup($l) $l + } + + # Most punctuation + array set keypress_lookup { + ! exclam + % percent + & ampersand + ( parenleft + ) parenright + * asterisk + + plus + , comma + - minus + . period + / slash + : colon + < less + = equal + > greater + ? question + @ at + ^ asciicircum + _ underscore + | bar + ~ asciitilde + ' apostrophe + } # Characters with meaning to Tcl... array set keypress_lookup [list \ - - minus \ - > greater \ \" quotedbl \ \# numbersign \ \$ dollar \ @@ -34,7 +81,6 @@ proc _init_keypress_lookup {} { \{ braceleft \ \} braceright \ " " space \ - \xA0 nobreakspace \ "\n" Return \ "\t" Tab] } @@ -42,8 +88,8 @@ proc _init_keypress_lookup {} { # Lookup an event in the keypress table. # For example: # Q -> Q -# ; -> semicolon -# > -> greater +# . -> period +# / -> slash # Delete -> Delete # Escape -> Escape @@ -65,7 +111,7 @@ proc _keypress_lookup {char} { } } -# Lookup and generate a pair of Key and KeyRelease events +# Lookup and generate a pair of KeyPress and KeyRelease events proc _keypress {win key} { set keysym [_keypress_lookup $key] @@ -78,7 +124,7 @@ proc _keypress {win key} { if {[focus] != $win} { focus -force $win } - event generate $win <Key-$keysym> + event generate $win <KeyPress-$keysym> _pause 50 if {[focus] != $win} { focus -force $win @@ -148,10 +194,10 @@ test event-1.1 {Tk_HandleEvent procedure, filter events for dead windows} -setup update bind .b <Destroy> { lappend x destroy - event generate .b <Button-1> + event generate .b <1> event generate .b <ButtonRelease-1> } - bind .b <Button-1> { + bind .b <1> { lappend x button } @@ -223,7 +269,7 @@ test event-2.3(keypress) {type into entry widget, triple click, hit Delete key, event generate $e <Enter> for {set i 0} {$i < 3} {incr i} { _pause 100 - event generate $e <Button-1> + event generate $e <ButtonPress-1> _pause 100 event generate $e <ButtonRelease-1> } @@ -265,6 +311,7 @@ test event-2.5(keypress) {type into text widget and then delete some text} -setu test event-2.6(keypress) {type into text widget, triple click, hit Delete key, and then type some more} -setup { deleteWindows + update idletasks } -body { set t [toplevel .t] set e [text $t.e] @@ -277,7 +324,7 @@ test event-2.6(keypress) {type into text widget, triple click, event generate $e <Enter> for {set i 0} {$i < 3} {incr i} { _pause 100 - event generate $e <Button-1> + event generate $e <ButtonPress-1> _pause 100 event generate $e <ButtonRelease-1> } @@ -309,7 +356,7 @@ test event-3.1(click-drag) {click and drag in a text widget, this tests # Click down to set the insert cursor position event generate $e <Enter> - event generate $e <Button-1> -x $anchor_x -y $anchor_y + event generate $e <ButtonPress-1> -x $anchor_x -y $anchor_y # Save the position of the insert cursor lappend result [$e index insert] @@ -335,7 +382,7 @@ test event-3.1(click-drag) {click and drag in a text widget, this tests # Now click and click and drag to the left, over "Tcl/Tk selection" - event generate $e <Button-1> -x $current_x -y $current_y + event generate $e <ButtonPress-1> -x $current_x -y $current_y while {[$e compare $current >= [list $anchor - 4 char]]} { foreach {current_x current_y} [_text_ind_to_x_y $e $current] break @@ -376,7 +423,7 @@ test event-3.1(click-drag) {click and drag in a text widget, this tests # Click down to set the insert cursor position event generate $e <Enter> - event generate $e <Button-1> -x $anchor_x -y $anchor_y + event generate $e <ButtonPress-1> -x $anchor_x -y $anchor_y # Save the position of the insert cursor lappend result [$e index insert] @@ -402,7 +449,7 @@ test event-3.1(click-drag) {click and drag in a text widget, this tests # Now click and click and drag to the left, over "Tcl/Tk selection" - event generate $e <Button-1> -x $current_x -y $current_y + event generate $e <ButtonPress-1> -x $current_x -y $current_y while {$current >= ($anchor - 4)} { foreach {current_x current_y} [_text_ind_to_x_y $e $current] break @@ -441,11 +488,11 @@ test event-4.1(double-click-drag) {click down, click up, click down again, # Click down, release, then click down again event generate $e <Enter> - event generate $e <Button-1> -x $anchor_x -y $anchor_y + event generate $e <ButtonPress-1> -x $anchor_x -y $anchor_y _pause 50 event generate $e <ButtonRelease-1> -x $anchor_x -y $anchor_y _pause 50 - event generate $e <Button-1> -x $anchor_x -y $anchor_y + event generate $e <ButtonPress-1> -x $anchor_x -y $anchor_y _pause 50 # Save the highlighted text @@ -512,11 +559,11 @@ test event-4.2(double-click-drag) {click down, click up, click down again, # Click down, release, then click down again event generate $e <Enter> - event generate $e <Button-1> -x $anchor_x -y $anchor_y + event generate $e <ButtonPress-1> -x $anchor_x -y $anchor_y _pause 50 event generate $e <ButtonRelease-1> -x $anchor_x -y $anchor_y _pause 50 - event generate $e <Button-1> -x $anchor_x -y $anchor_y + event generate $e <ButtonPress-1> -x $anchor_x -y $anchor_y _pause 50 set result [list] @@ -584,17 +631,17 @@ test event-5.1(triple-click-drag) {Triple click and drag across lines in a event generate $e <Enter> - event generate $e <Button-1> -x $anchor_x -y $anchor_y + event generate $e <ButtonPress-1> -x $anchor_x -y $anchor_y _pause 50 event generate $e <ButtonRelease-1> -x $anchor_x -y $anchor_y _pause 50 - event generate $e <Button-1> -x $anchor_x -y $anchor_y + event generate $e <ButtonPress-1> -x $anchor_x -y $anchor_y _pause 50 event generate $e <ButtonRelease-1> -x $anchor_x -y $anchor_y _pause 50 - event generate $e <Button-1> -x $anchor_x -y $anchor_y + event generate $e <ButtonPress-1> -x $anchor_x -y $anchor_y _pause 50 set result [list] @@ -634,7 +681,7 @@ test event-6.1(button-state) {button press in a window that is then } -body { set t [toplevel .t] - event generate $t <Button-1> + event generate $t <ButtonPress-1> destroy $t set t [toplevel .t] set motion nomotion @@ -673,11 +720,11 @@ test event-7.1(double-click) {A double click on a lone character # Double click near left hand egde of the letter A event generate $e <Enter> - event generate $e <Button-1> -x $left_x -y $left_y + event generate $e <ButtonPress-1> -x $left_x -y $left_y _pause 50 event generate $e <ButtonRelease-1> -x $left_x -y $left_y _pause 50 - event generate $e <Button-1> -x $left_x -y $left_y + event generate $e <ButtonPress-1> -x $left_x -y $left_y _pause 50 event generate $e <ButtonRelease-1> -x $left_x -y $left_y _pause 50 @@ -688,18 +735,18 @@ test event-7.1(double-click) {A double click on a lone character # Clear selection by clicking at 0,0 - event generate $e <Button-1> -x 0 -y 0 + event generate $e <ButtonPress-1> -x 0 -y 0 _pause 50 event generate $e <ButtonRelease-1> -x 0 -y 0 _pause 50 # Double click near right hand edge of the letter A - event generate $e <Button-1> -x $right_x -y $right_y + event generate $e <ButtonPress-1> -x $right_x -y $right_y _pause 50 event generate $e <ButtonRelease-1> -x $right_x -y $right_y _pause 50 - event generate $e <Button-1> -x $right_x -y $right_y + event generate $e <ButtonPress-1> -x $right_x -y $right_y _pause 50 event generate $e <ButtonRelease-1> -x $right_x -y $right_y _pause 50 @@ -740,11 +787,11 @@ test event-7.2(double-click) {A double click on a lone character # Double click near left hand egde of the letter A event generate $e <Enter> - event generate $e <Button-1> -x $left_x -y $left_y + event generate $e <ButtonPress-1> -x $left_x -y $left_y _pause 50 event generate $e <ButtonRelease-1> -x $left_x -y $left_y _pause 50 - event generate $e <Button-1> -x $left_x -y $left_y + event generate $e <ButtonPress-1> -x $left_x -y $left_y _pause 50 event generate $e <ButtonRelease-1> -x $left_x -y $left_y _pause 50 @@ -755,18 +802,18 @@ test event-7.2(double-click) {A double click on a lone character # Clear selection by clicking at 0,0 - event generate $e <Button-1> -x 0 -y 0 + event generate $e <ButtonPress-1> -x 0 -y 0 _pause 50 event generate $e <ButtonRelease-1> -x 0 -y 0 _pause 50 # Double click near right hand edge of the letter A - event generate $e <Button-1> -x $right_x -y $right_y + event generate $e <ButtonPress-1> -x $right_x -y $right_y _pause 50 event generate $e <ButtonRelease-1> -x $right_x -y $right_y _pause 50 - event generate $e <Button-1> -x $right_x -y $right_y + event generate $e <ButtonPress-1> -x $right_x -y $right_y _pause 50 event generate $e <ButtonRelease-1> -x $right_x -y $right_y _pause 50 @@ -790,7 +837,7 @@ test event-8 {event generate with keysyms corresponding to set e [entry $t.e] pack $e tkwait visibility $e - bind $e <Key> {lappend res keycode: %k keysym: %K} + bind $e <KeyPress> {lappend res keycode: %k keysym: %K} focus -force $e update event generate $e <diaeresis> @@ -815,66 +862,313 @@ test event-8 {event generate with keysyms corresponding to deleteWindows } -result {OK} -test event-9.1 {enter . window by destroying a toplevel - bug b1d115fa60} -setup { - set EnterBind [bind . <Enter>] -} -body { - wm geometry . 200x200+300+300 - wm deiconify . - _pause 200 - toplevel .top2 -width 200 -height 200 - wm geometry .top2 +[expr {[winfo rootx .]+50}]+[expr {[winfo rooty .]+50}] - update idletasks - wm deiconify .top2 - update idletasks - raise .top2 - _pause 400 - event generate .top2 <Motion> -warp 1 -x 50 -y 50 - _pause 100 - bind . <Enter> {lappend res %W} - set res [list ] - destroy .top2 +proc waitForWindowEvent {w event {timeout 1000}} { +# This proc is intended to overcome latency of windowing system +# notifications when toplevel windows are involved. These latencies vary +# considerably with the window manager in use, with the system load, +# with configured scheduling priorities for processes, etc ... +# Waiting for the corresponding window events evades the trouble that is +# associated with the alternative: waiting or halting the Tk process for a +# fixed amount of time (using "after ms"). With the latter strategy it's +# always a gamble how much waiting time is enough on an end user's system. +# It also leads to long fixed waiting times in order to be on the safe side. + + variable _windowEvent + + # Use counter as a unique ID to prevent subsequent waits + # from interfering with each other. + set counter [incr _windowEvent(counter)] + set _windowEvent($counter) 1 + set savedBinding [bind $w $event] + bind $w $event [list +waitForWindowEvent.signal $counter] + set afterID [after $timeout [list set _windowEvent($counter) -1]] + vwait _windowEvent($counter) + set late [expr {$_windowEvent($counter) == -1}] + bind $w $event $savedBinding + unset _windowEvent($counter) + if {$late} { + puts stderr "wait for $event event on $w timed out (> $timeout ms)" + } else { + after cancel $afterID + } +} +proc waitForWindowEvent.signal {counter} { +# Helper proc that records the triggering of a window event. + incr ::_windowEvent($counter) +} + +proc create_and_pack_frames {{w {}}} { + frame $w.f1 -bg blue -width 200 -height 200 + pack propagate $w.f1 0 + frame $w.f1.f2 -bg yellow -width 100 -height 100 + pack $w.f1.f2 $w.f1 -side bottom -anchor se update idletasks - _pause 200 - set res -} -cleanup { - deleteWindows - bind . <Enter> $EnterBind -} -result {.} -test event-9.2 {enter toplevel window by destroying a toplevel - bug b1d115fa60} -setup { - set iconified false - if {[winfo ismapped .]} { - wm iconify . - update - set iconified true +} + +proc setup_win_mousepointer {w} { +# Position the window and the mouse pointer as an initial state for some tests. +# The so-called "pointer window" is the $w window that will now contain the mouse pointer. + wm geometry . +700+400; # root window out of our way - must not cover windows from event-9.1* + toplevel $w + pack propagate $w 0 + wm geometry $w 300x300+100+100 + tkwait visibility $w + update; # service remaining screen drawing events (e.g. <Expose>) + set pointerWin [winfo containing [winfo pointerx $w] [winfo pointery $w]] + event generate $w <Motion> -warp 1 -x 250 -y 250 + if {($pointerWin ne $w) && ([tk windowingsystem] ne "aqua")} { + waitForWindowEvent $w <Enter> + } else { + controlPointerWarpTiming } +} + +test event-9.11 {pointer window container = parent} -setup { + setup_win_mousepointer .one + wm withdraw .one + create_and_pack_frames .one + wm deiconify .one + tkwait visibility .one.f1.f2 + _pause 200; # needed for Windows + update idletasks; # finish display of window + set result "|" } -body { - toplevel .top1 - wm geometry .top1 200x200+300+300 - wm deiconify .top1 - _pause 200 - toplevel .top2 -width 200 -height 200 - wm geometry .top2 +[expr {[winfo rootx .top1]+50}]+[expr {[winfo rooty .top1]+50}] - _pause 200 - wm deiconify .top2 - update idletasks - raise .top2 - _pause 400 - event generate .top2 <Motion> -warp 1 -x 50 -y 50 - _pause 100 - bind .top1 <Enter> {lappend res %W} - set res [list ] - destroy .top2 - _pause 200 - set res + bind all <Leave> {append result "<Leave> %d %W|"} + bind all <Enter> {append result "<Enter> %d %W|"} + destroy .one.f1.f2 + update + set result } -cleanup { - deleteWindows ; # destroy all children of ".", this already includes .top1 - if {$iconified} { - wm deiconify . - update - } -} -result {.top1} + bind all <Leave> {} + bind all <Enter> {} + destroy .one + unset result +} -result {|<Enter> NotifyInferior .one.f1|} + +test event-9.12 {pointer window container != parent} -setup { + setup_win_mousepointer .one + wm withdraw .one + create_and_pack_frames .one + pack propagate .one.f1.f2 0 + pack [frame .one.g -bg orange -width 80 -height 80] -anchor se -side bottom -in .one.f1.f2 + wm deiconify .one + tkwait visibility .one.g + event generate .one <Motion> -warp 1 -x 250 -y 250 + _pause 200; # needed for Windows + set result "|" +} -body { + bind all <Leave> {append result "<Leave> %d %W|"} + bind all <Enter> {append result "<Enter> %d %W|"} + destroy .one.g + update + set result +} -cleanup { + bind all <Leave> {} + bind all <Enter> {} + destroy .one + unset result +} -result {|<Enter> NotifyNonlinearVirtual .one.f1|<Enter> NotifyNonlinear .one.f1.f2|} + +test event-9.13 {pointer window is a toplevel, toplevel destination} -setup { + setup_win_mousepointer .one + toplevel .two + wm geometry .two 300x300+150+150 + wm withdraw .two + wm deiconify .two + waitForWindowEvent .two <Enter> + update idletasks; # finish displaying windows + set result | +} -body { + bind all <Leave> {append result "<Leave> %d %W|"} + bind all <Enter> {append result "<Enter> %d %W|"} + destroy .two + waitForWindowEvent .one <Enter> + update + set result +} -cleanup { + bind all <Leave> {} + bind all <Enter> {} + destroy .one + unset result +} -result {|<Enter> NotifyNonlinear .one|} + +test event-9.14 {pointer window is a toplevel, tk internal destination} -setup { + setup_win_mousepointer .one + wm withdraw .one + create_and_pack_frames .one + toplevel .two + wm geometry .two 300x300+150+150 + wm withdraw .two + wm deiconify .one + wm deiconify .two + waitForWindowEvent .two <Enter> + set result "|" +} -body { + bind all <Leave> {append result "<Leave> %d %W|"} + bind all <Enter> {append result "<Enter> %d %W|"} + destroy .two + waitForWindowEvent .one.f1.f2 <Enter> + set result +} -cleanup { + bind all <Leave> {} + bind all <Enter> {} + destroy .one + unset result +} -result {|<Enter> NotifyNonlinearVirtual .one|<Enter> NotifyNonlinearVirtual .one.f1|<Enter> NotifyNonlinear .one.f1.f2|} + +test event-9.15 {pointer window is a toplevel, destination is screen root} -setup { + setup_win_mousepointer .one; # ensure the mouse pointer is where we want it to be (the .one toplevel is not itself used in this test) +# destroy .one + toplevel .two + wm geometry .two 300x300+150+150 + wm deiconify .two + waitForWindowEvent .two <Enter> + update idletasks; # finish displaying .two + event generate .two <Motion> -warp 1 -x 275 -y 275 + controlPointerWarpTiming + set result "|" +} -body { + bind all <Leave> {append result "<Leave> %d %W|"} + bind all <Enter> {append result "<Enter> %d %W|"} + destroy .two + set result +} -cleanup { + bind all <Leave> {} + bind all <Enter> {} + destroy .one + unset result +} -result {|} + +test event-9.16 {Successive destructions (pointer window + parent), single generation of crossing events} -setup { + # Tests correctness of overwriting the dead window struct in + # TkPointerDeadWindow() and subsequent reading in GenerateEnterLeave(). + setup_win_mousepointer .one + wm withdraw .one + create_and_pack_frames .one + wm deiconify .one + tkwait visibility .one.f1.f2 + update idletasks; # finish displaying window + _pause 200; # needed for Windows + set result "|" +} -body { + bind all <Leave> {append result "<Leave> %d %W|"} + bind all <Enter> {append result "<Enter> %d %W|"} + destroy .one.f1 + update + set result +} -cleanup { + bind all <Leave> {} + bind all <Enter> {} + destroy .one + unset result +} -result {|<Enter> NotifyInferior .one|} + +test event-9.17 {Successive destructions (pointer window + parent), separate crossing events} -setup { + # Tests correctness of overwriting the dead window struct in + # TkPointerDeadWindow() and subsequent reading in GenerateEnterLeave(). + setup_win_mousepointer .one + wm withdraw .one + create_and_pack_frames .one + wm deiconify .one + tkwait visibility .one.f1.f2 + update idletasks; # finish displaying window + _pause 200; # needed for Windows + set result "|" +} -body { + bind all <Leave> {append result "<Leave> %d %W|"} + bind all <Enter> {append result "<Enter> %d %W|"} + destroy .one.f1.f2 + update; # make sure window is gone + destroy .one.f1 + update; # make sure window is gone + set result +} -cleanup { + bind all <Leave> {} + bind all <Enter> {} + destroy .one + unset result +} -result {|<Enter> NotifyInferior .one.f1|<Enter> NotifyInferior .one|} + +test event-9.18 {Successive destructions (pointer window + ancestors including its toplevel), destination is non-root toplevel} -setup { + setup_win_mousepointer .one + toplevel .two + pack propagate .two 0 + wm geometry .two 300x300+100+100 + create_and_pack_frames .two + wm deiconify .two + waitForWindowEvent .two.f1.f2 <Enter> + set result "|" +} -body { + bind all <Leave> {append result "<Leave> %d %W|"} + bind all <Enter> {append result "<Enter> %d %W|"} + destroy .two + waitForWindowEvent .one <Enter> + set result +} -cleanup { + bind all <Leave> {} + bind all <Enter> {} + destroy .one + unset result +} -result {|<Enter> NotifyNonlinear .one|} + +test event-9.19 {Successive destructions (pointer window + ancestors including its toplevel), destination is internal window, bypass root win} -setup { + setup_win_mousepointer .one; # ensure the mouse pointer is where we want it to be (the .one toplevel is not itself used in this test) +# destroy .one + toplevel .two + pack propagate .two 0 + wm geometry .two 300x300+100+100 + create_and_pack_frames .two + wm deiconify .two + toplevel .three + pack propagate .three 0 + wm geometry .three 300x300+110+110 + create_and_pack_frames .three + wm deiconify .three + waitForWindowEvent .three.f1.f2 <Enter> + update idletasks; # finish displaying windows + set result "|" +} -body { + bind all <Leave> {append result "<Leave> %d %W|"} + bind all <Enter> {append result "<Enter> %d %W|"} + destroy .three + waitForWindowEvent .two.f1.f2 <Enter> + update idletasks; #finish destroying .two + set result +} -cleanup { + bind all <Leave> {} + bind all <Enter> {} + destroy .one + destroy .two + unset result +} -result {|<Enter> NotifyNonlinearVirtual .two|<Enter> NotifyNonlinearVirtual .two.f1|<Enter> NotifyNonlinear .two.f1.f2|} + +test event-9.20 {Successive destructions (pointer window + ancestors including its toplevel), destination is screen root} -setup { + setup_win_mousepointer .one; # ensure the mouse pointer is where we want it to be (the .one toplevel is not itself used in this test) + destroy .one + toplevel .two + pack propagate .two 0 + wm geometry .two 300x300+100+100 + create_and_pack_frames .two + wm deiconify .two + waitForWindowEvent .two.f1.f2 <Enter> + set result "|" +} -body { + bind all <Leave> {append result "<Leave> %d %W|"} + bind all <Enter> {append result "<Enter> %d %W|"} + destroy .two + update idletasks; #finish destroying .two + set result +} -cleanup { + bind all <Leave> {} + bind all <Enter> {} + unset result +} -result {|} # cleanup +# macOS sometimes has trouble deleting the test window, +# causing a failure in focus.test. +_pause 200; +deleteWindows update unset -nocomplain keypress_lookup rename _init_keypress_lookup {} @@ -883,6 +1177,8 @@ rename _keypress {} rename _pause {} rename _text_ind_to_x_y {} rename _get_selection {} +rename create_and_pack_frames {} +rename setup_win_mousepointer {} cleanupTests return diff --git a/tests/font.test b/tests/font.test index ca38269..4c1f0de 100644 --- a/tests/font.test +++ b/tests/font.test @@ -2434,15 +2434,15 @@ test font-47.2 {Bug 3049518 - Canvas} -body { set twidth [font measure MyFont $text] set theight [font metrics MyFont -linespace] set circid [$c create polygon \ - 15 15 \ - [expr {15 + $twidth}] 15 \ - [expr {15 + $twidth}] [expr {15 + $theight}] \ - 15 [expr {15 + $theight}] \ - -width 1 -joinstyle round -smooth true -fill {} -outline blue] + 15 15 \ + [expr {15 + $twidth}] 15 \ + [expr {15 + $twidth}] [expr {15 + $theight}] \ + 15 [expr {15 + $theight}] \ + -width 1 -joinstyle round -smooth true -fill {} -outline blue] pack $c -fill both -expand 1 -side top update - # Lamda test functions + # Lambda test functions set circle_text {{w user_data text circ} { if {[winfo class $w] ne "Canvas"} { puts "Wrong widget type: $w" @@ -2468,6 +2468,7 @@ test font-47.2 {Bug 3049518 - Canvas} -body { apply $circle_text $c FontChanged $textid $circid update bind $c <<TkWorldChanged>> [list apply $circle_text %W %d $textid $circid] + update idletasks # Begin test: set results {} diff --git a/tests/pack.test b/tests/pack.test index 0731125..201bf9f 100644 --- a/tests/pack.test +++ b/tests/pack.test @@ -1553,6 +1553,11 @@ test pack-17.2 {PackLostContentProc procedure} -setup { # into account while the window is unmapped. # pack-18.1.2 checks that, on Windows, width/height changes are taken into # account on window remapping. +# +# While these tests pass on macOS, one can see by watching the tests +# that the window .pack is sometimes black, even though the frame is +# colored. So, evidently, even though the size changes are honored, +# the window is sometimes not completely configured. test pack-18.1.1 {unmap content when container unmapped} -constraints { macOrUnix failsOnUbuntu failsOnXQuarz } -setup { @@ -1562,7 +1567,8 @@ test pack-18.1.1 {unmap content when container unmapped} -constraints { # as the screen (screen switch causes scale and other tests to fail). wm geometry .pack +100+100 } -body { - frame .pack.a -width 100 -height 50 -relief raised -bd 2 + frame .pack.a -width 100 -height 50 -relief raised -bd 2 -bg green + after 100 pack .pack.a update set result [winfo ismapped .pack.a] @@ -1585,7 +1591,7 @@ test pack-18.1.2 {unmap content when container unmapped} -constraints { # as the screen (screen switch causes scale and other tests to fail). wm geometry .pack +100+100 } -body { - frame .pack.a -width 100 -height 50 -relief raised -bd 2 + frame .pack.a -width 100 -height 50 -relief raised -bd 2 -bg green pack .pack.a update set result [winfo ismapped .pack.a] @@ -1606,8 +1612,8 @@ test pack-18.2 {unmap content when container unmapped} -constraints {failsOnUbun # as the screen (screen switch causes scale and other tests to fail). wm geometry .pack +100+100 } -body { - frame .pack.a -relief raised -bd 2 - frame .pack.b -width 70 -height 30 -relief sunken -bd 2 + frame .pack.a -relief raised -bd 2 -bg green + frame .pack.b -width 70 -height 30 -relief sunken -bd 2 -bg red pack .pack.a pack .pack.b -in .pack.a update diff --git a/tests/ttk/ttk.test b/tests/ttk/ttk.test index 74cd80a..d099c40 100644 --- a/tests/ttk/ttk.test +++ b/tests/ttk/ttk.test @@ -136,6 +136,8 @@ test ttk-selfdestruct-ok-1 "Intentional self-destruction" -body { # Basic tests. # test ttk-1.1 "Create multiline button showing justified text" -body { + wm geometry . +100+100 + event generate . <Motion> -warp 1 -x 600 -y 600 pack [ttk::button .t -text "Hello\nWorld!!" -justify center] -expand true -fill both update } @@ -152,6 +154,8 @@ test ttk-1.4 "Original style preserved" -body { .t cget -style } -result "" +# Tests using this will fail if the top-level window contains the cursor + proc checkstate {w} { foreach statespec { {!active !disabled} @@ -166,7 +170,6 @@ proc checkstate {w} { set result } -# NB: this will fail if the top-level window pops up underneath the cursor test ttk-2.0 "Check state" -body { checkstate .t } -result [list 1 0 0 0 0 0] diff --git a/tests/unixWm.test b/tests/unixWm.test index 2ad40e2..0a86082 100644 --- a/tests/unixWm.test +++ b/tests/unixWm.test @@ -105,6 +105,7 @@ foreach geom "+20+80 +80+$Y0 +0+$Y0 -0-0 +0-0 -0+$Y0 -10-5 -10+$Y5 +10-5" { set i 1 foreach geom "+20+80 +80+$Y0 +0+$Y0 -0-0 +0-0 -0+$Y0 -10-5 -10+$Y5 +10-5" { test unixWm-3.$i {moving window while iconified} unix { + update wm iconify .t update idletasks wm geom .t $geom @@ -641,6 +642,8 @@ test unixWm-16.1 {Tk_WmCmd procedure, "deiconify" option} unix { test unixWm-16.2 {Tk_WmCmd procedure, "deiconify" option} unix { destroy .icon toplevel .icon -width 50 -height 50 -bg red + # calling update here prevents a crash in 16.3 on macOS + update wm iconwindow .t .icon set result [list [catch {wm deiconify .icon} msg] $msg] destroy .icon @@ -1352,8 +1355,12 @@ test unixWm-38.2 {Tk_WmCmd procedure, "withdraw" option} unix { test unixWm-38.3 {Tk_WmCmd procedure, "withdraw" option} unix { set result {} wm withdraw .t + #added to avoid a crash on macOS + update lappend result [wm state .t] [winfo ismapped .t] wm deiconify .t + #added to avoid a crash on macOS + update lappend result [wm state .t] [winfo ismapped .t] } {withdrawn 0 normal 1} @@ -1373,7 +1380,9 @@ test unixWm-40.1 {Tk_SetGrid procedure, set grid dimensions before turning on gr wm geometry .t } {30x10+0+0} test unixWm-40.2 {Tk_SetGrid procedure, turning on grid when dimensions already set} unix { + update destroy .t + update toplevel .t wm geometry .t 200x100+100+$Y0 listbox .t.l -height 20 -width 20 @@ -1798,6 +1807,8 @@ test unixWm-49.2 {Tk_GetRootCoords procedure, menubars} {unix testmenubar} { } {52 7 12 62} deleteWindows +# Make sure that the root window is out of the way! +wm geom . +700+700 wm withdraw . if {[tk windowingsystem] eq "aqua"} { # Modern mac windows have no border. diff --git a/tests/winfo.test b/tests/winfo.test index d4cc1ff..908647b 100644 --- a/tests/winfo.test +++ b/tests/winfo.test @@ -441,8 +441,10 @@ test winfo-13.3 {destroying container window} -setup { test winfo-13.4 {[winfo containing] with embedded windows} -setup { deleteWindows } -body { + wm geometry . +100+100 frame .con -container 1 pack .con -expand yes -fill both + update toplevel .emb -use [winfo id .con] -bd 0 -highlightthickness 0 button .emb.b pack .emb.b -expand yes -fill both diff --git a/tests/wm.test b/tests/wm.test index d913006..650292d 100644 --- a/tests/wm.test +++ b/tests/wm.test @@ -1084,6 +1084,8 @@ test wm-iconwindow-1.5 {usage} -setup { } -result {.icon is already an icon for .t2} test wm-iconwindow-2.1 {setting and reading values} -setup { + # without this macOS crashes for unknown reasons + wm iconwindow .t {} destroy .icon set result {} } -body { diff --git a/tests/xmfbox.test b/tests/xmfbox.test index 89eda3c..0d3b4d3 100644 --- a/tests/xmfbox.test +++ b/tests/xmfbox.test @@ -54,6 +54,7 @@ proc cleanup {} { } catch {unset foo} destroy .foo + update } # ---------------------------------------------------------------------- @@ -76,6 +77,7 @@ test xmfbox-1.2 {tk::MotifFDialog_Create, -parent switch} -constraints { } -body { toplevel .bar wm geometry .bar +0+0 + update set x [tk::MotifFDialog_Create foo open {-parent .bar}] } -cleanup { destroy $x @@ -89,6 +91,7 @@ test xmfbox-2.1 {tk::MotifFDialog_InterpFilter, ~ in dir names} -constraints { cleanup file mkdir ./~nosuchuser1 set x [tk::MotifFDialog_Create foo open {}] + update $::tk::dialog::file::foo(fEnt) delete 0 end $::tk::dialog::file::foo(fEnt) insert 0 [pwd]/~nosuchuser1 file normalize [file join {*}[tk::MotifFDialog_InterpFilter $x]] @@ -100,6 +103,7 @@ test xmfbox-2.2 {tk::MotifFDialog_InterpFilter, ~ in file names} -constraints { cleanup close [open ./~nosuchuser1 {CREAT TRUNC WRONLY}] set x [tk::MotifFDialog_Create foo open {}] + update $::tk::dialog::file::foo(fEnt) delete 0 end $::tk::dialog::file::foo(fEnt) insert 0 [pwd]/~nosuchuser1 file normalize [file join {*}[tk::MotifFDialog_InterpFilter $x]] @@ -111,6 +115,7 @@ test xmfbox-2.3 {tk::MotifFDialog_Update, ~ in file names} -constraints { cleanup close [open ./~nosuchuser1 {CREAT TRUNC WRONLY}] set x [tk::MotifFDialog_Create foo open {}] + update $::tk::dialog::file::foo(fEnt) delete 0 end $::tk::dialog::file::foo(fEnt) insert 0 [pwd]/~nosuchuser1 tk::MotifFDialog_InterpFilter $x @@ -124,6 +129,7 @@ test xmfbox-2.4 {tk::MotifFDialog_LoadFile, ~ in file names} -constraints { cleanup close [open ./~nosuchuser1 {CREAT TRUNC WRONLY}] set x [tk::MotifFDialog_Create foo open {}] + update set i [lsearch [$::tk::dialog::file::foo(fList) get 0 end] ~nosuchuser1] expr {$i >= 0} } -result 1 @@ -134,6 +140,7 @@ test xmfbox-2.5 {tk::MotifFDialog_BrowseFList, ~ in file names} -constraints { cleanup close [open ./~nosuchuser1 {CREAT TRUNC WRONLY}] set x [tk::MotifFDialog_Create foo open {}] + update set i [lsearch [$::tk::dialog::file::foo(fList) get 0 end] ~nosuchuser1] $::tk::dialog::file::foo(fList) selection clear 0 end $::tk::dialog::file::foo(fList) selection set $i diff --git a/win/tkWinWm.c b/win/tkWinWm.c index f6d3216..4ad0056 100644 --- a/win/tkWinWm.c +++ b/win/tkWinWm.c @@ -2466,6 +2466,33 @@ TkpWmGetState( *-------------------------------------------------------------- */ +static void CheckForPointer(TkWindow *winPtr) +{ + POINT mouse; + int x, y; + unsigned int state = TkWinGetModifierState(); + TkWindow **windows = TkWmStackorderToplevel(winPtr->mainPtr->winPtr); + TkWindow **w; + TkGetPointerCoords(NULL, &x, &y); + mouse.x = x; + mouse.y = y; + if (windows != NULL) { + for (w = windows; *w ; w++) { + RECT windowRect; + HWND hwnd = Tk_GetHWND(Tk_WindowId((Tk_Window) *w)); + if (GetWindowRect(hwnd, &windowRect) == 0) { + continue; + } + if (winPtr != *w && PtInRect(&windowRect, mouse)) { + Tk_Window target = Tk_CoordsToWindow(x, y, (Tk_Window) *w); + Tk_UpdatePointer((Tk_Window) target, x, y, state); + break; + } + } + ckfree(windows); + } +} + void TkWmDeadWindow( TkWindow *winPtr) /* Top-level window that's being deleted. */ @@ -2604,6 +2631,13 @@ TkWmDeadWindow( DecrIconRefCount(wmPtr->iconPtr); } + /* + * Check if the dead window is a toplevel containing the pointer. If so, + * find the window which will inherit the pointer and call + * TkUpdatePointer. + */ + + CheckForPointer(winPtr); ckfree(wmPtr); winPtr->wmInfoPtr = NULL; } @@ -6595,8 +6629,6 @@ TkWmStackorderToplevelEnumProc( TkWmStackorderToplevelPair *pair = (TkWmStackorderToplevelPair *) lParam; - /*fprintf(stderr, "Looking up HWND %d\n", hwnd);*/ - hPtr = Tcl_FindHashEntry(pair->table, hwnd); if (hPtr != NULL) { childWinPtr = (TkWindow *)Tcl_GetHashValue(hPtr); |