Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions Doc/library/tkinter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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:

Expand Down Expand Up @@ -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:

Expand Down
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.16.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
---
Expand Down
37 changes: 37 additions & 0 deletions Lib/test/test_tkinter/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,12 @@ def test_winfo_viewable(self):
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)
Expand Down Expand Up @@ -1057,6 +1063,37 @@ def test_wm_transient(self):
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):

Expand Down
44 changes: 44 additions & 0 deletions Lib/tkinter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1275,6 +1275,15 @@ def winfo_interps(self, displayof=0):
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(
Expand Down Expand Up @@ -2330,6 +2339,22 @@ def wm_group(self, pathName=None):

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.
Expand Down Expand Up @@ -2479,6 +2504,25 @@ def wm_sizefrom(self, who=None):

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)."""
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Loading