Index: .github/workflows/linux-build.yml ================================================================== --- .github/workflows/linux-build.yml +++ .github/workflows/linux-build.yml @@ -3,10 +3,11 @@ push: branches: - "main" - "core-8-branch" - "core-8-6-branch" + - "bug-47d4f29159" tags: - "core-**" permissions: contents: read defaults: Index: .github/workflows/mac-build.yml ================================================================== --- .github/workflows/mac-build.yml +++ .github/workflows/mac-build.yml @@ -3,10 +3,11 @@ push: branches: - "main" - "core-8-branch" - "core-8-6-branch" + - "bug-47d4f29159" tags: - "core-**" permissions: contents: read env: Index: .github/workflows/win-build.yml ================================================================== --- .github/workflows/win-build.yml +++ .github/workflows/win-build.yml @@ -3,10 +3,11 @@ push: branches: - "main" - "core-8-branch" - "core-8-6-branch" + - "bug-47d4f29159" tags: - "core-**" permissions: contents: read env: Index: doc/ttk_panedwindow.n ================================================================== --- doc/ttk_panedwindow.n +++ doc/ttk_panedwindow.n @@ -115,13 +115,11 @@ \fBinstate\fR \fBstate\fR .DE .SH "VIRTUAL EVENTS" .PP The panedwindow widget generates an \fB<>\fR virtual event on -LeaveNotify/NotifyInferior events, because Tk does not execute binding scripts -for events when the pointer crosses from a parent to a child. The -panedwindow widget needs to know when that happens. +LeaveNotify/NotifyInferior events. .SH "STYLING OPTIONS" .PP The class name for a \fBttk::panedwindow\fP is \fBTPanedwindow\fP. The sash has a class name of \fBSash\fP. .PP Index: generic/tkBind.c ================================================================== --- generic/tkBind.c +++ generic/tkBind.c @@ -2196,36 +2196,21 @@ dispPtr = ((TkWindow *) tkwin)->dispPtr; bindInfoPtr = winPtr->mainPtr->bindInfo; curEvent = bindPtr->eventInfo + eventPtr->type; /* - * Ignore the event completely if it is an Enter, Leave, FocusIn, or - * FocusOut event with detail NotifyInferior. The reason for ignoring - * these events is that we don't want transitions between a window and its - * children to be visible to bindings on the parent: this would cause - * problems for mega-widgets, since the internal structure of a - * mega-widget isn't supposed to be visible to people watching the parent. - * - * Furthermore we have to compute current time, needed for "event generate". + * Compute current time needed for "event generate", + * and reset counters for Key and Button events. */ switch (eventPtr->type) { case EnterNotify: case LeaveNotify: if (eventPtr->xcrossing.time) { bindInfoPtr->lastCurrentTime = CurrentTimeInMilliSecs(); bindInfoPtr->lastEventTime = eventPtr->xcrossing.time; } - if (eventPtr->xcrossing.detail == NotifyInferior) { - return; - } - break; - case FocusIn: - case FocusOut: - if (eventPtr->xfocus.detail == NotifyInferior) { - return; - } break; case KeyPress: case KeyRelease: { int reset = 1; Index: generic/tkCanvas.c ================================================================== --- generic/tkCanvas.c +++ generic/tkCanvas.c @@ -4961,13 +4961,21 @@ event = canvasPtr->pickEvent; event.type = LeaveNotify; /* - * If the event's detail happens to be NotifyInferior the binding - * mechanism will discard the event. To be consistent, always use - * NotifyAncestor. + * Behaviour before ticket #47d4f29159: + * If the event's detail happens to be NotifyInferior the binding + * mechanism will discard the event. To be consistent, always use + * NotifyAncestor. + * + * Behaviour after ticket #47d4f29159: + * The binding mechanism doesn't discard events with detail field + * NotifyInferior anymore. It would be best to base the detail + * field on the ancestry relationship between the old and new + * canvas items. For the time being, retain the choice from before + * ticket #47d4f29159, which doesn't harm. */ event.xcrossing.detail = NotifyAncestor; canvasPtr->flags |= REPICK_IN_PROGRESS; CanvasDoEvent(canvasPtr, &event); Index: generic/tkTextTag.c ================================================================== --- generic/tkTextTag.c +++ generic/tkTextTag.c @@ -1801,13 +1801,21 @@ && !(textPtr->flags & DESTROYED)) { event = textPtr->pickEvent; event.type = LeaveNotify; /* - * Always use a detail of NotifyAncestor. Besides being - * consistent, this avoids problems where the binding code will - * discard NotifyInferior events. + * Behaviour before ticket #47d4f29159: + * Always use a detail of NotifyAncestor. Besides being + * consistent, this avoids problems where the binding code will + * discard NotifyInferior events. + * + * Behaviour after ticket #47d4f29159: + * The binding mechanism doesn't discard events with detail field + * NotifyInferior anymore. It would be best to base the detail + * field on the ancestry relationship between the old and new + * tags. For the time being, retain the choice from before + * ticket #47d4f29159, which doesn't harm. */ event.xcrossing.detail = NotifyAncestor; TagBindEvent(textPtr, &event, numOldTags, oldArrayPtr); } Index: generic/ttk/ttkPanedwindow.c ================================================================== --- generic/ttk/ttkPanedwindow.c +++ generic/ttk/ttkPanedwindow.c @@ -467,18 +467,20 @@ }; /*------------------------------------------------------------------------ * +++ Event handler. * - * <> - * Tk does not execute binding scripts for events when - * the pointer crosses from a parent to a child. This widget - * needs to know when that happens, though, so it can reset - * the cursor. - * * This event handler generates an <> virtual event * on LeaveNotify/NotifyInferior. + * This was originally introduced because Tk used to discard events with + * detail field NotifyInferior. The <> event was then used + * to reset the cursor when the pointer crosses from a parent to a child. + * Since ticket #47d4f29159, LeaveNotify/NotifyInferior are no longer + * discarded: the event will trigger even with NotifyInferior + * detail field. The generated <> is nevertheless kept for + * backwards compatibility purpose since it is publicly documented, + * meaning that someone could bind to it. */ static const unsigned PanedEventMask = LeaveWindowMask; static void PanedEventProc(ClientData clientData, XEvent *eventPtr) { Index: generic/ttk/ttkWidget.c ================================================================== --- generic/ttk/ttkWidget.c +++ generic/ttk/ttkWidget.c @@ -240,12 +240,10 @@ * * For Expose and Configure, simply schedule the widget for redisplay. * For Destroy events, handle the cleanup process. * * For Focus events, set/clear the focus bit in the state field. - * It turns out this is impossible to do correctly in a binding script, - * because Tk filters out focus events with detail == NotifyInferior. * * For Deactivate/Activate pseudo-events, set/clear the background state * flag. */ Index: library/ttk/panedwindow.tcl ================================================================== --- library/ttk/panedwindow.tcl +++ library/ttk/panedwindow.tcl @@ -20,12 +20,10 @@ bind TPanedwindow { ttk::panedwindow::Release %W %x %y } bind TPanedwindow { ttk::panedwindow::SetCursor %W %x %y } bind TPanedwindow { ttk::panedwindow::SetCursor %W %x %y } bind TPanedwindow { ttk::panedwindow::ResetCursor %W } -# See <> -bind TPanedwindow <> { ttk::panedwindow::ResetCursor %W } ## Sash movement: # proc ttk::panedwindow::Press {w x y} { variable State Index: tests/bind.test ================================================================== --- tests/bind.test +++ tests/bind.test @@ -572,11 +572,11 @@ event generate .t.f return $x } -cleanup { destroy .t.f } -result {{.t.f z (.t.f binding)} {.t.f z (.t.f