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