2010-06-27 94 views
5

我正在尝试使用Growl Python绑定(来自Growl存储库的Growl.py v0.7)来编写一个小应用程序。目前缺少的功能之一是发送给Python的点击通知。咆哮Python绑定点击反馈?

我知道在Objective-C中,当用户点击通知时,它会向正在运行的应用程序发送一个触发器。我想用Python绑定来做类似的事情。当用户点击通知时,我想让Python程序在浏览器中打开一个URL(或以其他方式处理事件)。

关于我如何实现它的任何想法?

更新:感谢synthesizerpatel谁提供了一个有前途的解决方案,我把他的话在狮子工作。不幸的是,我开始淡出Mac,所以我不再做Mac编程了。虽然,我做了一些调试,因为它仍然不是雪豹工作,并在这里就是为什么:

Discussion Growl PyObjC not working with PyObjC 2.2b3

Source code

+0

这里有什么运气?我也很想知道。 – 2011-02-21 16:15:36

+0

这仍然是一个悬而未决的问题〜 – Patrick 2011-11-01 07:50:52

+0

您是否在寻找这个来捕获所有咆哮通知或者只是一个能够发送咆哮通知并且能够在用户解散它时捕捉鼠标点击的Python应用程序? – synthesizerpatel 2012-02-07 04:50:50

回答

1

这是你想要的吗?

#!/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() 
+0

嗨,感谢您的脚本。不幸的是,它没有为我工作,因为我有雪豹与咆哮1.2.2 – Patrick 2012-02-08 02:52:05

+0

如果有什么你应该有较少的问题,在这种情况下。 :D但是,事实确实如此,这正是你要找的。我很想知道你收到了什么错误信息。 – synthesizerpatel 2012-02-08 07:04:20

+0

是的,我应该提供更多的细节......脚本听起来很有希望,因为我想要的。运行程序后,它创建了两个选项的状态菜单。尽管在点击“Send a Grr!”之后,我只在控制台中收到一条消息,内容是“发送咆哮通知......”,没有实际的Growl通知。 – Patrick 2012-02-08 08:12:12