pyobjc
pyobjc copied to clipboard
How to make MPRemoteCommandCenter work while loop is running on a secondary thread
I think this is a question instead of a bug.
Background
I want to implement nowplaying for a PyQt5 application on macOS. The code in gist also works well. However, PyQt5 already has it's own event loop and I can't run two loop on a single thread. I don't know how to run the AppKit Loop on a secondary thread, can you please help me?
When the code runs properly, the playing center looks like this
Problem I try to run the loop on the secondary thread, and it does not work.
# Here is my code which trying to run the loop in a secondary thread.
t = threading.Thread(target=runloop)
t.start()
t.join()
Platform information
- Python version: 3.9
- macOS version: 12.0.1
One problem is with this function:
def runloop():
"""
HELP: This function can't be called in non-main thread.
"""
nowplaying = NowPlaying()
NSRunLoop.mainRunLoop().run()
As the docstring says this won't run on a non-main thread. Fixing that is easy enough: use currentRunLoop()
instead of mainRunLoop()
to fetch the runloop for the current thread.
That said, I don't know if this will fix your problem. A lot of GUI related APIs on macOS only work on the main thread, unless they are explicitly documented as working with multiple threads.
This qt bug report mentions that setting QT_EVENT_DISPATCHER_CORE_FOUNDATION=1
in the environment results in using the Cocoa runloop in the implementation of the Qt runloop. That may take away the need to use a different thread of the two loops:
- Use
os.putenv
to set the environment variable before importing Qt - Create the
NowPlaying
instance on the main thread - Don't run the
NSRunloop.run()
method, but use the Qt event loop as normal
Thanks for your detailed explanation. I'll have a try for the two methods and give some feedback lator.
I'm closing this issue because it not an issue with PyObjC itself.