0

I need to detect when the user pressed "quit" in the dock menu.

My application is actually just a launcher for the backend server of a web interface. I keep it in the dock menu by manually waiting for the launched process to end (with poll and sleep). The actvity monitor showed it as not responding so I added a native function to process events like "touches". Not responding flag is now gone, but the user cannot quit this application (because the native functions processes the event, I guess).

I used ctypes to access that native function.

TVB = subprocess.popen(args)
coreFoundation = cdll.LoadLibrary('/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation')

CFRunLoopRunInMode = coreFoundation.CFRunLoopRunInMode                  # the native function
CFRunLoopRunInMode.restype = c_int32                                    # its return type
CFRunLoopRunInMode.argtypes = [ c_void_p, c_double, c_bool ]            # its arguments types

defaultMode = c_void_p.in_dll(coreFoundation, u'kCFRunLoopDefaultMode') # the default mode to process events
sleepTime = c_double(5)                                                 # the duration to process the events
retAfterSourceHandled = c_bool(0)                                       # do NOT return after processing

while not TVB.poll():                                                   # keep alive as long as TVB is alive
    CFRunLoopRunInMode(defaultMode, sleepTime, retAfterSourceHandled)
    sleep(5)
    #detect 'quit' here and stop TVB, then quit

I will also consider other solutions to CFRunLoopRunInMode... Something like processNextEvent() would be ideal.

1 Answer 1

2

A possible solution to this problem is to use PyObjC and a custom UIApplicationDelegate implementation.

    import AppKit
    import Foundation
    from PyObjCTools import AppHelper

    class ApplicationDelegate(Foundation.NSObject):
        """ MAC OS UI specific Delegate class """

        def applicationDidFinishLaunching_(self, notification):
            """ Here you could register a timer to pull your sub-processes, for example. """
            pass

        def applicationWillTerminate_(self, notification):
            """ This is the hook you get for when the user clicks QUIT in dock """
            pass

    app = AppKit.NSApplication.sharedApplication()
    delegate = ApplicationDelegate.alloc().init()
    app.setDelegate_(delegate)
    AppHelper.runEventLoop()

In the end PyObjC is not much different than the ctypes loads you tried, but it has some helper methods (like AppKit.NSRunLoop.currentRunLoop(), or AppHelper.stopEventLoop()) which could make the python code clearer.

For this solution I assume to have a Python project further packed for deployment with py2app. I used pyObjc version 2.3 (installed with easy_install in Python 2.7 on Mac OS x 10.7.5).

Not the answer you're looking for? Browse other questions tagged or ask your own question.