Infinidat / infi.systray

Windows system tray icon
BSD 3-Clause "New" or "Revised" License
215 stars 40 forks source link

Provide a way to skip adding the default Quit option #44

Open lordmauve opened 3 years ago

lordmauve commented 3 years ago

I would like a way to avoid adding the default Quit option. I have two reasons:

  1. As my application heads towards production I don't want it to have a Quit option. The application will terminate itself in certain circumstances.
  2. Right now I'm struggling with an issue that is causing deadlocks.

I don't fully understand the deadlock issue but it is bad interaction across threads and it is somehow related to the unique wiring that the "on_quit" option has. The short story is that this works perfectly:

server = ...
tray = SysTrayIcon(..., menu_options=(("Quit", None, server.cancel),))
tray._menu_options.pop()
with tray:
    await server.run()

While

server = ...
with SysTrayIcon(..., on_quit=server.cancel):
    await server.run()

causes deadlocks on context manager exit in any situation other than clicking the "Close" button on the menu, due to some internals of server.cancel().

mirkovich0 commented 2 years ago

Hello. Yes, I'm interested in this too. Also, changing the language would be useful.

Fefedu973 commented 2 years ago

Hi ! just remove this line in "C:\Users\xxxx\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\infi\systray" traybar.py

image

JRiggles commented 1 month ago

FWIW, I was also looking for a way to do this and ultimately I also landed on using pop():

systray = SysTrayIcon(...)
systray._menu_options.pop()
systray.start()

I never feel great using private attributes like this, but it works.

I did notice, however, that if you define no menu options at all then the app will quit (or maybe crash, but there's no error message) after you double-click the system tray icon. I suspect this has to do with this (per the README):

When the user double-clicks the systray icon, the first option specified in menu_options will be executed.

To get around this, you can define a menu item that just does nothing, but at least one menu item has to exist.

# this menu item does nothing but display some text
# if you leave the text blank, you'll still get an empty rectangle
menu_options = (('v1.0.0', None, lambda _systray: None),)

NB: changing default_menu_index doesn't work and will most likely just throw a KeyError