I want to replicate the background of dock Stacks in grid and list mode. The background is translucent black with a blur effect:
Example of dock stack in grid mode http://www.thecustommac.com/wp-content/uploads/2009/09/stack-highlight.jpg
The problem is that [CALayer backgroundFilters] only applies to content in the window, the filters are not applied to content in other windows. Here's my code:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
//make window transparent
self.window.backgroundColor = [NSColor clearColor];
[self.window setOpaque:NO];
[self.window setHasShadow:NO];
[self.window setStyleMask:NSBorderlessWindowMask];
//make the content view layer hosting
CALayer *rootLayer = [CALayer layer];
[[self.window contentView] setLayer:rootLayer];
[[self.window contentView] setWantsLayer:YES];
//blur the background contents - NOT WORKING!
[rootLayer setBackgroundColor:CGColorCreateGenericGray(0.0, .716)];
CIFilter *blurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
[blurFilter setDefaults];
[rootLayer setBackgroundFilters:[NSArray arrayWithObject: blurFilter]];
}
I can't think of how else to achieve this effect. (I've taken a look at the Display Services to see if there are any useful functions but I can't see any.)
Any ideas?
There is private API available this. Here is sample code by Rob Keniger:
In 10.5 you can add any core image filter to a window using the private function 'CGSAddWindowFilter'.
typedef void * CGSConnectionID;
extern OSStatus CGSNewConnection(const void **attr, CGSConnectionID *id);
- (void)enableBlurForWindow:(NSWindow *)window
{
CGSConnectionID _myConnection;
uint32_t __compositingFilter;
int __compositingType = 1; // Apply filter to contents underneath the window, then draw window normally on top
/* Make a new connection to CoreGraphics, alternatively you could use the main connection*/
CGSNewConnection(NULL , &_myConnection);
/* The following creates a new CoreImage filter, then sets its options with a dictionary of values*/
CGSNewCIFilterByName (_myConnection, (CFStringRef)@"CIGaussianBlur", &__compositingFilter);
NSDictionary *optionsDict = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:3.0] forKey:@"inputRadius"];
CGSSetCIFilterValuesFromDictionary(_myConnection, __compositingFilter, (CFDictionaryRef)optionsDict);
/* Now just switch on the filter for the window */
CGSAddWindowFilter(_myConnection, [window windowNumber], __compositingFilter, __compositingType );
}
The filters are not being used by the root layer: From the docs:
/* An array of filters that are applied to the background of the layer.
* The root layer ignores this property. Animatable. */
@property(copy) NSArray *backgroundFilters;
Your code has some error, here is the code that just works:
typedef void * CGSConnection;
extern OSStatus CGSNewConnection(const void **attributes, CGSConnection * id);
-(void)enableBlurForWindow:(NSWindow *)window {
CGSConnection thisConnection;
NSUInteger compositingFilter;
NSInteger compositingType = 1 << 0;
// Make a new connection to Core Graphics
CGSNewConnection(NULL, &thisConnection);
// Create a Core Image filter and set it up
CGSNewCIFilterByName(thisConnection, (CFStringRef)@"CIGaussianBlur", &compositingFilter);
NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:2] forKey:@"inputRadius"];
CGSSetCIFilterValuesFromDictionary(thisConnection, compositingFilter, (__bridge CFDictionaryRef)options);
// Apply the filter to the window
CGSAddWindowFilter(thisConnection, [window windowNumber], compositingFilter, compositingType);
}
Then, use it:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[_window setOpaque:NO];
[_window setBackgroundColor: [NSColor colorWithCalibratedHue:0.568 saturation:0.388 brightness:0.941 alpha:0.6]];
[self enableBlurForWindow:_window];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With