blob: 3278955d0734f1ed0397680baefd6eef1ba9b8f2 [file] [log] [blame]
// Copyright 2013 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.
// This file tests whichever implementation of NativeAppWindow is used.
// I.e. it could be NativeAppWindowCocoa or ChromeNativeAppWindowViewsMac.
#include "extensions/browser/app_window/native_app_window.h"
#import <Cocoa/Cocoa.h>
#include "base/mac/mac_util.h"
#include "base/mac/scoped_nsobject.h"
#include "base/mac/sdk_forward_declarations.h"
#include "chrome/browser/apps/app_browsertest_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/extensions/app_launch_params.h"
#include "chrome/browser/ui/extensions/application_launch.h"
#include "content/public/browser/notification_service.h"
#include "content/public/test/test_utils.h"
#include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/common/constants.h"
using extensions::PlatformAppBrowserTest;
namespace {
class NativeAppWindowCocoaBrowserTest : public PlatformAppBrowserTest {
protected:
NativeAppWindowCocoaBrowserTest() {}
void SetUpAppWithWindows(int num_windows) {
app_ = InstallExtension(
test_data_dir_.AppendASCII("platform_apps").AppendASCII("minimal"), 1);
EXPECT_TRUE(app_);
for (int i = 0; i < num_windows; ++i) {
content::WindowedNotificationObserver app_loaded_observer(
content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
content::NotificationService::AllSources());
OpenApplication(
AppLaunchParams(profile(), app_, extensions::LAUNCH_CONTAINER_NONE,
NEW_WINDOW, extensions::SOURCE_TEST));
app_loaded_observer.Wait();
}
}
const extensions::Extension* app_;
private:
DISALLOW_COPY_AND_ASSIGN(NativeAppWindowCocoaBrowserTest);
};
} // namespace
// Test interaction of Hide/Show() with Hide/ShowWithApp().
IN_PROC_BROWSER_TEST_F(NativeAppWindowCocoaBrowserTest, HideShowWithApp) {
SetUpAppWithWindows(2);
extensions::AppWindowRegistry::AppWindowList windows =
extensions::AppWindowRegistry::Get(profile())->app_windows();
extensions::AppWindow* app_window = windows.front();
extensions::NativeAppWindow* native_window = app_window->GetBaseWindow();
NSWindow* ns_window = native_window->GetNativeWindow();
extensions::AppWindow* other_app_window = windows.back();
extensions::NativeAppWindow* other_native_window =
other_app_window->GetBaseWindow();
NSWindow* other_ns_window = other_native_window->GetNativeWindow();
// Normal Hide/Show.
app_window->Hide();
EXPECT_FALSE([ns_window isVisible]);
app_window->Show(extensions::AppWindow::SHOW_ACTIVE);
EXPECT_TRUE([ns_window isVisible]);
// Normal Hide/ShowWithApp.
native_window->HideWithApp();
EXPECT_FALSE([ns_window isVisible]);
native_window->ShowWithApp();
EXPECT_TRUE([ns_window isVisible]);
// HideWithApp, Hide, ShowWithApp does not show.
native_window->HideWithApp();
app_window->Hide();
native_window->ShowWithApp();
EXPECT_FALSE([ns_window isVisible]);
// Hide, HideWithApp, ShowWithApp does not show.
native_window->HideWithApp();
native_window->ShowWithApp();
EXPECT_FALSE([ns_window isVisible]);
// Return to shown state.
app_window->Show(extensions::AppWindow::SHOW_ACTIVE);
EXPECT_TRUE([ns_window isVisible]);
// HideWithApp the other window.
EXPECT_TRUE([other_ns_window isVisible]);
other_native_window->HideWithApp();
EXPECT_FALSE([other_ns_window isVisible]);
// HideWithApp, Show shows all windows for this app.
native_window->HideWithApp();
EXPECT_FALSE([ns_window isVisible]);
app_window->Show(extensions::AppWindow::SHOW_ACTIVE);
EXPECT_TRUE([ns_window isVisible]);
EXPECT_TRUE([other_ns_window isVisible]);
// Hide the other window.
other_app_window->Hide();
EXPECT_FALSE([other_ns_window isVisible]);
// HideWithApp, ShowWithApp does not show the other window.
native_window->HideWithApp();
EXPECT_FALSE([ns_window isVisible]);
native_window->ShowWithApp();
EXPECT_TRUE([ns_window isVisible]);
EXPECT_FALSE([other_ns_window isVisible]);
}
@interface ScopedNotificationWatcher : NSObject {
@private
BOOL received_;
}
- (id)initWithNotification:(NSString*)notification
andObject:(NSObject*)object;
- (void)onNotification:(NSString*)notification;
- (void)waitForNotification;
@end
@implementation ScopedNotificationWatcher
- (id)initWithNotification:(NSString*)notification
andObject:(NSObject*)object {
if ((self = [super init])) {
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(onNotification:)
name:notification
object:object];
}
return self;
}
- (void)onNotification:(NSString*)notification {
received_ = YES;
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)waitForNotification {
while (!received_)
content::RunAllPendingInMessageLoop();
}
@end
// Test that NativeAppWindow and AppWindow fullscreen state is updated when
// the window is fullscreened natively.
IN_PROC_BROWSER_TEST_F(NativeAppWindowCocoaBrowserTest, Fullscreen) {
if (!base::mac::IsOSLionOrLater())
return;
SetUpAppWithWindows(1);
extensions::AppWindow* app_window = GetFirstAppWindow();
extensions::NativeAppWindow* window = app_window->GetBaseWindow();
NSWindow* ns_window = app_window->GetNativeWindow();
base::scoped_nsobject<ScopedNotificationWatcher> watcher;
EXPECT_EQ(extensions::AppWindow::FULLSCREEN_TYPE_NONE,
app_window->fullscreen_types_for_test());
EXPECT_FALSE(window->IsFullscreen());
EXPECT_FALSE([ns_window styleMask] & NSFullScreenWindowMask);
watcher.reset([[ScopedNotificationWatcher alloc]
initWithNotification:NSWindowDidEnterFullScreenNotification
andObject:ns_window]);
[ns_window toggleFullScreen:nil];
[watcher waitForNotification];
EXPECT_TRUE(app_window->fullscreen_types_for_test() &
extensions::AppWindow::FULLSCREEN_TYPE_OS);
EXPECT_TRUE(window->IsFullscreen());
EXPECT_TRUE([ns_window styleMask] & NSFullScreenWindowMask);
watcher.reset([[ScopedNotificationWatcher alloc]
initWithNotification:NSWindowDidExitFullScreenNotification
andObject:ns_window]);
app_window->Restore();
EXPECT_FALSE(window->IsFullscreenOrPending());
[watcher waitForNotification];
EXPECT_EQ(extensions::AppWindow::FULLSCREEN_TYPE_NONE,
app_window->fullscreen_types_for_test());
EXPECT_FALSE(window->IsFullscreen());
EXPECT_FALSE([ns_window styleMask] & NSFullScreenWindowMask);
watcher.reset([[ScopedNotificationWatcher alloc]
initWithNotification:NSWindowDidEnterFullScreenNotification
andObject:ns_window]);
app_window->Fullscreen();
EXPECT_TRUE(window->IsFullscreenOrPending());
[watcher waitForNotification];
EXPECT_TRUE(app_window->fullscreen_types_for_test() &
extensions::AppWindow::FULLSCREEN_TYPE_WINDOW_API);
EXPECT_TRUE(window->IsFullscreen());
EXPECT_TRUE([ns_window styleMask] & NSFullScreenWindowMask);
watcher.reset([[ScopedNotificationWatcher alloc]
initWithNotification:NSWindowDidExitFullScreenNotification
andObject:ns_window]);
[ns_window toggleFullScreen:nil];
[watcher waitForNotification];
EXPECT_EQ(extensions::AppWindow::FULLSCREEN_TYPE_NONE,
app_window->fullscreen_types_for_test());
EXPECT_FALSE(window->IsFullscreen());
EXPECT_FALSE([ns_window styleMask] & NSFullScreenWindowMask);
}
// Test that, in frameless windows, the web contents has the same size as the
// window.
IN_PROC_BROWSER_TEST_F(NativeAppWindowCocoaBrowserTest, Frameless) {
extensions::AppWindow* app_window =
CreateTestAppWindow("{\"frame\": \"none\"}");
NSWindow* ns_window = app_window->GetNativeWindow();
NSView* web_contents = app_window->web_contents()->GetNativeView();
EXPECT_TRUE(NSEqualSizes(NSMakeSize(512, 384), [web_contents frame].size));
// Move and resize the window.
NSRect new_frame = NSMakeRect(50, 50, 200, 200);
[ns_window setFrame:new_frame display:YES];
EXPECT_TRUE(NSEqualSizes(new_frame.size, [web_contents frame].size));
// Windows created with NSBorderlessWindowMask by default don't have shadow,
// but packaged apps should always have one.
EXPECT_TRUE([ns_window hasShadow]);
// Since the window has no constraints, it should have all of the following
// style mask bits.
NSUInteger style_mask = NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask |
NSTexturedBackgroundWindowMask;
EXPECT_EQ(style_mask, [ns_window styleMask]);
CloseAppWindow(app_window);
}
namespace {
// Test that resize and fullscreen controls are correctly enabled/disabled.
void TestControls(extensions::AppWindow* app_window) {
NSWindow* ns_window = app_window->GetNativeWindow();
// The window is resizable.
EXPECT_TRUE([ns_window styleMask] & NSResizableWindowMask);
if (base::mac::IsOSSnowLeopard())
EXPECT_TRUE([ns_window showsResizeIndicator]);
// Due to this bug: http://crbug.com/362039, which manifests on the Cocoa
// implementation but not the views one, frameless windows should have
// fullscreen controls disabled.
BOOL can_fullscreen =
![NSStringFromClass([ns_window class]) isEqualTo:@"AppFramelessNSWindow"];
// The window can fullscreen and maximize.
if (base::mac::IsOSLionOrLater())
EXPECT_EQ(can_fullscreen, !!([ns_window collectionBehavior] &
NSWindowCollectionBehaviorFullScreenPrimary));
EXPECT_EQ(can_fullscreen,
[[ns_window standardWindowButton:NSWindowZoomButton] isEnabled]);
// Set a maximum size.
app_window->SetContentSizeConstraints(gfx::Size(), gfx::Size(200, 201));
EXPECT_EQ(200, [ns_window contentMaxSize].width);
EXPECT_EQ(201, [ns_window contentMaxSize].height);
NSView* web_contents = app_window->web_contents()->GetNativeView();
EXPECT_EQ(200, [web_contents frame].size.width);
EXPECT_EQ(201, [web_contents frame].size.height);
// Still resizable.
EXPECT_TRUE([ns_window styleMask] & NSResizableWindowMask);
if (base::mac::IsOSSnowLeopard())
EXPECT_TRUE([ns_window showsResizeIndicator]);
// Fullscreen and maximize are disabled.
if (base::mac::IsOSLionOrLater())
EXPECT_FALSE([ns_window collectionBehavior] &
NSWindowCollectionBehaviorFullScreenPrimary);
EXPECT_FALSE([[ns_window standardWindowButton:NSWindowZoomButton] isEnabled]);
// Set a minimum size equal to the maximum size.
app_window->SetContentSizeConstraints(gfx::Size(200, 201),
gfx::Size(200, 201));
EXPECT_EQ(200, [ns_window contentMinSize].width);
EXPECT_EQ(201, [ns_window contentMinSize].height);
// No longer resizable.
EXPECT_FALSE([ns_window styleMask] & NSResizableWindowMask);
if (base::mac::IsOSSnowLeopard())
EXPECT_FALSE([ns_window showsResizeIndicator]);
}
} // namespace
IN_PROC_BROWSER_TEST_F(NativeAppWindowCocoaBrowserTest, Controls) {
TestControls(CreateTestAppWindow("{}"));
}
IN_PROC_BROWSER_TEST_F(NativeAppWindowCocoaBrowserTest, ControlsFrameless) {
TestControls(CreateTestAppWindow("{\"frame\": \"none\"}"));
}