PageRenderTime 104ms CodeModel.GetById 17ms app.highlight 81ms RepoModel.GetById 1ms app.codeStats 1ms

/Tools/NativeHost/WebWindow.m

http://github.com/cacaodev/cappuccino
Objective C | 515 lines | 350 code | 135 blank | 30 comment | 50 complexity | bbcb2319f694916f4512c1b4f5181c9c MD5 | raw file
  1//
  2//  WebWindow.m
  3//  NativeHost
  4//
  5//  Created by Francisco Tolmasky on 10/18/09.
  6//  Copyright 2009 280 North, Inc.. All rights reserved.
  7//
  8
  9#import "WebWindow.h"
 10
 11
 12static NSMutableArray * DisabledWindows;
 13
 14CFMachPortRef tap_port;
 15
 16CGEventRef headTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
 17{
 18    // It's dangerous to fail in this code: could disable mousedown system-wide. So just try catch it all.
 19    @try
 20    {
 21        if (type == kCGEventLeftMouseDown)
 22        {
 23            CGPoint location = CGEventGetLocation(event);
 24            NSPoint NSLocation = NSMakePoint(location.x, location.y);
 25
 26            for (NSWindow * window in [NSApp windows])
 27            {
 28                if ([window isKindOfClass:[WebWindow class]] && ![(WebWindow *)window hitTest:NSLocation])
 29                {
 30                    [window setIgnoresMouseEvents:YES];
 31					[window performSelector:@selector(setIgnoresMouseEvents:) withObject:NO afterDelay:1.0];
 32					
 33                    [DisabledWindows addObject:window];
 34                }
 35            }
 36        }
 37        else if (type == kCGEventTapDisabledByTimeout)
 38            CGEventTapEnable(tap_port, YES);
 39
 40    }
 41    @catch (NSException * anException)
 42    {
 43    }
 44
 45    return event;
 46}
 47
 48
 49@interface WebWindowContentView : NSView
 50{
 51}
 52@end
 53
 54@implementation WebWindow
 55
 56+ (void)enableAllWindows
 57{
 58    [DisabledWindows makeObjectsPerformSelector:@selector(stopIgnoringMouseEvents)];
 59    [DisabledWindows removeAllObjects];
 60}
 61
 62+ (void)initialize
 63{
 64    if (self != [WebWindow class])
 65        return;
 66
 67    DisabledWindows = [[NSMutableArray alloc] init];
 68
 69    //| CGEventMaskBit(kCGEventTapDisabledByTimeout)
 70    tap_port = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap,
 71                                kCGEventTapOptionDefault,
 72                                CGEventMaskBit(kCGEventLeftMouseDown),
 73                                headTapCallback, NULL);
 74
 75    if (NULL == tap_port)
 76    {
 77        fprintf(stderr, "Error creating event tap\n");
 78        return;
 79    }
 80
 81    /* Create a run loop source from the tap port, add it to my run loop
 82     * and start executing the loop
 83     */
 84    CFRunLoopSourceRef tap_source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap_port, 0);
 85
 86    if (NULL == tap_source)
 87    {
 88        fprintf(stderr, "Error converting port to run loop source\n");
 89
 90        if (tap_port != NULL)
 91            CFRelease(tap_port);
 92
 93        return;
 94    }
 95
 96    CFRunLoopAddSource(CFRunLoopGetCurrent(), tap_source, kCFRunLoopCommonModes);
 97}
 98
 99- (id)initWithContentRect:(NSRect)aContentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)aBufferingType defer:(BOOL)shouldDeferCreation
