Files
cappuccino/Tools/NativeHost/WebWindow.m
T

516 lines
16 KiB
Objective-C

//
// WebWindow.m
// NativeHost
//
// Created by Francisco Tolmasky on 10/18/09.
// Copyright 2009 280 North, Inc.. All rights reserved.
//
#import "WebWindow.h"
static NSMutableArray * DisabledWindows;
CFMachPortRef tap_port;
CGEventRef headTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
{
// It's dangerous to fail in this code: could disable mousedown system-wide. So just try catch it all.
@try
{
if (type == kCGEventLeftMouseDown)
{
CGPoint location = CGEventGetLocation(event);
NSPoint NSLocation = NSMakePoint(location.x, location.y);
for (NSWindow * window in [NSApp windows])
{
if ([window isKindOfClass:[WebWindow class]] && ![(WebWindow *)window hitTest:NSLocation])
{
[window setIgnoresMouseEvents:YES];
[window performSelector:@selector(setIgnoresMouseEvents:) withObject:NO afterDelay:1.0];
[DisabledWindows addObject:window];
}
}
}
else if (type == kCGEventTapDisabledByTimeout)
CGEventTapEnable(tap_port, YES);
}
@catch (NSException * anException)
{
}
return event;
}
@interface WebWindowContentView : NSView
{
}
@end
@implementation WebWindow
+ (void)enableAllWindows
{
[DisabledWindows makeObjectsPerformSelector:@selector(stopIgnoringMouseEvents)];
[DisabledWindows removeAllObjects];
}
+ (void)initialize
{
if (self != [WebWindow class])
return;
DisabledWindows = [[NSMutableArray alloc] init];
//| CGEventMaskBit(kCGEventTapDisabledByTimeout)
tap_port = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
CGEventMaskBit(kCGEventLeftMouseDown),
headTapCallback, NULL);
if (NULL == tap_port)
{
fprintf(stderr, "Error creating event tap\n");
return;
}
/* Create a run loop source from the tap port, add it to my run loop
* and start executing the loop
*/
CFRunLoopSourceRef tap_source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap_port, 0);
if (NULL == tap_source)
{
fprintf(stderr, "Error converting port to run loop source\n");
if (tap_port != NULL)
CFRelease(tap_port);
return;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), tap_source, kCFRunLoopCommonModes);
}
- (id)initWithContentRect:(NSRect)aContentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)aBufferingType defer:(BOOL)shouldDeferCreation
{
self = [super initWithContentRect:aContentRect styleMask:NSBorderlessWindowMask backing:aBufferingType defer:shouldDeferCreation];
if (self)
{
id delegate = [NSApp delegate];
shadowView = [[WebWindowContentView alloc] init];
[self setContentView:shadowView];
webView = [[WebView alloc] initWithFrame:NSZeroRect];
[webView setDrawsBackground:NO];
[webView setUIDelegate:delegate];
[webView setFrameLoadDelegate:delegate];
[webView setResourceLoadDelegate:delegate];
[webView setPolicyDelegate:delegate];
[webView setShouldCloseWithWindow:YES];
[shadowView addSubview:webView];
[self setBackgroundColor:[NSColor clearColor]];
[self setOpaque:NO];
[self setIgnoresMouseEvents:NO];
[self setReleasedWhenClosed:YES];
[super setHasShadow:NO];
}
return self;
}
- (void)setFrame:(NSRect)aFrame display:(BOOL)shouldDisplay
{
[webView setFrame:NSMakeRect(33.0, 33.0, NSWidth(aFrame), NSHeight(aFrame))];
[super setFrame:NSInsetRect(aFrame, -33.0, -33.0) display:YES];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResizeNotification object:self];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidBecomeKeyNotification object:self];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResignKeyNotification object:self];
[shadowView release];
[webView release];
[super dealloc];
}
- (BOOL)canBecomeKeyWindow
{
// Necessary since this apparently returns NO for borderless windows.
return YES;
}
- (NSView *)webHitTest:(NSPoint)aPoint
{
NSPoint locationInWebView = [[self contentView] convertPoint:aPoint fromView:nil];
return [(NSView *)[self contentView] hitTest:locationInWebView];
}
- (void)sendEvent:(NSEvent *)anEvent
{
NSInteger type = [anEvent type];
if (type == NSLeftMouseDown)
{
NSView * view = [self webHitTest:[anEvent locationInWindow]];
leftMouseDownView = view;
[view mouseDown:anEvent];
}
else if (type == NSLeftMouseDragged)
[leftMouseDownView mouseDragged:anEvent];
else if (type == NSLeftMouseUp)
[leftMouseDownView mouseUp:anEvent];
else if (type == NSRightMouseDown)
{
NSView * view = [self webHitTest:[anEvent locationInWindow]];
rightMouseDownView = view;
[view rightMouseDown:anEvent];
}
else if (type == NSRightMouseDragged)
[rightMouseDownView rightMouseDragged:anEvent];
else if (type == NSRightMouseUp)
[rightMouseDownView rightMouseUp:anEvent];
else
[super sendEvent:anEvent];
// FIXME: other
}
// Override this to avoid the beep from unhandled events.
- (void)keyDown:(NSEvent *)anEvent
{
}
+ (WebWindow *)webWindow
{
return [[WebWindow alloc] initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
}
- (WebView *)webView
{
return webView;
}
- (void)updateShadow
{
[super setHasShadow:hasShadow && shadowStyle == CPCustomWindowShadowStyle];
[shadowView setNeedsDisplay:YES];
}
- (BOOL)hasShadow
{
return hasShadow;
}
- (void)setHasShadow:(BOOL)shouldHaveShadow
{
if (hasShadow == shouldHaveShadow)
return;
hasShadow = shouldHaveShadow;
[self updateShadow];
}
- (CPWindowShadowStyle)shadowStyle
{
return shadowStyle;
}
- (void)setShadowStyle:(CPWindowShadowStyle)aStyle
{
if (shadowStyle == aStyle)
return;
shadowStyle = aStyle;
[self updateShadow];
}
- (BOOL)hitTest:(NSPoint)aPoint
{
NSInteger windowNumber = [[[webView windowScriptObject] valueForKey:@"cpWindowNumber"] intValue];
#if LOGGING
WebScriptObject * frame = [[[NSApp delegate] windowScriptObject] evaluateWebScript:[NSString stringWithFormat:@"(objj_msgSend(objj_msgSend(CPApp, \"windowWithWindowNumber:\", %d), \"frame\"))", windowNumber]],
* origin = [frame valueForKey:@"origin"],
* size = [frame valueForKey:@"size"];
NSLog(@"(%f, %f) in { %f, %f, %f, %f }", aPoint.x, aPoint.y, [[origin valueForKey:@"x"] floatValue], [[origin valueForKey:@"y"] floatValue], [[size valueForKey:@"width"] floatValue], [[size valueForKey:@"height"] floatValue]);
#endif
return [[[[NSApp delegate] windowScriptObject] evaluateWebScript:[NSString stringWithFormat:@"(CGRectContainsPoint(objj_msgSend(objj_msgSend(CPApp, \"windowWithWindowNumber:\", %d), \"frame\"), CGPointMake(%f, %f)))", windowNumber, aPoint.x, aPoint.y]] boolValue];
}
- (void)stopIgnoringMouseEvents
{
[self setIgnoresMouseEvents:NO];
}
- (void)becomeKeyWindow
{
[super becomeKeyWindow];
[self updateShadow];
}
- (void)resignKeyWindow
{
[super resignKeyWindow];
[self updateShadow];
}
@end
@interface NSImage (Additions)
- (void)drawInRect:(NSRect)aRect slices:(CGFloat [])slices;
@end
@implementation NSImage (Additions)
- (void)drawInRect:(NSRect)aRect slices:(CGFloat [])slices
{
NSRect imageBounds = NSMakeRect(0.0, 0.0, [self size].width, [self size].height);
[self drawInRect:NSMakeRect(0.0, 0.0, slices[0], slices[1])
fromRect:NSMakeRect(0.0, 0.0, slices[0], slices[1])
operation:NSCompositeSourceOver
fraction:1.0];
[self drawInRect:NSMakeRect(NSMaxX(aRect) - slices[2], 0.0, slices[2], slices[1])
fromRect:NSMakeRect(NSMaxX(imageBounds) - slices[2], 0.0, slices[2], slices[1])
operation:NSCompositeSourceOver
fraction:1.0];
[self drawInRect:NSMakeRect(0.0, NSMaxY(aRect) - slices[3], slices[0], slices[3])
fromRect:NSMakeRect(0.0, NSMaxY(imageBounds) - slices[3], slices[0], slices[3])
operation:NSCompositeSourceOver
fraction:1.0];
[self drawInRect:NSMakeRect(NSMaxX(aRect) - slices[2], NSMaxY(aRect) - slices[3], slices[2], slices[3])
fromRect:NSMakeRect(NSMaxX(imageBounds) - slices[2], NSMaxY(imageBounds) - slices[3], slices[2], slices[3])
operation:NSCompositeSourceOver
fraction:1.0];
[self drawInRect:NSMakeRect(slices[0], 0.0, NSWidth(aRect) - slices[0] - slices[2], slices[1])
fromRect:NSMakeRect(slices[0], 0.0, 1.0, slices[1])
operation:NSCompositeSourceOver
fraction:1.0];
[self drawInRect:NSMakeRect(0.0, slices[1], slices[0], NSHeight(aRect) - slices[1] - slices[3])
fromRect:NSMakeRect(0.0, slices[1], slices[0], 1.0)
operation:NSCompositeSourceOver
fraction:1.0];
[self drawInRect:NSMakeRect(NSMaxX(aRect) - slices[2], slices[1], slices[2], NSHeight(aRect) - slices[1] - slices[3])
fromRect:NSMakeRect(NSMaxX(imageBounds) - slices[2], slices[1], slices[2], 1.0)
operation:NSCompositeSourceOver
fraction:1.0];
[self drawInRect:NSMakeRect(slices[0], NSMaxY(aRect) - slices[3], NSWidth(aRect) - slices[0] - slices[2], slices[3])
fromRect:NSMakeRect(slices[0], NSMaxY(imageBounds) - slices[3], 1.0, slices[3])
operation:NSCompositeSourceOver
fraction:1.0];
}
@end
@implementation WebWindowContentView : NSView
{
}
static float OUTlINE_HORIZONTAL_INSET = 33.0;
static float OUTlINE_VERTICAL_INSET = 33.0;
- (void)drawStandardActiveShadowInRect:(NSRect)aRect
{
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
CGRect bounds = CGRectInset(*(CGRect *)&aRect, OUTlINE_HORIZONTAL_INSET - 0.5, OUTlINE_VERTICAL_INSET - 0.5);
CGColorRef shadowColor = CGColorCreateGenericGray(0.0, 0.8);
CGContextSetShadowWithColor (context, CGSizeMake(0.0, -10.0), 100.0, shadowColor);
CGColorRelease(shadowColor);
CGColorRef fillColor = CGColorCreateGenericGray(1.0, 1.0);
CGColorRef strokeColor = CGColorCreateGenericGray(0.0, 0.2);
CGContextSetFillColorWithColor(context, fillColor);
CGContextSetStrokeColorWithColor(context, strokeColor);
CGColorRelease(fillColor);
CGColorRelease(strokeColor);
CGContextBeginPath(context);
CGContextAddArc(context, CGRectGetMinX(bounds) + 5.0, CGRectGetMaxY(bounds) - 5.0, 5.0, M_PI, M_PI_2, YES);
CGContextAddArc(context, CGRectGetMaxX(bounds) - 5.0, CGRectGetMaxY(bounds) - 5.0, 5.0, M_PI_2, 0, YES);
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), CGRectGetMinY(bounds));
CGContextAddLineToPoint(context, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFillStroke);
}
- (void)drawStandardInactiveShadowInRect:(NSRect)aRect
{
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
CGRect bounds = CGRectInset(*(CGRect *)&aRect, OUTlINE_HORIZONTAL_INSET - 0.5, OUTlINE_VERTICAL_INSET - 0.5);
CGColorRef shadowColor = CGColorCreateGenericGray(0.0, 0.5);
CGContextSetShadowWithColor (context, CGSizeMake(0.0, -10.0), 40.0, shadowColor);
CGColorRelease(shadowColor);
CGColorRef fillColor = CGColorCreateGenericGray(1.0, 1.0);
CGColorRef strokeColor = CGColorCreateGenericGray(0.0, 0.2);
CGContextSetFillColorWithColor(context, fillColor);
CGContextSetStrokeColorWithColor(context, strokeColor);
CGColorRelease(fillColor);
CGColorRelease(strokeColor);
CGContextBeginPath(context);
CGContextAddArc(context, CGRectGetMinX(bounds) + 5.0, CGRectGetMaxY(bounds) - 5.0, 5.0, M_PI, M_PI_2, YES);
CGContextAddArc(context, CGRectGetMaxX(bounds) - 5.0, CGRectGetMaxY(bounds) - 5.0, 5.0, M_PI_2, 0, YES);
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), CGRectGetMinY(bounds));
CGContextAddLineToPoint(context, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFillStroke);
}
- (void)drawMenuShadowInRect:(NSRect)aRect
{
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
CGRect bounds = CGRectInset(*(CGRect *)&aRect, OUTlINE_HORIZONTAL_INSET - 0.5, OUTlINE_VERTICAL_INSET - 0.5);
CGColorRef shadowColor = CGColorCreateGenericGray(0.0, 0.5);
CGContextSetShadowWithColor (context, CGSizeMake(0.0, -10.0), 30.0, shadowColor);
CGColorRelease(shadowColor);
CGColorRef fillColor = CGColorCreateGenericGray(1.0, 1.0);
CGColorRef strokeColor = CGColorCreateGenericGray(0.0, 0.2);
CGContextSetFillColorWithColor(context, fillColor);
CGContextSetStrokeColorWithColor(context, strokeColor);
CGColorRelease(fillColor);
CGColorRelease(strokeColor);
CGContextBeginPath(context);
CGContextAddArc(context, CGRectGetMinX(bounds) + 3.0, CGRectGetMaxY(bounds) - 3.0, 2.0, M_PI, M_PI_2, YES);
CGContextAddArc(context, CGRectGetMaxX(bounds) - 3.0, CGRectGetMaxY(bounds) - 3.0, 2.0, M_PI_2, 0, YES);
CGContextAddArc(context, CGRectGetMaxX(bounds) - 3.0, CGRectGetMinY(bounds) + 3.0, 2.0, 0, 3 * M_PI_2, YES);
CGContextAddArc(context, CGRectGetMinX(bounds) + 3.0, CGRectGetMinY(bounds) + 3.0, 2.0, 3 * M_PI_2, M_PI, YES);
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFill);//Stroke);
/*
CGContextBeginPath(context);
CGContextAddArc(context, CGRectGetMinX(bounds) + 3.0, CGRectGetMaxY(bounds) - 3.0, 2.0, M_PI, M_PI_2, YES);
CGContextAddArc(context, CGRectGetMaxX(bounds) - 3.0, CGRectGetMaxY(bounds) - 3.0, 2.0, M_PI_2, 0, YES);
CGContextAddArc(context, CGRectGetMaxX(bounds) - 3.0, CGRectGetMinY(bounds) + 3.0, 2.0, 0, 3 * M_PI_2, YES);
CGContextAddArc(context, CGRectGetMinX(bounds) + 3.0, CGRectGetMinY(bounds) + 3.0, 2.0, 3 * M_PI_2, M_PI, YES);
CGContextClosePath(context);
CGContextSetFillColorWithColor(context, CGColorGetConstantColor(kCGColorClear));
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGContextDrawPath(context, kCGPathFill);
*/
}
- (NSImage *)shadowImageWithSelector:(SEL)aSelector
{
static NSMutableDictionary * images = nil;
if (!images)
images = [[NSMutableDictionary alloc] init];
NSString * name = NSStringFromSelector(aSelector);
NSImage * image = [images objectForKey:name];
if (!image)
{
image = [[NSImage alloc] initWithSize:NSMakeSize(100.0, 100.0)];
[image lockFocus];
objc_msgSend(self, aSelector, NSMakeRect(0.0, 0.0, 100.0, 100.0));
[image unlockFocus];
[images setObject:image forKey:name];
[image release];
}
return image;
}
- (void)drawShadowWithSelector:(SEL)aSelector inRect:(NSRect)aRect
{
CGFloat slices[] = { 40.0, 49.0, 40.0, 49.0 };
if (NSWidth(aRect) > 100.0 || NSHeight(aRect) > 100.0)
[[self shadowImageWithSelector:aSelector] drawInRect:aRect slices:slices];
else
objc_msgSend(self, aSelector, aRect);
}
- (void)drawRect:(NSRect)aRect
{
WebWindow * window = (WebWindow *)[self window];
NSRect bounds = [self bounds];
if (![window hasShadow])
return;
if ([window shadowStyle] == CPStandardWindowShadowStyle)
if ([window isKeyWindow])
return [self drawShadowWithSelector:@selector(drawStandardActiveShadowInRect:) inRect:bounds];
else
return [self drawShadowWithSelector:@selector(drawStandardInactiveShadowInRect:) inRect:bounds];
if ([window shadowStyle] == CPMenuWindowShadowStyle)
return [self drawShadowWithSelector:@selector(drawMenuShadowInRect:) inRect:bounds];
}
@end