| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/apps/native_app_window_cocoa.h" | 5 #include "chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h" |
| 6 | 6 |
| 7 #include "apps/app_shim/extension_app_shim_handler_mac.h" | 7 #include "apps/app_shim/extension_app_shim_handler_mac.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/mac/mac_util.h" | 9 #include "base/mac/mac_util.h" |
| 10 #include "base/strings/sys_string_conversions.h" | 10 #include "base/strings/sys_string_conversions.h" |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 80 [window setCollectionBehavior:behavior]; | 80 [window setCollectionBehavior:behavior]; |
| 81 } | 81 } |
| 82 | 82 |
| 83 // Returns the level for windows that are configured to be always on top. | 83 // Returns the level for windows that are configured to be always on top. |
| 84 // This is not a constant because NSFloatingWindowLevel is a macro defined | 84 // This is not a constant because NSFloatingWindowLevel is a macro defined |
| 85 // as a function call. | 85 // as a function call. |
| 86 NSInteger AlwaysOnTopWindowLevel() { | 86 NSInteger AlwaysOnTopWindowLevel() { |
| 87 return NSFloatingWindowLevel; | 87 return NSFloatingWindowLevel; |
| 88 } | 88 } |
| 89 | 89 |
| 90 NSRect GfxToCocoaBounds(gfx::Rect bounds) { |
| 91 typedef apps::AppWindow::BoundsSpecification BoundsSpecification; |
| 92 |
| 93 NSRect main_screen_rect = [[[NSScreen screens] objectAtIndex:0] frame]; |
| 94 |
| 95 // If coordinates are unspecified, center window on primary screen. |
| 96 if (bounds.x() == BoundsSpecification::kUnspecifiedPosition) |
| 97 bounds.set_x(floor((NSWidth(main_screen_rect) - bounds.width()) / 2)); |
| 98 if (bounds.y() == BoundsSpecification::kUnspecifiedPosition) |
| 99 bounds.set_y(floor((NSHeight(main_screen_rect) - bounds.height()) / 2)); |
| 100 |
| 101 // Convert to Mac coordinates. |
| 102 NSRect cocoa_bounds = NSRectFromCGRect(bounds.ToCGRect()); |
| 103 cocoa_bounds.origin.y = NSHeight(main_screen_rect) - NSMaxY(cocoa_bounds); |
| 104 return cocoa_bounds; |
| 105 } |
| 106 |
| 90 } // namespace | 107 } // namespace |
| 91 | 108 |
| 92 @implementation NativeAppWindowController | 109 @implementation NativeAppWindowController |
| 93 | 110 |
| 94 @synthesize appWindow = appWindow_; | 111 @synthesize appWindow = appWindow_; |
| 95 | 112 |
| 96 - (void)windowWillClose:(NSNotification*)notification { | 113 - (void)windowWillClose:(NSNotification*)notification { |
| 97 if (appWindow_) | 114 if (appWindow_) |
| 98 appWindow_->WindowWillClose(); | 115 appWindow_->WindowWillClose(); |
| 99 } | 116 } |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 277 | 294 |
| 278 NativeAppWindowCocoa::NativeAppWindowCocoa( | 295 NativeAppWindowCocoa::NativeAppWindowCocoa( |
| 279 AppWindow* app_window, | 296 AppWindow* app_window, |
| 280 const AppWindow::CreateParams& params) | 297 const AppWindow::CreateParams& params) |
| 281 : app_window_(app_window), | 298 : app_window_(app_window), |
| 282 has_frame_(params.frame == AppWindow::FRAME_CHROME), | 299 has_frame_(params.frame == AppWindow::FRAME_CHROME), |
| 283 is_hidden_(false), | 300 is_hidden_(false), |
| 284 is_hidden_with_app_(false), | 301 is_hidden_with_app_(false), |
| 285 is_maximized_(false), | 302 is_maximized_(false), |
| 286 is_fullscreen_(false), | 303 is_fullscreen_(false), |
| 304 is_resizable_(params.resizable), |
| 305 shows_resize_controls_(true), |
| 306 shows_fullscreen_controls_(true), |
| 287 attention_request_id_(0), | 307 attention_request_id_(0), |
| 288 use_system_drag_(true) { | 308 use_system_drag_(true) { |
| 289 Observe(web_contents()); | 309 Observe(web_contents()); |
| 290 | 310 |
| 291 // Flip coordinates based on the primary screen. | |
| 292 NSRect main_screen_rect = [[[NSScreen screens] objectAtIndex:0] frame]; | |
| 293 NSRect cocoa_bounds = NSMakeRect(params.bounds.x(), | |
| 294 NSHeight(main_screen_rect) - params.bounds.y() - params.bounds.height(), | |
| 295 params.bounds.width(), params.bounds.height()); | |
| 296 | |
| 297 // If coordinates are < 0, center window on primary screen. | |
| 298 if (params.bounds.x() == INT_MIN) { | |
| 299 cocoa_bounds.origin.x = | |
| 300 floor((NSWidth(main_screen_rect) - NSWidth(cocoa_bounds)) / 2); | |
| 301 } | |
| 302 if (params.bounds.y() == INT_MIN) { | |
| 303 cocoa_bounds.origin.y = | |
| 304 floor((NSHeight(main_screen_rect) - NSHeight(cocoa_bounds)) / 2); | |
| 305 } | |
| 306 | |
| 307 // Initialize |restored_bounds_| after |cocoa_bounds| have been sanitized. | |
| 308 restored_bounds_ = cocoa_bounds; | |
| 309 | |
| 310 base::scoped_nsobject<NSWindow> window; | 311 base::scoped_nsobject<NSWindow> window; |
| 311 Class window_class; | 312 Class window_class; |
| 312 if (has_frame_) { | 313 if (has_frame_) { |
| 313 bool should_use_native_frame = | 314 bool should_use_native_frame = |
| 314 CommandLine::ForCurrentProcess()->HasSwitch( | 315 CommandLine::ForCurrentProcess()->HasSwitch( |
| 315 switches::kAppsUseNativeFrame); | 316 switches::kAppsUseNativeFrame); |
| 316 window_class = should_use_native_frame ? | 317 window_class = should_use_native_frame ? |
| 317 [ShellNSWindow class] : [ShellCustomFrameNSWindow class]; | 318 [ShellNSWindow class] : [ShellCustomFrameNSWindow class]; |
| 318 } else { | 319 } else { |
| 319 window_class = [ShellFramelessNSWindow class]; | 320 window_class = [ShellFramelessNSWindow class]; |
| 320 } | 321 } |
| 321 | 322 |
| 322 size_constraints_.set_minimum_size(params.minimum_size); | 323 // Estimate the initial bounds of the window. Once the frame insets are known, |
| 323 size_constraints_.set_maximum_size(params.maximum_size); | 324 // the window bounds and constraints can be set precisely. |
| 324 shows_resize_controls_ = | 325 NSRect cocoa_bounds = GfxToCocoaBounds( |
| 325 params.resizable && !size_constraints_.HasFixedSize(); | 326 params.GetInitialWindowBounds(gfx::Insets())); |
| 326 shows_fullscreen_controls_ = | |
| 327 params.resizable && !size_constraints_.HasMaximumSize(); | |
| 328 window.reset([[window_class alloc] | 327 window.reset([[window_class alloc] |
| 329 initWithContentRect:cocoa_bounds | 328 initWithContentRect:cocoa_bounds |
| 330 styleMask:GetWindowStyleMask() | 329 styleMask:GetWindowStyleMask() |
| 331 backing:NSBackingStoreBuffered | 330 backing:NSBackingStoreBuffered |
| 332 defer:NO]); | 331 defer:NO]); |
| 333 [window setTitle:base::SysUTF8ToNSString(extension()->name())]; | 332 [window setTitle:base::SysUTF8ToNSString(extension()->name())]; |
| 334 | 333 |
| 335 if (base::mac::IsOSSnowLeopard() && | 334 if (base::mac::IsOSSnowLeopard() && |
| 336 [window respondsToSelector:@selector(setBottomCornerRounded:)]) | 335 [window respondsToSelector:@selector(setBottomCornerRounded:)]) |
| 337 [window setBottomCornerRounded:NO]; | 336 [window setBottomCornerRounded:NO]; |
| 338 | 337 |
| 339 if (params.always_on_top) | 338 if (params.always_on_top) |
| 340 [window setLevel:AlwaysOnTopWindowLevel()]; | 339 [window setLevel:AlwaysOnTopWindowLevel()]; |
| 341 InitCollectionBehavior(window); | 340 InitCollectionBehavior(window); |
| 342 | 341 |
| 343 // Set the window to participate in Lion Fullscreen mode. Setting this flag | |
| 344 // has no effect on Snow Leopard or earlier. UI controls for fullscreen are | |
| 345 // only shown for apps that have unbounded size. | |
| 346 if (shows_fullscreen_controls_) | |
| 347 SetFullScreenCollectionBehavior(window, true); | |
| 348 | |
| 349 window_controller_.reset( | 342 window_controller_.reset( |
| 350 [[NativeAppWindowController alloc] initWithWindow:window.release()]); | 343 [[NativeAppWindowController alloc] initWithWindow:window.release()]); |
| 351 | 344 |
| 352 NSView* view = web_contents()->GetView()->GetNativeView(); | 345 NSView* view = web_contents()->GetView()->GetNativeView(); |
| 353 [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; | 346 [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; |
| 354 | 347 |
| 355 // By default, the whole frameless window is not draggable. | 348 // By default, the whole frameless window is not draggable. |
| 356 if (!has_frame_) { | 349 if (!has_frame_) { |
| 357 gfx::Rect window_bounds( | 350 gfx::Rect window_bounds( |
| 358 0, 0, NSWidth(cocoa_bounds), NSHeight(cocoa_bounds)); | 351 0, 0, NSWidth(cocoa_bounds), NSHeight(cocoa_bounds)); |
| 359 system_drag_exclude_areas_.push_back(window_bounds); | 352 system_drag_exclude_areas_.push_back(window_bounds); |
| 360 } | 353 } |
| 361 | 354 |
| 362 InstallView(); | 355 InstallView(); |
| 363 | 356 |
| 364 [[window_controller_ window] setDelegate:window_controller_]; | 357 [[window_controller_ window] setDelegate:window_controller_]; |
| 365 [window_controller_ setAppWindow:this]; | 358 [window_controller_ setAppWindow:this]; |
| 366 | 359 |
| 367 // Update the size constraints of the NSWindow. | 360 // We can now compute the precise window bounds and constraints. |
| 368 SetMinimumSize(params.minimum_size); | 361 gfx::Insets insets = GetFrameInsets(); |
| 369 SetMaximumSize(params.maximum_size); | 362 SetBounds(params.GetInitialWindowBounds(insets)); |
| 363 SetContentSizeConstraints(params.GetContentMinimumSize(insets), |
| 364 params.GetContentMaximumSize(insets)); |
| 365 |
| 366 // Initialize |restored_bounds_|. |
| 367 restored_bounds_ = [this->window() frame]; |
| 370 | 368 |
| 371 extension_keybinding_registry_.reset(new ExtensionKeybindingRegistryCocoa( | 369 extension_keybinding_registry_.reset(new ExtensionKeybindingRegistryCocoa( |
| 372 Profile::FromBrowserContext(app_window_->browser_context()), | 370 Profile::FromBrowserContext(app_window_->browser_context()), |
| 373 window, | 371 window, |
| 374 extensions::ExtensionKeybindingRegistry::PLATFORM_APPS_ONLY, | 372 extensions::ExtensionKeybindingRegistry::PLATFORM_APPS_ONLY, |
| 375 NULL)); | 373 NULL)); |
| 376 } | 374 } |
| 377 | 375 |
| 378 NSUInteger NativeAppWindowCocoa::GetWindowStyleMask() const { | 376 NSUInteger NativeAppWindowCocoa::GetWindowStyleMask() const { |
| 379 NSUInteger style_mask = NSTitledWindowMask | NSClosableWindowMask | | 377 NSUInteger style_mask = NSTitledWindowMask | NSClosableWindowMask | |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 606 if (bounds.width() < min_size.width) | 604 if (bounds.width() < min_size.width) |
| 607 checked_bounds.set_width(min_size.width); | 605 checked_bounds.set_width(min_size.width); |
| 608 if (bounds.height() < min_size.height) | 606 if (bounds.height() < min_size.height) |
| 609 checked_bounds.set_height(min_size.height); | 607 checked_bounds.set_height(min_size.height); |
| 610 NSSize max_size = [window() maxSize]; | 608 NSSize max_size = [window() maxSize]; |
| 611 if (checked_bounds.width() > max_size.width) | 609 if (checked_bounds.width() > max_size.width) |
| 612 checked_bounds.set_width(max_size.width); | 610 checked_bounds.set_width(max_size.width); |
| 613 if (checked_bounds.height() > max_size.height) | 611 if (checked_bounds.height() > max_size.height) |
| 614 checked_bounds.set_height(max_size.height); | 612 checked_bounds.set_height(max_size.height); |
| 615 | 613 |
| 616 NSRect cocoa_bounds = NSMakeRect(checked_bounds.x(), 0, | 614 NSRect cocoa_bounds = GfxToCocoaBounds(checked_bounds); |
| 617 checked_bounds.width(), | |
| 618 checked_bounds.height()); | |
| 619 // Flip coordinates based on the primary screen. | |
| 620 NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; | |
| 621 cocoa_bounds.origin.y = NSHeight([screen frame]) - checked_bounds.bottom(); | |
| 622 | |
| 623 [window() setFrame:cocoa_bounds display:YES]; | 615 [window() setFrame:cocoa_bounds display:YES]; |
| 624 // setFrame: without animate: does not trigger a windowDidEndLiveResize: so | 616 // setFrame: without animate: does not trigger a windowDidEndLiveResize: so |
| 625 // call it here. | 617 // call it here. |
| 626 WindowDidFinishResize(); | 618 WindowDidFinishResize(); |
| 627 } | 619 } |
| 628 | 620 |
| 629 void NativeAppWindowCocoa::UpdateWindowIcon() { | 621 void NativeAppWindowCocoa::UpdateWindowIcon() { |
| 630 // TODO(junmin): implement. | 622 // TODO(junmin): implement. |
| 631 } | 623 } |
| 632 | 624 |
| (...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1030 NSWindow* window = [window_controller_ window]; | 1022 NSWindow* window = [window_controller_ window]; |
| 1031 CHECK(!window || [window isKindOfClass:[ShellNSWindow class]]); | 1023 CHECK(!window || [window isKindOfClass:[ShellNSWindow class]]); |
| 1032 return static_cast<ShellNSWindow*>(window); | 1024 return static_cast<ShellNSWindow*>(window); |
| 1033 } | 1025 } |
| 1034 | 1026 |
| 1035 void NativeAppWindowCocoa::UpdateRestoredBounds() { | 1027 void NativeAppWindowCocoa::UpdateRestoredBounds() { |
| 1036 if (IsRestored(*this)) | 1028 if (IsRestored(*this)) |
| 1037 restored_bounds_ = [window() frame]; | 1029 restored_bounds_ = [window() frame]; |
| 1038 } | 1030 } |
| 1039 | 1031 |
| 1040 void NativeAppWindowCocoa::UpdateShelfMenu() { | 1032 void NativeAppWindowCocoa::SetContentSizeConstraints( |
| 1041 // TODO(tmdiep): To be implemented for Mac. | 1033 const gfx::Size& minimum_size, const gfx::Size& maximum_size) { |
| 1042 NOTIMPLEMENTED(); | 1034 // Update the size constraints. |
| 1043 } | 1035 size_constraints_.set_minimum_size(minimum_size); |
| 1044 | 1036 size_constraints_.set_maximum_size(maximum_size); |
| 1045 gfx::Size NativeAppWindowCocoa::GetMinimumSize() const { | |
| 1046 return size_constraints_.GetMinimumSize(); | |
| 1047 } | |
| 1048 | |
| 1049 void NativeAppWindowCocoa::SetMinimumSize(const gfx::Size& size) { | |
| 1050 size_constraints_.set_minimum_size(size); | |
| 1051 | 1037 |
| 1052 gfx::Size min_size = size_constraints_.GetMinimumSize(); | 1038 gfx::Size min_size = size_constraints_.GetMinimumSize(); |
| 1053 [window() setContentMinSize:NSMakeSize(min_size.width(), min_size.height())]; | 1039 [window() setContentMinSize:NSMakeSize(min_size.width(), min_size.height())]; |
| 1054 } | |
| 1055 | |
| 1056 gfx::Size NativeAppWindowCocoa::GetMaximumSize() const { | |
| 1057 return size_constraints_.GetMaximumSize(); | |
| 1058 } | |
| 1059 | |
| 1060 void NativeAppWindowCocoa::SetMaximumSize(const gfx::Size& size) { | |
| 1061 size_constraints_.set_maximum_size(size); | |
| 1062 | 1040 |
| 1063 gfx::Size max_size = size_constraints_.GetMaximumSize(); | 1041 gfx::Size max_size = size_constraints_.GetMaximumSize(); |
| 1064 const int kUnboundedSize = apps::SizeConstraints::kUnboundedSize; | 1042 const int kUnboundedSize = apps::SizeConstraints::kUnboundedSize; |
| 1065 CGFloat max_width = max_size.width() == kUnboundedSize ? | 1043 CGFloat max_width = max_size.width() == kUnboundedSize ? |
| 1066 CGFLOAT_MAX : max_size.width(); | 1044 CGFLOAT_MAX : max_size.width(); |
| 1067 CGFloat max_height = max_size.height() == kUnboundedSize ? | 1045 CGFloat max_height = max_size.height() == kUnboundedSize ? |
| 1068 CGFLOAT_MAX : max_size.height(); | 1046 CGFLOAT_MAX : max_size.height(); |
| 1069 [window() setContentMaxSize:NSMakeSize(max_width, max_height)]; | 1047 [window() setContentMaxSize:NSMakeSize(max_width, max_height)]; |
| 1048 |
| 1049 // Update the window controls. |
| 1050 shows_resize_controls_ = |
| 1051 is_resizable_ && !size_constraints_.HasFixedSize(); |
| 1052 shows_fullscreen_controls_ = |
| 1053 is_resizable_ && !size_constraints_.HasMaximumSize(); |
| 1054 |
| 1055 if (!is_fullscreen_) { |
| 1056 [window() setStyleMask:GetWindowStyleMask()]; |
| 1057 |
| 1058 // Set the window to participate in Lion Fullscreen mode. Setting this flag |
| 1059 // has no effect on Snow Leopard or earlier. UI controls for fullscreen are |
| 1060 // only shown for apps that have unbounded size. |
| 1061 SetFullScreenCollectionBehavior(window(), shows_fullscreen_controls_); |
| 1062 } |
| 1070 } | 1063 } |
| 1064 |
| 1065 void NativeAppWindowCocoa::UpdateShelfMenu() { |
| 1066 // TODO(tmdiep): To be implemented for Mac. |
| 1067 NOTIMPLEMENTED(); |
| 1068 } |
| 1069 |
| 1070 gfx::Size NativeAppWindowCocoa::GetContentMinimumSize() const { |
| 1071 return size_constraints_.GetMinimumSize(); |
| 1072 } |
| 1073 |
| 1074 void NativeAppWindowCocoa::SetContentMinimumSize(const gfx::Size& size) { |
| 1075 SetContentSizeConstraints(size, size_constraints_.GetMaximumSize()); |
| 1076 } |
| 1077 |
| 1078 gfx::Size NativeAppWindowCocoa::GetContentMaximumSize() const { |
| 1079 return size_constraints_.GetMaximumSize(); |
| 1080 } |
| 1081 |
| 1082 void NativeAppWindowCocoa::SetContentMaximumSize(const gfx::Size& size) { |
| 1083 SetContentSizeConstraints(size_constraints_.GetMinimumSize(), size); |
| 1084 } |
| OLD | NEW |