Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(139)

Unified Diff: ui/views/cocoa/bridged_native_widget_unittest.mm

Issue 388453002: MacViews: NativeWidget -> Widget notifications: fullscreen, activation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: respond to comments Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/views/cocoa/bridged_native_widget.mm ('k') | ui/views/cocoa/views_nswindow_delegate.mm » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/views/cocoa/bridged_native_widget_unittest.mm
diff --git a/ui/views/cocoa/bridged_native_widget_unittest.mm b/ui/views/cocoa/bridged_native_widget_unittest.mm
index 14a7f9c3c0bfc17fe35a420705f2ce6209b2426a..7c24cf7b4bba00c60ac619e56580433a3e28dc1b 100644
--- a/ui/views/cocoa/bridged_native_widget_unittest.mm
+++ b/ui/views/cocoa/bridged_native_widget_unittest.mm
@@ -6,7 +6,10 @@
#import <Cocoa/Cocoa.h>
+#import "base/mac/sdk_forward_declarations.h"
#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#import "testing/gtest_mac.h"
@@ -37,6 +40,91 @@ NSRange EmptyRange() {
} // namespace
+@interface NativeWidgetMacNotificationWaiter : NSObject {
+ @private
+ scoped_ptr<base::RunLoop> runLoop_;
+ base::scoped_nsobject<NSWindow> window_;
+ int enterCount_;
+ int exitCount_;
+ int targetEnterCount_;
+ int targetExitCount_;
+}
+
+@property(readonly, nonatomic) int enterCount;
+@property(readonly, nonatomic) int exitCount;
+
+// Initialize for the given window and start tracking notifications.
+- (id)initWithWindow:(NSWindow*)window;
+
+// Keep spinning a run loop until the enter and exit counts match.
+- (void)waitForEnterCount:(int)enterCount exitCount:(int)exitCount;
+
+// private:
+// Exit the RunLoop if there is one and the counts being tracked match.
+- (void)maybeQuitForChangedArg:(int*)changedArg;
+
+- (void)onEnter:(NSNotification*)notification;
+- (void)onExit:(NSNotification*)notification;
+
+@end
+
+@implementation NativeWidgetMacNotificationWaiter
+
+@synthesize enterCount = enterCount_;
+@synthesize exitCount = exitCount_;
+
+- (id)initWithWindow:(NSWindow*)window {
+ if ((self = [super init])) {
+ window_.reset([window retain]);
+ NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
+ [defaultCenter addObserver:self
+ selector:@selector(onEnter:)
+ name:NSWindowDidEnterFullScreenNotification
+ object:window];
+ [defaultCenter addObserver:self
+ selector:@selector(onExit:)
+ name:NSWindowDidExitFullScreenNotification
+ object:window];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ DCHECK(!runLoop_);
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (void)waitForEnterCount:(int)enterCount exitCount:(int)exitCount {
+ if (enterCount_ >= enterCount && exitCount_ >= exitCount)
+ return;
+
+ targetEnterCount_ = enterCount;
+ targetExitCount_ = exitCount;
+ runLoop_.reset(new base::RunLoop);
+ runLoop_->Run();
+ runLoop_.reset();
+}
+
+- (void)maybeQuitForChangedArg:(int*)changedArg {
+ ++*changedArg;
+ if (!runLoop_)
+ return;
+
+ if (enterCount_ >= targetEnterCount_ && exitCount_ >= targetExitCount_)
+ runLoop_->Quit();
+}
+
+- (void)onEnter:(NSNotification*)notification {
+ [self maybeQuitForChangedArg:&enterCount_];
+}
+
+- (void)onExit:(NSNotification*)notification {
+ [self maybeQuitForChangedArg:&exitCount_];
+}
+
+@end
+
namespace views {
namespace test {
@@ -148,6 +236,9 @@ void BridgedNativeWidgetTest::SetUp() {
view_.reset(new views::View);
base::scoped_nsobject<NSWindow> window([test_window() retain]);
+ // BridgedNativeWidget expects to be initialized with a hidden (deferred)
+ // window.
+ [window orderOut:nil];
EXPECT_FALSE([window delegate]);
bridge()->Init(window, Widget::InitParams());
@@ -156,6 +247,8 @@ void BridgedNativeWidgetTest::SetUp() {
bridge()->SetRootView(view_.get());
ns_view_ = bridge()->ns_view();
+ // Pretend it has been shown via NativeWidgetMac::Show().
+ [window orderFront:nil];
[test_window() makePretendKeyWindowAndSetFirstResponder:bridge()->ns_view()];
}
@@ -246,7 +339,7 @@ TEST_F(BridgedNativeWidgetInitTest, ParentWindowNotNativeWidgetMac) {
[[NSWindow alloc] initWithContentRect:NSMakeRect(50, 50, 400, 300)
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
- defer:NO]);
+ defer:YES]);
[child_window setReleasedWhenClosed:NO]; // Owned by scoped_nsobject.
EXPECT_FALSE([child_window parentWindow]);
@@ -415,5 +508,92 @@ TEST_F(BridgedNativeWidgetTest, TextInput_DeleteForward) {
EXPECT_EQ_RANGE(NSMakeRange(0, 0), [ns_view_ selectedRange]);
}
+// Tests for correct fullscreen tracking, regardless of whether it is initiated
+// by the Widget code or elsewhere (e.g. by the user).
+TEST_F(BridgedNativeWidgetTest, FullscreenSynchronousState) {
+ EXPECT_FALSE(widget_->IsFullscreen());
+ // Allow user-initiated fullscreen changes on the Window.
+ [test_window()
+ setCollectionBehavior:[test_window() collectionBehavior] |
+ NSWindowCollectionBehaviorFullScreenPrimary];
+
+ base::scoped_nsobject<NativeWidgetMacNotificationWaiter> waiter(
+ [[NativeWidgetMacNotificationWaiter alloc] initWithWindow:test_window()]);
+ const gfx::Rect restored_bounds = widget_->GetRestoredBounds();
+
+ // Simualate a user-initiated fullscreen. Note trying to to this again before
+ // spinning a runloop will cause Cocoa to emit text to stdio and ignore it.
+ [test_window() toggleFullScreen:nil];
+ EXPECT_TRUE(widget_->IsFullscreen());
+ EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds());
+
+ // Note there's now an animation running. While that's happening, toggling the
+ // state should work as expected, but do "nothing".
+ widget_->SetFullscreen(false);
+ EXPECT_FALSE(widget_->IsFullscreen());
+ EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds());
+ widget_->SetFullscreen(false); // Same request - should no-op.
+ EXPECT_FALSE(widget_->IsFullscreen());
+ EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds());
+
+ widget_->SetFullscreen(true);
+ EXPECT_TRUE(widget_->IsFullscreen());
+ EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds());
+
+ // Always finish out of fullscreen. Otherwise there are 4 NSWindow objects
+ // that Cocoa creates which don't close themselves and will be seen by the Mac
+ // test harness on teardown. Note that the test harness will be waiting until
+ // all animations complete, since these temporary animation windows will not
+ // be removed from the window list until they do.
+ widget_->SetFullscreen(false);
+ EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds());
+
+ // Now we must wait for the notifications. Since, if the widget is torn down,
+ // the NSWindowDelegate is removed, and the pending request to take out of
+ // fullscreen is lost. Since a message loop has not yet spun up in this test
+ // we can reliably say there will be one enter and one exit, despite all the
+ // toggling above.
+ base::MessageLoopForUI message_loop;
+ [waiter waitForEnterCount:1 exitCount:1];
+ EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds());
+}
+
+// Test fullscreen without overlapping calls and without changing collection
+// behaviour on the test window.
+TEST_F(BridgedNativeWidgetTest, FullscreenEnterAndExit) {
+ base::MessageLoopForUI message_loop;
+ base::scoped_nsobject<NativeWidgetMacNotificationWaiter> waiter(
+ [[NativeWidgetMacNotificationWaiter alloc] initWithWindow:test_window()]);
+
+ EXPECT_FALSE(widget_->IsFullscreen());
+ const gfx::Rect restored_bounds = widget_->GetRestoredBounds();
+ EXPECT_FALSE(restored_bounds.IsEmpty());
+
+ // Ensure this works without having to change collection behavior as for the
+ // test above.
+ widget_->SetFullscreen(true);
+ EXPECT_TRUE(widget_->IsFullscreen());
+ EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds());
+
+ // Should be zero until the runloop spins.
+ EXPECT_EQ(0, [waiter enterCount]);
+ [waiter waitForEnterCount:1 exitCount:0];
+
+ // Verify it hasn't exceeded.
+ EXPECT_EQ(1, [waiter enterCount]);
+ EXPECT_EQ(0, [waiter exitCount]);
+ EXPECT_TRUE(widget_->IsFullscreen());
+ EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds());
+
+ widget_->SetFullscreen(false);
+ EXPECT_FALSE(widget_->IsFullscreen());
+ EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds());
+
+ [waiter waitForEnterCount:1 exitCount:1];
+ EXPECT_EQ(1, [waiter enterCount]);
+ EXPECT_EQ(1, [waiter exitCount]);
+ EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds());
+}
+
} // namespace test
} // namespace views
« no previous file with comments | « ui/views/cocoa/bridged_native_widget.mm ('k') | ui/views/cocoa/views_nswindow_delegate.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698