Skip to content

tkinter with pre-release versions of Tk 9.0.5 or 8.6.18 drops all events sent to widgets in a hidden window #161428

Closed

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.

  4. ned-deily commented on Nov 10, 2026

    @ned-deily
    Member

    @culler, @serhiy-storchaka What is the consensus on this issue? Is it agreed that it is a Tk regression that needs to be fixed and, if so, is there a Tk issue tracking this? Or is it something else that a tkinter user needs to be aware of? If there is a Tk change needed, it would be good to get it into 9.0.5.

  5. culler commented on Nov 10, 2026

    @culler
    Contributor

    I agree that we should fix it ASAP. I did not see a ticket about it. I think @serhiy-storchaka knows
    what to do about it - I haven't looked at it myself, but I could if necessary.

  6. changed the title [-]macOS 3.13.17 installer: tkinter drops all events sent to widgets in a hidden window[/-] [+]tkinter with pre-release versions of Tk 9.0.5 or 8.6.18 drops all events sent to widgets in a hidden window[/+] on Nov 10, 2026
  7. ned-deily commented on Nov 10, 2026

    @ned-deily
    Member

    Updating the issue title to better reflect the scope of the problem. FTR, this affects the most recent python.org macOS installers (3.13.17, 3.14.9 & .10, 3.15.1 & .2, and 3.16.0a2) which use pre-release versions of Tk to address the critical menu hang issue seen on macOS 27. It could also affect Python builds on other platforms.

  8. added
    3.14bugs and security fixes
    3.15bugs and security fixes
    3.16new features, bugs and security fixes
    on Nov 10, 2026
  9. culler commented on Nov 10, 2026

    @culler
    Contributor

    I looked at the Tk tickets pertinent to this. (At lease one of them was originally reported as a tkinter bug.)

    Here is a synopsis, based on looking at the tickets. The issue was that creating more than 10000 ttk widgets on Windows was causing bad behavior, such as hangs or weird artifacts. The cause was a per-process limit on the number of system handles of a certain type, one of which is associated with each widget. That limit could be exceeded even when most of the widgets involved were never mapped. The fix for thar was to defer the creation of a widget until the first time that it actually gets mapped. That would at least allow 20000 widgets as long as fewer than 10000 of them were mapped. But a widget which does not exist does not receive virtual events, so it is not aware that its theme has changed when it actually gets created on its first map.

    The fix was applied to all platforms. Undoing that change for other platforms would only requjire one #ifndef and one #endif, as far as I can tell.

    Regarding macOS, I should mention that the macOS port of Tk 9.1 will provide a different way of "hiding" windows by setting a new attribute -hidden to True. That causes the window to be removed from the screen but has no effect on its underlying Tk structures. A window hidden in that sense will be able to receive events and will appear to Tk as a normal window. Something which can be used as a substitute for that, to provide a workaround right now, is to "hide" a window by setting its alpha attribute to 0 instead of withdrawing it.

  10. serhiy-storchaka commented on Nov 11, 2026

    @serhiy-storchaka
    Member

    First of all, what is the scope of the issue? Is it the theme change only, or there are other practical cases? I have several options for theme changes, but supporting other events (which may be never needed on practice) may need larger changes.

  11. ThingamabobsCoding commented on Nov 11, 2026

    @ThingamabobsCoding

    As far as I know, people use WM_WITHDRAW only to "hide" the rendering process. A simple, effective and good change would when the window just gets out of screen for it.

    win32: https://github.com/tcltk/tk/blob/main/win/tkWinWm.c#L8862
    Unix: https://github.com/tcltk/tk/blob/main/unix/tkUnixWm.c#L7867
    OSX: https://github.com/tcltk/tk/blob/main/macosx/tkMacOSXWm.c#L7032

    To make this a great change, please update the screen_info to be able to use with multiple monitors. A lazy approach however can be to position the window -10_000 x and y pixel and remove the thumbnail (maybe just call overrideredirct for it) if present. WITHDRAW seems to originate on X-Systems and for every other system it gets copied in its behavior.

  12. culler commented on Nov 11, 2026

    @culler
    Contributor

    Yes, they do that. But it doesn't actually accomplish what they want because the wm withdraw command unmaps the toplevel window and all of its descendants, and unmapped widgets do not get drawn. What actually happens, if you are lucky, is that the drawing takes place during the fade-and-scale animation when the window is restored to the screen. The window and its widgets do get configured to their final size while the window is withdrawn. But they do not get rendered.

    See TIP #765 for more details.

    Better support for multiple monitors would be a good thing. Moving the window to a position out of all monitors is not a good idea.

    Also, this discussion is off-topic for this Python issue. Feel free to move it to the Tcl Core list, after reading the TIP.

  13. culler commented on Nov 12, 2026

    @culler
    Contributor

    The change that led to this behavior has now been reverted in all three Tk branches, so the upcoming release of 9.0.5 will not include it.

  14. ned-deily commented on Nov 13, 2026

    @ned-deily
    Member

    Thanks everyone who was involved with reporting and with fixing this issue. Since the behavior change has now been reverted in the relevant Tk branches (see the Tk issue for the details), I am going to close this issue. The incorrect behavior should disappear as new versions of Tk are released and distributors of Python for macOS update the versions of Tk that they use. In particular, the next releases of the python.org installers for macOS (3.14.11, 3.15.3, and 3.16.0a3) will include this fix.

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 fixes3.14bugs and security fixes3.15bugs and security fixes3.16new features, bugs and 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