| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #import "chrome/browser/cocoa/browser_frame_view.h" |
| 6 |
| 7 #import <objc/runtime.h> |
| 8 #import <Carbon/Carbon.h> |
| 9 |
| 10 #include "base/logging.h" |
| 11 #include "base/scoped_nsobject.h" |
| 12 #import "chrome/browser/cocoa/chrome_browser_window.h" |
| 13 #import "third_party/GTM/AppKit/GTMTheme.h" |
| 14 |
| 15 // To line up our background pattern with the patterns in the tabs we need |
| 16 // to move our background patterns in the window frame up by two pixels. |
| 17 // This will make the themes look slightly different than in Windows/Linux |
| 18 // because of the differing heights between window top and tab top, but this |
| 19 // has been approved by UI. |
| 20 static const NSInteger kBrowserFrameViewPatternPhaseOffset = 2; |
| 21 |
| 22 @interface NSView (Swizzles) |
| 23 - (void)drawRectOriginal:(NSRect)rect; |
| 24 - (BOOL)_mouseInGroup:(NSButton*)widget; |
| 25 - (void)updateTrackingAreas; |
| 26 @end |
| 27 |
| 28 @implementation BrowserFrameView |
| 29 |
| 30 + (void)load { |
| 31 // This is where we swizzle drawRect, and add in two methods that we |
| 32 // need. If any of these fail it shouldn't affect the functionality of the |
| 33 // others. If they all fail, we will lose window frame theming and |
| 34 // roll overs for our close widgets, but things should still function |
| 35 // correctly. |
| 36 scoped_nsobject<NSAutoreleasePool> pool([[NSAutoreleasePool alloc] init]); |
| 37 Class grayFrameClass = NSClassFromString(@"NSGrayFrame"); |
| 38 DCHECK(grayFrameClass); |
| 39 if (!grayFrameClass) return; |
| 40 |
| 41 // Exchange draw rect |
| 42 Method m0 = class_getInstanceMethod([self class], @selector(drawRect:)); |
| 43 DCHECK(m0); |
| 44 if (m0) { |
| 45 BOOL didAdd = class_addMethod(grayFrameClass, |
| 46 @selector(drawRectOriginal:), |
| 47 method_getImplementation(m0), |
| 48 method_getTypeEncoding(m0)); |
| 49 DCHECK(didAdd); |
| 50 if (didAdd) { |
| 51 Method m1 = class_getInstanceMethod(grayFrameClass, @selector(drawRect:)); |
| 52 Method m2 = class_getInstanceMethod(grayFrameClass, |
| 53 @selector(drawRectOriginal:)); |
| 54 DCHECK(m1 && m2); |
| 55 if (m1 && m2) { |
| 56 method_exchangeImplementations(m1, m2); |
| 57 } |
| 58 } |
| 59 } |
| 60 |
| 61 // Add _mouseInGroup |
| 62 m0 = class_getInstanceMethod([self class], @selector(_mouseInGroup:)); |
| 63 DCHECK(m0); |
| 64 if (m0) { |
| 65 BOOL didAdd = class_addMethod(grayFrameClass, |
| 66 @selector(_mouseInGroup:), |
| 67 method_getImplementation(m0), |
| 68 method_getTypeEncoding(m0)); |
| 69 DCHECK(didAdd); |
| 70 } |
| 71 // Add updateTrackingArea |
| 72 m0 = class_getInstanceMethod([self class], @selector(updateTrackingAreas)); |
| 73 DCHECK(m0); |
| 74 if (m0) { |
| 75 BOOL didAdd = class_addMethod(grayFrameClass, |
| 76 @selector(updateTrackingAreas), |
| 77 method_getImplementation(m0), |
| 78 method_getTypeEncoding(m0)); |
| 79 DCHECK(didAdd); |
| 80 } |
| 81 } |
| 82 |
| 83 - (id)initWithFrame:(NSRect)frame { |
| 84 // This class is not for instantiating. |
| 85 [self doesNotRecognizeSelector:_cmd]; |
| 86 return nil; |
| 87 } |
| 88 |
| 89 - (id)initWithCoder:(NSCoder*)coder { |
| 90 // This class is not for instantiating. |
| 91 [self doesNotRecognizeSelector:_cmd]; |
| 92 return nil; |
| 93 } |
| 94 |
| 95 // Here is our custom drawing for our frame. |
| 96 - (void)drawRect:(NSRect)rect { |
| 97 // If this isn't the window class we expect, then pass it on to the |
| 98 // original implementation. |
| 99 if (![[self window] isKindOfClass:[ChromeBrowserWindow class]]) { |
| 100 [self drawRectOriginal:rect]; |
| 101 return; |
| 102 } |
| 103 |
| 104 // Clear out everything |
| 105 [[NSColor clearColor] set]; |
| 106 NSRectFillUsingOperation(rect, NSCompositeSourceOver); |
| 107 |
| 108 // Set up our clip |
| 109 NSWindow* window = [self window]; |
| 110 NSRect windowRect = [window frame]; |
| 111 windowRect.origin = NSMakePoint(0, 0); |
| 112 [[NSBezierPath bezierPathWithRoundedRect:windowRect |
| 113 xRadius:4 |
| 114 yRadius:4] addClip]; |
| 115 [[NSBezierPath bezierPathWithRect:rect] addClip]; |
| 116 |
| 117 // Draw our background color if we have one, otherwise fall back on |
| 118 // system drawing. |
| 119 GTMTheme* theme = [self gtm_theme]; |
| 120 GTMThemeState state = [window isMainWindow] ? GTMThemeStateActiveWindow |
| 121 : GTMThemeStateInactiveWindow; |
| 122 NSColor* color = [theme backgroundPatternColorForStyle:GTMThemeStyleWindow |
| 123 state:state]; |
| 124 if (color) { |
| 125 // If we have a theme pattern, draw it here. |
| 126 NSPoint phase = NSMakePoint(0, (NSHeight(windowRect) + |
| 127 kBrowserFrameViewPatternPhaseOffset)); |
| 128 [[NSGraphicsContext currentContext] setPatternPhase:phase]; |
| 129 [color set]; |
| 130 NSRectFill(rect); |
| 131 } else { |
| 132 [self drawRectOriginal:rect]; |
| 133 } |
| 134 |
| 135 // Check to see if we have an overlay image. |
| 136 NSImage* overlayImage = [theme valueForAttribute:@"overlay" |
| 137 style:GTMThemeStyleWindow |
| 138 state:state]; |
| 139 if (overlayImage) { |
| 140 NSSize overlaySize = [overlayImage size]; |
| 141 NSRect windowFrame = NSMakeRect(0, |
| 142 NSHeight(windowRect) - overlaySize.height, |
| 143 NSWidth(windowRect), |
| 144 overlaySize.height); |
| 145 NSRect imageFrame = NSMakeRect(0, 0, overlaySize.width, overlaySize.height); |
| 146 [overlayImage drawInRect:windowFrame |
| 147 fromRect:imageFrame |
| 148 operation:NSCompositeSourceOver |
| 149 fraction:1.0]; |
| 150 } |
| 151 } |
| 152 |
| 153 // Check to see if the mouse is currently in one of our window widgets. |
| 154 - (BOOL)_mouseInGroup:(NSButton*)widget { |
| 155 BOOL mouseInGroup = NO; |
| 156 if ([[self window] isKindOfClass:[ChromeBrowserWindow class]]) { |
| 157 ChromeBrowserWindow* window = |
| 158 static_cast<ChromeBrowserWindow*>([self window]); |
| 159 mouseInGroup = [window mouseInGroup:widget]; |
| 160 } else { |
| 161 mouseInGroup = [super _mouseInGroup:widget]; |
| 162 } |
| 163 return mouseInGroup; |
| 164 } |
| 165 |
| 166 // Let our window handle updating the window widget tracking area. |
| 167 - (void)updateTrackingAreas { |
| 168 [super updateTrackingAreas]; |
| 169 if ([[self window] isKindOfClass:[ChromeBrowserWindow class]]) { |
| 170 ChromeBrowserWindow* window = |
| 171 static_cast<ChromeBrowserWindow*>([self window]); |
| 172 [window updateTrackingAreas]; |
| 173 } |
| 174 } |
| 175 |
| 176 @end |
| OLD | NEW |