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