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 3// found in the LICENSE file. 4 5#import "chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h" 6 7#import <Cocoa/Cocoa.h> 8 9#include "base/mac/mac_util.h" 10#include "base/mac/sdk_forward_declarations.h" 11#include "chrome/browser/apps/app_browsertest_util.h" 12#include "chrome/browser/profiles/profile.h" 13#include "chrome/browser/ui/extensions/application_launch.h" 14#include "content/public/browser/notification_service.h" 15#include "content/public/test/test_utils.h" 16#include "extensions/browser/app_window/app_window_registry.h" 17 18using extensions::PlatformAppBrowserTest; 19 20namespace { 21 22class NativeAppWindowCocoaBrowserTest : public PlatformAppBrowserTest { 23 protected: 24 NativeAppWindowCocoaBrowserTest() {} 25 26 void SetUpAppWithWindows(int num_windows) { 27 app_ = InstallExtension( 28 test_data_dir_.AppendASCII("platform_apps").AppendASCII("minimal"), 1); 29 EXPECT_TRUE(app_); 30 31 for (int i = 0; i < num_windows; ++i) { 32 content::WindowedNotificationObserver app_loaded_observer( 33 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, 34 content::NotificationService::AllSources()); 35 OpenApplication( 36 AppLaunchParams(profile(), 37 app_, 38 extensions::LAUNCH_CONTAINER_NONE, 39 NEW_WINDOW)); 40 app_loaded_observer.Wait(); 41 } 42 } 43 44 const extensions::Extension* app_; 45 46 private: 47 DISALLOW_COPY_AND_ASSIGN(NativeAppWindowCocoaBrowserTest); 48}; 49 50} // namespace 51 52// Test interaction of Hide/Show() with Hide/ShowWithApp(). 53IN_PROC_BROWSER_TEST_F(NativeAppWindowCocoaBrowserTest, HideShowWithApp) { 54 SetUpAppWithWindows(2); 55 extensions::AppWindowRegistry::AppWindowList windows = 56 extensions::AppWindowRegistry::Get(profile())->app_windows(); 57 58 extensions::AppWindow* app_window = windows.front(); 59 extensions::NativeAppWindow* native_window = app_window->GetBaseWindow(); 60 NSWindow* ns_window = native_window->GetNativeWindow(); 61 62 extensions::AppWindow* other_app_window = windows.back(); 63 extensions::NativeAppWindow* other_native_window = 64 other_app_window->GetBaseWindow(); 65 NSWindow* other_ns_window = other_native_window->GetNativeWindow(); 66 67 // Normal Hide/Show. 68 app_window->Hide(); 69 EXPECT_FALSE([ns_window isVisible]); 70 app_window->Show(extensions::AppWindow::SHOW_ACTIVE); 71 EXPECT_TRUE([ns_window isVisible]); 72 73 // Normal Hide/ShowWithApp. 74 native_window->HideWithApp(); 75 EXPECT_FALSE([ns_window isVisible]); 76 native_window->ShowWithApp(); 77 EXPECT_TRUE([ns_window isVisible]); 78 79 // HideWithApp, Hide, ShowWithApp does not show. 80 native_window->HideWithApp(); 81 app_window->Hide(); 82 native_window->ShowWithApp(); 83 EXPECT_FALSE([ns_window isVisible]); 84 85 // Hide, HideWithApp, ShowWithApp does not show. 86 native_window->HideWithApp(); 87 native_window->ShowWithApp(); 88 EXPECT_FALSE([ns_window isVisible]); 89 90 // Return to shown state. 91 app_window->Show(extensions::AppWindow::SHOW_ACTIVE); 92 EXPECT_TRUE([ns_window isVisible]); 93 94 // HideWithApp the other window. 95 EXPECT_TRUE([other_ns_window isVisible]); 96 other_native_window->HideWithApp(); 97 EXPECT_FALSE([other_ns_window isVisible]); 98 99 // HideWithApp, Show shows all windows for this app. 100 native_window->HideWithApp(); 101 EXPECT_FALSE([ns_window isVisible]); 102 app_window->Show(extensions::AppWindow::SHOW_ACTIVE); 103 EXPECT_TRUE([ns_window isVisible]); 104 EXPECT_TRUE([other_ns_window isVisible]); 105 106 // Hide the other window. 107 other_app_window->Hide(); 108 EXPECT_FALSE([other_ns_window isVisible]); 109 110 // HideWithApp, ShowWithApp does not show the other window. 111 native_window->HideWithApp(); 112 EXPECT_FALSE([ns_window isVisible]); 113 native_window->ShowWithApp(); 114 EXPECT_TRUE([ns_window isVisible]); 115 EXPECT_FALSE([other_ns_window isVisible]); 116} 117 118// Only test fullscreen for 10.7 and above. 119// Replicate specific 10.7 SDK declarations for building with prior SDKs. 120#if !defined(MAC_OS_X_VERSION_10_7) || \ 121 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 122 123NSString* const NSWindowDidEnterFullScreenNotification = 124 @"NSWindowDidEnterFullScreenNotification"; 125NSString* const NSWindowDidExitFullScreenNotification = 126 @"NSWindowDidExitFullScreenNotification"; 127 128#endif // MAC_OS_X_VERSION_10_7 129 130@interface ScopedNotificationWatcher : NSObject { 131 @private 132 BOOL received_; 133} 134- (id)initWithNotification:(NSString*)notification 135 andObject:(NSObject*)object; 136- (void)onNotification:(NSString*)notification; 137- (void)waitForNotification; 138@end 139 140@implementation ScopedNotificationWatcher 141 142- (id)initWithNotification:(NSString*)notification 143 andObject:(NSObject*)object { 144 if ((self = [super init])) { 145 [[NSNotificationCenter defaultCenter] 146 addObserver:self 147 selector:@selector(onNotification:) 148 name:notification 149 object:object]; 150 } 151 return self; 152} 153 154- (void)onNotification:(NSString*)notification { 155 received_ = YES; 156 [[NSNotificationCenter defaultCenter] removeObserver:self]; 157} 158 159- (void)waitForNotification { 160 while (!received_) 161 content::RunAllPendingInMessageLoop(); 162} 163 164@end 165 166// Test that NativeAppWindow and AppWindow fullscreen state is updated when 167// the window is fullscreened natively. 168IN_PROC_BROWSER_TEST_F(NativeAppWindowCocoaBrowserTest, Fullscreen) { 169 if (!base::mac::IsOSLionOrLater()) 170 return; 171 172 SetUpAppWithWindows(1); 173 extensions::AppWindow* app_window = GetFirstAppWindow(); 174 extensions::NativeAppWindow* window = app_window->GetBaseWindow(); 175 NSWindow* ns_window = app_window->GetNativeWindow(); 176 base::scoped_nsobject<ScopedNotificationWatcher> watcher; 177 178 EXPECT_EQ(extensions::AppWindow::FULLSCREEN_TYPE_NONE, 179 app_window->fullscreen_types_for_test()); 180 EXPECT_FALSE(window->IsFullscreen()); 181 EXPECT_FALSE([ns_window styleMask] & NSFullScreenWindowMask); 182 183 watcher.reset([[ScopedNotificationWatcher alloc] 184 initWithNotification:NSWindowDidEnterFullScreenNotification 185 andObject:ns_window]); 186 [ns_window toggleFullScreen:nil]; 187 [watcher waitForNotification]; 188 EXPECT_TRUE(app_window->fullscreen_types_for_test() & 189 extensions::AppWindow::FULLSCREEN_TYPE_OS); 190 EXPECT_TRUE(window->IsFullscreen()); 191 EXPECT_TRUE([ns_window styleMask] & NSFullScreenWindowMask); 192 193 watcher.reset([[ScopedNotificationWatcher alloc] 194 initWithNotification:NSWindowDidExitFullScreenNotification 195 andObject:ns_window]); 196 app_window->Restore(); 197 EXPECT_FALSE(window->IsFullscreenOrPending()); 198 [watcher waitForNotification]; 199 EXPECT_EQ(extensions::AppWindow::FULLSCREEN_TYPE_NONE, 200 app_window->fullscreen_types_for_test()); 201 EXPECT_FALSE(window->IsFullscreen()); 202 EXPECT_FALSE([ns_window styleMask] & NSFullScreenWindowMask); 203 204 watcher.reset([[ScopedNotificationWatcher alloc] 205 initWithNotification:NSWindowDidEnterFullScreenNotification 206 andObject:ns_window]); 207 app_window->Fullscreen(); 208 EXPECT_TRUE(window->IsFullscreenOrPending()); 209 [watcher waitForNotification]; 210 EXPECT_TRUE(app_window->fullscreen_types_for_test() & 211 extensions::AppWindow::FULLSCREEN_TYPE_WINDOW_API); 212 EXPECT_TRUE(window->IsFullscreen()); 213 EXPECT_TRUE([ns_window styleMask] & NSFullScreenWindowMask); 214 215 watcher.reset([[ScopedNotificationWatcher alloc] 216 initWithNotification:NSWindowDidExitFullScreenNotification 217 andObject:ns_window]); 218 [ns_window toggleFullScreen:nil]; 219 [watcher waitForNotification]; 220 EXPECT_EQ(extensions::AppWindow::FULLSCREEN_TYPE_NONE, 221 app_window->fullscreen_types_for_test()); 222 EXPECT_FALSE(window->IsFullscreen()); 223 EXPECT_FALSE([ns_window styleMask] & NSFullScreenWindowMask); 224} 225