#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include <cursor-shape-v1-client-protocol.h>
#include <cursor-shapes-unstable-v1-client-protocol.h>
#include <linux/input.h>
#include <wayland-server-core.h>
#include <xdg-shell-server-protocol.h>
#include <cstddef>
#include <memory>
#include <utility>
#include <vector>
#include "base/environment.h"
#include "base/files/file_util.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/nix/xdg_util.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_command_line.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
#include "ui/base/hit_test.h"
#include "ui/base/owned_window_anchor.h"
#include "ui/base/ui_base_types.h"
#include "ui/display/display.h"
#include "ui/display/scoped_display_for_new_windows.h"
#include "ui/display/test/test_screen.h"
#include "ui/display/types/display_constants.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/transform.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/overlay_plane_data.h"
#include "ui/gfx/overlay_priority_hint.h"
#include "ui/gfx/overlay_transform.h"
#include "ui/ozone/common/bitmap_cursor.h"
#include "ui/ozone/common/features.h"
#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
#include "ui/ozone/platform/wayland/host/wayland_cursor_shape.h"
#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
#include "ui/ozone/platform/wayland/host/wayland_output.h"
#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_seat.h"
#include "ui/ozone/platform/wayland/host/wayland_subsurface.h"
#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
#include "ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.h"
#include "ui/ozone/platform/wayland/mojom/wayland_overlay_config.mojom.h"
#include "ui/ozone/platform/wayland/test/mock_pointer.h"
#include "ui/ozone/platform/wayland/test/mock_surface.h"
#include "ui/ozone/platform/wayland/test/mock_wayland_platform_window_delegate.h"
#include "ui/ozone/platform/wayland/test/mock_xdg_surface.h"
#include "ui/ozone/platform/wayland/test/scoped_wl_array.h"
#include "ui/ozone/platform/wayland/test/test_keyboard.h"
#include "ui/ozone/platform/wayland/test/test_output.h"
#include "ui/ozone/platform/wayland/test/test_region.h"
#include "ui/ozone/platform/wayland/test/test_touch.h"
#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
#include "ui/ozone/platform/wayland/test/test_zaura_toplevel.h"
#include "ui/ozone/platform/wayland/test/wayland_connection_test_api.h"
#include "ui/ozone/platform/wayland/test/wayland_test.h"
#include "ui/ozone/public/ozone_switches.h"
#include "ui/platform_window/platform_window.h"
#include "ui/platform_window/platform_window_delegate.h"
#include "ui/platform_window/platform_window_init_properties.h"
#include "ui/platform_window/wm/wm_move_resize_handler.h"
#include "wayland-server-protocol.h"
#if BUILDFLAG(IS_LINUX)
#include "ui/ozone/platform/wayland/host/wayland_async_cursor.h"
#endif
_;
DoAll;
ElementsAre;
Eq;
InvokeWithoutArgs;
Mock;
Return;
SaveArg;
StrEq;
Values;
namespace ui {
namespace {
constexpr float kDefaultCursorScale = …;
constexpr uint32_t kAugmentedSurfaceNotSupportedVersion = …;
struct PopupPosition { … };
base::ScopedFD MakeFD() { … }
wl::TestXdgPopup* GetTestXdgPopupByWindow(wl::TestWaylandServerThread* server,
const uint32_t surface_id) { … }
void AddStateToWlArray(uint32_t state, wl_array* states) { … }
wl::ScopedWlArray InitializeWlArrayWithActivatedState() { … }
wl::ScopedWlArray MakeStateArray(const std::vector<int32_t> states) { … }
class MockCursorShape : public WaylandCursorShape { … };
class MockZcrCursorShapes : public WaylandZcrCursorShapes { … };
BoundsChange;
constexpr BoundsChange kDefaultBoundsChange{ … };
scoped_refptr<PlatformCursor> AsPlatformCursor(
scoped_refptr<BitmapCursor> bitmap_cursor) { … }
DispatchEventCallback;
class TestWaylandWindowDelegate : public PlatformWindowDelegate { … };
}
class WaylandWindowTest : public WaylandTest { … };
TEST_P(WaylandWindowTest, Shutdown) { … }
TEST_P(WaylandWindowTest, SetTitle) { … }
TEST_P(WaylandWindowTest, OnSequencePointConfiguresWaylandWindow) { … }
TEST_P(WaylandWindowTest, ApplyPendingStatesAndCommit) { … }
#if BUILDFLAG(IS_LINUX)
TEST_P(WaylandWindowTest, HandleTiledEdges) { … }
#endif
TEST_P(WaylandWindowTest, DisregardUnpassedWindowConfigure) { … }
TEST_P(WaylandWindowTest, MismatchedSequencePoints) { … }
TEST_P(WaylandWindowTest, OnSequencePointClearsPreviousUnackedConfigures) { … }
TEST_P(WaylandWindowTest, RestoredBoundsSetWithCorrectOrigin) { … }
TEST_P(WaylandWindowTest, MaximizeAndRestore) { … }
TEST_P(WaylandWindowTest, MaximizeAndRestoreWithInsets) { … }
TEST_P(WaylandWindowTest, ClientInitiatedMinimize) { … }
TEST_P(WaylandWindowTest, ServerInitiatedMinimize) { … }
TEST_P(WaylandWindowTest, Minimize) { … }
TEST_P(WaylandWindowTest, ServerInitiatedRestoreFromMinimizedState) { … }
TEST_P(WaylandWindowTest, SetFullscreenAndRestore) { … }
TEST_P(WaylandWindowTest, StartWithFullscreen) { … }
TEST_P(WaylandWindowTest, StartMaximized) { … }
TEST_P(WaylandWindowTest, CompositorSideStateChanges) { … }
TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) { … }
TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximize) { … }
TEST_P(WaylandWindowTest, RestoreBoundsAfterFullscreen) { … }
TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximizeAndFullscreen) { … }
TEST_P(WaylandWindowTest, SetCanMaximize) { … }
TEST_P(WaylandWindowTest, SetCanFullscreen) { … }
TEST_P(WaylandWindowTest, SendsBoundsOnRequest) { … }
TEST_P(WaylandWindowTest, UpdateWindowRegion) { … }
TEST_P(WaylandWindowTest, CanDispatchMouseEventFocus) { … }
TEST_P(WaylandWindowTest, SetCursorUsesCursorShapeForCommonTypes) { … }
TEST_P(WaylandWindowTest, SetCursorCallsCursorShapeOncePerCursor) { … }
TEST_P(WaylandWindowTest, SetCursorDoesNotUseCursorShapeForNoneCursor) { … }
TEST_P(WaylandWindowTest, SetCursorDoesNotUseCursorShapeForCustomCursors) { … }
TEST_P(WaylandWindowTest, SetCursorUsesZcrCursorShapesForCommonTypes) { … }
TEST_P(WaylandWindowTest, SetCursorCallsZcrCursorShapesOncePerCursor) { … }
TEST_P(WaylandWindowTest, SetCursorDoesNotUseZcrCursorShapesForNoneCursor) { … }
TEST_P(WaylandWindowTest, SetCursorDoesNotUseZcrCursorShapesForCustomCursors) { … }
ACTION_P(CloneEvent, ptr) { … }
TEST_P(WaylandWindowTest, DispatchEvent) { … }
TEST_P(WaylandWindowTest, DispatchEventResult) { … }
TEST_P(WaylandWindowTest, ConfigureEvent) { … }
TEST_P(WaylandWindowTest, ConfigureEventWithNulledSize) { … }
TEST_P(WaylandWindowTest, ConfigureEventIsNotAckedMultipleTimes) { … }
TEST_P(WaylandWindowTest, ManyConfigureEventsDoesNotCrash) { … }
TEST_P(WaylandWindowTest,
ThrottledConfigureEventsDoNotGetStuckOnHiddenOcclusion) { … }
TEST_P(WaylandWindowTest, InitialConfigureFollowedByBoundsChangeCompletesAck) { … }
TEST_P(WaylandWindowTest, OnActivationChanged) { … }
TEST_P(WaylandWindowTest, OnAcceleratedWidgetDestroy) { … }
TEST_P(WaylandWindowTest, CanCreateMenuWindow) { … }
TEST_P(WaylandWindowTest, CreateAndDestroyNestedMenuWindow) { … }
TEST_P(WaylandWindowTest, DispatchesLocatedEventsToCapturedWindow) { … }
TEST_P(WaylandWindowTest, ConvertEventToTarget) { … }
TEST_P(WaylandWindowTest,
DispatchesLocatedEventsToCapturedWindowInTheSameStack) { … }
TEST_P(WaylandWindowTest, DispatchesKeyboardEventToToplevelWindow) { … }
TEST_P(WaylandWindowTest, CanDispatchEvent) { … }
TEST_P(WaylandWindowTest, DispatchWindowMove) { … }
TEST_P(WaylandWindowTest, DispatchWindowResize) { … }
TEST_P(WaylandWindowTest, ToplevelWindowUpdateWindowScale) { … }
TEST_P(WaylandWindowTest, ToplevelWindowOnRotateFocus) { … }
TEST_P(WaylandWindowTest, ToplevelWindowOnRotateFocus_NotActiveOrNotFocused) { … }
TEST_P(WaylandWindowTest, WaylandPopupSurfaceScale) { … }
TEST_P(WaylandWindowTest, WaylandPopupInitialBufferScale) { … }
TEST_P(WaylandWindowTest, WaylandPopupInitialBufferUsesParentScale) { … }
TEST_P(WaylandWindowTest, GetPreferredOutput) { … }
TEST_P(WaylandWindowTest, GetChildrenPreferredOutput) { … }
TEST_P(WaylandWindowTest, PopupPassesDefaultAnchorInformation) { … }
TEST_P(WaylandWindowTest, PopupPassesSetAnchorInformation) { … }
TEST_P(WaylandWindowTest, SetBoundsResizesEmptySizes) { … }
TEST_P(WaylandWindowTest, SetOpaqueRegion) { … }
TEST_P(WaylandWindowTest, OnCloseRequest) { … }
TEST_P(WaylandWindowTest, WaylandPopupSimpleParent) { … }
TEST_P(WaylandWindowTest, WaylandPopupNestedParent) { … }
TEST_P(WaylandWindowTest, SizeConstraintsInternal) { … }
TEST_P(WaylandWindowTest, SizeConstraintsExternal) { … }
TEST_P(WaylandWindowTest, OnSizeConstraintsChanged) { … }
TEST_P(WaylandWindowTest, DestroysCreatesSurfaceOnHideShow) { … }
TEST_P(WaylandWindowTest, DestroysCreatesPopupsOnHideShow) { … }
TEST_P(WaylandWindowTest, ReattachesBackgroundOnShow) { … }
TEST_P(WaylandWindowTest, SetsPropertiesOnShow) { … }
TEST_P(WaylandWindowTest, CreatesPopupOnButtonPressSerial) { … }
TEST_P(WaylandWindowTest, CreatesPopupOnTouchDownSerial) { … }
TEST_P(WaylandWindowTest, NestedPopupWindowsGetCorrectParent) { … }
TEST_P(WaylandWindowTest, DoesNotGrabPopupIfNoSeat) { … }
TEST_P(WaylandWindowTest, DoesNotGrabPopupUnlessParentHasGrab) { … }
TEST_P(WaylandWindowTest, InitialBounds) { … }
TEST_P(WaylandWindowTest, PrimarySnappedState) { … }
TEST_P(WaylandWindowTest, SecondarySnappedState) { … }
#if BUILDFLAG(IS_CHROMEOS_LACROS)
TEST_P(WaylandWindowTest, ImmersiveFullscreen) {
if (!IsAuraShellEnabled()) {
GTEST_SKIP();
}
testing::NiceMock<MockWaylandPlatformWindowDelegate> delegate_2;
auto toplevel = CreateWaylandWindowWithParams(
PlatformWindowType::kWindow, gfx::Rect(10, 10, 200, 200), &delegate_2);
EXPECT_CALL(delegate_2,
OnFullscreenTypeChanged(PlatformFullscreenType::kNone,
PlatformFullscreenType::kImmersive))
.Times(1);
{
WaylandWindow::WindowStates window_states;
window_states.is_maximized = false;
window_states.is_fullscreen = true;
window_states.is_immersive_fullscreen = true;
window_states.is_activated = true;
toplevel->HandleAuraToplevelConfigure(0, 0, 0, 0, window_states);
}
toplevel->HandleSurfaceConfigure(2);
}
TEST_P(WaylandWindowTest, ImmersiveFullscreen_Disabled) {
if (!IsAuraShellEnabled()) {
GTEST_SKIP();
}
uint32_t serial = 0;
testing::NiceMock<MockWaylandPlatformWindowDelegate> delegate_2;
auto toplevel = CreateWaylandWindowWithParams(
PlatformWindowType::kWindow, gfx::Rect(10, 10, 200, 200), &delegate_2);
{
WaylandWindow::WindowStates window_states;
window_states.is_maximized = false;
window_states.is_fullscreen = true;
window_states.is_immersive_fullscreen = true;
window_states.is_activated = true;
toplevel->HandleAuraToplevelConfigure(0, 0, 0, 0, window_states);
}
toplevel->HandleSurfaceConfigure(++serial);
EXPECT_CALL(delegate_2,
OnFullscreenTypeChanged(PlatformFullscreenType::kImmersive,
PlatformFullscreenType::kNone))
.Times(1);
{
WaylandWindow::WindowStates window_states;
window_states.is_maximized = false;
window_states.is_fullscreen = false;
window_states.is_immersive_fullscreen = false;
window_states.is_activated = true;
toplevel->HandleAuraToplevelConfigure(0, 0, 0, 0, window_states);
}
toplevel->HandleSurfaceConfigure(++serial);
}
#endif
namespace {
class WaylandSubsurfaceTest : public WaylandWindowTest { … };
}
TEST_P(WaylandSubsurfaceTest, OneWaylandSubsurfaceInteger) { … }
TEST_P(WaylandSubsurfaceTest, OneWaylandSubsurfaceNonInteger) { … }
TEST_P(WaylandSubsurfaceTest, NoDuplicateSubsurfaceRequests) { … }
TEST_P(WaylandWindowTest, NoDuplicateViewporterRequests) { … }
TEST_P(WaylandWindowTest, RepositionPopups) { … }
TEST_P(WaylandWindowTest, DoesNotCreateSurfaceSyncOnCommitWithoutBuffers) { … }
TEST_P(WaylandWindowTest, StartWithMinimized) { … }
class BlockableWaylandToplevelWindow : public WaylandToplevelWindow { … };
TEST_P(WaylandWindowTest, BlockingTouchDownUp_NoCrash) { … }
TEST_P(WaylandWindowTest, ChangeFocusDuringDispatch) { … }
TEST_P(WaylandWindowTest, WindowMovedResized) { … }
TEST_P(WaylandWindowTest, NoRoundingErrorInDIP) { … }
TEST_P(WaylandWindowTest, ScaleChangeWhenStateRequestThrottoled) { … }
TEST_P(WaylandWindowTest, SetShape) { … }
#if BUILDFLAG(IS_CHROMEOS_LACROS)
TEST_P(WaylandWindowTest, SetTopInset) {
if (!IsAuraShellEnabled()) {
GTEST_SKIP();
}
MockWaylandPlatformWindowDelegate delegate;
std::unique_ptr<WaylandWindow> toplevel_window =
CreateWaylandWindowWithParams(PlatformWindowType::kWindow,
gfx::Rect(300, 300), &delegate);
toplevel_window->AsWaylandToplevelWindow()->SetTopInset(32);
PostToServerAndWait([&](wl::TestWaylandServerThread* server) {
auto* surface = server->GetObject<wl::MockSurface>(
toplevel_window->root_surface()->get_surface_id());
ASSERT_TRUE(surface);
wl::TestZAuraToplevel* zaura_toplevel =
surface->xdg_surface()->xdg_toplevel()->zaura_toplevel();
ASSERT_TRUE(zaura_toplevel);
EXPECT_EQ(32, zaura_toplevel->top_inset());
});
toplevel_window->AsWaylandToplevelWindow()->SetTopInset(0);
PostToServerAndWait([&](wl::TestWaylandServerThread* server) {
auto* surface = server->GetObject<wl::MockSurface>(
toplevel_window->root_surface()->get_surface_id());
ASSERT_TRUE(surface);
wl::TestZAuraToplevel* zaura_toplevel =
surface->xdg_surface()->xdg_toplevel()->zaura_toplevel();
ASSERT_TRUE(zaura_toplevel);
EXPECT_EQ(0, zaura_toplevel->top_inset());
});
}
TEST_P(WaylandWindowTest, OverviewMode) {
if (!IsAuraShellEnabled()) {
GTEST_SKIP();
}
EXPECT_CALL(delegate_, OnOverviewModeChanged(Eq(true))).Times(1);
PostToServerAndWait([&](wl::TestWaylandServerThread* server) {
auto* surface = server->GetObject<wl::MockSurface>(surface_id_);
auto* toplevel = surface->xdg_surface()->xdg_toplevel()->zaura_toplevel();
zaura_toplevel_send_overview_change(toplevel->resource(),
ZAURA_TOPLEVEL_IN_OVERVIEW_IN_OVERVIEW);
});
EXPECT_CALL(delegate_, OnOverviewModeChanged(Eq(false))).Times(1);
PostToServerAndWait([&](wl::TestWaylandServerThread* server) {
auto* surface = server->GetObject<wl::MockSurface>(surface_id_);
auto* toplevel = surface->xdg_surface()->xdg_toplevel()->zaura_toplevel();
zaura_toplevel_send_overview_change(
toplevel->resource(), ZAURA_TOPLEVEL_IN_OVERVIEW_NOT_IN_OVERVIEW);
});
}
#endif
TEST_P(WaylandWindowTest, SetUnsetFloat) { … }
TEST_P(WaylandWindowTest,
UnsynchronizedOcclusionStateNotOverridenByConfigureOcclusionState) { … }
TEST_P(WaylandWindowTest, ReentrantApplyStateWorks) { … }
TEST_P(WaylandWindowTest, ConfigureWithSameStateAcksAndCommitsImmediately) { … }
class MultiDisplayWaylandWindowTest : public WaylandWindowTest { … };
TEST_P(MultiDisplayWaylandWindowTest, SetsNewWindowBoundsToCorrectDisplay) { … }
TEST_P(MultiDisplayWaylandWindowTest, NewWindowsRespectInitParamBounds) { … }
#if !BUILDFLAG(IS_CHROMEOS_LACROS)
INSTANTIATE_TEST_SUITE_P(…);
INSTANTIATE_TEST_SUITE_P(…);
#else
INSTANTIATE_TEST_SUITE_P(
XdgVersionStableTestWithAuraShell,
WaylandWindowTest,
Values(wl::ServerConfig{
.enable_aura_shell = wl::EnableAuraShellProtocol::kEnabled}));
INSTANTIATE_TEST_SUITE_P(
XdgVersionStableTestWithAuraShell,
MultiDisplayWaylandWindowTest,
Values(wl::ServerConfig{
.enable_aura_shell = wl::EnableAuraShellProtocol::kEnabled}));
#endif
#if !BUILDFLAG(IS_CHROMEOS_LACROS)
INSTANTIATE_TEST_SUITE_P(…);
#else
INSTANTIATE_TEST_SUITE_P(
XdgVersionStableTestWithAuraShell,
WaylandSubsurfaceTest,
Values(wl::ServerConfig{
.enable_aura_shell = wl::EnableAuraShellProtocol::kEnabled}));
#endif
}