Growl Notification - Won't fire notification using framework (Mist)

563 views Asked by At

I'm working on a small wrapper for the Growl 1.3.1 SDK. More specifically, I'd like to package Growl in my application so that even if the user doesn't have Growl, they will still be able to get notifications. I previously had Growl installed and my code would fire a notification. I have since uninstalled Growl and am using just the framework; Mist, I believe it is called. However, when I launch the code now (that Growl is uninstalled), no notification is fired! Below is the code I am currently working with:

#import "growlwrapper.h"

void showGrowlMessage(std::string title, std::string desc) {
    std::cout << "[Growl] showGrowlMessage() called." << std::endl;
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [GrowlApplicationBridge setGrowlDelegate: @""];
    [GrowlApplicationBridge
        notifyWithTitle: [NSString stringWithUTF8String:title.c_str()]
        description: [NSString stringWithUTF8String:desc.c_str()]
        notificationName: @"Upload"
        iconData: nil
        priority: 0
        isSticky: NO
        clickContext: nil
    ];
    [pool drain];
}

int main() {
    showGrowlMessage("Hello World!", "This is a test of the growl system");
    return 0;
}

I also have the appropriate Growl Registration dictionary, and am compiling with:

g++ growlwrapper.mm -framework Growl -framework Foundation -o growltest

Is there anything wrong with this code? Any ideas why it wouldn't be firing?


Edit: Seems the code above is working just fine. Just needed to be in a run loop, with the appropriate Growl dictionary stuff.

1

There are 1 answers

12
ipmcc On BEST ANSWER

I'm not an authority on Growl, but I have a pretty good hunch: When the Growl app is installed, a one-shot notification like this has a prayer to work, because the running app has a run loop and can drive UI from it. In the example you have here, there's no run loop, so there's no way for this one-shot app to ever draw any notifications -- it's dead before it even has a chance. I would guess if you made a boilerplate Cocoa app, and then called showGrowlMessage from applicationDidFinishLaunching:, but before you terminated/quit the app, I bet it would work. At the very least you should give that a try.

EDIT: If you create a new Cocoa non-document application, and add the following methods to the appDelegate class, it will successfully display a notification using the Mist (i.e. in-app) Growl.

@implementation SOAppDelegate

@synthesize window = _window;

- (void)showGrowlMessageTitled: (NSString*)title description:(NSString*) desc
{
    NSLog(@"[Growl] showGrowlMessage() called.");
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [GrowlApplicationBridge notifyWithTitle: title
                                description: desc
                           notificationName: @"Upload"
                                   iconData: nil
                                   priority: 0
                                   isSticky: NO
                               clickContext: nil];
    [pool drain];
}


- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    [GrowlApplicationBridge setGrowlDelegate: (NSObject<GrowlApplicationBridgeDelegate>*)self];
    [self showGrowlMessageTitled: @"Foo" description: @"Bar"];    
}

- (NSDictionary *) registrationDictionaryForGrowl
{
    return [NSDictionary dictionaryWithObjectsAndKeys: 
            [NSArray arrayWithObject: @"Upload"], GROWL_NOTIFICATIONS_ALL,
            [NSArray arrayWithObject: @"Upload"], GROWL_NOTIFICATIONS_DEFAULT,
            nil];
}

@end

So, in short, the problem with the original code was not only the runLoop problem, but that it was not passing a real delegate (i.e. object that implements the delegate methods described in the headers as required) to the GrowlApplicationBridge (it passes an empty string). You definitely still need a runLoop, but that's not all -- there's additional, non-optional setup for using this framework.