1// ServerDelegate.mm: OVDisplayServer.app delegated object 2// 3// Copyright (c) 2004-2006 The OpenVanilla Project (http://openvanilla.org) 4// All rights reserved. 5// 6// Redistribution and use in source and binary forms, with or without 7// modification, are permitted provided that the following conditions 8// are met: 9// 10// 1. Redistributions of source code must retain the above copyright 11// notice, this list of conditions and the following disclaimer. 12// 2. Redistributions in binary form must reproduce the above copyright 13// notice, this list of conditions and the following disclaimer in the 14// documentation and/or other materials provided with the distribution. 15// 3. Neither the name of OpenVanilla nor the names of its contributors 16// may be used to endorse or promote products derived from this software 17// without specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29// POSSIBILITY OF SUCH DAMAGE. 30 31#import "ServerDelegate.h" 32#import "NSDictionaryExtension.h" 33#import "NSStringExtension.h" 34#import <Carbon/Carbon.h> 35 36#define CVIB_FADEWAIT 0.5 // fade after 0.5 sec 37#define CVIB_FADEINTERVAL 0.05 // 0.05 sec/frame 38#define CVIB_FADEVALUE 0.025 // alphaValue-=0.025/frame 39 40enum { 41 OVDPS_NOTIFY_DEFAULT=0, 42 OVDPS_NOTIFY_SILENT=1 43}; 44 45// nop function to prevent Objective-C remote object failure 46// in some architectures--DO NOT REMOVE THIS WITHOUT EXTENSIVE TESTING! 47 48void nop() { 49 volatile a=10; 50} 51 52 53void CVFixWindowOrigin(NSWindow *w, Point p); 54 55@implementation ServerDelegate 56- (void)setConfig:(NSDictionary*)cfg { 57 [self applyConfig:cfg window:candi textField:canditext]; 58 [self applyConfig:cfg window:noti textField:notitext]; 59 notialpha=[noti alphaValue]; 60 61 notistyle=OVDPS_NOTIFY_DEFAULT; 62 NSString *ns=[cfg valueForKey:@"notificationStyle" default:@"default"]; 63 if ([ns isEqualToString:@"silent"]) notistyle=OVDPS_NOTIFY_SILENT; 64} 65- (void)candidateShow { 66 candion=YES; 67 [self solveConflict]; 68 [candi orderFront:self]; 69 // nop(); 70} 71- (void)candidateHide { 72 candion=NO; 73 [candi orderOut:self]; 74 // nop(); 75} 76- (void)candidateUpdate:(bycopy NSString*)s position:(Point)p { 77 [self updateTextInWindow:candi textField:canditext text:s position:p]; 78} 79- (void)notifyMessage:(bycopy NSString*)s position:(Point)p { 80 [self updateTextInWindow:noti textField:notitext text:s position:p]; 81 [self solveConflict]; 82 83 if (notistyle!=OVDPS_NOTIFY_DEFAULT) return; 84 [noti orderFront:self]; 85 // nop(); 86} 87- (void)notifyClose { 88 [noti orderOut:self]; 89 // nop(); 90} 91- (void)notifyFade { 92 if (fadetimer) [self stopTimer]; 93 94 if (notistyle!=OVDPS_NOTIFY_DEFAULT) return; 95 fadetimer=[NSTimer scheduledTimerWithTimeInterval:CVIB_FADEWAIT target:self selector:@selector(fadeStart) userInfo:nil repeats:NO]; 96} 97- (void)aboutDialog { 98 [aboutdialog setLevel:NSScreenSaverWindowLevel]; 99 [aboutdialog orderFront:self]; 100 // nop(); 101} 102- (void)dealloc { 103 [defaultbackground release]; 104 [candi release]; 105 [super dealloc]; 106} 107- (void)awakeFromNib { 108 // NSLog(@"OVDisplayServer started"); 109 NSConnection *c=[NSConnection defaultConnection]; 110 [c setRootObject:self]; 111 if ([c registerName:OVDSPSRVR_NAME]) ; // NSLog(@"OVDisplayServer registered"); 112 else NSLog(@"OVDisplayServer registration failed"); 113 114 NSRect fr=NSMakeRect(0, 0, 100, 20); 115 candion=NO; 116 candi=[self createWindow:fr]; 117 defaultbackground=[[candi backgroundColor] retain]; 118 canditext=[self createTextField:fr]; 119 [[candi contentView] addSubview:canditext]; 120 noti=[self createWindow:fr]; 121 notitext=[self createTextField:fr]; 122 [[noti contentView] addSubview:notitext]; 123 124 fadetimer=nil; 125} 126- (void)stopTimer { 127 if (fadetimer) [fadetimer invalidate]; 128 fadetimer=nil; 129 [noti setAlphaValue:notialpha]; 130} 131- (void)fadeStart { 132 [fadetimer invalidate]; 133 fadetimer=[NSTimer scheduledTimerWithTimeInterval:CVIB_FADEINTERVAL target:self selector:@selector(fadeWork) userInfo:nil repeats:YES]; 134 fadealpha=notialpha; 135} 136- (void)fadeWork { 137 fadealpha-=CVIB_FADEVALUE; 138 if (fadealpha<=0) { 139 [noti orderOut:self]; 140 [self stopTimer]; 141 // nop(); 142 return; 143 } 144 [noti setAlphaValue:fadealpha]; 145 146} 147- (void)solveConflict { 148 if (!candion) return; 149 NSRect cfr, nfr; 150 cfr=[candi frame]; 151 nfr=[noti frame]; 152 if (cfr.origin.y+cfr.size.height == nfr.origin.y+nfr.size.height) { 153 nfr.origin.y = cfr.origin.y - (nfr.size.height + 5); 154 [noti setFrameOrigin:nfr.origin]; 155 } 156} 157- (void)updateTextInWindow:(NSWindow*)w textField:(NSTextField*)t text:(NSString*)s position:(Point)p { 158 [t setStringValue:s]; 159 [t sizeToFit]; 160 NSRect r=[t frame]; 161 [w setContentSize:r.size]; 162 163 CVFixWindowOrigin(w, p); 164} 165- (NSWindow*)createWindow:(NSRect)fr { 166 NSWindow *w=[[NSWindow alloc] initWithContentRect:fr styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; 167 [w setLevel:NSScreenSaverWindowLevel]; 168 [w setMovableByWindowBackground:YES]; 169 [w setContentView:[[NSView alloc] initWithFrame:[w contentRectForFrameRect:fr]]]; 170 return w; 171} 172- (NSTextField*)createTextField:(NSRect)fr { 173 NSTextField *t=[[NSTextField alloc] initWithFrame:fr]; 174 [t setEditable:NO]; 175 [t setSelectable:NO]; 176 [t setBordered:NO]; 177 [t setDrawsBackground:NO]; 178 [t setFrameOrigin:NSMakePoint(0,0)]; 179 return t; 180} 181- (void)applyConfig:(NSDictionary*)d window:(NSWindow*)w textField:(NSTextField*)t { 182 float alpha=[[d valueForKey:@"opacity" default:@"1.0"] floatValue]; 183 NSColor *fc=[[d valueForKey:@"foreground" default:@"1.0 1.0 1.0"] colorByString]; 184 NSString *img=[d valueForKey:@"backgroundImage" default:@""]; 185 NSString *font=[d valueForKey:@"font" default:@"Lucida Grande"]; 186 float s=[[d valueForKey:@"size" default:@"18"] floatValue]; 187 188 [w setAlphaValue:alpha]; 189 [w setHasShadow:YES]; 190 [w setOpaque:YES]; 191 if ([img length]) { 192 NSImage *i=[[NSImage alloc] initByReferencingFile:img]; 193 if (i && [i isValid]) { 194 [i autorelease]; 195 NSColor *c=[NSColor colorWithPatternImage:i]; 196 [w setBackgroundColor:c]; 197 } 198 } 199 else { 200 // no image, use color 201 NSString *bcstr=[d valueForKey:@"background" default:@"1.0 1.0 1.0"]; 202 if ([bcstr isEqualToString:@"transparent"]) { 203 [w setHasShadow:NO]; 204 [w setOpaque:NO]; 205 [w setBackgroundColor:[NSColor clearColor]]; 206 } 207 else if ([bcstr isEqualToString:@"none"]) { 208 [w setBackgroundColor:defaultbackground]; 209 } 210 else { 211 NSColor *bc=[bcstr colorByString]; 212 [w setBackgroundColor:bc]; 213 } 214 } 215 216 [t setFont:[NSFont fontWithName:font size:s]]; 217 [t setTextColor:fc]; 218} 219@end 220 221void CVFixWindowOrigin(NSWindow *w, Point p) { 222 // first of all, we do a y-coordiate transformation (mirroring) 223 NSPoint np=NSMakePoint((float)p.h, (float)p.v); 224 225 float maxh=480; // a silly default, but anyway the below loop always runs 226 NSArray *sa=[NSScreen screens]; 227 int i, c=[sa count]; 228 for (i=0; i<c; i++) { 229 float h=[[sa objectAtIndex:i] frame].size.height; 230 if (h > maxh) maxh=h; 231 } 232 233 np.y=maxh-np.y; 234 235 NSSize s=[w frame].size; 236 237 // now we determine the window frame 238 NSRect f=[[NSScreen mainScreen] frame]; 239 BOOL found=NO; 240 241 for (i=0; i<c; i++) { 242 NSRect sf=[[sa objectAtIndex:i] frame]; 243 if (NSPointInRect(np, sf)) { 244 f=sf; 245 found=YES; 246 } 247 } 248 249 // if the origin is out of bound, we place the origin in the center of the main screen 250 if (found) { 251 np.y-=s.height; // must offset the height of the window 252 if (np.y > f.origin.y+f.size.height-s.height) np.y=f.origin.y+f.size.height-s.height; 253 if (np.x > f.origin.x+f.size.width-s.width) np.x=f.origin.x+f.size.width-s.width; 254 if (np.y < f.origin.y) np.y=f.origin.y; 255 if (np.x < f.origin.x) np.x=f.origin.x; 256 } 257 else { 258 np.x = f.origin.x + (f.size.width-s.width)/2; 259 np.y = f.origin.y + (f.size.height-s.height)/2; 260 } 261 262 [w setFrameOrigin:np]; 263} 264