I'm trying to use the Growl Python bindings (Growl.py v0.7 from the Growl repository) to write a small application. One of the features that's currently missing is the click notification sent to Python.
I know in Objective-C, when a user clicks the notification, it will send a trigger to the running application. I'd like to do a similar thing with the Python bindings. When a user clicks a notification, I'd like to have the Python program open a URL in the browser (or handle the event in another manner).
Any thoughts on how I might accomplish it?
Update: thanks to synthesizerpatel who provides a promising solution and I take his words it worked on Lion. Unfortunately, I'm beginning to fade out from Mac, so I don't do much Mac programming anymore. Though, I did some debugging as it's still not working on Snow Leopard, and here is why:
Discussion Growl PyObjC not working with PyObjC 2.2b3
Source code
Is this what you want?
#!/usr/bin/env python
#
# pyGrr!
#
# This code was originally found @
# http://www.cocoaforge.com/viewtopic.php?f=6&t=13359&p=91992&hilit=pyobjc+growl
# It is (to the best of our knowledge) the work of user 'tooru' on the same
# website.
#
# I make no claim to this code, all I did was get it working with PyObjC on Lion
# reformatted it a bit and added some more verbose explanations of what the script
# does. To be honest, I haven't touched pyobjc in a couple years and I was amazed
# that it still works! Even more amazed that I was able to get this example working
# in about 20 minutes.
#
# Great job tooru!
#
# I have verified this code works with the following combination of
# packages / versions
#
# * OSX Lion 10.7.3
# * Python 2.7
# * Growl 1.3
# * Growl SDK 1.3.1
#
#
# - Nathan Ramella [email protected] (http://www.remix.net)
##################################################################################
import objc
from Foundation import *
from AppKit import *
from PyObjCTools import AppHelper
import time
import sys
import os
myGrowlBundle = objc.loadBundle(
"GrowlApplicationBridge",
globals(),
bundle_path = objc.pathForFramework(
'/Library/Frameworks/Growl.framework'
)
)
class MenuMakerDelegate(NSObject):
"""
This is a delegate for Growl, a required element of using the Growl
service.
There isn't a requirement that delegates actually 'do' anything, but
in this case, it does. We'll make a little menu up on the status bar
which will be named 'pyGrr!'
Inside the menu will be two options, 'Send a Grr!', and 'Quit'.
Send a Grr! will emit a growl notification that when clicked calls back
to the Python code so you can take some sort of action - if you're that
type of person.
"""
statusbar = None
state = 'idle'
def applicationDidFinishLaunching_(self, notification):
"""
Setup the menu and our menu items. Getting excited yet?
"""
statusbar = NSStatusBar.systemStatusBar()
# Create the statusbar item
self.statusitem = statusbar.statusItemWithLength_(NSVariableStatusItemLength)
self.statusitem.setHighlightMode_(1) # Let it highlight upon clicking
self.statusitem.setToolTip_('pyGrr!') # Set a tooltip
self.statusitem.setTitle_('pyGrr!') # Set an initial title
# Build a very simple menu
self.menu = NSMenu.alloc().init()
menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(
'Send a Grr!',
'rcNotification:',
''
)
self.menu.addItem_(menuitem)
# Default event
menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(
'Quit',
'terminate:',
''
)
self.menu.addItem_(menuitem)
# Bind it to the status item
self.statusitem.setMenu_(self.menu)
def rcNotification_(self,notification):
"""
This is run when you select the 'Send a Grr!' menu item. It
will lovingly bundle up a Grr and send it Growl's way.
"""
print "Sending a growl notification at", time.time()
GrowlApplicationBridge.notifyWithTitle_description_notificationName_iconData_priority_isSticky_clickContext_(
"Grr! - I'm a title!",
"This is where you put notification information.",
"test1",
None,
0,
False,
"this ends up being the argument to your context callback"
)
class rcGrowl(NSObject):
"""
rcGrowl registers us with Growl to send out Grrs on behalf
of the user and do 'something' with the results when a
Grr has been clicked.
For additional information on what the what is going on
please refer to the growl dox @
http://growl.info/documentation/developer/implementing-growl.php
"""
def rcSetDelegate(self):
GrowlApplicationBridge.setGrowlDelegate_(self)
def registrationDictionaryForGrowl(self):
"""
http://growl.info/documentation/developer/implementing-growl.php#registration
"""
return {
u'ApplicationName' : 'rcGrowlMacTidy',
u'AllNotifications' : ['test1'],
u'DefaultNotifications' : ['test1'],
u'NotificationIcon' : None,
}
# don't know if it is working or not
def applicationNameForGrowl(self):
"""
Identifies the application.
"""
return 'rcGrowlMacTidy'
#def applicationIconDataForGrowl(self):
"""
If you wish to include a custom icon with the Grr,
you can do so here. Disabled by default since I didn't
want to bloat up this up
"""
#icon = NSImage.alloc().init()
#icon = icon.initWithContentsOfFile_(u'remix_icon.tiff')
#return icon
def growlNotificationWasClicked_(self, ctx):
"""
callback for onClick event
"""
print "we got a click! " + str(time.time()) + " >>> " + str(ctx) + " <<<\n"
def growlNotificationTimedOut_(self, ctx):
"""
callback for timing out
"""
print "We timed out" + str(ctx) + "\n"
def growlIsReady(self):
"""
Informs the delegate that GrowlHelperApp was launched
successfully. Presumably if it's already running it
won't need to run it again?
"""
print "growl IS READY"
if __name__ == "__main__":
# Both 'growlnotify' and this script seem to have the following
# error after emitting a Grr!
#
# Error Domain=GCDAsyncSocketErrorDomain Code=4 "Read operation timed out"
# UserInfo=0x7fa444e00070 {NSLocalizedDescription=Read operation timed out}
#
# So, we redirect stderr to /dev/null so that it doesn't muck up
# the output of this script. Some folks say upgrading Growl fixes it,
# others still have the problem. Doesn't seem to make much of a difference
# one way or another, things still seem to work regardless.
fp = os.open('/dev/null', os.O_RDWR|os.O_CREAT, 0o666)
dupped = os.dup(2)
os.dup2(fp, 2)
# set up system statusbar GUI
app = NSApplication.sharedApplication()
delegate = MenuMakerDelegate.alloc().init()
app.setDelegate_( delegate )
# set up growl delegate
rcGrowlDelegate=rcGrowl.new()
rcGrowlDelegate.rcSetDelegate()
AppHelper.runEventLoop()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With