Fixed a crash when Core Image was available.
[ITKit.git] / ITTransientStatusWindow.m
1 #import "ITTransientStatusWindow.h"
2 #import "ITWindowEffect.h"
3 #import <ApplicationServices/ApplicationServices.h>
4 #import "ITCoreGraphicsHacks.h"
5 #import "ITTextField.h"
6 #import "ITTSWBackgroundView.h"
7
8 #define EFFECT_FPS 30.0
9
10
11 /*************************************************************************/
12 #pragma mark -
13 #pragma mark PRIVATE METHOD DECLARATIONS
14 /*************************************************************************/
15
16 @interface ITTransientStatusWindow (Private)
17 - (id)initWithContentView:(NSView *)contentView
18                  exitMode:(ITTransientStatusWindowExitMode)exitMode
19            backgroundType:(ITTransientStatusWindowBackgroundType)backgroundType;
20 - (void)rebuildWindow;
21 - (void)startVanishTimer;
22 - (void)stopVanishTimer;
23 @end
24
25
26 /*************************************************************************/
27 #pragma mark -
28 #pragma mark IMPLEMENTATION
29 /*************************************************************************/
30
31 @implementation ITTransientStatusWindow
32
33
34 /*************************************************************************/
35 #pragma mark -
36 #pragma mark SHARED STATIC OBJECTS
37 /*************************************************************************/
38
39 static ITTransientStatusWindow *staticWindow = nil;
40
41
42 /*************************************************************************/
43 #pragma mark -
44 #pragma mark INITIALIZATION METHODS
45 /*************************************************************************/
46
47 + (ITTransientStatusWindow *)sharedWindow
48 {
49     if ( ! (staticWindow) ) {
50         staticWindow = [[self alloc] initWithContentView:nil
51                                                 exitMode:ITTransientStatusWindowExitAfterDelay
52                                           backgroundType:ITTransientStatusWindowRounded];
53     }
54     return staticWindow;
55 }
56
57 - (id)initWithContentView:(NSView *)contentView
58                  exitMode:(ITTransientStatusWindowExitMode)exitMode
59            backgroundType:(ITTransientStatusWindowBackgroundType)backgroundType
60 {
61     NSRect contentRect;
62     
63     // If no Content View was provided, use a generic view.
64     if ( ! (contentView) ) {
65         contentView = [[[NSView alloc] initWithFrame:
66             NSMakeRect(100.0, 100.0, 200.0, 200.0)] autorelease];
67     }
68     
69     // Set the content rect to the frame of the content view, now guaranteed to exist.
70     contentRect = [contentView frame];
71     
72     if ( ( self = [super initWithContentRect:contentRect
73                                    styleMask:NSBorderlessWindowMask
74                                      backing:NSBackingStoreBuffered
75                                        defer:NO] ) ) {
76                                     
77         _visibilityState     = ITWindowHiddenState;
78         _exitMode            = exitMode;
79         _exitDelay           = DEFAULT_EXIT_DELAY;
80         _backgroundType      = backgroundType;
81         _verticalPosition    = ITWindowPositionBottom;
82         _horizontalPosition  = ITWindowPositionLeft;
83         _screenPadding       = 32.0;
84         //_screenNumber        = 0;
85         _entryEffect         = nil;
86         _exitEffect          = nil;
87         _reallyIgnoresEvents = YES;
88         _exitTimer           = nil;
89                 [self setScreen:[NSScreen mainScreen]];
90
91 //      if ( _backgroundType == ITTransientStatusWindowRounded ) {
92 //          _contentSubView = contentView;
93 //      } else {
94 //          [self setContentView:contentView];
95 //      }
96
97         [self setIgnoresMouseEvents:YES];
98         [self setLevel:NSScreenSaverWindowLevel];
99         [self setContentView:contentView];
100         [self rebuildWindow];
101     }
102     return self;
103 }
104
105 - (void)dealloc
106 {
107         [_screen release];
108         [super dealloc];
109 }
110
111 /*************************************************************************/
112 #pragma mark -
113 #pragma mark INSTANCE METHODS
114 /*************************************************************************/
115
116 - (BOOL)ignoresMouseEvents
117 {
118     return _reallyIgnoresEvents;
119 }
120
121 - (void)setIgnoresMouseEvents:(BOOL)flag
122 {
123     //CGSValueObj        key;
124     //CGSValueObj        ignore;
125         CGSWindowTag tags;
126
127     /*key = CGSCreateCString("IgnoreForEvents");
128     ignore = CGSCreateBoolean( (flag ? kCGSTrue : kCGSFalse) );
129     CGSSetWindowProperty([NSApp contextID], (CGSWindowID)[self windowNumber], key, ignore);
130     CGSReleaseObj(key);
131     CGSReleaseObj(ignore);*/
132         
133         CGSGetWindowTags([NSApp contextID], (CGSWindowID)[self windowNumber], &tags, 32);
134
135         if (flag) {
136                 tags = tags | CGSTagTransparent;
137         } else {
138                 tags = tags & CGSTagTransparent;
139         }
140
141         CGSSetWindowTags([NSApp contextID], (CGSWindowID)[self windowNumber], &tags, 32);
142
143     _reallyIgnoresEvents = flag;
144 }
145
146 /*
147
148 - (id)contentView
149 {
150     if ( _backgroundType == ITTransientStatusWindowRounded ) {
151         return _contentSubView;
152     } else {
153         return [super contentView];
154     }
155 }
156
157 - (void)setContentView:(NSView *)aView
158 {
159     if ( _backgroundType == ITTransientStatusWindowRounded ) {
160        [_contentSubView removeFromSuperview];
161         _contentSubView = aView;
162         [_contentSubView setFrame:[[super contentView] frame]];
163         [[super contentView] addSubview:_contentSubView];
164         [_contentSubView setNextResponder:self];
165     } else {
166         [super setContentView:aView];
167     }
168 }
169
170 */
171
172 - (IBAction)appear:(id)sender
173 {
174     if ( _visibilityState == ITWindowHiddenState ) {
175          // Window is hidden.  Appear as normal, and start the timer.
176         [_entryEffect performAppear];
177     } else if ( _visibilityState == ITWindowVisibleState ) {
178          // Window is completely visible.  Simply reset the timer.
179         [self startVanishTimer];
180     } else if ( _visibilityState == ITWindowAppearingState ) {
181          // Window is on its way in.  Do nothing.
182     } else if ( _visibilityState == ITWindowVanishingState ) {
183         // Window is on its way out.  Cancel the vanish.
184         [_exitEffect cancelVanish];
185     }
186 }
187
188 - (IBAction)vanish:(id)sender
189 {
190     if ( _visibilityState == ITWindowVisibleState ) {
191         // Window is totally visible.  Perform exit effect.
192         [_exitEffect performVanish];
193     } else if ( _visibilityState == ITWindowHiddenState ) {
194         // Window is hidden.  Do nothing.
195     } else if ( _visibilityState == ITWindowAppearingState ) {
196         // Window is on its way in.  Cancel appear.
197         [_entryEffect cancelAppear];
198     } else if ( _visibilityState == ITWindowVanishingState ) {
199         // Window is on its way out.  Do nothing.
200     }
201 }
202
203 - (void)setScreen:(NSScreen *)newScreen
204 {
205         [_screen release];
206         _screen = [newScreen retain];
207 }
208
209 - (NSScreen *)screen
210 {
211         return _screen;
212 }
213
214 - (void)setSizing:(ITTransientStatusWindowSizing)newSizing
215 {
216     _sizing = newSizing;
217 }
218
219 - (ITTransientStatusWindowSizing)sizing
220 {
221     return _sizing;
222 }
223
224 - (ITWindowVisibilityState)visibilityState
225 {
226     return _visibilityState;
227 }
228
229 - (void)setVisibilityState:(ITWindowVisibilityState)newState
230 {
231     _visibilityState = newState;
232     
233     if ( _visibilityState == ITWindowVisibleState ) {
234         [self startVanishTimer];
235     } else if ( (_visibilityState == ITWindowVanishingState) || (_visibilityState == ITWindowHiddenState) ) {
236         [self stopVanishTimer];
237     }
238 }
239
240 - (ITTransientStatusWindowExitMode)exitMode
241 {
242     return _exitMode;
243 }
244
245 - (void)setExitMode:(ITTransientStatusWindowExitMode)newMode
246 {
247     _exitMode = newMode;
248     
249     if ( _visibilityState == ITWindowVisibleState ) {
250         if ( _exitMode == ITTransientStatusWindowExitOnCommand ) {
251             [self stopVanishTimer];
252         } else if ( _exitMode == ITTransientStatusWindowExitAfterDelay ) {
253             [self startVanishTimer];
254         }
255     }
256 }
257
258 - (float)exitDelay
259 {
260     return _exitDelay;
261 }
262
263 - (void)setExitDelay:(float)seconds
264 {
265     _exitDelay = seconds;
266 }
267
268 - (ITTransientStatusWindowBackgroundType)backgroundType
269 {
270 //  return _backgroundType;
271     return ITTransientStatusWindowRounded;
272 }
273
274 - (void)setBackgroundType:(ITTransientStatusWindowBackgroundType)newType
275 {
276 //  setBackgroundType: is currently ignored.  Defaults to ITTransientStatusWindowRounded.
277 //  _backgroundType = newType;
278     _backgroundType = ITTransientStatusWindowRounded;
279 }
280
281 - (ITVerticalWindowPosition)verticalPosition;
282 {
283     return _verticalPosition;
284 }
285
286 - (void)setVerticalPosition:(ITVerticalWindowPosition)newPosition;
287 {
288     _verticalPosition = newPosition;
289 }
290
291 - (ITHorizontalWindowPosition)horizontalPosition;
292 {
293     return _horizontalPosition;
294 }
295
296 - (void)setHorizontalPosition:(ITHorizontalWindowPosition)newPosition;
297 {
298     _horizontalPosition = newPosition;
299 }
300
301 - (float)effectProgress
302 {
303     return _effectProgress;
304 }
305
306 - (void)setEffectProgress:(float)newProgress
307 {
308     _effectProgress = newProgress;
309 }
310
311 - (float)screenPadding
312 {
313     return _screenPadding;
314 }
315
316 - (void)setScreenPadding:(float)newPadding
317 {
318     _screenPadding = newPadding;
319 }
320
321 /*- (int)screenNumber
322 {
323     return _screenNumber;
324 }
325
326 - (void)setScreenNumber:(int)newNumber
327 {
328     _screenNumber = newNumber;
329 }*/
330
331 - (ITWindowEffect *)entryEffect
332 {
333     return _entryEffect;
334 }
335
336 - (void)setEntryEffect:(ITWindowEffect *)newEffect
337 {
338     [_entryEffect releaseWhenIdle];
339     _entryEffect = [newEffect retain];
340 }
341
342 - (ITWindowEffect *)exitEffect
343 {
344     return _exitEffect;
345 }
346
347 - (void)setExitEffect:(ITWindowEffect *)newEffect
348 {
349     [_exitEffect releaseWhenIdle];
350     _exitEffect = [newEffect retain];
351 }
352
353
354 /*************************************************************************/
355 #pragma mark -
356 #pragma mark PRIVATE METHODS
357 /*************************************************************************/
358
359 - (void)rebuildWindow;
360 {
361     if ( _backgroundType == ITTransientStatusWindowRounded ) {
362         ITTSWBackgroundView *roundedView = [[[ITTSWBackgroundView alloc] initWithFrame:[self frame]] autorelease];
363
364         [self setBackgroundColor:[NSColor clearColor]];
365         [self setHasShadow:NO];
366         [self setOpaque:NO];
367         
368         [self setContentView:roundedView];
369 //      [super setContentView:roundedView];
370 //      [_contentSubView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
371 //      [self setContentView:_contentSubView];
372     } else {
373         // YUO == CLWONBAOT
374     }
375 }
376
377 - (void)startVanishTimer
378 {
379     if ( _exitMode == ITTransientStatusWindowExitAfterDelay) {
380         [self stopVanishTimer];
381         _exitTimer = [NSTimer scheduledTimerWithTimeInterval:_exitDelay
382                                                       target:self
383                                                     selector:@selector(doDelayedExit)
384                                                     userInfo:nil
385                                                      repeats:NO];
386     }
387 }
388
389 - (void)doDelayedExit
390 {
391     [self vanish:self];
392     _exitTimer = nil;
393 }
394
395 - (void)stopVanishTimer
396 {
397     if ( _exitTimer ) {
398         [_exitTimer invalidate];
399         _exitTimer = nil;
400     }
401 }
402
403 @end