|
evands@2183
|
1 |
//
|
|
evands@2183
|
2 |
// GrowlMenu.m
|
|
evands@2183
|
3 |
//
|
|
evands@2183
|
4 |
//
|
|
evands@2183
|
5 |
// Created by rudy on Sun Apr 17 2005.
|
|
evands@2183
|
6 |
// Copyright (c) 2005 The Growl Project. All rights reserved.
|
|
evands@2183
|
7 |
//
|
|
evands@2183
|
8 |
|
|
evands@2183
|
9 |
#import "GrowlMenu.h"
|
|
ofri@2448
|
10 |
#import "GrowlPreferencesController.h"
|
|
ingmarstein@2470
|
11 |
#import "GrowlPathUtilities.h"
|
|
eridius@2773
|
12 |
//#import "GrowlPluginController.h"
|
|
ingmarstein@2673
|
13 |
#include <unistd.h>
|
|
evands@2183
|
14 |
|
|
evands@2183
|
15 |
#define kRestartGrowl NSLocalizedString(@"Restart Growl", @"")
|
|
evands@2183
|
16 |
#define kRestartGrowlTooltip NSLocalizedString(@"Restart Growl", @"")
|
|
evands@2183
|
17 |
#define kStartGrowl NSLocalizedString(@"Start Growl", @"")
|
|
evands@2183
|
18 |
#define kStartGrowlTooltip NSLocalizedString(@"Start Growl", @"")
|
|
evands@2183
|
19 |
#define kStopGrowl NSLocalizedString(@"Stop Growl", @"")
|
|
evands@2183
|
20 |
#define kStopGrowlTooltip NSLocalizedString(@"Stop Growl", @"")
|
|
evands@2183
|
21 |
#define kDefaultDisplay NSLocalizedString(@"Default display", @"")
|
|
evands@2183
|
22 |
#define kDefaultDisplayTooltip NSLocalizedString(@"Set the default display style", @"")
|
|
rudy@2840
|
23 |
#define kOpenGrowlPreferences NSLocalizedString(@"Open Growl Preferences...", @"")
|
|
evands@2183
|
24 |
#define kOpenGrowlPreferencesTooltip NSLocalizedString(@"Open the Growl preference pane", @"")
|
|
ofri@2449
|
25 |
#define kSquelchMode NSLocalizedString(@"Log only, don't display", @"")
|
|
evands@2183
|
26 |
#define kSquelchModeTooltip NSLocalizedString(@"Don't show notifications, but still log them", @"")
|
|
rudy@2836
|
27 |
#define kStopGrowlMenu NSLocalizedString(@"Hide Status Item", @"")
|
|
eridius@2773
|
28 |
#define kStopGrowlMenuTooltip NSLocalizedString(@"Hide this status item", @"")
|
|
eridius@2773
|
29 |
#define kStickyWhenAwayMenu NSLocalizedString(@"Sticky Notifications", @"")
|
|
eridius@2773
|
30 |
#define kStickyWhenAwayMenuTooltip NSLocalizedString(@"Toggles the sticky notification state", @"")
|
|
ingmarstein@2594
|
31 |
#define kDefaultDisplayChanged NSLocalizedString(@"Default display changed to %@", @"")
|
|
evands@2183
|
32 |
|
|
evands@2183
|
33 |
int main(void) {
|
|
evands@2183
|
34 |
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
|
evands@2183
|
35 |
[NSApplication sharedApplication];
|
|
evands@2183
|
36 |
|
|
boredzo@4140
|
37 |
GrowlMenu *menu = [[[GrowlMenu alloc] init] autorelease];
|
|
evands@2183
|
38 |
[NSApp setDelegate:menu];
|
|
evands@2183
|
39 |
[NSApp run];
|
|
evands@2183
|
40 |
|
|
evands@2183
|
41 |
// dead code
|
|
evands@2183
|
42 |
[pool release];
|
|
evands@2183
|
43 |
|
|
evands@2183
|
44 |
return EXIT_SUCCESS;
|
|
evands@2183
|
45 |
}
|
|
evands@2183
|
46 |
|
|
evands@2183
|
47 |
@implementation GrowlMenu
|
|
evands@2183
|
48 |
|
|
evands@2183
|
49 |
- (void) applicationDidFinishLaunching:(NSNotification *)aNotification {
|
|
evands@2183
|
50 |
#pragma unused(aNotification)
|
|
ingmarstein@2673
|
51 |
pid = getpid();
|
|
boredzo@2496
|
52 |
preferences = [GrowlPreferencesController sharedController];
|
|
evands@2183
|
53 |
|
|
evands@2183
|
54 |
NSMenu *m = [self createMenu];
|
|
evands@2183
|
55 |
|
|
evands@2183
|
56 |
statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
|
|
evands@2183
|
57 |
|
|
evands@2183
|
58 |
NSBundle *bundle = [NSBundle mainBundle];
|
|
evands@2183
|
59 |
|
|
evands@2183
|
60 |
clawImage = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"growlmenu" ofType:@"png"]];
|
|
evands@2183
|
61 |
clawHighlightImage = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"growlmenu-alt" ofType:@"png"]];
|
|
evands@2183
|
62 |
squelchImage = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"squelch" ofType:@"png"]];
|
|
evands@2183
|
63 |
|
|
evands@2183
|
64 |
[self setImage];
|
|
evands@2183
|
65 |
|
|
evands@2183
|
66 |
[statusItem setMenu:m]; // retains m
|
|
evands@2183
|
67 |
[statusItem setToolTip:@"Growl"];
|
|
evands@2183
|
68 |
[statusItem setHighlightMode:YES];
|
|
evands@2183
|
69 |
|
|
evands@2183
|
70 |
[m release];
|
|
evands@2183
|
71 |
|
|
ingmarstein@2206
|
72 |
[self setGrowlMenuEnabled:YES];
|
|
ingmarstein@2206
|
73 |
|
|
evands@2183
|
74 |
NSNotificationCenter *nc = [NSDistributedNotificationCenter defaultCenter];
|
|
ingmarstein@2357
|
75 |
[nc addObserver:self
|
|
ingmarstein@2357
|
76 |
selector:@selector(shutdown:)
|
|
evands@2183
|
77 |
name:@"GrowlMenuShutdown"
|
|
evands@2183
|
78 |
object:nil];
|
|
evands@2183
|
79 |
[nc addObserver:self
|
|
evands@2183
|
80 |
selector:@selector(reloadPrefs:)
|
|
evands@2183
|
81 |
name:GrowlPreferencesChanged
|
|
evands@2183
|
82 |
object:nil];
|
|
ingmarstein@2594
|
83 |
|
|
ingmarstein@2594
|
84 |
[GrowlApplicationBridge setGrowlDelegate:self];
|
|
ingmarstein@2594
|
85 |
}
|
|
ingmarstein@2594
|
86 |
|
|
ingmarstein@2594
|
87 |
#pragma mark Growl delegate methods
|
|
ingmarstein@2594
|
88 |
|
|
ingmarstein@2594
|
89 |
- (NSString *) applicationNameForGrowl {
|
|
ingmarstein@2594
|
90 |
return @"GrowlMenu";
|
|
ingmarstein@2594
|
91 |
}
|
|
ingmarstein@2594
|
92 |
|
|
ingmarstein@2594
|
93 |
- (NSDictionary *) registrationDictionaryForGrowl {
|
|
evands@3746
|
94 |
NSArray *notifications = [NSArray arrayWithObject:@"Display changed"];
|
|
ingmarstein@2594
|
95 |
NSDictionary *registrationDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
evands@3746
|
96 |
notifications, GROWL_NOTIFICATIONS_ALL,
|
|
evands@3746
|
97 |
notifications, GROWL_NOTIFICATIONS_DEFAULT,
|
|
evands@3746
|
98 |
[NSDictionary dictionaryWithObject:NSLocalizedString(@"Display changed", "Notification posted by GrowlMenu when the display style changes")
|
|
evands@3746
|
99 |
forKey:@"Display changed"], GROWL_NOTIFICATIONS_HUMAN_READABLE_NAMES,
|
|
evands@3746
|
100 |
nil];
|
|
ingmarstein@2594
|
101 |
|
|
ingmarstein@2594
|
102 |
return registrationDictionary;
|
|
ingmarstein@2594
|
103 |
}
|
|
ingmarstein@2594
|
104 |
|
|
ingmarstein@2594
|
105 |
#pragma mark -
|
|
evands@2183
|
106 |
|
|
ingmarstein@2206
|
107 |
- (void) setGrowlMenuEnabled:(BOOL)state {
|
|
ingmarstein@2206
|
108 |
NSString *growlMenuPath = [[NSBundle mainBundle] bundlePath];
|
|
ingmarstein@2206
|
109 |
[preferences setStartAtLogin:growlMenuPath enabled:state];
|
|
ingmarstein@2206
|
110 |
[preferences setBool:state forKey:GrowlMenuExtraKey];
|
|
ingmarstein@2206
|
111 |
}
|
|
ingmarstein@2206
|
112 |
|
|
evands@2183
|
113 |
- (void) applicationWillTerminate:(NSNotification *)aNotification {
|
|
evands@2183
|
114 |
#pragma unused(aNotification)
|
|
evands@2183
|
115 |
[self release];
|
|
evands@2183
|
116 |
}
|
|
evands@2183
|
117 |
|
|
evands@2183
|
118 |
- (void) dealloc {
|
|
ingmarstein@2335
|
119 |
// [[NSStatusBar systemStatusBar] removeStatusItem:statusItem];
|
|
ingmarstein@2335
|
120 |
// [statusItem release];
|
|
ingmarstein@2335
|
121 |
[clawImage release];
|
|
ingmarstein@2335
|
122 |
[clawHighlightImage release];
|
|
ingmarstein@2335
|
123 |
[squelchImage release];
|
|
evands@2183
|
124 |
[super dealloc];
|
|
evands@2183
|
125 |
}
|
|
evands@2183
|
126 |
|
|
ingmarstein@2357
|
127 |
- (void) shutdown:(id)sender {
|
|
ingmarstein@2357
|
128 |
[self setGrowlMenuEnabled:NO];
|
|
ingmarstein@2357
|
129 |
[NSApp terminate:sender];
|
|
ingmarstein@2357
|
130 |
}
|
|
ingmarstein@2357
|
131 |
|
|
evands@2183
|
132 |
- (void) reloadPrefs:(NSNotification *)notification {
|
|
evands@2183
|
133 |
// ignore notifications which are sent by ourselves
|
|
evands@4016
|
134 |
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
|
ingmarstein@2357
|
135 |
NSNumber *pidValue = [[notification userInfo] objectForKey:@"pid"];
|
|
ingmarstein@2357
|
136 |
if (!pidValue || [pidValue intValue] != pid)
|
|
evands@2183
|
137 |
[self setImage];
|
|
evands@4016
|
138 |
[pool release];
|
|
evands@2183
|
139 |
}
|
|
evands@2183
|
140 |
|
|
ingmarstein@2357
|
141 |
- (void) openGrowlPreferences:(id)sender {
|
|
evands@2183
|
142 |
#pragma unused(sender)
|
|
ofri@2683
|
143 |
NSString *prefPane = [[GrowlPathUtilities growlPrefPaneBundle] bundlePath];
|
|
evands@2183
|
144 |
[[NSWorkspace sharedWorkspace] openFile:prefPane];
|
|
evands@2183
|
145 |
}
|
|
evands@2183
|
146 |
|
|
ingmarstein@2357
|
147 |
- (void) defaultDisplay:(id)sender {
|
|
ingmarstein@2594
|
148 |
NSString *pluginName = [sender title];
|
|
ingmarstein@2594
|
149 |
[preferences setDefaultDisplayPluginName:pluginName];
|
|
ingmarstein@2594
|
150 |
|
|
ingmarstein@2673
|
151 |
CFStringRef description = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, (CFStringRef)kDefaultDisplayChanged, pluginName);
|
|
ingmarstein@2673
|
152 |
const NSString *keys[5] = { GROWL_APP_NAME, GROWL_NOTIFICATION_NAME, GROWL_NOTIFICATION_TITLE, GROWL_NOTIFICATION_DESCRIPTION, GROWL_DISPLAY_PLUGIN };
|
|
ingmarstein@2673
|
153 |
const CFStringRef values[5] = { CFSTR("GrowlMenu"), CFSTR("Display changed"), CFSTR("Display changed"), description, (CFStringRef)pluginName };
|
|
ingmarstein@2673
|
154 |
CFDictionaryRef feedbackDictionary = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 5, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
|
ingmarstein@2673
|
155 |
CFRelease(description);
|
|
ingmarstein@2673
|
156 |
[GrowlApplicationBridge notifyWithDictionary:(NSDictionary *)feedbackDictionary];
|
|
ingmarstein@2673
|
157 |
CFRelease(feedbackDictionary);
|
|
evands@2183
|
158 |
}
|
|
evands@2183
|
159 |
|
|
ingmarstein@2357
|
160 |
- (void) stopGrowl:(id)sender {
|
|
evands@2183
|
161 |
#pragma unused(sender)
|
|
evands@2183
|
162 |
//If Growl is running, we should stop it.
|
|
evands@2183
|
163 |
if ([preferences isGrowlRunning])
|
|
evands@2183
|
164 |
[preferences setGrowlRunning:NO noMatterWhat:NO];
|
|
evands@2183
|
165 |
}
|
|
evands@2183
|
166 |
|
|
ingmarstein@2357
|
167 |
- (void) startGrowl:(id)sender {
|
|
evands@2183
|
168 |
#pragma unused(sender)
|
|
evands@2183
|
169 |
if (![preferences isGrowlRunning]) {
|
|
evands@2183
|
170 |
//If Growl isn't running, we should start it.
|
|
evands@2183
|
171 |
[preferences setGrowlRunning:YES noMatterWhat:NO];
|
|
evands@2183
|
172 |
} else {
|
|
evands@2183
|
173 |
//If Growl is running, we should restart it.
|
|
evands@2183
|
174 |
//Actually, we should HUP it, but we don't.
|
|
evands@2183
|
175 |
[preferences setGrowlRunning:NO noMatterWhat:NO];
|
|
evands@2183
|
176 |
[preferences setGrowlRunning:YES noMatterWhat:YES];
|
|
evands@2183
|
177 |
}
|
|
evands@2183
|
178 |
}
|
|
evands@2183
|
179 |
|
|
ingmarstein@2357
|
180 |
- (void) squelchMode:(id)sender {
|
|
evands@2183
|
181 |
#pragma unused(sender)
|
|
ingmarstein@2560
|
182 |
BOOL squelchMode = ![preferences squelchMode];
|
|
ingmarstein@2560
|
183 |
[preferences setSquelchMode:squelchMode];
|
|
ingmarstein@2560
|
184 |
[self setImage];
|
|
evands@2183
|
185 |
}
|
|
evands@2183
|
186 |
|
|
eridius@2773
|
187 |
- (void) stickyWhenIdle:(id)sender {
|
|
eridius@2773
|
188 |
#pragma unused(sender)
|
|
eridius@2773
|
189 |
BOOL idleModeState = ![preferences stickyWhenAway];
|
|
eridius@2773
|
190 |
[preferences setStickyWhenAway:idleModeState];
|
|
eridius@2773
|
191 |
}
|
|
eridius@2773
|
192 |
|
|
evands@2183
|
193 |
- (void) setImage {
|
|
ingmarstein@2560
|
194 |
if ([preferences squelchMode]) {
|
|
evands@2183
|
195 |
[statusItem setImage:squelchImage];
|
|
evands@2183
|
196 |
} else {
|
|
evands@2183
|
197 |
[statusItem setImage:clawImage];
|
|
evands@2183
|
198 |
[statusItem setAlternateImage:clawHighlightImage];
|
|
evands@2183
|
199 |
}
|
|
evands@2183
|
200 |
}
|
|
evands@2183
|
201 |
|
|
evands@2183
|
202 |
- (NSMenu *) createMenu {
|
|
evands@2183
|
203 |
NSZone *menuZone = [NSMenu menuZone];
|
|
evands@2183
|
204 |
NSMenu *m = [[NSMenu allocWithZone:menuZone] init];
|
|
evands@2183
|
205 |
|
|
evands@2183
|
206 |
NSMenuItem *tempMenuItem;
|
|
evands@2183
|
207 |
|
|
evands@2183
|
208 |
tempMenuItem = (NSMenuItem *)[m addItemWithTitle:kStartGrowl action:@selector(startGrowl:) keyEquivalent:@""];
|
|
evands@2183
|
209 |
[tempMenuItem setTarget:self];
|
|
evands@2183
|
210 |
[tempMenuItem setTag:1];
|
|
evands@2183
|
211 |
|
|
evands@2183
|
212 |
if ([preferences isGrowlRunning]) {
|
|
evands@2183
|
213 |
[tempMenuItem setTitle:kRestartGrowl];
|
|
evands@2183
|
214 |
[tempMenuItem setToolTip:kRestartGrowlTooltip];
|
|
evands@2183
|
215 |
} else {
|
|
evands@2183
|
216 |
[tempMenuItem setToolTip:kStartGrowlTooltip];
|
|
evands@2183
|
217 |
}
|
|
evands@2183
|
218 |
|
|
evands@2183
|
219 |
tempMenuItem = (NSMenuItem *)[m addItemWithTitle:kStopGrowl action:@selector(stopGrowl:) keyEquivalent:@""];
|
|
evands@2183
|
220 |
[tempMenuItem setTag:2];
|
|
evands@2183
|
221 |
[tempMenuItem setTarget:self];
|
|
evands@2183
|
222 |
[tempMenuItem setToolTip:kStopGrowlTooltip];
|
|
evands@2183
|
223 |
|
|
evands@2183
|
224 |
[m addItem:[NSMenuItem separatorItem]];
|
|
evands@2183
|
225 |
|
|
evands@3774
|
226 |
/*
|
|
evands@3774
|
227 |
//Squelch mode is "log-only" mode... but logging was removed from Growl 1.1.
|
|
evands@2183
|
228 |
tempMenuItem = (NSMenuItem *)[m addItemWithTitle:kSquelchMode action:@selector(squelchMode:) keyEquivalent:@""];
|
|
evands@2183
|
229 |
[tempMenuItem setTarget:self];
|
|
evands@2183
|
230 |
[tempMenuItem setTag:4];
|
|
evands@2183
|
231 |
[tempMenuItem setToolTip:kSquelchModeTooltip];
|
|
evands@3774
|
232 |
*/
|
|
evands@3774
|
233 |
|
|
eridius@2773
|
234 |
tempMenuItem = (NSMenuItem *)[m addItemWithTitle:kStickyWhenAwayMenu action:@selector(stickyWhenIdle:) keyEquivalent:@""];
|
|
eridius@2773
|
235 |
[tempMenuItem setTarget:self];
|
|
eridius@2773
|
236 |
[tempMenuItem setTag:6];
|
|
eridius@2773
|
237 |
[tempMenuItem setToolTip:kStickyWhenAwayMenuTooltip];
|
|
eridius@2773
|
238 |
|
|
eridius@2773
|
239 |
/*NSMenu *displays = [[NSMenu allocWithZone:menuZone] init];
|
|
evands@2183
|
240 |
NSString *name;
|
|
ingmarstein@2488
|
241 |
NSEnumerator *displayEnumerator = [[[GrowlPluginController sharedController] displayPlugins] objectEnumerator];
|
|
evands@2183
|
242 |
while ((name = [displayEnumerator nextObject])) {
|
|
evands@2183
|
243 |
tempMenuItem = (NSMenuItem *)[displays addItemWithTitle:name action:@selector(defaultDisplay:) keyEquivalent:@""];
|
|
evands@2183
|
244 |
[tempMenuItem setTarget:self];
|
|
evands@2183
|
245 |
[tempMenuItem setTag:3];
|
|
evands@2183
|
246 |
}
|
|
evands@2183
|
247 |
tempMenuItem = (NSMenuItem *)[m addItemWithTitle:kDefaultDisplay action:NULL keyEquivalent:@""];
|
|
evands@2183
|
248 |
[tempMenuItem setTarget:self];
|
|
evands@2183
|
249 |
[tempMenuItem setSubmenu:displays];
|
|
eridius@2773
|
250 |
[displays release];*/
|
|
evands@2183
|
251 |
[m addItem:[NSMenuItem separatorItem]];
|
|
evands@2183
|
252 |
|
|
eridius@2773
|
253 |
tempMenuItem = (NSMenuItem *)[m addItemWithTitle:kStopGrowlMenu action:@selector(shutdown:) keyEquivalent:@""];
|
|
eridius@2773
|
254 |
[tempMenuItem setTag:5];
|
|
eridius@2773
|
255 |
[tempMenuItem setTarget:self];
|
|
eridius@2773
|
256 |
[tempMenuItem setToolTip:kStopGrowlMenuTooltip];
|
|
eridius@2773
|
257 |
|
|
evands@2183
|
258 |
tempMenuItem = (NSMenuItem *)[m addItemWithTitle:kOpenGrowlPreferences action:@selector(openGrowlPreferences:) keyEquivalent:@""];
|
|
evands@2183
|
259 |
[tempMenuItem setTarget:self];
|
|
evands@2183
|
260 |
[tempMenuItem setToolTip:kOpenGrowlPreferencesTooltip];
|
|
evands@2183
|
261 |
|
|
evands@2183
|
262 |
return m;
|
|
evands@2183
|
263 |
}
|
|
evands@2183
|
264 |
|
|
evands@2183
|
265 |
- (BOOL) validateMenuItem:(NSMenuItem *)item {
|
|
evands@2183
|
266 |
switch ([item tag]) {
|
|
evands@2183
|
267 |
case 1:
|
|
evands@2183
|
268 |
if ([preferences isGrowlRunning]) {
|
|
evands@2183
|
269 |
[item setTitle:kRestartGrowl];
|
|
evands@2183
|
270 |
[item setToolTip:kRestartGrowlTooltip];
|
|
evands@2183
|
271 |
} else {
|
|
evands@2183
|
272 |
[item setTitle:kStartGrowl];
|
|
evands@2183
|
273 |
[item setToolTip:kStartGrowlTooltip];
|
|
evands@2183
|
274 |
}
|
|
evands@2183
|
275 |
break;
|
|
evands@2183
|
276 |
case 2:
|
|
evands@2183
|
277 |
return [preferences isGrowlRunning];
|
|
evands@2183
|
278 |
case 3:
|
|
ingmarstein@2560
|
279 |
[item setState:[[item title] isEqualToString:[preferences defaultDisplayPluginName]]];
|
|
evands@2183
|
280 |
break;
|
|
evands@2183
|
281 |
case 4:
|
|
ingmarstein@2560
|
282 |
[item setState:[preferences squelchMode]];
|
|
evands@2183
|
283 |
break;
|
|
eridius@2773
|
284 |
case 6:
|
|
eridius@2773
|
285 |
[item setState:[preferences stickyWhenAway]];
|
|
eridius@2773
|
286 |
break;
|
|
evands@2183
|
287 |
}
|
|
evands@2183
|
288 |
return YES;
|
|
evands@2183
|
289 |
}
|
|
evands@2183
|
290 |
|
|
evands@2183
|
291 |
@end
|