summaryrefslogtreecommitdiffstats
path: root/ui/views/widget/widget_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ui/views/widget/widget_unittest.cc')
-rw-r--r--ui/views/widget/widget_unittest.cc829
1 files changed, 829 insertions, 0 deletions
diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc
new file mode 100644
index 0000000..90632c6
--- /dev/null
+++ b/ui/views/widget/widget_unittest.cc
@@ -0,0 +1,829 @@
+// Copyright (c) 2011 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.
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/point.h"
+#include "ui/views/test/test_views_delegate.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/native_widget_delegate.h"
+#include "views/views_delegate.h"
+
+#if defined(USE_AURA)
+#include "ui/aura/window.h"
+#include "ui/views/widget/native_widget_aura.h"
+#elif defined(OS_WIN)
+#include "ui/views/widget/native_widget_win.h"
+#elif defined(TOOLKIT_USES_GTK)
+#include "ui/views/widget/native_widget_gtk.h"
+#endif
+
+namespace views {
+namespace {
+
+// A generic typedef to pick up relevant NativeWidget implementations.
+#if defined(USE_AURA)
+typedef NativeWidgetAura NativeWidgetPlatform;
+#elif defined(OS_WIN)
+typedef NativeWidgetWin NativeWidgetPlatform;
+#elif defined(TOOLKIT_USES_GTK)
+typedef NativeWidgetGtk NativeWidgetPlatform;
+#endif
+
+// A widget that assumes mouse capture always works. It won't on Gtk/Aura in
+// testing, so we mock it.
+#if defined(TOOLKIT_USES_GTK) || defined(USE_AURA)
+class NativeWidgetCapture : public NativeWidgetPlatform {
+ public:
+ NativeWidgetCapture(internal::NativeWidgetDelegate* delegate)
+ : NativeWidgetPlatform(delegate),
+ mouse_capture_(false) {}
+ virtual ~NativeWidgetCapture() {}
+
+ virtual void SetMouseCapture() OVERRIDE {
+ mouse_capture_ = true;
+ }
+ virtual void ReleaseMouseCapture() OVERRIDE {
+ if (mouse_capture_)
+ delegate()->OnMouseCaptureLost();
+ mouse_capture_ = false;
+ }
+ virtual bool HasMouseCapture() const OVERRIDE {
+ return mouse_capture_;
+ }
+
+ private:
+ bool mouse_capture_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeWidgetCapture);
+};
+#endif
+
+// A typedef that inserts our mock-capture NativeWidget implementation for
+// relevant platforms.
+#if defined(USE_AURA)
+typedef NativeWidgetCapture NativeWidgetPlatformForTest;
+#elif defined(OS_WIN)
+typedef NativeWidgetWin NativeWidgetPlatformForTest;
+#elif defined(TOOLKIT_USES_GTK)
+typedef NativeWidgetCapture NativeWidgetPlatformForTest;
+#endif
+
+// A view that always processes all mouse events.
+class MouseView : public View {
+ public:
+ MouseView() : View() {
+ }
+ virtual ~MouseView() {}
+
+ virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE {
+ return true;
+ }
+};
+
+typedef ViewsTestBase WidgetTest;
+
+NativeWidget* CreatePlatformNativeWidget(
+ internal::NativeWidgetDelegate* delegate) {
+ return new NativeWidgetPlatformForTest(delegate);
+}
+
+Widget* CreateTopLevelPlatformWidget() {
+ Widget* toplevel = new Widget;
+ Widget::InitParams toplevel_params(Widget::InitParams::TYPE_WINDOW);
+ toplevel_params.native_widget = CreatePlatformNativeWidget(toplevel);
+ toplevel->Init(toplevel_params);
+ return toplevel;
+}
+
+Widget* CreateChildPlatformWidget(gfx::NativeView parent_native_view) {
+ Widget* child = new Widget;
+ Widget::InitParams child_params(Widget::InitParams::TYPE_CONTROL);
+ child_params.native_widget = CreatePlatformNativeWidget(child);
+ child_params.parent = parent_native_view;
+ child->Init(child_params);
+ child->SetContentsView(new View);
+ return child;
+}
+
+#if defined(OS_WIN) && !defined(USE_AURA)
+// On Windows, it is possible for us to have a child window that is TYPE_POPUP.
+Widget* CreateChildPopupPlatformWidget(gfx::NativeView parent_native_view) {
+ Widget* child = new Widget;
+ Widget::InitParams child_params(Widget::InitParams::TYPE_POPUP);
+ child_params.child = true;
+ child_params.native_widget = CreatePlatformNativeWidget(child);
+ child_params.parent = parent_native_view;
+ child->Init(child_params);
+ child->SetContentsView(new View);
+ return child;
+}
+#endif
+
+Widget* CreateTopLevelNativeWidget() {
+ Widget* toplevel = new Widget;
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
+ toplevel->Init(params);
+ toplevel->SetContentsView(new View);
+ return toplevel;
+}
+
+Widget* CreateChildNativeWidgetWithParent(Widget* parent) {
+ Widget* child = new Widget;
+ Widget::InitParams params(Widget::InitParams::TYPE_CONTROL);
+ params.parent_widget = parent;
+ child->Init(params);
+ child->SetContentsView(new View);
+ return child;
+}
+
+Widget* CreateChildNativeWidget() {
+ return CreateChildNativeWidgetWithParent(NULL);
+}
+
+bool WidgetHasMouseCapture(const Widget* widget) {
+ return static_cast<const internal::NativeWidgetPrivate*>(widget->
+ native_widget())->HasMouseCapture();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget::GetTopLevelWidget tests.
+
+TEST_F(WidgetTest, GetTopLevelWidget_Native) {
+ // Create a hierarchy of native widgets.
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+#if defined(TOOLKIT_USES_GTK)
+ NativeWidgetGtk* native_widget =
+ static_cast<NativeWidgetGtk*>(toplevel->native_widget());
+ gfx::NativeView parent = native_widget->window_contents();
+#else
+ gfx::NativeView parent = toplevel->GetNativeView();
+#endif
+ Widget* child = CreateChildPlatformWidget(parent);
+
+ EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget());
+ EXPECT_EQ(toplevel, child->GetTopLevelWidget());
+
+ toplevel->CloseNow();
+ // |child| should be automatically destroyed with |toplevel|.
+}
+
+TEST_F(WidgetTest, GetTopLevelWidget_Synthetic) {
+ // Create a hierarchy consisting of a top level platform native widget and a
+ // child NativeWidget.
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+ Widget* child = CreateTopLevelNativeWidget();
+
+ EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget());
+ EXPECT_EQ(child, child->GetTopLevelWidget());
+
+ toplevel->CloseNow();
+ // |child| should be automatically destroyed with |toplevel|.
+}
+
+// Creates a hierarchy consisting of a desktop platform native widget, a
+// toplevel NativeWidget, and a child of that toplevel, another NativeWidget.
+TEST_F(WidgetTest, GetTopLevelWidget_SyntheticDesktop) {
+ // Create a hierarchy consisting of a desktop platform native widget,
+ // a toplevel NativeWidget and a chlid NativeWidget.
+ Widget* desktop = CreateTopLevelPlatformWidget();
+ Widget* toplevel = CreateTopLevelNativeWidget(); // Will be parented
+ // automatically to
+ // |toplevel|.
+
+ Widget* child = CreateChildNativeWidgetWithParent(toplevel);
+
+ EXPECT_EQ(desktop, desktop->GetTopLevelWidget());
+ EXPECT_EQ(toplevel, toplevel->GetTopLevelWidget());
+ EXPECT_EQ(toplevel, child->GetTopLevelWidget());
+
+ desktop->CloseNow();
+ // |toplevel|, |child| should be automatically destroyed with |toplevel|.
+}
+
+// Tests some grab/ungrab events.
+TEST_F(WidgetTest, DISABLED_GrabUngrab) {
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+ Widget* child1 = CreateChildNativeWidgetWithParent(toplevel);
+ Widget* child2 = CreateChildNativeWidgetWithParent(toplevel);
+
+ toplevel->SetBounds(gfx::Rect(0, 0, 500, 500));
+
+ child1->SetBounds(gfx::Rect(10, 10, 300, 300));
+ View* view = new MouseView();
+ view->SetBounds(0, 0, 300, 300);
+ child1->GetRootView()->AddChildView(view);
+
+ child2->SetBounds(gfx::Rect(200, 10, 200, 200));
+ view = new MouseView();
+ view->SetBounds(0, 0, 200, 200);
+ child2->GetRootView()->AddChildView(view);
+
+ toplevel->Show();
+ RunPendingMessages();
+
+ // Click on child1
+ MouseEvent pressed(ui::ET_MOUSE_PRESSED, 45, 45, ui::EF_LEFT_BUTTON_DOWN);
+ toplevel->OnMouseEvent(pressed);
+
+ EXPECT_TRUE(WidgetHasMouseCapture(toplevel));
+ EXPECT_TRUE(WidgetHasMouseCapture(child1));
+ EXPECT_FALSE(WidgetHasMouseCapture(child2));
+
+ MouseEvent released(ui::ET_MOUSE_RELEASED, 45, 45, ui::EF_LEFT_BUTTON_DOWN);
+ toplevel->OnMouseEvent(released);
+
+ EXPECT_FALSE(WidgetHasMouseCapture(toplevel));
+ EXPECT_FALSE(WidgetHasMouseCapture(child1));
+ EXPECT_FALSE(WidgetHasMouseCapture(child2));
+
+ RunPendingMessages();
+
+ // Click on child2
+ MouseEvent pressed2(ui::ET_MOUSE_PRESSED, 315, 45, ui::EF_LEFT_BUTTON_DOWN);
+ EXPECT_TRUE(toplevel->OnMouseEvent(pressed2));
+ EXPECT_TRUE(WidgetHasMouseCapture(toplevel));
+ EXPECT_TRUE(WidgetHasMouseCapture(child2));
+ EXPECT_FALSE(WidgetHasMouseCapture(child1));
+
+ MouseEvent released2(ui::ET_MOUSE_RELEASED, 315, 45, ui::EF_LEFT_BUTTON_DOWN);
+ toplevel->OnMouseEvent(released2);
+ EXPECT_FALSE(WidgetHasMouseCapture(toplevel));
+ EXPECT_FALSE(WidgetHasMouseCapture(child1));
+ EXPECT_FALSE(WidgetHasMouseCapture(child2));
+
+ toplevel->CloseNow();
+}
+
+// Test if a focus manager and an inputmethod work without CHECK failure
+// when window activation changes.
+TEST_F(WidgetTest, ChangeActivation) {
+ Widget* top1 = CreateTopLevelPlatformWidget();
+ // CreateInputMethod before activated
+ top1->GetInputMethod();
+ top1->Show();
+ RunPendingMessages();
+
+ Widget* top2 = CreateTopLevelPlatformWidget();
+ top2->Show();
+ RunPendingMessages();
+
+ top1->Activate();
+ RunPendingMessages();
+
+ // Create InputMethod after deactivated.
+ top2->GetInputMethod();
+ top2->Activate();
+ RunPendingMessages();
+
+ top1->Activate();
+ RunPendingMessages();
+
+ top1->CloseNow();
+ top2->CloseNow();
+}
+
+// Tests visibility of child widgets.
+TEST_F(WidgetTest, Visibility) {
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+#if defined(TOOLKIT_USES_GTK)
+ NativeWidgetGtk* native_widget =
+ static_cast<NativeWidgetGtk*>(toplevel->native_widget());
+ gfx::NativeView parent = native_widget->window_contents();
+#else
+ gfx::NativeView parent = toplevel->GetNativeView();
+#endif
+ Widget* child = CreateChildPlatformWidget(parent);
+
+ EXPECT_FALSE(toplevel->IsVisible());
+ EXPECT_FALSE(child->IsVisible());
+
+ child->Show();
+
+ EXPECT_FALSE(toplevel->IsVisible());
+ EXPECT_FALSE(child->IsVisible());
+
+ toplevel->Show();
+
+ EXPECT_TRUE(toplevel->IsVisible());
+ EXPECT_TRUE(child->IsVisible());
+
+ toplevel->CloseNow();
+ // |child| should be automatically destroyed with |toplevel|.
+}
+
+#if defined(OS_WIN) && !defined(USE_AURA)
+// On Windows, it is possible to have child window that are TYPE_POPUP. Unlike
+// regular child windows, these should be created as hidden and must be shown
+// explicitly.
+TEST_F(WidgetTest, Visibility_ChildPopup) {
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+ Widget* child_popup = CreateChildPopupPlatformWidget(
+ toplevel->GetNativeView());
+
+ EXPECT_FALSE(toplevel->IsVisible());
+ EXPECT_FALSE(child_popup->IsVisible());
+
+ toplevel->Show();
+
+ EXPECT_TRUE(toplevel->IsVisible());
+ EXPECT_FALSE(child_popup->IsVisible());
+
+ child_popup->Show();
+
+ EXPECT_TRUE(child_popup->IsVisible());
+
+ toplevel->CloseNow();
+ // |child_popup| should be automatically destroyed with |toplevel|.
+}
+#endif
+
+// Tests visibility of synthetic child widgets.
+TEST_F(WidgetTest, Visibility_Synthetic) {
+ // Create a hierarchy consisting of a desktop platform native widget,
+ // a toplevel NativeWidget and a chlid NativeWidget.
+ Widget* desktop = CreateTopLevelPlatformWidget();
+ desktop->Show();
+
+ Widget* toplevel = CreateTopLevelNativeWidget(); // Will be parented
+ // automatically to
+ // |toplevel|.
+
+ Widget* child = CreateChildNativeWidgetWithParent(toplevel);
+
+ EXPECT_FALSE(toplevel->IsVisible());
+ EXPECT_FALSE(child->IsVisible());
+
+ child->Show();
+
+ EXPECT_FALSE(toplevel->IsVisible());
+ EXPECT_FALSE(child->IsVisible());
+
+ toplevel->Show();
+
+ EXPECT_TRUE(toplevel->IsVisible());
+ EXPECT_TRUE(child->IsVisible());
+
+ desktop->CloseNow();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget ownership tests.
+//
+// Tests various permutations of Widget ownership specified in the
+// InitParams::Ownership param.
+
+// A WidgetTest that supplies a toplevel widget for NativeWidget to parent to.
+class WidgetOwnershipTest : public WidgetTest {
+ public:
+ WidgetOwnershipTest() {}
+ virtual ~WidgetOwnershipTest() {}
+
+ virtual void SetUp() {
+ WidgetTest::SetUp();
+ desktop_widget_ = CreateTopLevelPlatformWidget();
+ }
+
+ virtual void TearDown() {
+ desktop_widget_->CloseNow();
+ WidgetTest::TearDown();
+ }
+
+ private:
+ Widget* desktop_widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(WidgetOwnershipTest);
+};
+
+// A bag of state to monitor destructions.
+struct OwnershipTestState {
+ OwnershipTestState() : widget_deleted(false), native_widget_deleted(false) {}
+
+ bool widget_deleted;
+ bool native_widget_deleted;
+};
+
+// A platform NativeWidget subclass that updates a bag of state when it is
+// destroyed.
+class OwnershipTestNativeWidget : public NativeWidgetPlatform {
+ public:
+ OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
+ OwnershipTestState* state)
+ : NativeWidgetPlatform(delegate),
+ state_(state) {
+ }
+ virtual ~OwnershipTestNativeWidget() {
+ state_->native_widget_deleted = true;
+ }
+
+ private:
+ OwnershipTestState* state_;
+
+ DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidget);
+};
+
+// A views NativeWidget subclass that updates a bag of state when it is
+// destroyed.
+class OwnershipTestNativeWidgetPlatform : public NativeWidgetPlatformForTest {
+ public:
+ OwnershipTestNativeWidgetPlatform(internal::NativeWidgetDelegate* delegate,
+ OwnershipTestState* state)
+ : NativeWidgetPlatformForTest(delegate),
+ state_(state) {
+ }
+ virtual ~OwnershipTestNativeWidgetPlatform() {
+ state_->native_widget_deleted = true;
+ }
+
+ private:
+ OwnershipTestState* state_;
+
+ DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetPlatform);
+};
+
+// A Widget subclass that updates a bag of state when it is destroyed.
+class OwnershipTestWidget : public Widget {
+ public:
+ OwnershipTestWidget(OwnershipTestState* state) : state_(state) {}
+ virtual ~OwnershipTestWidget() {
+ state_->widget_deleted = true;
+ }
+
+ private:
+ OwnershipTestState* state_;
+
+ DISALLOW_COPY_AND_ASSIGN(OwnershipTestWidget);
+};
+
+// Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
+// widget.
+TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) {
+ OwnershipTestState state;
+
+ scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.native_widget =
+ new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget->Init(params);
+
+ // Now delete the Widget, which should delete the NativeWidget.
+ widget.reset();
+
+ EXPECT_TRUE(state.widget_deleted);
+ EXPECT_TRUE(state.native_widget_deleted);
+
+ // TODO(beng): write test for this ownership scenario and the NativeWidget
+ // being deleted out from under the Widget.
+}
+
+// Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
+TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) {
+ OwnershipTestState state;
+
+ scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.native_widget =
+ new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget->Init(params);
+
+ // Now delete the Widget, which should delete the NativeWidget.
+ widget.reset();
+
+ EXPECT_TRUE(state.widget_deleted);
+ EXPECT_TRUE(state.native_widget_deleted);
+
+ // TODO(beng): write test for this ownership scenario and the NativeWidget
+ // being deleted out from under the Widget.
+}
+
+// Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
+// destroy the parent view.
+TEST_F(WidgetOwnershipTest,
+ Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView) {
+ OwnershipTestState state;
+
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+
+ scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.native_widget =
+ new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
+ params.parent_widget = toplevel;
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget->Init(params);
+
+ // Now close the toplevel, which deletes the view hierarchy.
+ toplevel->CloseNow();
+
+ RunPendingMessages();
+
+ // This shouldn't delete the widget because it shouldn't be deleted
+ // from the native side.
+ EXPECT_FALSE(state.widget_deleted);
+ EXPECT_FALSE(state.native_widget_deleted);
+
+ // Now delete it explicitly.
+ widget.reset();
+
+ EXPECT_TRUE(state.widget_deleted);
+ EXPECT_TRUE(state.native_widget_deleted);
+}
+
+// NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
+// widget.
+TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) {
+ OwnershipTestState state;
+
+ Widget* widget = new OwnershipTestWidget(&state);
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.native_widget =
+ new OwnershipTestNativeWidgetPlatform(widget, &state);
+ widget->Init(params);
+
+ // Now destroy the native widget.
+ widget->CloseNow();
+
+ EXPECT_TRUE(state.widget_deleted);
+ EXPECT_TRUE(state.native_widget_deleted);
+}
+
+// NativeWidget owns its Widget, part 2: NativeWidget is a NativeWidget.
+#if defined(OS_CHROMEOS) && defined(TOOLKIT_USES_GTK)
+// Temporarily disable the test (http://crbug.com/104945).
+TEST_F(WidgetOwnershipTest, DISABLED_Ownership_ViewsNativeWidgetOwnsWidget) {
+#else
+TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) {
+#endif
+ OwnershipTestState state;
+
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+
+ Widget* widget = new OwnershipTestWidget(&state);
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.native_widget =
+ new OwnershipTestNativeWidgetPlatform(widget, &state);
+ params.parent_widget = toplevel;
+ widget->Init(params);
+
+ // Now destroy the native widget. This is achieved by closing the toplevel.
+ toplevel->CloseNow();
+
+ // The NativeWidget won't be deleted until after a return to the message loop
+ // so we have to run pending messages before testing the destruction status.
+ RunPendingMessages();
+
+ EXPECT_TRUE(state.widget_deleted);
+ EXPECT_TRUE(state.native_widget_deleted);
+}
+
+// NativeWidget owns its Widget, part 3: NativeWidget is a platform-native
+// widget, destroyed out from under it by the OS.
+TEST_F(WidgetOwnershipTest,
+ Ownership_PlatformNativeWidgetOwnsWidget_NativeDestroy) {
+ OwnershipTestState state;
+
+ Widget* widget = new OwnershipTestWidget(&state);
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.native_widget =
+ new OwnershipTestNativeWidgetPlatform(widget, &state);
+ widget->Init(params);
+
+ // Now simulate a destroy of the platform native widget from the OS:
+#if defined(USE_AURA)
+ delete widget->GetNativeView();
+#elif defined(OS_WIN)
+ DestroyWindow(widget->GetNativeView());
+#elif defined(TOOLKIT_USES_GTK)
+ gtk_widget_destroy(widget->GetNativeView());
+#endif
+
+ EXPECT_TRUE(state.widget_deleted);
+ EXPECT_TRUE(state.native_widget_deleted);
+}
+
+// NativeWidget owns its Widget, part 4: NativeWidget is a NativeWidget,
+// destroyed by the view hierarchy that contains it.
+#if defined(OS_CHROMEOS) && defined(TOOLKIT_USES_GTK)
+// Temporarily disable the test (http://crbug.com/104945).
+TEST_F(WidgetOwnershipTest,
+ DISABLED_Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) {
+#else
+TEST_F(WidgetOwnershipTest,
+ Ownership_ViewsNativeWidgetOwnsWidget_NativeDestroy) {
+#endif
+ OwnershipTestState state;
+
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+
+ Widget* widget = new OwnershipTestWidget(&state);
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.native_widget =
+ new OwnershipTestNativeWidgetPlatform(widget, &state);
+ params.parent_widget = toplevel;
+ widget->Init(params);
+
+ // Destroy the widget (achieved by closing the toplevel).
+ toplevel->CloseNow();
+
+ // The NativeWidget won't be deleted until after a return to the message loop
+ // so we have to run pending messages before testing the destruction status.
+ RunPendingMessages();
+
+ EXPECT_TRUE(state.widget_deleted);
+ EXPECT_TRUE(state.native_widget_deleted);
+}
+
+// NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget,
+// we close it directly.
+TEST_F(WidgetOwnershipTest,
+ Ownership_ViewsNativeWidgetOwnsWidget_Close) {
+ OwnershipTestState state;
+
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+
+ Widget* widget = new OwnershipTestWidget(&state);
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.native_widget =
+ new OwnershipTestNativeWidgetPlatform(widget, &state);
+ params.parent_widget = toplevel;
+ widget->Init(params);
+
+ // Destroy the widget.
+ widget->Close();
+ toplevel->CloseNow();
+
+ // The NativeWidget won't be deleted until after a return to the message loop
+ // so we have to run pending messages before testing the destruction status.
+ RunPendingMessages();
+
+ EXPECT_TRUE(state.widget_deleted);
+ EXPECT_TRUE(state.native_widget_deleted);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget observer tests.
+//
+
+class WidgetObserverTest : public WidgetTest,
+ Widget::Observer {
+ public:
+ WidgetObserverTest()
+ : active_(NULL),
+ widget_closed_(NULL),
+ widget_activated_(NULL),
+ widget_shown_(NULL),
+ widget_hidden_(NULL) {
+ }
+
+ virtual ~WidgetObserverTest() {}
+
+ virtual void OnWidgetClosing(Widget* widget) OVERRIDE {
+ if (active_ == widget)
+ active_ = NULL;
+ widget_closed_ = widget;
+ }
+
+ virtual void OnWidgetActivationChanged(Widget* widget,
+ bool active) OVERRIDE {
+ if (active) {
+ if (widget_activated_)
+ widget_activated_->Deactivate();
+ widget_activated_ = widget;
+ active_ = widget;
+ } else {
+ if (widget_activated_ == widget)
+ widget_activated_ = NULL;
+ widget_deactivated_ = widget;
+ }
+ }
+
+ virtual void OnWidgetVisibilityChanged(Widget* widget,
+ bool visible) OVERRIDE {
+ if (visible)
+ widget_shown_ = widget;
+ else
+ widget_hidden_ = widget;
+ }
+
+ void reset() {
+ active_ = NULL;
+ widget_closed_ = NULL;
+ widget_activated_ = NULL;
+ widget_deactivated_ = NULL;
+ widget_shown_ = NULL;
+ widget_hidden_ = NULL;
+ }
+
+ Widget* NewWidget() {
+ Widget* widget = CreateTopLevelNativeWidget();
+ widget->AddObserver(this);
+ return widget;
+ }
+
+ const Widget* active() const { return active_; }
+ const Widget* widget_closed() const { return widget_closed_; }
+ const Widget* widget_activated() const { return widget_activated_; }
+ const Widget* widget_deactivated() const { return widget_deactivated_; }
+ const Widget* widget_shown() const { return widget_shown_; }
+ const Widget* widget_hidden() const { return widget_hidden_; }
+
+ private:
+
+ Widget* active_;
+
+ Widget* widget_closed_;
+ Widget* widget_activated_;
+ Widget* widget_deactivated_;
+ Widget* widget_shown_;
+ Widget* widget_hidden_;
+};
+
+TEST_F(WidgetObserverTest, DISABLED_ActivationChange) {
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+
+ Widget* toplevel1 = NewWidget();
+ Widget* toplevel2 = NewWidget();
+
+ toplevel1->Show();
+ toplevel2->Show();
+
+ reset();
+
+ toplevel1->Activate();
+
+ RunPendingMessages();
+ EXPECT_EQ(toplevel1, widget_activated());
+
+ toplevel2->Activate();
+ RunPendingMessages();
+ EXPECT_EQ(toplevel1, widget_deactivated());
+ EXPECT_EQ(toplevel2, widget_activated());
+ EXPECT_EQ(toplevel2, active());
+
+ toplevel->CloseNow();
+}
+
+TEST_F(WidgetObserverTest, DISABLED_VisibilityChange) {
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+
+ Widget* child1 = NewWidget();
+ Widget* child2 = NewWidget();
+
+ toplevel->Show();
+ child1->Show();
+ child2->Show();
+
+ reset();
+
+ child1->Hide();
+ EXPECT_EQ(child1, widget_hidden());
+
+ child2->Hide();
+ EXPECT_EQ(child2, widget_hidden());
+
+ child1->Show();
+ EXPECT_EQ(child1, widget_shown());
+
+ child2->Show();
+ EXPECT_EQ(child2, widget_shown());
+
+ toplevel->CloseNow();
+}
+
+#if !defined(USE_AURA) && defined(OS_WIN)
+// Aura needs shell to maximize/fullscreen window.
+// NativeWidgetGtk doesn't implement GetRestoredBounds.
+TEST_F(WidgetTest, GetRestoredBounds) {
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+ EXPECT_EQ(toplevel->GetWindowScreenBounds().ToString(),
+ toplevel->GetRestoredBounds().ToString());
+ toplevel->Show();
+ toplevel->Maximize();
+ RunPendingMessages();
+ EXPECT_NE(toplevel->GetWindowScreenBounds().ToString(),
+ toplevel->GetRestoredBounds().ToString());
+ EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
+ EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
+
+ toplevel->Restore();
+ RunPendingMessages();
+ EXPECT_EQ(toplevel->GetWindowScreenBounds().ToString(),
+ toplevel->GetRestoredBounds().ToString());
+
+ toplevel->SetFullscreen(true);
+ RunPendingMessages();
+ EXPECT_NE(toplevel->GetWindowScreenBounds().ToString(),
+ toplevel->GetRestoredBounds().ToString());
+ EXPECT_GT(toplevel->GetRestoredBounds().width(), 0);
+ EXPECT_GT(toplevel->GetRestoredBounds().height(), 0);
+}
+#endif
+
+} // namespace
+} // namespace views