Closed glight2000 closed 2 years ago
I looked through the code a bit, but I've not yet been able to sort out where in pystray the problem is. I don't see it on windows nor linux.
It works good on my windows system but not on MacOS.
@moses-palmer has been responsive in the past to my questions, so hoping he's got some cycles to look at this one.
Thank you for your report.
What version of pynput do you use? This looks very much like a bug that was fixed in version 0.17.3. is it possible for you to upgrade?
Personally I was at 1.6.5. I'm upgrading now and will let you know if I see anything on my Windows system.
Thank you for answering on a Sunday. Appreciate you taking time on your weekend to help out.
c:\python\pycharmprojects>pip show pynput
Name: pynput
Version: 1.6.5
Summary: Monitor and control user input devices
Home-page: https://github.com/moses-palmer/pynput
Author: Moses Palmér
Author-email: moses.palmer@gmail.com
License: LGPLv3
Location: c:\python\anaconda3\lib\site-packages
Requires: six
Required-by:
c:\python\pycharmprojects>pip install --upgrade pynput
Collecting pynput
Downloading pynput-1.7.3-py2.py3-none-any.whl (99 kB)
|████████████████████████████████| 99 kB 3.2 MB/s
Requirement already satisfied, skipping upgrade: six in c:\python\anaconda3\lib\site-packages (from pynput) (1.16.0)
Installing collected packages: pynput
Attempting uninstall: pynput
Found existing installation: pynput 1.6.5
Uninstalling pynput-1.6.5:
Successfully uninstalled pynput-1.6.5
Successfully installed pynput-1.7.3
@moses-palmer @PySimpleGUI Thank you taking time on this.
Here is pynput info which my conda env is using. Looks like it is already the latest version.
Name: pynput
Version: 1.7.3
Summary: Monitor and control user input devices
Home-page: https://github.com/moses-palmer/pynput
Author: Moses Palmér
Author-email: moses.palmer@gmail.com
License: LGPLv3
Location: /Users/username/anaconda3/envs/envname/lib/python3.9/site-packages
Requires: pyobjc-framework-Quartz, six
Required-by:
@glight2000, I looked through the psgtray source code. As noted in the documentation, the pystray.Icon.run
method must be called from the main thread; for all but macOS, this is just a recommendation, but because of limitations in the operating system, it will not work on macOS.
I am afraid that I will have to close this issue, as the bug is in another library, and I see no workaround in pystray.
Can you tell us which library the problem is in?
If the problem is one layer down in the cake, then I would like to be able to go have a chat/look/log an issue with that layer.
Given the error is that the attribute is missing, this seems like a locking error where code should have held up until the threaded initialization completes. Can you perhaps add some protection so that the timing is right for the threaded version to work?
I noticed in your release notes this info:
v0.17.3 - macOS and AppIndicator bug fixes Let the default timeout for notifications when using the AppIndicator backend be decided by the desktop environment, not infinity. Thanks to Angelo Naselli! Do not attempt to create a menu before the icon has started on macOS
I'll check my code to see how the timing of showing an icon is compared to when the icon has started.
Is there a particular technique you recommend for checking to see that the "icon has started on macOS"?
For example, will this startup sequence fail on the Mac because the Menu is created prior to calling tray_icon.run()
? I think it's the "has started" part that I'm confused on.
self.tray_icon = pystray.Icon(self.title, self._create_image(self.icon))
self.tray_icon.default_action = self._default_action_callback
self.tray_icon.menu = pystray.Menu(*self.menu_items)
self.tray_icon.title = self.tooltip # tooltip for the icon
self.thread_started = True
self.tray_icon.run()
The problem lies in psgtray which attempts to start a thread in which to run the system tray code. This is not supported on macOS.
If I remove almost all code from the _run
implementation and leave only self._app.run()
which is absolutely necessary, I get the following error message in the console:
2021-10-11 05:07:34.367 Python[15732:137393] WARNING: nextEventMatchingMask should only be called from the Main Thread! This will throw an exception in the future.
2021-10-11 05:07:34.367 Python[15732:137393] *** Assertion failure in +[NSUndoManager _endTopLevelGroupings], /AppleInternal/BuildRoot/Library/Caches/com.apple.xbs/Sources/Foundation/Foundation-1677.104/Foundation/Misc.subproj/NSUndoManager.m:363
2021-10-11 05:07:34.368 Python[15732:137393] *** Assertion failure in +[NSUndoManager _endTopLevelGroupings], /AppleInternal/BuildRoot/Library/Caches/com.apple.xbs/Sources/Foundation/Foundation-1677.104/Foundation/Misc.subproj/NSUndoManager.m:363
An error occurred in the main loop
Traceback (most recent call last):
File "/Users/moses/src/pystray/lib/pystray/_darwin.py", line 115, in _run
self._app.run()
objc.error: NSInternalInconsistencyException - +[NSUndoManager(NSInternal) _endTopLevelGroupings] is only safe to invoke on the main thread.
This is a problem when integrating with other loop driven frameworks, since they also must hijack the main thread. To solve it on the pystray side would require some changes of API's to allow injecting a foreign NSApplication
instance, and adding another way to run it apart from the blocking run
.
This would be a rather pointless exercise, though, if the framework to integrate with did not provide the means to cooperate. I have no experience with Tkinter; do you know if it is possible to get access to the presumed NSApplication
used inside?
This would be a rather pointless exercise, though, if the framework to integrate with did not provide the means to cooperate. I have no experience with Tkinter; do you know if it is possible to get access to the presumed NSApplication used inside?
And right over the top of my head goes Moses! I don't know what an NSApplication
is, so I'm worthless in the short-term.
I've been super-impressed by your work on pystray in getting it to run as a thread. It's really opened up the possibilities with tkinter and PySimpleGUI. I've finally got a solid way of communicating with threads and the PySimpleGUI event loop so that integrating with them is trivial now.
Thank you for looking into all this. I really appreciate it. I know it's an obscure kind of thing. The Mac support is hellish to say the least. I've got a special config window just for Mac settings.
This is one of the last issues until I am ready for a version 1.0, so I decided to put some effort into it.
If you find the time, please have a look at the branch feature-run-detached. It introduces the new method run_detached
to allow running the icon in a non-blocking fashion. Please consult the documentation for more information, and see below for how to acquire the NSApplication
instance:
import AppKit
darwin_nsapplication = AppKit.NSApplication.sharedApplication()
Oh. Thank you both for your help, very much. Expecting the new version:)
OH WOW Moses, thank you SO SO SO much!!
Do I need to make changes to my code with the new version?
It sounds like I may need to perhaps re-architect how I'm running it now since I'm running it as a thread rather than doing any kind of protocol that is non-blocking.
Any hints are appreciated!
You will need to make some small changes to your application.
Icon.run
instead calls Icon.run_detached
.darwin_nsapplication
as a keyword argument to Icon.__init__
. See my comment above for to to get a reference; if you can get this from Tkinter, use that instead.I'm having a similar issue. I am running an asyncio project. In windows something like this worked. run-detached seems to block my service working. If I run run_detached its crashing python in macOS and fails to launch the icon.
providing darwin_nsapplication stops the other error just fails to launch.
loop.create_task(run_in_threadpool(app.startSystray))
loop.create_task(server.serve())
loop.create_task(app.app_start())
loop.run_forever()
run_in_threadpool is a starlette import
Just running this crashes python launcher in macOS.
app.startSystrayDetached()
loop.run_forever()
Or this
loop.create_task(run_in_threadpool(app.startSystrayDetached))
I believe loop.run_forever() is making it fail to launch
My icon setup looks like this. I am using tkinter also but cant see any reference to get the shared application
if sys.platform == 'darwin':
import AppKit
darwin_nsapplication = AppKit.NSApplication.sharedApplication()
else:
darwin_nsapplication = None
self.icon = icon(settings.SYSTRAY_TITLE,
icon=self.off_icon(),
title=settings.SYSTRAY_TITLE,
menu=menu(
....
),
darwin_nsapplication=darwin_nsapplication
)
I think its asyncio crashing the python launcher. Just running "run()" shows an icon. run_detached with an asyncio loop doesn't. I need an asyncio loop running to dispatch tasks to async methods on click events ie
def on_tray_stop(self) -> None:
"""Stopped from system tray menu or websocket."""
loop.create_task(self.on_stop())
I think there is a bug with asyncio and the threading call. My code launches but the icon does not.
The only way for this to work on mac is to reverse what goes to another thread. Keep this as the mainloop and send the uvicorn asyncio process to another thread. So run_detached is not useful. If I run run_detached before the asyncio calls the icon never displays.
@danrossi, your analysis of using run_detached
with asyncio is correct; run_detached
is only useful when integrating with a library that provides a platform mainloop, such as a Windows event loop, a glib mainloop or for macOS, a running NSApplication
.
@danrossi, your analysis of using
run_detached
with asyncio is correct;run_detached
is only useful when integrating with a library that provides a platform mainloop, such as a Windows event loop, a glib mainloop or for macOS, a runningNSApplication
.
so what is correct way to use run_detached in MacOS, i am facing the same problem because i need my python app working on background on Mac. Could you provide some example code for doing that?
I'm using psgtray(which feature is being supplied by pystray) for system tray. When run the sample code(page:https://github.com/PySimpleGUI/psgtray)on my mac os 11.6. I got a error:AttributeError: 'Icon' object has no attribute '_status_item'. Full error stack:
I also posted an issue here:
https://github.com/PySimpleGUI/psgtray/issues/2
.