1

Is there a way to change WM_CLASS of showinfo (and other dialogs)? className, class_ parameters do the job for Tk, Toplevel.

import tkinter as tk
from tkinter.messagebox import showinfo

if __name__ == '__main__':
    root = tk.Tk(className='ymail')
    mail_client = tk.Toplevel(root, class_='ymail')
    new_message = tk.Toplevel(root, class_='ymail')
    showinfo(title="Cancel sending", parent=new_message, message="""
Send is cancelled due to empty message""")
    root.mainloop()

For showinfo dialog

$ xprop WM_CLASS

gives

WM_CLASS(STRING) = "__tk__messagebox", "Dialog"

I think it is convenient to cycle tkinter windows with Alt-~ (Tilde), for which their WM_CLASS shall be the same.

I did the search ("tkinter change WM_CLASS showinfo"). Some of the hits are not applicable, some don't work (xdotool), and some I'd rather use as a last resort (converting C program to python).

Using    
Debian 10    
python 3.7.3    
GNOME 3.30.1

EDIT
Added workaround (using xdotool)

import threading
import subprocess
import time
import tkinter as tk
from tkinter.messagebox import showinfo


def change_dialog_class(from_="Dialog", to_="ymail"):
    cmd = f"xdotool search --class {from_} set_window --class {to_}"
    time.sleep(1)
    subprocess.run(cmd.split())


if __name__ == '__main__':
    root = tk.Tk(className='ymail')
    mail_client = tk.Toplevel(root, class_='ymail')
    new_message = tk.Toplevel(root, class_='ymail')
    tk.Frame.class_ = 'ymail'
    threading.Thread(target=change_dialog_class, args=("Dialog", "ymail"),
                     daemon=True).start()
    showinfo(title="Cancel sending", parent=new_message,
             message="""Send is cancelled due to empty message""")
    root.mainloop()

along with ymail.desktop it works

$ cat ~/.local/share/applications/ymail.desktop
[Desktop Entry]
Type=Application
Terminal=false
Name=ymail
Icon=python
StartupWMClass=ymail

yet, the python solution would be better

  • Its unclear what you actual need help with. Tkinter uses system native widgets and makes it easy to use them. I'm unsure how to address your question in my response. Could you add a propose to this? You may looking for something different. – Thingamabobs May 15 '22 at 17:15
  • when I run the code from the post I have 4 windows. For all of them but the dialog xprop outputs WM_CLASS(STRING) = "ymail", "Ymail" . I'd like to have the same for the dialog too. – Vladimir Zolotykh May 15 '22 at 17:25
  • Since I'm not a XSystem user it took me some time to follow up. It seems like that you are looking for `wm_group` and unfortunately it isnt possible without subclassing it, which results in pretty much the same as writing your own class with `tk.Toplevel`. Anyway I hope `toplevel.wm_group(root)` ease things out and works for you. – Thingamabobs May 15 '22 at 18:31

1 Answers1

1

Since I'm not a XSystem user it took me some time to follow up. It seems like that you are looking for wm_group and unfortunately it isnt possible without subclassing it, which results in pretty much the same as writing your own class with tk.Toplevel. Anyway I hope toplevel.wm_group(root) ease things out and works for you.

After I noticed that the SimpleDialog may has some functionality that you want to keep and can be hard to code for yourself, I decided to write an answer that you may want to use. It also provides the class_ option in case wm_group dosent work for you.

Here is the code:

import tkinter as tk
import tkinter.simpledialog as simpledialog

class MessageBox(simpledialog.SimpleDialog):
    def __init__(self, master,**kwargs):
        simpledialog.SimpleDialog.__init__(self,master,**kwargs)
        #root.tk.call('wm', 'group', self.root._w, master)
    def done(self,num):
        print(num)
        self.root.destroy()
        

root = tk.Tk()
MessageBox(root,title='Cancel',text='Im telling you!',class_='ymail',
           buttons=['Got it!','Nah'], default=None, cancel=None)
root.mainloop()

and here is the source: https://github.com/python/cpython/blob/main/Lib/tkinter/simpledialog.py#L31

Thingamabobs
  • 7,274
  • 5
  • 21
  • 54
  • GNOME manager treats MessageBox (your example) and its parent as one window. It is reasonable and differs from what I have seen before (for tkinter.messagebox). xprop output for both is the same. I'd like to unserstand why. – Vladimir Zolotykh May 17 '22 at 09:51
  • @VladimirZolotykh Without the possibility to check it myself, but I'm almost certain of it, it must be because this window ist handle as `transient`. You could request it by yourself via `toplevel.transient(master)` – Thingamabobs May 17 '22 at 10:31