blob: 2f3c721a5159bd5015bd75dfee6b34d47272eef9 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.h"
#import <Cocoa/Cocoa.h>
#import "base/mac/scoped_nsobject.h"
#import "base/mac/sdk_forward_declarations.h"
#include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h"
#import "chrome/browser/ui/views/apps/app_window_native_widget_mac.h"
#import "chrome/browser/ui/views/apps/native_app_window_frame_view_mac.h"
#import "ui/gfx/mac/coordinate_conversion.h"
// This observer is used to get NSWindow notifications. We need to monitor
// zoom and full screen events to store the correct bounds to Restore() to.
@interface ResizeNotificationObserver : NSObject {
@private
// Weak. Owns us.
ChromeNativeAppWindowViewsMac* nativeAppWindow_;
}
- (id)initForNativeAppWindow:(ChromeNativeAppWindowViewsMac*)nativeAppWindow;
- (void)onWindowWillStartLiveResize:(NSNotification*)notification;
- (void)onWindowWillExitFullScreen:(NSNotification*)notification;
- (void)onWindowDidExitFullScreen:(NSNotification*)notification;
- (void)stopObserving;
@end
@implementation ResizeNotificationObserver
- (id)initForNativeAppWindow:(ChromeNativeAppWindowViewsMac*)nativeAppWindow {
if ((self = [super init])) {
nativeAppWindow_ = nativeAppWindow;
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(onWindowWillStartLiveResize:)
name:NSWindowWillStartLiveResizeNotification
object:static_cast<ui::BaseWindow*>(nativeAppWindow)
->GetNativeWindow()
.GetNativeNSWindow()];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(onWindowWillExitFullScreen:)
name:NSWindowWillExitFullScreenNotification
object:static_cast<ui::BaseWindow*>(nativeAppWindow)
->GetNativeWindow()
.GetNativeNSWindow()];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(onWindowDidExitFullScreen:)
name:NSWindowDidExitFullScreenNotification
object:static_cast<ui::BaseWindow*>(nativeAppWindow)
->GetNativeWindow()
.GetNativeNSWindow()];
}
return self;
}
- (void)onWindowWillStartLiveResize:(NSNotification*)notification {
nativeAppWindow_->OnWindowWillStartLiveResize();
}
- (void)onWindowWillExitFullScreen:(NSNotification*)notification {
nativeAppWindow_->OnWindowWillExitFullScreen();
}
- (void)onWindowDidExitFullScreen:(NSNotification*)notification {
nativeAppWindow_->OnWindowDidExitFullScreen();
}
- (void)stopObserving {
[[NSNotificationCenter defaultCenter] removeObserver:self];
nativeAppWindow_ = nullptr;
}
@end
namespace {
bool NSWindowIsMaximized(NSWindow* window) {
// -[NSWindow isZoomed] only works if the zoom button is enabled.
if ([[window standardWindowButton:NSWindowZoomButton] isEnabled])
return [window isZoomed];
// We don't attempt to distinguish between a window that has been explicitly
// maximized versus one that has just been dragged by the user to fill the
// screen. This is the same behavior as -[NSWindow isZoomed] above.
return NSEqualRects([window frame], [[window screen] visibleFrame]);
}
} // namespace
ChromeNativeAppWindowViewsMac::ChromeNativeAppWindowViewsMac() {}
ChromeNativeAppWindowViewsMac::~ChromeNativeAppWindowViewsMac() {
[nswindow_observer_ stopObserving];
}
void ChromeNativeAppWindowViewsMac::OnWindowWillStartLiveResize() {
if (!NSWindowIsMaximized(GetNativeWindow().GetNativeNSWindow()) &&
!in_fullscreen_transition_) {
bounds_before_maximize_ = [GetNativeWindow().GetNativeNSWindow() frame];
}
}
void ChromeNativeAppWindowViewsMac::OnWindowWillExitFullScreen() {
in_fullscreen_transition_ = true;
}
void ChromeNativeAppWindowViewsMac::OnWindowDidExitFullScreen() {
in_fullscreen_transition_ = false;
}
void ChromeNativeAppWindowViewsMac::OnBeforeWidgetInit(
const extensions::AppWindow::CreateParams& create_params,
views::Widget::InitParams* init_params,
views::Widget* widget) {
DCHECK(!init_params->native_widget);
init_params->remove_standard_frame = IsFrameless();
init_params->native_widget = new AppWindowNativeWidgetMac(widget, this);
ChromeNativeAppWindowViews::OnBeforeWidgetInit(create_params, init_params,
widget);
}
views::NonClientFrameView*
ChromeNativeAppWindowViewsMac::CreateStandardDesktopAppFrame() {
return new NativeAppWindowFrameViewMac(widget(), this);
}
views::NonClientFrameView*
ChromeNativeAppWindowViewsMac::CreateNonStandardAppFrame() {
return new NativeAppWindowFrameViewMac(widget(), this);
}
bool ChromeNativeAppWindowViewsMac::IsMaximized() const {
return !IsMinimized() && !IsFullscreen() &&
NSWindowIsMaximized(GetNativeWindow().GetNativeNSWindow());
}
gfx::Rect ChromeNativeAppWindowViewsMac::GetRestoredBounds() const {
if (NSWindowIsMaximized(GetNativeWindow().GetNativeNSWindow()))
return gfx::ScreenRectFromNSRect(bounds_before_maximize_);
return ChromeNativeAppWindowViews::GetRestoredBounds();
}
void ChromeNativeAppWindowViewsMac::Show() {
UnhideWithoutActivation();
ChromeNativeAppWindowViews::Show();
}
void ChromeNativeAppWindowViewsMac::ShowInactive() {
if (is_hidden_with_app_)
return;
ChromeNativeAppWindowViews::ShowInactive();
}
void ChromeNativeAppWindowViewsMac::Activate() {
UnhideWithoutActivation();
ChromeNativeAppWindowViews::Activate();
}
void ChromeNativeAppWindowViewsMac::Maximize() {
if (IsFullscreen())
return;
NSWindow* window = GetNativeWindow().GetNativeNSWindow();
if (!NSWindowIsMaximized(window))
[window setFrame:[[window screen] visibleFrame] display:YES animate:YES];
if (IsMinimized())
[window deminiaturize:nil];
}
void ChromeNativeAppWindowViewsMac::Restore() {
NSWindow* window = GetNativeWindow().GetNativeNSWindow();
if (NSWindowIsMaximized(window))
[window setFrame:bounds_before_maximize_ display:YES animate:YES];
ChromeNativeAppWindowViews::Restore();
}
void ChromeNativeAppWindowViewsMac::FlashFrame(bool flash) {
apps::ExtensionAppShimHandler::Get()->RequestUserAttentionForWindow(
app_window(), flash ? apps::APP_SHIM_ATTENTION_CRITICAL
: apps::APP_SHIM_ATTENTION_CANCEL);
}
void ChromeNativeAppWindowViewsMac::OnWidgetCreated(views::Widget* widget) {
nswindow_observer_.reset(
[[ResizeNotificationObserver alloc] initForNativeAppWindow:this]);
}
void ChromeNativeAppWindowViewsMac::ShowWithApp() {
is_hidden_with_app_ = false;
if (!app_window()->is_hidden())
ShowInactive();
}
void ChromeNativeAppWindowViewsMac::HideWithApp() {
is_hidden_with_app_ = true;
ChromeNativeAppWindowViews::Hide();
}
void ChromeNativeAppWindowViewsMac::UnhideWithoutActivation() {
if (is_hidden_with_app_) {
apps::ExtensionAppShimHandler::Get()->UnhideWithoutActivationForWindow(
app_window());
is_hidden_with_app_ = false;
}
}