Plugins/Displays/Bubbles/GrowlBubblesWindowController.m
author boredzo
Sun Jul 06 15:10:15 2008 +0000 (2008-07-06)
changeset 4135 9d0747a53f45
parent 3958 157225f6bfee
child 4246 4f52d1d98978
child 4771 d398be175a6e
permissions -rw-r--r--
CFRelease the duration preference value if we get one. Found by the clang static analyzer.
     1 //
     2 //  GrowlBubblesWindowController.m
     3 //  Growl
     4 //
     5 //  Created by Nelson Elhage on Wed Jun 09 2004.
     6 //  Name changed from KABubbleWindowController.m by Justin Burns on Fri Nov 05 2004.
     7 //  Copyright (c) 2004-2006 The Growl Project. All rights reserved.
     8 //
     9 
    10 #import "GrowlBubblesWindowController.h"
    11 #import "GrowlBubblesWindowView.h"
    12 #import "GrowlBubblesPrefsController.h"
    13 #import "GrowlBubblesDefines.h"
    14 #import "GrowlApplicationNotification.h"
    15 #import "NSWindow+Transforms.h"
    16 #include "CFDictionaryAdditions.h"
    17 #import "GrowlWindowTransition.h"
    18 #import "GrowlFadingWindowTransition.h"
    19 #import "GrowlPositionController.h"
    20 
    21 @implementation GrowlBubblesWindowController
    22 
    23 #define GrowlBubblesPadding				5.0f
    24 
    25 #pragma mark -
    26 
    27 - (id) init {
    28 	screenNumber = 0U;
    29 	READ_GROWL_PREF_INT(GrowlBubblesScreen, GrowlBubblesPrefDomain, &screenNumber);
    30 	NSArray *screens = [NSScreen screens];
    31 	unsigned screensCount = [screens count];
    32 	if (screensCount) {
    33 		[self setScreen:((screensCount >= (screenNumber + 1)) ? [screens objectAtIndex:screenNumber] : [screens objectAtIndex:0])];
    34 	}
    35 
    36 	CFNumberRef prefsDuration = NULL;
    37 	READ_GROWL_PREF_VALUE(GrowlBubblesDuration, GrowlBubblesPrefDomain, CFNumberRef, &prefsDuration);
    38 	[self setDisplayDuration:(prefsDuration ?
    39 							  [(NSNumber *)prefsDuration doubleValue] :
    40 							  GrowlBubblesDurationPrefDefault)];
    41 	if (prefsDuration) CFRelease(prefsDuration);
    42 
    43 	// I tried setting the width/height to zero, since the view resizes itself later.
    44 	// This made it ignore the alpha at the edges (using 1.0 instead). Why?
    45 	// A window with a frame of NSZeroRect is off-screen and doesn't respect opacity even
    46 	// if moved on screen later. -Evan
    47 	NSPanel *panel = [[NSPanel alloc] initWithContentRect:NSMakeRect(0.0f, 0.0f, 270.0f, 65.0f)
    48 												styleMask:NSBorderlessWindowMask | NSNonactivatingPanelMask
    49 												  backing:NSBackingStoreBuffered
    50 													defer:YES];
    51 	NSRect panelFrame = [panel frame];
    52 	[panel setBecomesKeyOnlyIfNeeded:YES];
    53 	[panel setHidesOnDeactivate:NO];
    54 	[panel setBackgroundColor:[NSColor clearColor]];
    55 	[panel setLevel:NSStatusWindowLevel];
    56 	[panel setSticky:YES];
    57 	[panel setAlphaValue:0.0f];
    58 	[panel setOpaque:NO];
    59 	[panel setHasShadow:YES];
    60 	[panel setCanHide:NO];
    61 	[panel setOneShot:YES];
    62 	[panel useOptimizedDrawing:YES];
    63 	[panel setMovableByWindowBackground:NO];
    64 
    65 	// Create the content view...
    66 	GrowlBubblesWindowView *view = [[GrowlBubblesWindowView alloc] initWithFrame:panelFrame];
    67 	[view setTarget:self];
    68 	[view setAction:@selector(notificationClicked:)];
    69 	[panel setContentView:view];
    70 	[view release];
    71 
    72 	// call super so everything else is set up...
    73 	if ((self = [super initWithWindow:panel])) {
    74 		// set up the transitions...
    75 		GrowlFadingWindowTransition *fader = [[GrowlFadingWindowTransition alloc] initWithWindow:panel];
    76 		[self addTransition:fader];
    77 		[self setStartPercentage:0 endPercentage:100 forTransition:fader];
    78 		[fader setAutoReverses:YES];
    79 		[fader release];
    80 	}
    81 	[panel release];
    82 
    83 	return self;
    84 }
    85 
    86 #pragma mark -
    87 
    88 - (void) setNotification: (GrowlApplicationNotification *) theNotification {
    89 	[super setNotification:theNotification];
    90 	if (!theNotification)
    91 		return;
    92 
    93 	NSDictionary *noteDict = [notification dictionaryRepresentation];
    94 	NSString *title = [notification title];
    95 	NSString *text  = [notification notificationDescription];
    96 	NSImage *icon   = getObjectForKey(noteDict, GROWL_NOTIFICATION_ICON);
    97 	int priority    = getIntegerForKey(noteDict, GROWL_NOTIFICATION_PRIORITY);
    98 	
    99 	GrowlBubblesWindowView *view = [[self window] contentView];
   100 	[view setPriority:priority];
   101 	[view setTitle:title];
   102 	[view setText:text];
   103 	[view setIcon:icon];
   104 	[view sizeToFit];
   105 }
   106 
   107 #pragma mark -
   108 #pragma mark positioning methods
   109 
   110 - (NSPoint) idealOriginInRect:(NSRect)rect {
   111 	NSRect viewFrame = [[[self window] contentView] frame];
   112 	enum GrowlPosition originatingPosition = [[GrowlPositionController sharedInstance] originPosition];
   113 	NSPoint idealOrigin;
   114 	
   115 	switch(originatingPosition){
   116 		case GrowlTopRightPosition:
   117 			idealOrigin = NSMakePoint(NSMaxX(rect) - NSWidth(viewFrame) - GrowlBubblesPadding,
   118 									  NSMaxY(rect) - GrowlBubblesPadding - NSHeight(viewFrame));
   119 			break;
   120 		case GrowlTopLeftPosition:
   121 			idealOrigin = NSMakePoint(NSMinX(rect) + GrowlBubblesPadding,
   122 									  NSMaxY(rect) - GrowlBubblesPadding - NSHeight(viewFrame));
   123 			break;
   124 		case GrowlBottomLeftPosition:
   125 			idealOrigin = NSMakePoint(NSMinX(rect) + GrowlBubblesPadding,
   126 									  NSMinY(rect) + GrowlBubblesPadding);
   127 			break;
   128 		case GrowlBottomRightPosition:
   129 			idealOrigin = NSMakePoint(NSMaxX(rect) - NSWidth(viewFrame) - GrowlBubblesPadding,
   130 									  NSMinY(rect) + GrowlBubblesPadding);
   131 			break;
   132 		default:
   133 			idealOrigin = NSMakePoint(NSMaxX(rect) - NSWidth(viewFrame) - GrowlBubblesPadding,
   134 									  NSMaxY(rect) - GrowlBubblesPadding - NSHeight(viewFrame));
   135 			break;			
   136 	}
   137 	
   138 	return idealOrigin;	
   139 }
   140 
   141 - (enum GrowlExpansionDirection) primaryExpansionDirection {
   142 	enum GrowlPosition originatingPosition = [[GrowlPositionController sharedInstance] originPosition];
   143 	enum GrowlExpansionDirection directionToExpand;
   144 	
   145 	switch(originatingPosition){
   146 		case GrowlTopLeftPosition:
   147 			directionToExpand = GrowlDownExpansionDirection;
   148 			break;
   149 		case GrowlTopRightPosition:
   150 			directionToExpand = GrowlDownExpansionDirection;
   151 			break;
   152 		case GrowlBottomLeftPosition:
   153 			directionToExpand = GrowlUpExpansionDirection;
   154 			break;
   155 		case GrowlBottomRightPosition:
   156 			directionToExpand = GrowlUpExpansionDirection;
   157 			break;
   158 		default:
   159 			directionToExpand = GrowlDownExpansionDirection;
   160 			break;			
   161 	}
   162 	
   163 	return directionToExpand;
   164 }
   165 
   166 - (enum GrowlExpansionDirection) secondaryExpansionDirection {
   167 	enum GrowlPosition originatingPosition = [[GrowlPositionController sharedInstance] originPosition];
   168 	enum GrowlExpansionDirection directionToExpand;
   169 	
   170 	switch(originatingPosition){
   171 		case GrowlTopLeftPosition:
   172 			directionToExpand = GrowlRightExpansionDirection;
   173 			break;
   174 		case GrowlTopRightPosition:
   175 			directionToExpand = GrowlLeftExpansionDirection;
   176 			break;
   177 		case GrowlBottomLeftPosition:
   178 			directionToExpand = GrowlRightExpansionDirection;
   179 			break;
   180 		case GrowlBottomRightPosition:
   181 			directionToExpand = GrowlLeftExpansionDirection;
   182 			break;
   183 		default:
   184 			directionToExpand = GrowlRightExpansionDirection;
   185 			break;
   186 	}
   187 	
   188 	return directionToExpand;
   189 }
   190 
   191 - (float) requiredDistanceFromExistingDisplays {
   192 	return GrowlBubblesPadding;
   193 }
   194 
   195 @end