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 view.
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 _screenPadding = 32.0;
100 _entryEffect = ITTransientStatusWindowEffectNone;
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 - (ITWindowEffect *)entryEffect
279 - (void)setEntryEffect:(ITWindowEffect *)newEffect
281 [_entryEffect autorelease];
282 _entryEffect = [newEffect retain];
285 - (ITWindowEffect *)exitEffect
290 - (void)setExitEffect:(ITWindowEffect *)newEffect
292 [_exitEffect autorelease];
293 _exitEffect = [newEffect retain];
297 /*************************************************************************/
299 #pragma mark PRIVATE METHODS
300 /*************************************************************************/
302 - (void)rebuildWindow;
304 if ( _backgroundType == ITTransientStatusWindowRounded ) {
305 ITGrayRoundedView *roundedView = [[[ITGrayRoundedView alloc] initWithFrame:[self frame]] autorelease];
307 [self setBackgroundColor:[NSColor clearColor]];
308 [self setHasShadow:NO];
311 [self setContentView:roundedView];
312 // [super setContentView:roundedView];
313 // [_contentSubView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
314 // [self setContentView:_contentSubView];
320 - (void)performEffect
322 if ( _visibilityState == ITTransientStatusWindowHiddenState ) {
323 _visibilityState = ITTransientStatusWindowEnteringState;
324 } else if ( _visibilityState == ITTransientStatusWindowVisibleState ) {
325 _visibilityState = ITTransientStatusWindowExitingState;
330 if ( _entryEffect == ITTransientStatusWindowEffectDissolve ) {
331 [self dissolveEffect];
332 } else if ( _entryEffect == ITTransientStatusWindowEffectSlideVertically ) {
333 [self slideVerticalEffect];
334 } else if ( _entryEffect == ITTransientStatusWindowEffectSlideHorizontally ) {
335 [self slideHorizontalEffect];
336 } else if ( _entryEffect == ITTransientStatusWindowEffectPivot ) {
341 - (void)dissolveEffect
343 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
344 [super orderFront:self];
345 _visibilityState = ITTransientStatusWindowVisibleState;
347 [super orderOut:self];
348 _visibilityState = ITTransientStatusWindowHiddenState;
352 - (void)slideVerticalEffect
354 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
355 [super orderFront:self];
356 _visibilityState = ITTransientStatusWindowVisibleState;
358 [super orderOut:self];
359 _visibilityState = ITTransientStatusWindowHiddenState;
363 - (void)slideHorizontalEffect
365 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
366 [super orderFront:self];
367 _visibilityState = ITTransientStatusWindowVisibleState;
369 [super orderOut:self];
370 _visibilityState = ITTransientStatusWindowHiddenState;
376 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
377 [self setPivot:315.0];
378 _effectProgress = 0.0;
379 [self setAlphaValue:0.0];
380 [super orderFront:self];
381 _effectTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / EFFECT_FPS)
383 selector:@selector(pivotStep)
387 [super orderOut:self];
388 _visibilityState = ITTransientStatusWindowHiddenState;
394 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
395 float interPivot = 0.0;
396 _effectProgress += (1.0 / (EFFECT_FPS * _effectTime));
397 _effectProgress = (_effectProgress < 1.0 ? _effectProgress : 1.0);
398 interPivot = (( sin((_effectProgress * pi) - (pi / 2)) + 1 ) / 2);
399 [self setPivot:((interPivot * 45) + 315)];
400 [self setAlphaValue:interPivot];
401 if ( _effectProgress >= 1.0 ) {
411 if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
412 [_effectTimer invalidate];
414 _effectProgress = 0.0;
415 _visibilityState = ITTransientStatusWindowVisibleState;
422 - (void)setPivot:(float)angle
424 float degAngle = (angle * (pi / 180));
425 CGAffineTransform transform = CGAffineTransformMakeRotation(degAngle);
428 transform.tx = -32.0;
429 transform.ty = [self frame].size.height + 32.0;
431 CGSSetWindowTransform([NSApp contextID],
432 (CGSWindowID)[self windowNumber],
433 CGAffineTransformTranslate(transform,
434 (([self frame].origin.x - 32.0) * -1),
435 (([[self screen] frame].size.height - ([self frame].origin.y) + 32.0) * -1) ));