mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 13:07:02 +00:00
516 lines
16 KiB
Objective-C
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
|
|
|