1 // Copyright 2015 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.
5 #import "chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.h"
7 #import <Cocoa/Cocoa.h>
9 #import "base/mac/scoped_nsobject.h"
10 #import "base/mac/sdk_forward_declarations.h"
11 #include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h"
12 #import "chrome/browser/ui/views/apps/app_window_native_widget_mac.h"
13 #import "chrome/browser/ui/views/apps/native_app_window_frame_view_mac.h"
14 #import "ui/gfx/mac/coordinate_conversion.h"
16 @interface NSView (WebContentsView)
17 - (void)setMouseDownCanMoveWindow:(BOOL)can_move;
20 // This observer is used to get NSWindowWillStartLiveResizeNotification. We need
21 // a single hook when animated/user resize begins to save the current bounds.
22 @interface StartResizeNotificationObserver : NSObject {
25 ChromeNativeAppWindowViewsMac* nativeAppWindow_;
27 - (id)initForNativeAppWindow:(ChromeNativeAppWindowViewsMac*)nativeAppWindow;
28 - (void)onWindowWillStartLiveResize:(NSNotification*)notification;
29 - (void)stopObserving;
32 @implementation StartResizeNotificationObserver
34 - (id)initForNativeAppWindow:(ChromeNativeAppWindowViewsMac*)nativeAppWindow {
35 if ((self = [super init])) {
36 nativeAppWindow_ = nativeAppWindow;
37 [[NSNotificationCenter defaultCenter]
39 selector:@selector(onWindowWillStartLiveResize:)
40 name:NSWindowWillStartLiveResizeNotification
41 object:static_cast<ui::BaseWindow*>(nativeAppWindow)
47 - (void)onWindowWillStartLiveResize:(NSNotification*)notification {
48 nativeAppWindow_->OnWindowWillStartLiveResize();
51 - (void)stopObserving {
52 [[NSNotificationCenter defaultCenter] removeObserver:self];
53 nativeAppWindow_ = nullptr;
60 bool NSWindowIsMaximized(NSWindow* window) {
61 // -[NSWindow isZoomed] only works if the zoom button is enabled.
62 if ([[window standardWindowButton:NSWindowZoomButton] isEnabled])
63 return [window isZoomed];
65 // We don't attempt to distinguish between a window that has been explicitly
66 // maximized versus one that has just been dragged by the user to fill the
67 // screen. This is the same behavior as -[NSWindow isZoomed] above.
68 return NSEqualRects([window frame], [[window screen] visibleFrame]);
73 ChromeNativeAppWindowViewsMac::ChromeNativeAppWindowViewsMac()
74 : is_hidden_with_app_(false) {
77 ChromeNativeAppWindowViewsMac::~ChromeNativeAppWindowViewsMac() {
78 [nswindow_observer_ stopObserving];
81 void ChromeNativeAppWindowViewsMac::OnWindowWillStartLiveResize() {
82 if (!NSWindowIsMaximized(GetNativeWindow())) {
83 bounds_before_maximize_ = [GetNativeWindow() frame];
87 void ChromeNativeAppWindowViewsMac::OnBeforeWidgetInit(
88 const extensions::AppWindow::CreateParams& create_params,
89 views::Widget::InitParams* init_params,
90 views::Widget* widget) {
91 DCHECK(!init_params->native_widget);
92 init_params->remove_standard_frame = IsFrameless();
93 init_params->native_widget = new AppWindowNativeWidgetMac(widget, this);
94 ChromeNativeAppWindowViews::OnBeforeWidgetInit(create_params, init_params,
98 views::NonClientFrameView*
99 ChromeNativeAppWindowViewsMac::CreateStandardDesktopAppFrame() {
100 return new NativeAppWindowFrameViewMac(widget(), this);
103 views::NonClientFrameView*
104 ChromeNativeAppWindowViewsMac::CreateNonStandardAppFrame() {
105 return new NativeAppWindowFrameViewMac(widget(), this);
108 bool ChromeNativeAppWindowViewsMac::IsMaximized() const {
109 return !IsMinimized() && NSWindowIsMaximized(GetNativeWindow());
112 gfx::Rect ChromeNativeAppWindowViewsMac::GetRestoredBounds() const {
113 if (NSWindowIsMaximized(GetNativeWindow()))
114 return gfx::ScreenRectFromNSRect(bounds_before_maximize_);
116 return ChromeNativeAppWindowViews::GetRestoredBounds();
119 void ChromeNativeAppWindowViewsMac::Show() {
120 UnhideWithoutActivation();
121 ChromeNativeAppWindowViews::Show();
124 void ChromeNativeAppWindowViewsMac::ShowInactive() {
125 if (is_hidden_with_app_)
128 ChromeNativeAppWindowViews::ShowInactive();
131 void ChromeNativeAppWindowViewsMac::Activate() {
132 UnhideWithoutActivation();
133 ChromeNativeAppWindowViews::Activate();
136 void ChromeNativeAppWindowViewsMac::Maximize() {
140 NSWindow* window = GetNativeWindow();
141 if (!NSWindowIsMaximized(window))
142 [window setFrame:[[window screen] visibleFrame] display:YES animate:YES];
145 [window deminiaturize:nil];
148 void ChromeNativeAppWindowViewsMac::Restore() {
149 NSWindow* window = GetNativeWindow();
150 if (NSWindowIsMaximized(window))
151 [window setFrame:bounds_before_maximize_ display:YES animate:YES];
153 ChromeNativeAppWindowViews::Restore();
156 void ChromeNativeAppWindowViewsMac::FlashFrame(bool flash) {
157 apps::ExtensionAppShimHandler::RequestUserAttentionForWindow(
158 app_window(), flash ? apps::APP_SHIM_ATTENTION_CRITICAL
159 : apps::APP_SHIM_ATTENTION_CANCEL);
162 void ChromeNativeAppWindowViewsMac::OnWidgetCreated(views::Widget* widget) {
163 nswindow_observer_.reset(
164 [[StartResizeNotificationObserver alloc] initForNativeAppWindow:this]);
167 void ChromeNativeAppWindowViewsMac::UpdateDraggableRegions(
168 const std::vector<extensions::DraggableRegion>& regions) {
169 ChromeNativeAppWindowViews::UpdateDraggableRegions(regions);
171 NSView* web_contents_view = app_window()->web_contents()->GetNativeView();
172 [web_contents_view setMouseDownCanMoveWindow:YES];
175 void ChromeNativeAppWindowViewsMac::ShowWithApp() {
176 is_hidden_with_app_ = false;
177 if (!app_window()->is_hidden())
181 void ChromeNativeAppWindowViewsMac::HideWithApp() {
182 is_hidden_with_app_ = true;
183 ChromeNativeAppWindowViews::Hide();
186 void ChromeNativeAppWindowViewsMac::UnhideWithoutActivation() {
187 if (is_hidden_with_app_) {
188 apps::ExtensionAppShimHandler::UnhideWithoutActivationForWindow(
190 is_hidden_with_app_ = false;