#include <memory>
#include <set>
#include <utility>
#include <vector>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/ranges/algorithm.h"
#include "base/run_loop.h"
#include "base/test/gtest_util.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#include "ui/base/hit_test.h"
#include "ui/color/color_id.h"
#include "ui/color/color_provider.h"
#include "ui/color/color_provider_manager.h"
#include "ui/color/color_recipe.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/compositor/test/draw_waiter_for_test.h"
#include "ui/events/event_observer.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/native_theme/native_theme.h"
#include "ui/native_theme/test_native_theme.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/buildflags.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/event_monitor.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/style/platform_style.h"
#include "ui/views/test/mock_drag_controller.h"
#include "ui/views/test/mock_native_widget.h"
#include "ui/views/test/native_widget_factory.h"
#include "ui/views/test/test_views.h"
#include "ui/views/test/test_widget_observer.h"
#include "ui/views/test/views_test_utils.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/view_test_api.h"
#include "ui/views/views_test_suite.h"
#include "ui/views/widget/native_widget_delegate.h"
#include "ui/views/widget/native_widget_private.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/views/widget/widget_deletion_observer.h"
#include "ui/views/widget/widget_interactive_uitest_utils.h"
#include "ui/views/widget/widget_removals_observer.h"
#include "ui/views/widget/widget_utils.h"
#include "ui/views/window/dialog_delegate.h"
#include "ui/views/window/native_frame_view.h"
#if defined(USE_AURA)
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/view_prop.h"
#include "ui/views/test/test_platform_native_widget.h"
#include "ui/views/widget/native_widget_aura.h"
#include "ui/wm/core/base_focus_rules.h"
#include "ui/wm/core/focus_controller.h"
#include "ui/wm/core/shadow_controller.h"
#include "ui/wm/core/shadow_controller_delegate.h"
#endif
#if BUILDFLAG(IS_WIN)
#include "ui/base/win/window_event_target.h"
#include "ui/views/win/hwnd_util.h"
#endif
#if BUILDFLAG(IS_MAC)
#include "base/mac/mac_util.h"
#endif
#if BUILDFLAG(ENABLE_DESKTOP_AURA)
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#endif
#if BUILDFLAG(IS_OZONE)
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/platform_gl_egl_utility.h"
#endif
namespace views::test {
namespace {
gfx::Point ConvertPointFromWidgetToView(View* view, const gfx::Point& p) {
gfx::Point tmp(p);
View::ConvertPointToTarget(view->GetWidget()->GetRootView(), view, &tmp);
return tmp;
}
std::unique_ptr<ui::test::EventGenerator> CreateEventGenerator(
gfx::NativeWindow root_window,
gfx::NativeWindow target_window) {
auto generator =
std::make_unique<ui::test::EventGenerator>(root_window, target_window);
return generator;
}
class TestBubbleDialogDelegateView : public BubbleDialogDelegateView {
public:
explicit TestBubbleDialogDelegateView(View* anchor)
: BubbleDialogDelegateView(anchor, BubbleBorder::NONE) {}
~TestBubbleDialogDelegateView() override = default;
bool ShouldShowCloseButton() const override {
reset_controls_called_ = true;
return true;
}
mutable bool reset_controls_called_ = false;
};
ui::GestureEvent CreateTestGestureEvent(ui::EventType type, int x, int y) {
return ui::GestureEvent(x, y, 0, base::TimeTicks(),
ui::GestureEventDetails(type));
}
ui::GestureEvent CreateTestGestureEvent(const ui::GestureEventDetails& details,
int x,
int y) {
return ui::GestureEvent(x, y, 0, base::TimeTicks(), details);
}
class TestWidgetRemovalsObserver : public WidgetRemovalsObserver {
public:
TestWidgetRemovalsObserver() = default;
TestWidgetRemovalsObserver(const TestWidgetRemovalsObserver&) = delete;
TestWidgetRemovalsObserver& operator=(const TestWidgetRemovalsObserver&) =
delete;
~TestWidgetRemovalsObserver() override = default;
void OnWillRemoveView(Widget* widget, View* view) override {
removed_views_.insert(view);
}
bool DidRemoveView(View* view) {
return removed_views_.find(view) != removed_views_.end();
}
private:
std::set<View*> removed_views_;
};
}
class ScrollableEventCountView : public EventCountView {
public:
ScrollableEventCountView() = default;
ScrollableEventCountView(const ScrollableEventCountView&) = delete;
ScrollableEventCountView& operator=(const ScrollableEventCountView&) = delete;
~ScrollableEventCountView() override = default;
private:
void OnGestureEvent(ui::GestureEvent* event) override {
EventCountView::OnGestureEvent(event);
switch (event->type()) {
case ui::ET_GESTURE_SCROLL_BEGIN:
case ui::ET_GESTURE_SCROLL_UPDATE:
case ui::ET_GESTURE_SCROLL_END:
case ui::ET_SCROLL_FLING_START:
event->SetHandled();
break;
default:
break;
}
}
void OnScrollEvent(ui::ScrollEvent* event) override {
EventCountView::OnScrollEvent(event);
if (event->type() == ui::ET_SCROLL)
event->SetHandled();
}
};
class MinimumSizeFrameView : public NativeFrameView {
public:
explicit MinimumSizeFrameView(Widget* frame) : NativeFrameView(frame) {}
MinimumSizeFrameView(const MinimumSizeFrameView&) = delete;
MinimumSizeFrameView& operator=(const MinimumSizeFrameView&) = delete;
~MinimumSizeFrameView() override = default;
private:
gfx::Size GetMinimumSize() const override { return gfx::Size(300, 400); }
};
class EventCountHandler : public ui::EventHandler {
public:
EventCountHandler() = default;
EventCountHandler(const EventCountHandler&) = delete;
EventCountHandler& operator=(const EventCountHandler&) = delete;
~EventCountHandler() override = default;
int GetEventCount(ui::EventType type) { return event_count_[type]; }
void ResetCounts() { event_count_.clear(); }
protected:
void OnEvent(ui::Event* event) override {
RecordEvent(*event);
ui::EventHandler::OnEvent(event);
}
private:
void RecordEvent(const ui::Event& event) { ++event_count_[event.type()]; }
std::map<ui::EventType, int> event_count_;
};
TEST_F(WidgetTest, WidgetInitParams) {
Widget::InitParams init1;
EXPECT_EQ(Widget::InitParams::WindowOpacity::kInferred, init1.opacity);
}
class WidgetWithCustomParamsTest : public WidgetTest {
public:
using InitFunction = base::RepeatingCallback<void(Widget::InitParams*)>;
void SetInitFunction(const InitFunction& init) { init_ = std::move(init); }
Widget::InitParams CreateParams(Widget::InitParams::Type type) override {
Widget::InitParams params = WidgetTest::CreateParams(type);
DCHECK(init_) << "If you don't need an init function, use WidgetTest";
init_.Run(¶ms);
return params;
}
private:
InitFunction init_;
};
TEST_F(WidgetWithCustomParamsTest, NamePropagatedFromParams) {
SetInitFunction(base::BindLambdaForTesting(
[](Widget::InitParams* params) { params->name = "MyWidget"; }));
std::unique_ptr<Widget> widget = CreateTestWidget();
EXPECT_EQ("MyWidget", widget->native_widget_private()->GetName());
EXPECT_EQ("MyWidget", widget->GetName());
}
TEST_F(WidgetWithCustomParamsTest, NamePropagatedFromDelegate) {
WidgetDelegate delegate;
delegate.set_internal_name("Foobar");
SetInitFunction(base::BindLambdaForTesting(
[&](Widget::InitParams* params) { params->delegate = &delegate; }));
std::unique_ptr<Widget> widget = CreateTestWidget();
EXPECT_EQ(delegate.internal_name(),
widget->native_widget_private()->GetName());
EXPECT_EQ(delegate.internal_name(), widget->GetName());
}
TEST_F(WidgetWithCustomParamsTest, NamePropagatedFromContentsViewClassName) {
class ViewWithClassName : public View {
public:
const char* GetClassName() const override { return "ViewWithClassName"; }
};
WidgetDelegate delegate;
auto view = std::make_unique<ViewWithClassName>();
auto* contents = delegate.SetContentsView(std::move(view));
SetInitFunction(base::BindLambdaForTesting(
[&](Widget::InitParams* params) { params->delegate = &delegate; }));
std::unique_ptr<Widget> widget = CreateTestWidget();
EXPECT_EQ(contents->GetClassName(),
widget->native_widget_private()->GetName());
EXPECT_EQ(contents->GetClassName(), widget->GetName());
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(WidgetWithCustomParamsTest, SkottieColorsTest) {
struct SkottieColors {
bool operator==(const SkottieColors& other) const {
return color1 == other.color1 && color1_shade1 == other.color1_shade1 &&
color1_shade2 == other.color1_shade2 && color2 == other.color2 &&
color3 == other.color3 && color4 == other.color4 &&
color5 == other.color5 && color6 == other.color6 &&
base_color == other.base_color &&
secondary_color == other.secondary_color;
}
bool operator!=(const SkottieColors& other) const {
return !operator==(other);
}
SkColor color1, color1_shade1, color1_shade2, color2, color3, color4,
color5, color6, base_color, secondary_color;
};
class ViewObservingSkottieColors : public View {
public:
void OnThemeChanged() override {
View::OnThemeChanged();
const ui::ColorProvider* provider = GetColorProvider();
history.push_back({provider->GetColor(ui::kColorNativeColor1),
provider->GetColor(ui::kColorNativeColor1Shade1),
provider->GetColor(ui::kColorNativeColor1Shade2),
provider->GetColor(ui::kColorNativeColor2),
provider->GetColor(ui::kColorNativeColor3),
provider->GetColor(ui::kColorNativeColor4),
provider->GetColor(ui::kColorNativeColor5),
provider->GetColor(ui::kColorNativeColor6),
provider->GetColor(ui::kColorNativeBaseColor),
provider->GetColor(ui::kColorNativeSecondaryColor)});
}
std::vector<SkottieColors> history;
};
ui::NativeTheme* theme = ui::NativeTheme::GetInstanceForNativeUi();
theme->set_use_dark_colors(false);
WidgetDelegate delegate1;
ViewObservingSkottieColors* contents1 =
delegate1.SetContentsView(std::make_unique<ViewObservingSkottieColors>());
SetInitFunction(base::BindLambdaForTesting([&](Widget::InitParams* params) {
params->delegate = &delegate1;
params->background_elevation =
ui::ColorProviderManager::ElevationMode::kLow;
}));
std::unique_ptr<Widget> widget1 = CreateTestWidget();
ASSERT_EQ(1u, contents1->history.size());
WidgetDelegate delegate2;
ViewObservingSkottieColors* contents2 =
delegate2.SetContentsView(std::make_unique<ViewObservingSkottieColors>());
SetInitFunction(base::BindLambdaForTesting([&](Widget::InitParams* params) {
params->delegate = &delegate2;
params->background_elevation =
ui::ColorProviderManager::ElevationMode::kHigh;
}));
std::unique_ptr<Widget> widget2 = CreateTestWidget();
ASSERT_EQ(1u, contents2->history.size());
EXPECT_EQ(contents1->history[0u], contents2->history[0u]);
theme->set_use_dark_colors(true);
theme->NotifyOnNativeThemeUpdated();
ASSERT_EQ(2u, contents1->history.size());
ASSERT_EQ(2u, contents2->history.size());
EXPECT_NE(contents1->history[0u], contents1->history[1u]);
EXPECT_NE(contents2->history[0u], contents2->history[1u]);
EXPECT_NE(contents1->history[1u], contents2->history[1u]);
WidgetDelegate delegate3;
ViewObservingSkottieColors* contents3 =
delegate3.SetContentsView(std::make_unique<ViewObservingSkottieColors>());
SetInitFunction(base::BindLambdaForTesting([&](Widget::InitParams* params) {
params->delegate = &delegate3;
params->background_elevation =
ui::ColorProviderManager::ElevationMode::kLow;
}));
std::unique_ptr<Widget> widget3 = CreateTestWidget();
ASSERT_EQ(1u, contents3->history.size());
EXPECT_EQ(contents1->history[1u], contents3->history[0u]);
WidgetDelegate delegate4;
ViewObservingSkottieColors* contents4 =
delegate4.SetContentsView(std::make_unique<ViewObservingSkottieColors>());
SetInitFunction(base::BindLambdaForTesting([&](Widget::InitParams* params) {
params->delegate = &delegate4;
params->background_elevation =
ui::ColorProviderManager::ElevationMode::kHigh;
}));
std::unique_ptr<Widget> widget4 = CreateTestWidget();
ASSERT_EQ(1u, contents4->history.size());
EXPECT_EQ(contents2->history[1u], contents4->history[0u]);
theme->set_use_dark_colors(false);
theme->NotifyOnNativeThemeUpdated();
ASSERT_EQ(3u, contents1->history.size());
ASSERT_EQ(3u, contents2->history.size());
ASSERT_EQ(2u, contents3->history.size());
ASSERT_EQ(2u, contents4->history.size());
EXPECT_EQ(contents1->history[0u], contents1->history[2u]);
EXPECT_EQ(contents2->history[0u], contents2->history[2u]);
EXPECT_EQ(contents1->history[2u], contents3->history[1u]);
EXPECT_EQ(contents2->history[2u], contents4->history[1u]);
}
#endif
class WidgetColorModeTest : public WidgetTest {
public:
static constexpr SkColor kLightColor = SK_ColorWHITE;
static constexpr SkColor kDarkColor = SK_ColorBLACK;
WidgetColorModeTest() = default;
~WidgetColorModeTest() override = default;
void SetUp() override {
WidgetTest::SetUp();
ui::ColorProviderManager& manager =
ui::ColorProviderManager::GetForTesting();
manager.AppendColorProviderInitializer(base::BindRepeating(&AddColor));
}
void TearDown() override {
ui::ColorProviderManager::ResetForTesting();
WidgetTest::TearDown();
}
private:
static void AddColor(ui::ColorProvider* provider,
const ui::ColorProviderManager::Key& key) {
ui::ColorMixer& mixer = provider->AddMixer();
mixer[ui::kColorSysPrimary] = {
key.color_mode == ui::ColorProviderManager::ColorMode::kDark
? kDarkColor
: kLightColor};
}
};
TEST_F(WidgetColorModeTest, ColorModeOverride_NoOverride) {
ui::TestNativeTheme test_theme;
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
test_theme.SetDarkMode(true);
widget->SetNativeThemeForTest(&test_theme);
widget->SetColorModeOverride({});
EXPECT_EQ(kDarkColor,
widget->GetColorProvider()->GetColor(ui::kColorSysPrimary));
}
TEST_F(WidgetColorModeTest, ColorModeOverride_DarkOverride) {
ui::TestNativeTheme test_theme;
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
test_theme.SetDarkMode(false);
widget->SetNativeThemeForTest(&test_theme);
widget->SetColorModeOverride(ui::ColorProviderManager::ColorMode::kDark);
EXPECT_EQ(kDarkColor,
widget->GetColorProvider()->GetColor(ui::kColorSysPrimary));
}
TEST_F(WidgetColorModeTest, ColorModeOverride_LightOverride) {
ui::TestNativeTheme test_theme;
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
test_theme.SetDarkMode(true);
widget->SetNativeThemeForTest(&test_theme);
widget->SetColorModeOverride(ui::ColorProviderManager::ColorMode::kLight);
EXPECT_EQ(kLightColor,
widget->GetColorProvider()->GetColor(ui::kColorSysPrimary));
}
TEST_F(WidgetTest, NativeWindowProperty) {
const char* key = "foo";
int value = 3;
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
EXPECT_EQ(nullptr, widget->GetNativeWindowProperty(key));
widget->SetNativeWindowProperty(key, &value);
EXPECT_EQ(&value, widget->GetNativeWindowProperty(key));
widget->SetNativeWindowProperty(key, nullptr);
EXPECT_EQ(nullptr, widget->GetNativeWindowProperty(key));
}
TEST_F(WidgetTest, GetParent) {
WidgetAutoclosePtr toplevel(CreateTopLevelPlatformWidget());
Widget* child = CreateChildPlatformWidget(toplevel->GetNativeView());
Widget* grandchild = CreateChildPlatformWidget(child->GetNativeView());
EXPECT_EQ(nullptr, toplevel->parent());
EXPECT_EQ(child, grandchild->parent());
EXPECT_EQ(toplevel.get(), child->parent());
}
TEST_F(WidgetTest, ArrowKeyFocusTraversalOffByDefault) {
WidgetAutoclosePtr toplevel(CreateTopLevelPlatformWidget());
DCHECK(!toplevel->widget_delegate()->enable_arrow_key_traversal());
View* container = toplevel->client_view();
container->SetLayoutManager(std::make_unique<FillLayout>());
auto* const button1 =
container->AddChildView(std::make_unique<LabelButton>());
auto* const button2 =
container->AddChildView(std::make_unique<LabelButton>());
toplevel->Show();
button1->RequestFocus();
ui::KeyEvent right_arrow(ui::ET_KEY_PRESSED, ui::VKEY_RIGHT, ui::EF_NONE);
toplevel->OnKeyEvent(&right_arrow);
EXPECT_TRUE(button1->HasFocus());
EXPECT_FALSE(button2->HasFocus());
ui::KeyEvent left_arrow(ui::ET_KEY_PRESSED, ui::VKEY_LEFT, ui::EF_NONE);
toplevel->OnKeyEvent(&left_arrow);
EXPECT_TRUE(button1->HasFocus());
EXPECT_FALSE(button2->HasFocus());
ui::KeyEvent up_arrow(ui::ET_KEY_PRESSED, ui::VKEY_UP, ui::EF_NONE);
toplevel->OnKeyEvent(&up_arrow);
EXPECT_TRUE(button1->HasFocus());
EXPECT_FALSE(button2->HasFocus());
ui::KeyEvent down_arrow(ui::ET_KEY_PRESSED, ui::VKEY_DOWN, ui::EF_NONE);
toplevel->OnKeyEvent(&down_arrow);
EXPECT_TRUE(button1->HasFocus());
EXPECT_FALSE(button2->HasFocus());
}
TEST_F(WidgetTest, ArrowKeyTraversalMovesFocusBetweenViews) {
WidgetAutoclosePtr toplevel(CreateTopLevelPlatformWidget());
toplevel->widget_delegate()->SetEnableArrowKeyTraversal(true);
View* container = toplevel->client_view();
container->SetLayoutManager(std::make_unique<FillLayout>());
auto* const button1 =
container->AddChildView(std::make_unique<LabelButton>());
auto* const button2 =
container->AddChildView(std::make_unique<LabelButton>());
auto* const button3 =
container->AddChildView(std::make_unique<LabelButton>());
toplevel->Show();
button1->RequestFocus();
ui::KeyEvent right_arrow(ui::ET_KEY_PRESSED, ui::VKEY_RIGHT, ui::EF_NONE);
toplevel->OnKeyEvent(&right_arrow);
EXPECT_FALSE(button1->HasFocus());
EXPECT_TRUE(button2->HasFocus());
EXPECT_FALSE(button3->HasFocus());
ui::KeyEvent down_arrow(ui::ET_KEY_PRESSED, ui::VKEY_DOWN, ui::EF_NONE);
toplevel->OnKeyEvent(&down_arrow);
EXPECT_FALSE(button1->HasFocus());
EXPECT_FALSE(button2->HasFocus());
EXPECT_TRUE(button3->HasFocus());
ui::KeyEvent left_arrow(ui::ET_KEY_PRESSED, ui::VKEY_LEFT, ui::EF_NONE);
toplevel->OnKeyEvent(&left_arrow);
EXPECT_FALSE(button1->HasFocus());
EXPECT_TRUE(button2->HasFocus());
EXPECT_FALSE(button3->HasFocus());
ui::KeyEvent up_arrow(ui::ET_KEY_PRESSED, ui::VKEY_UP, ui::EF_NONE);
toplevel->OnKeyEvent(&up_arrow);
EXPECT_TRUE(button1->HasFocus());
EXPECT_FALSE(button2->HasFocus());
EXPECT_FALSE(button3->HasFocus());
ui::KeyEvent up_arrow2(ui::ET_KEY_PRESSED, ui::VKEY_UP, ui::EF_NONE);
toplevel->OnKeyEvent(&up_arrow2);
EXPECT_FALSE(button1->HasFocus());
EXPECT_FALSE(button2->HasFocus());
EXPECT_TRUE(button3->HasFocus());
ui::KeyEvent down_arrow2(ui::ET_KEY_PRESSED, ui::VKEY_DOWN, ui::EF_NONE);
toplevel->OnKeyEvent(&down_arrow2);
EXPECT_TRUE(button1->HasFocus());
EXPECT_FALSE(button2->HasFocus());
EXPECT_FALSE(button3->HasFocus());
}
TEST_F(WidgetTest, ArrowKeyTraversalNotInheritedByChildWidgets) {
WidgetAutoclosePtr parent(CreateTopLevelPlatformWidget());
Widget* child = CreateChildPlatformWidget(parent->GetNativeView());
parent->widget_delegate()->SetEnableArrowKeyTraversal(true);
View* container = child->GetContentsView();
DCHECK(container);
container->SetLayoutManager(std::make_unique<FillLayout>());
auto* const button1 =
container->AddChildView(std::make_unique<LabelButton>());
auto* const button2 =
container->AddChildView(std::make_unique<LabelButton>());
parent->Show();
child->Show();
button1->RequestFocus();
ui::KeyEvent right_arrow(ui::ET_KEY_PRESSED, ui::VKEY_RIGHT, ui::EF_NONE);
child->OnKeyEvent(&right_arrow);
EXPECT_TRUE(button1->HasFocus());
EXPECT_FALSE(button2->HasFocus());
}
TEST_F(WidgetTest, ArrowKeyTraversalMayBeExplicitlyEnabledByChildWidgets) {
WidgetAutoclosePtr parent(CreateTopLevelPlatformWidget());
Widget* child = CreateChildPlatformWidget(parent->GetNativeView());
child->widget_delegate()->SetEnableArrowKeyTraversal(true);
View* container = child->GetContentsView();
container->SetLayoutManager(std::make_unique<FillLayout>());
auto* const button1 =
container->AddChildView(std::make_unique<LabelButton>());
auto* const button2 =
container->AddChildView(std::make_unique<LabelButton>());
parent->Show();
child->Show();
button1->RequestFocus();
ui::KeyEvent right_arrow(ui::ET_KEY_PRESSED, ui::VKEY_RIGHT, ui::EF_NONE);
child->OnKeyEvent(&right_arrow);
EXPECT_FALSE(button1->HasFocus());
EXPECT_TRUE(button2->HasFocus());
}
TEST_F(WidgetTest, GetTopLevelWidget_Native) {
WidgetAutoclosePtr toplevel(CreateTopLevelPlatformWidget());
gfx::NativeView parent = toplevel->GetNativeView();
Widget* child = CreateChildPlatformWidget(parent);
EXPECT_EQ(toplevel.get(), toplevel->GetTopLevelWidget());
EXPECT_EQ(toplevel.get(), child->GetTopLevelWidget());
}
TEST_F(WidgetTest, ChangeActivation) {
WidgetAutoclosePtr top1(CreateTopLevelPlatformWidget());
top1->Show();
RunPendingMessages();
WidgetAutoclosePtr top2(CreateTopLevelPlatformWidget());
top2->Show();
RunPendingMessages();
top1->Activate();
RunPendingMessages();
top2->Activate();
RunPendingMessages();
top1->Activate();
RunPendingMessages();
}
TEST_F(WidgetTest, Visibility) {
WidgetAutoclosePtr toplevel(CreateTopLevelPlatformWidget());
gfx::NativeView parent = toplevel->GetNativeView();
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->Hide();
EXPECT_FALSE(toplevel->IsVisible());
EXPECT_FALSE(child->IsVisible());
child->Hide();
toplevel->Show();
EXPECT_TRUE(toplevel->IsVisible());
EXPECT_FALSE(child->IsVisible());
}
TEST_F(WidgetTest, ChildBoundsRelativeToParent) {
WidgetAutoclosePtr toplevel(CreateTopLevelPlatformWidget());
Widget* child = CreateChildPlatformWidget(toplevel->GetNativeView());
toplevel->SetBounds(gfx::Rect(160, 100, 320, 200));
child->SetBounds(gfx::Rect(0, 0, 320, 200));
child->Show();
toplevel->Show();
gfx::Rect toplevel_bounds = toplevel->GetWindowBoundsInScreen();
EXPECT_NE(gfx::Vector2d(0, 0), toplevel_bounds.OffsetFromOrigin());
EXPECT_EQ(toplevel_bounds, child->GetWindowBoundsInScreen());
}
struct OwnershipTestState {
OwnershipTestState() = default;
bool widget_deleted = false;
bool native_widget_deleted = false;
};
class WidgetOwnershipTest : public WidgetTest {
public:
WidgetOwnershipTest() = default;
WidgetOwnershipTest(const WidgetOwnershipTest&) = delete;
WidgetOwnershipTest& operator=(const WidgetOwnershipTest&) = delete;
~WidgetOwnershipTest() override = default;
void TearDown() override {
EXPECT_TRUE(state()->widget_deleted);
EXPECT_TRUE(state()->native_widget_deleted);
WidgetTest::TearDown();
}
OwnershipTestState* state() { return &state_; }
private:
OwnershipTestState state_;
};
class OwnershipTestWidget : public Widget {
public:
explicit OwnershipTestWidget(OwnershipTestState* state) : state_(state) {}
OwnershipTestWidget(const OwnershipTestWidget&) = delete;
OwnershipTestWidget& operator=(const OwnershipTestWidget&) = delete;
~OwnershipTestWidget() override { state_->widget_deleted = true; }
private:
raw_ptr<OwnershipTestState> state_;
};
class NativeWidgetDestroyedWaiter {
public:
explicit NativeWidgetDestroyedWaiter(OwnershipTestState* state)
: state_(state) {}
base::OnceClosure GetNativeWidgetDestroyedCallback() {
return base::BindOnce(
[](OwnershipTestState* state, base::RunLoop* run_loop) {
state->native_widget_deleted = true;
run_loop->Quit();
},
state_.get(), &run_loop_);
}
void Wait() {
if (!state_->native_widget_deleted)
run_loop_.Run();
}
private:
base::RunLoop run_loop_;
raw_ptr<OwnershipTestState> state_;
};
using NativeWidgetOwnsWidgetTest = WidgetOwnershipTest;
TEST_F(NativeWidgetOwnsWidgetTest, NonDesktopWidget_CloseNow) {
Widget* widget = new OwnershipTestWidget(state());
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget = CreatePlatformNativeWidgetImpl(
widget, kStubCapture, &state()->native_widget_deleted);
widget->Init(std::move(params));
widget->CloseNow();
EXPECT_TRUE(state()->widget_deleted);
EXPECT_TRUE(state()->native_widget_deleted);
}
TEST_F(NativeWidgetOwnsWidgetTest, NonDesktopWidget_Close) {
NativeWidgetDestroyedWaiter waiter(state());
Widget* widget = new OwnershipTestWidget(state());
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget = CreatePlatformNativeWidgetImpl(
widget, kStubCapture, waiter.GetNativeWidgetDestroyedCallback());
widget->Init(std::move(params));
widget->Close();
waiter.Wait();
EXPECT_TRUE(state()->widget_deleted);
EXPECT_TRUE(state()->native_widget_deleted);
}
#if BUILDFLAG(ENABLE_DESKTOP_AURA)
TEST_F(NativeWidgetOwnsWidgetTest, DesktopWidget_Close) {
NativeWidgetDestroyedWaiter waiter(state());
Widget* widget = new OwnershipTestWidget(state());
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget = CreatePlatformDesktopNativeWidgetImpl(
widget, kStubCapture, waiter.GetNativeWidgetDestroyedCallback());
widget->Init(std::move(params));
widget->Close();
waiter.Wait();
EXPECT_TRUE(state()->widget_deleted);
EXPECT_TRUE(state()->native_widget_deleted);
}
#endif
#if BUILDFLAG(ENABLE_DESKTOP_AURA)
TEST_F(NativeWidgetOwnsWidgetTest, DesktopWidget_CloseNow) {
NativeWidgetDestroyedWaiter waiter(state());
Widget* widget = new OwnershipTestWidget(state());
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget = CreatePlatformDesktopNativeWidgetImpl(
widget, kStubCapture, waiter.GetNativeWidgetDestroyedCallback());
widget->Init(std::move(params));
widget->CloseNow();
waiter.Wait();
EXPECT_TRUE(state()->widget_deleted);
EXPECT_TRUE(state()->native_widget_deleted);
}
#endif
TEST_F(NativeWidgetOwnsWidgetTest, NonDestkopWidget_CloseNowParent) {
NativeWidgetDestroyedWaiter waiter(state());
Widget* toplevel = CreateTopLevelPlatformWidget();
Widget* widget = new OwnershipTestWidget(state());
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.parent = toplevel->GetNativeView();
params.native_widget = CreatePlatformNativeWidgetImpl(
widget, kStubCapture, waiter.GetNativeWidgetDestroyedCallback());
widget->Init(std::move(params));
toplevel->CloseNow();
waiter.Wait();
EXPECT_TRUE(state()->widget_deleted);
EXPECT_TRUE(state()->native_widget_deleted);
}
#if BUILDFLAG(ENABLE_DESKTOP_AURA)
TEST_F(NativeWidgetOwnsWidgetTest, DestkopWidget_CloseNowParent) {
NativeWidgetDestroyedWaiter waiter(state());
Widget* toplevel = CreateTopLevelPlatformDesktopWidget();
Widget* widget = new OwnershipTestWidget(state());
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.parent = toplevel->GetNativeView();
params.native_widget = CreatePlatformDesktopNativeWidgetImpl(
widget, kStubCapture, waiter.GetNativeWidgetDestroyedCallback());
widget->Init(std::move(params));
toplevel->CloseNow();
waiter.Wait();
EXPECT_TRUE(state()->widget_deleted);
EXPECT_TRUE(state()->native_widget_deleted);
}
#endif
TEST_F(NativeWidgetOwnsWidgetTest, NonDesktopWidget_NativeDestroy) {
Widget* widget = new OwnershipTestWidget(state());
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget = CreatePlatformNativeWidgetImpl(
widget, kStubCapture, &state()->native_widget_deleted);
widget->Init(std::move(params));
SimulateNativeDestroy(widget);
EXPECT_TRUE(state()->widget_deleted);
EXPECT_TRUE(state()->native_widget_deleted);
}
#if BUILDFLAG(ENABLE_DESKTOP_AURA)
TEST_F(NativeWidgetOwnsWidgetTest, DesktopWidget_NativeDestroy) {
NativeWidgetDestroyedWaiter waiter(state());
Widget* widget = new OwnershipTestWidget(state());
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget = CreatePlatformDesktopNativeWidgetImpl(
widget, kStubCapture, waiter.GetNativeWidgetDestroyedCallback());
widget->Init(std::move(params));
SimulateDesktopNativeDestroy(widget);
waiter.Wait();
EXPECT_TRUE(state()->widget_deleted);
EXPECT_TRUE(state()->native_widget_deleted);
}
#endif
using WidgetOwnsNativeWidgetTest = WidgetOwnershipTest;
TEST_F(WidgetOwnsNativeWidgetTest, Ownership) {
auto widget = std::make_unique<OwnershipTestWidget>(state());
Widget::InitParams params = CreateParamsForTestWidget();
params.native_widget = CreatePlatformNativeWidgetImpl(
widget.get(), kStubCapture, &state()->native_widget_deleted);
widget->Init(std::move(params));
widget.reset();
}
TEST_F(WidgetOwnsNativeWidgetTest, DestroyParentView) {
Widget* toplevel = CreateTopLevelPlatformWidget();
auto widget = std::make_unique<OwnershipTestWidget>(state());
Widget::InitParams params = CreateParamsForTestWidget();
params.parent = toplevel->GetNativeView();
params.native_widget = CreatePlatformNativeWidgetImpl(
widget.get(), kStubCapture, &state()->native_widget_deleted);
widget->Init(std::move(params));
toplevel->CloseNow();
RunPendingMessages();
EXPECT_FALSE(state()->widget_deleted);
EXPECT_FALSE(state()->native_widget_deleted);
}
TEST_F(WidgetOwnsNativeWidgetTest, WidgetDelegateView) {
auto widget = std::make_unique<OwnershipTestWidget>(state());
Widget::InitParams params = CreateParamsForTestWidget();
params.native_widget = CreatePlatformNativeWidgetImpl(
widget.get(), kStubCapture, &state()->native_widget_deleted);
params.delegate = new WidgetDelegateView();
widget->Init(std::move(params));
}
TEST_F(WidgetOwnsNativeWidgetTest, IdempotentCloseNow) {
auto widget = std::make_unique<OwnershipTestWidget>(state());
Widget::InitParams params = CreateParamsForTestWidget();
params.native_widget = CreatePlatformNativeWidgetImpl(
widget.get(), kStubCapture, &state()->native_widget_deleted);
widget->Init(std::move(params));
widget->CloseNow();
RunPendingMessages();
widget->CloseNow();
RunPendingMessages();
}
TEST_F(WidgetOwnsNativeWidgetTest, IdempotentClose) {
auto widget = std::make_unique<OwnershipTestWidget>(state());
Widget::InitParams params = CreateParamsForTestWidget();
params.native_widget = CreatePlatformNativeWidgetImpl(
widget.get(), kStubCapture, &state()->native_widget_deleted);
widget->Init(std::move(params));
widget->Close();
RunPendingMessages();
widget->Close();
RunPendingMessages();
}
using ClientOwnsWidgetTest = WidgetOwnershipTest;
TEST_F(ClientOwnsWidgetTest, Ownership) {
auto widget = std::make_unique<OwnershipTestWidget>(state());
Widget::InitParams params = CreateParamsForTestWidget();
params.native_widget = CreatePlatformNativeWidgetImpl(
widget.get(), kStubCapture, &state()->native_widget_deleted);
params.ownership = Widget::InitParams::CLIENT_OWNS_WIDGET;
widget->Init(std::move(params));
widget->CloseNow();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(state()->native_widget_deleted);
}
class WidgetWithDestroyedNativeViewOrNativeWidgetTest
: public ViewsTestBase,
public testing::WithParamInterface<
std::tuple<ViewsTestBase::NativeWidgetType,
Widget::InitParams::Ownership>> {
public:
WidgetWithDestroyedNativeViewOrNativeWidgetTest() = default;
WidgetWithDestroyedNativeViewOrNativeWidgetTest(
const WidgetWithDestroyedNativeViewOrNativeWidgetTest&) = delete;
WidgetWithDestroyedNativeViewOrNativeWidgetTest& operator=(
const WidgetWithDestroyedNativeViewOrNativeWidgetTest&) = delete;
~WidgetWithDestroyedNativeViewOrNativeWidgetTest() override = default;
void SetUp() override {
set_native_widget_type(
std::get<ViewsTestBase::NativeWidgetType>(GetParam()));
ViewsTestBase::SetUp();
if (std::get<Widget::InitParams::Ownership>(GetParam()) ==
Widget::InitParams::CLIENT_OWNS_WIDGET) {
widget_ = std::make_unique<Widget>();
Widget::InitParams params = CreateParamsForTestWidget();
params.ownership = Widget::InitParams::CLIENT_OWNS_WIDGET;
widget_->Init(std::move(params));
} else {
widget_ = CreateTestWidget();
}
widget()->Show();
widget()->native_widget_private()->CloseNow();
task_environment()->RunUntilIdle();
}
Widget* widget() { return widget_.get(); }
static std::string PrintTestName(
const ::testing::TestParamInfo<
WidgetWithDestroyedNativeViewOrNativeWidgetTest::ParamType>& info) {
std::string test_name;
switch (std::get<ViewsTestBase::NativeWidgetType>(info.param)) {
case ViewsTestBase::NativeWidgetType::kDefault:
test_name += "DefaultNativeWidget";
break;
case ViewsTestBase::NativeWidgetType::kDesktop:
test_name += "DesktopNativeWidget";
break;
}
test_name += "_";
switch (std::get<Widget::InitParams::Ownership>(info.param)) {
case Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET:
test_name += "WidgetOwnsNativeWidget";
break;
case Widget::InitParams::CLIENT_OWNS_WIDGET:
test_name += "ClientOwnsNativeWidget";
break;
case Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET:
test_name += "NativeWidgetOwnsWidget";
break;
}
return test_name;
}
private:
std::unique_ptr<Widget> widget_;
};
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, Activate) {
widget()->Activate();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, AddAndRemoveObserver) {
TestWidgetObserver observer(widget());
widget()->RemoveObserver(&observer);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
AddAndRemoveRemovalsObserver) {
TestWidgetRemovalsObserver removals_observer;
widget()->AddRemovalsObserver(&removals_observer);
widget()->RemoveRemovalsObserver(&removals_observer);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, AsWidget) {
widget()->AsWidget();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, CanActivate) {
widget()->CanActivate();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, CenterWindow) {
widget()->CenterWindow(gfx::Size());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, ClearNativeFocus) {
widget()->ClearNativeFocus();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, ClientView) {
widget()->client_view();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, Close) {
widget()->Close();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
CloseAllSecondaryWidgets) {
widget()->CloseAllSecondaryWidgets();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, CloseNow) {
widget()->CloseNow();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, ClosedReason) {
widget()->closed_reason();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, CloseWithReason) {
widget()->CloseWithReason(views::Widget::ClosedReason::kUnspecified);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
CreateNonClientFrameView) {
widget()->CreateNonClientFrameView();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, Deactivate) {
widget()->Deactivate();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, DebugToggleFrameType) {
widget()->DebugToggleFrameType();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, DraggedView) {
widget()->dragged_view();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, EndMoveLoop) {
widget()->EndMoveLoop();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, ExecuteCommand) {
widget()->ExecuteCommand(0);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, FlashFrame) {
widget()->FlashFrame(true);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, FrameType) {
widget()->frame_type();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, FrameTypeChanged) {
widget()->FrameTypeChanged();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetAccelerator) {
ui::Accelerator accelerator;
widget()->GetAccelerator(0, &accelerator);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetAllChildWidgets) {
views::Widget::Widgets widgets;
Widget::GetAllChildWidgets(widget()->GetNativeView(), &widgets);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetAllOwnedWidgets) {
views::Widget::Widgets widgets;
Widget::GetAllOwnedWidgets(widget()->GetNativeView(), &widgets);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetAndSetZOrderLevel) {
widget()->SetZOrderLevel(ui::ZOrderLevel::kNormal);
widget()->GetZOrderLevel();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
GetClientAreaBoundsInScreen) {
widget()->GetClientAreaBoundsInScreen();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetColorProvider) {
widget()->GetColorProvider();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetCompositor) {
widget()->GetCompositor();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetContentsView) {
widget()->GetContentsView();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetCustomTheme) {
widget()->GetCustomTheme();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetEventSink) {
widget()->GetEventSink();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetFocusSearch) {
widget()->GetFocusSearch();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetFocusManager) {
widget()->GetFocusManager();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetFocusTraversable) {
widget()->GetFocusTraversable();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetGestureConsumer) {
widget()->GetGestureConsumer();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetGestureRecognizer) {
widget()->GetGestureRecognizer();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetHitTestMask) {
SkPath mask;
widget()->GetHitTestMask(&mask);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetInputMethod) {
widget()->GetInputMethod();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetLayer) {
widget()->GetLayer();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetMinimumSize) {
widget()->GetMinimumSize();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetMaximumSize) {
widget()->GetMaximumSize();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetName) {
widget()->GetName();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetNativeTheme) {
widget()->GetNativeTheme();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetNativeView) {
widget()->GetNativeView();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetNativeWindow) {
widget()->GetNativeWindow();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
GetNativeWindowProperty) {
widget()->GetNativeWindowProperty("xx");
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetNonClientComponent) {
gfx::Point point;
widget()->GetNonClientComponent(point);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
GetPrimaryWindowWidget) {
widget()->GetPrimaryWindowWidget();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetRestoredBounds) {
widget()->GetRestoredBounds();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetRootView) {
widget()->GetRootView();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetSublevelManager) {
widget()->GetSublevelManager();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetThemeProvider) {
widget()->GetThemeProvider();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetTooltipManager) {
widget()->GetTooltipManager();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetTopLevelWidget) {
widget()->GetTopLevelWidget();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
GetTopLevelWidgetForNativeView) {
Widget::GetTopLevelWidgetForNativeView(widget()->GetNativeView());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetWeakPtr) {
widget()->GetWeakPtr();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
GetWidgetForNativeView) {
Widget::GetWidgetForNativeView(widget()->GetNativeView());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
GetWidgetForNativeWindow) {
Widget::GetWidgetForNativeWindow(widget()->GetNativeWindow());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
GetWindowBoundsInScreen) {
widget()->GetWindowBoundsInScreen();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
GetWorkAreaBoundsInScreen) {
widget()->GetWorkAreaBoundsInScreen();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetWorkspace) {
widget()->GetWorkspace();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, GetZOrderSublevel) {
widget()->GetZOrderSublevel();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, HasCapture) {
widget()->HasCapture();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, HasFocusManager) {
widget()->HasFocusManager();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, HasHitTestMask) {
widget()->HasHitTestMask();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, HasObserver) {
TestWidgetObserver observer(widget());
widget()->HasObserver(&observer);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, HasRemovalsObserver) {
TestWidgetRemovalsObserver observer;
widget()->HasRemovalsObserver(&observer);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, Hide) {
widget()->Hide();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, Init) {
Widget::InitParams params;
EXPECT_DCHECK_DEATH(widget()->Init(std::move(params)));
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, is_secondary_widget) {
widget()->is_secondary_widget();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, IsActive) {
widget()->IsActive();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, IsClosed) {
widget()->IsClosed();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, IsDialogBox) {
widget()->IsDialogBox();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, IsFullscreen) {
widget()->IsFullscreen();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, IsMaximized) {
widget()->IsMaximized();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, IsMinimized) {
widget()->IsMinimized();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, IsModal) {
widget()->IsModal();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, IsMouseEventsEnabled) {
widget()->IsMouseEventsEnabled();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, IsMoveLoopSupported) {
widget()->IsMoveLoopSupported();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
IsNativeWidgetInitialized) {
widget()->IsNativeWidgetInitialized();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, IsStackedAbove) {
std::unique_ptr<Widget> other_widget = CreateTestWidget();
widget()->IsStackedAbove(other_widget->GetNativeView());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
IsTranslucentWindowOpacitySupported) {
widget()->IsTranslucentWindowOpacitySupported();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, IsVisible) {
widget()->IsVisible();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
IsVisibleOnAllWorkspaces) {
widget()->IsVisibleOnAllWorkspaces();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, OnGestureEvent) {
ui::GestureEvent event =
CreateTestGestureEvent(ui::ET_GESTURE_SCROLL_BEGIN, 5, 5);
widget()->OnGestureEvent(&event);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, OnKeyEvent) {
ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_RIGHT, ui::EF_NONE);
widget()->OnKeyEvent(&event);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, OnMouseCaptureLost) {
widget()->OnMouseCaptureLost();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, OnMouseEvent) {
gfx::Point p(200, 200);
ui::MouseEvent event(ui::ET_MOUSE_MOVED, p, p, ui::EventTimeForNow(),
ui::EF_NONE, ui::EF_NONE);
widget()->OnMouseEvent(&event);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, OnNativeBlur) {
widget()->OnNativeBlur();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, OnNativeFocus) {
widget()->OnNativeFocus();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, OnNativeThemeUpdated) {
ui::TestNativeTheme theme;
widget()->OnNativeThemeUpdated(&theme);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
OnNativeWidgetActivationChanged) {
widget()->OnNativeWidgetActivationChanged(false);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
OnNativeWidgetAddedToCompositor) {
widget()->OnNativeWidgetAddedToCompositor();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
OnNativeWidgetBeginUserBoundsChange) {
widget()->OnNativeWidgetBeginUserBoundsChange();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, OnNativeWidgetCreated) {
EXPECT_DCHECK_DEATH(widget()->OnNativeWidgetCreated());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
OnNativeWidgetDestroyed) {
widget()->OnNativeWidgetDestroyed();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
OnNativeWidgetDestroying) {
EXPECT_DCHECK_DEATH(widget()->OnNativeWidgetDestroying());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
OnNativeWidgetEndUserBoundsChange) {
widget()->OnNativeWidgetEndUserBoundsChange();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, OnNativeWidgetMove) {
widget()->OnNativeWidgetMove();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, OnNativeWidgetPaint) {
auto display_list = base::MakeRefCounted<cc::DisplayItemList>();
widget()->OnNativeWidgetPaint(
ui::PaintContext(display_list.get(), 1, gfx::Rect(), false));
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
OnNativeWidgetParentChanged) {
widget()->OnNativeWidgetParentChanged(nullptr);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
OnNativeWidgetRemovingFromCompositor) {
widget()->OnNativeWidgetRemovingFromCompositor();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
OnNativeWidgetSizeChanged) {
widget()->OnNativeWidgetSizeChanged(gfx::Size());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
OnNativeWidgetVisibilityChanged) {
widget()->OnNativeWidgetVisibilityChanged(false);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
OnNativeWidgetWindowShowStateChanged) {
widget()->OnNativeWidgetWindowShowStateChanged();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
OnNativeWidgetWorkspaceChanged) {
widget()->OnNativeWidgetWorkspaceChanged();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, OnOwnerClosing) {
widget()->OnOwnerClosing();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
OnParentShouldPaintAsActiveChanged) {
widget()->OnParentShouldPaintAsActiveChanged();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, OnScrollEvent) {
ui::ScrollEvent scroll(ui::ET_SCROLL, gfx::Point(65, 5),
ui::EventTimeForNow(), 0, 0, 20, 0, 20, 2);
widget()->OnScrollEvent(&scroll);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
OnSizeConstraintsChanged) {
widget()->OnSizeConstraintsChanged();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, LayerTreeChanged) {
widget()->LayerTreeChanged();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
LayoutRootViewIfNecessary) {
widget()->LayoutRootViewIfNecessary();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, LockPaintAsActive) {
widget()->LockPaintAsActive();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, Maximize) {
widget()->Maximize();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, Minimize) {
widget()->Minimize();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, movement_disabled) {
widget()->movement_disabled();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, native_widget_private) {
widget()->native_widget_private();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, native_widget) {
widget()->native_widget();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, non_client_view) {
widget()->non_client_view();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
NotifyNativeViewHierarchyChanged) {
widget()->NotifyNativeViewHierarchyChanged();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
NotifyNativeViewHierarchyWillChange) {
widget()->NotifyNativeViewHierarchyWillChange();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, NotifyWillRemoveView) {
widget()->NotifyWillRemoveView(widget()->non_client_view());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, parent) {
widget()->parent();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
RegisterPaintAsActiveChangedCallback) {
auto subscription =
widget()->RegisterPaintAsActiveChangedCallback(base::DoNothing());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, ReleaseCapture) {
widget()->ReleaseCapture();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, ReorderNativeViews) {
widget()->ReorderNativeViews();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, ReparentNativeView) {
EXPECT_DCHECK_DEATH(
Widget::ReparentNativeView(widget()->GetNativeView(), nullptr));
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, Restore) {
widget()->Restore();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, RunMoveLoop) {
widget()->RunMoveLoop(gfx::Vector2d(), views::Widget::MoveLoopSource::kMouse,
views::Widget::MoveLoopEscapeBehavior::kHide);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, RunShellDrag) {
std::unique_ptr<OSExchangeData> data(std::make_unique<OSExchangeData>());
widget()->RunShellDrag(nullptr, std::move(data), gfx::Point(), 0,
ui::mojom::DragEventSource::kMouse);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, ScheduleLayout) {
widget()->ScheduleLayout();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, SchedulePaintInRect) {
widget()->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, SetAspectRatio) {
widget()->SetAspectRatio(gfx::SizeF(1.0, 1.0));
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, SetBounds) {
widget()->SetBounds(gfx::Rect(0, 0, 100, 80));
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, SetBoundsConstrained) {
widget()->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
SetCanAppearInExistingFullscreenSpaces) {
widget()->SetCanAppearInExistingFullscreenSpaces(false);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, SetCapture) {
widget()->SetCapture(widget()->GetRootView());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, SetContentsView) {
View view;
EXPECT_DCHECK_DEATH(widget()->SetContentsView(std::make_unique<View>()));
EXPECT_DCHECK_DEATH(widget()->SetContentsView(&view));
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, SetCursor) {
widget()->SetCursor(ui::Cursor());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
SetFocusTraversableParent) {
std::unique_ptr<Widget> another_widget = CreateTestWidget();
widget()->SetFocusTraversableParent(another_widget->GetFocusTraversable());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
SetFocusTraversableParentView) {
std::unique_ptr<Widget> another_widget = CreateTestWidget();
widget()->SetFocusTraversableParentView(another_widget->GetContentsView());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, SetFullscreen) {
widget()->SetFullscreen(true);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, SetInitialFocus) {
widget()->SetInitialFocus(ui::SHOW_STATE_INACTIVE);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
SetNativeWindowProperty) {
widget()->SetNativeWindowProperty("xx", widget());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, SetOpacity) {
widget()->SetOpacity(0.f);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, SetShape) {
auto rects = std::make_unique<Widget::ShapeRects>();
rects->emplace_back(40, 0, 20, 100);
rects->emplace_back(0, 40, 100, 20);
widget()->SetShape(std::move(rects));
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, SetSize) {
widget()->SetSize(gfx::Size(10, 11));
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
SetVisibilityChangedAnimationsEnabled) {
widget()->SetVisibilityChangedAnimationsEnabled(false);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
SetVisibilityAnimationDuration) {
widget()->SetVisibilityAnimationDuration(base::Seconds(1));
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
SetVisibilityAnimationTransition) {
widget()->SetVisibilityAnimationTransition(Widget::ANIMATE_BOTH);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, SetVisible) {
widget()->SetVisibilityAnimationTransition(Widget::ANIMATE_BOTH);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
SetVisibleOnAllWorkspaces) {
widget()->SetVisibleOnAllWorkspaces(true);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
ShouldDescendIntoChildForEventHandling) {
widget()->ShouldDescendIntoChildForEventHandling(nullptr, gfx::NativeView(),
nullptr, gfx::Point(0, 0));
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
ShouldHandleNativeWidgetActivationChanged) {
widget()->ShouldHandleNativeWidgetActivationChanged(true);
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, ShouldPaintAsActive) {
widget()->ShouldPaintAsActive();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, ShouldUseNativeFrame) {
widget()->ShouldUseNativeFrame();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
ShouldWindowContentsBeTransparent) {
widget()->ShouldWindowContentsBeTransparent();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, Show) {
widget()->Show();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, ShowEmojiPanel) {
widget()->ShowEmojiPanel();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, ShowInactive) {
widget()->ShowInactive();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, StackAbove) {
std::unique_ptr<Widget> another_widget = CreateTestWidget();
widget()->StackAbove(another_widget->GetNativeView());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, StackAboveWidget) {
std::unique_ptr<Widget> another_widget = CreateTestWidget();
widget()->StackAboveWidget(another_widget.get());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, StackAtTop) {
widget()->StackAtTop();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest,
SynthesizeMouseMoveEvent) {
widget()->SynthesizeMouseMoveEvent();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, ThemeChanged) {
widget()->ThemeChanged();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, UnlockPaintAsActive) {
EXPECT_DCHECK_DEATH(widget()->UnlockPaintAsActive());
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, UpdateWindowIcon) {
widget()->UpdateWindowIcon();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, UpdateWindowTitle) {
widget()->UpdateWindowTitle();
}
TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, ViewHierarchyChanged) {
widget()->ViewHierarchyChanged(
ViewHierarchyChangedDetails(true, nullptr, nullptr, nullptr));
}
INSTANTIATE_TEST_SUITE_P(
PlatformWidgetWithDestroyedNativeViewOrNativeWidgetTest,
WidgetWithDestroyedNativeViewOrNativeWidgetTest,
::testing::Combine(
::testing::Values(ViewsTestBase::NativeWidgetType::kDefault,
ViewsTestBase::NativeWidgetType::kDesktop),
::testing::Values(Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET,
Widget::InitParams::CLIENT_OWNS_WIDGET)),
WidgetWithDestroyedNativeViewOrNativeWidgetTest::PrintTestName);
class WidgetObserverTest : public WidgetTest, public WidgetObserver {
public:
WidgetObserverTest() = default;
~WidgetObserverTest() override = default;
void CloseOnNextHide(Widget* widget) { widget_to_close_on_hide_ = widget; }
void OnWidgetDestroying(Widget* widget) override {
if (active_ == widget)
active_ = nullptr;
if (widget_activated_ == widget)
widget_activated_ = nullptr;
widget_closed_ = widget;
}
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_ = nullptr;
widget_deactivated_ = widget;
}
}
void OnWidgetVisibilityChanged(Widget* widget, bool visible) override {
if (visible) {
widget_shown_ = widget;
return;
}
widget_hidden_ = widget;
if (widget_to_close_on_hide_) {
widget_to_close_on_hide_->Close();
widget_to_close_on_hide_ = nullptr;
}
}
void OnWidgetBoundsChanged(Widget* widget,
const gfx::Rect& new_bounds) override {
widget_bounds_changed_ = widget;
}
void reset() {
active_ = nullptr;
widget_closed_ = nullptr;
widget_activated_ = nullptr;
widget_deactivated_ = nullptr;
widget_shown_ = nullptr;
widget_hidden_ = nullptr;
widget_bounds_changed_ = nullptr;
}
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_; }
const Widget* widget_bounds_changed() const { return widget_bounds_changed_; }
private:
raw_ptr<Widget> active_ = nullptr;
raw_ptr<Widget> widget_closed_ = nullptr;
raw_ptr<Widget> widget_activated_ = nullptr;
raw_ptr<Widget> widget_deactivated_ = nullptr;
raw_ptr<Widget> widget_shown_ = nullptr;
raw_ptr<Widget> widget_hidden_ = nullptr;
raw_ptr<Widget> widget_bounds_changed_ = nullptr;
raw_ptr<Widget> widget_to_close_on_hide_ = nullptr;
};
#if BUILDFLAG(IS_MAC)
#define MAYBE_ActivationChange DISABLED_ActivationChange
#else
#define MAYBE_ActivationChange ActivationChange
#endif
TEST_F(WidgetObserverTest, MAYBE_ActivationChange) {
WidgetAutoclosePtr toplevel1(NewWidget());
WidgetAutoclosePtr toplevel2(NewWidget());
toplevel1->Show();
toplevel2->Show();
reset();
toplevel1->Activate();
RunPendingMessages();
EXPECT_EQ(toplevel1.get(), widget_activated());
toplevel2->Activate();
RunPendingMessages();
EXPECT_EQ(toplevel1.get(), widget_deactivated());
EXPECT_EQ(toplevel2.get(), widget_activated());
EXPECT_EQ(toplevel2.get(), active());
}
namespace {
class WidgetActivationForwarder : public TestWidgetObserver {
public:
WidgetActivationForwarder(Widget* current_active_widget,
Widget* widget_to_activate)
: TestWidgetObserver(current_active_widget),
widget_to_activate_(widget_to_activate) {}
WidgetActivationForwarder(const WidgetActivationForwarder&) = delete;
WidgetActivationForwarder& operator=(const WidgetActivationForwarder&) =
delete;
~WidgetActivationForwarder() override = default;
private:
void OnWidgetClosing(Widget* widget) override {
widget->OnNativeWidgetActivationChanged(false);
widget_to_activate_->Activate();
}
void OnWidgetActivationChanged(Widget* widget, bool active) override {
if (!active)
widget->Close();
}
raw_ptr<Widget> widget_to_activate_;
};
class WidgetCloseCounter : public TestWidgetObserver {
public:
explicit WidgetCloseCounter(Widget* widget) : TestWidgetObserver(widget) {}
WidgetCloseCounter(const WidgetCloseCounter&) = delete;
WidgetCloseCounter& operator=(const WidgetCloseCounter&) = delete;
~WidgetCloseCounter() override = default;
int close_count() const { return close_count_; }
private:
void OnWidgetClosing(Widget* widget) override { close_count_++; }
int close_count_ = 0;
};
}
TEST_F(WidgetObserverTest, CloseReentrancy) {
Widget* widget1 = CreateTopLevelPlatformWidget();
Widget* widget2 = CreateTopLevelPlatformWidget();
WidgetCloseCounter counter(widget1);
WidgetActivationForwarder focus_manager(widget1, widget2);
widget1->Close();
EXPECT_EQ(1, counter.close_count());
widget2->Close();
}
TEST_F(WidgetObserverTest, VisibilityChange) {
WidgetAutoclosePtr toplevel(CreateTopLevelPlatformWidget());
WidgetAutoclosePtr child1(NewWidget());
WidgetAutoclosePtr child2(NewWidget());
toplevel->Show();
child1->Show();
child2->Show();
reset();
child1->Hide();
EXPECT_EQ(child1.get(), widget_hidden());
child2->Hide();
EXPECT_EQ(child2.get(), widget_hidden());
child1->Show();
EXPECT_EQ(child1.get(), widget_shown());
child2->Show();
EXPECT_EQ(child2.get(), widget_shown());
}
TEST_F(WidgetObserverTest, DestroyBubble) {
ViewsDelegate::GetInstance()->set_native_widget_factory(
ViewsDelegate::NativeWidgetFactory());
WidgetAutoclosePtr anchor(CreateTopLevelPlatformWidget());
anchor->Show();
BubbleDialogDelegateView* bubble_delegate =
new TestBubbleDialogDelegateView(anchor->client_view());
{
WidgetAutoclosePtr bubble_widget(
BubbleDialogDelegateView::CreateBubble(bubble_delegate));
bubble_widget->Show();
}
anchor->Hide();
}
TEST_F(WidgetObserverTest, WidgetBoundsChanged) {
WidgetAutoclosePtr child1(NewWidget());
WidgetAutoclosePtr child2(NewWidget());
child1->OnNativeWidgetMove();
EXPECT_EQ(child1.get(), widget_bounds_changed());
child2->OnNativeWidgetMove();
EXPECT_EQ(child2.get(), widget_bounds_changed());
child1->OnNativeWidgetSizeChanged(gfx::Size());
EXPECT_EQ(child1.get(), widget_bounds_changed());
child2->OnNativeWidgetSizeChanged(gfx::Size());
EXPECT_EQ(child2.get(), widget_bounds_changed());
}
TEST_F(WidgetObserverTest, WidgetBoundsChangedNative) {
Widget* widget = new Widget();
widget->AddObserver(this);
EXPECT_FALSE(widget_bounds_changed());
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.bounds = gfx::Rect(50, 50, 100, 100);
widget->Init(std::move(params));
EXPECT_TRUE(widget_bounds_changed());
reset();
widget->SetSize(gfx::Size(160, 100));
EXPECT_FALSE(widget->IsVisible());
EXPECT_TRUE(widget_bounds_changed());
reset();
widget->SetSize(gfx::Size(160, 100));
EXPECT_FALSE(widget_bounds_changed());
reset();
widget->Show();
EXPECT_TRUE(widget->IsVisible());
EXPECT_FALSE(widget_bounds_changed());
reset();
widget->SetSize(gfx::Size(170, 100));
EXPECT_TRUE(widget_bounds_changed());
reset();
widget->SetSize(gfx::Size(170, 100));
EXPECT_FALSE(widget_bounds_changed());
reset();
widget->SetBounds(gfx::Rect(110, 110, 170, 100));
EXPECT_TRUE(widget_bounds_changed());
reset();
widget->SetBounds(gfx::Rect(110, 110, 170, 100));
EXPECT_FALSE(widget_bounds_changed());
reset();
widget->CloseNow();
EXPECT_FALSE(widget_bounds_changed());
}
namespace {
class MoveTrackingTestDesktopWidgetDelegate : public TestDesktopWidgetDelegate {
public:
int move_count() const { return move_count_; }
void OnWidgetMove() override { ++move_count_; }
private:
int move_count_ = 0;
};
}
class DesktopWidgetObserverTest : public WidgetObserverTest {
public:
DesktopWidgetObserverTest() = default;
DesktopWidgetObserverTest(const DesktopWidgetObserverTest&) = delete;
DesktopWidgetObserverTest& operator=(const DesktopWidgetObserverTest&) =
delete;
~DesktopWidgetObserverTest() override = default;
void SetUp() override {
set_native_widget_type(NativeWidgetType::kDesktop);
WidgetObserverTest::SetUp();
}
};
TEST_F(DesktopWidgetObserverTest, OnWidgetMovedWhenOriginChangesNative) {
MoveTrackingTestDesktopWidgetDelegate delegate;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
delegate.InitWidget(std::move(params));
Widget* widget = delegate.GetWidget();
widget->Show();
widget->SetBounds(gfx::Rect(100, 100, 300, 200));
const int moves_during_init = delegate.move_count();
widget->SetBounds(gfx::Rect(100, 100, 310, 210));
EXPECT_EQ(moves_during_init, delegate.move_count());
widget->SetBounds(gfx::Rect(110, 110, 310, 210));
EXPECT_EQ(moves_during_init + 1, delegate.move_count());
widget->SetBounds(gfx::Rect(90, 90, 330, 230));
EXPECT_EQ(moves_during_init + 2, delegate.move_count());
widget->SetBounds(gfx::Rect(90, 90, 330, 240));
EXPECT_EQ(moves_during_init + 2, delegate.move_count());
widget->SetBounds(gfx::Rect(90, 100, 330, 250));
EXPECT_EQ(moves_during_init + 3, delegate.move_count());
}
TEST_F(WidgetObserverTest, ClosingOnHiddenParent) {
WidgetAutoclosePtr parent(NewWidget());
Widget* child = CreateChildPlatformWidget(parent->GetNativeView());
TestWidgetObserver child_observer(child);
EXPECT_FALSE(parent->IsVisible());
EXPECT_FALSE(child->IsVisible());
parent->Show();
EXPECT_TRUE(parent->IsVisible());
EXPECT_TRUE(child->IsVisible());
CloseOnNextHide(child);
EXPECT_FALSE(child_observer.widget_closed());
parent->Hide();
RunPendingMessages();
EXPECT_TRUE(child_observer.widget_closed());
}
#if BUILDFLAG(IS_LINUX)
TEST_F(WidgetTest, GetWindowPlacement) {
#else
TEST_F(DesktopWidgetTest, GetWindowPlacement) {
#endif
WidgetAutoclosePtr widget;
widget.reset(CreateTopLevelNativeWidget());
gfx::Rect expected_bounds(100, 110, 200, 220);
widget->SetBounds(expected_bounds);
widget->Show();
ui::WindowShowState show_state = ui::SHOW_STATE_END;
gfx::Rect restored_bounds;
internal::NativeWidgetPrivate* native_widget =
widget->native_widget_private();
native_widget->GetWindowPlacement(&restored_bounds, &show_state);
EXPECT_EQ(expected_bounds, restored_bounds);
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
EXPECT_EQ(ui::SHOW_STATE_DEFAULT, show_state);
widget->Restore();
native_widget->GetWindowPlacement(&restored_bounds, &show_state);
#endif
EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
views::test::PropertyWaiter minimize_waiter(
base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget.get())),
true);
widget->Minimize();
EXPECT_TRUE(minimize_waiter.Wait());
native_widget->GetWindowPlacement(&restored_bounds, &show_state);
EXPECT_EQ(ui::SHOW_STATE_MINIMIZED, show_state);
EXPECT_EQ(expected_bounds, restored_bounds);
views::test::PropertyWaiter restore_waiter(
base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget.get())),
false);
widget->Restore();
EXPECT_TRUE(restore_waiter.Wait());
native_widget->GetWindowPlacement(&restored_bounds, &show_state);
EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
EXPECT_EQ(expected_bounds, restored_bounds);
expected_bounds = gfx::Rect(130, 140, 230, 250);
widget->SetBounds(expected_bounds);
native_widget->GetWindowPlacement(&restored_bounds, &show_state);
EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
EXPECT_EQ(expected_bounds, restored_bounds);
widget->SetFullscreen(true);
native_widget->GetWindowPlacement(&restored_bounds, &show_state);
#if BUILDFLAG(IS_WIN)
EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
#else
EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, show_state);
EXPECT_EQ(expected_bounds, restored_bounds);
#endif
widget->SetFullscreen(false);
native_widget->GetWindowPlacement(&restored_bounds, &show_state);
EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state);
EXPECT_EQ(expected_bounds, restored_bounds);
}
TEST_F(DesktopWidgetTest, MinimumSizeConstraints) {
TestDesktopWidgetDelegate delegate;
gfx::Size minimum_size(100, 100);
const gfx::Size smaller_size(90, 90);
delegate.set_contents_view(new StaticSizedView(minimum_size));
delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
Widget* widget = delegate.GetWidget();
widget->Show();
EXPECT_GT(delegate.initial_bounds().width(), minimum_size.width());
EXPECT_GT(delegate.initial_bounds().height(), minimum_size.height());
EXPECT_EQ(delegate.initial_bounds().size(),
widget->GetWindowBoundsInScreen().size());
EXPECT_EQ(gfx::Size(), widget->GetMaximumSize());
if (!widget->ShouldUseNativeFrame()) {
minimum_size = widget->non_client_view()
->GetWindowBoundsForClientBounds(gfx::Rect(minimum_size))
.size();
}
EXPECT_EQ(minimum_size, widget->GetMinimumSize());
EXPECT_EQ(minimum_size, GetNativeWidgetMinimumContentSize(widget));
widget->SetBounds(gfx::Rect(smaller_size));
EXPECT_EQ(minimum_size, widget->GetClientAreaBoundsInScreen().size());
widget->SetSize(smaller_size);
EXPECT_EQ(minimum_size, widget->GetClientAreaBoundsInScreen().size());
}
#if BUILDFLAG(ENABLE_DESKTOP_AURA)
TEST_F(DesktopWidgetTest, GetPossiblyDestroyedParent) {
WidgetAutoclosePtr root(CreateTopLevelNativeWidget());
const auto create_widget = [](Widget* parent, bool is_desktop) {
Widget* widget = new Widget;
Widget::InitParams init_params(Widget::InitParams::TYPE_WINDOW);
init_params.parent = parent->GetNativeView();
init_params.context = parent->GetNativeView();
if (is_desktop) {
init_params.native_widget =
new test::TestPlatformNativeWidget<DesktopNativeWidgetAura>(
widget, false, nullptr);
} else {
init_params.native_widget =
new test::TestPlatformNativeWidget<NativeWidgetAura>(widget, false,
nullptr);
}
widget->Init(std::move(init_params));
return widget;
};
WidgetAutoclosePtr child(create_widget(root.get(), false));
WidgetAutoclosePtr grandchild(create_widget(child.get(), true));
child.reset();
EXPECT_EQ(grandchild->parent(), nullptr);
}
#endif
TEST_F(WidgetTest, GetWindowBoundsInScreen) {
const gfx::Rect kTestBounds(150, 150, 400, 300);
const gfx::Size kTestSize(200, 180);
{
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
widget->Show();
EXPECT_NE(kTestSize.ToString(),
widget->GetWindowBoundsInScreen().size().ToString());
widget->SetSize(kTestSize);
EXPECT_EQ(kTestSize.ToString(),
widget->GetWindowBoundsInScreen().size().ToString());
EXPECT_NE(kTestBounds.ToString(),
widget->GetWindowBoundsInScreen().ToString());
widget->SetBounds(kTestBounds);
EXPECT_EQ(kTestBounds.ToString(),
widget->GetWindowBoundsInScreen().ToString());
widget->SetSize(kTestSize);
EXPECT_EQ(kTestBounds.origin().ToString(),
widget->GetWindowBoundsInScreen().origin().ToString());
}
WidgetAutoclosePtr widget(CreateTopLevelFramelessPlatformWidget());
widget->Show();
EXPECT_NE(kTestSize.ToString(),
widget->GetWindowBoundsInScreen().size().ToString());
widget->SetSize(kTestSize);
EXPECT_EQ(kTestSize.ToString(),
widget->GetWindowBoundsInScreen().size().ToString());
EXPECT_NE(kTestBounds.ToString(),
widget->GetWindowBoundsInScreen().ToString());
widget->SetBounds(kTestBounds);
EXPECT_EQ(kTestBounds.ToString(),
widget->GetWindowBoundsInScreen().ToString());
EXPECT_EQ(kTestBounds.ToString(),
widget->GetClientAreaBoundsInScreen().ToString());
widget->SetSize(kTestSize);
EXPECT_EQ(kTestBounds.origin().ToString(),
widget->GetWindowBoundsInScreen().origin().ToString());
}
#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
#define MAYBE_GetRestoredBounds DISABLED_GetRestoredBounds
#else
#define MAYBE_GetRestoredBounds GetRestoredBounds
#endif
TEST_F(DesktopWidgetTest, MAYBE_GetRestoredBounds) {
WidgetAutoclosePtr toplevel(CreateTopLevelNativeWidget());
toplevel->Show();
EXPECT_FALSE(toplevel->GetRestoredBounds().IsEmpty());
const gfx::Rect bounds(100, 100, 200, 200);
toplevel->SetBounds(bounds);
EXPECT_EQ(bounds, toplevel->GetWindowBoundsInScreen());
EXPECT_EQ(bounds, toplevel->GetRestoredBounds());
toplevel->Maximize();
RunPendingMessages();
#if BUILDFLAG(IS_MAC)
EXPECT_EQ(toplevel->GetWindowBoundsInScreen(), toplevel->GetRestoredBounds());
#else
EXPECT_NE(toplevel->GetWindowBoundsInScreen(), toplevel->GetRestoredBounds());
#endif
EXPECT_EQ(bounds, toplevel->GetRestoredBounds());
toplevel->Restore();
RunPendingMessages();
EXPECT_EQ(bounds, toplevel->GetWindowBoundsInScreen());
EXPECT_EQ(bounds, toplevel->GetRestoredBounds());
toplevel->SetFullscreen(true);
RunPendingMessages();
EXPECT_NE(toplevel->GetWindowBoundsInScreen(), toplevel->GetRestoredBounds());
EXPECT_EQ(bounds, toplevel->GetRestoredBounds());
toplevel->SetFullscreen(false);
RunPendingMessages();
EXPECT_EQ(bounds, toplevel->GetWindowBoundsInScreen());
EXPECT_EQ(bounds, toplevel->GetRestoredBounds());
}
TEST_F(WidgetTest, KeyboardInputEvent) {
WidgetAutoclosePtr toplevel(CreateTopLevelPlatformWidget());
View* container = toplevel->client_view();
Textfield* textfield = new Textfield();
textfield->SetText(u"some text");
container->AddChildView(textfield);
toplevel->Show();
textfield->RequestFocus();
ui::KeyEvent backspace_p(ui::ET_KEY_PRESSED, ui::VKEY_DELETE, ui::EF_NONE);
toplevel->OnKeyEvent(&backspace_p);
EXPECT_TRUE(backspace_p.stopped_propagation());
ui::KeyEvent backspace_r(ui::ET_KEY_RELEASED, ui::VKEY_DELETE, ui::EF_NONE);
toplevel->OnKeyEvent(&backspace_r);
EXPECT_FALSE(backspace_r.handled());
}
TEST_F(WidgetTest, BubbleControlsResetOnInit) {
WidgetAutoclosePtr anchor(CreateTopLevelPlatformWidget());
anchor->Show();
{
TestBubbleDialogDelegateView* bubble_delegate =
new TestBubbleDialogDelegateView(anchor->client_view());
WidgetAutoclosePtr bubble_widget(
BubbleDialogDelegateView::CreateBubble(bubble_delegate));
EXPECT_TRUE(bubble_delegate->reset_controls_called_);
bubble_widget->Show();
}
anchor->Hide();
}
#if BUILDFLAG(IS_WIN)
TEST_F(DesktopWidgetTest, TestViewWidthAfterMinimizingWidget) {
std::unique_ptr<Widget> widget =
CreateTestWidget(Widget::InitParams::TYPE_WINDOW);
NonClientView* non_client_view = widget->non_client_view();
non_client_view->SetFrameView(
std::make_unique<MinimumSizeFrameView>(widget.get()));
non_client_view->InvalidateLayout();
views::test::RunScheduledLayout(non_client_view);
widget->Show();
EXPECT_NE(0, non_client_view->frame_view()->width());
widget->Minimize();
EXPECT_EQ(0, non_client_view->frame_view()->width());
}
#endif
class DesktopAuraTestValidPaintWidget : public Widget, public WidgetObserver {
public:
explicit DesktopAuraTestValidPaintWidget(Widget::InitParams init_params)
: Widget(std::move(init_params)) {
observation_.Observe(this);
}
DesktopAuraTestValidPaintWidget(const DesktopAuraTestValidPaintWidget&) =
delete;
DesktopAuraTestValidPaintWidget& operator=(
const DesktopAuraTestValidPaintWidget&) = delete;
~DesktopAuraTestValidPaintWidget() override = default;
bool ReadReceivedPaintAndReset() {
return std::exchange(received_paint_, false);
}
bool received_paint_while_hidden() const {
return received_paint_while_hidden_;
}
void WaitUntilPaint() {
if (received_paint_)
return;
base::RunLoop runloop;
quit_closure_ = runloop.QuitClosure();
runloop.Run();
quit_closure_.Reset();
}
void OnWidgetDestroying(Widget* widget) override { expect_paint_ = false; }
void OnNativeWidgetPaint(const ui::PaintContext& context) override {
received_paint_ = true;
EXPECT_TRUE(expect_paint_);
if (!expect_paint_)
received_paint_while_hidden_ = true;
views::Widget::OnNativeWidgetPaint(context);
if (!quit_closure_.is_null())
std::move(quit_closure_).Run();
}
void OnWidgetVisibilityChanged(Widget* widget, bool visible) override {
expect_paint_ = visible;
}
private:
bool received_paint_ = false;
bool expect_paint_ = true;
bool received_paint_while_hidden_ = false;
base::OnceClosure quit_closure_;
base::ScopedObservation<Widget, WidgetObserver> observation_{this};
};
class DesktopAuraPaintWidgetTest : public DesktopWidgetTest {
public:
std::unique_ptr<views::Widget> CreateTestWidget(
views::Widget::InitParams::Type type =
views::Widget::InitParams::TYPE_WINDOW_FRAMELESS) override {
auto widget = std::make_unique<DesktopAuraTestValidPaintWidget>(
CreateParamsForTestWidget(type));
paint_widget_ = widget.get();
View* contents_view =
widget->SetContentsView(std::make_unique<ContentsView>());
contents_view->SetFocusBehavior(View::FocusBehavior::ALWAYS);
widget->Show();
widget->Activate();
return widget;
}
DesktopAuraTestValidPaintWidget* paint_widget() { return paint_widget_; }
private:
class ContentsView : public View {
void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
node_data->SetNameExplicitlyEmpty();
node_data->role = ax::mojom::Role::kDialog;
}
};
raw_ptr<DesktopAuraTestValidPaintWidget> paint_widget_ = nullptr;
};
TEST_F(DesktopAuraPaintWidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) {
std::unique_ptr<Widget> widget = CreateTestWidget();
paint_widget()->WaitUntilPaint();
EXPECT_TRUE(paint_widget()->ReadReceivedPaintAndReset());
widget->SchedulePaintInRect(widget->GetRestoredBounds());
widget->Close();
RunPendingMessages();
EXPECT_FALSE(paint_widget()->ReadReceivedPaintAndReset());
EXPECT_FALSE(paint_widget()->received_paint_while_hidden());
}
TEST_F(DesktopAuraPaintWidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) {
std::unique_ptr<Widget> widget = CreateTestWidget();
paint_widget()->WaitUntilPaint();
EXPECT_TRUE(paint_widget()->ReadReceivedPaintAndReset());
widget->SchedulePaintInRect(widget->GetRestoredBounds());
widget->Hide();
RunPendingMessages();
EXPECT_FALSE(paint_widget()->ReadReceivedPaintAndReset());
EXPECT_FALSE(paint_widget()->received_paint_while_hidden());
widget->Close();
}
TEST_F(DesktopWidgetTest, TestWindowVisibilityAfterHide) {
std::unique_ptr<Widget> widget =
CreateTestWidget(Widget::InitParams::TYPE_WINDOW);
NonClientView* non_client_view = widget->non_client_view();
non_client_view->SetFrameView(
std::make_unique<MinimumSizeFrameView>(widget.get()));
widget->Show();
EXPECT_TRUE(IsNativeWindowVisible(widget->GetNativeWindow()));
widget->Hide();
EXPECT_FALSE(IsNativeWindowVisible(widget->GetNativeWindow()));
widget->Show();
EXPECT_TRUE(IsNativeWindowVisible(widget->GetNativeWindow()));
}
TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
EventCountView* cursor_view = new EventCountView;
cursor_view->SetBounds(60, 0, 50, 40);
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
widget->GetRootView()->AddChildView(cursor_view);
ui::ScrollEvent scroll(ui::ET_SCROLL, gfx::Point(65, 5),
ui::EventTimeForNow(), 0, 0, 20, 0, 20, 2);
widget->OnScrollEvent(&scroll);
EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL));
EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
cursor_view->ResetCounts();
ui::ScrollEvent scroll2(ui::ET_SCROLL, gfx::Point(5, 5),
ui::EventTimeForNow(), 0, 0, 20, 0, 20, 2);
widget->OnScrollEvent(&scroll2);
EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL));
EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_MOUSEWHEEL));
}
TEST_F(WidgetTest, GestureScrollEventDispatching) {
EventCountView* noscroll_view = new EventCountView;
EventCountView* scroll_view = new ScrollableEventCountView;
noscroll_view->SetBounds(0, 0, 50, 40);
scroll_view->SetBounds(60, 0, 40, 40);
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
widget->GetRootView()->AddChildView(noscroll_view);
widget->GetRootView()->AddChildView(scroll_view);
{
ui::GestureEvent begin =
CreateTestGestureEvent(ui::ET_GESTURE_SCROLL_BEGIN, 5, 5);
widget->OnGestureEvent(&begin);
ui::GestureEvent update = CreateTestGestureEvent(
ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10), 25, 15);
widget->OnGestureEvent(&update);
ui::GestureEvent end =
CreateTestGestureEvent(ui::ET_GESTURE_SCROLL_END, 25, 15);
widget->OnGestureEvent(&end);
EXPECT_EQ(1, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
EXPECT_EQ(0, noscroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
}
{
ui::GestureEvent begin =
CreateTestGestureEvent(ui::ET_GESTURE_SCROLL_BEGIN, 65, 5);
widget->OnGestureEvent(&begin);
ui::GestureEvent update = CreateTestGestureEvent(
ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 20, 10), 85, 15);
widget->OnGestureEvent(&update);
ui::GestureEvent end =
CreateTestGestureEvent(ui::ET_GESTURE_SCROLL_END, 85, 15);
widget->OnGestureEvent(&end);
EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_GESTURE_SCROLL_END));
}
}
TEST_F(WidgetTest, EventHandlersOnRootView) {
WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
View* root_view = widget->GetRootView();
EventCountView* view =
root_view->AddChildView(std::make_unique<EventCountView>());
view->SetBounds(0, 0, 20, 20);
EventCountHandler h1;
root_view->AddPreTargetHandler(&h1);
EventCountHandler h2;
root_view->AddPostTargetHandler(&h2);
widget->SetBounds(gfx::Rect(0, 0, 100, 100));
widget->Show();
ui::ScrollEvent scroll(ui::ET_SCROLL, gfx::Point(5, 5), ui::EventTimeForNow(),
0, 0, 20, 0, 20, 2);
widget->OnScrollEvent(&scroll);
EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL));
EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL));
EXPECT_EQ(1, h1.GetEventCount(ui::ET_MOUSEWHEEL));
EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSEWHEEL));
EXPECT_EQ(1, h2.GetEventCount(ui::ET_MOUSEWHEEL));
h1.ResetCounts();
view->ResetCounts();
h2.ResetCounts();
ui::ScrollEvent fling(ui::ET_SCROLL_FLING_START, gfx::Point(5, 5),
ui::EventTimeForNow(), 0, 0, 20, 0, 20, 2);
widget->OnScrollEvent(&fling);
EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL_FLING_START));
EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL_FLING_START));
EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL_FLING_START));
EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
h1.ResetCounts();
view->ResetCounts();
h2.ResetCounts();
view->set_handle_mode(EventCountView::CONSUME_EVENTS);
ui::GestureEvent tap_down =
CreateTestGestureEvent(ui::ET_GESTURE_TAP_DOWN, 5, 5);
widget->OnGestureEvent(&tap_down);
EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_DOWN));
ui::GestureEvent tap_cancel =
CreateTestGestureEvent(ui::ET_GESTURE_TAP_CANCEL, 5, 5);
widget->OnGestureEvent(&tap_cancel);
EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
h1.ResetCounts();
view->ResetCounts();
h2.ResetCounts();
ui::ScrollEvent consumed_scroll(ui::ET_SCROLL, gfx::Point(5, 5),
ui::EventTimeForNow(), 0, 0, 20, 0, 20, 2);
widget->OnScrollEvent(&consumed_scroll);
EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
EXPECT_EQ(0, h2.GetEventCount(ui::ET_SCROLL));
EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
root_view->RemovePreTargetHandler(&h1);
}
TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
View* root_view = widget->GetRootView();
widget->SetBounds(gfx::Rect(0, 0, 100, 100));
EventCountView* v1 =
root_view->AddChildView(std::make_unique<EventCountView>());
v1->SetBounds(5, 5, 10, 10);
EventCountView* v2 =
root_view->AddChildView(std::make_unique<EventCountView>());
v2->SetBounds(5, 15, 10, 10);
widget->Show();
widget->SynthesizeMouseMoveEvent();
EXPECT_EQ(0, v1->GetEventCount(ui::ET_MOUSE_MOVED));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_MOVED));
gfx::Point cursor_location(v1->GetBoundsInScreen().CenterPoint());
auto generator =
CreateEventGenerator(GetContext(), widget->GetNativeWindow());
generator->MoveMouseTo(cursor_location);
EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_MOVED));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_MOVED));
widget->SynthesizeMouseMoveEvent();
EXPECT_EQ(2, v1->GetEventCount(ui::ET_MOUSE_MOVED));
root_view->RemoveChildViewT(v1);
EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_MOVED));
v2->SetBounds(5, 5, 10, 10);
EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_MOVED));
widget->SynthesizeMouseMoveEvent();
EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_MOVED));
}
namespace {
class MousePressEventConsumer : public ui::EventHandler {
public:
MousePressEventConsumer() = default;
MousePressEventConsumer(const MousePressEventConsumer&) = delete;
MousePressEventConsumer& operator=(const MousePressEventConsumer&) = delete;
private:
void OnMouseEvent(ui::MouseEvent* event) override {
if (event->type() == ui::ET_MOUSE_PRESSED)
event->SetHandled();
}
};
}
#if !BUILDFLAG(IS_MAC) || defined(USE_AURA)
TEST_F(WidgetTest, MouseEventDispatchWhileTouchIsDown) {
Widget* widget = CreateTopLevelNativeWidget();
widget->Show();
widget->SetSize(gfx::Size(300, 300));
EventCountView* event_count_view =
widget->GetRootView()->AddChildView(std::make_unique<EventCountView>());
event_count_view->SetBounds(0, 0, 300, 300);
MousePressEventConsumer consumer;
event_count_view->AddPostTargetHandler(&consumer);
auto generator =
CreateEventGenerator(GetContext(), widget->GetNativeWindow());
generator->PressTouch();
generator->ClickLeftButton();
EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED));
EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_RELEASED));
widget->CloseNow();
}
#endif
TEST_F(WidgetTest, MousePressCausesCapture) {
Widget* widget = CreateTopLevelNativeWidget();
widget->Show();
widget->SetSize(gfx::Size(300, 300));
EventCountView* event_count_view =
widget->GetRootView()->AddChildView(std::make_unique<EventCountView>());
event_count_view->SetBounds(0, 0, 300, 300);
EXPECT_EQ(
gfx::kNullNativeView,
internal::NativeWidgetPrivate::GetGlobalCapture(widget->GetNativeView()));
MousePressEventConsumer consumer;
event_count_view->AddPostTargetHandler(&consumer);
auto generator =
CreateEventGenerator(GetContext(), widget->GetNativeWindow());
generator->MoveMouseTo(widget->GetClientAreaBoundsInScreen().CenterPoint());
generator->PressLeftButton();
EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED));
EXPECT_EQ(
widget->GetNativeView(),
internal::NativeWidgetPrivate::GetGlobalCapture(widget->GetNativeView()));
widget->CloseNow();
}
namespace {
class CaptureEventConsumer : public ui::EventHandler {
public:
explicit CaptureEventConsumer(Widget* widget)
: event_count_view_(new EventCountView()), widget_(widget) {}
CaptureEventConsumer(const CaptureEventConsumer&) = delete;
CaptureEventConsumer& operator=(const CaptureEventConsumer&) = delete;
~CaptureEventConsumer() override { widget_->CloseNow(); }
private:
void OnMouseEvent(ui::MouseEvent* event) override {
if (event->type() == ui::ET_MOUSE_PRESSED) {
event->SetHandled();
widget_->Show();
widget_->SetSize(gfx::Size(200, 200));
event_count_view_->SetBounds(0, 0, 200, 200);
widget_->GetRootView()->AddChildView(event_count_view_.get());
widget_->SetCapture(event_count_view_);
}
}
raw_ptr<EventCountView> event_count_view_;
raw_ptr<Widget> widget_;
};
}
TEST_F(WidgetTest, CaptureDuringMousePressNotOverridden) {
Widget* widget = CreateTopLevelNativeWidget();
widget->Show();
widget->SetSize(gfx::Size(300, 300));
EventCountView* event_count_view =
widget->GetRootView()->AddChildView(std::make_unique<EventCountView>());
event_count_view->SetBounds(0, 0, 300, 300);
EXPECT_EQ(
gfx::kNullNativeView,
internal::NativeWidgetPrivate::GetGlobalCapture(widget->GetNativeView()));
Widget* widget2 = CreateTopLevelNativeWidget();
CaptureEventConsumer consumer(widget2);
event_count_view->AddPostTargetHandler(&consumer);
auto generator =
CreateEventGenerator(GetRootWindow(widget), widget->GetNativeWindow());
generator->MoveMouseTo(widget->GetClientAreaBoundsInScreen().CenterPoint());
generator->PressLeftButton();
EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED));
EXPECT_NE(
widget->GetNativeView(),
internal::NativeWidgetPrivate::GetGlobalCapture(widget->GetNativeView()));
EXPECT_EQ(
widget2->GetNativeView(),
internal::NativeWidgetPrivate::GetGlobalCapture(widget->GetNativeView()));
widget->CloseNow();
}
class ClosingEventObserver : public ui::EventObserver {
public:
explicit ClosingEventObserver(Widget* widget) : widget_(widget) {}
ClosingEventObserver(const ClosingEventObserver&) = delete;
ClosingEventObserver& operator=(const ClosingEventObserver&) = delete;
void OnEvent(const ui::Event& event) override {
if (widget_)
widget_->CloseNow();
widget_ = nullptr;
}
private:
raw_ptr<Widget> widget_;
};
class ClosingView : public View {
public:
explicit ClosingView(Widget* widget) : widget_(widget) {}
ClosingView(const ClosingView&) = delete;
ClosingView& operator=(const ClosingView&) = delete;
void OnEvent(ui::Event* event) override {
if (widget_ && event->type() == ui::ET_MOUSE_PRESSED) {
Widget* widget = widget_;
widget_ = nullptr;
widget->CloseNow();
}
}
private:
raw_ptr<Widget> widget_;
};
TEST_F(WidgetTest, DestroyedWithCaptureViaEventMonitor) {
Widget* widget = CreateTopLevelNativeWidget();
TestWidgetObserver observer(widget);
widget->Show();
widget->SetSize(gfx::Size(300, 300));
ClosingView* closing_view = widget->GetContentsView()->AddChildView(
std::make_unique<ClosingView>(widget));
widget->SetCapture(closing_view);
ClosingEventObserver closing_event_observer(widget);
auto monitor = EventMonitor::CreateApplicationMonitor(
&closing_event_observer, widget->GetNativeWindow(),
{ui::ET_MOUSE_PRESSED});
auto generator =
CreateEventGenerator(GetContext(), widget->GetNativeWindow());
generator->set_target(ui::test::EventGenerator::Target::APPLICATION);
EXPECT_FALSE(observer.widget_closed());
generator->PressLeftButton();
EXPECT_TRUE(observer.widget_closed());
}
TEST_F(WidgetTest, LockPaintAsActive) {
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
widget->ShowInactive();
EXPECT_FALSE(widget->ShouldPaintAsActive());
auto lock = widget->LockPaintAsActive();
EXPECT_TRUE(widget->ShouldPaintAsActive());
auto lock2 = widget->LockPaintAsActive();
EXPECT_TRUE(widget->ShouldPaintAsActive());
lock2.reset();
EXPECT_TRUE(widget->ShouldPaintAsActive());
lock.reset();
EXPECT_FALSE(widget->ShouldPaintAsActive());
}
TEST_F(WidgetTest, LockPaintAsActive_AlreadyActive) {
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
widget->Show();
EXPECT_TRUE(widget->ShouldPaintAsActive());
auto lock = widget->LockPaintAsActive();
EXPECT_TRUE(widget->ShouldPaintAsActive());
lock.reset();
EXPECT_TRUE(widget->ShouldPaintAsActive());
}
TEST_F(WidgetTest, LockPaintAsActive_BecomesActive) {
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
widget->ShowInactive();
EXPECT_FALSE(widget->ShouldPaintAsActive());
auto lock = widget->LockPaintAsActive();
EXPECT_TRUE(widget->ShouldPaintAsActive());
widget->Activate();
lock.reset();
EXPECT_TRUE(widget->ShouldPaintAsActive());
}
class PaintAsActiveCallbackCounter {
public:
explicit PaintAsActiveCallbackCounter(Widget* widget) {
paint_as_active_subscription_ =
widget->RegisterPaintAsActiveChangedCallback(base::BindRepeating(
&PaintAsActiveCallbackCounter::Call, base::Unretained(this)));
}
void Call() { count_++; }
int CallCount() { return count_; }
private:
int count_ = 0;
base::CallbackListSubscription paint_as_active_subscription_;
};
TEST_F(WidgetTest, LockParentPaintAsActive) {
if (!PlatformStyle::kInactiveWidgetControlsAppearDisabled)
return;
WidgetAutoclosePtr parent(CreateTopLevelPlatformWidget());
WidgetAutoclosePtr child(CreateChildPlatformWidget(parent->GetNativeView()));
WidgetAutoclosePtr grandchild(
CreateChildPlatformWidget(child->GetNativeView()));
WidgetAutoclosePtr other(CreateTopLevelPlatformWidget());
child->widget_delegate()->SetCanActivate(true);
grandchild->widget_delegate()->SetCanActivate(true);
PaintAsActiveCallbackCounter parent_control(parent.get());
PaintAsActiveCallbackCounter child_control(child.get());
PaintAsActiveCallbackCounter grandchild_control(grandchild.get());
PaintAsActiveCallbackCounter other_control(other.get());
parent->Show();
EXPECT_TRUE(parent->ShouldPaintAsActive());
EXPECT_TRUE(child->ShouldPaintAsActive());
EXPECT_TRUE(grandchild->ShouldPaintAsActive());
EXPECT_FALSE(other->ShouldPaintAsActive());
EXPECT_EQ(parent_control.CallCount(), 1);
EXPECT_EQ(child_control.CallCount(), 1);
EXPECT_EQ(grandchild_control.CallCount(), 1);
EXPECT_EQ(other_control.CallCount(), 0);
other->Show();
EXPECT_FALSE(parent->ShouldPaintAsActive());
EXPECT_FALSE(child->ShouldPaintAsActive());
EXPECT_FALSE(grandchild->ShouldPaintAsActive());
EXPECT_TRUE(other->ShouldPaintAsActive());
EXPECT_EQ(parent_control.CallCount(), 2);
EXPECT_EQ(child_control.CallCount(), 2);
EXPECT_EQ(grandchild_control.CallCount(), 2);
EXPECT_EQ(other_control.CallCount(), 1);
child->Show();
EXPECT_TRUE(parent->ShouldPaintAsActive());
EXPECT_TRUE(child->ShouldPaintAsActive());
EXPECT_TRUE(grandchild->ShouldPaintAsActive());
EXPECT_FALSE(other->ShouldPaintAsActive());
EXPECT_EQ(parent_control.CallCount(), 3);
EXPECT_EQ(child_control.CallCount(), 3);
EXPECT_EQ(grandchild_control.CallCount(), 3);
EXPECT_EQ(other_control.CallCount(), 2);
other->Show();
EXPECT_FALSE(parent->ShouldPaintAsActive());
EXPECT_FALSE(child->ShouldPaintAsActive());
EXPECT_FALSE(grandchild->ShouldPaintAsActive());
EXPECT_TRUE(other->ShouldPaintAsActive());
EXPECT_EQ(parent_control.CallCount(), 4);
EXPECT_EQ(child_control.CallCount(), 4);
EXPECT_EQ(grandchild_control.CallCount(), 4);
EXPECT_EQ(other_control.CallCount(), 3);
grandchild->Show();
EXPECT_TRUE(parent->ShouldPaintAsActive());
EXPECT_TRUE(child->ShouldPaintAsActive());
EXPECT_TRUE(grandchild->ShouldPaintAsActive());
EXPECT_FALSE(other->ShouldPaintAsActive());
EXPECT_EQ(parent_control.CallCount(), 5);
EXPECT_EQ(child_control.CallCount(), 5);
EXPECT_EQ(grandchild_control.CallCount(), 5);
EXPECT_EQ(other_control.CallCount(), 4);
}
TEST_F(DesktopWidgetTest,
ClosingActiveChildDoesNotPrematurelyPaintParentInactive) {
auto top_level_widget = CreateTestWidget();
top_level_widget->Show();
auto bubble_widget = std::make_unique<Widget>();
Widget::InitParams init_params =
CreateParamsForTestWidget(Widget::InitParams::TYPE_BUBBLE);
init_params.parent = top_level_widget->GetNativeView();
bubble_widget->Init(std::move(init_params));
bubble_widget->Show();
EXPECT_TRUE(bubble_widget->ShouldPaintAsActive());
EXPECT_TRUE(top_level_widget->ShouldPaintAsActive());
PaintAsActiveCallbackCounter top_level_counter(top_level_widget.get());
PaintAsActiveCallbackCounter bubble_counter(bubble_widget.get());
bubble_widget->Close();
EXPECT_FALSE(bubble_widget->ShouldPaintAsActive());
EXPECT_TRUE(top_level_widget->ShouldPaintAsActive());
EXPECT_EQ(top_level_counter.CallCount(), 0);
EXPECT_EQ(bubble_counter.CallCount(), 0);
}
class TestNativeWidgetDestroyedWidget : public Widget {
public:
void OnNativeWidgetDestroyed() override;
};
void TestNativeWidgetDestroyedWidget::OnNativeWidgetDestroyed() {
Widget::OnNativeWidgetDestroyed();
delete this;
}
TEST_F(DesktopWidgetTest, WidgetDestroyedItselfDoesNotCrash) {
TestDesktopWidgetDelegate delegate(new TestNativeWidgetDestroyedWidget);
delegate.InitWidget(CreateParamsForTestWidget());
delegate.GetWidget()->Show();
delegate.GetWidget()->CloseNow();
}
TEST_F(DesktopWidgetTest, SingleWindowClosing) {
TestDesktopWidgetDelegate delegate;
delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
EXPECT_EQ(0, delegate.window_closing_count());
delegate.GetWidget()->CloseNow();
EXPECT_EQ(1, delegate.window_closing_count());
}
TEST_F(DesktopWidgetTest, CloseRequested_AllowsClose) {
constexpr Widget::ClosedReason kReason = Widget::ClosedReason::kLostFocus;
TestDesktopWidgetDelegate delegate;
delegate.set_can_close(true);
delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
WidgetDestroyedWaiter waiter(delegate.GetWidget());
delegate.GetWidget()->CloseWithReason(kReason);
EXPECT_TRUE(delegate.GetWidget()->IsClosed());
EXPECT_EQ(kReason, delegate.GetWidget()->closed_reason());
EXPECT_EQ(kReason, delegate.last_closed_reason());
waiter.Wait();
}
TEST_F(DesktopWidgetTest, CloseRequested_DisallowClose) {
constexpr Widget::ClosedReason kReason = Widget::ClosedReason::kLostFocus;
TestDesktopWidgetDelegate delegate;
delegate.set_can_close(false);
delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
delegate.GetWidget()->CloseWithReason(kReason);
EXPECT_FALSE(delegate.GetWidget()->IsClosed());
EXPECT_EQ(Widget::ClosedReason::kUnspecified,
delegate.GetWidget()->closed_reason());
EXPECT_EQ(kReason, delegate.last_closed_reason());
delegate.GetWidget()->CloseNow();
}
TEST_F(DesktopWidgetTest, CloseRequested_SecondCloseIgnored) {
constexpr Widget::ClosedReason kReason1 = Widget::ClosedReason::kLostFocus;
constexpr Widget::ClosedReason kReason2 = Widget::ClosedReason::kUnspecified;
TestDesktopWidgetDelegate delegate;
delegate.set_can_close(true);
delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
WidgetDestroyedWaiter waiter(delegate.GetWidget());
delegate.GetWidget()->CloseWithReason(kReason1);
EXPECT_TRUE(delegate.GetWidget()->IsClosed());
EXPECT_EQ(kReason1, delegate.last_closed_reason());
delegate.GetWidget()->CloseWithReason(kReason2);
EXPECT_TRUE(delegate.GetWidget()->IsClosed());
EXPECT_EQ(kReason1, delegate.last_closed_reason());
waiter.Wait();
}
class WidgetWindowTitleTest : public DesktopWidgetTest {
protected:
void RunTest(bool desktop_native_widget) {
WidgetAutoclosePtr widget(new Widget());
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
if (!desktop_native_widget) {
init_params.native_widget =
CreatePlatformNativeWidgetImpl(widget.get(), kStubCapture, nullptr);
}
widget->Init(std::move(init_params));
internal::NativeWidgetPrivate* native_widget =
widget->native_widget_private();
std::u16string empty;
std::u16string s1(u"Title1");
std::u16string s2(u"Title2");
std::u16string s3(u"TitleLong");
EXPECT_FALSE(native_widget->SetWindowTitle(empty));
EXPECT_TRUE(native_widget->SetWindowTitle(s1));
EXPECT_TRUE(native_widget->SetWindowTitle(s2));
EXPECT_TRUE(native_widget->SetWindowTitle(s3));
EXPECT_FALSE(native_widget->SetWindowTitle(s3));
}
};
TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
bool desktop_native_widget = false;
RunTest(desktop_native_widget);
}
TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
bool desktop_native_widget = true;
RunTest(desktop_native_widget);
}
TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
Widget* widget = new Widget;
Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_POPUP);
widget->Init(std::move(params));
widget->SetContentsView(
std::make_unique<CloseWidgetView>(ui::ET_MOUSE_PRESSED));
widget->SetSize(gfx::Size(100, 100));
widget->Show();
auto generator =
CreateEventGenerator(GetContext(), widget->GetNativeWindow());
WidgetDeletionObserver deletion_observer(widget);
generator->PressLeftButton();
if (deletion_observer.IsWidgetAlive())
generator->ReleaseLeftButton();
EXPECT_FALSE(deletion_observer.IsWidgetAlive());
}
#if !BUILDFLAG(IS_MAC) || defined(USE_AURA)
TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) {
Widget* widget = new Widget;
Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_POPUP);
widget->Init(std::move(params));
widget->SetContentsView(
std::make_unique<CloseWidgetView>(ui::ET_GESTURE_TAP_DOWN));
widget->SetSize(gfx::Size(100, 100));
widget->Show();
auto generator =
CreateEventGenerator(GetContext(), widget->GetNativeWindow());
WidgetDeletionObserver deletion_observer(widget);
generator->GestureTapAt(widget->GetWindowBoundsInScreen().CenterPoint());
EXPECT_FALSE(deletion_observer.IsWidgetAlive());
}
#endif
class GetNativeThemeFromDestructorView : public WidgetDelegateView {
public:
GetNativeThemeFromDestructorView() = default;
GetNativeThemeFromDestructorView(const GetNativeThemeFromDestructorView&) =
delete;
GetNativeThemeFromDestructorView& operator=(
const GetNativeThemeFromDestructorView&) = delete;
~GetNativeThemeFromDestructorView() override { VerifyNativeTheme(); }
private:
void VerifyNativeTheme() { ASSERT_TRUE(GetNativeTheme() != nullptr); }
};
bool RunGetNativeThemeFromDestructor(Widget::InitParams params,
bool is_first_run) {
bool needs_second_run = false;
WidgetTest::WidgetAutoclosePtr widget(new Widget);
params.delegate = new GetNativeThemeFromDestructorView;
if (!is_first_run) {
params.native_widget =
CreatePlatformNativeWidgetImpl(widget.get(), kStubCapture, nullptr);
needs_second_run = true;
}
widget->Init(std::move(params));
return needs_second_run;
}
TEST_F(DesktopWidgetTest, GetNativeThemeFromDestructor) {
if (RunGetNativeThemeFromDestructor(
CreateParams(Widget::InitParams::TYPE_POPUP), true)) {
RunGetNativeThemeFromDestructor(
CreateParams(Widget::InitParams::TYPE_POPUP), false);
}
}
class CloseDestroysWidget : public Widget {
public:
CloseDestroysWidget(bool* destroyed, base::OnceClosure quit_closure)
: destroyed_(destroyed), quit_closure_(std::move(quit_closure)) {
DCHECK(destroyed_);
DCHECK(quit_closure_);
}
CloseDestroysWidget(const CloseDestroysWidget&) = delete;
CloseDestroysWidget& operator=(const CloseDestroysWidget&) = delete;
~CloseDestroysWidget() override {
*destroyed_ = true;
std::move(quit_closure_).Run();
}
void Detach() { destroyed_ = nullptr; }
private:
raw_ptr<bool> destroyed_;
base::OnceClosure quit_closure_;
};
class AnimationEndObserver : public ui::ImplicitAnimationObserver {
public:
AnimationEndObserver() = default;
AnimationEndObserver(const AnimationEndObserver&) = delete;
AnimationEndObserver& operator=(const AnimationEndObserver&) = delete;
~AnimationEndObserver() override = default;
bool animation_completed() const { return animation_completed_; }
void OnImplicitAnimationsCompleted() override { animation_completed_ = true; }
private:
bool animation_completed_ = false;
};
class WidgetBoundsObserver : public WidgetObserver {
public:
WidgetBoundsObserver() = default;
WidgetBoundsObserver(const WidgetBoundsObserver&) = delete;
WidgetBoundsObserver& operator=(const WidgetBoundsObserver&) = delete;
~WidgetBoundsObserver() override = default;
gfx::Rect bounds() { return bounds_; }
void OnWidgetDestroying(Widget* widget) override {
EXPECT_TRUE(widget->GetNativeWindow());
EXPECT_TRUE(Widget::GetWidgetForNativeWindow(widget->GetNativeWindow()));
bounds_ = widget->GetWindowBoundsInScreen();
}
private:
gfx::Rect bounds_;
};
TEST_F(DesktopWidgetTest, CloseDestroys) {
bool destroyed = false;
base::RunLoop run_loop;
CloseDestroysWidget* widget =
new CloseDestroysWidget(&destroyed, run_loop.QuitClosure());
Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_MENU);
params.opacity = Widget::InitParams::WindowOpacity::kOpaque;
params.bounds = gfx::Rect(50, 50, 250, 250);
widget->Init(std::move(params));
widget->Show();
widget->Hide();
widget->Close();
EXPECT_FALSE(destroyed);
run_loop.Run();
EXPECT_TRUE(destroyed);
if (!destroyed) {
widget->Detach();
widget->CloseNow();
}
}
TEST_F(WidgetTest, CloseWidgetWhileAnimating) {
std::unique_ptr<Widget> widget = CreateTestWidget();
AnimationEndObserver animation_observer;
WidgetBoundsObserver widget_observer;
gfx::Rect bounds(100, 100, 50, 50);
{
ui::ScopedAnimationDurationScaleMode animation_scale_mode(
ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
ui::ScopedLayerAnimationSettings animation_settings(
widget->GetLayer()->GetAnimator());
animation_settings.AddObserver(&animation_observer);
widget->AddObserver(&widget_observer);
widget->Show();
widget->SetBounds(bounds);
widget.reset();
EXPECT_FALSE(animation_observer.animation_completed());
}
EXPECT_TRUE(animation_observer.animation_completed());
EXPECT_EQ(widget_observer.bounds(), bounds);
}
#if BUILDFLAG(ENABLE_DESKTOP_AURA) || BUILDFLAG(IS_MAC)
TEST_F(DesktopWidgetTest, CloseAllSecondaryWidgets) {
Widget* widget1 = CreateTopLevelNativeWidget();
Widget* widget2 = CreateTopLevelNativeWidget();
TestWidgetObserver observer1(widget1);
TestWidgetObserver observer2(widget2);
widget1->Show();
Widget::CloseAllSecondaryWidgets();
EXPECT_TRUE(observer1.widget_closed());
EXPECT_TRUE(observer2.widget_closed());
}
#endif
TEST_F(DesktopWidgetTest, ValidDuringOnNativeWidgetDestroyingFromCloseNow) {
Widget* widget = CreateTopLevelNativeWidget();
widget->Show();
gfx::Rect screen_rect(50, 50, 100, 100);
widget->SetBounds(screen_rect);
WidgetBoundsObserver observer;
widget->AddObserver(&observer);
widget->CloseNow();
EXPECT_EQ(screen_rect, observer.bounds());
}
TEST_F(DesktopWidgetTest, ValidDuringOnNativeWidgetDestroyingFromClose) {
Widget* widget = CreateTopLevelNativeWidget();
widget->Show();
gfx::Rect screen_rect(50, 50, 100, 100);
widget->SetBounds(screen_rect);
WidgetBoundsObserver observer;
widget->AddObserver(&observer);
widget->Close();
EXPECT_EQ(gfx::Rect(), observer.bounds());
base::RunLoop().RunUntilIdle();
#if !(BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
EXPECT_EQ(screen_rect, observer.bounds());
#endif
}
TEST_F(WidgetTest, NoCrashOnWidgetDelete) {
CreateTestWidget();
}
TEST_F(WidgetTest, NoCrashOnResizeConstraintsWindowTitleOnPopup) {
CreateTestWidget(Widget::InitParams::TYPE_POPUP)->OnSizeConstraintsChanged();
}
TEST_F(WidgetTest, NoCrashOnWidgetDeleteWithPendingEvents) {
std::unique_ptr<Widget> widget = CreateTestWidget();
widget->Show();
auto generator =
CreateEventGenerator(GetContext(), widget->GetNativeWindow());
generator->MoveMouseTo(10, 10);
#if BUILDFLAG(IS_MAC)
generator->ClickLeftButton();
#else
generator->PressTouch();
#endif
widget.reset();
}
class RootViewTestView : public View {
public:
RootViewTestView() = default;
private:
bool OnMousePressed(const ui::MouseEvent& event) override { return true; }
void OnGestureEvent(ui::GestureEvent* event) override {
if (event->type() == ui::ET_GESTURE_TAP_DOWN)
event->SetHandled();
}
};
#if BUILDFLAG(IS_WIN)
#define MAYBE_DisableTestRootViewHandlersWhenHidden \
DISABLED_TestRootViewHandlersWhenHidden
#else
#define MAYBE_DisableTestRootViewHandlersWhenHidden \
TestRootViewHandlersWhenHidden
#endif
TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
Widget* widget = CreateTopLevelNativeWidget();
widget->SetBounds(gfx::Rect(0, 0, 300, 300));
View* view = new RootViewTestView();
view->SetBounds(0, 0, 300, 300);
internal::RootView* root_view =
static_cast<internal::RootView*>(widget->GetRootView());
root_view->AddChildView(view);
widget->Show();
EXPECT_EQ(nullptr, GetMousePressedHandler(root_view));
gfx::Point click_location(45, 15);
ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
widget->OnMouseEvent(&press);
EXPECT_EQ(view, GetMousePressedHandler(root_view));
widget->Hide();
EXPECT_EQ(nullptr, GetMousePressedHandler(root_view));
widget->Show();
EXPECT_EQ(nullptr, GetMouseMoveHandler(root_view));
gfx::Point move_location(45, 15);
ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location,
ui::EventTimeForNow(), 0, 0);
widget->OnMouseEvent(&move);
EXPECT_EQ(view, GetMouseMoveHandler(root_view));
widget->Hide();
EXPECT_EQ(nullptr, GetMouseMoveHandler(root_view));
widget->Show();
EXPECT_EQ(nullptr, GetGestureHandler(root_view));
ui::GestureEvent tap_down =
CreateTestGestureEvent(ui::ET_GESTURE_TAP_DOWN, 15, 15);
widget->OnGestureEvent(&tap_down);
EXPECT_EQ(view, GetGestureHandler(root_view));
widget->Hide();
EXPECT_EQ(nullptr, GetGestureHandler(root_view));
widget->Close();
}
TEST_F(WidgetTest, GestureEndEvents) {
Widget* widget = CreateTopLevelNativeWidget();
widget->SetBounds(gfx::Rect(0, 0, 300, 300));
EventCountView* view = new EventCountView();
view->SetBounds(0, 0, 300, 300);
internal::RootView* root_view =
static_cast<internal::RootView*>(widget->GetRootView());
root_view->AddChildView(view);
widget->Show();
EXPECT_EQ(nullptr, GetGestureHandler(root_view));
ui::GestureEvent end = CreateTestGestureEvent(ui::ET_GESTURE_END, 15, 15);
widget->OnGestureEvent(&end);
EXPECT_EQ(nullptr, GetGestureHandler(root_view));
view->set_handle_mode(EventCountView::CONSUME_EVENTS);
ui::GestureEvent tap = CreateTestGestureEvent(ui::ET_GESTURE_TAP, 15, 15);
widget->OnGestureEvent(&tap);
EXPECT_TRUE(tap.handled());
EXPECT_EQ(view, GetGestureHandler(root_view));
ui::GestureEventDetails details(ui::ET_GESTURE_END);
details.set_touch_points(2);
ui::GestureEvent end_second_touch_point =
CreateTestGestureEvent(details, 15, 15);
widget->OnGestureEvent(&end_second_touch_point);
EXPECT_EQ(view, GetGestureHandler(root_view));
end = CreateTestGestureEvent(ui::ET_GESTURE_END, 15, 15);
widget->OnGestureEvent(&end);
EXPECT_TRUE(end.handled());
EXPECT_EQ(nullptr, GetGestureHandler(root_view));
tap = CreateTestGestureEvent(ui::ET_GESTURE_TAP, 15, 15);
widget->OnGestureEvent(&tap);
EXPECT_TRUE(tap.handled());
EXPECT_EQ(view, GetGestureHandler(root_view));
view->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
end_second_touch_point = CreateTestGestureEvent(details, 15, 15);
widget->OnGestureEvent(&end_second_touch_point);
EXPECT_EQ(view, GetGestureHandler(root_view));
end = CreateTestGestureEvent(ui::ET_GESTURE_END, 15, 15);
widget->OnGestureEvent(&end);
EXPECT_FALSE(end.handled());
EXPECT_EQ(nullptr, GetGestureHandler(root_view));
widget->Close();
}
TEST_F(WidgetTest, GestureEventsNotProcessed) {
Widget* widget = CreateTopLevelNativeWidget();
widget->SetBounds(gfx::Rect(0, 0, 300, 300));
EventCountView* v1 = new EventCountView();
v1->SetBounds(0, 0, 300, 300);
EventCountView* v2 = new EventCountView();
v2->SetBounds(0, 0, 100, 100);
EventCountView* v3 = new EventCountView();
v3->SetBounds(0, 0, 50, 50);
EventCountView* v4 = new EventCountView();
v4->SetBounds(0, 0, 10, 10);
internal::RootView* root_view =
static_cast<internal::RootView*>(widget->GetRootView());
root_view->AddChildView(v1);
v1->AddChildView(v2);
v2->AddChildView(v3);
v3->AddChildView(v4);
widget->Show();
ui::GestureEvent begin = CreateTestGestureEvent(ui::ET_GESTURE_BEGIN, 5, 5);
widget->OnGestureEvent(&begin);
EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_BEGIN));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_BEGIN));
EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_BEGIN));
EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_BEGIN));
EXPECT_EQ(nullptr, GetGestureHandler(root_view));
EXPECT_TRUE(begin.handled());
v1->ResetCounts();
v2->ResetCounts();
v3->ResetCounts();
v4->ResetCounts();
ui::GestureEvent end = CreateTestGestureEvent(ui::ET_GESTURE_END, 5, 5);
widget->OnGestureEvent(&end);
EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
EXPECT_EQ(nullptr, GetGestureHandler(root_view));
EXPECT_TRUE(end.handled());
v1->ResetCounts();
v2->ResetCounts();
v3->ResetCounts();
v4->ResetCounts();
ui::GestureEventDetails details(ui::ET_GESTURE_END);
details.set_touch_points(2);
ui::GestureEvent end_second_touch_point =
CreateTestGestureEvent(details, 5, 5);
widget->OnGestureEvent(&end_second_touch_point);
EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
EXPECT_EQ(nullptr, GetGestureHandler(root_view));
EXPECT_TRUE(end_second_touch_point.handled());
v1->ResetCounts();
v2->ResetCounts();
v3->ResetCounts();
v4->ResetCounts();
ui::GestureEvent scroll_update =
CreateTestGestureEvent(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
widget->OnGestureEvent(&scroll_update);
EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
EXPECT_EQ(nullptr, GetGestureHandler(root_view));
EXPECT_TRUE(scroll_update.handled());
v1->ResetCounts();
v2->ResetCounts();
v3->ResetCounts();
v4->ResetCounts();
ui::GestureEvent scroll_end =
CreateTestGestureEvent(ui::ET_GESTURE_SCROLL_END, 5, 5);
widget->OnGestureEvent(&scroll_end);
EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
EXPECT_EQ(nullptr, GetGestureHandler(root_view));
EXPECT_TRUE(scroll_end.handled());
v1->ResetCounts();
v2->ResetCounts();
v3->ResetCounts();
v4->ResetCounts();
ui::GestureEvent scroll_fling_start =
CreateTestGestureEvent(ui::ET_SCROLL_FLING_START, 5, 5);
widget->OnGestureEvent(&scroll_fling_start);
EXPECT_EQ(0, v1->GetEventCount(ui::ET_SCROLL_FLING_START));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_SCROLL_FLING_START));
EXPECT_EQ(0, v3->GetEventCount(ui::ET_SCROLL_FLING_START));
EXPECT_EQ(0, v4->GetEventCount(ui::ET_SCROLL_FLING_START));
EXPECT_EQ(nullptr, GetGestureHandler(root_view));
EXPECT_TRUE(scroll_fling_start.handled());
v1->ResetCounts();
v2->ResetCounts();
v3->ResetCounts();
v4->ResetCounts();
widget->Close();
}
TEST_F(WidgetTest, GestureEventDispatch) {
Widget* widget = CreateTopLevelNativeWidget();
widget->SetBounds(gfx::Rect(0, 0, 300, 300));
EventCountView* v1 = new EventCountView();
v1->SetBounds(0, 0, 300, 300);
EventCountView* v2 = new EventCountView();
v2->SetBounds(0, 0, 100, 100);
EventCountView* v3 = new EventCountView();
v3->SetBounds(0, 0, 50, 50);
EventCountView* v4 = new EventCountView();
v4->SetBounds(0, 0, 10, 10);
internal::RootView* root_view =
static_cast<internal::RootView*>(widget->GetRootView());
root_view->AddChildView(v1);
v1->AddChildView(v2);
v2->AddChildView(v3);
v3->AddChildView(v4);
widget->Show();
ui::GestureEvent tap = CreateTestGestureEvent(ui::ET_GESTURE_TAP, 5, 5);
EXPECT_EQ(nullptr, GetGestureHandler(root_view));
widget->OnGestureEvent(&tap);
EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_EQ(nullptr, GetGestureHandler(root_view));
EXPECT_FALSE(tap.handled());
v1->ResetCounts();
v2->ResetCounts();
v3->ResetCounts();
v4->ResetCounts();
v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
v2->set_handle_mode(EventCountView::CONSUME_EVENTS);
v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
tap = CreateTestGestureEvent(ui::ET_GESTURE_TAP, 5, 5);
widget->OnGestureEvent(&tap);
EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_EQ(v3, GetGestureHandler(root_view));
EXPECT_TRUE(tap.handled());
v1->ResetCounts();
v2->ResetCounts();
v3->ResetCounts();
v4->ResetCounts();
v4->set_handle_mode(EventCountView::CONSUME_EVENTS);
tap = CreateTestGestureEvent(ui::ET_GESTURE_TAP, 5, 5);
widget->OnGestureEvent(&tap);
EXPECT_TRUE(tap.handled());
ui::GestureEvent show_press =
CreateTestGestureEvent(ui::ET_GESTURE_SHOW_PRESS, 5, 5);
widget->OnGestureEvent(&show_press);
tap = CreateTestGestureEvent(ui::ET_GESTURE_TAP, 5, 5);
widget->OnGestureEvent(&tap);
EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_EQ(2, v3->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SHOW_PRESS));
EXPECT_TRUE(tap.handled());
EXPECT_TRUE(show_press.handled());
EXPECT_EQ(v3, GetGestureHandler(root_view));
v1->ResetCounts();
v2->ResetCounts();
v3->ResetCounts();
v4->ResetCounts();
v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
tap = CreateTestGestureEvent(ui::ET_GESTURE_TAP, 5, 5);
widget->OnGestureEvent(&tap);
EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_FALSE(tap.handled());
EXPECT_EQ(v3, GetGestureHandler(root_view));
widget->Close();
}
TEST_F(WidgetTest, ScrollGestureEventDispatch) {
Widget* widget = CreateTopLevelNativeWidget();
widget->SetBounds(gfx::Rect(0, 0, 300, 300));
EventCountView* v1 = new EventCountView();
v1->SetBounds(0, 0, 300, 300);
EventCountView* v2 = new EventCountView();
v2->SetBounds(0, 0, 100, 100);
EventCountView* v3 = new EventCountView();
v3->SetBounds(0, 0, 50, 50);
EventCountView* v4 = new EventCountView();
v4->SetBounds(0, 0, 10, 10);
internal::RootView* root_view =
static_cast<internal::RootView*>(widget->GetRootView());
root_view->AddChildView(v1);
v1->AddChildView(v2);
v2->AddChildView(v3);
v3->AddChildView(v4);
widget->Show();
v3->set_handle_mode(EventCountView::CONSUME_EVENTS);
EXPECT_EQ(nullptr, GetGestureHandler(root_view));
ui::GestureEvent tap_down =
CreateTestGestureEvent(ui::ET_GESTURE_TAP_DOWN, 5, 5);
widget->OnGestureEvent(&tap_down);
EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP_DOWN));
EXPECT_EQ(v3, GetGestureHandler(root_view));
EXPECT_TRUE(tap_down.handled());
v1->ResetCounts();
v2->ResetCounts();
v3->ResetCounts();
v4->ResetCounts();
ui::GestureEvent tap_cancel =
CreateTestGestureEvent(ui::ET_GESTURE_TAP_CANCEL, 5, 5);
widget->OnGestureEvent(&tap_cancel);
EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP_CANCEL));
EXPECT_EQ(v3, GetGestureHandler(root_view));
EXPECT_TRUE(tap_cancel.handled());
v1->ResetCounts();
v2->ResetCounts();
v3->ResetCounts();
v4->ResetCounts();
v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS);
v1->set_handle_mode(EventCountView::CONSUME_EVENTS);
ui::GestureEvent scroll_begin =
CreateTestGestureEvent(ui::ET_GESTURE_SCROLL_BEGIN, 5, 5);
widget->OnGestureEvent(&scroll_begin);
EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
EXPECT_EQ(1, v2->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
EXPECT_EQ(1, v3->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_BEGIN));
EXPECT_EQ(v1, GetGestureHandler(root_view));
EXPECT_TRUE(scroll_begin.handled());
v1->ResetCounts();
v2->ResetCounts();
v3->ResetCounts();
v4->ResetCounts();
ui::GestureEvent scroll_update =
CreateTestGestureEvent(ui::ET_GESTURE_SCROLL_UPDATE, 5, 5);
widget->OnGestureEvent(&scroll_update);
EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_UPDATE));
EXPECT_EQ(v1, GetGestureHandler(root_view));
EXPECT_TRUE(scroll_update.handled());
v1->ResetCounts();
v2->ResetCounts();
v3->ResetCounts();
v4->ResetCounts();
ui::GestureEvent scroll_end =
CreateTestGestureEvent(ui::ET_GESTURE_SCROLL_END, 5, 5);
widget->OnGestureEvent(&scroll_end);
EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_SCROLL_END));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_SCROLL_END));
EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_SCROLL_END));
EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_SCROLL_END));
EXPECT_EQ(v1, GetGestureHandler(root_view));
EXPECT_TRUE(scroll_end.handled());
v1->ResetCounts();
v2->ResetCounts();
v3->ResetCounts();
v4->ResetCounts();
ui::GestureEvent pinch_begin =
CreateTestGestureEvent(ui::ET_GESTURE_PINCH_BEGIN, 5, 5);
widget->OnGestureEvent(&pinch_begin);
EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_PINCH_BEGIN));
EXPECT_EQ(v1, GetGestureHandler(root_view));
EXPECT_TRUE(pinch_begin.handled());
v1->ResetCounts();
v2->ResetCounts();
v3->ResetCounts();
v4->ResetCounts();
ui::GestureEvent end = CreateTestGestureEvent(ui::ET_GESTURE_END, 5, 5);
widget->OnGestureEvent(&end);
EXPECT_EQ(1, v1->GetEventCount(ui::ET_GESTURE_END));
EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END));
EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END));
EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END));
EXPECT_EQ(nullptr, GetGestureHandler(root_view));
EXPECT_TRUE(end.handled());
widget->Close();
}
#if !BUILDFLAG(IS_MAC)
TEST_F(WidgetTest, NotifyDragControllerWhenDragWillStart) {
UniqueWidgetPtr widget(std::make_unique<Widget>());
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.bounds = gfx::Rect(650, 650);
widget->Init(std::move(params));
widget->Show();
MockDragController mock_drag_controller;
views::View contents_view;
contents_view.set_drag_controller(&mock_drag_controller);
widget->SetContentsView(&contents_view);
EXPECT_CALL(mock_drag_controller, OnWillStartDragForView(&contents_view));
ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
generator.MoveMouseTo(contents_view.GetBoundsInScreen().CenterPoint());
generator.PressLeftButton();
generator.MoveMouseBy(200, 0);
generator.ReleaseLeftButton();
}
#endif
class GestureLocationView : public EventCountView {
public:
GestureLocationView() = default;
GestureLocationView(const GestureLocationView&) = delete;
GestureLocationView& operator=(const GestureLocationView&) = delete;
~GestureLocationView() override = default;
void set_expected_location(gfx::Point expected_location) {
expected_location_ = expected_location;
}
void OnGestureEvent(ui::GestureEvent* event) override {
EventCountView::OnGestureEvent(event);
EXPECT_EQ(expected_location_, event->location());
}
private:
gfx::Point expected_location_;
};
TEST_F(WidgetTest, GestureEventLocationWhileBubbling) {
Widget* widget = CreateTopLevelNativeWidget();
widget->SetBounds(gfx::Rect(0, 0, 300, 300));
GestureLocationView* v1 = new GestureLocationView();
v1->SetBounds(50, 50, 150, 150);
GestureLocationView* v2 = new GestureLocationView();
v2->SetBounds(50, 20, 50, 80);
GestureLocationView* v3 = new GestureLocationView();
v3->SetBounds(20, 30, 10, 10);
internal::RootView* root_view =
static_cast<internal::RootView*>(widget->GetRootView());
root_view->AddChildView(v1);
v1->AddChildView(v2);
v2->AddChildView(v3);
widget->Show();
gfx::Point location_in_root(125, 105);
ui::GestureEvent tap = CreateTestGestureEvent(
ui::ET_GESTURE_TAP, location_in_root.x(), location_in_root.y());
gfx::Point location_in_v1(ConvertPointFromWidgetToView(v1, location_in_root));
EXPECT_EQ(gfx::Point(75, 55), location_in_v1);
gfx::Point location_in_v2(ConvertPointFromWidgetToView(v2, location_in_root));
EXPECT_EQ(gfx::Point(25, 35), location_in_v2);
gfx::Point location_in_v3(ConvertPointFromWidgetToView(v3, location_in_root));
EXPECT_EQ(gfx::Point(5, 5), location_in_v3);
v1->set_expected_location(location_in_v1);
v2->set_expected_location(location_in_v2);
v3->set_expected_location(location_in_v3);
widget->OnGestureEvent(&tap);
EXPECT_EQ(location_in_root, tap.location());
EventCountView* view1 = v1;
EventCountView* view2 = v2;
EventCountView* view3 = v3;
EXPECT_EQ(1, view1->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_EQ(1, view2->GetEventCount(ui::ET_GESTURE_TAP));
EXPECT_EQ(1, view3->GetEventCount(ui::ET_GESTURE_TAP));
widget->Close();
}
TEST_F(WidgetTest, GetAllChildWidgets) {
WidgetAutoclosePtr toplevel(CreateTopLevelPlatformWidget());
Widget* w1 = CreateChildPlatformWidget(toplevel->GetNativeView());
Widget* w11 = CreateChildPlatformWidget(w1->GetNativeView());
Widget* w2 = CreateChildPlatformWidget(toplevel->GetNativeView());
Widget* w21 = CreateChildPlatformWidget(w2->GetNativeView());
Widget* w22 = CreateChildPlatformWidget(w2->GetNativeView());
std::set<Widget*> expected;
expected.insert(toplevel.get());
expected.insert(w1);
expected.insert(w11);
expected.insert(w2);
expected.insert(w21);
expected.insert(w22);
std::set<Widget*> child_widgets;
Widget::GetAllChildWidgets(toplevel->GetNativeView(), &child_widgets);
EXPECT_TRUE(base::ranges::equal(expected, child_widgets));
EXPECT_EQ(1u, expected.erase(toplevel.get()));
std::set<Widget*> owned_widgets;
Widget::GetAllOwnedWidgets(toplevel->GetNativeView(), &owned_widgets);
EXPECT_TRUE(base::ranges::equal(expected, owned_widgets));
}
class DestroyedTrackingView : public View {
public:
DestroyedTrackingView(const std::string& name,
std::vector<std::string>* add_to)
: name_(name), add_to_(add_to) {}
DestroyedTrackingView(const DestroyedTrackingView&) = delete;
DestroyedTrackingView& operator=(const DestroyedTrackingView&) = delete;
~DestroyedTrackingView() override { add_to_->push_back(name_); }
private:
const std::string name_;
raw_ptr<std::vector<std::string>> add_to_;
};
class WidgetChildDestructionTest : public DesktopWidgetTest {
public:
WidgetChildDestructionTest() = default;
WidgetChildDestructionTest(const WidgetChildDestructionTest&) = delete;
WidgetChildDestructionTest& operator=(const WidgetChildDestructionTest&) =
delete;
void RunDestroyChildWidgetsTest(bool top_level_has_desktop_native_widget_aura,
bool child_has_desktop_native_widget_aura) {
std::vector<std::string> destroyed;
Widget* top_level = new Widget;
Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_WINDOW);
if (!top_level_has_desktop_native_widget_aura) {
params.native_widget =
CreatePlatformNativeWidgetImpl(top_level, kStubCapture, nullptr);
}
top_level->Init(std::move(params));
top_level->GetRootView()->AddChildView(
new DestroyedTrackingView("parent", &destroyed));
top_level->Show();
Widget* child = new Widget;
Widget::InitParams child_params =
CreateParams(views::Widget::InitParams::TYPE_POPUP);
child_params.parent = top_level->GetNativeView();
if (!child_has_desktop_native_widget_aura) {
child_params.native_widget =
CreatePlatformNativeWidgetImpl(child, kStubCapture, nullptr);
}
child->Init(std::move(child_params));
child->GetRootView()->AddChildView(
new DestroyedTrackingView("child", &destroyed));
child->Show();
top_level->native_widget_private()->CloseNow();
ASSERT_EQ(2u, destroyed.size());
EXPECT_EQ("child", destroyed[0]);
EXPECT_EQ("parent", destroyed[1]);
}
};
TEST_F(WidgetChildDestructionTest,
DestroyChildWidgetsInOrderWithDesktopNativeWidget) {
RunDestroyChildWidgetsTest(true, false);
}
TEST_F(WidgetChildDestructionTest,
DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) {
RunDestroyChildWidgetsTest(true, true);
}
TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
RunDestroyChildWidgetsTest(false, false);
}
TEST_F(WidgetTest, FullscreenStatePropagated) {
std::unique_ptr<Widget> top_level_widget = CreateTestWidget();
top_level_widget->SetFullscreen(true);
EXPECT_EQ(top_level_widget->IsVisible(),
IsNativeWindowVisible(top_level_widget->GetNativeWindow()));
}
TEST_F(DesktopWidgetTest, FullscreenStatePropagated_DesktopWidget) {
std::unique_ptr<Widget> top_level_widget = CreateTestWidget();
top_level_widget->SetFullscreen(true);
EXPECT_EQ(top_level_widget->IsVisible(),
IsNativeWindowVisible(top_level_widget->GetNativeWindow()));
}
class DestroyingWidgetBoundsObserver : public WidgetObserver {
public:
explicit DestroyingWidgetBoundsObserver(std::unique_ptr<Widget> widget)
: widget_(std::move(widget)) {
widget_->AddObserver(this);
}
~DestroyingWidgetBoundsObserver() override = default;
void OnWidgetBoundsChanged(Widget* widget,
const gfx::Rect& new_bounds) override {
widget_->RemoveObserver(this);
widget_.reset();
}
private:
std::unique_ptr<Widget> widget_;
};
#if BUILDFLAG(IS_MAC)
#define MAYBE_DeleteInSetFullscreen DISABLED_DeleteInSetFullscreen
#else
#define MAYBE_DeleteInSetFullscreen DeleteInSetFullscreen
#endif
TEST_F(DesktopWidgetTest, MAYBE_DeleteInSetFullscreen) {
std::unique_ptr<Widget> widget = std::make_unique<Widget>();
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget->Init(std::move(params));
Widget* w = widget.get();
DestroyingWidgetBoundsObserver destroyer(std::move(widget));
w->SetFullscreen(true);
}
namespace {
class FullscreenAwareFrame : public views::NonClientFrameView {
public:
explicit FullscreenAwareFrame(views::Widget* widget) : widget_(widget) {}
FullscreenAwareFrame(const FullscreenAwareFrame&) = delete;
FullscreenAwareFrame& operator=(const FullscreenAwareFrame&) = delete;
~FullscreenAwareFrame() override = default;
gfx::Rect GetBoundsForClientView() const override { return gfx::Rect(); }
gfx::Rect GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const override {
return gfx::Rect();
}
int NonClientHitTest(const gfx::Point& point) override { return HTNOWHERE; }
void GetWindowMask(const gfx::Size& size, SkPath* window_mask) override {}
void ResetWindowControls() override {}
void UpdateWindowIcon() override {}
void UpdateWindowTitle() override {}
void SizeConstraintsChanged() override {}
void Layout() override {
if (widget_->IsFullscreen())
fullscreen_layout_called_ = true;
}
bool fullscreen_layout_called() const { return fullscreen_layout_called_; }
private:
raw_ptr<views::Widget> widget_;
bool fullscreen_layout_called_ = false;
};
}
TEST_F(WidgetTest, FullscreenFrameLayout) {
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
auto frame_view = std::make_unique<FullscreenAwareFrame>(widget.get());
FullscreenAwareFrame* frame = frame_view.get();
widget->non_client_view()->SetFrameView(std::move(frame_view));
widget->Maximize();
RunPendingMessages();
EXPECT_FALSE(frame->fullscreen_layout_called());
widget->SetFullscreen(true);
widget->Show();
#if BUILDFLAG(IS_MAC)
EXPECT_TRUE(frame->fullscreen_layout_called());
#else
EXPECT_TRUE(ViewTestApi(frame).needs_layout());
#endif
widget->LayoutRootViewIfNecessary();
RunPendingMessages();
EXPECT_TRUE(frame->fullscreen_layout_called());
}
namespace {
class IsActiveFromDestroyObserver : public WidgetObserver {
public:
IsActiveFromDestroyObserver() = default;
IsActiveFromDestroyObserver(const IsActiveFromDestroyObserver&) = delete;
IsActiveFromDestroyObserver& operator=(const IsActiveFromDestroyObserver&) =
delete;
~IsActiveFromDestroyObserver() override = default;
void OnWidgetDestroying(Widget* widget) override { widget->IsActive(); }
};
}
class ChildDesktopWidgetTest : public DesktopWidgetTest {
public:
Widget::InitParams CreateParams(Widget::InitParams::Type type) override {
Widget::InitParams params = DesktopWidgetTest::CreateParams(type);
if (context_)
params.context = context_;
return params;
}
std::unique_ptr<Widget> CreateChildWidget(gfx::NativeWindow context) {
context_ = context;
return CreateTestWidget();
}
private:
gfx::NativeWindow context_ = nullptr;
};
TEST_F(ChildDesktopWidgetTest, IsActiveFromDestroy) {
IsActiveFromDestroyObserver observer;
std::unique_ptr<Widget> parent_widget = CreateTestWidget();
parent_widget->Show();
std::unique_ptr<Widget> child_widget =
CreateChildWidget(parent_widget->GetNativeWindow());
child_widget->AddObserver(&observer);
child_widget->Show();
parent_widget->CloseNow();
}
TEST_F(WidgetTest, MouseEventTypesViaGenerator) {
WidgetAutoclosePtr widget(CreateTopLevelFramelessPlatformWidget());
EventCountView* view =
widget->GetRootView()->AddChildView(std::make_unique<EventCountView>());
view->set_handle_mode(EventCountView::CONSUME_EVENTS);
view->SetBounds(10, 10, 50, 40);
widget->SetBounds(gfx::Rect(0, 0, 100, 80));
widget->Show();
auto generator =
CreateEventGenerator(GetContext(), widget->GetNativeWindow());
const gfx::Point view_center_point = view->GetBoundsInScreen().CenterPoint();
generator->set_current_screen_location(view_center_point);
generator->ClickLeftButton();
EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_PRESSED));
EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
generator->PressRightButton();
EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_RELEASED));
EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
generator->ReleaseRightButton();
EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_PRESSED));
EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_RELEASED));
EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, view->last_flags());
EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_MOVED));
EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_ENTERED));
generator->MoveMouseTo(view_center_point + gfx::Vector2d(10, 10));
EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_MOVED));
EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
EXPECT_EQ(ui::EF_NONE, view->last_flags());
generator->MoveMouseTo(view_center_point + gfx::Vector2d(11, 11));
EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSE_EXITED));
const gfx::Point out_of_bounds_point =
view->GetBoundsInScreen().bottom_right() + gfx::Vector2d(10, 10);
generator->MoveMouseTo(out_of_bounds_point);
EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_MOVED));
EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_ENTERED));
EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
generator->MoveMouseTo(view_center_point);
EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_MOVED));
EXPECT_EQ(2, view->GetEventCount(ui::ET_MOUSE_ENTERED));
EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_EXITED));
generator->DragMouseTo(out_of_bounds_point);
EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_PRESSED));
EXPECT_EQ(3, view->GetEventCount(ui::ET_MOUSE_RELEASED));
EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_DRAGGED));
EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, view->last_flags());
}
TEST_F(WidgetTest, NonClientWindowValidAfterInit) {
WidgetAutoclosePtr widget(CreateTopLevelFramelessPlatformWidget());
View* root_view = widget->GetRootView();
const gfx::Rect test_rect(0, 0, 500, 500);
root_view->SetBoundsRect(test_rect);
EXPECT_NE(test_rect.size(), widget->GetWindowBoundsInScreen().size());
EXPECT_EQ(test_rect, root_view->bounds());
widget->ReorderNativeViews();
EXPECT_EQ(test_rect, root_view->bounds());
}
#if BUILDFLAG(IS_WIN)
class SubclassWindowHelper {
public:
explicit SubclassWindowHelper(HWND window)
: window_(window), message_to_destroy_on_(0) {
EXPECT_EQ(instance_, nullptr);
instance_ = this;
EXPECT_TRUE(Subclass());
}
SubclassWindowHelper(const SubclassWindowHelper&) = delete;
SubclassWindowHelper& operator=(const SubclassWindowHelper&) = delete;
~SubclassWindowHelper() {
Unsubclass();
instance_ = nullptr;
}
bool received_message(unsigned int message) {
return (messages_.find(message) != messages_.end());
}
void Clear() { messages_.clear(); }
void set_message_to_destroy_on(unsigned int message) {
message_to_destroy_on_ = message;
}
private:
bool Subclass() {
old_proc_ = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(
window_, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WndProc)));
return old_proc_ != nullptr;
}
void Unsubclass() {
::SetWindowLongPtr(window_, GWLP_WNDPROC,
reinterpret_cast<LONG_PTR>(old_proc_));
}
static LRESULT CALLBACK WndProc(HWND window,
unsigned int message,
WPARAM w_param,
LPARAM l_param) {
EXPECT_NE(instance_, nullptr);
EXPECT_EQ(window, instance_->window_);
instance_->messages_.insert(message);
LRESULT ret = ::CallWindowProc(instance_->old_proc_, window, message,
w_param, l_param);
if (message == instance_->message_to_destroy_on_) {
instance_->Unsubclass();
::DestroyWindow(window);
}
return ret;
}
WNDPROC old_proc_;
HWND window_;
static SubclassWindowHelper* instance_;
std::set<unsigned int> messages_;
unsigned int message_to_destroy_on_;
};
SubclassWindowHelper* SubclassWindowHelper::instance_ = nullptr;
TEST_F(DesktopWidgetTest,
DISABLED_SysCommandMoveOnNCLButtonDownOnCaptionAndMoveTest) {
std::unique_ptr<Widget> widget =
CreateTestWidget(Widget::InitParams::TYPE_WINDOW);
widget->Show();
::SetCursorPos(500, 500);
HWND window = widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
SubclassWindowHelper subclass_helper(window);
::PostMessage(window, WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(100, 100));
RunPendingMessages();
EXPECT_TRUE(subclass_helper.received_message(WM_NCLBUTTONDOWN));
EXPECT_FALSE(subclass_helper.received_message(WM_SYSCOMMAND));
subclass_helper.Clear();
::PostMessage(window, WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(100, 100));
::PostMessage(window, WM_NCMOUSEMOVE, HTCAPTION, MAKELPARAM(100, 100));
RunPendingMessages();
EXPECT_TRUE(subclass_helper.received_message(WM_NCLBUTTONDOWN));
EXPECT_TRUE(subclass_helper.received_message(WM_NCMOUSEMOVE));
EXPECT_FALSE(subclass_helper.received_message(WM_SYSCOMMAND));
subclass_helper.Clear();
::PostMessage(window, WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(100, 100));
::PostMessage(window, WM_NCMOUSEMOVE, HTCAPTION, MAKELPARAM(110, 110));
RunPendingMessages();
EXPECT_TRUE(subclass_helper.received_message(WM_NCLBUTTONDOWN));
EXPECT_TRUE(subclass_helper.received_message(WM_NCMOUSEMOVE));
EXPECT_TRUE(subclass_helper.received_message(WM_SYSCOMMAND));
subclass_helper.Clear();
::PostMessage(window, WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(100, 100));
::PostMessage(window, WM_NCMOUSEMOVE, HTTOP, MAKELPARAM(110, 102));
RunPendingMessages();
EXPECT_TRUE(subclass_helper.received_message(WM_NCLBUTTONDOWN));
EXPECT_TRUE(subclass_helper.received_message(WM_NCMOUSEMOVE));
EXPECT_TRUE(subclass_helper.received_message(WM_SYSCOMMAND));
subclass_helper.Clear();
::PostMessage(window, WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(100, 100));
::PostMessage(window, WM_MOUSEMOVE, HTCLIENT, MAKELPARAM(110, 110));
RunPendingMessages();
EXPECT_TRUE(subclass_helper.received_message(WM_NCLBUTTONDOWN));
EXPECT_TRUE(subclass_helper.received_message(WM_MOUSEMOVE));
EXPECT_TRUE(subclass_helper.received_message(WM_SYSCOMMAND));
}
TEST_F(DesktopWidgetTest, DISABLED_DestroyInSysCommandNCLButtonDownOnCaption) {
std::unique_ptr<Widget> widget =
CreateTestWidget(Widget::InitParams::TYPE_WINDOW);
widget->Show();
::SetCursorPos(500, 500);
HWND window = widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
SubclassWindowHelper subclass_helper(window);
subclass_helper.set_message_to_destroy_on(WM_SYSCOMMAND);
::PostMessage(window, WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(100, 100));
::PostMessage(window, WM_NCMOUSEMOVE, HTCAPTION, MAKELPARAM(110, 110));
RunPendingMessages();
EXPECT_TRUE(subclass_helper.received_message(WM_NCLBUTTONDOWN));
EXPECT_TRUE(subclass_helper.received_message(WM_SYSCOMMAND));
}
#endif
TEST_F(WidgetTest, ZOrderLevel) {
WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
EXPECT_EQ(ui::ZOrderLevel::kNormal, widget->GetZOrderLevel());
widget->SetZOrderLevel(ui::ZOrderLevel::kFloatingWindow);
EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow, widget->GetZOrderLevel());
widget->SetZOrderLevel(ui::ZOrderLevel::kNormal);
EXPECT_EQ(ui::ZOrderLevel::kNormal, widget->GetZOrderLevel());
}
namespace {
class ScaleFactorView : public View {
public:
ScaleFactorView() = default;
ScaleFactorView(const ScaleFactorView&) = delete;
ScaleFactorView& operator=(const ScaleFactorView&) = delete;
void OnDeviceScaleFactorChanged(float old_device_scale_factor,
float new_device_scale_factor) override {
last_scale_factor_ = new_device_scale_factor;
View::OnDeviceScaleFactorChanged(old_device_scale_factor,
new_device_scale_factor);
}
float last_scale_factor() const { return last_scale_factor_; }
private:
float last_scale_factor_ = 0.f;
};
}
TEST_F(WidgetTest, OnDeviceScaleFactorChanged) {
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
ScaleFactorView* view = new ScaleFactorView;
widget->GetRootView()->AddChildView(view);
float scale_factor = widget->GetLayer()->device_scale_factor();
EXPECT_NE(scale_factor, 0.f);
view->OnDeviceScaleFactorChanged(0.f, scale_factor);
EXPECT_EQ(scale_factor, view->last_scale_factor());
scale_factor *= 2.0f;
widget->GetLayer()->OnDeviceScaleFactorChanged(scale_factor);
EXPECT_EQ(scale_factor, view->last_scale_factor());
}
TEST_F(WidgetTest, WidgetRemovalsObserverCalled) {
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
TestWidgetRemovalsObserver removals_observer;
widget->AddRemovalsObserver(&removals_observer);
View* parent = new View();
widget->client_view()->AddChildView(parent);
View* child = new View();
parent->AddChildView(child);
widget->client_view()->RemoveChildView(parent);
EXPECT_TRUE(removals_observer.DidRemoveView(parent));
EXPECT_FALSE(removals_observer.DidRemoveView(child));
delete parent;
widget->RemoveRemovalsObserver(&removals_observer);
}
TEST_F(WidgetTest, WidgetRemovalsObserverCalledWhenRemovingRootView) {
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
TestWidgetRemovalsObserver removals_observer;
widget->AddRemovalsObserver(&removals_observer);
views::View* root_view = widget->GetRootView();
widget.reset();
EXPECT_TRUE(removals_observer.DidRemoveView(root_view));
}
TEST_F(WidgetTest, WidgetRemovalsObserverCalledWhenMovingBetweenWidgets) {
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
TestWidgetRemovalsObserver removals_observer;
widget->AddRemovalsObserver(&removals_observer);
View* parent = new View();
widget->client_view()->AddChildView(parent);
View* child = new View();
widget->client_view()->AddChildView(child);
parent->AddChildView(child);
EXPECT_FALSE(removals_observer.DidRemoveView(child));
WidgetAutoclosePtr widget2(CreateTopLevelPlatformWidget());
widget2->client_view()->AddChildView(child);
EXPECT_TRUE(removals_observer.DidRemoveView(child));
widget->RemoveRemovalsObserver(&removals_observer);
}
TEST_F(WidgetTest, MouseWheelEvent) {
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
widget->SetBounds(gfx::Rect(0, 0, 600, 600));
EventCountView* event_count_view =
widget->client_view()->AddChildView(std::make_unique<EventCountView>());
event_count_view->SetBounds(0, 0, 600, 600);
widget->Show();
auto event_generator =
CreateEventGenerator(GetContext(), widget->GetNativeWindow());
event_generator->MoveMouseWheel(1, 1);
EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSEWHEEL));
}
class CloseFromClosingObserver : public WidgetObserver {
public:
~CloseFromClosingObserver() override {
EXPECT_TRUE(was_on_widget_closing_called_);
}
void OnWidgetClosing(Widget* widget) override {
ASSERT_FALSE(was_on_widget_closing_called_);
was_on_widget_closing_called_ = true;
widget->Close();
}
private:
bool was_on_widget_closing_called_ = false;
};
TEST_F(WidgetTest, CloseNowFollowedByCloseDoesntCallOnWidgetClosingTwice) {
CloseFromClosingObserver observer;
std::unique_ptr<Widget> widget = std::make_unique<Widget>();
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget->Init(std::move(params));
widget->AddObserver(&observer);
widget->CloseNow();
widget->RemoveObserver(&observer);
widget.reset();
}
namespace {
class TestSaveWindowPlacementWidgetDelegate : public TestDesktopWidgetDelegate {
public:
TestSaveWindowPlacementWidgetDelegate() = default;
TestSaveWindowPlacementWidgetDelegate(
const TestSaveWindowPlacementWidgetDelegate&) = delete;
TestSaveWindowPlacementWidgetDelegate operator=(
const TestSaveWindowPlacementWidgetDelegate&) = delete;
~TestSaveWindowPlacementWidgetDelegate() override = default;
void set_should_save_window_placement(bool should_save) {
should_save_window_placement_ = should_save;
}
int save_window_placement_count() const {
return save_window_placement_count_;
}
std::string GetWindowName() const final { return GetWidget()->GetName(); }
bool ShouldSaveWindowPlacement() const final {
return should_save_window_placement_;
}
void SaveWindowPlacement(const gfx::Rect& bounds,
ui::WindowShowState show_state) override {
save_window_placement_count_++;
}
private:
bool should_save_window_placement_ = true;
int save_window_placement_count_ = 0;
};
}
TEST_F(WidgetTest, ShouldSaveWindowPlacement) {
for (bool save : {false, true}) {
SCOPED_TRACE(save ? "ShouldSave" : "ShouldNotSave");
TestSaveWindowPlacementWidgetDelegate widget_delegate;
widget_delegate.set_should_save_window_placement(save);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.name = "TestWidget";
widget_delegate.InitWidget(std::move(params));
auto* widget = widget_delegate.GetWidget();
widget->Close();
EXPECT_EQ(save ? 1 : 0, widget_delegate.save_window_placement_count());
}
}
class WidgetSetAspectRatioTest
: public ViewsTestBase,
public testing::WithParamInterface<gfx::Size > {
public:
WidgetSetAspectRatioTest() : margin_(GetParam()) {}
WidgetSetAspectRatioTest(const WidgetSetAspectRatioTest&) = delete;
WidgetSetAspectRatioTest& operator=(const WidgetSetAspectRatioTest&) = delete;
~WidgetSetAspectRatioTest() override = default;
void SetUp() override {
ViewsTestBase::SetUp();
widget_ = std::make_unique<Widget>();
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
native_widget_ = std::make_unique<MockNativeWidget>(widget());
ON_CALL(*native_widget(), CreateNonClientFrameView).WillByDefault([this]() {
return std::make_unique<NonClientFrameViewWithFixedMargin>(margin());
});
params.native_widget = native_widget();
widget()->Init(std::move(params));
task_environment()->RunUntilIdle();
}
void TearDown() override {
native_widget_.reset();
widget()->Close();
widget_.reset();
ViewsTestBase::TearDown();
}
const gfx::Size& margin() const { return margin_; }
Widget* widget() { return widget_.get(); }
MockNativeWidget* native_widget() { return native_widget_.get(); }
private:
const gfx::Size margin_;
std::unique_ptr<Widget> widget_;
std::unique_ptr<MockNativeWidget> native_widget_;
class NonClientFrameViewWithFixedMargin : public NonClientFrameView {
public:
explicit NonClientFrameViewWithFixedMargin(const gfx::Size& margin)
: margin_(margin) {}
gfx::Rect GetBoundsForClientView() const override {
gfx::Rect r = bounds();
return gfx::Rect(r.x(), r.y(), r.width() - margin_.width(),
r.height() - margin_.height());
}
const gfx::Size margin_;
};
};
TEST_P(WidgetSetAspectRatioTest, SetAspectRatioIncludesMargin) {
const gfx::Rect root_view_bounds(0, 0, 100, 200);
ASSERT_GT(root_view_bounds.width(), margin().width());
ASSERT_GT(root_view_bounds.height(), margin().height());
widget()->non_client_view()->SetBoundsRect(root_view_bounds);
const gfx::SizeF aspect_ratio(1.5f, 1.0f);
EXPECT_CALL(*native_widget(), SetAspectRatio(aspect_ratio, margin()));
widget()->SetAspectRatio(aspect_ratio);
}
INSTANTIATE_TEST_SUITE_P(WidgetSetAspectRatioTestInstantiation,
WidgetSetAspectRatioTest,
::testing::Values(gfx::Size(15, 20), gfx::Size(0, 0)));
class WidgetShadowTest : public WidgetTest {
public:
WidgetShadowTest() = default;
WidgetShadowTest(const WidgetShadowTest&) = delete;
WidgetShadowTest& operator=(const WidgetShadowTest&) = delete;
~WidgetShadowTest() override = default;
void SetUp() override {
set_native_widget_type(NativeWidgetType::kDesktop);
WidgetTest::SetUp();
InitControllers();
}
void TearDown() override {
#if defined(USE_AURA) && !BUILDFLAG(ENABLE_DESKTOP_AURA)
shadow_controller_.reset();
focus_controller_.reset();
#endif
WidgetTest::TearDown();
}
Widget::InitParams CreateParams(Widget::InitParams::Type type) override {
Widget::InitParams params =
WidgetTest::CreateParams(override_type_.value_or(type));
params.shadow_type = Widget::InitParams::ShadowType::kDrop;
params.shadow_elevation = 10;
params.name = name_;
params.child = force_child_;
return params;
}
protected:
absl::optional<Widget::InitParams::Type> override_type_;
std::string name_;
bool force_child_ = false;
private:
#if BUILDFLAG(ENABLE_DESKTOP_AURA) || BUILDFLAG(IS_MAC)
void InitControllers() {}
#else
class TestFocusRules : public wm::BaseFocusRules {
public:
TestFocusRules() = default;
TestFocusRules(const TestFocusRules&) = delete;
TestFocusRules& operator=(const TestFocusRules&) = delete;
bool SupportsChildActivation(const aura::Window* window) const override {
return true;
}
};
void InitControllers() {
focus_controller_ =
std::make_unique<wm::FocusController>(new TestFocusRules);
shadow_controller_ = std::make_unique<wm::ShadowController>(
focus_controller_.get(), nullptr);
}
std::unique_ptr<wm::FocusController> focus_controller_;
std::unique_ptr<wm::ShadowController> shadow_controller_;
#endif
};
#if BUILDFLAG(IS_MAC)
#define MAYBE_ShadowsInRootWindow DISABLED_ShadowsInRootWindow
#else
#define MAYBE_ShadowsInRootWindow ShadowsInRootWindow
#endif
TEST_F(WidgetShadowTest, MAYBE_ShadowsInRootWindow) {
#if defined(USE_AURA) && !BUILDFLAG(ENABLE_DESKTOP_AURA)
bool top_level_window_should_have_shadow = true;
#else
bool top_level_window_should_have_shadow = false;
#endif
name_ = "other_top_level";
Widget* other_top_level = CreateTopLevelNativeWidget();
name_ = "top_level";
Widget* top_level = CreateTopLevelNativeWidget();
top_level->SetBounds(gfx::Rect(100, 100, 320, 200));
EXPECT_FALSE(WidgetHasInProcessShadow(top_level));
EXPECT_FALSE(top_level->IsVisible());
top_level->ShowInactive();
EXPECT_EQ(top_level_window_should_have_shadow,
WidgetHasInProcessShadow(top_level));
top_level->Show();
EXPECT_EQ(top_level_window_should_have_shadow,
WidgetHasInProcessShadow(top_level));
name_ = "control";
Widget* control = CreateChildNativeWidgetWithParent(top_level);
control->SetBounds(gfx::Rect(20, 20, 160, 100));
EXPECT_TRUE(WidgetHasInProcessShadow(control));
control->ShowInactive();
EXPECT_TRUE(WidgetHasInProcessShadow(control));
control->Show();
EXPECT_TRUE(WidgetHasInProcessShadow(control));
name_ = "child";
override_type_ = Widget::InitParams::TYPE_POPUP;
force_child_ = true;
Widget* child = CreateChildNativeWidgetWithParent(top_level);
child->SetBounds(gfx::Rect(20, 20, 160, 100));
EXPECT_FALSE(WidgetHasInProcessShadow(child));
child->ShowInactive();
EXPECT_TRUE(WidgetHasInProcessShadow(child));
child->Show();
EXPECT_TRUE(WidgetHasInProcessShadow(child));
other_top_level->Show();
top_level->Show();
EXPECT_EQ(top_level_window_should_have_shadow,
WidgetHasInProcessShadow(top_level));
top_level->Close();
other_top_level->Close();
}
#if BUILDFLAG(IS_WIN)
TEST_F(DesktopWidgetTest, WindowModalOwnerDestroyedEnabledTest) {
std::unique_ptr<Widget> top_level_widget = CreateTestWidget();
top_level_widget->Show();
const auto create_params = [this](Widget* widget, gfx::NativeView parent) {
Widget::InitParams init_params =
CreateParamsForTestWidget(Widget::InitParams::TYPE_WINDOW);
init_params.delegate = new WidgetDelegate();
init_params.delegate->SetModalType(ui::MODAL_TYPE_WINDOW);
init_params.parent = parent;
init_params.native_widget =
new test::TestPlatformNativeWidget<DesktopNativeWidgetAura>(
widget, false, nullptr);
return init_params;
};
Widget owner_dialog_widget;
owner_dialog_widget.Init(
create_params(&owner_dialog_widget, top_level_widget->GetNativeView()));
owner_dialog_widget.Show();
HWND owner_hwnd = HWNDForWidget(&owner_dialog_widget);
Widget owned_dialog_widget;
owned_dialog_widget.Init(
create_params(&owned_dialog_widget, owner_dialog_widget.GetNativeView()));
owned_dialog_widget.Show();
HWND owned_hwnd = HWNDForWidget(&owned_dialog_widget);
RunPendingMessages();
HWND top_hwnd = HWNDForWidget(top_level_widget.get());
EXPECT_FALSE(!!IsWindowEnabled(owner_hwnd));
EXPECT_FALSE(!!IsWindowEnabled(top_hwnd));
EXPECT_TRUE(!!IsWindowEnabled(owned_hwnd));
owner_dialog_widget.CloseNow();
RunPendingMessages();
EXPECT_FALSE(!!IsWindow(owner_hwnd));
EXPECT_FALSE(!!IsWindow(owned_hwnd));
EXPECT_TRUE(!!IsWindowEnabled(top_hwnd));
top_level_widget->CloseNow();
}
TEST_F(DesktopWidgetTest, StackAboveTest) {
WidgetAutoclosePtr root_one(CreateTopLevelNativeWidget());
WidgetAutoclosePtr root_two(CreateTopLevelNativeWidget());
Widget* child_one = CreateChildNativeWidgetWithParent(root_one->AsWidget());
Widget* child_one_b = CreateChildNativeWidgetWithParent(root_one->AsWidget());
Widget* child_two = CreateChildNativeWidgetWithParent(root_two->AsWidget());
Widget* grandchild_one =
CreateChildNativeWidgetWithParent(child_one->AsWidget());
Widget* grandchild_two =
CreateChildNativeWidgetWithParent(child_two->AsWidget());
root_one->ShowInactive();
child_one->ShowInactive();
child_one_b->ShowInactive();
grandchild_one->ShowInactive();
root_two->ShowInactive();
child_two->ShowInactive();
grandchild_two->ShowInactive();
EXPECT_TRUE(child_one->IsStackedAbove(root_one->GetNativeView()));
EXPECT_TRUE(child_one_b->IsStackedAbove(root_one->GetNativeView()));
EXPECT_TRUE(grandchild_one->IsStackedAbove(child_one->GetNativeView()));
EXPECT_TRUE(grandchild_two->IsStackedAbove(root_two->GetNativeView()));
EXPECT_TRUE(child_one->IsStackedAbove(child_one_b->GetNativeView()));
EXPECT_TRUE(grandchild_one->IsStackedAbove(child_one_b->GetNativeView()));
EXPECT_TRUE(root_two->IsStackedAbove(root_one->GetNativeView()));
EXPECT_TRUE(root_two->IsStackedAbove(child_one_b->GetNativeView()));
EXPECT_TRUE(child_two->IsStackedAbove(child_one_b->GetNativeView()));
EXPECT_TRUE(child_two->IsStackedAbove(grandchild_one->GetNativeView()));
EXPECT_TRUE(grandchild_two->IsStackedAbove(child_one->GetNativeView()));
EXPECT_TRUE(grandchild_two->IsStackedAbove(root_one->GetNativeView()));
EXPECT_FALSE(root_one->IsStackedAbove(grandchild_two->GetNativeView()));
EXPECT_FALSE(root_one->IsStackedAbove(grandchild_one->GetNativeView()));
EXPECT_FALSE(child_two->IsStackedAbove(grandchild_two->GetNativeView()));
EXPECT_FALSE(child_one->IsStackedAbove(grandchild_two->GetNativeView()));
EXPECT_FALSE(child_one_b->IsStackedAbove(child_two->GetNativeView()));
EXPECT_FALSE(grandchild_one->IsStackedAbove(grandchild_two->GetNativeView()));
EXPECT_FALSE(grandchild_one->IsStackedAbove(root_two->GetNativeView()));
EXPECT_FALSE(child_one_b->IsStackedAbove(grandchild_one->GetNativeView()));
}
#endif
#if BUILDFLAG(ENABLE_DESKTOP_AURA) || BUILDFLAG(IS_MAC)
namespace {
bool CanHaveCompositingManager() {
#if BUILDFLAG(IS_OZONE)
auto* const egl_utility =
ui::OzonePlatform::GetInstance()->GetPlatformGLEGLUtility();
return (egl_utility != nullptr) && egl_utility->HasVisualManager();
#else
return false;
#endif
}
bool ExpectWidgetTransparency(Widget::InitParams::WindowOpacity opacity) {
switch (opacity) {
case Widget::InitParams::WindowOpacity::kOpaque:
return false;
case Widget::InitParams::WindowOpacity::kTranslucent:
return true;
case Widget::InitParams::WindowOpacity::kInferred:
ADD_FAILURE() << "WidgetOpacity must be explicitly set";
return false;
}
}
class CompositingWidgetTest : public DesktopWidgetTest {
public:
CompositingWidgetTest()
: widget_types_{Widget::InitParams::TYPE_WINDOW,
Widget::InitParams::TYPE_WINDOW_FRAMELESS,
Widget::InitParams::TYPE_CONTROL,
Widget::InitParams::TYPE_POPUP,
Widget::InitParams::TYPE_MENU,
Widget::InitParams::TYPE_TOOLTIP,
Widget::InitParams::TYPE_BUBBLE,
Widget::InitParams::TYPE_DRAG} {}
CompositingWidgetTest(const CompositingWidgetTest&) = delete;
CompositingWidgetTest& operator=(const CompositingWidgetTest&) = delete;
~CompositingWidgetTest() override = default;
Widget::InitParams CreateParams(Widget::InitParams::Type type) override {
Widget::InitParams params = DesktopWidgetTest::CreateParams(type);
params.opacity = opacity_;
return params;
}
void CheckAllWidgetsForOpacity(
const Widget::InitParams::WindowOpacity opacity) {
opacity_ = opacity;
for (const auto& widget_type : widget_types_) {
#if BUILDFLAG(IS_MAC)
if (widget_type == Widget::InitParams::TYPE_TOOLTIP)
continue;
#elif BUILDFLAG(IS_WIN)
if (widget_type != Widget::InitParams::TYPE_WINDOW)
continue;
#endif
std::unique_ptr<Widget> widget = CreateTestWidget(widget_type);
if (widget_type == Widget::InitParams::TYPE_WINDOW_FRAMELESS ||
widget_type == Widget::InitParams::TYPE_CONTROL)
continue;
#if BUILDFLAG(IS_MAC)
bool should_be_transparent =
opacity_ == Widget::InitParams::WindowOpacity::kTranslucent;
#else
bool should_be_transparent = widget->ShouldWindowContentsBeTransparent();
#endif
EXPECT_EQ(IsNativeWindowTransparent(widget->GetNativeWindow()),
should_be_transparent);
if (CanHaveCompositingManager()) {
if (HasCompositingManager() && ExpectWidgetTransparency(opacity))
EXPECT_TRUE(widget->IsTranslucentWindowOpacitySupported());
else
EXPECT_FALSE(widget->IsTranslucentWindowOpacitySupported());
}
}
}
protected:
const std::vector<Widget::InitParams::Type> widget_types_;
Widget::InitParams::WindowOpacity opacity_ =
Widget::InitParams::WindowOpacity::kInferred;
};
}
TEST_F(CompositingWidgetTest, Transparency_DesktopWidgetOpaque) {
CheckAllWidgetsForOpacity(Widget::InitParams::WindowOpacity::kOpaque);
}
TEST_F(CompositingWidgetTest, Transparency_DesktopWidgetTranslucent) {
CheckAllWidgetsForOpacity(Widget::InitParams::WindowOpacity::kTranslucent);
}
#endif
}