pyobjc icon indicating copy to clipboard operation
pyobjc copied to clipboard

How to make MPRemoteCommandCenter work while loop is running on a secondary thread

Open cosven opened this issue 2 years ago • 2 comments

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

middle_img_v2_52ea7d27-a617-46c7-a79d-ede5b480420g

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

cosven avatar May 11 '22 17:05 cosven

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

ronaldoussoren avatar May 15 '22 08:05 ronaldoussoren

Thanks for your detailed explanation. I'll have a try for the two methods and give some feedback lator.

cosven avatar May 16 '22 02:05 cosven

I'm closing this issue because it not an issue with PyObjC itself.

ronaldoussoren avatar Jan 22 '23 10:01 ronaldoussoren