OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #include "chrome/browser/ui/cocoa/panels/panel_window_controller_cocoa.h" | 5 #include "chrome/browser/ui/cocoa/panels/panel_window_controller_cocoa.h" |
6 | 6 |
7 #import <Cocoa/Cocoa.h> | 7 #import <Cocoa/Cocoa.h> |
8 | 8 |
9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 10 matching lines...) Expand all Loading... |
21 #import "chrome/browser/ui/cocoa/panels/panel_cocoa.h" | 21 #import "chrome/browser/ui/cocoa/panels/panel_cocoa.h" |
22 #import "chrome/browser/ui/cocoa/panels/panel_titlebar_view_cocoa.h" | 22 #import "chrome/browser/ui/cocoa/panels/panel_titlebar_view_cocoa.h" |
23 #import "chrome/browser/ui/cocoa/panels/panel_utils_cocoa.h" | 23 #import "chrome/browser/ui/cocoa/panels/panel_utils_cocoa.h" |
24 #import "chrome/browser/ui/cocoa/tab_contents/favicon_util_mac.h" | 24 #import "chrome/browser/ui/cocoa/tab_contents/favicon_util_mac.h" |
25 #import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h" | 25 #import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h" |
26 #import "chrome/browser/ui/cocoa/tabs/throbber_view.h" | 26 #import "chrome/browser/ui/cocoa/tabs/throbber_view.h" |
27 #include "chrome/browser/ui/panels/panel_bounds_animation.h" | 27 #include "chrome/browser/ui/panels/panel_bounds_animation.h" |
28 #include "chrome/browser/ui/panels/panel_collection.h" | 28 #include "chrome/browser/ui/panels/panel_collection.h" |
29 #include "chrome/browser/ui/panels/panel_constants.h" | 29 #include "chrome/browser/ui/panels/panel_constants.h" |
30 #include "chrome/browser/ui/panels/panel_manager.h" | 30 #include "chrome/browser/ui/panels/panel_manager.h" |
31 #include "chrome/browser/ui/panels/stacked_panel_collection.h" | |
32 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 31 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
33 #include "chrome/browser/ui/toolbar/encoding_menu_controller.h" | 32 #include "chrome/browser/ui/toolbar/encoding_menu_controller.h" |
34 #include "content/public/browser/render_widget_host_view.h" | 33 #include "content/public/browser/render_widget_host_view.h" |
35 #include "content/public/browser/web_contents.h" | 34 #include "content/public/browser/web_contents.h" |
36 #include "content/public/browser/web_contents_view.h" | 35 #include "content/public/browser/web_contents_view.h" |
37 #include "grit/ui_resources.h" | 36 #include "grit/ui_resources.h" |
| 37 #include "third_party/WebKit/public/web/WebCursorInfo.h" |
38 #include "ui/base/resource/resource_bundle.h" | 38 #include "ui/base/resource/resource_bundle.h" |
39 #include "ui/gfx/image/image.h" | 39 #include "ui/gfx/image/image.h" |
| 40 #include "webkit/common/cursors/webcursor.h" |
40 | 41 |
41 using content::WebContents; | 42 using content::WebContents; |
42 | 43 |
43 const int kMinimumWindowSize = 1; | 44 const int kMinimumWindowSize = 1; |
44 const double kBoundsAnimationSpeedPixelsPerSecond = 1000; | 45 const double kBoundsAnimationSpeedPixelsPerSecond = 1000; |
45 const double kBoundsAnimationMaxDurationSeconds = 0.18; | 46 const double kBoundsAnimationMaxDurationSeconds = 0.18; |
46 | 47 |
47 // Edge thickness to trigger user resizing via system, in screen pixels. | 48 // Resize edge thickness, in screen pixels. |
48 const double kWidthOfMouseResizeArea = 15.0; | 49 const double kWidthOfMouseResizeArea = 4.0; |
49 | 50 |
50 @interface PanelWindowControllerCocoa (PanelsCanBecomeKey) | 51 @interface PanelWindowControllerCocoa (PanelsCanBecomeKey) |
51 // Internal helper method for extracting the total number of panel windows | 52 // Internal helper method for extracting the total number of panel windows |
52 // from the panel manager. Used to decide if panel can become the key window. | 53 // from the panel manager. Used to decide if panel can become the key window. |
53 - (int)numPanels; | 54 - (int)numPanels; |
54 @end | 55 @end |
55 | 56 |
56 @implementation PanelWindowCocoaImpl | 57 @implementation PanelWindowCocoaImpl |
57 // The panels cannot be reduced to 3-px windows on the edge of the screen | 58 // The panels cannot be reduced to 3-px windows on the edge of the screen |
58 // active area (above Dock). Default constraining logic makes at least a height | 59 // active area (above Dock). Default constraining logic makes at least a height |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 // Ignore key events if window cannot become key window to fix problem | 101 // Ignore key events if window cannot become key window to fix problem |
101 // where keyboard input is still going into a minimized panel even though | 102 // where keyboard input is still going into a minimized panel even though |
102 // the app has been deactivated in -[PanelWindowControllerCocoa deactivate:]. | 103 // the app has been deactivated in -[PanelWindowControllerCocoa deactivate:]. |
103 - (void)sendEvent:(NSEvent*)anEvent { | 104 - (void)sendEvent:(NSEvent*)anEvent { |
104 NSEventType eventType = [anEvent type]; | 105 NSEventType eventType = [anEvent type]; |
105 if ((eventType == NSKeyDown || eventType == NSKeyUp) && | 106 if ((eventType == NSKeyDown || eventType == NSKeyUp) && |
106 ![self canBecomeKeyWindow]) | 107 ![self canBecomeKeyWindow]) |
107 return; | 108 return; |
108 [super sendEvent:anEvent]; | 109 [super sendEvent:anEvent]; |
109 } | 110 } |
110 | |
111 - (void)mouseMoved:(NSEvent*)event { | |
112 // Cocoa does not support letting the application determine the edges that | |
113 // can trigger the user resizing. To work around this, we track the mouse | |
114 // location. When it is close to the edge/corner where the user resizing | |
115 // is not desired, we force the min and max size of the window to be same | |
116 // as current window size. For all other cases, we restore the min and max | |
117 // size. | |
118 PanelWindowControllerCocoa* controller = | |
119 base::mac::ObjCCast<PanelWindowControllerCocoa>([self windowController]); | |
120 NSRect frame = [self frame]; | |
121 if ([controller canResizeByMouseAtCurrentLocation]) { | |
122 // Mac window server limits window sizes to 10000. | |
123 NSSize maxSize = NSMakeSize(10000, 10000); | |
124 | |
125 // If the user is resizing a stacked panel by its bottom edge, make sure its | |
126 // height cannot grow more than what the panel below it could offer. This is | |
127 // because growing a stacked panel by y amount will shrink the panel below | |
128 // it by same amount and we do not want the panel below it being shrunk to | |
129 // be smaller than the titlebar. | |
130 Panel* panel = [controller panel]; | |
131 NSPoint point = [NSEvent mouseLocation]; | |
132 if (point.y < NSMinY(frame) + kWidthOfMouseResizeArea && panel->stack()) { | |
133 Panel* belowPanel = panel->stack()->GetPanelBelow(panel); | |
134 if (belowPanel && !belowPanel->IsMinimized()) { | |
135 maxSize.height = panel->GetBounds().height() + | |
136 belowPanel->GetBounds().height() - panel::kTitlebarHeight; | |
137 } | |
138 } | |
139 | |
140 // Enable the user-resizing by setting both min and max size to the right | |
141 // values. | |
142 [self setMinSize:NSMakeSize(panel::kPanelMinWidth, | |
143 panel::kPanelMinHeight)]; | |
144 [self setMaxSize:maxSize]; | |
145 } else { | |
146 // Disable the user-resizing by setting both min and max size to be same as | |
147 // current window size. | |
148 [self setMinSize:frame.size]; | |
149 [self setMaxSize:frame.size]; | |
150 } | |
151 | |
152 [super mouseMoved:event]; | |
153 } | |
154 @end | 111 @end |
155 | 112 |
| 113 // Transparent view covering the whole panel in order to intercept mouse |
| 114 // messages for custom user resizing. We need custom resizing because panels |
| 115 // use their own constrained layout. |
| 116 @interface PanelResizeByMouseOverlay : NSView <MouseDragControllerClient> { |
| 117 @private |
| 118 Panel* panel_; |
| 119 base::scoped_nsobject<MouseDragController> dragController_; |
| 120 base::scoped_nsobject<NSCursor> dragCursor_; |
| 121 base::scoped_nsobject<NSCursor> eastWestCursor_; |
| 122 base::scoped_nsobject<NSCursor> northSouthCursor_; |
| 123 base::scoped_nsobject<NSCursor> northEastSouthWestCursor_; |
| 124 base::scoped_nsobject<NSCursor> northWestSouthEastCursor_; |
| 125 NSRect leftCursorRect_; |
| 126 NSRect rightCursorRect_; |
| 127 NSRect topCursorRect_; |
| 128 NSRect bottomCursorRect_; |
| 129 NSRect topLeftCursorRect_; |
| 130 NSRect topRightCursorRect_; |
| 131 NSRect bottomLeftCursorRect_; |
| 132 NSRect bottomRightCursorRect_; |
| 133 } |
| 134 @end |
| 135 |
| 136 namespace { |
| 137 NSCursor* LoadWebKitCursor(WebKit::WebCursorInfo::Type type) { |
| 138 return WebCursor(WebCursor::CursorInfo(type)).GetNativeCursor(); |
| 139 } |
| 140 } |
| 141 |
| 142 @implementation PanelResizeByMouseOverlay |
| 143 - (PanelResizeByMouseOverlay*)initWithFrame:(NSRect)frame panel:(Panel*)panel { |
| 144 if ((self = [super initWithFrame:frame])) { |
| 145 panel_ = panel; |
| 146 dragController_.reset([[MouseDragController alloc] initWithClient:self]); |
| 147 |
| 148 eastWestCursor_.reset( |
| 149 [LoadWebKitCursor(WebKit::WebCursorInfo::TypeEastWestResize) retain]); |
| 150 northSouthCursor_.reset( |
| 151 [LoadWebKitCursor(WebKit::WebCursorInfo::TypeNorthSouthResize) retain]); |
| 152 northEastSouthWestCursor_.reset( |
| 153 [LoadWebKitCursor(WebKit::WebCursorInfo::TypeNorthEastSouthWestResize) |
| 154 retain]); |
| 155 northWestSouthEastCursor_.reset( |
| 156 [LoadWebKitCursor(WebKit::WebCursorInfo::TypeNorthWestSouthEastResize) |
| 157 retain]); |
| 158 } |
| 159 return self; |
| 160 } |
| 161 |
| 162 - (BOOL)acceptsFirstMouse:(NSEvent*)event { |
| 163 return YES; |
| 164 } |
| 165 |
| 166 // |pointInWindow| is in window coordinates. |
| 167 - (panel::ResizingSides)edgeHitTest:(NSPoint)pointInWindow { |
| 168 panel::Resizability resizability = panel_->CanResizeByMouse(); |
| 169 DCHECK_NE(panel::NOT_RESIZABLE, resizability); |
| 170 |
| 171 NSPoint point = [self convertPoint:pointInWindow fromView:nil]; |
| 172 BOOL flipped = [self isFlipped]; |
| 173 |
| 174 if ((resizability & panel::RESIZABLE_TOP_LEFT) && |
| 175 NSMouseInRect(point, topLeftCursorRect_, flipped)) { |
| 176 return panel::RESIZE_TOP_LEFT; |
| 177 } |
| 178 if ((resizability & panel::RESIZABLE_TOP_RIGHT) && |
| 179 NSMouseInRect(point, topRightCursorRect_, flipped)) { |
| 180 return panel::RESIZE_TOP_RIGHT; |
| 181 } |
| 182 if ((resizability & panel::RESIZABLE_BOTTOM_LEFT) && |
| 183 NSMouseInRect(point, bottomLeftCursorRect_, flipped)) { |
| 184 return panel::RESIZE_BOTTOM_LEFT; |
| 185 } |
| 186 if ((resizability & panel::RESIZABLE_BOTTOM_RIGHT) && |
| 187 NSMouseInRect(point, bottomRightCursorRect_, flipped)) { |
| 188 return panel::RESIZE_BOTTOM_RIGHT; |
| 189 } |
| 190 |
| 191 if ((resizability & panel::RESIZABLE_LEFT) && |
| 192 NSMouseInRect(point, leftCursorRect_, flipped)) { |
| 193 return panel::RESIZE_LEFT; |
| 194 } |
| 195 if ((resizability & panel::RESIZABLE_RIGHT) && |
| 196 NSMouseInRect(point, rightCursorRect_, flipped)) { |
| 197 return panel::RESIZE_RIGHT; |
| 198 } |
| 199 if ((resizability & panel::RESIZABLE_TOP) && |
| 200 NSMouseInRect(point, topCursorRect_, flipped)) { |
| 201 return panel::RESIZE_TOP; |
| 202 } |
| 203 if ((resizability & panel::RESIZABLE_BOTTOM) && |
| 204 NSMouseInRect(point, bottomCursorRect_, flipped)) { |
| 205 return panel::RESIZE_BOTTOM; |
| 206 } |
| 207 |
| 208 return panel::RESIZE_NONE; |
| 209 } |
| 210 |
| 211 // NSWindow uses this method to figure out if this view is under the mouse |
| 212 // and hence the one to handle the incoming mouse event. |
| 213 // Since this view covers the whole panel, it is asked first. |
| 214 // See if this is the mouse event we are interested in (in the resize areas) |
| 215 // and return 'nil' to let NSWindow find another candidate otherwise. |
| 216 // |point| is in coordinate system of the parent view. |
| 217 - (NSView*)hitTest:(NSPoint)point { |
| 218 // If panel is not resizable, let the mouse events fall through. |
| 219 if (panel::NOT_RESIZABLE == panel_->CanResizeByMouse()) |
| 220 return nil; |
| 221 |
| 222 NSPoint pointInWindow = [[self superview] convertPoint:point toView:nil]; |
| 223 return [self edgeHitTest:pointInWindow] == panel::RESIZE_NONE ? nil : self; |
| 224 } |
| 225 |
| 226 // Delegate these to MouseDragController, it will call back on |
| 227 // MouseDragControllerClient protocol. |
| 228 - (void)mouseDown:(NSEvent*)event { |
| 229 [dragController_ mouseDown:event]; |
| 230 } |
| 231 |
| 232 - (void)mouseDragged:(NSEvent*)event { |
| 233 [dragController_ mouseDragged:event]; |
| 234 } |
| 235 |
| 236 - (void)mouseUp:(NSEvent*)event { |
| 237 [dragController_ mouseUp:event]; |
| 238 } |
| 239 |
| 240 // MouseDragControllerClient protocol. |
| 241 |
| 242 - (void)prepareForDrag { |
| 243 // If the panel is not resizable, hitTest should have failed and no mouse |
| 244 // events should have come here. |
| 245 DCHECK_NE(panel::NOT_RESIZABLE, panel_->CanResizeByMouse()); |
| 246 |
| 247 // Make sure the cursor stays the same during whole resize operation. |
| 248 // The cursor rects normally do not guarantee the same cursor, since the |
| 249 // mouse may temporarily leave the cursor rect area (or even the window) so |
| 250 // the cursor will flicker. Disable cursor rects and grab the current cursor |
| 251 // so we can set it on mouseDragged: events to avoid flicker. |
| 252 [[self window] disableCursorRects]; |
| 253 dragCursor_.reset([[NSCursor currentCursor] retain]); |
| 254 } |
| 255 |
| 256 - (void)cleanupAfterDrag { |
| 257 [[self window] enableCursorRects]; |
| 258 dragCursor_.reset(); |
| 259 } |
| 260 |
| 261 - (void)dragStarted:(NSPoint)initialMouseLocation { |
| 262 NSPoint initialMouseLocationScreen = |
| 263 [[self window] convertBaseToScreen:initialMouseLocation]; |
| 264 |
| 265 panel_->manager()->StartResizingByMouse( |
| 266 panel_, |
| 267 cocoa_utils::ConvertPointFromCocoaCoordinates(initialMouseLocationScreen), |
| 268 [self edgeHitTest:initialMouseLocation]); |
| 269 } |
| 270 |
| 271 - (void)dragProgress:(NSPoint)mouseLocation { |
| 272 NSPoint mouseLocationScreen = |
| 273 [[self window] convertBaseToScreen:mouseLocation]; |
| 274 panel_->manager()->ResizeByMouse( |
| 275 cocoa_utils::ConvertPointFromCocoaCoordinates(mouseLocationScreen)); |
| 276 |
| 277 // Set the resize cursor on every mouse drag event in case the mouse |
| 278 // wandered outside the window and was switched to another one. |
| 279 // This does not produce flicker, seems the real cursor is updated after |
| 280 // mouseDrag is processed. |
| 281 [dragCursor_ set]; |
| 282 } |
| 283 |
| 284 - (void)dragEnded:(BOOL)cancelled { |
| 285 panel_->manager()->EndResizingByMouse(cancelled); |
| 286 } |
| 287 |
| 288 - (void)resetCursorRects { |
| 289 panel::Resizability resizability = panel_->CanResizeByMouse(); |
| 290 if (panel::NOT_RESIZABLE == resizability) |
| 291 return; |
| 292 |
| 293 NSRect bounds = [self bounds]; |
| 294 |
| 295 // Left vertical edge. |
| 296 if (resizability & panel::RESIZABLE_LEFT) { |
| 297 leftCursorRect_ = NSMakeRect( |
| 298 NSMinX(bounds), |
| 299 NSMinY(bounds) + kWidthOfMouseResizeArea, |
| 300 kWidthOfMouseResizeArea, |
| 301 NSHeight(bounds) - 2 * kWidthOfMouseResizeArea); |
| 302 [self addCursorRect:leftCursorRect_ cursor:eastWestCursor_]; |
| 303 } |
| 304 |
| 305 // Right vertical edge. |
| 306 if (resizability & panel::RESIZABLE_RIGHT) { |
| 307 rightCursorRect_ = leftCursorRect_; |
| 308 rightCursorRect_.origin.x = NSMaxX(bounds) - kWidthOfMouseResizeArea; |
| 309 [self addCursorRect:rightCursorRect_ cursor:eastWestCursor_]; |
| 310 } |
| 311 |
| 312 // Top horizontal edge. |
| 313 if (resizability & panel::RESIZABLE_TOP) { |
| 314 topCursorRect_ = NSMakeRect(NSMinX(bounds) + kWidthOfMouseResizeArea, |
| 315 NSMaxY(bounds) - kWidthOfMouseResizeArea, |
| 316 NSWidth(bounds) - 2 * kWidthOfMouseResizeArea, |
| 317 kWidthOfMouseResizeArea); |
| 318 [self addCursorRect:topCursorRect_ cursor:northSouthCursor_]; |
| 319 } |
| 320 |
| 321 // Top left corner. |
| 322 if (resizability & panel::RESIZABLE_TOP_LEFT) { |
| 323 topLeftCursorRect_ = NSMakeRect(NSMinX(bounds), |
| 324 NSMaxY(bounds) - kWidthOfMouseResizeArea, |
| 325 kWidthOfMouseResizeArea, |
| 326 NSMaxY(bounds)); |
| 327 [self addCursorRect:topLeftCursorRect_ cursor:northWestSouthEastCursor_]; |
| 328 } |
| 329 |
| 330 // Top right corner. |
| 331 if (resizability & panel::RESIZABLE_TOP_RIGHT) { |
| 332 topRightCursorRect_ = topLeftCursorRect_; |
| 333 topRightCursorRect_.origin.x = NSMaxX(bounds) - kWidthOfMouseResizeArea; |
| 334 [self addCursorRect:topRightCursorRect_ cursor:northEastSouthWestCursor_]; |
| 335 } |
| 336 |
| 337 // Bottom horizontal edge. |
| 338 if (resizability & panel::RESIZABLE_BOTTOM) { |
| 339 bottomCursorRect_ = topCursorRect_; |
| 340 bottomCursorRect_.origin.y = NSMinY(bounds); |
| 341 [self addCursorRect:bottomCursorRect_ cursor:northSouthCursor_]; |
| 342 } |
| 343 |
| 344 // Bottom right corner. |
| 345 if (resizability & panel::RESIZABLE_BOTTOM_RIGHT) { |
| 346 bottomRightCursorRect_ = topRightCursorRect_; |
| 347 bottomRightCursorRect_.origin.y = NSMinY(bounds); |
| 348 [self addCursorRect:bottomRightCursorRect_ |
| 349 cursor:northWestSouthEastCursor_]; |
| 350 } |
| 351 |
| 352 // Bottom left corner. |
| 353 if (resizability & panel::RESIZABLE_BOTTOM_LEFT) { |
| 354 bottomLeftCursorRect_ = bottomRightCursorRect_; |
| 355 bottomLeftCursorRect_.origin.x = NSMinX(bounds); |
| 356 [self addCursorRect:bottomLeftCursorRect_ cursor:northEastSouthWestCursor_]; |
| 357 } |
| 358 } |
| 359 @end |
| 360 |
156 // ChromeEventProcessingWindow expects its controller to implement the | 361 // ChromeEventProcessingWindow expects its controller to implement the |
157 // BrowserCommandExecutor protocol. | 362 // BrowserCommandExecutor protocol. |
158 @interface PanelWindowControllerCocoa (InternalAPI) <BrowserCommandExecutor> | 363 @interface PanelWindowControllerCocoa (InternalAPI) <BrowserCommandExecutor> |
159 | 364 |
160 // BrowserCommandExecutor methods. | 365 // BrowserCommandExecutor methods. |
161 - (void)executeCommand:(int)command; | 366 - (void)executeCommand:(int)command; |
162 | 367 |
163 @end | 368 @end |
164 | 369 |
165 @implementation PanelWindowControllerCocoa (InternalAPI) | 370 @implementation PanelWindowControllerCocoa (InternalAPI) |
(...skipping 11 matching lines...) Expand all Loading... |
177 [base::mac::FrameworkBundle() pathForResource:@"Panel" ofType:@"nib"]; | 382 [base::mac::FrameworkBundle() pathForResource:@"Panel" ofType:@"nib"]; |
178 if ((self = [super initWithWindowNibPath:nibpath owner:self])) { | 383 if ((self = [super initWithWindowNibPath:nibpath owner:self])) { |
179 windowShim_.reset(window); | 384 windowShim_.reset(window); |
180 animateOnBoundsChange_ = YES; | 385 animateOnBoundsChange_ = YES; |
181 canBecomeKeyWindow_ = YES; | 386 canBecomeKeyWindow_ = YES; |
182 activationRequestedByPanel_ = NO; | 387 activationRequestedByPanel_ = NO; |
183 } | 388 } |
184 return self; | 389 return self; |
185 } | 390 } |
186 | 391 |
187 - (Panel*)panel { | |
188 return windowShim_->panel(); | |
189 } | |
190 | |
191 - (void)awakeFromNib { | 392 - (void)awakeFromNib { |
192 NSWindow* window = [self window]; | 393 NSWindow* window = [self window]; |
193 | 394 |
194 DCHECK(window); | 395 DCHECK(window); |
195 DCHECK(titlebar_view_); | 396 DCHECK(titlebar_view_); |
196 DCHECK_EQ(self, [window delegate]); | 397 DCHECK_EQ(self, [window delegate]); |
197 | 398 |
198 [self updateWindowLevel]; | 399 [self updateWindowLevel]; |
199 | 400 |
200 [self updateWindowCollectionBehavior]; | 401 [self updateWindowCollectionBehavior]; |
201 | 402 |
202 [titlebar_view_ attach]; | 403 [titlebar_view_ attach]; |
203 | 404 |
204 // Set initial size of the window to match the size of the panel to give | 405 // Set initial size of the window to match the size of the panel to give |
205 // the renderer the proper size to work with earlier, avoiding a resize | 406 // the renderer the proper size to work with earlier, avoiding a resize |
206 // after the window is revealed. | 407 // after the window is revealed. |
207 gfx::Rect panelBounds = windowShim_->panel()->GetBounds(); | 408 gfx::Rect panelBounds = windowShim_->panel()->GetBounds(); |
208 NSRect frame = [window frame]; | 409 NSRect frame = [window frame]; |
209 frame.size.width = panelBounds.width(); | 410 frame.size.width = panelBounds.width(); |
210 frame.size.height = panelBounds.height(); | 411 frame.size.height = panelBounds.height(); |
211 [window setFrame:frame display:NO]; | 412 [window setFrame:frame display:NO]; |
212 | 413 |
213 // MacOS will turn the user-resizing to the user-dragging if the direction of | 414 // Add a transparent overlay on top of the whole window to process mouse |
214 // the dragging is orthogonal to the direction of the arrow cursor. We do not | 415 // events - for example, user-resizing. |
215 // want this since it will bypass our dragging logic. The panel window is | 416 NSView* superview = [[window contentView] superview]; |
216 // still draggable because we track and handle the dragging in our custom way. | 417 NSRect bounds = [superview bounds]; |
217 [[self window] setMovable:NO]; | 418 overlayView_.reset( |
218 | 419 [[PanelResizeByMouseOverlay alloc] initWithFrame:bounds |
219 [self updateTrackingArea]; | 420 panel:windowShim_->panel()]); |
| 421 // Set autoresizing behavior: glued to edges. |
| 422 [overlayView_ setAutoresizingMask:(NSViewHeightSizable | NSViewWidthSizable)]; |
| 423 [superview addSubview:overlayView_ positioned:NSWindowAbove relativeTo:nil]; |
220 } | 424 } |
221 | 425 |
222 - (void)updateWebContentsViewFrame { | 426 - (void)updateWebContentsViewFrame { |
223 content::WebContents* webContents = windowShim_->panel()->GetWebContents(); | 427 content::WebContents* webContents = windowShim_->panel()->GetWebContents(); |
224 if (!webContents) | 428 if (!webContents) |
225 return; | 429 return; |
226 | 430 |
227 // Compute the size of the web contents view. Don't assume it's similar to the | 431 // Compute the size of the web contents view. Don't assume it's similar to the |
228 // size of the contentView, because the contentView is managed by the Cocoa | 432 // size of the contentView, because the contentView is managed by the Cocoa |
229 // to be (window - standard titlebar), while we have taller custom titlebar | 433 // to be (window - standard titlebar), while we have taller custom titlebar |
(...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 - (void)windowDidBecomeKey:(NSNotification*)notification { | 795 - (void)windowDidBecomeKey:(NSNotification*)notification { |
592 // We need to activate the controls (in the "WebView"). To do this, get the | 796 // We need to activate the controls (in the "WebView"). To do this, get the |
593 // selected WebContents's RenderWidgetHostView and tell it to activate. | 797 // selected WebContents's RenderWidgetHostView and tell it to activate. |
594 if (WebContents* contents = windowShim_->panel()->GetWebContents()) { | 798 if (WebContents* contents = windowShim_->panel()->GetWebContents()) { |
595 if (content::RenderWidgetHostView* rwhv = | 799 if (content::RenderWidgetHostView* rwhv = |
596 contents->GetRenderWidgetHostView()) | 800 contents->GetRenderWidgetHostView()) |
597 rwhv->SetActive(true); | 801 rwhv->SetActive(true); |
598 } | 802 } |
599 | 803 |
600 windowShim_->panel()->OnActiveStateChanged(true); | 804 windowShim_->panel()->OnActiveStateChanged(true); |
601 | |
602 // Make the window user-resizable when it gains the focus. | |
603 [[self window] setStyleMask: | |
604 [[self window] styleMask] | NSResizableWindowMask]; | |
605 } | 805 } |
606 | 806 |
607 - (void)windowDidResignKey:(NSNotification*)notification { | 807 - (void)windowDidResignKey:(NSNotification*)notification { |
608 // If our app is still active and we're still the key window, ignore this | 808 // If our app is still active and we're still the key window, ignore this |
609 // message, since it just means that a menu extra (on the "system status bar") | 809 // message, since it just means that a menu extra (on the "system status bar") |
610 // was activated; we'll get another |-windowDidResignKey| if we ever really | 810 // was activated; we'll get another |-windowDidResignKey| if we ever really |
611 // lose key window status. | 811 // lose key window status. |
612 if ([NSApp isActive] && ([NSApp keyWindow] == [self window])) | 812 if ([NSApp isActive] && ([NSApp keyWindow] == [self window])) |
613 return; | 813 return; |
614 | 814 |
615 [self onWindowDidResignKey]; | 815 [self onWindowDidResignKey]; |
616 | |
617 // Make the window not user-resizable when it loses the focus. This is to | |
618 // solve the problem that the bottom edge of the active panel does not | |
619 // trigger the user-resizing if this panel stacks with another inactive | |
620 // panel at the bottom. | |
621 [[self window] setStyleMask: | |
622 [[self window] styleMask] & ~NSResizableWindowMask]; | |
623 } | |
624 | |
625 - (void)windowWillStartLiveResize:(NSNotification*)notification { | |
626 // Check if the user-resizing is allowed for the triggering edge/corner. | |
627 // This is an extra safe guard because we are not able to track the mouse | |
628 // movement outside the window and Cocoa could trigger the user-resizing | |
629 // when the mouse moves a bit outside the edge/corner. | |
630 if (![self canResizeByMouseAtCurrentLocation]) | |
631 return; | |
632 userResizing_ = YES; | |
633 windowShim_->panel()->OnPanelStartUserResizing(); | |
634 } | |
635 | |
636 - (void)windowDidEndLiveResize:(NSNotification*)notification { | |
637 if (!userResizing_) | |
638 return; | |
639 userResizing_ = NO; | |
640 | |
641 Panel* panel = windowShim_->panel(); | |
642 panel->OnPanelEndUserResizing(); | |
643 | |
644 gfx::Rect newBounds = | |
645 cocoa_utils::ConvertRectFromCocoaCoordinates([[self window] frame]); | |
646 if (windowShim_->panel()->GetBounds() == newBounds) | |
647 return; | |
648 windowShim_->set_cached_bounds_directly(newBounds); | |
649 | |
650 panel->IncreaseMaxSize(newBounds.size()); | |
651 panel->set_full_size(newBounds.size()); | |
652 | |
653 panel->collection()->RefreshLayout(); | |
654 } | |
655 | |
656 - (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)newSize { | |
657 // As an extra safe guard, we avoid the user resizing if it is deemed not to | |
658 // be allowed (see comment in windowWillStartLiveResize). | |
659 if ([[self window] inLiveResize] && !userResizing_) | |
660 return [[self window] frame].size; | |
661 return newSize; | |
662 } | 816 } |
663 | 817 |
664 - (void)windowDidResize:(NSNotification*)notification { | 818 - (void)windowDidResize:(NSNotification*)notification { |
665 Panel* panel = windowShim_->panel(); | 819 Panel* panel = windowShim_->panel(); |
666 if (userResizing_) { | |
667 panel->collection()->OnPanelResizedByMouse( | |
668 panel, | |
669 cocoa_utils::ConvertRectFromCocoaCoordinates([[self window] frame])); | |
670 } | |
671 | |
672 [self updateTrackingArea]; | |
673 | |
674 if (![self isAnimatingBounds] || | 820 if (![self isAnimatingBounds] || |
675 panel->collection()->type() != PanelCollection::DOCKED) | 821 panel->collection()->type() != PanelCollection::DOCKED) |
676 return; | 822 return; |
677 | 823 |
678 // Remove the web contents view from the view hierarchy when the panel is not | 824 // Remove the web contents view from the view hierarchy when the panel is not |
679 // taller than the titlebar. Put it back when the panel grows taller than | 825 // taller than the titlebar. Put it back when the panel grows taller than |
680 // the titlebar. Note that RenderWidgetHostViewMac works for the case that | 826 // the titlebar. Note that RenderWidgetHostViewMac works for the case that |
681 // the web contents view does not exist in the view hierarchy (i.e. the tab | 827 // the web contents view does not exist in the view hierarchy (i.e. the tab |
682 // is not the main one), but it does not work well, like causing occasional | 828 // is not the main one), but it does not work well, like causing occasional |
683 // crashes (http://crbug.com/265932), if the web contents view is made hidden. | 829 // crashes (http://crbug.com/265932), if the web contents view is made hidden. |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
819 - (void)updateWindowCollectionBehavior { | 965 - (void)updateWindowCollectionBehavior { |
820 if (![self isWindowLoaded]) | 966 if (![self isWindowLoaded]) |
821 return; | 967 return; |
822 NSWindowCollectionBehavior collectionBehavior = | 968 NSWindowCollectionBehavior collectionBehavior = |
823 NSWindowCollectionBehaviorParticipatesInCycle; | 969 NSWindowCollectionBehaviorParticipatesInCycle; |
824 if (windowShim_->panel()->IsAlwaysOnTop()) | 970 if (windowShim_->panel()->IsAlwaysOnTop()) |
825 collectionBehavior |= NSWindowCollectionBehaviorCanJoinAllSpaces; | 971 collectionBehavior |= NSWindowCollectionBehaviorCanJoinAllSpaces; |
826 [[self window] setCollectionBehavior:collectionBehavior]; | 972 [[self window] setCollectionBehavior:collectionBehavior]; |
827 } | 973 } |
828 | 974 |
829 - (void)updateTrackingArea { | 975 - (void)enableResizeByMouse:(BOOL)enable { |
830 NSView* superview = [[[self window] contentView] superview]; | 976 if (![self isWindowLoaded]) |
831 | 977 return; |
832 if (trackingArea_.get()) | 978 [[self window] invalidateCursorRectsForView:overlayView_]; |
833 [superview removeTrackingArea:trackingArea_.get()]; | |
834 | |
835 trackingArea_.reset( | |
836 [[CrTrackingArea alloc] initWithRect:[superview bounds] | |
837 options:NSTrackingInVisibleRect | | |
838 NSTrackingMouseMoved | | |
839 NSTrackingActiveInKeyWindow | |
840 owner:superview | |
841 userInfo:nil]); | |
842 [superview addTrackingArea:trackingArea_.get()]; | |
843 } | 979 } |
844 | 980 |
845 - (void)showShadow:(BOOL)show { | 981 - (void)showShadow:(BOOL)show { |
846 if (![self isWindowLoaded]) | 982 if (![self isWindowLoaded]) |
847 return; | 983 return; |
848 [[self window] setHasShadow:show]; | 984 [[self window] setHasShadow:show]; |
849 } | 985 } |
850 | 986 |
851 - (void)miniaturize { | 987 - (void)miniaturize { |
852 [[self window] miniaturize:nil]; | 988 [[self window] miniaturize:nil]; |
853 } | 989 } |
854 | 990 |
855 - (BOOL)isMiniaturized { | 991 - (BOOL)isMiniaturized { |
856 return [[self window] isMiniaturized]; | 992 return [[self window] isMiniaturized]; |
857 } | 993 } |
858 | 994 |
859 - (BOOL)canResizeByMouseAtCurrentLocation { | |
860 panel::Resizability resizability = windowShim_->panel()->CanResizeByMouse(); | |
861 NSRect frame = [[self window] frame]; | |
862 NSPoint point = [NSEvent mouseLocation]; | |
863 | |
864 if (point.y < NSMinY(frame) + kWidthOfMouseResizeArea) { | |
865 if (point.x < NSMinX(frame) + kWidthOfMouseResizeArea && | |
866 (resizability & panel::RESIZABLE_BOTTOM_LEFT) == 0) { | |
867 return NO; | |
868 } | |
869 if (point.x > NSMaxX(frame) - kWidthOfMouseResizeArea && | |
870 (resizability & panel::RESIZABLE_BOTTOM_RIGHT) == 0) { | |
871 return NO; | |
872 } | |
873 if ((resizability & panel::RESIZABLE_BOTTOM) == 0) | |
874 return NO; | |
875 } else if (point.y > NSMaxY(frame) - kWidthOfMouseResizeArea) { | |
876 if (point.x < NSMinX(frame) + kWidthOfMouseResizeArea && | |
877 (resizability & panel::RESIZABLE_TOP_LEFT) == 0) { | |
878 return NO; | |
879 } | |
880 if (point.x > NSMaxX(frame) - kWidthOfMouseResizeArea && | |
881 (resizability & panel::RESIZABLE_TOP_RIGHT) == 0) { | |
882 return NO; | |
883 } | |
884 if ((resizability & panel::RESIZABLE_TOP) == 0) | |
885 return NO; | |
886 } else { | |
887 if (point.x < NSMinX(frame) + kWidthOfMouseResizeArea && | |
888 (resizability & panel::RESIZABLE_LEFT) == 0) { | |
889 return NO; | |
890 } | |
891 if (point.x > NSMaxX(frame) - kWidthOfMouseResizeArea && | |
892 (resizability & panel::RESIZABLE_RIGHT) == 0) { | |
893 return NO; | |
894 } | |
895 } | |
896 return YES; | |
897 } | |
898 | |
899 // We have custom implementation of these because our titlebar height is custom | 995 // We have custom implementation of these because our titlebar height is custom |
900 // and does not match the standard one. | 996 // and does not match the standard one. |
901 - (NSRect)frameRectForContentRect:(NSRect)contentRect { | 997 - (NSRect)frameRectForContentRect:(NSRect)contentRect { |
902 // contentRect is in contentView coord system. We should add a titlebar on top | 998 // contentRect is in contentView coord system. We should add a titlebar on top |
903 // and then convert to the windows coord system. | 999 // and then convert to the windows coord system. |
904 contentRect.size.height += panel::kTitlebarHeight; | 1000 contentRect.size.height += panel::kTitlebarHeight; |
905 NSRect frameRect = [[[self window] contentView] convertRect:contentRect | 1001 NSRect frameRect = [[[self window] contentView] convertRect:contentRect |
906 toView:nil]; | 1002 toView:nil]; |
907 return frameRect; | 1003 return frameRect; |
908 } | 1004 } |
909 | 1005 |
910 - (NSRect)contentRectForFrameRect:(NSRect)frameRect { | 1006 - (NSRect)contentRectForFrameRect:(NSRect)frameRect { |
911 NSRect contentRect = [[[self window] contentView] convertRect:frameRect | 1007 NSRect contentRect = [[[self window] contentView] convertRect:frameRect |
912 fromView:nil]; | 1008 fromView:nil]; |
913 contentRect.size.height -= panel::kTitlebarHeight; | 1009 contentRect.size.height -= panel::kTitlebarHeight; |
914 if (contentRect.size.height < 0) | 1010 if (contentRect.size.height < 0) |
915 contentRect.size.height = 0; | 1011 contentRect.size.height = 0; |
916 return contentRect; | 1012 return contentRect; |
917 } | 1013 } |
918 | 1014 |
919 @end | 1015 @end |
OLD | NEW |