100{
101    self = [super initWithContentRect:aContentRect styleMask:NSBorderlessWindowMask backing:aBufferingType defer:shouldDeferCreation];
102
103    if (self)
104    {
105        id delegate = [NSApp delegate];
106
107        shadowView = [[WebWindowContentView alloc] init];
108
109        [self setContentView:shadowView];
110
111        webView = [[WebView alloc] initWithFrame:NSZeroRect];
112
113        [webView setDrawsBackground:NO];
114        [webView setUIDelegate:delegate];
115        [webView setFrameLoadDelegate:delegate];
116        [webView setResourceLoadDelegate:delegate];
117        [webView setPolicyDelegate:delegate];
118        [webView setShouldCloseWithWindow:YES];
119
120        [shadowView addSubview:webView];
121
122        [self setBackgroundColor:[NSColor clearColor]];
123        [self setOpaque:NO];
124        [self setIgnoresMouseEvents:NO];
125        [self setReleasedWhenClosed:YES];
126        [super setHasShadow:NO];
127    }
128
129    return self;
130}
131
132- (void)setFrame:(NSRect)aFrame display:(BOOL)shouldDisplay
133{
134    [webView setFrame:NSMakeRect(33.0, 33.0, NSWidth(aFrame), NSHeight(aFrame))];
135    [super setFrame:NSInsetRect(aFrame, -33.0, -33.0) display:YES];
136}
137
138- (void)dealloc
139{
140    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResizeNotification object:self];
141    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidBecomeKeyNotification object:self];
142    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResignKeyNotification object:self];
143
144    [shadowView release];
145    [webView release];
146    [super dealloc];
147}
148
149- (BOOL)canBecomeKeyWindow
150{
151    // Necessary since this apparently returns NO for borderless windows.
152    return YES;
153}
154
155- (NSView *)webHitTest:(NSPoint)aPoint
156{
157    NSPoint locationInWebView = [[self contentView] convertPoint:aPoint fromView:nil];
158
159    return [(NSView *)[self contentView] hitTest:locationInWebView];
160}
161
162- (void)sendEvent:(NSEvent *)anEvent
163{
164    NSInteger type = [anEvent type];
165
166    if (type == NSLeftMouseDown)
167    {
168        NSView * view = [self webHitTest:[anEvent locationInWindow]];
169
170        leftMouseDownView = view;
171
172        [view mouseDown:anEvent];
173    }
174
175    else if (type == NSLeftMouseDragged)
176        [leftMouseDownView mouseDragged:anEvent];
177
178    else if (type == NSLeftMouseUp)
179        [leftMouseDownView mouseUp:anEvent];
180
181    else if (type == NSRightMouseDown)
182    {
183        NSView * view = [self webHitTest:[anEvent locationInWindow]];
184
185        rightMouseDownView = view;
186
187        [view rightMouseDown:anEvent];
188    }
189    else if (type == NSRightMouseDragged)
190        [rightMouseDownView rightMouseDragged:anEvent];
191
192    else if (type == NSRightMouseUp)
193        [rightMouseDownView rightMouseUp:anEvent];
194
195    else
196        [super sendEvent:anEvent];
197
198    // FIXME: other
199}
200
201// Override this to avoid the beep from unhandled events.
202- (void)keyDown:(NSEvent *)anEvent
203{
204}
205
206+ (WebWindow *)webWindow
207{
208    return [[WebWindow alloc] initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
209}
210
211- (WebView *)webView
212{
213    return webView;
214}
215
216- (void)updateShadow
217{
218    [super setHasShadow:hasShadow && shadowStyle == CPCustomWindowShadowStyle];
219    [shadowView setNeedsDisplay:YES];
220}
221
222- (BOOL)hasShadow
223{
224    return hasShadow;
225}
226
227- (void)setHasShadow:(BOOL)shouldHaveShadow
228{
229    if (hasShadow == shouldHaveShadow)
230        return;
231
232    hasShadow = shouldHaveShadow;
233
234    [self updateShadow];
235}
236
237- (CPWindowShadowStyle)shadowStyle
238{
239    return shadowStyle;
240}
241
242- (void)setShadowStyle:(CPWindowShadowStyle)aStyle
243{
244    if (shadowStyle == aStyle)
245        return;
246
247    shadowStyle = aStyle;
248
249    [self updateShadow];
250}
251
252- (BOOL)hitTest:(NSPoint)aPoint
253{
254    NSInteger windowNumber = [[[webView windowScriptObject] valueForKey:@"cpWindowNumber"] intValue];
255
256#if LOGGING
257    WebScriptObject * frame = [[[NSApp delegate] windowScriptObject] evaluateWebScript:[NSString stringWithFormat:@"(objj_msgSend(objj_msgSend(CPApp, \"windowWithWindowNumber:\", %d), \"frame\"))", windowNumber]],
258                    * origin = [frame valueForKey:@"origin"],
259                    * size = [frame valueForKey:@"size"];
260
261    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]);
262#endif
263
264    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];
265}
266
267- (void)stopIgnoringMouseEvents
268{
269    [self setIgnoresMouseEvents:NO];
270}
271
272- (void)becomeKeyWindow
273{
274    [super becomeKeyWindow];
275
276    [self updateShadow];
277}
278
279- (void)resignKeyWindow
280{
281    [super resignKeyWindow];
282
283    [self updateShadow];
284}
285
286@end
287
288@interface NSImage (Additions)
289
290- (void)drawInRect:(NSRect)aRect slices:(CGFloat [])slices;
291
292@end
293
294@implementation NSImage (Additions)
295
296- (void)drawInRect:(NSRect)aRect slices:(CGFloat [])slices
297{
298    NSRect imageBounds = NSMakeRect(0.0, 0.0, [self size].width, [self size].height);
299
300    [self drawInRect:NSMakeRect(0.0, 0.0, slices[0], slices[1])
301            fromRect:NSMakeRect(0.0, 0.0, slices[0], slices[1])
302           operation:NSCompositeSourceOver
303            fraction:1.0];
304
305    [self drawInRect:NSMakeRect(NSMaxX(aRect) - slices[2], 0.0, slices[2], slices[1])
306            fromRect:NSMakeRect(NSMaxX(imageBounds) - slices[2], 0.0, slices[2], slices[1])
307           operation:NSCompositeSourceOver
308            fraction:1.0];
309
310    [self drawInRect:NSMakeRect(0.0, NSMaxY(aRect) - slices[3], slices[0], slices[3])
311            fromRect:NSMakeRect(0.0, NSMaxY(imageBounds) - slices[3], slices[0], slices[3])
312           operation:NSCompositeSourceOver
313            fraction:1.0];
314
315    [self drawInRect:NSMakeRect(NSMaxX(aRect) - slices[2], NSMaxY(aRect) - slices[3], slices[2], slices[3])
316            fromRect:NSMakeRect(NSMaxX(imageBounds) - slices[2], NSMaxY(imageBounds) - slices[3], slices[2], slices[3])
317           operation:NSCompositeSourceOver
318            fraction:1.0];
319
320    [self drawInRect:NSMakeRect(slices[0], 0.0, NSWidth(aRect) - slices[0] - slices[2], slices[1])
321            fromRect:NSMakeRect(slices[0], 0.0, 1.0, slices[1])
322           operation:NSCompositeSourceOver
323            fraction:1.0];
324
325    [self drawInRect:NSMakeRect(0.0, slices[1], slices[0], NSHeight(aRect) - slices[1] - slices[3])
326            fromRect:NSMakeRect(0.0, slices[1], slices[0], 1.0)
327           operation:NSCompositeSourceOver
328            fraction:1.0];
329
330    [self drawInRect:NSMakeRect(NSMaxX(aRect) - slices[2], slices[1], slices[2], NSHeight(aRect) - slices[1] - slices[3])
331            fromRect:NSMakeRect(NSMaxX(imageBounds) - slices[2], slices[1], slices[2], 1.0)
332           operation:NSCompositeSourceOver
333            fraction:1.0];
334
335    [self drawInRect:NSMakeRect(slices[0], NSMaxY(aRect) - slices[3], NSWidth(aRect) - slices[0] - slices[2], slices[3])
336            fromRect:NSMakeRect(slices[0], NSMaxY(imageBounds) - slices[3], 1.0, slices[3])
337           operation:NSCompositeSourceOver
338            fraction:1.0];
339}
340
341@end
342
343@implementation WebWindowContentView : NSView
344{
345}
346
347static float OUTlINE_HORIZONTAL_INSET   = 33.0;
348static float OUTlINE_VERTICAL_INSET     = 33.0;
349
350- (void)drawStandardActiveShadowInRect:(NSRect)aRect
351{
352    CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
353
354    CGRect bounds = CGRectInset(*(CGRect *)&aRect, OUTlINE_HORIZONTAL_INSET - 0.5, OUTlINE_VERTICAL_INSET - 0.5);
355
356    CGColorRef shadowColor = CGColorCreateGenericGray(0.0, 0.8);
357    CGContextSetShadowWithColor (context, CGSizeMake(0.0, -10.0), 100.0, shadowColor);
358    CGColorRelease(shadowColor);
359
360    CGColorRef fillColor = CGColorCreateGenericGray(1.0, 1.0);
361    CGColorRef strokeColor = CGColorCreateGenericGray(0.0, 0.2);
362
363    CGContextSetFillColorWithColor(context, fillColor);
364    CGContextSetStrokeColorWithColor(context, strokeColor);
365
366    CGColorRelease(fillColor);
367    CGColorRelease(strokeColor);
368
369    CGContextBeginPath(context);
370
371    CGContextAddArc(context, CGRectGetMinX(bounds) + 5.0, CGRectGetMaxY(bounds) - 5.0, 5.0, M_PI, M_PI_2, YES);
372    CGContextAddArc(context, CGRectGetMaxX(bounds) - 5.0, CGRectGetMaxY(bounds) - 5.0, 5.0, M_PI_2, 0, YES);
373    CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), CGRectGetMinY(bounds));
374    CGContextAddLineToPoint(context, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
375
376    CGContextClosePath(context);
377
378    CGContextDrawPath(context, kCGPathFillStroke);
379}
380
381- (void)drawStandardInactiveShadowInRect:(NSRect)aRect
382{
383    CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
384
385    CGRect bounds = CGRectInset(*(CGRect *)&aRect, OUTlINE_HORIZONTAL_INSET - 0.5, OUTlINE_VERTICAL_INSET - 0.5);
386
387    CGColorRef shadowColor = CGColorCreateGenericGray(0.0, 0.5);
388    CGContextSetShadowWithColor (context, CGSizeMake(0.0, -10.0), 40.0, shadowColor);
389    CGColorRelease(shadowColor);
390
391    CGColorRef fillColor = CGColorCreateGenericGray(1.0, 1.0);
392    CGColorRef strokeColor = CGColorCreateGenericGray(0.0, 0.2);
393
394    CGContextSetFillColorWithColor(context, fillColor);
395    CGContextSetStrokeColorWithColor(context, strokeColor);
396
397    CGColorRelease(fillColor);
398    CGColorRelease(strokeColor);
399
400    CGContextBeginPath(context);
401
402    CGContextAddArc(context, CGRectGetMinX(bounds) + 5.0, CGRectGetMaxY(bounds) - 5.0, 5.0, M_PI, M_PI_2, YES);
403    CGContextAddArc(context, CGRectGetMaxX(bounds) - 5.0, CGRectGetMaxY(bounds) - 5.0, 5.0, M_PI_2, 0, YES);
404    CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), CGRectGetMinY(bounds));
405    CGContextAddLineToPoint(context, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
406
407    CGContextClosePath(context);
408
409    CGContextDrawPath(context, kCGPathFillStroke);
410}
411
412- (void)drawMenuShadowInRect:(NSRect)aRect
413{
414    CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
415
416    CGRect bounds = CGRectInset(*(CGRect *)&aRect, OUTlINE_HORIZONTAL_INSET - 0.5, OUTlINE_VERTICAL_INSET - 0.5);
417
418    CGColorRef shadowColor = CGColorCreateGenericGray(0.0, 0.5);
419    CGContextSetShadowWithColor (context, CGSizeMake(0.0, -10.0), 30.0, shadowColor);
420    CGColorRelease(shadowColor);
421
422    CGColorRef fillColor = CGColorCreateGenericGray(1.0, 1.0);
423    CGColorRef strokeColor = CGColorCreateGenericGray(0.0, 0.2);
424
425    CGContextSetFillColorWithColor(context, fillColor);
426    CGContextSetStrokeColorWithColor(context, strokeColor);
427
428    CGColorRelease(fillColor);
429    CGColorRelease(strokeColor);
430
431    CGContextBeginPath(context);
432
433    CGContextAddArc(context, CGRectGetMinX(bounds) + 3.0, CGRectGetMaxY(bounds) - 3.0, 2.0, M_PI, M_PI_2, YES);
434    CGContextAddArc(context, CGRectGetMaxX(bounds) - 3.0, CGRectGetMaxY(bounds) - 3.0, 2.0, M_PI_2, 0, YES);
435    CGContextAddArc(context, CGRectGetMaxX(bounds) - 3.0, CGRectGetMinY(bounds) + 3.0, 2.0, 0, 3 * M_PI_2, YES);
436    CGContextAddArc(context, CGRectGetMinX(bounds) + 3.0, CGRectGetMinY(bounds) + 3.0, 2.0, 3 * M_PI_2, M_PI, YES);
437
438    CGContextClosePath(context);
439
440    CGContextDrawPath(context, kCGPathFill);//Stroke);
441
442/*
443    CGContextBeginPath(context);
444
445    CGContextAddArc(context, CGRectGetMinX(bounds) + 3.0, CGRectGetMaxY(bounds) - 3.0, 2.0, M_PI, M_PI_2, YES);
446    CGContextAddArc(context, CGRectGetMaxX(bounds) - 3.0, CGRectGetMaxY(bounds) - 3.0, 2.0, M_PI_2, 0, YES);
447    CGContextAddArc(context, CGRectGetMaxX(bounds) - 3.0, CGRectGetMinY(bounds) + 3.0, 2.0, 0, 3 * M_PI_2, YES);
448    CGContextAddArc(context, CGRectGetMinX(bounds) + 3.0, CGRectGetMinY(bounds) + 3.0, 2.0, 3 * M_PI_2, M_PI, YES);
449
450    CGContextClosePath(context);
451
452    CGContextSetFillColorWithColor(context, CGColorGetConstantColor(kCGColorClear));
453
454    CGContextSetBlendMode(context, kCGBlendModeCopy);
455    CGContextDrawPath(context, kCGPathFill);
456*/
457}
458
459- (NSImage *)shadowImageWithSelector:(SEL)aSelector
460{
461    static NSMutableDictionary * images = nil;
462
463    if (!images)
464        images = [[NSMutableDictionary alloc] init];
465
466    NSString * name = NSStringFromSelector(aSelector);
467    NSImage * image = [images objectForKey:name];
468
469    if (!image)
470    {
471        image = [[NSImage alloc] initWithSize:NSMakeSize(100.0, 100.0)];
472
473        [image lockFocus];
474        objc_msgSend(self, aSelector, NSMakeRect(0.0, 0.0, 100.0, 100.0));
475        [image unlockFocus];
476
477        [images setObject:image forKey:name];
478
479        [image release];
480    }
481
482    return image;
483}
484
485- (void)drawShadowWithSelector:(SEL)aSelector inRect:(NSRect)aRect
486{
487    CGFloat slices[] = { 40.0, 49.0, 40.0, 49.0 };
488
489    if (NSWidth(aRect) > 100.0 || NSHeight(aRect) > 100.0)
490        [[self shadowImageWithSelector:aSelector] drawInRect:aRect slices:slices];
491    else
492        objc_msgSend(self, aSelector, aRect);
493}
494
495- (void)drawRect:(NSRect)aRect
496{
497    WebWindow * window = (WebWindow *)[self window];
498    NSRect bounds = [self bounds];
499
500    if (![window hasShadow])
501        return;
502
503    if ([window shadowStyle] == CPStandardWindowShadowStyle)
504        if ([window isKeyWindow])
505            return [self drawShadowWithSelector:@selector(drawStandardActiveShadowInRect:) inRect:bounds];
506        else
507            return [self drawShadowWithSelector:@selector(drawStandardInactiveShadowInRect:) inRect:bounds];
508
509
510    if ([window shadowStyle] == CPMenuWindowShadowStyle)
511        return [self drawShadowWithSelector:@selector(drawMenuShadowInRect:) inRect:bounds];
512}
513
514@end
515