Fixed a leak found by the clang static analyzer. I have to hope this works, because I can't see a way to switch to this transition in the Growl prefpane.
Note: This is an original fix by me, not cribbed from Adium (GPL) source code.
2 * Project: RippleEffect
4 * Author: Andrew Wellington
7 * Copyright (C) 2005 Andrew Wellington.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
22 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 /* NSWindow Category for our bonus features */
36 @interface NSWindow(AWRipplePrivate)
38 - (void)scaleX:(double)x Y:(double)y;
41 @implementation NSWindow(AWRipplePrivate)
46 - (void)scaleX:(double)x Y:(double)y {
47 CGAffineTransform original;
50 //NSLog(@"%@", NSStringFromRect(_frame));
51 NSPoint point = NSMakePoint(_frame.size.width / 2.0, _frame.size.height / 2.0);
53 if ([[NSScreen screens] count]) {
54 screenFrame = [[[NSScreen screens] objectAtIndex:0] frame];
56 scalePoint.x = _frame.origin.x + point.x;
57 scalePoint.y = - ((_frame.origin.y + point.y) - screenFrame.size.height);
59 original.a = 1.0 ; original.b = 0.0 ;
60 original.c = 0.0 ; original.d = 1.0 ;
61 original.tx = - _frame.origin.x ;
62 original.ty = + _frame.origin.y + _frame.size.height - NSMaxY(screenFrame);
64 original = CGAffineTransformTranslate(original, scalePoint.x, scalePoint.y);
65 original = CGAffineTransformScale(original, x, y);
66 original = CGAffineTransformTranslate(original, -scalePoint.x, -scalePoint.y);
68 CGSSetWindowTransform(_CGSDefaultConnection(), _windowNum, original);
74 /* NSWindow Category implementation for easy rippling */
75 @implementation NSWindow(AWRipple)
80 rippler = [[AWRippler alloc] init];
81 [rippler rippleWindow:self];
86 /* Interface for Core Image Core Graphics Server filter */
87 @interface CICGSFilter : NSObject
90 unsigned int _filter_id;
93 + (id)filterWithFilter:(CIFilter *)filter connectionID:(CGSConnection)cid;
94 - (id)initWithFilter:(CIFilter *)filter connectionID:(CGSConnection)cid;
96 - (void)setValue:(id)value forKey:(NSString *)key;
97 - (void)setValuesForKeysWithDictionary:(NSDictionary *)dict;
98 - (int)addToWindow:(CGSWindow)windowID flags:(unsigned int)flags;
99 - (int)removeFromWindow:(CGSWindow)windowID;
103 /* NSWindow subclass for our covering window */
104 @interface AWRippleWindow : NSWindow {
108 @implementation AWRippleWindow
109 - (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag {
110 #pragma unused (aStyle, bufferingType, flag)
111 NSWindow* result = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
112 [result setBackgroundColor: [NSColor clearColor]];
113 [result setAlphaValue:1.0];
114 [result setOpaque:NO];
119 /* NSView subclass for our covering window */
120 @interface AWRippleView : NSView {
124 @implementation AWRippleView
125 -(void)drawRect:(NSRect)rect
127 #pragma unused (rect)
128 NSLog(@"%s", __FUNCTION__);
130 [[NSColor clearColor] set];
131 NSRectFill([self frame]);
135 /* CoreGraphics private stuff */
136 extern CGSConnection _CGSDefaultConnection(void);
138 /* The magic rippler class */
139 @implementation AWRippler
155 - (void) rippleWindow:(NSWindow *)rippleWindow
157 CGSConnection cid = _CGSDefaultConnection();
162 NSEnumerator *screenEnum;
165 if (!FLOAT_EQ(startTime, 0.0))
168 rippleRect = [rippleWindow frame];
169 ripplingWindow = [rippleWindow retain];
171 /* create covering window */
172 rect = NSMakeRect(0.0,0.0,0.0,0.0);
173 screens = [NSScreen screens];
174 screenEnum = [screens objectEnumerator];
176 while ((screen = [screenEnum nextObject]))
178 rect = NSUnionRect(rect, [screen frame]);
181 win = [[AWRippleWindow alloc] initWithContentRect:rect
182 styleMask:NSBorderlessWindowMask
183 backing:NSBackingStoreNonretained
185 [win setBackgroundColor:[NSColor clearColor]];
187 [win setHasShadow:NO];
188 [win setContentView:[[[AWRippleView alloc] initWithFrame:[win frame]] autorelease]];
190 [win orderFrontRegardless];
191 [rippleWindow orderWindow:NSWindowAbove relativeTo:[win windowNum]];
194 /* calculate the rectangle in the covering window */
195 screenRect = [[[NSScreen screens] objectAtIndex:0] frame];
196 rippleRect.origin.y = - (NSMaxY(rippleRect) - screenRect.size.height);
199 rippleFilter = [[CIFilter filterWithName:@"CIShapedWaterRipple"] retain];
200 [rippleFilter setDefaults];
201 [rippleFilter setValue:[NSNumber numberWithFloat:40.0] forKey:@"inputCornerRadius"];
202 [rippleFilter setValue:[CIVector vectorWithX:rippleRect.origin.x-40.0 Y:(rippleRect.origin.y - 40.0)] forKey:@"inputPoint0"];
203 [rippleFilter setValue:[CIVector vectorWithX:(rippleRect.origin.x + rippleRect.size.width + 40.0) Y:(rippleRect.origin.y + rippleRect.size.height + 40.0)] forKey:@"inputPoint1"];
206 [rippleFilter setValue:[NSNumber numberWithFloat:0.0] forKey:@"inputPhase"];
208 windowFilter = [[CICGSFilter filterWithFilter:rippleFilter connectionID:cid] retain];
209 [windowFilter addToWindow:aWindowID flags:0x3001];
210 aWindowID = [win windowNum];
213 [NSThread detachNewThreadSelector:@selector(animationLoop:) toTarget:self withObject:self];
216 - (void)animationLoop:(id)sender
218 #pragma unused (sender)
219 NSAutoreleasePool *pool;
220 CGSConnection cid = _CGSDefaultConnection();
221 CICGSFilter *oldFilter = windowFilter;
224 CGAffineTransform originalTransform;
226 CGSGetWindowTransform(cid, [ripplingWindow windowNum], &originalTransform);
228 pool = [[NSAutoreleasePool alloc] init];
230 startTime = CFAbsoluteTimeGetCurrent();
231 now = CFAbsoluteTimeGetCurrent();
233 while (now < (startTime + 2.5) && (now >= startTime))
235 if (now - startTime < 1.5) {
236 scale = 1.0 - exp(-2.4 * (now - startTime)) * sin(40.0/M_PI * (now - startTime)) * 0.15;
237 //[ripplingWindow scaleX:scale Y:scale];
241 CGSSetWindowTransform(cid, [ripplingWindow windowNum], originalTransform);
244 [rippleFilter setValue:[NSNumber numberWithFloat:160*(now - startTime)] forKey:@"inputPhase"];
245 windowFilter = [[CICGSFilter filterWithFilter:rippleFilter connectionID:cid] retain];
246 [windowFilter addToWindow:aWindowID flags:0x3001];
247 [oldFilter removeFromWindow:aWindowID];
249 now = CFAbsoluteTimeGetCurrent();
251 CGSSetWindowTransform(cid, [ripplingWindow windowNum], originalTransform);
253 [windowFilter removeFromWindow:aWindowID];
254 [rippleFilter release];
255 [windowFilter release];
256 [ripplingWindow release];
257 [win orderOut: self];