Changed controlKey display character, per Alex's request.
[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
126     key = CGSCreateCString("IgnoreForEvents");
127     ignore = CGSCreateBoolean( (flag ? kCGSTrue : kCGSFalse) );
128     CGSSetWindowProperty([NSApp contextID], (CGSWindowID)[self windowNumber], key, ignore);
129     CGSReleaseObj(key);
130     CGSReleaseObj(ignore);
131
132     _reallyIgnoresEvents = flag;
133 }
134
135 /*
136
137 - (id)contentView
138 {
139     if ( _backgroundType == ITTransientStatusWindowRounded ) {
140         return _contentSubView;
141     } else {
142         return [super contentView];
143     }
144 }
145
146 - (void)setContentView:(NSView *)aView
147 {
148     if ( _backgroundType == ITTransientStatusWindowRounded ) {
149        [_contentSubView removeFromSuperview];
150         _contentSubView = aView;
151         [_contentSubView setFrame:[[super contentView] frame]];
152         [[super contentView] addSubview:_contentSubView];
153         [_contentSubView setNextResponder:self];
154     } else {
155         [super setContentView:aView];
156     }
157 }
158
159 */
160
161 - (IBAction)appear:(id)sender
162 {
163     if ( _visibilityState == ITWindowHiddenState ) {
164          // Window is hidden.  Appear as normal, and start the timer.
165         [_entryEffect performAppear];
166     } else if ( _visibilityState == ITWindowVisibleState ) {
167          // Window is completely visible.  Simply reset the timer.
168         [self startVanishTimer];
169     } else if ( _visibilityState == ITWindowAppearingState ) {
170          // Window is on its way in.  Do nothing.
171     } else if ( _visibilityState == ITWindowVanishingState ) {
172         // Window is on its way out.  Cancel the vanish.
173         [_exitEffect cancelVanish];
174     }
175 }
176
177 - (IBAction)vanish:(id)sender
178 {
179     if ( _visibilityState == ITWindowVisibleState ) {
180         // Window is totally visible.  Perform exit effect.
181         [_exitEffect performVanish];
182     } else if ( _visibilityState == ITWindowHiddenState ) {
183         // Window is hidden.  Do nothing.
184     } else if ( _visibilityState == ITWindowAppearingState ) {
185         // Window is on its way in.  Cancel appear.
186         [_entryEffect cancelAppear];
187     } else if ( _visibilityState == ITWindowVanishingState ) {
188         // Window is on its way out.  Do nothing.
189     }
190 }
191
192 - (void)setScreen:(NSScreen *)newScreen
193 {
194         [_screen release];
195         _screen = [newScreen retain];
196 }
197
198 - (NSScreen *)screen
199 {
200         return _screen;
201 }
202
203 - (void)setSizing:(ITTransientStatusWindowSizing)newSizing
204 {
205     _sizing = newSizing;
206 }
207
208 - (ITTransientStatusWindowSizing)sizing
209 {
210     return _sizing;
211 }
212
213 - (ITWindowVisibilityState)visibilityState
214 {
215     return _visibilityState;
216 }
217
218 - (void)setVisibilityState:(ITWindowVisibilityState)newState
219 {
220     _visibilityState = newState;
221     
222     if ( _visibilityState == ITWindowVisibleState ) {
223         [self startVanishTimer];
224     } else if ( (_visibilityState == ITWindowVanishingState) || (_visibilityState == ITWindowHiddenState) ) {
225         [self stopVanishTimer];
226     }
227 }
228
229 - (ITTransientStatusWindowExitMode)exitMode
230 {
231     return _exitMode;
232 }
233
234 - (void)setExitMode:(ITTransientStatusWindowExitMode)newMode
235 {
236     _exitMode = newMode;
237     
238     if ( _visibilityState == ITWindowVisibleState ) {
239         if ( _exitMode == ITTransientStatusWindowExitOnCommand ) {
240             [self stopVanishTimer];
241         } else if ( _exitMode == ITTransientStatusWindowExitAfterDelay ) {
242             [self startVanishTimer];
243         }
244     }
245 }
246
247 - (float)exitDelay
248 {
249     return _exitDelay;
250 }
251
252 - (void)setExitDelay:(float)seconds
253 {
254     _exitDelay = seconds;
255 }
256
257 - (ITTransientStatusWindowBackgroundType)backgroundType
258 {
259 //  return _backgroundType;
260     return ITTransientStatusWindowRounded;
261 }
262
263 - (void)setBackgroundType:(ITTransientStatusWindowBackgroundType)newType
264 {
265 //  setBackgroundType: is currently ignored.  Defaults to ITTransientStatusWindowRounded.
266 //  _backgroundType = newType;
267     _backgroundType = ITTransientStatusWindowRounded;
268 }
269
270 - (ITVerticalWindowPosition)verticalPosition;
271 {
272     return _verticalPosition;
273 }
274
275 - (void)setVerticalPosition:(ITVerticalWindowPosition)newPosition;
276 {
277     _verticalPosition = newPosition;
278 }
279
280 - (ITHorizontalWindowPosition)horizontalPosition;
281 {
282     return _horizontalPosition;
283 }
284
285 - (void)setHorizontalPosition:(ITHorizontalWindowPosition)newPosition;
286 {
287     _horizontalPosition = newPosition;
288 }
289
290 - (float)effectProgress
291 {
292     return _effectProgress;
293 }
294
295 - (void)setEffectProgress:(float)newProgress
296 {
297     _effectProgress = newProgress;
298 }
299
300 - (float)screenPadding
301 {
302     return _screenPadding;
303 }
304
305 - (void)setScreenPadding:(float)newPadding
306 {
307     _screenPadding = newPadding;
308 }
309
310 /*- (int)screenNumber
311 {
312     return _screenNumber;
313 }
314
315 - (void)setScreenNumber:(int)newNumber
316 {
317     _screenNumber = newNumber;
318 }*/
319
320 - (ITWindowEffect *)entryEffect
321 {
322     return _entryEffect;
323 }
324
325 - (void)setEntryEffect:(ITWindowEffect *)newEffect
326 {
327     [_entryEffect releaseWhenIdle];
328     _entryEffect = [newEffect retain];
329 }
330
331 - (ITWindowEffect *)exitEffect
332 {
333     return _exitEffect;
334 }
335
336 - (void)setExitEffect:(ITWindowEffect *)newEffect
337 {
338     [_exitEffect releaseWhenIdle];
339     _exitEffect = [newEffect retain];
340 }
341
342
343 /*************************************************************************/
344 #pragma mark -
345 #pragma mark PRIVATE METHODS
346 /*************************************************************************/
347
348 - (void)rebuildWindow;
349 {
350     if ( _backgroundType == ITTransientStatusWindowRounded ) {
351         ITTSWBackgroundView *roundedView = [[[ITTSWBackgroundView alloc] initWithFrame:[self frame]] autorelease];
352
353         [self setBackgroundColor:[NSColor clearColor]];
354         [self setHasShadow:NO];
355         [self setOpaque:NO];
356         
357         [self setContentView:roundedView];
358 //      [super setContentView:roundedView];
359 //      [_contentSubView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
360 //      [self setContentView:_contentSubView];
361     } else {
362         // YUO == CLWONBAOT
363     }
364 }
365
366 - (void)startVanishTimer
367 {
368     if ( _exitMode == ITTransientStatusWindowExitAfterDelay) {
369         [self stopVanishTimer];
370         _exitTimer = [NSTimer scheduledTimerWithTimeInterval:_exitDelay
371                                                       target:self
372                                                     selector:@selector(doDelayedExit)
373                                                     userInfo:nil
374                                                      repeats:NO];
375     }
376 }
377
378 - (void)doDelayedExit
379 {
380     [self vanish:self];
381     _exitTimer = nil;
382 }
383
384 - (void)stopVanishTimer
385 {
386     if ( _exitTimer ) {
387         [_exitTimer invalidate];
388         _exitTimer = nil;
389     }
390 }
391
392 @end