// ServerDelegate.mm: OVDisplayServer.app delegated object // // Copyright (c) 2004-2006 The OpenVanilla Project (http://openvanilla.org) // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // 3. Neither the name of OpenVanilla nor the names of its contributors // may be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. #import "ServerDelegate.h" #import "NSDictionaryExtension.h" #import "NSStringExtension.h" #import #define CVIB_FADEWAIT 0.5 // fade after 0.5 sec #define CVIB_FADEINTERVAL 0.05 // 0.05 sec/frame #define CVIB_FADEVALUE 0.025 // alphaValue-=0.025/frame enum { OVDPS_NOTIFY_DEFAULT=0, OVDPS_NOTIFY_SILENT=1 }; // nop function to prevent Objective-C remote object failure // in some architectures--DO NOT REMOVE THIS WITHOUT EXTENSIVE TESTING! void nop() { volatile a=10; } void CVFixWindowOrigin(NSWindow *w, Point p); @implementation ServerDelegate - (void)setConfig:(NSDictionary*)cfg { [self applyConfig:cfg window:candi textField:canditext]; [self applyConfig:cfg window:noti textField:notitext]; notialpha=[noti alphaValue]; notistyle=OVDPS_NOTIFY_DEFAULT; NSString *ns=[cfg valueForKey:@"notificationStyle" default:@"default"]; if ([ns isEqualToString:@"silent"]) notistyle=OVDPS_NOTIFY_SILENT; } - (void)candidateShow { candion=YES; [self solveConflict]; [candi orderFront:self]; // nop(); } - (void)candidateHide { candion=NO; [candi orderOut:self]; // nop(); } - (void)candidateUpdate:(bycopy NSString*)s position:(Point)p { [self updateTextInWindow:candi textField:canditext text:s position:p]; } - (void)notifyMessage:(bycopy NSString*)s position:(Point)p { [self updateTextInWindow:noti textField:notitext text:s position:p]; [self solveConflict]; if (notistyle!=OVDPS_NOTIFY_DEFAULT) return; [noti orderFront:self]; // nop(); } - (void)notifyClose { [noti orderOut:self]; // nop(); } - (void)notifyFade { if (fadetimer) [self stopTimer]; if (notistyle!=OVDPS_NOTIFY_DEFAULT) return; fadetimer=[NSTimer scheduledTimerWithTimeInterval:CVIB_FADEWAIT target:self selector:@selector(fadeStart) userInfo:nil repeats:NO]; } - (void)aboutDialog { [aboutdialog setLevel:NSScreenSaverWindowLevel]; [aboutdialog orderFront:self]; // nop(); } - (void)dealloc { [defaultbackground release]; [candi release]; [super dealloc]; } - (void)awakeFromNib { // NSLog(@"OVDisplayServer started"); NSConnection *c=[NSConnection defaultConnection]; [c setRootObject:self]; if ([c registerName:OVDSPSRVR_NAME]) ; // NSLog(@"OVDisplayServer registered"); else NSLog(@"OVDisplayServer registration failed"); NSRect fr=NSMakeRect(0, 0, 100, 20); candion=NO; candi=[self createWindow:fr]; defaultbackground=[[candi backgroundColor] retain]; canditext=[self createTextField:fr]; [[candi contentView] addSubview:canditext]; noti=[self createWindow:fr]; notitext=[self createTextField:fr]; [[noti contentView] addSubview:notitext]; fadetimer=nil; } - (void)stopTimer { if (fadetimer) [fadetimer invalidate]; fadetimer=nil; [noti setAlphaValue:notialpha]; } - (void)fadeStart { [fadetimer invalidate]; fadetimer=[NSTimer scheduledTimerWithTimeInterval:CVIB_FADEINTERVAL target:self selector:@selector(fadeWork) userInfo:nil repeats:YES]; fadealpha=notialpha; } - (void)fadeWork { fadealpha-=CVIB_FADEVALUE; if (fadealpha<=0) { [noti orderOut:self]; [self stopTimer]; // nop(); return; } [noti setAlphaValue:fadealpha]; } - (void)solveConflict { if (!candion) return; NSRect cfr, nfr; cfr=[candi frame]; nfr=[noti frame]; if (cfr.origin.y+cfr.size.height == nfr.origin.y+nfr.size.height) { nfr.origin.y = cfr.origin.y - (nfr.size.height + 5); [noti setFrameOrigin:nfr.origin]; } } - (void)updateTextInWindow:(NSWindow*)w textField:(NSTextField*)t text:(NSString*)s position:(Point)p { [t setStringValue:s]; [t sizeToFit]; NSRect r=[t frame]; [w setContentSize:r.size]; CVFixWindowOrigin(w, p); } - (NSWindow*)createWindow:(NSRect)fr { NSWindow *w=[[NSWindow alloc] initWithContentRect:fr styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; [w setLevel:NSScreenSaverWindowLevel]; [w setMovableByWindowBackground:YES]; [w setContentView:[[NSView alloc] initWithFrame:[w contentRectForFrameRect:fr]]]; return w; } - (NSTextField*)createTextField:(NSRect)fr { NSTextField *t=[[NSTextField alloc] initWithFrame:fr]; [t setEditable:NO]; [t setSelectable:NO]; [t setBordered:NO]; [t setDrawsBackground:NO]; [t setFrameOrigin:NSMakePoint(0,0)]; return t; } - (void)applyConfig:(NSDictionary*)d window:(NSWindow*)w textField:(NSTextField*)t { float alpha=[[d valueForKey:@"opacity" default:@"1.0"] floatValue]; NSColor *fc=[[d valueForKey:@"foreground" default:@"1.0 1.0 1.0"] colorByString]; NSString *img=[d valueForKey:@"backgroundImage" default:@""]; NSString *font=[d valueForKey:@"font" default:@"Lucida Grande"]; float s=[[d valueForKey:@"size" default:@"18"] floatValue]; [w setAlphaValue:alpha]; [w setHasShadow:YES]; [w setOpaque:YES]; if ([img length]) { NSImage *i=[[NSImage alloc] initByReferencingFile:img]; if (i && [i isValid]) { [i autorelease]; NSColor *c=[NSColor colorWithPatternImage:i]; [w setBackgroundColor:c]; } } else { // no image, use color NSString *bcstr=[d valueForKey:@"background" default:@"1.0 1.0 1.0"]; if ([bcstr isEqualToString:@"transparent"]) { [w setHasShadow:NO]; [w setOpaque:NO]; [w setBackgroundColor:[NSColor clearColor]]; } else if ([bcstr isEqualToString:@"none"]) { [w setBackgroundColor:defaultbackground]; } else { NSColor *bc=[bcstr colorByString]; [w setBackgroundColor:bc]; } } [t setFont:[NSFont fontWithName:font size:s]]; [t setTextColor:fc]; } @end void CVFixWindowOrigin(NSWindow *w, Point p) { // first of all, we do a y-coordiate transformation (mirroring) NSPoint np=NSMakePoint((float)p.h, (float)p.v); float maxh=480; // a silly default, but anyway the below loop always runs NSArray *sa=[NSScreen screens]; int i, c=[sa count]; for (i=0; i maxh) maxh=h; } np.y=maxh-np.y; NSSize s=[w frame].size; // now we determine the window frame NSRect f=[[NSScreen mainScreen] frame]; BOOL found=NO; for (i=0; i f.origin.y+f.size.height-s.height) np.y=f.origin.y+f.size.height-s.height; if (np.x > f.origin.x+f.size.width-s.width) np.x=f.origin.x+f.size.width-s.width; if (np.y < f.origin.y) np.y=f.origin.y; if (np.x < f.origin.x) np.x=f.origin.x; } else { np.x = f.origin.x + (f.size.width-s.width)/2; np.y = f.origin.y + (f.size.height-s.height)/2; } [w setFrameOrigin:np]; }