From e4fbaea258605ad01892f783375433c8bf613270 Mon Sep 17 00:00:00 2001 From: culler Date: Tue, 21 May 2024 22:42:45 +0000 Subject: Only 9.13, 9.14. and 9.19 fail on windows. Debug output included. --- generic/tkGrab.c | 21 +++++++++++++++++++-- generic/tkPointer.c | 11 +++++++++-- generic/tkWindow.c | 5 ++--- tests/event.test | 11 ++++++++++- win/tkWinWm.c | 39 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 79 insertions(+), 8 deletions(-) diff --git a/generic/tkGrab.c b/generic/tkGrab.c index c8e5253..b4228bd 100644 --- a/generic/tkGrab.c +++ b/generic/tkGrab.c @@ -998,6 +998,10 @@ TkInOutEvents( { TkWindow *winPtr; int upLevels, downLevels, i, j, focus; +#define NAME(w) (w ? Tk_PathName(w) : "NULL") + + fprintf(stderr, "TkInOutEvents: %s -> %s\n", + NAME(sourcePtr), NAME(destPtr)); /* * There are four possible cases to deal with: @@ -1029,7 +1033,7 @@ TkInOutEvents( /* * Generate enter/leave events and add them to the grab event queue. */ - + #define QUEUE(w, t, d) \ if (w->window != None) { \ eventPtr->type = t; \ @@ -1043,19 +1047,24 @@ TkInOutEvents( Tk_QueueWindowEvent(eventPtr, position); \ } +#define DBGEV(w, t, d) fprintf(stderr, " Queueing %s %s for %s\n", t, d, NAME(w)) + if (downLevels == 0) { /* * SourcePtr is an inferior of destPtr. */ if (leaveType != 0) { + DBGEV(sourcePtr, "", "NotifyAncestor"); QUEUE(sourcePtr, leaveType, NotifyAncestor); for (winPtr = sourcePtr->parentPtr, i = upLevels-1; i > 0; winPtr = winPtr->parentPtr, i--) { + DBGEV(winPtr, "", "NotifyVirtual"); QUEUE(winPtr, leaveType, NotifyVirtual); } } if ((enterType != 0) && (destPtr != NULL)) { + DBGEV(destPtr, "", "NotifyVirtual"); QUEUE(destPtr, enterType, NotifyInferior); } } else if (upLevels == 0) { @@ -1064,6 +1073,7 @@ TkInOutEvents( */ if ((leaveType != 0) && (sourcePtr != NULL)) { + DBGEV(sourcePtr, "", "NotifyInferior"); QUEUE(sourcePtr, leaveType, NotifyInferior); } if (enterType != 0) { @@ -1072,9 +1082,11 @@ TkInOutEvents( winPtr = winPtr->parentPtr, j++) { /* empty */ } + DBGEV(winPtr, "", "NotifyVirtual"); QUEUE(winPtr, enterType, NotifyVirtual); } if (destPtr != NULL) { + DBGEV(winPtr, "", "NotifyVirtual"); QUEUE(destPtr, enterType, NotifyAncestor); } } @@ -1084,10 +1096,12 @@ TkInOutEvents( */ if (leaveType != 0) { + DBGEV(sourcePtr, "", "NotifyNonlinear"); QUEUE(sourcePtr, leaveType, NotifyNonlinear); for (winPtr = sourcePtr->parentPtr, i = upLevels-1; i > 0; winPtr = winPtr->parentPtr, i--) { - QUEUE(winPtr, leaveType, NotifyNonlinearVirtual); + DBGEV(winPtr, "", "NotifyNonlinearVirtual"); + QUEUE(winPtr, leaveType, NotifyNonlinearVirtual); } } if (enterType != 0) { @@ -1095,13 +1109,16 @@ TkInOutEvents( for (winPtr = destPtr->parentPtr, j = 1; j < i; winPtr = winPtr->parentPtr, j++) { } + DBGEV(winPtr, "", "NotifyNonlinearVirtual"); QUEUE(winPtr, enterType, NotifyNonlinearVirtual); } if (destPtr != NULL) { + DBGEV(destPtr, "", "NotifyNonlinear"); QUEUE(destPtr, enterType, NotifyNonlinear); } } } + fflush(stderr); } /* diff --git a/generic/tkPointer.c b/generic/tkPointer.c index be05b06..df26de1 100644 --- a/generic/tkPointer.c +++ b/generic/tkPointer.c @@ -228,7 +228,10 @@ Tk_UpdatePointer( unsigned changes = (state ^ tsdPtr->lastState) & ALL_BUTTONS; int type, b; unsigned mask; - + fprintf(stderr, "TkUpdatePointer: %s -> %s\n", + tsdPtr->lastWinPtr ? Tk_PathName(tsdPtr->lastWinPtr) : "NULL", + tkwin ? Tk_PathName(tkwin) : "NULL"); + fflush(stderr); pos.x = x; pos.y = y; @@ -493,8 +496,11 @@ TkPointerDeadWindow( { ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - + fprintf(stderr, "TkPointerDeadWindow: %s\n", winPtr ? Tk_PathName(winPtr) : "NULL"); if (winPtr == tsdPtr->lastWinPtr) { + //This fails on Windows because the windows version of TkWnDeadWindow + //does not (yet) call TkUpdatePointer when a dead toplevel contains the + //pointer. tsdPtr->lastWinPtr = TkGetContainer(winPtr); } if (winPtr == tsdPtr->grabWinPtr) { @@ -514,6 +520,7 @@ TkPointerDeadWindow( TkpSetCapture(NULL); } } + fflush(stderr); } /* diff --git a/generic/tkWindow.c b/generic/tkWindow.c index e322bb4..e8c56dd 100644 --- a/generic/tkWindow.c +++ b/generic/tkWindow.c @@ -1328,12 +1328,11 @@ static void SendEnterLeaveForDestroy( { #if defined(MAC_OSX_TK) || defined(_WIN32) int x, y; - unsigned int state; + unsigned int state = TkWinGetModifierState(); Tk_Window pointerWin; TkWindow *containerPtr; - XQueryPointer(Tk_Display(tkwin), None, NULL, NULL, &x, &y, - NULL, NULL, &state); + TkGetPointerCoords(NULL, &x, &y); pointerWin = Tk_CoordsToWindow(x, y, tkwin); if (pointerWin == tkwin) { if (!Tk_IsTopLevel(tkwin)) { diff --git a/tests/event.test b/tests/event.test index 6388533..42f28f5 100644 --- a/tests/event.test +++ b/tests/event.test @@ -873,6 +873,7 @@ proc waitForWindowEvent {w event {timeout 1000}} { # 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. + puts stderr "Waiting for $event on $w" variable _windowEvent # Use counter as a unique ID to prevent subsequent waits @@ -890,6 +891,7 @@ proc waitForWindowEvent {w event {timeout 1000}} { puts stderr "wait for $event event on $w timed out (> $timeout ms)" } else { after cancel $afterID + puts stderr "Event received" } } proc waitForWindowEvent.signal {counter} { @@ -981,6 +983,7 @@ test event-9.12 {pointer window container != parent} -setup { } -result {| NotifyNonlinearVirtual .one.f1| NotifyNonlinear .one.f1.f2|} test event-9.13 {pointer window is a toplevel, toplevel destination} -setup { + puts stderr "9.13 setup started" setup_win_mousepointer .one toplevel .two wm geometry .two 300x300+150+150 @@ -989,11 +992,14 @@ test event-9.13 {pointer window is a toplevel, toplevel destination} -setup { waitForWindowEvent .two bind all {append result " %d %W|"} bind all {append result " %d %W|"} - set result "|" + set result | + puts stderr "9.13 setup done" } -body { + puts stderr "9.13 body started - destroying .two" destroy .two waitForWindowEvent .one set result + puts stderr "9.13 body finished" } -cleanup { bind all {} bind all {} @@ -1002,6 +1008,7 @@ test event-9.13 {pointer window is a toplevel, toplevel destination} -setup { } -result {| NotifyNonlinear .one|} test event-9.14 {pointer window is a toplevel, tk internal destination} -setup { + puts stderr "9.14 setup" setup_win_mousepointer .one wm withdraw .one create_and_pack_frames .one @@ -1015,9 +1022,11 @@ test event-9.14 {pointer window is a toplevel, tk internal destination} -setup { bind all {append result " %d %W|"} set result "|" } -body { + puts stderr "9.14 body" destroy .two waitForWindowEvent .one.f1.f2 set result + puts stderr "9.14 body finished" } -cleanup { bind all {} bind all {} diff --git a/win/tkWinWm.c b/win/tkWinWm.c index 90503a6..146b82b 100644 --- a/win/tkWinWm.c +++ b/win/tkWinWm.c @@ -2577,6 +2577,36 @@ TkpWmGetState( *-------------------------------------------------------------- */ +static void CheckForPointer(TkWindow *winPtr) +{ + Display *display = Tk_Display(winPtr); + POINT mouse; + unsigned int state = TkWinGetModifierState(); + TkWindow **windows = TkWmStackorderToplevel(winPtr->mainPtr->winPtr); + TkWindow **w; + TkGetPointerCoords(NULL, &mouse.x, &mouse.y); + fprintf(stderr, "CheckForPointer: %s with mouse @(%d, %d)\n", + Tk_PathName(winPtr), mouse.x, mouse.y); + if (windows != NULL) { + for (w = windows; *w ; w++) { + RECT windowRect; + HWND hwnd = Tk_GetHWND(Tk_WindowId((Tk_Window) *w)); + fprintf(stderr, " Checking %s\n", Tk_PathName(*w)); + if (GetWindowRect(hwnd, &windowRect) == 0) { + continue; + } + if (winPtr != *w && PtInRect(&windowRect, mouse)) { + fprintf(stderr, "Pointer is in %s. Calling Tk_UpdatePointer\n", + Tk_PathName(*w)); + Tk_UpdatePointer((Tk_Window) *w, mouse.x, mouse.y, state); + break; + } + } + ckfree(windows); + } + fflush(stderr); +} + void TkWmDeadWindow( TkWindow *winPtr) /* Top-level window that's being deleted. */ @@ -2715,6 +2745,15 @@ 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); + //TkPointerDeadWindow(winPtr); + ckfree(wmPtr); winPtr->wmInfoPtr = NULL; } -- cgit v0.12