Skip to content

macOS 3.13.17 installer: tkinter drops all events sent to widgets in a hidden window #161428

Open

Description

@israel-dryer

Bug report

With the python.org macOS installer for 3.13.17, widgets inside a hidden toplevel (withdrawn, or iconified) receive no events. This includes events sent synchronously with event_generate and ttk's <<ThemeChanged>>. The events are dropped rather than deferred: none are delivered after the window is shown. 3.13.16 with the same Tk patchlevel (8.6.18) delivers them all, as do Windows and Linux builds.

import sys
import tkinter as tk
from tkinter import ttk

root = tk.Tk()
print("python", sys.version.split()[0], "tk", root.tk.call("info", "patchlevel"))


def run(label, hide):
    top = tk.Toplevel(root)
    hide(top)
    frame = ttk.Frame(top, width=50, height=50)
    hits = []
    for ev in ("<Enter>", "<<Custom>>", "<<ThemeChanged>>"):
        frame.bind(ev, lambda e, ev=ev: hits.append(ev), "+")
    frame.pack()
    root.update()
    frame.event_generate("<Enter>")
    frame.event_generate("<<Custom>>")
    style = ttk.Style()
    style.theme_use("alt" if style.theme_use() != "alt" else "clam")
    root.update()
    hidden = list(hits)
    top.deiconify()
    root.update()
    print(f"{label:24} while hidden: {hidden}  after show: {hits[len(hidden):]}")
    top.destroy()


def shown_then_withdrawn(top):
    root.update()
    top.withdraw()
    root.update()


run("never shown, withdrawn", lambda t: t.withdraw())
run("shown, then withdrawn", shown_then_withdrawn)
run("iconified", lambda t: t.iconify())
root.destroy()

3.13.16 (expected):

python 3.13.16 tk 8.6.18
never shown, withdrawn   while hidden: ['<<ThemeChanged>>', '<Enter>', '<<Custom>>', '<<ThemeChanged>>']  after show: []
shown, then withdrawn    while hidden: ['<Enter>', '<<Custom>>', '<<ThemeChanged>>']  after show: []
iconified                while hidden: ['<Enter>', '<<Custom>>', '<<ThemeChanged>>']  after show: []

3.13.17 (actual):

python 3.13.17 tk 8.6.18
never shown, withdrawn   while hidden: []  after show: []
shown, then withdrawn    while hidden: []  after show: []
iconified                while hidden: []  after show: []

Both runs are on the same GitHub Actions macos-latest image (macos-26-arm64, 20261102.0473.1), using the python.org builds installed by actions/setup-python.

Practical effect: apps that build windows while hidden (a common pattern to avoid visible re-layout), or that update hidden or minimized windows through virtual events, silently lose those updates. For example, a ttk theme switch doesn't reach hidden windows.

CPython versions tested on:

3.13

Operating systems tested on:

macOS

Activity

  1. ned-deily commented on Nov 6, 2026

    @ned-deily
    Member

    As noted on the 3.13.17 release page, "The macOS installer for this release is built with a pre-release of Tk [8.6], fixing a possible hang on macOS 27.0 in applications using tkinter, like IDLE, in older releases." #158053 links to the 8.6 pre-release source used. Presumably, the difference in behavior is due to some change in Tk since the 8.6.18 release and prior to the snapshot of the Tk core-8-6-branch.

    However, your test case also fails with the current python.org macOS Python 3.15.2 which used a post-9.0.4 snapshot of the Tk core-9-0-branch (to also get around the menu hang on macOS 27) but behaves as expected using the 3.15.0 installer which was built with the Tk 9.0.4 release.

    Perhaps @culler has an idea whether this was a known issue and is fixed in the upcoming 9.0.5 release?

    (Keep in mind that Python 3.13 has now reached the security-fix-only phase of its release cycle which means that only source code is included in future releases and no binaries including no installers for macOS or Windows. The latest release, 3.13.18, was source-only.)

  2. ThingamabobsCoding commented on Nov 6, 2026

    @ThingamabobsCoding

    Arranges for window to be withdrawn from the screen. This causes the window to be unmapped and forgotten about by the window manager. If the window has never been mapped, then this command causes the window to be mapped in the withdrawn state. Not all window managers appear to know how to handle windows that are mapped in the withdrawn state. Note that it sometimes seems to be necessary to withdraw a window and then re-map it (e.g. with wm deiconify) to get some window managers to pay attention to changes in window attributes such as group See: https://www.tcl-lang.org/man/tcl9.0/TkCmd/wm.html#M72

    Withdrawn is a special state, you could to try to refactor to use overrideredirect in combination with a fully transparent window or positioning the window outside of the screen. I prefer to show a loading screen btw but this may take some more considerations

  3. serhiy-storchaka commented on Nov 6, 2026

    @serhiy-storchaka
    Member

    This is a Tk regression. The fix for Tk ticket 88ffa70453 (3d4a73e5eba6, 2026-10-20) stopped realizing a ttk widget when it is created, and both snapshots contain it.

    Generated events have always been silently dropped for a widget whose window does not exist yet, as they still are for classic widgets. ttk widgets were the exception since 2008, and they have now lost it. Calling winfo_id() on the widget restores delivery.

    It is not macOS-specific, and not fixed in the upcoming 9.0.5. I will report it upstream.

    The same change breaks several tkinter and IDLE tests, tracked in gh-161441.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.13only security fixestopic-tkintertype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions