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 ( _entryEffect == ITTransientStatusWindowEffectNone ) {
150 [super orderFront:sender];
151 _visibilityState = ITTransientStatusWindowVisibleState;
153 [self performEffect];
155 if ( _exitMode == ITTransientStatusWindowExitAfterDelay ) {
156 // set the timer, and orderOut: when it lapses.
160 - (void)makeKeyAndOrderFront:(id)sender
162 if ( _exitMode == ITTransientStatusWindowExitAfterDelay ) {
163 // set the timer, and orderOut: when it lapses.
166 if ( _entryEffect == ITTransientStatusWindowEffectNone ) {
167 [super makeKeyAndOrderFront:sender];
168 _visibilityState = ITTransientStatusWindowVisibleState;
170 [self performEffect];
171 [self makeKeyWindow];
175 - (void)orderOut:(id)sender
177 if ( _entryEffect == ITTransientStatusWindowEffectNone ) {
178 [super orderOut:sender];
179 _visibilityState = ITTransientStatusWindowHiddenState;
181 [self performEffect];
185 - (NSTimeInterval)animationResizeTime:(NSRect)newFrame
194 if ( _backgroundType == ITTransientStatusWindowRounded ) {
195 return _contentSubView;
197 return [super contentView];
201 - (void)setContentView:(NSView *)aView
203 if ( _backgroundType == ITTransientStatusWindowRounded ) {
204 [_contentSubView removeFromSuperview];
205 _contentSubView = aView;
206 [_contentSubView setFrame:[[super contentView] frame]];
207 [[super contentView] addSubview:_contentSubView];
208 [_contentSubView setNextResponder:self];
210 [super setContentView:aView];
216 - (ITTransientStatusWindowVisibilityState)visibilityState
218 return _visibilityState;
221 - (ITTransientStatusWindowExitMode)exitMode
226 - (void)setExitMode:(ITTransientStatusWindowExitMode)newMode
236 - (void)setExitDelay:(float)seconds
238 _exitDelay = seconds;
241 - (ITTransientStatusWindowBackgroundType)backgroundType
243 // return _backgroundType;
244 return ITTransientStatusWindowRounded;
247 - (void)setBackgroundType:(ITTransientStatusWindowBackgroundType)newType
249 // setBackgroundType: is currently ignored. Defaults to ITTransientStatusWindowRounded.
250 // _backgroundType = newType;
251 _backgroundType = ITTransientStatusWindowRounded;
254 - (ITTransientStatusWindowPosition)verticalPosition;
256 return _verticalPosition;
259 - (void)setVerticalPosition:(ITTransientStatusWindowPosition)newPosition;
261 _verticalPosition = newPosition;
264 - (ITTransientStatusWindowPosition)horizontalPosition;
266 return _horizontalPosition;
269 - (void)setHorizontalPosition:(ITTransientStatusWindowPosition)newPosition;
271 _horizontalPosition = newPosition;
274 - (ITTransientStatusWindowEffect)entryEffect
279 - (void)setEntryEffect:(ITTransientStatusWindowEffect)newEffect;
281 _entryEffect = newEffect;
284 - (ITTransientStatusWindowEffect)exitEffect;
289 - (void)setExitEffect:(ITTransientStatusWindowEffect)newEffect;
291 _exitEffect = newEffect;
295 /*************************************************************************/
297 #pragma mark PRIVATE METHODS
298 /*************************************************************************/
300 - (void)rebuildWindow;
302 if ( _backgroundType == ITTransientStatusWindowRounded ) {
303 ITGrayRoundedView *roundedView = [[[ITGrayRoundedView alloc] initWithFrame:[self frame]] autorelease];
305 [self setBackgroundColor:[NSColor clearColor]];
306 [self setHasShadow:NO];
309 [self setContentView:roundedView];
310 // [super setContentView:roundedView];
311 // [_contentSubView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
312 // [self setContentView:_contentSubView];
318 - (void)performEffect
320 if ( _visibilityState == ITTransientStatusWindowHiddenState ) {
321 _visibilityState = ITTransientStatusWindowEnteringState;
322 } else if ( _visibilityState == ITTransientStatusWindowVisibleState ) {
323 _visibilityState = ITTransientStatusWindowExitingState;
328 if ( _entryEffect == ITTransientStatusWindowEffectDissolve ) {
329 [self dissolveEffect];
330 } else if ( _entryEffect == ITTransientStatusWindowEffectSlideVertically ) {
331 [self slideVerticalEffect];
332 } else if ( _entryEffect == ITTransientStatusWindowEffectSlideHorizontally ) {
333 [self slideHorizontalEffect];
334 } else if ( _entryEffect == ITTransientStatusWindowEffectPivot ) {
339 - (void)dissolveEffect
341 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
342 [super orderFront:self];
343 _visibilityState = ITTransientStatusWindowVisibleState;
345 [super orderOut:self];
346 _visibilityState = ITTransientStatusWindowHiddenState;
350 - (void)slideVerticalEffect
352 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
353 [super orderFront:self];
354 _visibilityState = ITTransientStatusWindowVisibleState;
356 [super orderOut:self];
357 _visibilityState = ITTransientStatusWindowHiddenState;
361 - (void)slideHorizontalEffect
363 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
364 [super orderFront:self];
365 _visibilityState = ITTransientStatusWindowVisibleState;
367 [super orderOut:self];
368 _visibilityState = ITTransientStatusWindowHiddenState;
374 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
375 [self setPivot:315.0];
376 _effectProgress = 0.0;
377 [self setAlphaValue:0.0];
378 [super orderFront:self];
379 _effectTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / EFFECT_FPS)
381 selector:@selector(pivotStep)
385 [super orderOut:self];
386 _visibilityState = ITTransientStatusWindowHiddenState;
392 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
393 float interPivot = 0.0;
394 _effectProgress += (1.0 / (EFFECT_FPS * _effectTime));
395 _effectProgress = (_effectProgress < 1.0 ? _effectProgress : 1.0);
396 interPivot = (( sin((_effectProgress * pi) - (pi / 2)) + 1 ) / 2);
397 [self setPivot:((interPivot * 45) + 315)];
398 [self setAlphaValue:interPivot];
399 if ( _effectProgress >= 1.0 ) {
409 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
410 [_effectTimer invalidate];
412 _effectProgress = 0.0;
413 _visibilityState = ITTransientStatusWindowVisibleState;
420 - (void)setPivot:(float)angle
422 float degAngle = (angle * (pi / 180));
423 CGAffineTransform transform = CGAffineTransformMakeRotation(degAngle);
424 transform.tx = -32.0;
425 transform.ty = [self frame].size.height + 32.0;
426 CGSSetWindowTransform([NSApp contextID],
427 (CGSWindowID)[self windowNumber],
428 CGAffineTransformTranslate(transform,
429 (([self frame].origin.x - 32.0) * -1),
430 (([[self screen] frame].size.height - ([self frame].origin.y) + 32.0) * -1) ));