Index: views/widget/widget_unittest.cc |
diff --git a/views/widget/widget_unittest.cc b/views/widget/widget_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..580bed8524eef4cbcbef4be5f45cd28cc8078ca1 |
--- /dev/null |
+++ b/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/views/test/test_views_delegate.h" |
+#include "ui/views/test/views_test_base.h" |
+#include "ui/gfx/point.h" |
+#include "ui/gfx/native_widget_types.h" |
+#include "views/views_delegate.h" |
+#include "views/widget/native_widget_delegate.h" |
+ |
+#if defined(USE_AURA) |
+#include "ui/aura/window.h" |
+#include "views/widget/native_widget_aura.h" |
+#elif defined(OS_WIN) |
+#include "views/widget/native_widget_win.h" |
+#elif defined(TOOLKIT_USES_GTK) |
+#include "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 |