| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/views/widget/native_widget_aura.h" |
| |
| #include <memory> |
| #include <set> |
| #include <utility> |
| |
| #include "base/command_line.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/run_loop.h" |
| #include "base/scoped_observation.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/uuid.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/aura/client/aura_constants.h" |
| #include "ui/aura/env.h" |
| #include "ui/aura/layout_manager.h" |
| #include "ui/aura/test/aura_test_helper.h" |
| #include "ui/aura/window.h" |
| #include "ui/aura/window_observer.h" |
| #include "ui/aura/window_tree_host.h" |
| #include "ui/base/metadata/metadata_header_macros.h" |
| #include "ui/base/metadata/metadata_impl_macros.h" |
| #include "ui/base/mojom/ui_base_types.mojom-shared.h" |
| #include "ui/base/mojom/window_show_state.mojom.h" |
| #include "ui/compositor/layer.h" |
| #include "ui/compositor/layer_animator.h" |
| #include "ui/events/event.h" |
| #include "ui/events/event_utils.h" |
| #include "ui/events/test/event_generator.h" |
| #include "ui/views/layout/fill_layout.h" |
| #include "ui/views/test/views_test_base.h" |
| #include "ui/views/test/widget_test.h" |
| #include "ui/views/widget/root_view.h" |
| #include "ui/views/widget/unique_widget_ptr.h" |
| #include "ui/views/widget/widget_delegate.h" |
| #include "ui/wm/core/base_focus_rules.h" |
| #include "ui/wm/core/default_activation_client.h" |
| #include "ui/wm/core/focus_controller.h" |
| #include "ui/wm/core/transient_window_manager.h" |
| #include "ui/wm/core/window_util.h" |
| |
| namespace views { |
| namespace { |
| |
| NativeWidgetAura* Init(aura::Window* parent, Widget* widget) { |
| Widget::InitParams params(Widget::InitParams::Ownership::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_POPUP); |
| params.parent = parent; |
| widget->Init(std::move(params)); |
| return static_cast<NativeWidgetAura*>(widget->native_widget()); |
| } |
| |
| // TestFocusRules is intended to provide a way to manually set a window's |
| // activatability so that the focus rules can be tested. |
| class TestFocusRules : public wm::BaseFocusRules { |
| public: |
| TestFocusRules() = default; |
| |
| TestFocusRules(const TestFocusRules&) = delete; |
| TestFocusRules& operator=(const TestFocusRules&) = delete; |
| |
| ~TestFocusRules() override = default; |
| |
| void set_can_activate(bool can_activate) { can_activate_ = can_activate; } |
| |
| // wm::BaseFocusRules overrides: |
| bool SupportsChildActivation(const aura::Window* window) const override { |
| return true; |
| } |
| |
| bool CanActivateWindow(const aura::Window* window) const override { |
| return can_activate_ && (!window || window->IsVisible()); |
| } |
| |
| private: |
| bool can_activate_ = true; |
| }; |
| |
| } // namespace |
| |
| class NativeWidgetAuraTest : public ViewsTestBase { |
| public: |
| NativeWidgetAuraTest() = default; |
| |
| NativeWidgetAuraTest(const NativeWidgetAuraTest&) = delete; |
| NativeWidgetAuraTest& operator=(const NativeWidgetAuraTest&) = delete; |
| |
| ~NativeWidgetAuraTest() override = default; |
| |
| TestFocusRules* test_focus_rules() { return test_focus_rules_; } |
| |
| // testing::Test overrides: |
| void SetUp() override { |
| ViewsTestBase::SetUp(); |
| test_focus_rules_ = new TestFocusRules; |
| focus_controller_ = |
| std::make_unique<wm::FocusController>(test_focus_rules_); |
| wm::SetActivationClient(root_window(), focus_controller_.get()); |
| host()->SetBoundsInPixels(gfx::Rect(640, 480)); |
| } |
| |
| private: |
| std::unique_ptr<wm::FocusController> focus_controller_; |
| raw_ptr<TestFocusRules> test_focus_rules_; |
| }; |
| |
| TEST_F(NativeWidgetAuraTest, CenterWindowLargeParent) { |
| // Make a parent window larger than the host represented by |
| // WindowEventDispatcher. |
| auto parent = std::make_unique<aura::Window>(nullptr); |
| parent->Init(ui::LAYER_NOT_DRAWN); |
| parent->SetBounds(gfx::Rect(0, 0, 1024, 800)); |
| auto widget = std::make_unique<Widget>(); |
| NativeWidgetAura* window = Init(parent.get(), widget.get()); |
| |
| window->CenterWindow(gfx::Size(100, 100)); |
| EXPECT_EQ(gfx::Rect((640 - 100) / 2, (480 - 100) / 2, 100, 100), |
| window->GetNativeWindow()->bounds()); |
| } |
| |
| TEST_F(NativeWidgetAuraTest, CenterWindowSmallParent) { |
| // Make a parent window smaller than the host represented by |
| // WindowEventDispatcher. |
| auto parent = std::make_unique<aura::Window>(nullptr); |
| parent->Init(ui::LAYER_NOT_DRAWN); |
| parent->SetBounds(gfx::Rect(0, 0, 480, 320)); |
| auto widget = std::make_unique<Widget>(); |
| NativeWidgetAura* window = Init(parent.get(), widget.get()); |
| |
| window->CenterWindow(gfx::Size(100, 100)); |
| EXPECT_EQ(gfx::Rect((480 - 100) / 2, (320 - 100) / 2, 100, 100), |
| window->GetNativeWindow()->bounds()); |
| } |
| |
| // Verifies CenterWindow() constrains to parent size. |
| TEST_F(NativeWidgetAuraTest, CenterWindowSmallParentNotAtOrigin) { |
| // Make a parent window smaller than the host represented by |
| // WindowEventDispatcher and offset it slightly from the origin. |
| auto parent = std::make_unique<aura::Window>(nullptr); |
| parent->Init(ui::LAYER_NOT_DRAWN); |
| parent->SetBounds(gfx::Rect(20, 40, 480, 320)); |
| auto widget = std::make_unique<Widget>(); |
| NativeWidgetAura* window = Init(parent.get(), widget.get()); |
| window->CenterWindow(gfx::Size(500, 600)); |
| |
| // |window| should be no bigger than |parent|. |
| EXPECT_EQ("20,40 480x320", window->GetNativeWindow()->bounds().ToString()); |
| } |
| |
| // Verifies CenterWindow() honors the transient parent unless it's bigger than |
| // the transient parent. |
| TEST_F(NativeWidgetAuraTest, CenterTransientWindow) { |
| aura::Window* root = aura::test::AuraTestHelper::GetInstance()->GetContext(); |
| // Ensure that the root window size is larger than windows created in this |
| // test. |
| ASSERT_GT(root->bounds().width(), 600); |
| ASSERT_GT(root->bounds().height(), 400); |
| |
| // Make a parent window smaller than the host represented by |
| // WindowEventDispatcher and offset it slightly from the origin. |
| auto parent = std::make_unique<aura::Window>(nullptr); |
| parent->SetType(aura::client::WINDOW_TYPE_NORMAL); |
| parent->Init(ui::LAYER_NOT_DRAWN); |
| |
| gfx::Rect parent_bounds(root->bounds().width() - 450, 50, 400, 300); |
| parent->SetBounds(parent_bounds); |
| |
| root->AddChild(parent.get()); |
| |
| auto create_widget = |
| [&](views::WidgetDelegate* delegate, |
| const gfx::Size& preferred_size) -> std::unique_ptr<views::Widget> { |
| Widget::InitParams params(Widget::InitParams::Ownership::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW_FRAMELESS); |
| params.delegate = delegate; |
| params.delegate->SetContentsView(std::make_unique<views::View>()) |
| ->SetPreferredSize(preferred_size); |
| params.parent = parent.get(); |
| auto widget = std::make_unique<Widget>(); |
| widget->Init(std::move(params)); |
| return widget; |
| }; |
| |
| { |
| SCOPED_TRACE("small fits parent"); |
| constexpr gfx::Size kTransientSize(300, 200); |
| auto delegate_owned = std::make_unique<WidgetDelegate>(); |
| auto widget = create_widget(delegate_owned.get(), kTransientSize); |
| |
| ASSERT_EQ(parent.get(), wm::GetTransientParent(widget->GetNativeWindow())); |
| EXPECT_EQ(kTransientSize, widget->GetWindowBoundsInScreen().size()); |
| EXPECT_EQ(parent_bounds.CenterPoint(), |
| widget->GetWindowBoundsInScreen().CenterPoint()); |
| } |
| { |
| SCOPED_TRACE("larger centers root"); |
| constexpr gfx::Size kTransientSize(500, 400); |
| auto delegate_owned = std::make_unique<WidgetDelegate>(); |
| auto widget = create_widget(delegate_owned.get(), kTransientSize); |
| |
| ASSERT_EQ(parent.get(), wm::GetTransientParent(widget->GetNativeWindow())); |
| EXPECT_EQ(kTransientSize, widget->GetWindowBoundsInScreen().size()); |
| EXPECT_EQ(root->bounds().CenterPoint(), |
| widget->GetWindowBoundsInScreen().CenterPoint()); |
| } |
| { |
| SCOPED_TRACE("widget centers parent but fit to the root"); |
| constexpr gfx::Size kTransientSize(500, 200); |
| auto delegate_owned = std::make_unique<WidgetDelegate>(); |
| auto widget = create_widget(delegate_owned.get(), kTransientSize); |
| |
| ASSERT_EQ(parent.get(), wm::GetTransientParent(widget->GetNativeWindow())); |
| EXPECT_EQ(kTransientSize, widget->GetWindowBoundsInScreen().size()); |
| // The transient window should be within the root but it's center should |
| // be closest to the center of the parent. In this case, the transient |
| // window's right side should be attached to the root's left, but y is |
| // centered. |
| gfx::Rect expected( |
| {root->bounds().width() - kTransientSize.width(), |
| parent_bounds.CenterPoint().y() - kTransientSize.height() / 2}, |
| kTransientSize); |
| |
| EXPECT_EQ(expected, widget->GetWindowBoundsInScreen()); |
| } |
| } |
| |
| // View which handles both mouse and gesture events. |
| class EventHandlingView : public View { |
| METADATA_HEADER(EventHandlingView, View) |
| |
| public: |
| EventHandlingView() = default; |
| EventHandlingView(const EventHandlingView&) = delete; |
| EventHandlingView& operator=(const EventHandlingView&) = delete; |
| ~EventHandlingView() override = default; |
| |
| // Returns whether an event specified by `type_to_query` has been handled. |
| bool HandledEventBefore(ui::EventType type_to_query) const { |
| return handled_gestures_set_.find(type_to_query) != |
| handled_gestures_set_.cend(); |
| } |
| |
| // View: |
| void OnMouseEvent(ui::MouseEvent* event) override { event->SetHandled(); } |
| void OnGestureEvent(ui::GestureEvent* event) override { |
| // Record the handled gesture event. |
| const ui::EventType event_type = event->type(); |
| if (handled_gestures_set_.find(event_type) == |
| handled_gestures_set_.cend()) { |
| EXPECT_TRUE(handled_gestures_set_.insert(event->type()).second); |
| } else { |
| // Only EventType::kGestureScrollUpdate events can be received more than |
| // once. |
| EXPECT_EQ(ui::EventType::kGestureScrollUpdate, event->type()); |
| } |
| |
| event->SetHandled(); |
| } |
| |
| private: |
| std::set<ui::EventType> handled_gestures_set_; |
| }; |
| |
| BEGIN_METADATA(EventHandlingView) |
| END_METADATA |
| |
| // Verifies that when the mouse click interrupts the gesture scroll, the view |
| // where the gesture scroll starts should receive the scroll end event. |
| TEST_F(NativeWidgetAuraTest, MouseClickInterruptsGestureScroll) { |
| Widget::InitParams init_params = |
| CreateParams(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW_FRAMELESS); |
| init_params.bounds = gfx::Rect(100, 100); |
| auto widget = std::make_unique<Widget>(); |
| widget->Init(std::move(init_params)); |
| widget->Show(); |
| |
| auto* contents_view = widget->SetContentsView(std::make_unique<View>()); |
| auto* child_view = |
| contents_view->AddChildView(std::make_unique<EventHandlingView>()); |
| child_view->SetBoundsRect(gfx::Rect(gfx::Size{50, 50})); |
| |
| auto scroll_callback = [](ui::test::EventGenerator* event_generator, |
| int* step_count, ui::EventType event_type, |
| const gfx::Vector2dF& offset) { |
| if (event_type != ui::EventType::kGestureScrollUpdate) { |
| return; |
| } |
| |
| *step_count -= 1; |
| if (*step_count) { |
| return; |
| } |
| |
| // Do not interrupt the gesture scroll until the last gesture update event |
| // is handled. |
| |
| DCHECK_EQ(0, *step_count); |
| event_generator->MoveMouseTo(event_generator->current_screen_location()); |
| event_generator->ClickLeftButton(); |
| }; |
| |
| const gfx::Point center_point = child_view->GetBoundsInScreen().CenterPoint(); |
| gfx::Point target_point = center_point; |
| target_point.Offset(0, 20); |
| int step_count = 10; |
| ui::test::EventGenerator generator(widget->GetNativeView()->GetRootWindow()); |
| generator.GestureScrollSequenceWithCallback( |
| center_point, target_point, |
| /*duration=*/base::Milliseconds(100), step_count, |
| base::BindRepeating(scroll_callback, &generator, &step_count)); |
| |
| // Verify that `child_view` receives gesture end events. |
| EXPECT_TRUE(child_view->HandledEventBefore(ui::EventType::kGestureScrollEnd)); |
| EXPECT_TRUE(child_view->HandledEventBefore(ui::EventType::kGestureEnd)); |
| } |
| |
| TEST_F(NativeWidgetAuraTest, CreateMinimized) { |
| Widget::InitParams params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW); |
| params.parent = nullptr; |
| params.context = root_window(); |
| params.show_state = ui::mojom::WindowShowState::kMinimized; |
| params.bounds.SetRect(0, 0, 1024, 800); |
| auto widget = std::make_unique<Widget>(); |
| widget->Init(std::move(params)); |
| widget->Show(); |
| |
| EXPECT_TRUE(widget->IsMinimized()); |
| } |
| |
| // Tests that GetRestoreBounds returns the window bounds even if the window is |
| // transformed. |
| TEST_F(NativeWidgetAuraTest, RestoreBounds) { |
| Widget::InitParams params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW); |
| params.parent = nullptr; |
| params.context = root_window(); |
| params.bounds.SetRect(0, 0, 400, 400); |
| auto widget = std::make_unique<Widget>(); |
| widget->Init(std::move(params)); |
| widget->Show(); |
| EXPECT_EQ(gfx::Rect(400, 400), widget->GetRestoredBounds()); |
| |
| gfx::Transform transform; |
| transform.Translate(100.f, 100.f); |
| widget->GetNativeWindow()->SetTransform(transform); |
| EXPECT_EQ(gfx::Rect(400, 400), widget->GetRestoredBounds()); |
| } |
| |
| TEST_F(NativeWidgetAuraTest, GetWorkspace) { |
| Widget::InitParams params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW); |
| params.parent = nullptr; |
| params.context = root_window(); |
| params.show_state = ui::mojom::WindowShowState::kMinimized; |
| params.bounds.SetRect(0, 0, 1024, 800); |
| auto widget = std::make_unique<Widget>(); |
| widget->Init(std::move(params)); |
| widget->Show(); |
| |
| widget->GetNativeWindow()->SetProperty( |
| aura::client::kWindowWorkspaceKey, |
| aura::client::kWindowWorkspaceUnassignedWorkspace); |
| EXPECT_EQ("", widget->GetWorkspace()); |
| |
| widget->GetNativeWindow()->SetProperty( |
| aura::client::kWindowWorkspaceKey, |
| aura::client::kWindowWorkspaceVisibleOnAllWorkspaces); |
| EXPECT_EQ("", widget->GetWorkspace()); |
| |
| const int desk_index = 1; |
| widget->GetNativeWindow()->SetProperty(aura::client::kWindowWorkspaceKey, |
| desk_index); |
| EXPECT_EQ(base::NumberToString(desk_index), widget->GetWorkspace()); |
| } |
| |
| // A WindowObserver that counts kShowStateKey property changes. |
| class TestWindowObserver : public aura::WindowObserver { |
| public: |
| explicit TestWindowObserver(gfx::NativeWindow window) { |
| window_observation_.Observe(window); |
| } |
| |
| TestWindowObserver(const TestWindowObserver&) = delete; |
| TestWindowObserver& operator=(const TestWindowObserver&) = delete; |
| |
| ~TestWindowObserver() override = default; |
| |
| // aura::WindowObserver: |
| void OnWindowPropertyChanged(aura::Window* window, |
| const void* key, |
| intptr_t old) override { |
| if (key != aura::client::kShowStateKey) { |
| return; |
| } |
| count_++; |
| state_ = window_observation_.GetSource()->GetProperty( |
| aura::client::kShowStateKey); |
| } |
| |
| int count() const { return count_; } |
| ui::mojom::WindowShowState state() const { return state_; } |
| void Reset() { count_ = 0; } |
| |
| private: |
| base::ScopedObservation<aura::Window, aura::WindowObserver> |
| window_observation_{this}; |
| int count_ = 0; |
| ui::mojom::WindowShowState state_ = ui::mojom::WindowShowState::kDefault; |
| }; |
| |
| // Tests that window transitions from normal to minimized and back do not |
| // involve extra show state transitions. |
| TEST_F(NativeWidgetAuraTest, ToggleState) { |
| Widget::InitParams params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW); |
| params.parent = nullptr; |
| params.context = root_window(); |
| params.show_state = ui::mojom::WindowShowState::kNormal; |
| params.bounds.SetRect(0, 0, 1024, 800); |
| auto widget = std::make_unique<Widget>(); |
| widget->Init(std::move(params)); |
| auto observer = |
| std::make_unique<TestWindowObserver>(widget->GetNativeWindow()); |
| widget->Show(); |
| EXPECT_FALSE(widget->IsMinimized()); |
| EXPECT_EQ(0, observer->count()); |
| EXPECT_EQ(ui::mojom::WindowShowState::kDefault, observer->state()); |
| |
| widget->Minimize(); |
| EXPECT_TRUE(widget->IsMinimized()); |
| EXPECT_EQ(1, observer->count()); |
| EXPECT_EQ(ui::mojom::WindowShowState::kMinimized, observer->state()); |
| observer->Reset(); |
| |
| widget->Show(); |
| widget->Restore(); |
| EXPECT_EQ(1, observer->count()); |
| EXPECT_EQ(ui::mojom::WindowShowState::kNormal, observer->state()); |
| |
| observer.reset(); |
| EXPECT_FALSE(widget->IsMinimized()); |
| } |
| |
| class TestLayoutManagerBase : public aura::LayoutManager { |
| public: |
| TestLayoutManagerBase() = default; |
| |
| TestLayoutManagerBase(const TestLayoutManagerBase&) = delete; |
| TestLayoutManagerBase& operator=(const TestLayoutManagerBase&) = delete; |
| |
| ~TestLayoutManagerBase() override = default; |
| |
| // aura::LayoutManager: |
| void OnWindowResized() override {} |
| void OnWindowAddedToLayout(aura::Window* child) override {} |
| void OnWillRemoveWindowFromLayout(aura::Window* child) override {} |
| void OnWindowRemovedFromLayout(aura::Window* child) override {} |
| void OnChildWindowVisibilityChanged(aura::Window* child, |
| bool visible) override {} |
| void SetChildBounds(aura::Window* child, |
| const gfx::Rect& requested_bounds) override {} |
| }; |
| |
| // Used by ShowMaximizedDoesntBounceAround. See it for details. |
| class MaximizeLayoutManager : public TestLayoutManagerBase { |
| public: |
| MaximizeLayoutManager() = default; |
| |
| MaximizeLayoutManager(const MaximizeLayoutManager&) = delete; |
| MaximizeLayoutManager& operator=(const MaximizeLayoutManager&) = delete; |
| |
| ~MaximizeLayoutManager() override = default; |
| |
| private: |
| // aura::LayoutManager: |
| void OnWindowAddedToLayout(aura::Window* child) override { |
| // This simulates what happens when adding a maximized window. |
| SetChildBoundsDirect(child, gfx::Rect(0, 0, 300, 300)); |
| } |
| }; |
| |
| // This simulates BrowserView, which creates a custom RootView so that |
| // OnNativeWidgetSizeChanged that is invoked during Init matters. |
| class TestWidget : public Widget { |
| public: |
| TestWidget() = default; |
| |
| TestWidget(const TestWidget&) = delete; |
| TestWidget& operator=(const TestWidget&) = delete; |
| |
| // Returns true if the size changes to a non-empty size, and then to another |
| // size. |
| bool did_size_change_more_than_once() const { |
| return did_size_change_more_than_once_; |
| } |
| |
| void OnNativeWidgetSizeChanged(const gfx::Size& new_size) override { |
| if (last_size_.IsEmpty()) { |
| last_size_ = new_size; |
| } else if (!did_size_change_more_than_once_ && new_size != last_size_) { |
| did_size_change_more_than_once_ = true; |
| } |
| Widget::OnNativeWidgetSizeChanged(new_size); |
| } |
| |
| private: |
| bool did_size_change_more_than_once_ = false; |
| gfx::Size last_size_; |
| }; |
| |
| // Verifies the size of the widget doesn't change more than once during Init if |
| // the window ends up maximized. This is important as otherwise |
| // RenderWidgetHostViewAura ends up getting resized during construction, which |
| // leads to noticeable flashes. |
| TEST_F(NativeWidgetAuraTest, ShowMaximizedDoesntBounceAround) { |
| root_window()->SetBounds(gfx::Rect(0, 0, 640, 480)); |
| root_window()->SetLayoutManager(std::make_unique<MaximizeLayoutManager>()); |
| auto widget = std::make_unique<TestWidget>(); |
| Widget::InitParams params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW); |
| params.parent = nullptr; |
| params.context = root_window(); |
| params.show_state = ui::mojom::WindowShowState::kMaximized; |
| params.bounds = gfx::Rect(10, 10, 100, 200); |
| widget->Init(std::move(params)); |
| EXPECT_FALSE( |
| static_cast<TestWidget*>(widget.get())->did_size_change_more_than_once()); |
| } |
| |
| class PropertyTestLayoutManager : public TestLayoutManagerBase { |
| public: |
| PropertyTestLayoutManager() = default; |
| |
| PropertyTestLayoutManager(const PropertyTestLayoutManager&) = delete; |
| PropertyTestLayoutManager& operator=(const PropertyTestLayoutManager&) = |
| delete; |
| |
| ~PropertyTestLayoutManager() override = default; |
| |
| bool added() const { return added_; } |
| |
| private: |
| // aura::LayoutManager: |
| void OnWindowAddedToLayout(aura::Window* child) override { |
| EXPECT_EQ(aura::client::kResizeBehaviorCanResize | |
| aura::client::kResizeBehaviorCanMaximize | |
| aura::client::kResizeBehaviorCanMinimize | |
| aura::client::kResizeBehaviorCanFullscreen, |
| child->GetProperty(aura::client::kResizeBehaviorKey)); |
| added_ = true; |
| } |
| |
| bool added_ = false; |
| }; |
| |
| // Verifies the resize behavior when added to the layout manager. |
| TEST_F(NativeWidgetAuraTest, TestPropertiesWhenAddedToLayout) { |
| root_window()->SetBounds(gfx::Rect(0, 0, 640, 480)); |
| PropertyTestLayoutManager* layout_manager = root_window()->SetLayoutManager( |
| std::make_unique<PropertyTestLayoutManager>()); |
| auto widget = std::make_unique<TestWidget>(); |
| Widget::InitParams params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW); |
| |
| auto delegate_owned = std::make_unique<WidgetDelegate>(); |
| params.delegate = delegate_owned.get(); |
| params.delegate->RegisterDeleteDelegateCallback( |
| WidgetDelegate::RegisterDeleteCallbackPassKey(), |
| base::DoNothingWithBoundArgs(std::move(delegate_owned))); |
| params.delegate->SetHasWindowSizeControls(true); |
| params.parent = nullptr; |
| params.context = root_window(); |
| widget->Init(std::move(params)); |
| EXPECT_TRUE(layout_manager->added()); |
| } |
| |
| TEST_F(NativeWidgetAuraTest, GetClientAreaScreenBounds) { |
| // Create a widget. |
| Widget::InitParams params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW); |
| params.context = root_window(); |
| params.bounds.SetRect(10, 20, 300, 400); |
| auto widget = std::make_unique<Widget>(); |
| widget->Init(std::move(params)); |
| |
| // For Aura, client area bounds match window bounds. |
| gfx::Rect client_bounds = widget->GetClientAreaBoundsInScreen(); |
| EXPECT_EQ(10, client_bounds.x()); |
| EXPECT_EQ(20, client_bounds.y()); |
| EXPECT_EQ(300, client_bounds.width()); |
| EXPECT_EQ(400, client_bounds.height()); |
| } |
| |
| // View subclass that tracks whether it has gotten a gesture event. |
| class GestureTrackingView : public View { |
| METADATA_HEADER(GestureTrackingView, View) |
| |
| public: |
| GestureTrackingView() = default; |
| |
| GestureTrackingView(const GestureTrackingView&) = delete; |
| GestureTrackingView& operator=(const GestureTrackingView&) = delete; |
| |
| void set_consume_gesture_event(bool value) { consume_gesture_event_ = value; } |
| |
| void clear_got_gesture_event() { got_gesture_event_ = false; } |
| bool got_gesture_event() const { return got_gesture_event_; } |
| |
| // View overrides: |
| void OnGestureEvent(ui::GestureEvent* event) override { |
| got_gesture_event_ = true; |
| if (consume_gesture_event_) { |
| event->StopPropagation(); |
| } |
| } |
| |
| private: |
| // Was OnGestureEvent() invoked? |
| bool got_gesture_event_ = false; |
| |
| // Dictates what OnGestureEvent() returns. |
| bool consume_gesture_event_ = true; |
| }; |
| |
| BEGIN_METADATA(GestureTrackingView) |
| END_METADATA |
| |
| // Verifies a capture isn't set on touch press and that the view that gets |
| // the press gets the release. |
| TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) { |
| // Create two views (both sized the same). |child| is configured not to |
| // consume the gesture event. |
| auto content_view = std::make_unique<GestureTrackingView>(); |
| GestureTrackingView* child = new GestureTrackingView(); |
| child->set_consume_gesture_event(false); |
| content_view->SetLayoutManager(std::make_unique<FillLayout>()); |
| content_view->AddChildViewRaw(child); |
| auto widget = std::make_unique<TestWidget>(); |
| Widget::InitParams params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW_FRAMELESS); |
| params.context = root_window(); |
| params.bounds = gfx::Rect(0, 0, 100, 200); |
| widget->Init(std::move(params)); |
| GestureTrackingView* view = widget->SetContentsView(std::move(content_view)); |
| widget->Show(); |
| |
| ui::TouchEvent press(ui::EventType::kTouchPressed, gfx::Point(41, 51), |
| ui::EventTimeForNow(), |
| ui::PointerDetails(ui::EventPointerType::kTouch, 1)); |
| ui::EventDispatchDetails details = GetEventSink()->OnEventFromSource(&press); |
| ASSERT_FALSE(details.dispatcher_destroyed); |
| // Both views should get the press. |
| EXPECT_TRUE(view->got_gesture_event()); |
| EXPECT_TRUE(child->got_gesture_event()); |
| view->clear_got_gesture_event(); |
| child->clear_got_gesture_event(); |
| // Touch events should not automatically grab capture. |
| EXPECT_FALSE(widget->HasCapture()); |
| |
| // Release touch. Only |view| should get the release since that it consumed |
| // the press. |
| ui::TouchEvent release(ui::EventType::kTouchReleased, gfx::Point(250, 251), |
| ui::EventTimeForNow(), |
| ui::PointerDetails(ui::EventPointerType::kTouch, 1)); |
| details = GetEventSink()->OnEventFromSource(&release); |
| ASSERT_FALSE(details.dispatcher_destroyed); |
| EXPECT_TRUE(view->got_gesture_event()); |
| EXPECT_FALSE(child->got_gesture_event()); |
| view->clear_got_gesture_event(); |
| } |
| |
| // Verifies views with layers are targeted for events properly. |
| TEST_F(NativeWidgetAuraTest, PreferViewLayersToChildWindows) { |
| // Create two widgets: |parent| and |child|. |child| is a child of |parent|. |
| auto parent = std::make_unique<Widget>(); |
| Widget::InitParams parent_params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW_FRAMELESS); |
| parent_params.context = root_window(); |
| parent->Init(std::move(parent_params)); |
| View* parent_root = parent->SetContentsView(std::make_unique<View>()); |
| parent->SetBounds(gfx::Rect(0, 0, 400, 400)); |
| parent->Show(); |
| |
| auto child = std::make_unique<Widget>(); |
| Widget::InitParams child_params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_CONTROL); |
| child_params.parent = parent->GetNativeWindow(); |
| child->Init(std::move(child_params)); |
| child->SetBounds(gfx::Rect(0, 0, 200, 200)); |
| child->Show(); |
| |
| // Point is over |child|. |
| EXPECT_EQ( |
| child->GetNativeWindow(), |
| parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(50, 50))); |
| |
| // Create a view with a layer and stack it at the bottom (below |child|). |
| auto* view_with_layer = parent_root->AddChildView(std::make_unique<View>()); |
| view_with_layer->SetBounds(0, 0, 50, 50); |
| view_with_layer->SetPaintToLayer(); |
| |
| // Make sure that |child| still gets the event. |
| EXPECT_EQ( |
| child->GetNativeWindow(), |
| parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(20, 20))); |
| |
| // Move |view_with_layer| to the top and make sure it gets the |
| // event when the point is within |view_with_layer|'s bounds. |
| view_with_layer->layer()->parent()->StackAtTop(view_with_layer->layer()); |
| EXPECT_EQ( |
| parent->GetNativeWindow(), |
| parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(20, 20))); |
| |
| // Point is over |child|, it should get the event. |
| EXPECT_EQ( |
| child->GetNativeWindow(), |
| parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(70, 70))); |
| |
| parent_root->RemoveChildViewT(view_with_layer); |
| view_with_layer = nullptr; |
| |
| EXPECT_EQ( |
| child->GetNativeWindow(), |
| parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(20, 20))); |
| } |
| |
| // Verifies views with layers are targeted for events properly. |
| TEST_F(NativeWidgetAuraTest, |
| ShouldDescendIntoChildForEventHandlingChecksVisibleBounds) { |
| // Create two widgets: |parent| and |child|. |child| is a child of |parent|. |
| auto parent = std::make_unique<Widget>(); |
| Widget::InitParams parent_params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW_FRAMELESS); |
| parent_params.context = root_window(); |
| parent->Init(std::move(parent_params)); |
| View* parent_root_view = parent->SetContentsView(std::make_unique<View>()); |
| parent->SetBounds(gfx::Rect(0, 0, 400, 400)); |
| parent->Show(); |
| |
| auto child = std::make_unique<Widget>(); |
| Widget::InitParams child_params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_CONTROL); |
| child_params.parent = parent->GetNativeWindow(); |
| child->Init(std::move(child_params)); |
| child->SetBounds(gfx::Rect(0, 0, 200, 200)); |
| child->Show(); |
| |
| // Point is over |child|. |
| EXPECT_EQ( |
| child->GetNativeWindow(), |
| parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(50, 50))); |
| |
| View* parent_root_view_child = |
| parent_root_view->AddChildView(std::make_unique<View>()); |
| parent_root_view_child->SetBounds(0, 0, 10, 10); |
| |
| // Create a View whose layer extends outside the bounds of its parent. Event |
| // targeting should only consider the visible bounds. |
| View* parent_root_view_child_child = |
| parent_root_view_child->AddChildView(std::make_unique<View>()); |
| parent_root_view_child_child->SetBounds(0, 0, 100, 100); |
| parent_root_view_child_child->SetPaintToLayer(); |
| parent_root_view_child_child->layer()->parent()->StackAtTop( |
| parent_root_view_child_child->layer()); |
| |
| // 20,20 is over |parent_root_view_child_child|'s layer, but not the visible |
| // bounds of |parent_root_view_child_child|, so |child| should be the event |
| // target. |
| EXPECT_EQ( |
| child->GetNativeWindow(), |
| parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(20, 20))); |
| } |
| |
| // Verifies views with layers that have SetCanProcessEventWithinSubtree(false) |
| // set are ignored for event targeting (i.e. the underlying child window can |
| // still be the target of those events). |
| TEST_F( |
| NativeWidgetAuraTest, |
| ShouldDescendIntoChildForEventHandlingIgnoresViewsThatDoNotProcessEvents) { |
| // Create two widgets: `parent` and `child`. `child` is a child of `parent`. |
| auto parent = std::make_unique<Widget>(); |
| Widget::InitParams parent_params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW_FRAMELESS); |
| parent_params.context = root_window(); |
| parent->Init(std::move(parent_params)); |
| View* const parent_root_view = |
| parent->SetContentsView(std::make_unique<View>()); |
| parent->SetBounds(gfx::Rect(0, 0, 400, 400)); |
| parent->Show(); |
| |
| auto child = std::make_unique<Widget>(); |
| Widget::InitParams child_params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_CONTROL); |
| child_params.parent = parent->GetNativeWindow(); |
| child->Init(std::move(child_params)); |
| child->SetBounds(gfx::Rect(0, 0, 200, 200)); |
| child->Show(); |
| |
| // Point is over `child`. |
| EXPECT_EQ( |
| child->GetNativeWindow(), |
| parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(50, 50))); |
| |
| View* const view_overlapping_child = |
| parent_root_view->AddChildView(std::make_unique<View>()); |
| view_overlapping_child->SetBoundsRect(gfx::Rect(0, 0, 200, 200)); |
| view_overlapping_child->SetPaintToLayer(); |
| view_overlapping_child->layer()->parent()->StackAtTop( |
| view_overlapping_child->layer()); |
| |
| // While `view_overlapping_child` receives events, parent should be the event |
| // handler as the view is on top of the child widget. This basically is used |
| // to verify that the test setup is working (view with layer overlapping child |
| // window receives events). |
| EXPECT_EQ( |
| parent->GetNativeWindow(), |
| parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(50, 50))); |
| |
| // Events should not be routed to `parent` if the view overlapping `child` |
| // does not process events. |
| view_overlapping_child->SetCanProcessEventsWithinSubtree(false); |
| EXPECT_EQ( |
| child->GetNativeWindow(), |
| parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(50, 50))); |
| } |
| |
| // Verifies that widget->FlashFrame() sets aura::client::kDrawAttentionKey, |
| // and activating the window clears it. |
| TEST_F(NativeWidgetAuraTest, FlashFrame) { |
| auto widget = std::make_unique<Widget>(); |
| Widget::InitParams params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW); |
| params.context = root_window(); |
| widget->Init(std::move(params)); |
| aura::Window* window = widget->GetNativeWindow(); |
| EXPECT_FALSE(window->GetProperty(aura::client::kDrawAttentionKey)); |
| widget->FlashFrame(true); |
| EXPECT_TRUE(window->GetProperty(aura::client::kDrawAttentionKey)); |
| widget->FlashFrame(false); |
| EXPECT_FALSE(window->GetProperty(aura::client::kDrawAttentionKey)); |
| widget->FlashFrame(true); |
| EXPECT_TRUE(window->GetProperty(aura::client::kDrawAttentionKey)); |
| widget->Activate(); |
| EXPECT_FALSE(window->GetProperty(aura::client::kDrawAttentionKey)); |
| } |
| |
| // Used to track calls to WidgetDelegate::OnWidgetMove(). |
| class MoveTestWidgetDelegate : public WidgetDelegateView { |
| public: |
| MoveTestWidgetDelegate() = default; |
| |
| MoveTestWidgetDelegate(const MoveTestWidgetDelegate&) = delete; |
| MoveTestWidgetDelegate& operator=(const MoveTestWidgetDelegate&) = delete; |
| |
| ~MoveTestWidgetDelegate() override = default; |
| |
| void ClearGotMove() { got_move_ = false; } |
| bool got_move() const { return got_move_; } |
| |
| // WidgetDelegate overrides: |
| void OnWidgetMove() override { got_move_ = true; } |
| |
| private: |
| bool got_move_ = false; |
| }; |
| |
| // This test simulates what happens when a window is normally maximized. That |
| // is, it's layer is acquired for animation then the window is maximized. |
| // Acquiring the layer resets the bounds of the window. This test verifies the |
| // Widget is still notified correctly of a move in this case. |
| TEST_F(NativeWidgetAuraTest, OnWidgetMovedInvokedAfterAcquireLayer) { |
| // |delegate| is not owned by the Widget but it is deleted when the widget |
| // is destroyed since it is "owned" by the root view via the View hierarchy. |
| auto delegate = std::make_unique<MoveTestWidgetDelegate>(); |
| auto* delegate_ptr = delegate.release(); |
| UniqueWidgetPtr widget = base::WrapUnique(Widget::CreateWindowWithContext( |
| delegate_ptr, root_window(), gfx::Rect(10, 10, 100, 200))); |
| widget->Show(); |
| delegate_ptr->ClearGotMove(); |
| // Simulate a maximize with animation. |
| widget->GetNativeView()->RecreateLayer(); |
| widget->SetBounds(gfx::Rect(0, 0, 500, 500)); |
| EXPECT_TRUE(delegate_ptr->got_move()); |
| } |
| |
| // Tests that if a widget has a view which should be initially focused when the |
| // widget is shown, this view should not get focused if the associated window |
| // can not be activated. |
| TEST_F(NativeWidgetAuraTest, PreventFocusOnNonActivableWindow) { |
| test_focus_rules()->set_can_activate(false); |
| test::TestInitialFocusWidgetDelegate delegate(root_window()); |
| delegate.GetWidget()->Show(); |
| EXPECT_FALSE(delegate.view()->HasFocus()); |
| |
| test_focus_rules()->set_can_activate(true); |
| test::TestInitialFocusWidgetDelegate delegate2(root_window()); |
| delegate2.GetWidget()->Show(); |
| EXPECT_TRUE(delegate2.view()->HasFocus()); |
| } |
| |
| // Tests that the transient child bubble window is only visible if the parent is |
| // visible. |
| TEST_F(NativeWidgetAuraTest, VisibilityOfChildBubbleWindow) { |
| // Create a parent window. |
| auto parent = std::make_unique<Widget>(); |
| Widget::InitParams parent_params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW); |
| parent_params.context = root_window(); |
| parent->Init(std::move(parent_params)); |
| parent->SetBounds(gfx::Rect(0, 0, 480, 320)); |
| |
| // Add a child bubble window to the above parent window and show it. |
| auto child = std::make_unique<Widget>(); |
| Widget::InitParams child_params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_BUBBLE); |
| child_params.parent = parent->GetNativeWindow(); |
| child->Init(std::move(child_params)); |
| child->SetBounds(gfx::Rect(0, 0, 200, 200)); |
| child->Show(); |
| |
| // Check that the bubble window is added as the transient child and it is |
| // hidden because parent window is hidden. |
| wm::TransientWindowManager* manager = |
| wm::TransientWindowManager::GetOrCreate(child->GetNativeWindow()); |
| EXPECT_EQ(parent->GetNativeWindow(), manager->transient_parent()); |
| EXPECT_FALSE(parent->IsVisible()); |
| EXPECT_FALSE(child->IsVisible()); |
| |
| // Show the parent window should make the transient child bubble visible. |
| parent->Show(); |
| EXPECT_TRUE(parent->IsVisible()); |
| EXPECT_TRUE(child->IsVisible()); |
| } |
| |
| // Tests that for a child transient window, if its modal type is |
| // ui::mojom::ModalType::kWindow, then its visibility is controlled by its |
| // transient parent's visibility. |
| TEST_F(NativeWidgetAuraTest, TransientChildModalWindowVisibility) { |
| // Create the delegate first so it's destroyed last. |
| auto delegate_owned = std::make_unique<WidgetDelegate>(); |
| // Create a parent window. |
| auto parent = std::make_unique<Widget>(); |
| Widget::InitParams parent_params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW); |
| parent_params.context = root_window(); |
| parent->Init(std::move(parent_params)); |
| parent->SetBounds(gfx::Rect(0, 0, 400, 400)); |
| parent->Show(); |
| EXPECT_TRUE(parent->IsVisible()); |
| |
| // Create a ui::mojom::ModalType::kWindow modal type transient child window. |
| auto child = std::make_unique<Widget>(); |
| Widget::InitParams child_params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW); |
| child_params.parent = parent->GetNativeWindow(); |
| |
| child_params.delegate = delegate_owned.get(); |
| child_params.delegate->RegisterDeleteDelegateCallback( |
| WidgetDelegate::RegisterDeleteCallbackPassKey(), |
| base::DoNothingWithBoundArgs(std::move(delegate_owned))); |
| child_params.delegate->SetModalType(ui::mojom::ModalType::kWindow); |
| child->Init(std::move(child_params)); |
| child->SetBounds(gfx::Rect(0, 0, 200, 200)); |
| child->Show(); |
| EXPECT_TRUE(parent->IsVisible()); |
| EXPECT_TRUE(child->IsVisible()); |
| |
| // Hide the parent window should also hide the child window. |
| parent->Hide(); |
| EXPECT_FALSE(parent->IsVisible()); |
| EXPECT_FALSE(child->IsVisible()); |
| |
| // The child window can't be shown if the parent window is hidden. |
| child->Show(); |
| EXPECT_FALSE(parent->IsVisible()); |
| EXPECT_FALSE(child->IsVisible()); |
| |
| parent->Show(); |
| EXPECT_TRUE(parent->IsVisible()); |
| EXPECT_TRUE(child->IsVisible()); |
| } |
| |
| // Tests that widgets that are created minimized have the correct restore |
| // bounds. |
| TEST_F(NativeWidgetAuraTest, MinimizedWidgetRestoreBounds) { |
| const gfx::Rect restore_bounds(300, 300); |
| |
| auto widget = std::make_unique<Widget>(); |
| Widget::InitParams params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW); |
| params.context = root_window(); |
| params.show_state = ui::mojom::WindowShowState::kMinimized; |
| params.bounds = restore_bounds; |
| |
| widget->Init(std::move(params)); |
| widget->Show(); |
| |
| aura::Window* window = widget->GetNativeWindow(); |
| EXPECT_EQ(ui::mojom::WindowShowState::kMinimized, |
| window->GetProperty(aura::client::kShowStateKey)); |
| EXPECT_EQ(restore_bounds, |
| *window->GetProperty(aura::client::kRestoreBoundsKey)); |
| |
| widget->Restore(); |
| EXPECT_EQ(restore_bounds, window->bounds()); |
| } |
| |
| // Tests that the `kDeskUuidKey` is set if the `workspace` parameter is |
| // a uuid, and that the `kWindowWorkspaceKey` is set if it's a string |
| // representation of an integer. |
| TEST_F(NativeWidgetAuraTest, WorkspaceUuid) { |
| // If the `workspace` param is a uuid, `kDeskUuidKey` should be set. |
| Widget::InitParams params(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW); |
| params.parent = nullptr; |
| params.context = root_window(); |
| params.show_state = ui::mojom::WindowShowState::kMinimized; |
| params.bounds.SetRect(0, 0, 1024, 800); |
| const std::string uuid = "e1b6731b-2a99-48be-bcb7-54e3ba274d05"; |
| params.workspace = base::Uuid::ParseLowercase(uuid).AsLowercaseString(); |
| auto widget = std::make_unique<Widget>(); |
| widget->Init(std::move(params)); |
| widget->Show(); |
| |
| EXPECT_EQ(-1, widget->GetNativeWindow()->GetProperty( |
| aura::client::kWindowWorkspaceKey)); |
| EXPECT_THAT( |
| widget->GetNativeWindow()->GetProperty(aura::client::kDeskUuidKey), |
| testing::Pointee(uuid)); |
| |
| // If the `workspace` param is an int, `kWindowWorkspaceKey` should be set. |
| Widget::InitParams params2(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW); |
| params2.parent = nullptr; |
| params2.context = root_window(); |
| params2.show_state = ui::mojom::WindowShowState::kMinimized; |
| params2.bounds.SetRect(0, 0, 1024, 800); |
| params2.workspace = "2"; |
| auto widget2 = std::make_unique<Widget>(); |
| widget2->Init(std::move(params2)); |
| widget2->Show(); |
| |
| EXPECT_EQ(2, widget2->GetNativeWindow()->GetProperty( |
| aura::client::kWindowWorkspaceKey)); |
| EXPECT_FALSE( |
| widget2->GetNativeWindow()->GetProperty(aura::client::kDeskUuidKey)); |
| } |
| |
| // Series of tests that verifies having a null NativeWidgetDelegate doesn't |
| // crash. |
| class NativeWidgetAuraWithNoDelegateTest : public NativeWidgetAuraTest { |
| public: |
| NativeWidgetAuraWithNoDelegateTest() = default; |
| |
| NativeWidgetAuraWithNoDelegateTest( |
| const NativeWidgetAuraWithNoDelegateTest&) = delete; |
| NativeWidgetAuraWithNoDelegateTest& operator=( |
| const NativeWidgetAuraWithNoDelegateTest&) = delete; |
| |
| ~NativeWidgetAuraWithNoDelegateTest() override = default; |
| |
| // testing::Test overrides: |
| void SetUp() override { |
| NativeWidgetAuraTest::SetUp(); |
| Widget widget; |
| native_widget_ = new NativeWidgetAura(&widget); |
| Widget::InitParams params = |
| CreateParams(Widget::InitParams::CLIENT_OWNS_WIDGET, |
| Widget::InitParams::TYPE_WINDOW); |
| params.native_widget = native_widget_; |
| widget.Init(std::move(params)); |
| widget.Show(); |
| // Notify all widget observers that the widget is destroying so they can |
| // unregister properly and clear the pointer to the widget. |
| widget.OnNativeWidgetDestroying(); |
| // Widget will create a DefaultWidgetDelegate if no delegates are provided. |
| // Call Widget::OnNativeWidgetDestroyed() to destroy |
| // the WidgetDelegate properly. |
| widget.OnNativeWidgetDestroyed(); |
| } |
| |
| void TearDown() override { |
| native_widget_.ExtractAsDangling()->CloseNow(); |
| ViewsTestBase::TearDown(); |
| } |
| |
| raw_ptr<NativeWidgetAura> native_widget_ = nullptr; |
| }; |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, GetHitTestMaskTest) { |
| SkPath mask; |
| native_widget_->GetHitTestMask(&mask); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, GetMaximumSizeTest) { |
| native_widget_->GetMaximumSize(); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, GetMinimumSizeTest) { |
| native_widget_->GetMinimumSize(); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, GetNonClientComponentTest) { |
| native_widget_->GetNonClientComponent(gfx::Point()); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, GetWidgetTest) { |
| native_widget_->GetWidget(); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, HasHitTestMaskTest) { |
| native_widget_->HasHitTestMask(); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, OnBoundsChangedTest) { |
| native_widget_->OnCaptureLost(); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, OnCaptureLostTest) { |
| native_widget_->OnBoundsChanged(gfx::Rect(), gfx::Rect()); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, OnGestureEventTest) { |
| ui::GestureEvent gesture( |
| 0, 0, 0, ui::EventTimeForNow(), |
| ui::GestureEventDetails(ui::EventType::kGestureTapDown)); |
| native_widget_->OnGestureEvent(&gesture); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, OnKeyEventTest) { |
| ui::KeyEvent key(ui::EventType::kKeyPressed, ui::VKEY_0, ui::EF_NONE); |
| native_widget_->OnKeyEvent(&key); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, OnMouseEventTest) { |
| ui::MouseEvent move(ui::EventType::kMouseMoved, gfx::Point(), gfx::Point(), |
| ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE); |
| native_widget_->OnMouseEvent(&move); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, OnPaintTest) { |
| native_widget_->OnPaint(ui::PaintContext(nullptr, 0, gfx::Rect(), false)); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, OnResizeLoopEndedTest) { |
| native_widget_->OnResizeLoopEnded(nullptr); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, OnResizeLoopStartedTest) { |
| native_widget_->OnResizeLoopStarted(nullptr); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, OnScrollEventTest) { |
| ui::ScrollEvent scroll(ui::EventType::kScroll, gfx::Point(), |
| ui::EventTimeForNow(), 0, 0, 0, 0, 0, 0); |
| native_widget_->OnScrollEvent(&scroll); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, OnTransientParentChangedTest) { |
| native_widget_->OnTransientParentChanged(nullptr); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, OnWindowAddedToRootWindowTest) { |
| native_widget_->OnWindowAddedToRootWindow(nullptr); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, OnWindowPropertyChangedTest) { |
| native_widget_->OnWindowPropertyChanged(nullptr, nullptr, 0); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, OnWindowRemovingFromRootWindowTest) { |
| native_widget_->OnWindowRemovingFromRootWindow(nullptr, nullptr); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, |
| OnWindowTargetVisibilityChangedTest) { |
| native_widget_->OnWindowTargetVisibilityChanged(false); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, OnWindowActivatedTest) { |
| native_widget_->OnWindowActivated( |
| wm::ActivationChangeObserver::ActivationReason::ACTIVATION_CLIENT, |
| native_widget_->GetNativeView(), nullptr); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, OnWindowFocusedTest) { |
| native_widget_->OnWindowFocused(nullptr, nullptr); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, ShouldActivateTest) { |
| native_widget_->ShouldActivate(); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, |
| ShouldDescendIntoChildForEventHandlingTest) { |
| native_widget_->ShouldDescendIntoChildForEventHandling(nullptr, gfx::Point()); |
| } |
| |
| TEST_F(NativeWidgetAuraWithNoDelegateTest, UpdateVisualStateTest) { |
| native_widget_->UpdateVisualState(); |
| } |
| |
| } // namespace views |