|
boredzo@2405
|
1 |
//
|
|
boredzo@2405
|
2 |
// GrowlDisplayWindowController.m
|
|
boredzo@2405
|
3 |
// Display Plugins
|
|
boredzo@2405
|
4 |
//
|
|
boredzo@2405
|
5 |
// Created by Mac-arena the Bored Zo on 2005-06-03.
|
|
ingmarstein@3040
|
6 |
// Copyright 2004-2006 The Growl Project. All rights reserved.
|
|
boredzo@2405
|
7 |
//
|
|
boredzo@2405
|
8 |
|
|
boredzo@2405
|
9 |
#import "GrowlDisplayWindowController.h"
|
|
ingmarstein@2470
|
10 |
#import "GrowlPathUtilities.h"
|
|
boredzo@2405
|
11 |
#import "GrowlDefines.h"
|
|
ofri@2503
|
12 |
#import "GrowlWindowTransition.h"
|
|
ofri@2657
|
13 |
#import "GrowlPositionController.h"
|
|
boredzo@2428
|
14 |
#import "NSViewAdditions.h"
|
|
eridius@2773
|
15 |
#import "GrowlNotificationDisplayBridge.h"
|
|
eridius@2773
|
16 |
#import "GrowlApplicationNotification.h"
|
|
evands@3641
|
17 |
#import "GrowlNotificationView.h"
|
|
boredzo@2405
|
18 |
|
|
boredzo@3137
|
19 |
#include "GrowlLog.h"
|
|
boredzo@3137
|
20 |
|
|
evands@3829
|
21 |
#define DEFAULT_TRANSITION_DURATION 0.75
|
|
evands@3829
|
22 |
|
|
jkp@2758
|
23 |
static NSMutableDictionary *existingInstances;
|
|
ofri@2657
|
24 |
|
|
evands@3499
|
25 |
@interface GrowlDisplayWindowController (PRIVATE)
|
|
evands@3499
|
26 |
- (void)cancelDisplayDelayedPerforms;
|
|
evands@3581
|
27 |
- (BOOL)supportsStickyNotifications;
|
|
evands@3499
|
28 |
@end
|
|
rudy@2828
|
29 |
|
|
evands@4005
|
30 |
@interface NSWindow (LeopardMethods)
|
|
evands@4005
|
31 |
- (void)setCollectionBehavior:(int)collectionBehavior;
|
|
evands@4005
|
32 |
@end
|
|
evands@4005
|
33 |
|
|
boredzo@2405
|
34 |
@implementation GrowlDisplayWindowController
|
|
boredzo@2405
|
35 |
|
|
jkp@2758
|
36 |
#pragma mark -
|
|
boredzo@3070
|
37 |
#pragma mark Caching
|
|
jkp@2758
|
38 |
|
|
jkp@2758
|
39 |
+ (void) registerInstance:(id)instance withIdentifier:(NSString *)ident {
|
|
jkp@2758
|
40 |
if (!existingInstances)
|
|
jkp@2758
|
41 |
existingInstances = [[NSMutableDictionary alloc] init];
|
|
ingmarstein@2943
|
42 |
|
|
ingmarstein@3008
|
43 |
NSDictionary *classInstances = [existingInstances objectForKey:self];
|
|
ingmarstein@3008
|
44 |
if (!classInstances) {
|
|
jkp@2758
|
45 |
classInstances = [[NSMutableDictionary alloc] init];
|
|
jkp@2758
|
46 |
[existingInstances setObject:classInstances forKey:self];
|
|
boredzo@4142
|
47 |
[classInstances release];
|
|
jkp@2758
|
48 |
}
|
|
jkp@2758
|
49 |
[classInstances setValue:instance forKey:ident];
|
|
jkp@2758
|
50 |
}
|
|
jkp@2758
|
51 |
|
|
eridius@2762
|
52 |
+ (id) instanceWithIdentifier:(NSString *)ident {
|
|
jkp@2758
|
53 |
NSMutableDictionary *classInstances = [existingInstances objectForKey:self];
|
|
jkp@2758
|
54 |
if (classInstances)
|
|
jkp@2758
|
55 |
return [classInstances objectForKey:ident];
|
|
jkp@2758
|
56 |
else
|
|
jkp@2758
|
57 |
return nil;
|
|
jkp@2758
|
58 |
}
|
|
jkp@2758
|
59 |
|
|
jkp@2758
|
60 |
+ (void) unregisterInstanceWithIdentifier:(NSString *)ident {
|
|
jkp@2758
|
61 |
NSMutableDictionary *classInstances = [existingInstances objectForKey:self];
|
|
jkp@2758
|
62 |
if (classInstances)
|
|
jkp@2758
|
63 |
[classInstances removeObjectForKey:ident];
|
|
jkp@2758
|
64 |
}
|
|
jkp@2758
|
65 |
|
|
jkp@2758
|
66 |
#pragma mark -
|
|
jkp@2758
|
67 |
|
|
ingmarstein@2943
|
68 |
- (id) initWithWindowNibName:(NSString *)windowNibName bridge:(GrowlNotificationDisplayBridge *)displayBridge {
|
|
eridius@2773
|
69 |
// NOTE: for completeness we ought to offer the other nib related init methods with the plugin as a param
|
|
ingmarstein@2943
|
70 |
if ((self = [self initWithWindowNibName:windowNibName owner:displayBridge])) {
|
|
ingmarstein@2943
|
71 |
[self setBridge:displayBridge]; // weak reference
|
|
ingmarstein@2943
|
72 |
}
|
|
eridius@2773
|
73 |
return self;
|
|
eridius@2773
|
74 |
}
|
|
eridius@2773
|
75 |
|
|
ingmarstein@2943
|
76 |
- (id) initWithBridge:(GrowlNotificationDisplayBridge *)displayBridge {
|
|
ingmarstein@3036
|
77 |
/* Subclasses using this method should call initWithWindowNibName: from init */
|
|
ingmarstein@2943
|
78 |
if ((self = [self init])) {
|
|
ingmarstein@2943
|
79 |
[self setBridge:displayBridge]; // weak reference
|
|
ingmarstein@2943
|
80 |
}
|
|
eridius@2773
|
81 |
return self;
|
|
eridius@2773
|
82 |
}
|
|
eridius@2773
|
83 |
|
|
ingmarstein@2663
|
84 |
- (id) initWithWindow:(NSWindow *)window {
|
|
ingmarstein@2663
|
85 |
if ((self = [super initWithWindow:window])) {
|
|
jkp@2744
|
86 |
windowTransitions = [[NSMutableDictionary alloc] init];
|
|
ofri@2658
|
87 |
ignoresOtherNotifications = NO;
|
|
eridius@2773
|
88 |
bridge = nil;
|
|
jkp@2816
|
89 |
startTimes = NSCreateMapTable(NSObjectMapKeyCallBacks, NSIntMapValueCallBacks, 0U);
|
|
jkp@2816
|
90 |
endTimes = NSCreateMapTable(NSObjectMapKeyCallBacks, NSIntMapValueCallBacks, 0U);
|
|
evands@3829
|
91 |
transitionDuration = DEFAULT_TRANSITION_DURATION;
|
|
evands@3829
|
92 |
|
|
evands@4005
|
93 |
//Show notifications on all Spaces
|
|
evands@4005
|
94 |
if ([window respondsToSelector:@selector(setCollectionBehavior:)]) {
|
|
evands@4005
|
95 |
#define NSWindowCollectionBehaviorCanJoinAllSpaces 1 << 0
|
|
evands@4005
|
96 |
[window setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces];
|
|
evands@4005
|
97 |
}
|
|
evands@4005
|
98 |
|
|
evands@3644
|
99 |
//Respond to 'close all notifications' by closing
|
|
evands@3644
|
100 |
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
evands@3644
|
101 |
selector:@selector(stopDisplay)
|
|
evands@3644
|
102 |
name:GROWL_CLOSE_ALL_NOTIFICATIONS
|
|
evands@3644
|
103 |
object:nil];
|
|
ofri@2503
|
104 |
}
|
|
ingmarstein@2591
|
105 |
|
|
ofri@2503
|
106 |
return self;
|
|
ofri@2503
|
107 |
}
|
|
ofri@2503
|
108 |
|
|
boredzo@2405
|
109 |
- (void) dealloc {
|
|
ofri@2498
|
110 |
[self setDelegate:nil];
|
|
boredzo@3137
|
111 |
[[self bridge] removeObserver:self forKeyPath:@"notification"];
|
|
evands@3644
|
112 |
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
evands@3645
|
113 |
[self stopAllTransitions];
|
|
eridius@2773
|
114 |
|
|
ingmarstein@2943
|
115 |
NSFreeMapTable(startTimes);
|
|
ingmarstein@2943
|
116 |
NSFreeMapTable(endTimes);
|
|
ingmarstein@2943
|
117 |
|
|
evands@3499
|
118 |
[bridge release];
|
|
ingmarstein@2416
|
119 |
[target release];
|
|
ingmarstein@2416
|
120 |
[clickContext release];
|
|
ingmarstein@2416
|
121 |
[clickHandlerEnabled release];
|
|
ingmarstein@2416
|
122 |
[appName release];
|
|
ingmarstein@2416
|
123 |
[appPid release];
|
|
jkp@2741
|
124 |
[windowTransitions release];
|
|
evands@3536
|
125 |
[notification release];
|
|
boredzo@2405
|
126 |
|
|
boredzo@2405
|
127 |
[super dealloc];
|
|
boredzo@2405
|
128 |
}
|
|
boredzo@2405
|
129 |
|
|
boredzo@2405
|
130 |
#pragma mark -
|
|
boredzo@2405
|
131 |
#pragma mark Screenshot mode
|
|
boredzo@2405
|
132 |
|
|
boredzo@2426
|
133 |
- (void) takeScreenshot {
|
|
boredzo@2428
|
134 |
NSView *view = [[self window] contentView];
|
|
ofri@2683
|
135 |
NSString *path = [[[GrowlPathUtilities screenshotsDirectory] stringByAppendingPathComponent:[GrowlPathUtilities nextScreenshotName]] stringByAppendingPathExtension:@"png"];
|
|
boredzo@2428
|
136 |
[[view dataWithPNGInsideRect:[view frame]] writeToFile:path atomically:NO];
|
|
boredzo@2428
|
137 |
}
|
|
boredzo@2405
|
138 |
|
|
boredzo@2405
|
139 |
#pragma mark -
|
|
boredzo@2405
|
140 |
#pragma mark Display control
|
|
boredzo@2405
|
141 |
|
|
evands@3578
|
142 |
- (BOOL)reposition_startingDisplay:(BOOL)shouldStartDisplay
|
|
evands@3578
|
143 |
{
|
|
ingmarstein@2663
|
144 |
NSWindow *window = [self window];
|
|
evands@3645
|
145 |
|
|
ofri@2658
|
146 |
//Make sure we don't cover any other notification (or not)
|
|
jkp@2841
|
147 |
BOOL foundSpace = NO;
|
|
jkp@2841
|
148 |
GrowlPositionController *pc = [GrowlPositionController sharedInstance];
|
|
jkp@2841
|
149 |
if ([self respondsToSelector:@selector(idealOriginInRect:)])
|
|
jkp@2841
|
150 |
foundSpace = [pc positionDisplay:self];
|
|
jkp@2841
|
151 |
else
|
|
Peter@4208
|
152 |
foundSpace = (ignoresOtherNotifications || [pc reserveRect:[window frame] forDisplayController:self]);
|
|
evands@3580
|
153 |
|
|
jkp@2841
|
154 |
if (foundSpace) {
|
|
evands@3578
|
155 |
if (shouldStartDisplay) {
|
|
evands@3578
|
156 |
[self cancelDisplayDelayedPerforms];
|
|
evands@3829
|
157 |
|
|
evands@3578
|
158 |
[self willDisplayNotification];
|
|
evands@3829
|
159 |
|
|
evands@3578
|
160 |
[window orderFront:nil];
|
|
evands@3578
|
161 |
|
|
evands@3578
|
162 |
if ([self startAllTransitions]) {
|
|
evands@3578
|
163 |
[self performSelector:@selector(didFinishTransitionsBeforeDisplay)
|
|
evands@3578
|
164 |
withObject:nil
|
|
evands@3578
|
165 |
afterDelay:transitionDuration];
|
|
evands@3578
|
166 |
} else {
|
|
evands@3578
|
167 |
[self didFinishTransitionsBeforeDisplay];
|
|
evands@3578
|
168 |
}
|
|
evands@3578
|
169 |
|
|
evands@3578
|
170 |
[self didDisplayNotification];
|
|
rudy@2828
|
171 |
}
|
|
evands@3567
|
172 |
|
|
evands@3567
|
173 |
} else {
|
|
ingmarstein@2943
|
174 |
[[NSNotificationCenter defaultCenter] postNotificationName:GrowlDisplayWindowControllerNotificationBlockedNotification
|
|
jkp@2741
|
175 |
object:self];
|
|
evands@3578
|
176 |
|
|
evands@3567
|
177 |
//Try again in 10 seconds
|
|
evands@3578
|
178 |
if (!shouldStartDisplay) {
|
|
evands@3578
|
179 |
//If we're restarting, get this display off-screen while we wait
|
|
evands@3578
|
180 |
//XXX This should be more fluid
|
|
evands@3578
|
181 |
[window orderOut:nil];
|
|
evands@3578
|
182 |
|
|
evands@3578
|
183 |
[[GrowlPositionController sharedInstance] clearReservedRectForDisplayController:self];
|
|
evands@3578
|
184 |
|
|
evands@3578
|
185 |
}
|
|
evands@3567
|
186 |
[self performSelector:@selector(startDisplay) withObject:nil afterDelay:5];
|
|
evands@3567
|
187 |
}
|
|
evands@3578
|
188 |
|
|
evands@3567
|
189 |
return foundSpace;
|
|
evands@3578
|
190 |
}
|
|
evands@3578
|
191 |
|
|
evands@3578
|
192 |
- (BOOL) startDisplay {
|
|
evands@3581
|
193 |
return [self reposition_startingDisplay:YES];
|
|
boredzo@2405
|
194 |
}
|
|
boredzo@2405
|
195 |
|
|
evands@3641
|
196 |
- (void) stopDisplay {
|
|
evands@3641
|
197 |
id contentView = [[self window] contentView];
|
|
evands@3641
|
198 |
if ([contentView respondsToSelector:@selector(mouseOver)] &&
|
|
evands@3645
|
199 |
[contentView mouseOver] &&
|
|
evands@3645
|
200 |
!userRequestedClose) {
|
|
evands@3641
|
201 |
//The mouse is currently within the view; close when it exits
|
|
evands@3641
|
202 |
[contentView setCloseOnMouseExit:YES];
|
|
evands@3641
|
203 |
|
|
rudy@2828
|
204 |
} else {
|
|
evands@3645
|
205 |
//If we're already transitioning out, just keep doing our thing
|
|
evands@3645
|
206 |
if (displayStatus != GrowlDisplayTransitioningOutStatus) {
|
|
evands@3645
|
207 |
[self cancelDisplayDelayedPerforms];
|
|
evands@3829
|
208 |
|
|
evands@3645
|
209 |
[self willTakeDownNotification];
|
|
evands@3645
|
210 |
if ([self startAllTransitions]) {
|
|
evands@3645
|
211 |
[self performSelector:@selector(didFinishTransitionsAfterDisplay)
|
|
evands@3645
|
212 |
withObject:nil
|
|
evands@3645
|
213 |
afterDelay:transitionDuration];
|
|
evands@3645
|
214 |
} else {
|
|
evands@3645
|
215 |
[self didFinishTransitionsAfterDisplay];
|
|
evands@3645
|
216 |
}
|
|
evands@3641
|
217 |
}
|
|
evands@3645
|
218 |
}
|
|
evands@3645
|
219 |
}
|
|
evands@3645
|
220 |
|
|
evands@3645
|
221 |
- (void) clickedClose {
|
|
evands@3645
|
222 |
userRequestedClose = YES;
|
|
evands@3645
|
223 |
[self stopDisplay];
|
|
boredzo@2405
|
224 |
}
|
|
boredzo@2405
|
225 |
|
|
boredzo@2405
|
226 |
#pragma mark -
|
|
boredzo@2405
|
227 |
#pragma mark Display stages
|
|
boredzo@2405
|
228 |
|
|
evands@3499
|
229 |
- (void)cancelDisplayDelayedPerforms
|
|
evands@3499
|
230 |
{
|
|
evands@3499
|
231 |
[[self class] cancelPreviousPerformRequestsWithTarget:self
|
|
evands@3499
|
232 |
selector:@selector(didFinishTransitionsBeforeDisplay)
|
|
evands@3499
|
233 |
object:nil];
|
|
evands@3499
|
234 |
|
|
evands@3499
|
235 |
[[self class] cancelPreviousPerformRequestsWithTarget:self
|
|
evands@3499
|
236 |
selector:@selector(didFinishTransitionsAfterDisplay)
|
|
evands@3499
|
237 |
object:nil];
|
|
evands@3499
|
238 |
|
|
evands@3499
|
239 |
[[self class] cancelPreviousPerformRequestsWithTarget:self
|
|
evands@3499
|
240 |
selector:@selector(stopDisplay)
|
|
evands@3499
|
241 |
object:nil];
|
|
evands@3499
|
242 |
}
|
|
evands@3499
|
243 |
|
|
boredzo@2405
|
244 |
- (void) willDisplayNotification {
|
|
evands@3576
|
245 |
displayStatus = GrowlDisplayTransitioningInStatus;
|
|
evands@3576
|
246 |
|
|
ingmarstein@2943
|
247 |
[[NSNotificationCenter defaultCenter] postNotificationName:GrowlDisplayWindowControllerWillDisplayWindowNotification
|
|
jkp@2741
|
248 |
object:self];
|
|
ingmarstein@2663
|
249 |
}
|
|
ingmarstein@2663
|
250 |
|
|
jkp@2816
|
251 |
- (void) didFinishTransitionsBeforeDisplay {
|
|
evands@3499
|
252 |
[self cancelDisplayDelayedPerforms];
|
|
evands@3499
|
253 |
|
|
evands@3580
|
254 |
if (![[[notification auxiliaryDictionary] objectForKey:GROWL_NOTIFICATION_STICKY] boolValue] ||
|
|
evands@3580
|
255 |
![self supportsStickyNotifications]) {
|
|
evands@3499
|
256 |
[self performSelector:@selector(stopDisplay)
|
|
evands@3499
|
257 |
withObject:nil
|
|
evands@3499
|
258 |
afterDelay:(displayDuration+transitionDuration)];
|
|
evands@3499
|
259 |
}
|
|
evands@3576
|
260 |
|
|
evands@3576
|
261 |
displayStatus = GrowlDisplayOnScreenStatus;
|
|
jkp@2816
|
262 |
}
|
|
jkp@2816
|
263 |
|
|
jkp@2816
|
264 |
- (void) didFinishTransitionsAfterDisplay {
|
|
evands@3499
|
265 |
[self cancelDisplayDelayedPerforms];
|
|
evands@3499
|
266 |
|
|
jkp@2816
|
267 |
//Clear the rect we reserved...
|
|
jkp@2816
|
268 |
NSWindow *window = [self window];
|
|
jkp@2816
|
269 |
[window orderOut:nil];
|
|
evands@3541
|
270 |
|
|
evands@3541
|
271 |
//Release all window transitions immediately; they may have retained our window.
|
|
evands@3645
|
272 |
[self stopAllTransitions];
|
|
evands@3541
|
273 |
[windowTransitions release]; windowTransitions = nil;
|
|
evands@3541
|
274 |
|
|
evands@3517
|
275 |
[[GrowlPositionController sharedInstance] clearReservedRectForDisplayController:self];
|
|
rudy@3135
|
276 |
|
|
evands@3683
|
277 |
[self didTakeDownNotification];
|
|
evands@3683
|
278 |
|
|
rudy@3135
|
279 |
if ((bridge) && ([bridge respondsToSelector:@selector(display)]))
|
|
rudy@3135
|
280 |
[[bridge display] displayWindowControllerDidTakeDownWindow:self];
|
|
evands@3499
|
281 |
else {
|
|
evands@3499
|
282 |
NSLog(@"%@ bridge does not respond to display",bridge);
|
|
evands@3499
|
283 |
}
|
|
jkp@2816
|
284 |
}
|
|
jkp@2816
|
285 |
|
|
ingmarstein@2663
|
286 |
- (void) didDisplayNotification {
|
|
boredzo@2405
|
287 |
if (screenshotMode)
|
|
boredzo@2405
|
288 |
[self takeScreenshot];
|
|
boredzo@2405
|
289 |
|
|
ingmarstein@2943
|
290 |
[[NSNotificationCenter defaultCenter] postNotificationName:GrowlDisplayWindowControllerDidDisplayWindowNotification
|
|
jkp@2741
|
291 |
object:self];
|
|
ingmarstein@2663
|
292 |
}
|
|
ingmarstein@2663
|
293 |
|
|
boredzo@2405
|
294 |
- (void) willTakeDownNotification {
|
|
ingmarstein@2943
|
295 |
[[NSNotificationCenter defaultCenter] postNotificationName:GrowlDisplayWindowControllerWillTakeWindowDownNotification
|
|
jkp@2741
|
296 |
object:self];
|
|
evands@3576
|
297 |
displayStatus = GrowlDisplayTransitioningOutStatus;
|
|
ingmarstein@2663
|
298 |
}
|
|
ingmarstein@2663
|
299 |
|
|
ingmarstein@2663
|
300 |
- (void) didTakeDownNotification {
|
|
jkp@2741
|
301 |
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
|
boredzo@2405
|
302 |
if (clickContext) {
|
|
jkp@2741
|
303 |
NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] initWithCapacity:2U];
|
|
jkp@2741
|
304 |
[userInfo setValue:clickContext forKey:GROWL_KEY_CLICKED_CONTEXT];
|
|
ingmarstein@2663
|
305 |
if (appPid)
|
|
jkp@2741
|
306 |
[userInfo setValue:appPid forKey:GROWL_APP_PID];
|
|
jkp@2741
|
307 |
[nc postNotificationName:GROWL_NOTIFICATION_TIMED_OUT object:appName userInfo:userInfo];
|
|
jkp@2741
|
308 |
[userInfo release];
|
|
boredzo@2405
|
309 |
|
|
boredzo@2405
|
310 |
//Avoid duplicate click messages by immediately clearing the clickContext
|
|
boredzo@2405
|
311 |
clickContext = nil;
|
|
boredzo@2405
|
312 |
}
|
|
evands@3499
|
313 |
[nc postNotificationName:GrowlDisplayWindowControllerDidTakeWindowDownNotification object:self];
|
|
evands@3499
|
314 |
}
|
|
boredzo@2405
|
315 |
#pragma mark -
|
|
boredzo@2405
|
316 |
#pragma mark Click feedback
|
|
boredzo@2405
|
317 |
|
|
ingmarstein@2663
|
318 |
- (void) notificationClicked:(id)sender {
|
|
boredzo@2405
|
319 |
#pragma unused(sender)
|
|
boredzo@2405
|
320 |
if (clickContext) {
|
|
jkp@2741
|
321 |
NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] initWithCapacity:3U];
|
|
jkp@2741
|
322 |
[userInfo setValue:clickHandlerEnabled forKey:@"ClickHandlerEnabled"];
|
|
jkp@2741
|
323 |
[userInfo setValue:clickContext forKey:GROWL_KEY_CLICKED_CONTEXT];
|
|
ingmarstein@2663
|
324 |
if (appPid)
|
|
jkp@2741
|
325 |
[userInfo setValue:appPid forKey:GROWL_APP_PID];
|
|
ingmarstein@2943
|
326 |
[[NSNotificationCenter defaultCenter] postNotificationName:GROWL_NOTIFICATION_CLICKED
|
|
jkp@2741
|
327 |
object:appName
|
|
jkp@2741
|
328 |
userInfo:userInfo];
|
|
jkp@2741
|
329 |
[userInfo release];
|
|
boredzo@2405
|
330 |
|
|
boredzo@2405
|
331 |
//Avoid duplicate click messages by immediately clearing the clickContext
|
|
ingmarstein@2663
|
332 |
clickContext = nil;
|
|
boredzo@2405
|
333 |
}
|
|
boredzo@2405
|
334 |
|
|
boredzo@2405
|
335 |
if (target && action && [target respondsToSelector:action])
|
|
boredzo@2405
|
336 |
[target performSelector:action withObject:self];
|
|
ingmarstein@3009
|
337 |
|
|
evands@3645
|
338 |
//Now that we've notified the clickContext and target, it's as if the user just clicked the close button
|
|
evands@3645
|
339 |
[self clickedClose];
|
|
boredzo@2405
|
340 |
}
|
|
boredzo@2405
|
341 |
|
|
boredzo@2405
|
342 |
#pragma mark -
|
|
ofri@2503
|
343 |
#pragma mark Window Transitions
|
|
ofri@2503
|
344 |
|
|
jkp@2744
|
345 |
- (BOOL) addTransition:(GrowlWindowTransition *)transition {
|
|
ofri@2503
|
346 |
[transition setWindow:[self window]];
|
|
ofri@2503
|
347 |
[transition setDelegate:self];
|
|
ingmarstein@3009
|
348 |
if (![windowTransitions objectForKey:[transition class]]) {
|
|
jkp@2744
|
349 |
[windowTransitions setObject:transition forKey:[transition class]];
|
|
jkp@2744
|
350 |
return TRUE;
|
|
jkp@2744
|
351 |
}
|
|
jkp@2744
|
352 |
return FALSE;
|
|
ofri@2503
|
353 |
}
|
|
ofri@2503
|
354 |
|
|
ofri@2503
|
355 |
- (void) removeTransition:(GrowlWindowTransition *)transition {
|
|
ofri@2503
|
356 |
[transition setDelegate:nil];
|
|
ofri@2503
|
357 |
[transition setWindow:nil];
|
|
evands@3541
|
358 |
|
|
evands@3541
|
359 |
[windowTransitions removeObjectForKey:[transition class]];
|
|
ofri@2503
|
360 |
}
|
|
ofri@2503
|
361 |
|
|
jkp@2816
|
362 |
- (void) setStartPercentage:(unsigned)start endPercentage:(unsigned)end forTransition:(GrowlWindowTransition *)transition {
|
|
ingmarstein@2943
|
363 |
NSAssert1((start <= 100U || start < end),
|
|
jkp@2816
|
364 |
@"The start parameter was invalid for the transition: %@",
|
|
jkp@2816
|
365 |
transition);
|
|
ingmarstein@2943
|
366 |
NSAssert1((end <= 100U || start < end),
|
|
jkp@2816
|
367 |
@"The end parameter was invalid for the transition: %@",
|
|
jkp@2816
|
368 |
transition);
|
|
ingmarstein@2943
|
369 |
|
|
jkp@2816
|
370 |
NSMapInsert(startTimes, transition, (void *)start);
|
|
jkp@2816
|
371 |
NSMapInsert(endTimes, transition, (void *)end);
|
|
jkp@2816
|
372 |
}
|
|
jkp@2816
|
373 |
|
|
jkp@2816
|
374 |
#pragma mark-
|
|
jkp@2816
|
375 |
|
|
ofri@2503
|
376 |
- (NSArray *) allTransitions {
|
|
evands@3522
|
377 |
return [windowTransitions allValues];
|
|
ofri@2503
|
378 |
}
|
|
ofri@2503
|
379 |
|
|
ofri@2503
|
380 |
- (NSArray *) activeTransitions {
|
|
jkp@2741
|
381 |
int count = [windowTransitions count];
|
|
jkp@2741
|
382 |
NSMutableArray *result = [NSMutableArray arrayWithCapacity:count];
|
|
jkp@2744
|
383 |
NSArray *transitionArray = [windowTransitions allValues];
|
|
jkp@2741
|
384 |
|
|
jkp@2741
|
385 |
int i;
|
|
jkp@2741
|
386 |
for (i=0; i<count; ++i) {
|
|
jkp@2744
|
387 |
GrowlWindowTransition *transition = [transitionArray objectAtIndex:i];
|
|
ofri@2503
|
388 |
if ([transition isAnimating])
|
|
jkp@2741
|
389 |
[result addObject:transition];
|
|
jkp@2741
|
390 |
}
|
|
jkp@2741
|
391 |
|
|
evands@3522
|
392 |
return result;
|
|
ofri@2503
|
393 |
}
|
|
ofri@2503
|
394 |
|
|
ofri@2503
|
395 |
- (NSArray *) inactiveTransitions {
|
|
jkp@2741
|
396 |
int count = [windowTransitions count];
|
|
jkp@2741
|
397 |
NSMutableArray *result = [NSMutableArray arrayWithCapacity:count];
|
|
jkp@2744
|
398 |
NSArray *transitionArray = [windowTransitions allValues];
|
|
jkp@2741
|
399 |
|
|
jkp@2741
|
400 |
int i;
|
|
jkp@2741
|
401 |
for (i=0; i<count; ++i) {
|
|
jkp@2744
|
402 |
GrowlWindowTransition *transition = [transitionArray objectAtIndex:i];
|
|
ofri@2503
|
403 |
if (![transition isAnimating])
|
|
ingmarstein@2943
|
404 |
[result addObject:transition];
|
|
jkp@2741
|
405 |
}
|
|
jkp@2741
|
406 |
|
|
evands@3522
|
407 |
return result;
|
|
ofri@2503
|
408 |
}
|
|
ofri@2503
|
409 |
|
|
jkp@2816
|
410 |
- (BOOL) startAllTransitions {
|
|
jkp@2816
|
411 |
BOOL result = NO;
|
|
jkp@2816
|
412 |
GrowlWindowTransition *transition;
|
|
jkp@2816
|
413 |
NSEnumerator *transitionEnum = [[windowTransitions allValues] objectEnumerator];
|
|
jkp@2816
|
414 |
|
|
jkp@2816
|
415 |
while ((transition = [transitionEnum nextObject]))
|
|
jkp@2816
|
416 |
if ([self startTransition:transition])
|
|
jkp@2816
|
417 |
result = YES;
|
|
jkp@2816
|
418 |
return result;
|
|
jkp@2816
|
419 |
}
|
|
jkp@2816
|
420 |
|
|
jkp@2816
|
421 |
- (BOOL) startTransition:(GrowlWindowTransition *)transition {
|
|
jkp@2816
|
422 |
int startPercentage = (int) NSMapGet(startTimes, transition);
|
|
jkp@2816
|
423 |
int endPercentage = (int) NSMapGet(endTimes, transition);
|
|
ingmarstein@2943
|
424 |
|
|
jkp@2816
|
425 |
// If there were no times set up then the end time would be NULL (0)...
|
|
jkp@2816
|
426 |
if (endPercentage == 0)
|
|
jkp@2816
|
427 |
return NO;
|
|
ingmarstein@2943
|
428 |
|
|
jkp@2816
|
429 |
// Work out the start and the end times...
|
|
evands@3829
|
430 |
CFTimeInterval startTime = (float)startPercentage * ((float)transitionDuration * 0.01);
|
|
evands@3829
|
431 |
CFTimeInterval endTime = (float)endPercentage * ((float)transitionDuration * 0.01);
|
|
ingmarstein@2943
|
432 |
|
|
jkp@2816
|
433 |
// Set up this transition...
|
|
jkp@2816
|
434 |
[transition setDuration: (endTime - startTime)];
|
|
evands@3499
|
435 |
[transition performSelector:@selector(startAnimation)
|
|
evands@3499
|
436 |
withObject:nil
|
|
evands@3499
|
437 |
afterDelay:startTime];
|
|
ingmarstein@2943
|
438 |
|
|
jkp@2816
|
439 |
return YES;
|
|
jkp@2816
|
440 |
}
|
|
jkp@2816
|
441 |
|
|
jkp@2816
|
442 |
- (BOOL) startTransitionOfKind:(Class)transitionClass {
|
|
jkp@2744
|
443 |
GrowlWindowTransition *transition = [windowTransitions objectForKey:transitionClass];
|
|
jkp@2744
|
444 |
if (transition)
|
|
jkp@2816
|
445 |
return [self startTransition:transition];
|
|
jkp@2816
|
446 |
return NO;
|
|
ofri@2503
|
447 |
}
|
|
ofri@2503
|
448 |
|
|
ofri@2503
|
449 |
- (void) stopAllTransitions {
|
|
jkp@2816
|
450 |
GrowlWindowTransition *transition;
|
|
jkp@2816
|
451 |
NSEnumerator *transitionEnum = [[windowTransitions allValues] objectEnumerator];
|
|
jkp@2816
|
452 |
while (( transition = [transitionEnum nextObject] ))
|
|
jkp@2816
|
453 |
[self stopTransition:transition];
|
|
jkp@2816
|
454 |
}
|
|
jkp@2816
|
455 |
|
|
jkp@2816
|
456 |
- (void) stopTransition:(GrowlWindowTransition *)transition {
|
|
jkp@2816
|
457 |
[transition stopAnimation];
|
|
evands@3541
|
458 |
[self removeTransition:transition];
|
|
evands@3541
|
459 |
|
|
evands@3499
|
460 |
[[self class] cancelPreviousPerformRequestsWithTarget:transition
|
|
evands@3499
|
461 |
selector:@selector(startAnimation)
|
|
evands@3499
|
462 |
object:nil];
|
|
jkp@2744
|
463 |
}
|
|
jkp@2744
|
464 |
|
|
jkp@2744
|
465 |
- (void) stopTransitionOfKind:(Class)transitionClass {
|
|
jkp@2744
|
466 |
GrowlWindowTransition *transition = [windowTransitions objectForKey:transitionClass];
|
|
jkp@2744
|
467 |
if (transition)
|
|
jkp@2816
|
468 |
[self stopTransition:transition];
|
|
ofri@2503
|
469 |
}
|
|
ofri@2503
|
470 |
|
|
ingmarstein@3825
|
471 |
- (void) animationDidEnd:(NSAnimation *)animation
|
|
evands@3524
|
472 |
{
|
|
evands@3524
|
473 |
if ([animation isKindOfClass:[GrowlWindowTransition class]] &&
|
|
evands@3524
|
474 |
([(GrowlWindowTransition *)animation window] == [self window]) &&
|
|
rudy@3823
|
475 |
([(GrowlWindowTransition *)animation direction] == GrowlReverseTransition)) {
|
|
evands@3524
|
476 |
//A fade out nonrepeating animation finished. We don't need to wait on our timeout; we know we finished displaying a notification.
|
|
evands@3524
|
477 |
[self didFinishTransitionsAfterDisplay];
|
|
evands@3524
|
478 |
}
|
|
ingmarstein@3825
|
479 |
}
|
|
ingmarstein@3825
|
480 |
|
|
ingmarstein@3825
|
481 |
- (void) reverseAllTransitions
|
|
evands@3576
|
482 |
{
|
|
evands@3576
|
483 |
[[windowTransitions allValues] makeObjectsPerformSelector:@selector(reverse)];
|
|
evands@3576
|
484 |
}
|
|
evands@3576
|
485 |
|
|
evands@3576
|
486 |
#pragma mark -
|
|
ingmarstein@3825
|
487 |
- (void) mouseEnteredNotificationView:(GrowlNotificationView *)notificationView
|
|
evands@3645
|
488 |
{
|
|
evands@3645
|
489 |
#pragma unused (notificationView)
|
|
evands@3645
|
490 |
if (!userRequestedClose &&
|
|
evands@3645
|
491 |
(displayStatus == GrowlDisplayTransitioningOutStatus)) {
|
|
evands@3645
|
492 |
// We're transitioning out; we need to go back to transitioning in...
|
|
evands@3645
|
493 |
[self willDisplayNotification];
|
|
evands@3645
|
494 |
[self reverseAllTransitions];
|
|
evands@3645
|
495 |
[self didFinishTransitionsBeforeDisplay];
|
|
evands@3645
|
496 |
|
|
evands@3645
|
497 |
// ...but when the mouse leaves, transition out again
|
|
evands@3645
|
498 |
[self stopDisplay];
|
|
evands@3645
|
499 |
}
|
|
evands@3645
|
500 |
}
|
|
evands@3645
|
501 |
|
|
ingmarstein@3825
|
502 |
- (void) mouseExitedNotificationView:(GrowlNotificationView *)notificationView
|
|
evands@3645
|
503 |
{
|
|
evands@3645
|
504 |
#pragma unused (notificationView)
|
|
evands@3645
|
505 |
// Notifies us that the mouse left the notification view.
|
|
evands@3645
|
506 |
}
|
|
evands@3645
|
507 |
|
|
evands@3645
|
508 |
#pragma mark -
|
|
evands@3576
|
509 |
#pragma mark Notifications
|
|
boredzo@2405
|
510 |
|
|
ingmarstein@2943
|
511 |
- (GrowlApplicationNotification *) notification {
|
|
ingmarstein@2943
|
512 |
// Only here for binding conformance
|
|
ingmarstein@2943
|
513 |
return notification;
|
|
ingmarstein@2943
|
514 |
}
|
|
ingmarstein@2943
|
515 |
|
|
ingmarstein@2943
|
516 |
- (void) setNotification:(GrowlApplicationNotification *)theNotification {
|
|
ingmarstein@3009
|
517 |
if (notification != theNotification) {
|
|
ingmarstein@3009
|
518 |
[notification release];
|
|
evands@3536
|
519 |
notification = [theNotification retain];
|
|
ingmarstein@3009
|
520 |
}
|
|
eridius@2773
|
521 |
}
|
|
eridius@2773
|
522 |
|
|
evands@3576
|
523 |
- (void) updateToNotification:(GrowlApplicationNotification *)theNotification {
|
|
evands@3576
|
524 |
[self setNotification:theNotification];
|
|
evands@3576
|
525 |
|
|
evands@3576
|
526 |
switch (displayStatus) {
|
|
evands@3576
|
527 |
case GrowlDisplayUnknownStatus:
|
|
evands@3576
|
528 |
case GrowlDisplayTransitioningInStatus:
|
|
evands@3576
|
529 |
//Do nothing; we're still transitioning in
|
|
evands@3576
|
530 |
break;
|
|
evands@3576
|
531 |
|
|
evands@3576
|
532 |
case GrowlDisplayOnScreenStatus:
|
|
evands@3576
|
533 |
//We're on screen; reset our timer for transitioning out
|
|
evands@3576
|
534 |
[self didFinishTransitionsBeforeDisplay];
|
|
evands@3576
|
535 |
break;
|
|
evands@3576
|
536 |
|
|
evands@3576
|
537 |
case GrowlDisplayTransitioningOutStatus:
|
|
evands@3645
|
538 |
//Reset userRequestedClose in case we were transitioning out via the user's request; we have new information!
|
|
evands@3645
|
539 |
userRequestedClose = NO;
|
|
evands@3645
|
540 |
|
|
evands@3576
|
541 |
[self willDisplayNotification];
|
|
evands@3576
|
542 |
[self reverseAllTransitions];
|
|
evands@3576
|
543 |
[self didFinishTransitionsBeforeDisplay];
|
|
evands@3580
|
544 |
|
|
evands@3576
|
545 |
break;
|
|
evands@3576
|
546 |
}
|
|
evands@3578
|
547 |
|
|
evands@3578
|
548 |
[self reposition_startingDisplay:NO];
|
|
evands@3576
|
549 |
}
|
|
evands@3576
|
550 |
|
|
eridius@2773
|
551 |
#pragma mark -
|
|
eridius@2773
|
552 |
|
|
ingmarstein@2943
|
553 |
- (GrowlNotificationDisplayBridge *) bridge {
|
|
ingmarstein@2943
|
554 |
return bridge;
|
|
ingmarstein@2943
|
555 |
}
|
|
ingmarstein@2943
|
556 |
|
|
ingmarstein@3036
|
557 |
- (void) setBridge:(GrowlNotificationDisplayBridge *)theBridge {
|
|
evands@3499
|
558 |
if (bridge != theBridge) {
|
|
evands@3499
|
559 |
if (bridge) {
|
|
evands@3499
|
560 |
NSLog(@"*** This may be an error. %@ had its bridge reset", self);
|
|
evands@3499
|
561 |
[bridge removeObserver:self forKeyPath:@"notification"];
|
|
evands@3499
|
562 |
}
|
|
evands@3499
|
563 |
|
|
evands@3499
|
564 |
bridge = [theBridge retain];
|
|
evands@3499
|
565 |
|
|
evands@3499
|
566 |
[bridge addObserver:self forKeyPath:@"notification" options:NSKeyValueObservingOptionNew context:NULL];
|
|
evands@3499
|
567 |
[self observeValueForKeyPath:@"notification" ofObject:bridge change:nil context:NULL];
|
|
evands@3499
|
568 |
}
|
|
evands@3499
|
569 |
}
|
|
evands@3499
|
570 |
|
|
evands@3499
|
571 |
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
|
|
evands@3499
|
572 |
{
|
|
evands@3499
|
573 |
#pragma unused(change)
|
|
evands@3499
|
574 |
#pragma unused(context)
|
|
evands@3499
|
575 |
if ((object == bridge) &&
|
|
evands@3499
|
576 |
[keyPath isEqualToString:@"notification"]) {
|
|
evands@3499
|
577 |
[self setNotification:[bridge notification]];
|
|
evands@3499
|
578 |
}
|
|
eridius@2773
|
579 |
}
|
|
eridius@2773
|
580 |
|
|
eridius@2773
|
581 |
#pragma mark -
|
|
eridius@2773
|
582 |
|
|
jkp@2816
|
583 |
- (CFTimeInterval) transitionDuration {
|
|
jkp@2816
|
584 |
return transitionDuration;
|
|
jkp@2816
|
585 |
}
|
|
jkp@2816
|
586 |
|
|
ingmarstein@3036
|
587 |
- (void) setTransitionDuration:(CFTimeInterval)theTransitionDuration{
|
|
jkp@2816
|
588 |
transitionDuration = theTransitionDuration;
|
|
jkp@2816
|
589 |
}
|
|
jkp@2816
|
590 |
|
|
jkp@2816
|
591 |
#pragma mark -
|
|
jkp@2816
|
592 |
|
|
ingmarstein@2663
|
593 |
- (CFTimeInterval) displayDuration {
|
|
boredzo@2405
|
594 |
return displayDuration;
|
|
boredzo@2405
|
595 |
}
|
|
boredzo@2405
|
596 |
|
|
ingmarstein@2663
|
597 |
- (void) setDisplayDuration:(CFTimeInterval)newDuration {
|
|
boredzo@2405
|
598 |
displayDuration = newDuration;
|
|
boredzo@2405
|
599 |
}
|
|
boredzo@2405
|
600 |
|
|
boredzo@2405
|
601 |
#pragma mark -
|
|
boredzo@2405
|
602 |
|
|
boredzo@2405
|
603 |
- (BOOL) screenshotModeEnabled {
|
|
boredzo@2405
|
604 |
return screenshotMode;
|
|
boredzo@2405
|
605 |
}
|
|
boredzo@2405
|
606 |
|
|
ingmarstein@2663
|
607 |
- (void) setScreenshotModeEnabled:(BOOL)newScreenshotMode {
|
|
boredzo@2405
|
608 |
screenshotMode = newScreenshotMode;
|
|
boredzo@2405
|
609 |
}
|
|
boredzo@2405
|
610 |
|
|
boredzo@2405
|
611 |
#pragma mark -
|
|
boredzo@2405
|
612 |
|
|
boredzo@2405
|
613 |
- (NSScreen *) screen {
|
|
boredzo@2405
|
614 |
NSArray *screens = [NSScreen screens];
|
|
boredzo@2405
|
615 |
if (screenNumber < [screens count])
|
|
boredzo@2405
|
616 |
return [screens objectAtIndex:screenNumber];
|
|
boredzo@2405
|
617 |
else
|
|
boredzo@2405
|
618 |
return [NSScreen mainScreen];
|
|
boredzo@2405
|
619 |
}
|
|
ingmarstein@2663
|
620 |
|
|
ingmarstein@2663
|
621 |
- (void) setScreen:(NSScreen *)newScreen {
|
|
boredzo@2405
|
622 |
unsigned newScreenNumber = [[NSScreen screens] indexOfObjectIdenticalTo:newScreen];
|
|
ingmarstein@2416
|
623 |
if (newScreenNumber == NSNotFound)
|
|
boredzo@2405
|
624 |
[NSException raise:NSInternalInconsistencyException format:@"Tried to set %@ %p to a screen %p that isn't in the screen list", [self class], self, newScreen];
|
|
eridius@2773
|
625 |
[self setScreenNumber:newScreenNumber];
|
|
eridius@2773
|
626 |
}
|
|
eridius@2773
|
627 |
|
|
eridius@2773
|
628 |
- (void) setScreenNumber:(unsigned)newScreenNumber {
|
|
boredzo@2405
|
629 |
[self willChangeValueForKey:@"screenNumber"];
|
|
boredzo@2405
|
630 |
screenNumber = newScreenNumber;
|
|
boredzo@2405
|
631 |
[self didChangeValueForKey:@"screenNumber"];
|
|
boredzo@2405
|
632 |
}
|
|
boredzo@2405
|
633 |
|
|
evands@3580
|
634 |
- (BOOL)supportsStickyNotifications
|
|
evands@3580
|
635 |
{
|
|
evands@3580
|
636 |
return ![[self window] ignoresMouseEvents];
|
|
evands@3580
|
637 |
}
|
|
evands@3580
|
638 |
|
|
boredzo@2405
|
639 |
#pragma mark -
|
|
boredzo@2405
|
640 |
|
|
boredzo@2405
|
641 |
- (id) target {
|
|
boredzo@2405
|
642 |
return target;
|
|
boredzo@2405
|
643 |
}
|
|
boredzo@2405
|
644 |
|
|
ingmarstein@2663
|
645 |
- (void) setTarget:(id)object {
|
|
ingmarstein@2416
|
646 |
if (object != target) {
|
|
ingmarstein@2416
|
647 |
[target release];
|
|
ingmarstein@2416
|
648 |
target = [object retain];
|
|
ingmarstein@2416
|
649 |
}
|
|
boredzo@2405
|
650 |
}
|
|
boredzo@2405
|
651 |
|
|
boredzo@2405
|
652 |
#pragma mark -
|
|
boredzo@2405
|
653 |
|
|
boredzo@2405
|
654 |
- (SEL) action {
|
|
boredzo@2405
|
655 |
return action;
|
|
boredzo@2405
|
656 |
}
|
|
boredzo@2405
|
657 |
|
|
boredzo@2405
|
658 |
- (void) setAction:(SEL) selector {
|
|
boredzo@2405
|
659 |
action = selector;
|
|
boredzo@2405
|
660 |
}
|
|
boredzo@2405
|
661 |
|
|
boredzo@2405
|
662 |
#pragma mark -
|
|
boredzo@2405
|
663 |
|
|
boredzo@2405
|
664 |
- (NSString *) notifyingApplicationName {
|
|
boredzo@2405
|
665 |
return appName;
|
|
boredzo@2405
|
666 |
}
|
|
boredzo@2405
|
667 |
|
|
ingmarstein@2663
|
668 |
- (void) setNotifyingApplicationName:(NSString *)inAppName {
|
|
boredzo@2405
|
669 |
if (inAppName != appName) {
|
|
boredzo@2405
|
670 |
[appName release];
|
|
boredzo@2405
|
671 |
appName = [inAppName copy];
|
|
boredzo@2405
|
672 |
}
|
|
boredzo@2405
|
673 |
}
|
|
boredzo@2405
|
674 |
|
|
boredzo@2405
|
675 |
#pragma mark -
|
|
boredzo@2405
|
676 |
|
|
ingmarstein@2416
|
677 |
- (NSNumber *) notifyingApplicationProcessIdentifier {
|
|
boredzo@2405
|
678 |
return appPid;
|
|
boredzo@2405
|
679 |
}
|
|
boredzo@2405
|
680 |
|
|
ingmarstein@2663
|
681 |
- (void) setNotifyingApplicationProcessIdentifier:(NSNumber *)inAppPid {
|
|
boredzo@2405
|
682 |
if (inAppPid != appPid) {
|
|
ingmarstein@2416
|
683 |
[appPid release];
|
|
ingmarstein@2416
|
684 |
appPid = [inAppPid retain];
|
|
boredzo@2405
|
685 |
}
|
|
boredzo@2405
|
686 |
}
|
|
boredzo@2405
|
687 |
|
|
boredzo@2405
|
688 |
#pragma mark -
|
|
boredzo@2405
|
689 |
|
|
boredzo@2405
|
690 |
- (id) clickContext {
|
|
boredzo@2405
|
691 |
return clickContext;
|
|
boredzo@2405
|
692 |
}
|
|
boredzo@2405
|
693 |
|
|
ingmarstein@2663
|
694 |
- (void) setClickContext:(id)inClickContext {
|
|
ingmarstein@2663
|
695 |
if (clickContext != inClickContext) {
|
|
ingmarstein@2663
|
696 |
[clickContext release];
|
|
ingmarstein@2663
|
697 |
clickContext = [inClickContext retain];
|
|
ingmarstein@2663
|
698 |
}
|
|
boredzo@2405
|
699 |
}
|
|
boredzo@2405
|
700 |
|
|
boredzo@2405
|
701 |
#pragma mark -
|
|
boredzo@2405
|
702 |
|
|
ofri@2658
|
703 |
- (BOOL) ignoresOtherNotifications {
|
|
ofri@2658
|
704 |
return ignoresOtherNotifications;
|
|
ofri@2658
|
705 |
}
|
|
ofri@2658
|
706 |
|
|
ingmarstein@2663
|
707 |
- (void) setIgnoresOtherNotifications:(BOOL)flag {
|
|
ofri@2658
|
708 |
ignoresOtherNotifications = flag;
|
|
ofri@2658
|
709 |
}
|
|
ofri@2658
|
710 |
|
|
ofri@2658
|
711 |
#pragma mark -
|
|
ofri@2658
|
712 |
|
|
boredzo@2405
|
713 |
- (id) delegate {
|
|
boredzo@2405
|
714 |
return delegate;
|
|
boredzo@2405
|
715 |
}
|
|
ingmarstein@2663
|
716 |
|
|
ingmarstein@2663
|
717 |
- (void) setDelegate:(id)newDelegate {
|
|
boredzo@2405
|
718 |
if (delegate)
|
|
boredzo@2405
|
719 |
[self removeNotificationObserver:delegate];
|
|
boredzo@2405
|
720 |
|
|
boredzo@2405
|
721 |
if (newDelegate)
|
|
boredzo@2405
|
722 |
[self addNotificationObserver:newDelegate];
|
|
boredzo@2405
|
723 |
|
|
boredzo@2405
|
724 |
delegate = newDelegate;
|
|
boredzo@2405
|
725 |
}
|
|
boredzo@2405
|
726 |
|
|
boredzo@2405
|
727 |
#pragma mark -
|
|
boredzo@2405
|
728 |
|
|
ingmarstein@2416
|
729 |
- (NSNumber *) clickHandlerEnabled {
|
|
ingmarstein@2416
|
730 |
return clickHandlerEnabled;
|
|
ingmarstein@2416
|
731 |
}
|
|
ingmarstein@2416
|
732 |
|
|
ingmarstein@2663
|
733 |
- (void) setClickHandlerEnabled:(NSNumber *)flag {
|
|
ingmarstein@2416
|
734 |
if (flag != clickHandlerEnabled) {
|
|
ingmarstein@2416
|
735 |
[clickHandlerEnabled release];
|
|
ingmarstein@2416
|
736 |
clickHandlerEnabled = [flag retain];
|
|
ingmarstein@2416
|
737 |
}
|
|
ingmarstein@2416
|
738 |
}
|
|
ingmarstein@2416
|
739 |
|
|
ingmarstein@2416
|
740 |
#pragma mark -
|
|
ingmarstein@2416
|
741 |
|
|
ingmarstein@2663
|
742 |
- (void) addNotificationObserver:(id)observer {
|
|
boredzo@2405
|
743 |
NSParameterAssert(observer != nil);
|
|
boredzo@2405
|
744 |
|
|
boredzo@2405
|
745 |
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
|
boredzo@2405
|
746 |
|
|
boredzo@2405
|
747 |
if (observer) {
|
|
boredzo@2405
|
748 |
//register the new delegate.
|
|
ingmarstein@2416
|
749 |
if ([observer respondsToSelector:@selector(displayWindowControllerWillDisplayWindow:)])
|
|
boredzo@2405
|
750 |
[nc addObserver:observer
|
|
boredzo@2405
|
751 |
selector:@selector(displayWindowControllerWillDisplayWindow:)
|
|
evands@3499
|
752 |
name:GrowlDisplayWindowControllerWillDisplayWindowNotification
|
|
boredzo@2405
|
753 |
object:self];
|
|
ingmarstein@2416
|
754 |
if ([observer respondsToSelector:@selector(displayWindowControllerDidDisplayWindow:)])
|
|
boredzo@2405
|
755 |
[nc addObserver:observer
|
|
boredzo@2405
|
756 |
selector:@selector(displayWindowControllerDidDisplayWindow:)
|
|
evands@3499
|
757 |
name:GrowlDisplayWindowControllerDidDisplayWindowNotification
|
|
boredzo@2405
|
758 |
object:self];
|
|
ingmarstein@2416
|
759 |
|
|
ingmarstein@2416
|
760 |
if ([observer respondsToSelector:@selector(displayWindowControllerWillTakeDownWindow:)])
|
|
boredzo@2405
|
761 |
[nc addObserver:observer
|
|
ofri@2719
|
762 |
selector:@selector(displayWindowControllerWillTakeWindowDown:)
|
|
evands@3499
|
763 |
name:GrowlDisplayWindowControllerWillTakeWindowDownNotification
|
|
boredzo@2405
|
764 |
object:self];
|
|
ofri@2719
|
765 |
if ([observer respondsToSelector:@selector(displayWindowControllerDidTakeWindowDown:)])
|
|
boredzo@2405
|
766 |
[nc addObserver:observer
|
|
ofri@2719
|
767 |
selector:@selector(displayWindowControllerDidTakeWindowDown:)
|
|
evands@3499
|
768 |
name:GrowlDisplayWindowControllerDidTakeWindowDownNotification
|
|
boredzo@2405
|
769 |
object:self];
|
|
ofri@2657
|
770 |
if ([observer respondsToSelector:@selector(displayWindowControllerNotificationBlocked:)])
|
|
ofri@2657
|
771 |
[nc addObserver:observer
|
|
ofri@2657
|
772 |
selector:@selector(displayWindowControllerNotificationBlocked:)
|
|
evands@3499
|
773 |
name:GrowlDisplayWindowControllerNotificationBlockedNotification
|
|
ofri@2657
|
774 |
object:self];
|
|
boredzo@2405
|
775 |
}
|
|
boredzo@2405
|
776 |
}
|
|
ingmarstein@2663
|
777 |
- (void) removeNotificationObserver:(id)observer {
|
|
jkp@2741
|
778 |
[[NSNotificationCenter defaultCenter] removeObserver:observer];
|
|
boredzo@2405
|
779 |
}
|
|
boredzo@2405
|
780 |
|
|
boredzo@2405
|
781 |
@end
|