Search code examples
pythonosx-mountain-lionpyobjcnsusernotification

Working with Mountain Lion's Notification Center using PyObjC


I'm trying to send notifications to Mountain Lion from my python script and react to clicks on the notifications. Sending the notifications works perfectly find by now. But yet I was not able to get Lion to call back my script upon a click.

Here is what I do. I implemented a Notification class. The only purpose of an instance of that class is to provide notifications by invoking notify(). In the same method I set the object the app's delegate.

import Foundation
import objc
import AppKit

class MountainLionNotification(Foundation.NSObject, Notification):

    def notify(self, title, subtitle, text, url):
        NSUserNotification = objc.lookUpClass('NSUserNotification')
        NSUserNotificationCenter = objc.lookUpClass('NSUserNotificationCenter')
        notification = NSUserNotification.alloc().init()
        notification.setTitle_(str(title))
        notification.setSubtitle_(str(subtitle))
        notification.setInformativeText_(str(text))
        notification.setSoundName_("NSUserNotificationDefaultSoundName")
        notification.setUserInfo_({"action":"open_url", "value":url})
        AppKit.NSApplication.sharedApplication().setDelegate_(self)
        NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification)

    def applicationDidFinishLaunching_(self, sender):
        userInfo = sender.userInfo()
        if userInfo["action"] == "open_url":
            import subprocess
            subprocess.Popen(['open', userInfo["value"]])

Now I expected applicationDidFinishLaunching_() to be called upon a click on the notification. Unfortunately that never happens. What am I doing wrong?


Solution

  • Ok, found it. Didn't run AppHelper.runEventLoop(). Obviously a facepalm mistake. The following code works:

    class MountainLionNotification(Foundation.NSObject, Notification):
    
        def notify(self, title, subtitle, text, url):
            NSUserNotification = objc.lookUpClass('NSUserNotification')
            NSUserNotificationCenter = objc.lookUpClass('NSUserNotificationCenter')
            notification = NSUserNotification.alloc().init()
            notification.setTitle_(str(title))
            notification.setSubtitle_(str(subtitle))
            notification.setInformativeText_(str(text))
            notification.setSoundName_("NSUserNotificationDefaultSoundName")
            notification.setHasActionButton_(True)
            notification.setOtherButtonTitle_("View")
            notification.setUserInfo_({"action":"open_url", "value":url})
            NSUserNotificationCenter.defaultUserNotificationCenter().setDelegate_(self)
            NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification)
    
        def userNotificationCenter_didActivateNotification_(self, center, notification):
            userInfo = notification.userInfo()
            if userInfo["action"] == "open_url":
                import subprocess
                subprocess.Popen(['open', userInfo["value"]])