| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/cocoa/chrome_browser_window.h" | 5 #import "chrome/browser/cocoa/chrome_browser_window.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #import "chrome/browser/cocoa/browser_window_controller.h" | 8 #import "chrome/browser/cocoa/browser_window_controller.h" |
| 9 #import "chrome/browser/cocoa/browser_frame_view.h" |
| 10 #import "chrome/browser/cocoa/tab_strip_controller.h" |
| 9 #import "chrome/browser/renderer_host/render_widget_host_view_mac.h" | 11 #import "chrome/browser/renderer_host/render_widget_host_view_mac.h" |
| 10 #include "chrome/browser/global_keyboard_shortcuts_mac.h" | 12 #include "chrome/browser/global_keyboard_shortcuts_mac.h" |
| 11 | 13 |
| 14 // Our browser window does some interesting things to get the behaviors that |
| 15 // we want. We replace the standard window controls (zoom, close, miniaturize) |
| 16 // with our own versions, so that we can position them slightly differently than |
| 17 // the default window has them. To do this, we hide the ones that Apple provides |
| 18 // us with, and create our own. This requires us to handle tracking for the |
| 19 // buttons (so that they highlight and activate correctly) as well as implement |
| 20 // the private method _mouseInGroup in our frame view class which is required |
| 21 // to get the rollover highlight drawing to draw correctly. |
| 22 @interface ChromeBrowserWindow(ChromeBrowserWindowPrivateMethods) |
| 23 // Return the view that does the "frame" drawing. |
| 24 - (NSView*)frameView; |
| 25 @end |
| 26 |
| 12 typedef int (*KeyToCommandMapper)(bool, bool, bool, int); | 27 typedef int (*KeyToCommandMapper)(bool, bool, bool, int); |
| 13 | 28 |
| 14 @implementation ChromeBrowserWindow | 29 @implementation ChromeBrowserWindow |
| 30 - (id)initWithContentRect:(NSRect)contentRect |
| 31 styleMask:(NSUInteger)aStyle |
| 32 backing:(NSBackingStoreType)bufferingType |
| 33 defer:(BOOL)flag { |
| 34 if ((self = [super initWithContentRect:contentRect |
| 35 styleMask:aStyle |
| 36 backing:bufferingType |
| 37 defer:flag])) { |
| 38 NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter]; |
| 39 [defaultCenter addObserver:self |
| 40 selector:@selector(themeDidChangeNotification:) |
| 41 name:kGTMThemeDidChangeNotification |
| 42 object:nil]; |
| 43 |
| 44 // Hook ourselves up to get notified if the user changes the system |
| 45 // theme on us. |
| 46 NSDistributedNotificationCenter* distCenter = |
| 47 [NSDistributedNotificationCenter defaultCenter]; |
| 48 [distCenter addObserver:self |
| 49 selector:@selector(systemThemeDidChangeNotification:) |
| 50 name:@"AppleAquaColorVariantChanged" |
| 51 object:nil]; |
| 52 [self setOpaque:NO]; |
| 53 // Set up our buttons how we like them. |
| 54 NSView* frameView = [self frameView]; |
| 55 NSRect frameViewBounds = [frameView bounds]; |
| 56 |
| 57 // Find all the "original" buttons, and hide them. We can't use the original |
| 58 // buttons because the OS likes to move them around when we resize windows |
| 59 // and will put them back in what it considers to be their "preferred" |
| 60 // locations. |
| 61 NSButton* oldButton = [self standardWindowButton:NSWindowCloseButton]; |
| 62 [oldButton setHidden:YES]; |
| 63 oldButton = [self standardWindowButton:NSWindowMiniaturizeButton]; |
| 64 [oldButton setHidden:YES]; |
| 65 oldButton = [self standardWindowButton:NSWindowZoomButton]; |
| 66 [oldButton setHidden:YES]; |
| 67 |
| 68 // Create and position our new buttons. |
| 69 closeButton_ = [NSWindow standardWindowButton:NSWindowCloseButton |
| 70 forStyleMask:aStyle]; |
| 71 NSRect closeButtonFrame = [closeButton_ frame]; |
| 72 closeButtonFrame.origin = |
| 73 NSMakePoint(kChromeWindowButtonsOffsetFromLeft, |
| 74 (NSHeight(frameViewBounds) - |
| 75 NSHeight(closeButtonFrame) - |
| 76 kChromeWindowButtonsOffsetFromTop)); |
| 77 [closeButton_ setFrame:closeButtonFrame]; |
| 78 [closeButton_ setTarget:self]; |
| 79 [closeButton_ setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin]; |
| 80 [frameView addSubview:closeButton_]; |
| 81 |
| 82 miniaturizeButton_ = |
| 83 [NSWindow standardWindowButton:NSWindowMiniaturizeButton |
| 84 forStyleMask:aStyle]; |
| 85 NSRect miniaturizeButtonFrame = [miniaturizeButton_ frame]; |
| 86 miniaturizeButtonFrame.origin = |
| 87 NSMakePoint((NSMaxX(closeButtonFrame) + |
| 88 kChromeWindowButtonsInterButtonSpacing), |
| 89 NSMinY(closeButtonFrame)); |
| 90 [miniaturizeButton_ setFrame:miniaturizeButtonFrame]; |
| 91 [miniaturizeButton_ setTarget:self]; |
| 92 [miniaturizeButton_ setAutoresizingMask:(NSViewMaxXMargin | |
| 93 NSViewMinYMargin)]; |
| 94 [frameView addSubview:miniaturizeButton_]; |
| 95 |
| 96 zoomButton_ = [NSWindow standardWindowButton:NSWindowZoomButton |
| 97 forStyleMask:aStyle]; |
| 98 NSRect zoomButtonFrame = [zoomButton_ frame]; |
| 99 zoomButtonFrame.origin = |
| 100 NSMakePoint((NSMaxX(miniaturizeButtonFrame) + |
| 101 kChromeWindowButtonsInterButtonSpacing), |
| 102 NSMinY(miniaturizeButtonFrame)); |
| 103 [zoomButton_ setFrame:zoomButtonFrame]; |
| 104 [zoomButton_ setTarget:self]; |
| 105 [zoomButton_ setAutoresizingMask:(NSViewMaxXMargin | |
| 106 NSViewMinYMargin)]; |
| 107 |
| 108 [frameView addSubview:zoomButton_]; |
| 109 [self updateTrackingAreas]; |
| 110 } |
| 111 return self; |
| 112 } |
| 113 |
| 114 - (void)dealloc { |
| 115 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 116 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; |
| 117 [super dealloc]; |
| 118 } |
| 119 |
| 120 - (NSView*)frameView { |
| 121 return [[self contentView] superview]; |
| 122 } |
| 123 |
| 124 // The tab strip view covers our window buttons. So we add hit testing here |
| 125 // to find them properly and return them to the accessibility system. |
| 126 - (id)accessibilityHitTest:(NSPoint)point { |
| 127 NSPoint windowPoint = [self convertScreenToBase:point]; |
| 128 NSControl* controls[] = { closeButton_, zoomButton_, miniaturizeButton_ }; |
| 129 id value = nil; |
| 130 for (size_t i = 0; i < sizeof(controls) / sizeof(controls[0]); ++i) { |
| 131 if (NSPointInRect(windowPoint, [controls[i] frame])) { |
| 132 value = [controls[i] accessibilityHitTest:point]; |
| 133 break; |
| 134 } |
| 135 } |
| 136 if (!value) { |
| 137 value = [super accessibilityHitTest:point]; |
| 138 } |
| 139 return value; |
| 140 } |
| 141 |
| 142 // Map our custom buttons into the accessibility hierarchy correctly. |
| 143 - (id)accessibilityAttributeValue:(NSString*)attribute { |
| 144 id value = nil; |
| 145 struct { |
| 146 NSString* attribute_; |
| 147 id value_; |
| 148 } attributeMap[] = { |
| 149 { NSAccessibilityCloseButtonAttribute, [closeButton_ cell]}, |
| 150 { NSAccessibilityZoomButtonAttribute, [zoomButton_ cell]}, |
| 151 { NSAccessibilityMinimizeButtonAttribute, [miniaturizeButton_ cell]}, |
| 152 }; |
| 153 |
| 154 for (size_t i = 0; i < sizeof(attributeMap) / sizeof(attributeMap[0]); ++i) { |
| 155 if ([attributeMap[i].attribute_ isEqualToString:attribute]) { |
| 156 value = attributeMap[i].value_; |
| 157 break; |
| 158 } |
| 159 } |
| 160 if (!value) { |
| 161 value = [super accessibilityAttributeValue:attribute]; |
| 162 } |
| 163 return value; |
| 164 } |
| 165 |
| 166 - (void)updateTrackingAreas { |
| 167 NSView* frameView = [self frameView]; |
| 168 if (widgetTrackingArea_) { |
| 169 [frameView removeTrackingArea:widgetTrackingArea_]; |
| 170 } |
| 171 NSRect trackingRect = [closeButton_ frame]; |
| 172 trackingRect.size.width = NSMaxX([zoomButton_ frame]) - NSMinX(trackingRect); |
| 173 widgetTrackingArea_.reset( |
| 174 [[NSTrackingArea alloc] initWithRect:trackingRect |
| 175 options:(NSTrackingMouseEnteredAndExited | |
| 176 NSTrackingActiveAlways) |
| 177 owner:self |
| 178 userInfo:nil]); |
| 179 [frameView addTrackingArea:widgetTrackingArea_]; |
| 180 } |
| 181 |
| 182 - (void)windowMainStatusChanged { |
| 183 [closeButton_ setNeedsDisplay]; |
| 184 [zoomButton_ setNeedsDisplay]; |
| 185 [miniaturizeButton_ setNeedsDisplay]; |
| 186 NSView* frameView = [self frameView]; |
| 187 NSView* contentView = [self contentView]; |
| 188 NSRect updateRect = [frameView frame]; |
| 189 NSRect contentRect = [contentView frame]; |
| 190 CGFloat tabStripHeight = [TabStripController defaultTabHeight]; |
| 191 updateRect.size.height -= NSHeight(contentRect) - tabStripHeight; |
| 192 updateRect.origin.y = NSMaxY(contentRect) - tabStripHeight; |
| 193 [[self frameView] setNeedsDisplayInRect:updateRect]; |
| 194 } |
| 195 |
| 196 - (void)becomeMainWindow { |
| 197 [self windowMainStatusChanged]; |
| 198 [super becomeMainWindow]; |
| 199 } |
| 200 |
| 201 - (void)resignMainWindow { |
| 202 [self windowMainStatusChanged]; |
| 203 [super resignMainWindow]; |
| 204 } |
| 205 |
| 206 - (void)themeDidChangeNotification:(NSNotification*)aNotification { |
| 207 GTMTheme* theme = [aNotification object]; |
| 208 if ([theme isEqual:[self gtm_theme]]) { |
| 209 [[self frameView] setNeedsDisplay:YES]; |
| 210 } |
| 211 } |
| 212 |
| 213 - (void)systemThemeDidChangeNotification:(NSNotification*)aNotification { |
| 214 [closeButton_ setNeedsDisplay]; |
| 215 [zoomButton_ setNeedsDisplay]; |
| 216 [miniaturizeButton_ setNeedsDisplay]; |
| 217 } |
| 218 |
| 219 - (void)sendEvent:(NSEvent*)event { |
| 220 // For cocoa windows, clicking on the close and the miniaturize (but not the |
| 221 // zoom buttons) while a window is in the background does NOT bring that |
| 222 // window to the front. We don't get that behavior for free, so we handle |
| 223 // it here. Zoom buttons do bring the window to the front. Note that |
| 224 // Finder windows (in Leopard) behave differently in this regard in that |
| 225 // zoom buttons don't bring the window to the foreground. |
| 226 BOOL eventHandled = NO; |
| 227 if (![self isMainWindow]) { |
| 228 if ([event type] == NSLeftMouseDown) { |
| 229 NSView* frameView = [self frameView]; |
| 230 NSPoint mouse = [frameView convertPointFromBase:[event locationInWindow]]; |
| 231 if (NSPointInRect(mouse, [closeButton_ frame])) { |
| 232 [closeButton_ mouseDown:event]; |
| 233 eventHandled = YES; |
| 234 } else if (NSPointInRect(mouse, [miniaturizeButton_ frame])) { |
| 235 [miniaturizeButton_ mouseDown:event]; |
| 236 eventHandled = YES; |
| 237 } |
| 238 } |
| 239 } |
| 240 if (!eventHandled) { |
| 241 [super sendEvent:event]; |
| 242 } |
| 243 } |
| 244 |
| 245 // Update our buttons so that they highlight correctly. |
| 246 - (void)mouseEntered:(NSEvent*)event { |
| 247 entered_ = YES; |
| 248 [closeButton_ setNeedsDisplay]; |
| 249 [zoomButton_ setNeedsDisplay]; |
| 250 [miniaturizeButton_ setNeedsDisplay]; |
| 251 } |
| 252 |
| 253 // Update our buttons so that they highlight correctly. |
| 254 - (void)mouseExited:(NSEvent*)event { |
| 255 entered_ = NO; |
| 256 [closeButton_ setNeedsDisplay]; |
| 257 [zoomButton_ setNeedsDisplay]; |
| 258 [miniaturizeButton_ setNeedsDisplay]; |
| 259 } |
| 260 |
| 261 - (BOOL)mouseInGroup:(NSButton*)widget { |
| 262 return entered_; |
| 263 } |
| 15 | 264 |
| 16 - (BOOL)handleExtraKeyboardShortcut:(NSEvent*)event fromTable: | 265 - (BOOL)handleExtraKeyboardShortcut:(NSEvent*)event fromTable: |
| 17 (KeyToCommandMapper)commandForKeyboardShortcut { | 266 (KeyToCommandMapper)commandForKeyboardShortcut { |
| 18 // Extract info from |event|. | 267 // Extract info from |event|. |
| 19 NSUInteger modifers = [event modifierFlags]; | 268 NSUInteger modifers = [event modifierFlags]; |
| 20 const bool cmdKey = modifers & NSCommandKeyMask; | 269 const bool cmdKey = modifers & NSCommandKeyMask; |
| 21 const bool shiftKey = modifers & NSShiftKeyMask; | 270 const bool shiftKey = modifers & NSShiftKeyMask; |
| 22 const bool cntrlKey = modifers & NSControlKeyMask; | 271 const bool cntrlKey = modifers & NSControlKeyMask; |
| 23 const int keyCode = [event keyCode]; | 272 const int keyCode = [event keyCode]; |
| 24 | 273 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 | 314 |
| 66 - (void)setShouldHideTitle:(BOOL)flag { | 315 - (void)setShouldHideTitle:(BOOL)flag { |
| 67 shouldHideTitle_ = flag; | 316 shouldHideTitle_ = flag; |
| 68 } | 317 } |
| 69 | 318 |
| 70 -(BOOL)_isTitleHidden { | 319 -(BOOL)_isTitleHidden { |
| 71 return shouldHideTitle_; | 320 return shouldHideTitle_; |
| 72 } | 321 } |
| 73 | 322 |
| 74 @end | 323 @end |
| OLD | NEW |