I've added a one second cache to the NSMenu proxy because otherwise the menu provider...
[ITKit.git] / ITStatusItem.m
1 #import "ITStatusItem.h"
2 #import <CoreServices/CoreServices.h>
3
4 @interface ITStatusItemMenuProxy : NSProxy {
5         id <ITStatusItemMenuProvider> menuProvider;
6         ITStatusItem *statusItem;
7         AbsoluteTime cachedTime;
8         NSMenu *menu;
9 }
10
11 - (id)initWithMenuProvider:(id <ITStatusItemMenuProvider>)provider statusItem:(ITStatusItem *)item;
12
13 @end
14
15 @implementation ITStatusItemMenuProxy
16
17 + (BOOL)respondsToSelector:(SEL)aSelector {
18         if (![super respondsToSelector:aSelector]) {
19                 return [NSMenu respondsToSelector:aSelector];
20         }
21         return YES;
22 }
23
24 - (id)initWithMenuProvider:(id <ITStatusItemMenuProvider>)provider statusItem:(ITStatusItem *)item {
25         menuProvider = [provider retain];
26         statusItem = [item retain];
27         cachedTime = UpTime();
28         menu = nil;
29         return self;
30 }
31
32 - (void)forwardInvocation:(NSInvocation *)anInvocation {
33         AbsoluteTime diff = SubAbsoluteFromAbsolute(UpTime(),cachedTime);
34         
35         if (!menu || diff.lo > 1000000) {
36                 [menu release];
37                 menu = [[menuProvider menuForStatusItem:statusItem] retain];
38                 cachedTime = UpTime();
39         }
40         
41         [anInvocation setTarget:menu];
42         [anInvocation invoke];
43 }
44
45 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
46         return [NSMenu instanceMethodSignatureForSelector:aSelector];
47 }
48
49 - (void)dealloc {
50         [menu release];
51         [statusItem release];
52         [menuProvider release];
53         [super dealloc];
54 }
55
56 @end
57
58 @class NSStatusBarButton;
59
60 @interface NSStatusItem (ITStatusItemHacks)
61 - (id)_initInStatusBar:(NSStatusBar *)statusBar withLength:(float)length withPriority:(int)priority;
62 - (NSStatusBarButton *)_button;
63 @end
64
65 @protocol _ITStatusItemNSStatusBarButtonMethods
66 - (NSMenu *)statusMenu;
67 - (void)setStatusMenu:(NSMenu *)menu;
68 @end
69
70 @protocol _ITStatusItemNSStatusItemPantherCompatability
71 - (void)setAlternateImage:(NSImage *)image;
72 - (NSImage *)alternateImage;
73 @end
74
75 @implementation ITStatusItem
76
77 static BOOL _ITStatusItemShouldKillShadow = NO;
78
79 + (void)initialize {
80         if ((floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_1) && (floor(NSAppKitVersionNumber) <= 663.6)) {
81                 _ITStatusItemShouldKillShadow = YES;
82         }
83 }
84
85 - (id)initWithStatusBar:(NSStatusBar *)statusBar withLength:(float)length {
86         return [self _initInStatusBar:statusBar withLength:length withPriority:1000];
87 }
88
89 - (id)_initInStatusBar:(NSStatusBar *)statusBar withLength:(float)length withPriority:(int)priority {
90         if ((self = [super _initInStatusBar:statusBar withLength:length withPriority:priority])) {
91                 _menuProvider = nil;
92                 _menuProxy = nil;
93                 if (_ITStatusItemShouldKillShadow) {
94                         [[(NSButton *)[self _button] cell] setType:NSNullCellType];
95                 }
96             [self setHighlightMode:YES];
97         }
98         return self;
99 }
100
101 - (NSImage *)alternateImage {
102         if ([super respondsToSelector:@selector(alternateImage)]) {
103                 return [(id <_ITStatusItemNSStatusItemPantherCompatability>)super alternateImage];
104         }
105         return [(NSButton *)[self _button] alternateImage];
106 }
107
108 - (void)setAlternateImage:(NSImage*)image {
109         if ([super respondsToSelector:@selector(setAlternateImage:)]) {
110                 [(id <_ITStatusItemNSStatusItemPantherCompatability>)super setAlternateImage:image];
111                 return;
112         }
113         [(NSButton *)[self _button] setAlternateImage:image];
114 }
115
116 - (id <ITStatusItemMenuProvider>)menuProvider {
117         return _menuProvider;
118 }
119
120 - (void)setMenuProvider:(id <ITStatusItemMenuProvider>)provider {
121         [_menuProxy autorelease];
122         _menuProxy = nil;
123         _menuProvider = provider;
124         if (_menuProvider) {
125                 _menuProxy = [[ITStatusItemMenuProxy alloc] initWithMenuProvider:_menuProvider statusItem:self];
126                 [(id <_ITStatusItemNSStatusBarButtonMethods>)[self _button] setStatusMenu:_menuProxy];
127         } else {
128                 [self setMenu:[self menu]];
129         }
130 }
131
132 - (void)dealloc {
133         [_menuProxy release];
134         [super dealloc];
135 }
136
137 @end