Tk Source Code

Artifact [e0190519]
Login

Artifact e01905195bab16fac45cda5d94b680b81d3a863c0d72c455ab7d0b40b1fa7991:

Attachment "crossing_events_upon_pw_destroy.patch" to ticket [22349fc7] added by erikleunissen 2024-02-18 13:45:46.
diff -ur --exclude tkBind.c --exclude option.test tk.old/generic/tkPointer.c tk.new/generic/tkPointer.c
--- tk.old/generic/tkPointer.c	2022-06-06 18:40:39.000000000 +0200
+++ tk.new/generic/tkPointer.c	2024-02-18 09:46:05.000000000 +0100
@@ -33,6 +33,10 @@
 				 * reported. */
     TkWindow *cursorWinPtr;	/* Window that is currently controlling the
 				 * global cursor. */
+    int pwIsDead;		/* 1 if destroyed, 0 if not */
+    TkWindow deadWin;		/* Replacement for a destroyed pointer
+				 * window, used as the source window for
+				 * generating crossing events. */
 } ThreadSpecificData;
 static Tcl_ThreadDataKey dataKey;
 
@@ -131,7 +135,28 @@
     TkWindow *restrictWinPtr = tsdPtr->restrictWinPtr;
     TkWindow *lastWinPtr = tsdPtr->lastWinPtr;
 
-    if (winPtr != tsdPtr->lastWinPtr) {
+    if (tsdPtr->pwIsDead) {
+	XEvent event;
+	TkWindow *deadWinPtr = &tsdPtr->deadWin;
+	TkWindow *targetPtr = deadWinPtr->parentPtr;
+
+	if (targetPtr && (targetPtr->window != None)) {
+
+	    /*
+	     * Only generate Enter events. We can't deliver Leave events
+	     * since the windows to receive them don't exist anymore.
+	     */
+
+	    InitializeEvent(&event, targetPtr, EnterNotify, x, y, state,
+		    NotifyInferior);
+	    TkInOutEvents(&event, deadWinPtr, winPtr, 0,
+		    EnterNotify, TCL_QUEUE_TAIL);
+	}
+
+	tsdPtr->lastWinPtr = winPtr;
+	tsdPtr->pwIsDead = 0;
+	crossed = 1;
+    } else if (winPtr != lastWinPtr) {
 	if (restrictWinPtr) {
 	    int newPos, oldPos;
 
@@ -178,7 +203,8 @@
 		XEvent event;
 
 		/*
-		 * Generate appropriate Enter/Leave events.
+		 * Generate Enter/Leave events for the old and new pointer
+		 * window and their intermediates.
 		 */
 
 		InitializeEvent(&event, targetPtr, LeaveNotify, x, y, state,
@@ -189,6 +215,7 @@
 		crossed = 1;
 	    }
 	}
+
 	tsdPtr->lastWinPtr = winPtr;
     }
 
@@ -495,7 +522,18 @@
 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
 
     if (winPtr == tsdPtr->lastWinPtr) {
-	tsdPtr->lastWinPtr = TkGetContainer(winPtr);
+	TkWindow *deadWinPtr = &tsdPtr->deadWin;
+	tsdPtr->pwIsDead = 1;
+
+	/*
+	 * Save the pointer window information that GenerateEnterLeave()
+	 * needs for generating crossing events.
+	 */
+
+	deadWinPtr->parentPtr = winPtr->parentPtr;
+	deadWinPtr->flags = winPtr->flags;
+
+	tsdPtr->lastWinPtr = winPtr->parentPtr;
     }
     if (winPtr == tsdPtr->grabWinPtr) {
 	tsdPtr->grabWinPtr = NULL;