1 #import "ITTransientStatusWindow.h"
2 #import <CoreGraphics/CoreGraphics.h>
3 #import "ITCoreGraphicsHacks.h"
4 #import "ITTextField.h"
5 #import "ITGrayRoundedView.h"
8 #define EFFECT_FPS 30.0
11 /*************************************************************************/
13 #pragma mark EVIL HACKERY
14 /*************************************************************************/
16 @interface NSApplication (HACKHACKHACKHACK)
17 - (CGSConnectionID)contextID;
21 /*************************************************************************/
23 #pragma mark PRIVATE METHOD DECLARATIONS
24 /*************************************************************************/
26 @interface ITTransientStatusWindow (Private)
27 - (id)initWithContentView:(NSView *)contentView
28 exitMode:(ITTransientStatusWindowExitMode)exitMode
29 backgroundType:(ITTransientStatusWindowBackgroundType)backgroundType;
30 - (void)rebuildWindow;
31 - (void)performEffect;
32 - (void)dissolveEffect;
33 - (void)slideVerticalEffect;
34 - (void)slideHorizontalEffect;
38 - (void)setPivot:(float)angle;
42 /*************************************************************************/
44 #pragma mark IMPLEMENTATION
45 /*************************************************************************/
47 @implementation ITTransientStatusWindow
50 /*************************************************************************/
52 #pragma mark SHARED STATIC OBJECTS
53 /*************************************************************************/
55 static ITTransientStatusWindow *staticWindow = nil;
58 /*************************************************************************/
60 #pragma mark INITIALIZATION METHODS
61 /*************************************************************************/
63 + (ITTransientStatusWindow *)sharedWindow
65 if ( ! (staticWindow) ) {
66 staticWindow = [[self alloc] initWithContentView:nil
67 exitMode:ITTransientStatusWindowExitAfterDelay
68 backgroundType:ITTransientStatusWindowRounded];
73 - (id)initWithContentView:(NSView *)contentView
74 exitMode:(ITTransientStatusWindowExitMode)exitMode
75 backgroundType:(ITTransientStatusWindowBackgroundType)backgroundType
79 // If no Content View was provided, use a generic NSView with the app icon.
80 if ( ! (contentView) ) {
81 contentView = [[[NSView alloc] initWithFrame:
82 NSMakeRect(100.0, 100.0, 200.0, 200.0)] autorelease];
85 // Set the content rect to the frame of the content view, now guaranteed to exist.
86 contentRect = [contentView frame];
88 if ( ( self = [super initWithContentRect:contentRect
89 styleMask:NSBorderlessWindowMask
90 backing:NSBackingStoreBuffered
93 _visibilityState = ITTransientStatusWindowHiddenState;
95 _exitDelay = DEFAULT_EXIT_DELAY;
96 _backgroundType = backgroundType;
97 _verticalPosition = ITTransientStatusWindowPositionBottom;
98 _horizontalPosition = ITTransientStatusWindowPositionLeft;
99 // _entryEffect = ITTransientStatusWindowEffectNone;
100 _entryEffect = ITTransientStatusWindowEffectPivot;
101 _exitEffect = ITTransientStatusWindowEffectDissolve;
102 _effectTime = DEFAULT_EFFECT_TIME;
103 _effectProgress = 0.00;
104 _reallyIgnoresEvents = YES;
108 // if ( _backgroundType == ITTransientStatusWindowRounded ) {
109 // _contentSubView = contentView;
111 // [self setContentView:contentView];
114 [self setIgnoresMouseEvents:YES];
115 [self setLevel:NSScreenSaverWindowLevel];
116 [self setContentView:contentView];
117 [self rebuildWindow];
123 /*************************************************************************/
125 #pragma mark INSTANCE METHODS
126 /*************************************************************************/
128 - (BOOL)ignoresMouseEvents
130 return _reallyIgnoresEvents;
133 - (void)setIgnoresMouseEvents:(BOOL)flag
138 key = CGSCreateCString("IgnoreForEvents");
139 ignore = CGSCreateBoolean( (flag ? kCGSTrue : kCGSFalse) );
140 CGSSetWindowProperty([NSApp contextID], (CGSWindowID)[self windowNumber], key, ignore);
142 CGSReleaseObj(ignore);
144 _reallyIgnoresEvents = flag;
147 - (void)orderFront:(id)sender
149 if ( _exitMode == ITTransientStatusWindowExitAfterDelay ) {
150 // set the timer, and orderOut: when it lapses.
153 if ( _entryEffect == ITTransientStatusWindowEffectNone ) {
154 [super orderFront:sender];
155 _visibilityState = ITTransientStatusWindowVisibleState;
157 [self performEffect];
161 - (void)makeKeyAndOrderFront:(id)sender
163 if ( _exitMode == ITTransientStatusWindowExitAfterDelay ) {
164 // set the timer, and orderOut: when it lapses.
167 if ( _entryEffect == ITTransientStatusWindowEffectNone ) {
168 [super makeKeyAndOrderFront:sender];
169 _visibilityState = ITTransientStatusWindowVisibleState;
171 [self performEffect];
172 [self makeKeyWindow];
176 - (void)orderOut:(id)sender
178 if ( _entryEffect == ITTransientStatusWindowEffectNone ) {
179 [super orderOut:sender];
180 _visibilityState = ITTransientStatusWindowHiddenState;
182 [self performEffect];
186 - (NSTimeInterval)animationResizeTime:(NSRect)newFrame
195 if ( _backgroundType == ITTransientStatusWindowRounded ) {
196 return _contentSubView;
198 return [super contentView];
202 - (void)setContentView:(NSView *)aView
204 if ( _backgroundType == ITTransientStatusWindowRounded ) {
205 [_contentSubView removeFromSuperview];
206 _contentSubView = aView;
207 [_contentSubView setFrame:[[super contentView] frame]];
208 [[super contentView] addSubview:_contentSubView];
209 [_contentSubView setNextResponder:self];
211 [super setContentView:aView];
217 - (ITTransientStatusWindowVisibilityState)visibilityState
219 return _visibilityState;
222 - (ITTransientStatusWindowExitMode)exitMode
227 - (void)setExitMode:(ITTransientStatusWindowExitMode)newMode
237 - (void)setExitDelay:(float)seconds
239 _exitDelay = seconds;
242 - (ITTransientStatusWindowBackgroundType)backgroundType
244 // return _backgroundType;
245 return ITTransientStatusWindowRounded;
248 - (void)setBackgroundType:(ITTransientStatusWindowBackgroundType)newType
250 // setBackgroundType: is currently ignored. Defaults to ITTransientStatusWindowRounded.
251 // _backgroundType = newType;
252 _backgroundType = ITTransientStatusWindowRounded;
255 - (ITTransientStatusWindowPosition)verticalPosition;
257 return _verticalPosition;
260 - (void)setVerticalPosition:(ITTransientStatusWindowPosition)newPosition;
262 _verticalPosition = newPosition;
265 - (ITTransientStatusWindowPosition)horizontalPosition;
267 return _horizontalPosition;
270 - (void)setHorizontalPosition:(ITTransientStatusWindowPosition)newPosition;
272 _horizontalPosition = newPosition;
275 - (ITTransientStatusWindowEffect)entryEffect
280 - (void)setEntryEffect:(ITTransientStatusWindowEffect)newEffect;
282 _entryEffect = newEffect;
285 - (ITTransientStatusWindowEffect)exitEffect;
290 - (void)setExitEffect:(ITTransientStatusWindowEffect)newEffect;
292 _exitEffect = newEffect;
296 /*************************************************************************/
298 #pragma mark PRIVATE METHODS
299 /*************************************************************************/
301 - (void)rebuildWindow;
303 if ( _backgroundType == ITTransientStatusWindowRounded ) {
304 ITGrayRoundedView *roundedView = [[[ITGrayRoundedView alloc] initWithFrame:[self frame]] autorelease];
306 [self setBackgroundColor:[NSColor clearColor]];
307 [self setHasShadow:NO];
310 [self setContentView:roundedView];
311 // [super setContentView:roundedView];
312 // [_contentSubView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
313 // [self setContentView:_contentSubView];
319 - (void)performEffect
321 if ( _visibilityState == ITTransientStatusWindowHiddenState ) {
322 _visibilityState = ITTransientStatusWindowEnteringState;
323 } else if ( _visibilityState == ITTransientStatusWindowVisibleState ) {
324 _visibilityState = ITTransientStatusWindowExitingState;
329 if ( _entryEffect == ITTransientStatusWindowEffectDissolve ) {
330 [self dissolveEffect];
331 } else if ( _entryEffect == ITTransientStatusWindowEffectSlideVertically ) {
332 [self slideVerticalEffect];
333 } else if ( _entryEffect == ITTransientStatusWindowEffectSlideHorizontally ) {
334 [self slideHorizontalEffect];
335 } else if ( _entryEffect == ITTransientStatusWindowEffectPivot ) {
340 - (void)dissolveEffect
342 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
343 [super orderFront:self];
344 _visibilityState = ITTransientStatusWindowVisibleState;
346 [super orderOut:self];
347 _visibilityState = ITTransientStatusWindowHiddenState;
351 - (void)slideVerticalEffect
353 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
354 [super orderFront:self];
355 _visibilityState = ITTransientStatusWindowVisibleState;
357 [super orderOut:self];
358 _visibilityState = ITTransientStatusWindowHiddenState;
362 - (void)slideHorizontalEffect
364 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
365 [super orderFront:self];
366 _visibilityState = ITTransientStatusWindowVisibleState;
368 [super orderOut:self];
369 _visibilityState = ITTransientStatusWindowHiddenState;
375 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
376 [self setPivot:315.0];
377 _effectProgress = 0.0;
378 [self setAlphaValue:0.0];
379 [super orderFront:self];
380 _effectTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / EFFECT_FPS)
382 selector:@selector(pivotStep)
386 [super orderOut:self];
387 _visibilityState = ITTransientStatusWindowHiddenState;
393 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
394 float interPivot = 0.0;
395 _effectProgress += (1.0 / (EFFECT_FPS * _effectTime));
396 _effectProgress = (_effectProgress < 1.0 ? _effectProgress : 1.0);
397 interPivot = (( sin((_effectProgress * pi) - (pi / 2)) + 1 ) / 2);
398 [self setPivot:((interPivot * 45) + 315)];
399 [self setAlphaValue:interPivot];
400 if ( _effectProgress >= 1.0 ) {
410 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
411 [_effectTimer invalidate];
413 _effectProgress = 0.0;
414 _visibilityState = ITTransientStatusWindowVisibleState;
421 - (void)setPivot:(float)angle
423 float degAngle = (angle * (pi / 180));
424 CGAffineTransform transform = CGAffineTransformMakeRotation(degAngle);
425 transform.tx = -32.0;
426 transform.ty = [self frame].size.height + 32.0;
427 CGSSetWindowTransform([NSApp contextID],
428 (CGSWindowID)[self windowNumber],
429 CGAffineTransformTranslate(transform,
430 (([self frame].origin.x - 32.0) * -1),
431 (([[self screen] frame].size.height - ([self frame].origin.y) + 32.0) * -1) ));