From: Serhiy Storchaka Date: Mon, 22 Jun 2026 12:13:50 +0000 (+0300) Subject: gh-151874: Add tkinter wm_stackorder, wm_iconbadge and winfo_isdark (GH-151875) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=851b77976025042c9c8c926549841df318886bfb;p=thirdparty%2FPython%2Fcpython.git gh-151874: Add tkinter wm_stackorder, wm_iconbadge and winfo_isdark (GH-151875) Wrap the Tk commands "wm stackorder" (toplevel stacking order, since Tk 8.4), "wm iconbadge" (application icon badge, new in Tk 9.0) and "winfo isdark" (dark mode detection, new in Tk 9.0) as the methods Wm.wm_stackorder(), Wm.wm_iconbadge() and Misc.winfo_isdark(), with the usual stackorder and iconbadge short aliases. Co-authored-by: Claude Opus 4.8 --- diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 222a4d0128bd..fcace71329b3 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -2134,6 +2134,16 @@ Base and mixin classes window; otherwise it refers to the display of the application's main window. + .. method:: winfo_isdark() + + On macOS and Windows, return ``True`` if the widget is in "dark mode", + and ``False`` otherwise. + Always return ``False`` on X11. + + .. versionadded:: next + + Requires Tk 9.1 or newer. + .. method:: winfo_ismapped() Return ``1`` if the widget is currently mapped, ``0`` otherwise. @@ -2605,6 +2615,24 @@ Base and mixin classes empty string. :meth:`wm_group` is an alias of :meth:`!group`. + .. method:: wm_iconbadge(badge) + :no-typesetting: + + .. method:: iconbadge(badge) + + Set a badge for the window's icon, intended for display in the Dock + (macOS), taskbar (Windows) or app panel (X11). + *badge* may be a positive integer (for example a count of unread + messages) or an exclamation point to denote that attention is needed; + an empty string removes the badge. + On X11 the variable ``::tk::icons::base_icon(window)`` must be set to the + window's icon image for the badge to appear. + :meth:`wm_iconbadge` is an alias of :meth:`!iconbadge`. + + .. versionadded:: next + + Requires Tk 9.0 or newer. + .. method:: wm_iconbitmap(bitmap=None, default=None) :no-typesetting: @@ -2814,6 +2842,22 @@ Base and mixin classes has been set. :meth:`wm_sizefrom` is an alias of :meth:`!sizefrom`. + .. method:: wm_stackorder(relation=None, window=None) + :no-typesetting: + + .. method:: stackorder(relation=None, window=None) + + Query the stacking order of top-level windows. + With no arguments, return a list of the mapped top-level widgets in + stacking order, from lowest to highest, recursively including this + window's top-level children. + If *relation* is ``'isabove'`` or ``'isbelow'`` and *window* is another + top-level, return ``True`` if this window is respectively above or below + *window* in the stacking order, and ``False`` otherwise. + :meth:`wm_stackorder` is an alias of :meth:`!stackorder`. + + .. versionadded:: next + .. method:: wm_state(newstate=None) :no-typesetting: diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index 24a767c56e83..8abc4d0af8d1 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -163,6 +163,11 @@ tkinter synchronization of the displayed view with the underlying text. (Contributed by Serhiy Storchaka in :gh:`151675`.) +* Added new window-management methods :meth:`~tkinter.Misc.winfo_isdark` + (dark mode detection), :meth:`~tkinter.Wm.wm_iconbadge` (application icon + badge) and :meth:`~tkinter.Wm.wm_stackorder` (toplevel stacking order). + (Contributed by Serhiy Storchaka in :gh:`151874`.) + xml --- diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index b4cb5aaae1b1..77bf84304e78 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -751,6 +751,12 @@ class WinfoTest(AbstractTkTest, unittest.TestCase): self.root.update() self.assertTrue(f.winfo_viewable()) + @requires_tk(9, 1) + def test_winfo_isdark(self): + self.assertIsInstance(self.root.winfo_isdark(), bool) + if self.root._windowingsystem == 'x11': + self.assertFalse(self.root.winfo_isdark()) + def test_winfo_atom(self): atom = self.root.winfo_atom('PRIMARY') self.assertIsInstance(atom, int) @@ -1057,6 +1063,37 @@ class WmTest(AbstractTkTest, unittest.TestCase): t.transient(self.root) self.assertEqual(str(t.transient()), str(self.root)) + def test_wm_stackorder(self): + t1 = tkinter.Toplevel(self.root) + t2 = tkinter.Toplevel(self.root) + t1.deiconify() + t2.deiconify() + self.root.update() + t1.lift(t2) # Raise t1 above t2. + self.root.update() + order = self.root.wm_stackorder() + self.assertIsInstance(order, list) + self.assertTrue(all(isinstance(w, tkinter.Misc) for w in order)) + names = [str(w) for w in order] + self.assertIn(str(t1), names) + self.assertIn(str(t2), names) + # The list is ordered from lowest to highest, consistently with the + # isabove/isbelow queries. + self.assertGreater(names.index(str(t1)), names.index(str(t2))) + self.assertIs(t1.wm_stackorder('isabove', t2), True) + self.assertIs(t1.wm_stackorder('isbelow', t2), False) + self.assertIs(t2.wm_stackorder('isbelow', t1), True) + + @requires_tk(9, 0) + def test_wm_iconbadge(self): + if self.root._windowingsystem == 'x11': + # On X11 the badge requires ::tk::icons::base_icon to be set. + self.skipTest('iconbadge needs a base icon on X11') + # The badge is not queryable, so just check the call does not fail. + self.root.wm_iconbadge('3') + self.root.wm_iconbadge('!') + self.root.wm_iconbadge('') + class EventTest(AbstractTkTest, unittest.TestCase): diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 8bdf7cc1e2d9..24d229ed74d9 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -1275,6 +1275,15 @@ class Misc: args = ('winfo', 'interps') + self._displayof(displayof) return self.tk.splitlist(self.tk.call(args)) + def winfo_isdark(self): # new in Tk 9.1 + """Return whether this widget is in "dark mode". + + On macOS and Windows return True if the widget is in "dark mode", + and False otherwise. Always return False on X11. + """ + return self.tk.getboolean( + self.tk.call('winfo', 'isdark', self._w)) + def winfo_ismapped(self): """Return true if this widget is mapped.""" return self.tk.getint( @@ -2330,6 +2339,22 @@ class Wm: group = wm_group + def wm_iconbadge(self, badge): # new in Tk 9.0 + """Set a badge for the icon of this widget. + + BADGE can be a positive integer number, for instance the number of + new or unread messages, or an exclamation point denoting attention + needed. If BADGE is an empty string, the badge image is removed from + the application icon. + + The badge is intended for display in the Dock (macOS), taskbar + (Windows) or app panel (X11). On X11, the variable + ::tk::icons::base_icon(WINDOW) must be set to the image used for the + window icon for this command to work.""" + return self.tk.call('wm', 'iconbadge', self._w, badge) + + iconbadge = wm_iconbadge + def wm_iconbitmap(self, bitmap=None, default=None): """Set bitmap for the iconified widget to BITMAP. Return the bitmap if None is given. @@ -2479,6 +2504,25 @@ class Wm: sizefrom = wm_sizefrom + def wm_stackorder(self, relation=None, window=None): + """Query the stacking order of toplevel windows. + + If called with no arguments, return a list of toplevel widgets in + stacking order, from lowest to highest. The list recursively + includes all of this window's children that are toplevels; only + toplevels currently mapped to the screen are included. + + If RELATION is "isabove" or "isbelow" and WINDOW is another toplevel, + return True if this window is respectively above or below WINDOW in + the stacking order, and False otherwise.""" + if relation is None: + return [self._nametowidget(x) for x in self.tk.splitlist( + self.tk.call('wm', 'stackorder', self._w))] + return self.tk.getboolean( + self.tk.call('wm', 'stackorder', self._w, relation, window)) + + stackorder = wm_stackorder + def wm_state(self, newstate=None): """Query or set the state of this widget as one of normal, icon, iconic (see wm_iconwindow), withdrawn, or zoomed (Windows only).""" diff --git a/Misc/NEWS.d/next/Library/2026-06-22-00-46-57.gh-issue-151874.8VtTrq.rst b/Misc/NEWS.d/next/Library/2026-06-22-00-46-57.gh-issue-151874.8VtTrq.rst new file mode 100644 index 000000000000..50a33f5be809 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-22-00-46-57.gh-issue-151874.8VtTrq.rst @@ -0,0 +1,3 @@ +Add the :mod:`tkinter` methods :meth:`!Misc.winfo_isdark`, +:meth:`!Wm.wm_iconbadge` and :meth:`!Wm.wm_stackorder`, wrapping the +``winfo isdark``, ``wm iconbadge`` and ``wm stackorder`` Tk commands.