From 41eda11012414e416fbea698a4e281a6d8a3578e Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 22 Jun 2026 01:51:38 +0300 Subject: [PATCH] gh-151886: Add tkinter Misc.tk_appname, tk_useinputmethods and tk_caret Wrap three long-standing Tk commands that had no tkinter wrapper: * Misc.tk_appname() queries or sets the name used to communicate with the application through the send command (Tk 8.5). * Misc.tk_useinputmethods() queries or sets whether Tk uses the X Input Methods (XIM) for filtering events (Tk 8.5). * Misc.tk_caret() sets or queries the per-display caret location used for accessibility and for placing the input method window (Tk 8.5). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01XWevzas4XVpjzedzR9gKVo --- Doc/library/tkinter.rst | 32 +++++++++++++++ Doc/whatsnew/3.16.rst | 6 +++ Lib/test/test_tkinter/test_misc.py | 23 +++++++++++ Lib/tkinter/__init__.py | 41 +++++++++++++++++++ ...-06-22-01-51-06.gh-issue-151886.MsLlNz.rst | 4 ++ 5 files changed, 106 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-06-22-01-51-06.gh-issue-151886.MsLlNz.rst diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 222a4d0128bd8d..f937a746a60e74 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -1932,6 +1932,38 @@ Base and mixin classes A true *boolean* value enables strict Motif compliance (for example, no color change when the mouse passes over a slider). Return the resulting setting. + + .. method:: tk_appname(name=None) + + Query or set the name used to communicate with this application through + the ``send`` command. + With no argument, return the current name; otherwise change it to *name* + and return the actual name set, which may have a suffix appended to keep + it unique among the applications on the display. + + .. versionadded:: next + + .. method:: tk_useinputmethods(boolean=None, *, displayof=0) + + Query or set whether Tk uses the X Input Methods (XIM) for filtering + events, and return the resulting state. + This is significant only on X11; if XIM support is not available it + always returns ``False``. + + .. versionadded:: next + + .. method:: tk_caret(*, x=None, y=None, height=None) + + Set or query the caret location for the widget's display. + The caret is the per-display insertion position used for global focus + indication (for accessibility) and for placing the input method + (XIM or IME) window. + With no argument, return the current location as a dictionary with the + keys ``'x'``, ``'y'`` and ``'height'``; otherwise update the given + coordinates. + + .. versionadded:: next + .. method:: busy(**kw) :no-typesetting: diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index ec8e367d938ddb..e1321df53c6340 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -157,6 +157,12 @@ tkinter synchronization of the displayed view with the underlying text. (Contributed by Serhiy Storchaka in :gh:`151675`.) +* Added the :meth:`~tkinter.Misc.tk_appname`, + :meth:`~tkinter.Misc.tk_useinputmethods` and :meth:`~tkinter.Misc.tk_caret` + methods, exposing the application send name, the X Input Methods state and + the input method caret location. + (Contributed by Serhiy Storchaka in :gh:`151886`.) + xml --- diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index b4cb5aaae1b1e5..3baa22ec32bd85 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -463,6 +463,29 @@ def test_tk_bisque(self): self.assertEqual(root['background'], '#ffe4c4') self.assertRaises(TypeError, root.tk_bisque, 'x') + def test_tk_appname(self): + old = self.root.tk_appname() + self.assertIsInstance(old, str) + self.addCleanup(self.root.tk_appname, old) + # Setting the name returns the actual name (possibly with a suffix + # appended to keep it unique). + new = self.root.tk_appname('PythonTkTest') + self.assertIsInstance(new, str) + self.assertEqual(self.root.tk_appname(), new) + + def test_tk_useinputmethods(self): + old = self.root.tk_useinputmethods() + self.assertIsInstance(old, bool) + self.addCleanup(self.root.tk_useinputmethods, old) + # Setting returns the resulting state. On systems without XIM support + # the state is always False, so only check the True->False direction. + self.assertIs(self.root.tk_useinputmethods(False), False) + + def test_tk_caret(self): + self.assertIsNone(self.root.tk_caret(x=5, y=10, height=20)) + caret = self.root.tk_caret() + self.assertEqual(caret, {'x': 5, 'y': 10, 'height': 20}) + def test_wait_variable(self): var = tkinter.StringVar(self.root) self.assertEqual(self.root.waitvar, self.root.wait_variable) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 8bdf7cc1e2d96b..e6b54677a648fb 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -745,6 +745,47 @@ def tk_setPalette(self, *args, **kw): self.tk.call(('tk_setPalette',) + _flatten(args) + _flatten(list(kw.items()))) + def tk_appname(self, name=None): + """Query or set the name used to communicate with this application + through the send command. + + With no argument, return the current name; otherwise change it to NAME + and return the actual name set (which may have a suffix appended to + keep it unique).""" + if name is None: + return self.tk.call('tk', 'appname') + return self.tk.call('tk', 'appname', name) + + def tk_useinputmethods(self, boolean=None, *, displayof=0): + """Query or set whether Tk uses the X Input Methods (XIM) for filtering + events, and return the resulting state. + + This is significant only on X11; if XIM support is not available it + always returns False.""" + args = ('tk', 'useinputmethods') + self._displayof(displayof) + if boolean is not None: + args += (boolean,) + return self.tk.getboolean(self.tk.call(args)) + + def tk_caret(self, *, x=None, y=None, height=None): + """Set or query the caret location for this widget's display. + + The caret is the per-display insertion position used for global focus + indication (for accessibility) and for placing the input method + (XIM or IME) window. With no argument, return the current location as + a dictionary with keys 'x', 'y' and 'height'; otherwise update the + given coordinates.""" + args = ('tk', 'caret', self._w) + for option, value in (('-x', x), ('-y', y), ('-height', height)): + if value is not None: + args += (option, value) + if len(args) > 3: + self.tk.call(args) + else: + values = self.tk.splitlist(self.tk.call(args)) + return {values[i][1:]: self.tk.getint(values[i + 1]) + for i in range(0, len(values), 2)} + def wait_variable(self, name='PY_VAR'): """Wait until the variable is modified. diff --git a/Misc/NEWS.d/next/Library/2026-06-22-01-51-06.gh-issue-151886.MsLlNz.rst b/Misc/NEWS.d/next/Library/2026-06-22-01-51-06.gh-issue-151886.MsLlNz.rst new file mode 100644 index 00000000000000..7a454ab95f371f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-22-01-51-06.gh-issue-151886.MsLlNz.rst @@ -0,0 +1,4 @@ +Add the :meth:`!tkinter.Misc.tk_appname`, +:meth:`!tkinter.Misc.tk_useinputmethods` and :meth:`!tkinter.Misc.tk_caret` +methods, wrapping the ``tk appname``, ``tk useinputmethods`` and ``tk caret`` +Tk commands.