diff options
Diffstat (limited to 'chromium/components/exo/wayland')
32 files changed, 1280 insertions, 121 deletions
diff --git a/chromium/components/exo/wayland/BUILD.gn b/chromium/components/exo/wayland/BUILD.gn index 28c660133d4..6800a87c54d 100644 --- a/chromium/components/exo/wayland/BUILD.gn +++ b/chromium/components/exo/wayland/BUILD.gn @@ -36,7 +36,6 @@ source_set("wayland") { "wayland_touch_delegate.cc", "wayland_touch_delegate.h", "wayland_watcher.cc", - "wayland_watcher.h", "wl_compositor.cc", "wl_compositor.h", "wl_data_device_manager.cc", @@ -120,10 +119,12 @@ source_set("wayland") { deps += [ "//build/config/linux/libdrm", "//third_party/wayland-protocols:linux_dmabuf_protocol", + "//ui/ozone", ] if (is_chromeos) { deps += [ + "//ash", "//ash/public/cpp", "//ui/events/ozone/layout", ] @@ -152,6 +153,8 @@ source_set("wayland") { "wayland_positioner.h", "wl_shell.cc", "wl_shell.h", + "xdg_shell.cc", + "xdg_shell.h", "zcr_color_space.cc", "zcr_color_space.h", "zcr_cursor_shapes.cc", diff --git a/chromium/components/exo/wayland/DEPS b/chromium/components/exo/wayland/DEPS index 33a9ebc4583..074321a0083 100644 --- a/chromium/components/exo/wayland/DEPS +++ b/chromium/components/exo/wayland/DEPS @@ -1,4 +1,5 @@ include_rules = [ "+services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h", "+third_party/wayland/include", + "+ui/ozone/public", ] diff --git a/chromium/components/exo/wayland/clients/blur.cc b/chromium/components/exo/wayland/clients/blur.cc index 4b37d4db4d3..e30e562cd8a 100644 --- a/chromium/components/exo/wayland/clients/blur.cc +++ b/chromium/components/exo/wayland/clients/blur.cc @@ -215,7 +215,7 @@ void Blur::Run(double sigma_x, } if (gr_context_) { - gr_context_->flush(); + gr_context_->flushAndSubmit(); glFinish(); } diff --git a/chromium/components/exo/wayland/clients/blur_main.cc b/chromium/components/exo/wayland/clients/blur_main.cc index 477041346cd..f1718f8dfe6 100644 --- a/chromium/components/exo/wayland/clients/blur_main.cc +++ b/chromium/components/exo/wayland/clients/blur_main.cc @@ -8,6 +8,7 @@ #include "base/at_exit.h" #include "base/command_line.h" +#include "base/logging.h" #include "base/message_loop/message_pump_type.h" #include "base/strings/string_number_conversions.h" #include "base/task/single_thread_task_executor.h" diff --git a/chromium/components/exo/wayland/clients/client_base.cc b/chromium/components/exo/wayland/clients/client_base.cc index e2f0dd9ac27..95323b80b57 100644 --- a/chromium/components/exo/wayland/clients/client_base.cc +++ b/chromium/components/exo/wayland/clients/client_base.cc @@ -968,7 +968,7 @@ std::unique_ptr<ClientBase::Buffer> ClientBase::CreateDrmBuffer( texture_info.fFormat = kSizedInternalFormat; GrBackendTexture backend_texture(size.width(), size.height(), GrMipMapped::kNo, texture_info); - buffer->sk_surface = SkSurface::MakeFromBackendTextureAsRenderTarget( + buffer->sk_surface = SkSurface::MakeFromBackendTexture( gr_context_.get(), backend_texture, kTopLeft_GrSurfaceOrigin, /* sampleCnt */ 0, kColorType, /* colorSpace */ nullptr, /* props */ nullptr); diff --git a/chromium/components/exo/wayland/clients/color_space.cc b/chromium/components/exo/wayland/clients/color_space.cc index 6e366d84a06..27931638ef4 100644 --- a/chromium/components/exo/wayland/clients/color_space.cc +++ b/chromium/components/exo/wayland/clients/color_space.cc @@ -11,6 +11,7 @@ #include "base/at_exit.h" #include "base/command_line.h" +#include "base/logging.h" #include "base/message_loop/message_pump_type.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" diff --git a/chromium/components/exo/wayland/clients/explicit_synchronization.cc b/chromium/components/exo/wayland/clients/explicit_synchronization.cc index cc346d2c231..a54d2cc0f94 100644 --- a/chromium/components/exo/wayland/clients/explicit_synchronization.cc +++ b/chromium/components/exo/wayland/clients/explicit_synchronization.cc @@ -88,7 +88,7 @@ void ExplicitSynchronizationClient::Run() { .toSkColor()); // Create an EGLSyncKHR object to signal when rendering is done. - gr_context_->flush(); + gr_context_->flushAndSubmit(); buffer->egl_sync.reset(new ScopedEglSync( eglCreateSyncKHR(eglGetCurrentDisplay(), egl_sync_type_, nullptr))); DCHECK(buffer->egl_sync->is_valid()); diff --git a/chromium/components/exo/wayland/clients/fullscreen_shell.cc b/chromium/components/exo/wayland/clients/fullscreen_shell.cc index 19024dafae2..59a5a76022e 100644 --- a/chromium/components/exo/wayland/clients/fullscreen_shell.cc +++ b/chromium/components/exo/wayland/clients/fullscreen_shell.cc @@ -112,7 +112,7 @@ void FullscreenClient::Paint(const wl_callback_listener& frame_listener) { canvas->drawRect(rect, paint); if (gr_context_) { - gr_context_->flush(); + gr_context_->flushAndSubmit(); glFinish(); } diff --git a/chromium/components/exo/wayland/clients/rects.cc b/chromium/components/exo/wayland/clients/rects.cc index d4d101cc03d..8f34046b6b9 100644 --- a/chromium/components/exo/wayland/clients/rects.cc +++ b/chromium/components/exo/wayland/clients/rects.cc @@ -438,7 +438,7 @@ int RectsClient::Run(const ClientBase::InitParams& params, } GrContext* gr_context = gr_context_.get(); if (gr_context) { - gr_context->flush(); + gr_context->flushAndSubmit(); #if defined(USE_GBM) if (egl_sync_type_) { diff --git a/chromium/components/exo/wayland/clients/simple.cc b/chromium/components/exo/wayland/clients/simple.cc index 1a517247ca2..37015530eb2 100644 --- a/chromium/components/exo/wayland/clients/simple.cc +++ b/chromium/components/exo/wayland/clients/simple.cc @@ -140,7 +140,7 @@ void Simple::Run(int frames, canvas->clear(kColors[++frame_count % base::size(kColors)]); if (gr_context_) { - gr_context_->flush(); + gr_context_->flushAndSubmit(); glFinish(); } diff --git a/chromium/components/exo/wayland/clients/subsurface.cc b/chromium/components/exo/wayland/clients/subsurface.cc index 0ef02b65bc0..41afd463c22 100644 --- a/chromium/components/exo/wayland/clients/subsurface.cc +++ b/chromium/components/exo/wayland/clients/subsurface.cc @@ -98,7 +98,7 @@ void SubSurfaceClient::Run(const ClientBase::InitParams& params) { canvas->drawIRect(rect, paint); canvas->restore(); if (gr_context_) { - gr_context_->flush(); + gr_context_->flushAndSubmit(); glFinish(); } wl_surface_damage(child_surface.get(), 0, 0, kSubsurfaceWidth, @@ -114,7 +114,7 @@ void SubSurfaceClient::Run(const ClientBase::InitParams& params) { static const SkColor kColors[] = {SK_ColorRED, SK_ColorBLACK}; canvas->clear(kColors[frame_count % base::size(kColors)]); if (gr_context_) { - gr_context_->flush(); + gr_context_->flushAndSubmit(); glFinish(); } wl_surface_set_buffer_scale(surface_.get(), scale_); diff --git a/chromium/components/exo/wayland/clients/yuv.cc b/chromium/components/exo/wayland/clients/yuv.cc index 026c8091448..e626a58f129 100644 --- a/chromium/components/exo/wayland/clients/yuv.cc +++ b/chromium/components/exo/wayland/clients/yuv.cc @@ -9,6 +9,7 @@ #include "base/at_exit.h" #include "base/command_line.h" +#include "base/logging.h" #include "base/message_loop/message_pump_type.h" #include "base/task/single_thread_task_executor.h" #include "components/exo/wayland/clients/client_base.h" diff --git a/chromium/components/exo/wayland/server.cc b/chromium/components/exo/wayland/server.cc index 281e49f7876..7aadc0b13fc 100644 --- a/chromium/components/exo/wayland/server.cc +++ b/chromium/components/exo/wayland/server.cc @@ -28,6 +28,7 @@ #include <vsync-feedback-unstable-v1-server-protocol.h> #include <wayland-server-core.h> #include <wayland-server-protocol-core.h> +#include <xdg-shell-server-protocol.h> #include <xdg-shell-unstable-v6-server-protocol.h> #include <memory> @@ -60,6 +61,7 @@ #if defined(OS_CHROMEOS) #include "components/exo/wayland/wl_shell.h" +#include "components/exo/wayland/xdg_shell.h" #include "components/exo/wayland/zcr_color_space.h" #include "components/exo/wayland/zcr_cursor_shapes.h" #include "components/exo/wayland/zcr_gaming_input.h" @@ -79,6 +81,7 @@ #if defined(USE_OZONE) #include <linux-dmabuf-unstable-v1-server-protocol.h> #include "components/exo/wayland/zwp_linux_dmabuf.h" +#include "ui/ozone/public/ozone_platform.h" #endif #if defined(USE_FULLSCREEN_SHELL) @@ -104,6 +107,18 @@ const base::FilePath::CharType kSocketName[] = FILE_PATH_LITERAL("wayland-0"); // Group used for wayland socket. const char kWaylandSocketGroup[] = "wayland"; +bool IsDrmAtomicAvailable() { +#if defined(USE_OZONE) + auto& host_properties = + ui::OzonePlatform::GetInstance()->GetInitializedHostProperties(); + return host_properties.supports_overlays; +#else + LOG(WARNING) << "Ozone disabled, cannot determine whether DrmAtomic is " + "present. Assuming it is not"; + return false; +#endif +} + } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -150,9 +165,14 @@ Server::Server(Display* display) wl_global_create(wl_display_.get(), &wl_seat_interface, kWlSeatVersion, seat_data_.get(), bind_seat); - wl_global_create(wl_display_.get(), - &zwp_linux_explicit_synchronization_v1_interface, 1, - display_, bind_linux_explicit_synchronization); + if (IsDrmAtomicAvailable()) { + // The release fence needed by linux-explicit-sync comes from DRM-atomic. + // If DRM atomic is not supported, linux-explicit-sync interface is + // disabled. + wl_global_create(wl_display_.get(), + &zwp_linux_explicit_synchronization_v1_interface, 1, + display_, bind_linux_explicit_synchronization); + } wl_global_create(wl_display_.get(), &zaura_shell_interface, kZAuraShellVersion, display_, bind_aura_shell); #if defined(OS_CHROMEOS) @@ -192,10 +212,15 @@ Server::Server(Display* display) wl_global_create(wl_display_.get(), &zwp_text_input_manager_v1_interface, 1, zwp_text_manager_data_.get(), bind_text_input_manager); + zxdg_shell_data_ = + std::make_unique<WaylandZxdgShell>(display_, serial_tracker_.get()); + wl_global_create(wl_display_.get(), &zxdg_shell_v6_interface, 1, + zxdg_shell_data_.get(), bind_zxdg_shell_v6); + xdg_shell_data_ = std::make_unique<WaylandXdgShell>(display_, serial_tracker_.get()); - wl_global_create(wl_display_.get(), &zxdg_shell_v6_interface, 1, - xdg_shell_data_.get(), bind_xdg_shell_v6); + wl_global_create(wl_display_.get(), &xdg_wm_base_interface, 1, + xdg_shell_data_.get(), bind_xdg_shell); #endif #if defined(USE_FULLSCREEN_SHELL) diff --git a/chromium/components/exo/wayland/server.h b/chromium/components/exo/wayland/server.h index 3f36907b9af..971164e2e00 100644 --- a/chromium/components/exo/wayland/server.h +++ b/chromium/components/exo/wayland/server.h @@ -25,6 +25,7 @@ class WaylandDisplayOutput; struct WaylandSeat; struct WaylandTextInputManager; struct WaylandXdgShell; +struct WaylandZxdgShell; // This class is a thin wrapper around a Wayland display server. All Wayland // requests are dispatched into the given Exosphere display. @@ -67,6 +68,7 @@ class Server : public display::DisplayObserver { #if defined(OS_CHROMEOS) std::unique_ptr<WaylandTextInputManager> zwp_text_manager_data_; + std::unique_ptr<WaylandZxdgShell> zxdg_shell_data_; std::unique_ptr<WaylandXdgShell> xdg_shell_data_; #endif diff --git a/chromium/components/exo/wayland/wayland_display_observer.cc b/chromium/components/exo/wayland/wayland_display_observer.cc index 850781e00e2..6633ddf7c17 100644 --- a/chromium/components/exo/wayland/wayland_display_observer.cc +++ b/chromium/components/exo/wayland/wayland_display_observer.cc @@ -8,6 +8,7 @@ #include <string> +#include "components/exo/wayland/wayland_display_output.h" #include "components/exo/wm_helper.h" #include "ui/display/manager/managed_display_info.h" #include "ui/display/screen.h" @@ -15,14 +16,16 @@ namespace exo { namespace wayland { -WaylandDisplayObserver::WaylandDisplayObserver(int64_t id, +WaylandDisplayObserver::WaylandDisplayObserver(WaylandDisplayOutput* output, wl_resource* output_resource) - : id_(id), output_resource_(output_resource) { + : output_(output), output_resource_(output_resource) { + output_->RegisterOutput(output_resource_); display::Screen::GetScreen()->AddObserver(this); SendDisplayMetrics(); } WaylandDisplayObserver::~WaylandDisplayObserver() { + output_->UnregisterOutput(output_resource_); display::Screen::GetScreen()->RemoveObserver(this); } @@ -39,7 +42,7 @@ bool WaylandDisplayObserver::HasScaleObserver() const { void WaylandDisplayObserver::OnDisplayMetricsChanged( const display::Display& display, uint32_t changed_metrics) { - if (id_ != display.id()) + if (output_->id() != display.id()) return; // There is no need to check DISPLAY_METRIC_PRIMARY because when primary @@ -59,8 +62,8 @@ void WaylandDisplayObserver::OnDisplayMetricsChanged( void WaylandDisplayObserver::SendDisplayMetrics() { display::Display display; - bool rv = - display::Screen::GetScreen()->GetDisplayWithDisplayId(id_, &display); + bool rv = display::Screen::GetScreen()->GetDisplayWithDisplayId(output_->id(), + &display); DCHECK(rv); const display::ManagedDisplayInfo& info = diff --git a/chromium/components/exo/wayland/wayland_display_observer.h b/chromium/components/exo/wayland/wayland_display_observer.h index 9bd126651f6..fcd67650b11 100644 --- a/chromium/components/exo/wayland/wayland_display_observer.h +++ b/chromium/components/exo/wayland/wayland_display_observer.h @@ -15,6 +15,7 @@ struct wl_resource; namespace exo { namespace wayland { +class WaylandDisplayOutput; class WaylandDisplayObserver : public display::DisplayObserver { public: @@ -28,7 +29,8 @@ class WaylandDisplayObserver : public display::DisplayObserver { virtual ~ScaleObserver() {} }; - WaylandDisplayObserver(int64_t id, wl_resource* output_resource); + WaylandDisplayObserver(WaylandDisplayOutput* output, + wl_resource* output_resource); ~WaylandDisplayObserver() override; void SetScaleObserver(base::WeakPtr<ScaleObserver> scale_observer); bool HasScaleObserver() const; @@ -43,8 +45,8 @@ class WaylandDisplayObserver : public display::DisplayObserver { // compensate for the rotation of an output device. wl_output_transform OutputTransform(display::Display::Rotation rotation); - // The ID of the display being observed. - const int64_t id_; + // Output. + WaylandDisplayOutput* output_; // The output resource associated with the display. wl_resource* const output_resource_; diff --git a/chromium/components/exo/wayland/wayland_display_output.cc b/chromium/components/exo/wayland/wayland_display_output.cc index 6d451f4d6c0..560cf5a08c5 100644 --- a/chromium/components/exo/wayland/wayland_display_output.cc +++ b/chromium/components/exo/wayland/wayland_display_output.cc @@ -7,12 +7,22 @@ #include <wayland-server-core.h> #include <wayland-server-protocol-core.h> +#include "base/logging.h" +#include "base/stl_util.h" +#include "components/exo/surface.h" +#include "components/exo/wayland/server_util.h" + namespace exo { namespace wayland { WaylandDisplayOutput::WaylandDisplayOutput(int64_t id) : id_(id) {} WaylandDisplayOutput::~WaylandDisplayOutput() { + // Empty the output_ids_ so that Unregister will be no op. + auto ids = std::move(output_ids_); + for (auto pair : ids) + wl_resource_destroy(pair.second); + if (global_) wl_global_destroy(global_); } @@ -25,5 +35,24 @@ void WaylandDisplayOutput::set_global(wl_global* global) { global_ = global; } +void WaylandDisplayOutput::UnregisterOutput(wl_resource* output_resource) { + base::EraseIf(output_ids_, [output_resource](auto& pair) { + return pair.second == output_resource; + }); +} + +void WaylandDisplayOutput::RegisterOutput(wl_resource* output_resource) { + auto* client = wl_resource_get_client(output_resource); + output_ids_.insert(std::make_pair(client, output_resource)); +} + +wl_resource* WaylandDisplayOutput::GetOutputResourceForClient( + wl_client* client) { + auto iter = output_ids_.find(client); + if (iter == output_ids_.end()) + return nullptr; + return iter->second; +} + } // namespace wayland } // namespace exo diff --git a/chromium/components/exo/wayland/wayland_display_output.h b/chromium/components/exo/wayland/wayland_display_output.h index 711fef685f1..eeae307b040 100644 --- a/chromium/components/exo/wayland/wayland_display_output.h +++ b/chromium/components/exo/wayland/wayland_display_output.h @@ -7,9 +7,12 @@ #include <stdint.h> +#include "base/containers/flat_map.h" #include "base/macros.h" +struct wl_client; struct wl_global; +struct wl_resource; namespace exo { namespace wayland { @@ -18,15 +21,23 @@ namespace wayland { // and associated with a global. class WaylandDisplayOutput { public: - explicit WaylandDisplayOutput(int64_t id); + explicit WaylandDisplayOutput(int64_t display_id); ~WaylandDisplayOutput(); int64_t id() const; void set_global(wl_global* global); + // Register/Unregister output resources, which will be used to + // notify surface when enter/leave the output. + void UnregisterOutput(wl_resource* output_resource); + void RegisterOutput(wl_resource* output_resource); + + wl_resource* GetOutputResourceForClient(wl_client* client); + private: const int64_t id_; wl_global* global_ = nullptr; + base::flat_map<wl_client*, wl_resource*> output_ids_; DISALLOW_COPY_AND_ASSIGN(WaylandDisplayOutput); }; diff --git a/chromium/components/exo/wayland/wayland_positioner.cc b/chromium/components/exo/wayland/wayland_positioner.cc index 625fad4a5e8..65b9ec694e0 100644 --- a/chromium/components/exo/wayland/wayland_positioner.cc +++ b/chromium/components/exo/wayland/wayland_positioner.cc @@ -4,28 +4,129 @@ #include "components/exo/wayland/wayland_positioner.h" +#include <xdg-shell-unstable-v6-server-protocol.h> + namespace exo { namespace wayland { namespace { -// Represents the 1-dimensional projection of the gravity/anchor values. -enum Direction { kNegative = -1, kNeutral = 0, kPositive = 1 }; +std::pair<WaylandPositioner::Direction, WaylandPositioner::Direction> +DecomposeUnstableAnchor(uint32_t anchor) { + WaylandPositioner::Direction x, y; + + if (anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) { + x = WaylandPositioner::Direction::kNegative; + } else if (anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT) { + x = WaylandPositioner::Direction::kPositive; + } else { + x = WaylandPositioner::Direction::kNeutral; + } + + if (anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP) { + y = WaylandPositioner::Direction::kNegative; + } else if (anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM) { + y = WaylandPositioner::Direction::kPositive; + } else { + y = WaylandPositioner::Direction::kNeutral; + } + + return std::make_pair(x, y); +} + +std::pair<WaylandPositioner::Direction, WaylandPositioner::Direction> +DecomposeStableAnchor(uint32_t anchor) { + switch (anchor) { + default: + case XDG_POSITIONER_ANCHOR_NONE: + return std::make_pair(WaylandPositioner::Direction::kNeutral, + WaylandPositioner::Direction::kNeutral); + case XDG_POSITIONER_ANCHOR_TOP: + return std::make_pair(WaylandPositioner::Direction::kNeutral, + WaylandPositioner::Direction::kNegative); + case XDG_POSITIONER_ANCHOR_BOTTOM: + return std::make_pair(WaylandPositioner::Direction::kNeutral, + WaylandPositioner::Direction::kPositive); + case XDG_POSITIONER_ANCHOR_LEFT: + return std::make_pair(WaylandPositioner::Direction::kNegative, + WaylandPositioner::Direction::kNeutral); + case XDG_POSITIONER_ANCHOR_RIGHT: + return std::make_pair(WaylandPositioner::Direction::kPositive, + WaylandPositioner::Direction::kNeutral); + case XDG_POSITIONER_ANCHOR_TOP_LEFT: + return std::make_pair(WaylandPositioner::Direction::kNegative, + WaylandPositioner::Direction::kNegative); + case XDG_POSITIONER_ANCHOR_TOP_RIGHT: + return std::make_pair(WaylandPositioner::Direction::kPositive, + WaylandPositioner::Direction::kNegative); + case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: + return std::make_pair(WaylandPositioner::Direction::kNegative, + WaylandPositioner::Direction::kPositive); + case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: + return std::make_pair(WaylandPositioner::Direction::kPositive, + WaylandPositioner::Direction::kPositive); + } +} + +std::pair<WaylandPositioner::Direction, WaylandPositioner::Direction> +DecomposeUnstableGravity(uint32_t gravity) { + WaylandPositioner::Direction x, y; + + if (gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT) { + x = WaylandPositioner::Direction::kNegative; + } else if (gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT) { + x = WaylandPositioner::Direction::kPositive; + } else { + x = WaylandPositioner::Direction::kNeutral; + } + + if (gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) { + y = WaylandPositioner::Direction::kNegative; + } else if (gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM) { + y = WaylandPositioner::Direction::kPositive; + } else { + y = WaylandPositioner::Direction::kNeutral; + } -static Direction Flip(Direction d) { - return (Direction)-d; + return std::make_pair(x, y); +} + +std::pair<WaylandPositioner::Direction, WaylandPositioner::Direction> +DecomposeStableGravity(uint32_t gravity) { + switch (gravity) { + default: + case XDG_POSITIONER_GRAVITY_NONE: + return std::make_pair(WaylandPositioner::Direction::kNeutral, + WaylandPositioner::Direction::kNeutral); + case XDG_POSITIONER_GRAVITY_TOP: + return std::make_pair(WaylandPositioner::Direction::kNeutral, + WaylandPositioner::Direction::kNegative); + case XDG_POSITIONER_GRAVITY_BOTTOM: + return std::make_pair(WaylandPositioner::Direction::kNeutral, + WaylandPositioner::Direction::kPositive); + case XDG_POSITIONER_GRAVITY_LEFT: + return std::make_pair(WaylandPositioner::Direction::kNegative, + WaylandPositioner::Direction::kNeutral); + case XDG_POSITIONER_GRAVITY_RIGHT: + return std::make_pair(WaylandPositioner::Direction::kPositive, + WaylandPositioner::Direction::kNeutral); + case XDG_POSITIONER_GRAVITY_TOP_LEFT: + return std::make_pair(WaylandPositioner::Direction::kNegative, + WaylandPositioner::Direction::kNegative); + case XDG_POSITIONER_GRAVITY_TOP_RIGHT: + return std::make_pair(WaylandPositioner::Direction::kPositive, + WaylandPositioner::Direction::kNegative); + case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT: + return std::make_pair(WaylandPositioner::Direction::kNegative, + WaylandPositioner::Direction::kPositive); + case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT: + return std::make_pair(WaylandPositioner::Direction::kPositive, + WaylandPositioner::Direction::kPositive); + } } -// Decodes a masked anchor/gravity bitfield to the direction. -Direction MaskToDirection(uint32_t field, - uint32_t negative_mask, - uint32_t positive_mask) { - DCHECK(!((field & negative_mask) && (field & positive_mask))); - if (field & negative_mask) - return kNegative; - if (field & positive_mask) - return kPositive; - return kNeutral; +static WaylandPositioner::Direction Flip(WaylandPositioner::Direction d) { + return (WaylandPositioner::Direction)-d; } // Represents the possible/actual positioner adjustments for this window. @@ -63,8 +164,8 @@ Range1D Calculate(const ConstraintAdjustment& adjustments, Range1D anchor_range, uint32_t size, int32_t offset, - Direction anchor, - Direction gravity) { + WaylandPositioner::Direction anchor, + WaylandPositioner::Direction gravity) { if (adjustments.flip) { return Calculate({/*flip=*/false, adjustments.slide, adjustments.resize}, work_size, anchor_range, size, -offset, Flip(anchor), @@ -91,25 +192,25 @@ Range1D Calculate(const ConstraintAdjustment& adjustments, int32_t start = offset; switch (anchor) { - case Direction::kNegative: + case WaylandPositioner::Direction::kNegative: start += anchor_range.start; break; - case Direction::kNeutral: + case WaylandPositioner::Direction::kNeutral: start += anchor_range.center(); break; - case Direction::kPositive: + case WaylandPositioner::Direction::kPositive: start += anchor_range.end; break; } switch (gravity) { - case Direction::kNegative: + case WaylandPositioner::Direction::kNegative: start -= size; break; - case Direction::kNeutral: + case WaylandPositioner::Direction::kNeutral: start -= size / 2; break; - case Direction::kPositive: + case WaylandPositioner::Direction::kPositive: break; } return {start, start + size}; @@ -124,8 +225,8 @@ std::pair<Range1D, ConstraintAdjustment> DetermineBestConstraintAdjustment( const Range1D& anchor_range, uint32_t size, int32_t offset, - Direction anchor, - Direction gravity, + WaylandPositioner::Direction anchor, + WaylandPositioner::Direction gravity, const ConstraintAdjustment& valid_adjustments) { if (work_area.start != 0) { int32_t shift = -work_area.start; @@ -174,29 +275,47 @@ std::pair<Range1D, ConstraintAdjustment> DetermineBestConstraintAdjustment( } // namespace +void WaylandPositioner::SetAnchor(uint32_t anchor) { + std::pair<WaylandPositioner::Direction, WaylandPositioner::Direction> + decompose; + if (version_ == UNSTABLE) { + decompose = DecomposeUnstableAnchor(anchor); + } else { + decompose = DecomposeStableAnchor(anchor); + } + anchor_x_ = decompose.first; + anchor_y_ = decompose.second; +} + +void WaylandPositioner::SetGravity(uint32_t gravity) { + std::pair<WaylandPositioner::Direction, WaylandPositioner::Direction> + decompose; + if (version_ == UNSTABLE) { + decompose = DecomposeUnstableGravity(gravity); + } else { + decompose = DecomposeStableGravity(gravity); + } + gravity_x_ = decompose.first; + gravity_y_ = decompose.second; +} + WaylandPositioner::Result WaylandPositioner::CalculatePosition( const gfx::Rect& work_area, bool flip_x, bool flip_y) const { - Direction anchor_x = MaskToDirection(anchor_, ZXDG_POSITIONER_V6_ANCHOR_LEFT, - ZXDG_POSITIONER_V6_ANCHOR_RIGHT); - Direction anchor_y = MaskToDirection(anchor_, ZXDG_POSITIONER_V6_ANCHOR_TOP, - ZXDG_POSITIONER_V6_ANCHOR_BOTTOM); - Direction gravity_x = - MaskToDirection(gravity_, ZXDG_POSITIONER_V6_GRAVITY_LEFT, - ZXDG_POSITIONER_V6_GRAVITY_RIGHT); - Direction gravity_y = - MaskToDirection(gravity_, ZXDG_POSITIONER_V6_GRAVITY_TOP, - ZXDG_POSITIONER_V6_GRAVITY_BOTTOM); + auto anchor_x = anchor_x_; + auto anchor_y = anchor_y_; + auto gravity_x = gravity_x_; + auto gravity_y = gravity_y_; ConstraintAdjustment adjustments_x = MaskToConstraintAdjustment( - adjustment_, ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X, - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X, - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X); + adjustment_, XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X); ConstraintAdjustment adjustments_y = MaskToConstraintAdjustment( - adjustment_, ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y, - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y, - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y); + adjustment_, XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y); int32_t offset_x = offset_.x(); int32_t offset_y = offset_.y(); diff --git a/chromium/components/exo/wayland/wayland_positioner.h b/chromium/components/exo/wayland/wayland_positioner.h index a623e0d4326..ccd5427838f 100644 --- a/chromium/components/exo/wayland/wayland_positioner.h +++ b/chromium/components/exo/wayland/wayland_positioner.h @@ -5,7 +5,7 @@ #ifndef COMPONENTS_EXO_WAYLAND_WAYLAND_POSITIONER_H_ #define COMPONENTS_EXO_WAYLAND_WAYLAND_POSITIONER_H_ -#include <xdg-shell-unstable-v6-server-protocol.h> +#include <xdg-shell-server-protocol.h> #include "base/macros.h" #include "ui/gfx/geometry/point.h" @@ -26,7 +26,14 @@ class WaylandPositioner { bool y_flipped; }; - WaylandPositioner() = default; + // Represents the 1-dimensional projection of the gravity/anchor values. + enum Direction { kNegative = -1, kNeutral = 0, kPositive = 1 }; + + // Controls whether anchor and gravity are set using the unstable bitfields or + // the stable enums. + enum Version { UNSTABLE, STABLE }; + + WaylandPositioner(Version v) : version_(v) {} // Calculate and return position from current state. Result CalculatePosition(const gfx::Rect& work_area, @@ -39,27 +46,31 @@ class WaylandPositioner { anchor_rect_ = std::move(anchor_rect); } - void SetAnchor(uint32_t anchor) { anchor_ = anchor; } + void SetAnchor(uint32_t anchor); - void SetGravity(uint32_t gravity) { gravity_ = gravity; } + void SetGravity(uint32_t gravity); void SetAdjustment(uint32_t adjustment) { adjustment_ = adjustment; } void SetOffset(gfx::Vector2d offset) { offset_ = std::move(offset); } private: + Version version_; + gfx::Size size_; gfx::Rect anchor_rect_; - uint32_t anchor_ = ZXDG_POSITIONER_V6_ANCHOR_NONE; + Direction anchor_x_ = kNeutral; + Direction anchor_y_ = kNeutral; - uint32_t gravity_ = ZXDG_POSITIONER_V6_GRAVITY_NONE; + Direction gravity_x_ = kNeutral; + Direction gravity_y_ = kNeutral; // A bitmask that defines the subset of modifications to the position/size // that are allowed, see zxdg_positioner.constraint_adjustment() for more // details. - uint32_t adjustment_ = ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_NONE; + uint32_t adjustment_ = XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE; // Defines an absolute translation (i.e. unaffected by flipping, scaling or // resizing) for the placement of the window relative to the |anchor_rect_|. diff --git a/chromium/components/exo/wayland/wayland_positioner_unittest.cc b/chromium/components/exo/wayland/wayland_positioner_unittest.cc index 035f3b91f90..c30ea99d7db 100644 --- a/chromium/components/exo/wayland/wayland_positioner_unittest.cc +++ b/chromium/components/exo/wayland/wayland_positioner_unittest.cc @@ -5,6 +5,7 @@ #include "components/exo/wayland/wayland_positioner.h" #include "testing/gtest/include/gtest/gtest.h" +#include "xdg-shell-server-protocol.h" #include "xdg-shell-unstable-v6-server-protocol.h" namespace exo { @@ -21,7 +22,9 @@ class WaylandPositionerTest : public testing::Test { bool flip_x = false; bool flip_y = false; - TestCaseBuilder() { positioner.SetAnchorRect({2, 2, 1, 1}); } + explicit TestCaseBuilder(WaylandPositioner::Version v) : positioner(v) { + positioner.SetAnchorRect({2, 2, 1, 1}); + } TestCaseBuilder& SetFlipState(bool x, bool y) { flip_x = x; @@ -66,31 +69,35 @@ class WaylandPositionerTest : public testing::Test { }; }; -TEST_F(WaylandPositionerTest, UnconstrainedCases) { +// Tests for the unstable protocol. + +TEST_F(WaylandPositionerTest, UnconstrainedCasesUnstable) { // No gravity or anchor. - EXPECT_EQ(TestCaseBuilder().SetSize(1, 1).SolveToRect(), + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE) + .SetSize(1, 1) + .SolveToRect(), gfx::Rect(2, 2, 1, 1)); // Anchor without gravity. - EXPECT_EQ(TestCaseBuilder() + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE) .SetSize(2, 1) .SetAnchor(ZXDG_POSITIONER_V6_ANCHOR_RIGHT) .SolveToRect(), gfx::Rect(2, 2, 2, 1)); - EXPECT_EQ(TestCaseBuilder() + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE) .SetSize(2, 1) .SetAnchor(ZXDG_POSITIONER_V6_ANCHOR_LEFT) .SolveToRect(), gfx::Rect(1, 2, 2, 1)); // Gravity without anchor. - EXPECT_EQ(TestCaseBuilder() + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE) .SetSize(1, 2) .SetAnchorRect(2, 2, 0, 0) .SetGravity(ZXDG_POSITIONER_V6_GRAVITY_TOP) .SolveToRect(), gfx::Rect(2, 0, 1, 2)); - EXPECT_EQ(TestCaseBuilder() + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE) .SetSize(1, 2) .SetAnchorRect(2, 2, 0, 0) .SetGravity(ZXDG_POSITIONER_V6_GRAVITY_BOTTOM) @@ -98,7 +105,7 @@ TEST_F(WaylandPositionerTest, UnconstrainedCases) { gfx::Rect(2, 2, 1, 2)); // Gravity + anchor in the same direction. - EXPECT_EQ(TestCaseBuilder() + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE) .SetSize(2, 2) .SetGravity(ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | ZXDG_POSITIONER_V6_GRAVITY_LEFT) @@ -108,7 +115,7 @@ TEST_F(WaylandPositionerTest, UnconstrainedCases) { gfx::Rect(0, 3, 2, 2)); // Gravity + anchor in opposing directions. - EXPECT_EQ(TestCaseBuilder() + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE) .SetSize(2, 2) .SetGravity(ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | ZXDG_POSITIONER_V6_GRAVITY_LEFT) @@ -118,8 +125,8 @@ TEST_F(WaylandPositionerTest, UnconstrainedCases) { gfx::Rect(1, 2, 2, 2)); } -TEST_F(WaylandPositionerTest, FlipSlideResizePriority) { - TestCaseBuilder builder; +TEST_F(WaylandPositionerTest, FlipSlideResizePriorityUnstable) { + TestCaseBuilder builder{WaylandPositioner::Version::UNSTABLE}; builder.SetAnchorRect(4, 4, 0, 0) .SetSize(2, 2) .SetGravity(ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | @@ -150,10 +157,10 @@ TEST_F(WaylandPositionerTest, FlipSlideResizePriority) { gfx::Rect(4, 4, 1, 1)); } -TEST_F(WaylandPositionerTest, TriesToMaximizeArea) { +TEST_F(WaylandPositionerTest, TriesToMaximizeAreaUnstable) { // The size is too large to fit where the anchor is. WaylandPositioner::Result result = - TestCaseBuilder() + TestCaseBuilder(WaylandPositioner::Version::UNSTABLE) .SetAnchorRect(2, 4, 0, 0) .SetSize(4, 10) .SetGravity(ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | @@ -171,9 +178,9 @@ TEST_F(WaylandPositionerTest, TriesToMaximizeArea) { EXPECT_FALSE(result.y_flipped); } -TEST_F(WaylandPositionerTest, PropagatesAnInitialFlip) { +TEST_F(WaylandPositionerTest, PropagatesAnInitialFlipUnstable) { WaylandPositioner::Result result = - TestCaseBuilder() + TestCaseBuilder(WaylandPositioner::Version::UNSTABLE) .SetAnchorRect(3, 1, 0, 0) .SetSize(2, 2) .SetGravity(ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | @@ -195,8 +202,8 @@ TEST_F(WaylandPositionerTest, PropagatesAnInitialFlip) { // This is a common case for dropdown menus. In ChromeOS we do not let them // slide if they might occlude the anchor rectangle. For this case, x axis does // slide but the y axis resized instead. -TEST_F(WaylandPositionerTest, PreventsSlidingThatOccludesAnchorRect) { - EXPECT_EQ(TestCaseBuilder() +TEST_F(WaylandPositionerTest, PreventsSlidingThatOccludesAnchorRectUnstable) { + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE) .SetSize(3, 3) .SetGravity(ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | ZXDG_POSITIONER_V6_GRAVITY_RIGHT) @@ -208,7 +215,7 @@ TEST_F(WaylandPositionerTest, PreventsSlidingThatOccludesAnchorRect) { // Here we ensure that the 4x4 popup does slide, which is allowed because // the anchor rect is already occluded. - EXPECT_EQ(TestCaseBuilder() + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE) .SetSize(4, 4) .SetGravity(ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | ZXDG_POSITIONER_V6_GRAVITY_RIGHT) @@ -219,6 +226,145 @@ TEST_F(WaylandPositionerTest, PreventsSlidingThatOccludesAnchorRect) { gfx::Rect(1, 1, 4, 4)); } +// Tests for the stable protocol. + +TEST_F(WaylandPositionerTest, UnconstrainedCases) { + // No gravity or anchor. + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE) + .SetSize(1, 1) + .SolveToRect(), + gfx::Rect(2, 2, 1, 1)); + + // Anchor without gravity. + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE) + .SetSize(2, 1) + .SetAnchor(XDG_POSITIONER_ANCHOR_RIGHT) + .SolveToRect(), + gfx::Rect(2, 2, 2, 1)); + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE) + .SetSize(2, 1) + .SetAnchor(XDG_POSITIONER_ANCHOR_LEFT) + .SolveToRect(), + gfx::Rect(1, 2, 2, 1)); + + // Gravity without anchor. + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE) + .SetSize(1, 2) + .SetAnchorRect(2, 2, 0, 0) + .SetGravity(XDG_POSITIONER_GRAVITY_TOP) + .SolveToRect(), + gfx::Rect(2, 0, 1, 2)); + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE) + .SetSize(1, 2) + .SetAnchorRect(2, 2, 0, 0) + .SetGravity(XDG_POSITIONER_GRAVITY_BOTTOM) + .SolveToRect(), + gfx::Rect(2, 2, 1, 2)); + + // Gravity + anchor in the same direction. + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE) + .SetSize(2, 2) + .SetGravity(XDG_POSITIONER_GRAVITY_BOTTOM_LEFT) + .SetAnchor(XDG_POSITIONER_ANCHOR_BOTTOM_LEFT) + .SolveToRect(), + gfx::Rect(0, 3, 2, 2)); + + // Gravity + anchor in opposing directions. + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE) + .SetSize(2, 2) + .SetGravity(XDG_POSITIONER_GRAVITY_BOTTOM_LEFT) + .SetAnchor(XDG_POSITIONER_ANCHOR_TOP_RIGHT) + .SolveToRect(), + gfx::Rect(1, 2, 2, 2)); +} + +TEST_F(WaylandPositionerTest, FlipSlideResizePriority) { + TestCaseBuilder builder{WaylandPositioner::Version::STABLE}; + builder.SetAnchorRect(4, 4, 0, 0) + .SetSize(2, 2) + .SetGravity(XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT) + .SetAnchor(XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT); + // Flip is enabled, so the result will be at 2,2 (i.e. flipping a 2-wide + // square around 4,4). + EXPECT_EQ(builder.SetAdjustment(~XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE) + .SolveToRect(), + gfx::Rect(2, 2, 2, 2)); + // If we cant flip on an axis, that axis will slide to 3 instead. + EXPECT_EQ(builder.SetAdjustment(~XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X) + .SolveToRect(), + gfx::Rect(3, 2, 2, 2)); + EXPECT_EQ(builder.SetAdjustment(~XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y) + .SolveToRect(), + gfx::Rect(2, 3, 2, 2)); + // If we cant flip or slide, we resize. + EXPECT_EQ(builder + .SetAdjustment(XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y) + .SolveToRect(), + gfx::Rect(4, 4, 1, 1)); +} + +TEST_F(WaylandPositionerTest, TriesToMaximizeArea) { + // The size is too large to fit where the anchor is. + WaylandPositioner::Result result = + TestCaseBuilder(WaylandPositioner::Version::STABLE) + .SetAnchorRect(2, 4, 0, 0) + .SetSize(4, 10) + .SetGravity(XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT) + .SetAnchor(XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT) + .SetAdjustment(~XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE) + .Solve(); + // We can slide to 1 on x, but we must resize on y (after sliding to 0). + EXPECT_EQ(result.origin, gfx::Point(1, 0)); + // The x size will be preserved but y shrinks to the work area. + EXPECT_EQ(result.size, gfx::Size(4, 5)); + // Neither axis will be flipped. + EXPECT_FALSE(result.x_flipped); + EXPECT_FALSE(result.y_flipped); +} + +TEST_F(WaylandPositionerTest, PropagatesAnInitialFlip) { + WaylandPositioner::Result result = + TestCaseBuilder(WaylandPositioner::Version::STABLE) + .SetAnchorRect(3, 1, 0, 0) + .SetSize(2, 2) + .SetGravity(XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT) + .SetAnchor(XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT) + .SetAdjustment(~XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE) + .SetFlipState(true, true) + .Solve(); + // With a propagated flip state: + // - Normally the x would not need to flip, but it propagates the flip. + // - Y also propagates, but that makes it constrained so it flips back. + EXPECT_EQ(result.origin, gfx::Point(1, 1)); + EXPECT_EQ(result.size, gfx::Size(2, 2)); + EXPECT_TRUE(result.x_flipped); + EXPECT_FALSE(result.y_flipped); +} + +// This is a common case for dropdown menus. In ChromeOS we do not let them +// slide if they might occlude the anchor rectangle. For this case, x axis does +// slide but the y axis resized instead. +TEST_F(WaylandPositionerTest, PreventsSlidingThatOccludesAnchorRect) { + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE) + .SetSize(3, 3) + .SetGravity(XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT) + .SetAnchor(XDG_POSITIONER_ANCHOR_BOTTOM_LEFT) + .SetAdjustment(~XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE) + .SolveToRect(), + gfx::Rect(2, 3, 3, 2)); + + // Here we ensure that the 4x4 popup does slide, which is allowed because + // the anchor rect is already occluded. + EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE) + .SetSize(4, 4) + .SetGravity(XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT) + .SetAnchor(XDG_POSITIONER_ANCHOR_TOP_LEFT) + .SetAdjustment(~XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE) + .SolveToRect(), + gfx::Rect(1, 1, 4, 4)); +} + } // namespace } // namespace wayland } // namespace exo diff --git a/chromium/components/exo/wayland/wl_compositor.cc b/chromium/components/exo/wayland/wl_compositor.cc index 9096d2b87d6..0f01baee969 100644 --- a/chromium/components/exo/wayland/wl_compositor.cc +++ b/chromium/components/exo/wayland/wl_compositor.cc @@ -12,14 +12,17 @@ #include "components/exo/buffer.h" #include "components/exo/display.h" #include "components/exo/surface.h" +#include "components/exo/wayland/server.h" #include "components/exo/wayland/server_util.h" #include "third_party/skia/include/core/SkRegion.h" +#include "ui/display/types/display_constants.h" #if defined(OS_CHROMEOS) #include "components/exo/wayland/zwp_linux_explicit_synchronization.h" #endif namespace exo { +class Server; namespace wayland { namespace { @@ -202,8 +205,8 @@ const struct wl_surface_interface surface_implementation = { void compositor_create_surface(wl_client* client, wl_resource* resource, uint32_t id) { - std::unique_ptr<Surface> surface = - GetUserDataAs<Display>(resource)->CreateSurface(); + Display* display = GetUserDataAs<Display>(resource); + std::unique_ptr<Surface> surface = display->CreateSurface(); wl_resource* surface_resource = wl_resource_create( client, &wl_surface_interface, wl_resource_get_version(resource), id); diff --git a/chromium/components/exo/wayland/wl_data_device_manager.cc b/chromium/components/exo/wayland/wl_data_device_manager.cc index b4ee13f4f56..5d08696c85e 100644 --- a/chromium/components/exo/wayland/wl_data_device_manager.cc +++ b/chromium/components/exo/wayland/wl_data_device_manager.cc @@ -303,6 +303,11 @@ class WaylandDataDeviceDelegate : public DataDeviceDelegate { uint32_t serial) { base::Optional<wayland::SerialTracker::EventType> event_type = serial_tracker_->GetEventType(serial); + if (event_type == base::nullopt) { + LOG(ERROR) << "The serial passed to StartDrag does not exist."; + source->Cancelled(); + return; + } if (event_type == wayland::SerialTracker::EventType::POINTER_BUTTON_DOWN && serial_tracker_->GetPointerDownSerial() == serial) { data_device->StartDrag( @@ -314,8 +319,23 @@ class WaylandDataDeviceDelegate : public DataDeviceDelegate { source, origin, icon, ui::DragDropTypes::DragEventSource::DRAG_EVENT_SOURCE_TOUCH); } else { + LOG(ERROR) << "The serial passed to StartDrag does not match its " + "expected types."; + source->Cancelled(); + } + } + + void SetSelection(DataDevice* data_device, + DataSource* source, + uint32_t serial) { + base::Optional<wayland::SerialTracker::EventType> event_type = + serial_tracker_->GetEventType(serial); + if (event_type == base::nullopt) { + LOG(ERROR) << "The serial passed to SetSelection does not exist."; source->Cancelled(); + return; } + data_device->SetSelection(source); } private: @@ -347,10 +367,15 @@ void data_device_start_drag(wl_client* client, void data_device_set_selection(wl_client* client, wl_resource* resource, - wl_resource* data_source, + wl_resource* source_resource, uint32_t serial) { - GetUserDataAs<DataDevice>(resource)->SetSelection( - data_source ? GetUserDataAs<DataSource>(data_source) : nullptr, serial); + DataDevice* data_device = GetUserDataAs<DataDevice>(resource); + static_cast<WaylandDataDeviceDelegate*>(data_device->get_delegate()) + ->SetSelection(data_device, + source_resource + ? GetUserDataAs<DataSource>(source_resource) + : nullptr, + serial); } void data_device_release(wl_client* client, wl_resource* resource) { diff --git a/chromium/components/exo/wayland/wl_output.cc b/chromium/components/exo/wayland/wl_output.cc index b6b80bf515b..b95c1969890 100644 --- a/chromium/components/exo/wayland/wl_output.cc +++ b/chromium/components/exo/wayland/wl_output.cc @@ -28,15 +28,17 @@ void output_release(wl_client* client, wl_resource* resource) { const struct wl_output_interface output_implementation = {output_release}; -void bind_output(wl_client* client, void* data, uint32_t version, uint32_t id) { +void bind_output(wl_client* client, + void* data, + uint32_t version, + uint32_t output_id) { WaylandDisplayOutput* output = static_cast<WaylandDisplayOutput*>(data); - wl_resource* resource = wl_resource_create( - client, &wl_output_interface, std::min(version, kWlOutputVersion), id); - - SetImplementation( - resource, &output_implementation, - std::make_unique<WaylandDisplayObserver>(output->id(), resource)); + wl_resource* resource = + wl_resource_create(client, &wl_output_interface, + std::min(version, kWlOutputVersion), output_id); + SetImplementation(resource, &output_implementation, + std::make_unique<WaylandDisplayObserver>(output, resource)); } } // namespace wayland diff --git a/chromium/components/exo/wayland/xdg_shell.cc b/chromium/components/exo/wayland/xdg_shell.cc new file mode 100644 index 00000000000..8e8f0b4db68 --- /dev/null +++ b/chromium/components/exo/wayland/xdg_shell.cc @@ -0,0 +1,692 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/exo/wayland/xdg_shell.h" + +#include <wayland-server-core.h> +#include <wayland-server-protocol-core.h> +#include <xdg-shell-server-protocol.h> + +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/window_properties.h" +#include "ash/public/cpp/window_state_type.h" +#include "base/bind.h" +#include "base/strings/utf_string_conversions.h" +#include "components/exo/display.h" +#include "components/exo/wayland/serial_tracker.h" +#include "components/exo/wayland/server_util.h" +#include "components/exo/wayland/wayland_positioner.h" +#include "components/exo/xdg_shell_surface.h" +#include "ui/aura/window_observer.h" +#include "ui/base/hit_test.h" +#include "ui/display/screen.h" +#include "ui/views/widget/widget.h" +#include "ui/wm/core/coordinate_conversion.h" + +namespace exo { +namespace wayland { +namespace { + +//////////////////////////////////////////////////////////////////////////////// +// xdg_positioner_interface: + +void xdg_positioner_destroy(wl_client* client, wl_resource* resource) { + wl_resource_destroy(resource); +} + +void xdg_positioner_set_size(wl_client* client, + wl_resource* resource, + int32_t width, + int32_t height) { + if (width < 1 || height < 1) { + wl_resource_post_error(resource, XDG_POSITIONER_ERROR_INVALID_INPUT, + "width and height must be positive and non-zero"); + return; + } + + GetUserDataAs<WaylandPositioner>(resource)->SetSize(gfx::Size(width, height)); +} + +void xdg_positioner_set_anchor_rect(wl_client* client, + wl_resource* resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height) { + if (width < 1 || height < 1) { + wl_resource_post_error(resource, XDG_POSITIONER_ERROR_INVALID_INPUT, + "width and height must be positive and non-zero"); + return; + } + + GetUserDataAs<WaylandPositioner>(resource)->SetAnchorRect( + gfx::Rect(x, y, width, height)); +} + +void xdg_positioner_set_anchor(wl_client* client, + wl_resource* resource, + uint32_t anchor) { + if (((anchor & XDG_POSITIONER_ANCHOR_LEFT) && + (anchor & XDG_POSITIONER_ANCHOR_RIGHT)) || + ((anchor & XDG_POSITIONER_ANCHOR_TOP) && + (anchor & XDG_POSITIONER_ANCHOR_BOTTOM))) { + wl_resource_post_error(resource, XDG_POSITIONER_ERROR_INVALID_INPUT, + "same-axis values are not allowed"); + return; + } + + GetUserDataAs<WaylandPositioner>(resource)->SetAnchor(anchor); +} + +void xdg_positioner_set_gravity(wl_client* client, + wl_resource* resource, + uint32_t gravity) { + if (((gravity & XDG_POSITIONER_GRAVITY_LEFT) && + (gravity & XDG_POSITIONER_GRAVITY_RIGHT)) || + ((gravity & XDG_POSITIONER_GRAVITY_TOP) && + (gravity & XDG_POSITIONER_GRAVITY_BOTTOM))) { + wl_resource_post_error(resource, XDG_POSITIONER_ERROR_INVALID_INPUT, + "same-axis values are not allowed"); + return; + } + + GetUserDataAs<WaylandPositioner>(resource)->SetGravity(gravity); +} + +void xdg_positioner_set_constraint_adjustment(wl_client* client, + wl_resource* resource, + uint32_t adjustment) { + GetUserDataAs<WaylandPositioner>(resource)->SetAdjustment(adjustment); +} + +void xdg_positioner_set_offset(wl_client* client, + wl_resource* resource, + int32_t x, + int32_t y) { + GetUserDataAs<WaylandPositioner>(resource)->SetOffset(gfx::Vector2d(x, y)); +} + +const struct xdg_positioner_interface xdg_positioner_implementation = { + xdg_positioner_destroy, xdg_positioner_set_size, + xdg_positioner_set_anchor_rect, xdg_positioner_set_anchor, + xdg_positioner_set_gravity, xdg_positioner_set_constraint_adjustment, + xdg_positioner_set_offset}; + +//////////////////////////////////////////////////////////////////////////////// +// xdg_toplevel_interface: + +int XdgToplevelResizeComponent(uint32_t edges) { + switch (edges) { + case XDG_TOPLEVEL_RESIZE_EDGE_TOP: + return HTTOP; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM: + return HTBOTTOM; + case XDG_TOPLEVEL_RESIZE_EDGE_LEFT: + return HTLEFT; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT: + return HTTOPLEFT; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT: + return HTBOTTOMLEFT; + case XDG_TOPLEVEL_RESIZE_EDGE_RIGHT: + return HTRIGHT; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT: + return HTTOPRIGHT; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT: + return HTBOTTOMRIGHT; + default: + return HTBOTTOMRIGHT; + } +} + +using XdgSurfaceConfigureCallback = + base::RepeatingCallback<void(const gfx::Size& size, + ash::WindowStateType state_type, + bool resizing, + bool activated)>; + +uint32_t HandleXdgSurfaceConfigureCallback( + wl_resource* resource, + SerialTracker* serial_tracker, + const XdgSurfaceConfigureCallback& callback, + const gfx::Size& size, + ash::WindowStateType state_type, + bool resizing, + bool activated, + const gfx::Vector2d& origin_offset) { + uint32_t serial = + serial_tracker->GetNextSerial(SerialTracker::EventType::OTHER_EVENT); + callback.Run(size, state_type, resizing, activated); + xdg_surface_send_configure(resource, serial); + wl_client_flush(wl_resource_get_client(resource)); + return serial; +} + +struct WaylandXdgSurface { + WaylandXdgSurface(std::unique_ptr<XdgShellSurface> shell_surface, + SerialTracker* const serial_tracker) + : shell_surface(std::move(shell_surface)), + serial_tracker(serial_tracker) {} + + std::unique_ptr<XdgShellSurface> shell_surface; + + // Owned by Server, which always outlives this surface. + SerialTracker* const serial_tracker; + + DISALLOW_COPY_AND_ASSIGN(WaylandXdgSurface); +}; + +// Wrapper around shell surface that allows us to handle the case where the +// xdg surface resource is destroyed before the toplevel resource. +class WaylandToplevel : public aura::WindowObserver { + public: + WaylandToplevel(wl_resource* resource, wl_resource* surface_resource) + : resource_(resource), + shell_surface_data_( + GetUserDataAs<WaylandXdgSurface>(surface_resource)) { + shell_surface_data_->shell_surface->host_window()->AddObserver(this); + shell_surface_data_->shell_surface->set_close_callback(base::BindRepeating( + &WaylandToplevel::OnClose, weak_ptr_factory_.GetWeakPtr())); + shell_surface_data_->shell_surface->set_configure_callback( + base::BindRepeating( + &HandleXdgSurfaceConfigureCallback, surface_resource, + shell_surface_data_->serial_tracker, + base::BindRepeating(&WaylandToplevel::OnConfigure, + weak_ptr_factory_.GetWeakPtr()))); + } + ~WaylandToplevel() override { + if (shell_surface_data_) + shell_surface_data_->shell_surface->host_window()->RemoveObserver(this); + } + + // Overridden from aura::WindowObserver: + void OnWindowDestroying(aura::Window* window) override { + shell_surface_data_ = nullptr; + } + + void SetParent(WaylandToplevel* parent) { + if (!shell_surface_data_) + return; + + if (!parent) { + shell_surface_data_->shell_surface->SetParent(nullptr); + return; + } + + // This is a no-op if parent is not mapped. + if (parent->shell_surface_data_ && + parent->shell_surface_data_->shell_surface->GetWidget()) + shell_surface_data_->shell_surface->SetParent( + parent->shell_surface_data_->shell_surface.get()); + } + + void SetTitle(const base::string16& title) { + if (shell_surface_data_) + shell_surface_data_->shell_surface->SetTitle(title); + } + + void SetApplicationId(const char* application_id) { + if (shell_surface_data_) + shell_surface_data_->shell_surface->SetApplicationId(application_id); + } + + void Move() { + if (shell_surface_data_) + shell_surface_data_->shell_surface->StartMove(); + } + + void Resize(int component) { + if (!shell_surface_data_) + return; + + if (component != HTNOWHERE) + shell_surface_data_->shell_surface->StartResize(component); + } + + void SetMaximumSize(const gfx::Size& size) { + if (shell_surface_data_) + shell_surface_data_->shell_surface->SetMaximumSize(size); + } + + void SetMinimumSize(const gfx::Size& size) { + if (shell_surface_data_) + shell_surface_data_->shell_surface->SetMinimumSize(size); + } + + void Maximize() { + if (shell_surface_data_) + shell_surface_data_->shell_surface->Maximize(); + } + + void Restore() { + if (shell_surface_data_) + shell_surface_data_->shell_surface->Restore(); + } + + void SetFullscreen(bool fullscreen) { + if (shell_surface_data_) + shell_surface_data_->shell_surface->SetFullscreen(fullscreen); + } + + void Minimize() { + if (shell_surface_data_) + shell_surface_data_->shell_surface->Minimize(); + } + + private: + void OnClose() { + xdg_toplevel_send_close(resource_); + wl_client_flush(wl_resource_get_client(resource_)); + } + + static void AddState(wl_array* states, xdg_toplevel_state state) { + xdg_toplevel_state* value = static_cast<xdg_toplevel_state*>( + wl_array_add(states, sizeof(xdg_toplevel_state))); + DCHECK(value); + *value = state; + } + + void OnConfigure(const gfx::Size& size, + ash::WindowStateType state_type, + bool resizing, + bool activated) { + wl_array states; + wl_array_init(&states); + if (state_type == ash::WindowStateType::kMaximized) + AddState(&states, XDG_TOPLEVEL_STATE_MAXIMIZED); + if (state_type == ash::WindowStateType::kFullscreen) + AddState(&states, XDG_TOPLEVEL_STATE_FULLSCREEN); + if (resizing) + AddState(&states, XDG_TOPLEVEL_STATE_RESIZING); + if (activated) + AddState(&states, XDG_TOPLEVEL_STATE_ACTIVATED); + xdg_toplevel_send_configure(resource_, size.width(), size.height(), + &states); + wl_array_release(&states); + } + + wl_resource* const resource_; + WaylandXdgSurface* shell_surface_data_; + base::WeakPtrFactory<WaylandToplevel> weak_ptr_factory_{this}; + + DISALLOW_COPY_AND_ASSIGN(WaylandToplevel); +}; + +void xdg_toplevel_destroy(wl_client* client, wl_resource* resource) { + wl_resource_destroy(resource); +} + +void xdg_toplevel_set_parent(wl_client* client, + wl_resource* resource, + wl_resource* parent) { + WaylandToplevel* parent_surface = nullptr; + if (parent) + parent_surface = GetUserDataAs<WaylandToplevel>(parent); + + GetUserDataAs<WaylandToplevel>(resource)->SetParent(parent_surface); +} + +void xdg_toplevel_set_title(wl_client* client, + wl_resource* resource, + const char* title) { + GetUserDataAs<WaylandToplevel>(resource)->SetTitle( + base::string16(base::UTF8ToUTF16(title))); +} + +void xdg_toplevel_set_app_id(wl_client* client, + wl_resource* resource, + const char* app_id) { + GetUserDataAs<WaylandToplevel>(resource)->SetApplicationId(app_id); +} + +void xdg_toplevel_show_window_menu(wl_client* client, + wl_resource* resource, + wl_resource* seat, + uint32_t serial, + int32_t x, + int32_t y) { + NOTIMPLEMENTED(); +} + +void xdg_toplevel_move(wl_client* client, + wl_resource* resource, + wl_resource* seat, + uint32_t serial) { + GetUserDataAs<WaylandToplevel>(resource)->Move(); +} + +void xdg_toplevel_resize(wl_client* client, + wl_resource* resource, + wl_resource* seat, + uint32_t serial, + uint32_t edges) { + GetUserDataAs<WaylandToplevel>(resource)->Resize( + XdgToplevelResizeComponent(edges)); +} + +void xdg_toplevel_set_max_size(wl_client* client, + wl_resource* resource, + int32_t width, + int32_t height) { + GetUserDataAs<WaylandToplevel>(resource)->SetMaximumSize( + gfx::Size(width, height)); +} + +void xdg_toplevel_set_min_size(wl_client* client, + wl_resource* resource, + int32_t width, + int32_t height) { + GetUserDataAs<WaylandToplevel>(resource)->SetMinimumSize( + gfx::Size(width, height)); +} + +void xdg_toplevel_set_maximized(wl_client* client, wl_resource* resource) { + GetUserDataAs<WaylandToplevel>(resource)->Maximize(); +} + +void xdg_toplevel_unset_maximized(wl_client* client, wl_resource* resource) { + GetUserDataAs<WaylandToplevel>(resource)->Restore(); +} + +void xdg_toplevel_set_fullscreen(wl_client* client, + wl_resource* resource, + wl_resource* output) { + GetUserDataAs<WaylandToplevel>(resource)->SetFullscreen(true); +} + +void xdg_toplevel_unset_fullscreen(wl_client* client, wl_resource* resource) { + GetUserDataAs<WaylandToplevel>(resource)->SetFullscreen(false); +} + +void xdg_toplevel_set_minimized(wl_client* client, wl_resource* resource) { + GetUserDataAs<WaylandToplevel>(resource)->Minimize(); +} + +const struct xdg_toplevel_interface xdg_toplevel_implementation = { + xdg_toplevel_destroy, xdg_toplevel_set_parent, + xdg_toplevel_set_title, xdg_toplevel_set_app_id, + xdg_toplevel_show_window_menu, xdg_toplevel_move, + xdg_toplevel_resize, xdg_toplevel_set_max_size, + xdg_toplevel_set_min_size, xdg_toplevel_set_maximized, + xdg_toplevel_unset_maximized, xdg_toplevel_set_fullscreen, + xdg_toplevel_unset_fullscreen, xdg_toplevel_set_minimized}; + +//////////////////////////////////////////////////////////////////////////////// +// xdg_popup_interface: + +// Wrapper around shell surface that allows us to handle the case where the +// xdg surface resource is destroyed before the popup resource. +class WaylandPopup : aura::WindowObserver { + public: + WaylandPopup(wl_resource* resource, wl_resource* surface_resource) + : resource_(resource), + shell_surface_data_( + GetUserDataAs<WaylandXdgSurface>(surface_resource)) { + shell_surface_data_->shell_surface->host_window()->AddObserver(this); + shell_surface_data_->shell_surface->set_close_callback(base::BindRepeating( + &WaylandPopup::OnClose, weak_ptr_factory_.GetWeakPtr())); + shell_surface_data_->shell_surface->set_configure_callback( + base::BindRepeating( + &HandleXdgSurfaceConfigureCallback, surface_resource, + shell_surface_data_->serial_tracker, + base::BindRepeating(&WaylandPopup::OnConfigure, + weak_ptr_factory_.GetWeakPtr()))); + } + ~WaylandPopup() override { + if (shell_surface_data_) + shell_surface_data_->shell_surface->host_window()->RemoveObserver(this); + } + + void Grab() { + if (!shell_surface_data_) { + wl_resource_post_error(resource_, XDG_POPUP_ERROR_INVALID_GRAB, + "the surface has already been destroyed"); + return; + } + if (shell_surface_data_->shell_surface->GetWidget()) { + wl_resource_post_error(resource_, XDG_POPUP_ERROR_INVALID_GRAB, + "grab must be called before construction"); + return; + } + shell_surface_data_->shell_surface->Grab(); + } + + // Overridden from aura::WindowObserver: + void OnWindowDestroying(aura::Window* window) override { + shell_surface_data_ = nullptr; + } + + private: + void OnClose() { + xdg_popup_send_popup_done(resource_); + wl_client_flush(wl_resource_get_client(resource_)); + } + + void OnConfigure(const gfx::Size& size, + ash::WindowStateType state_type, + bool resizing, + bool activated) { + // Nothing to do here as popups don't have additional configure state. + } + + wl_resource* const resource_; + WaylandXdgSurface* shell_surface_data_; + base::WeakPtrFactory<WaylandPopup> weak_ptr_factory_{this}; + + DISALLOW_COPY_AND_ASSIGN(WaylandPopup); +}; + +void xdg_popup_destroy(wl_client* client, wl_resource* resource) { + wl_resource_destroy(resource); +} + +void xdg_popup_grab(wl_client* client, + wl_resource* resource, + wl_resource* seat, + uint32_t serial) { + GetUserDataAs<WaylandPopup>(resource)->Grab(); +} + +const struct xdg_popup_interface xdg_popup_implementation = {xdg_popup_destroy, + xdg_popup_grab}; + +//////////////////////////////////////////////////////////////////////////////// +// xdg_surface_interface: + +void xdg_surface_destroy(wl_client* client, wl_resource* resource) { + wl_resource_destroy(resource); +} + +void xdg_surface_get_toplevel(wl_client* client, + wl_resource* resource, + uint32_t id) { + auto* shell_surface_data = GetUserDataAs<WaylandXdgSurface>(resource); + if (shell_surface_data->shell_surface->GetEnabled()) { + wl_resource_post_error(resource, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, + "surface has already been constructed"); + return; + } + + shell_surface_data->shell_surface->SetCanMinimize(true); + shell_surface_data->shell_surface->SetEnabled(true); + + wl_resource* xdg_toplevel_resource = + wl_resource_create(client, &xdg_toplevel_interface, 1, id); + + SetImplementation( + xdg_toplevel_resource, &xdg_toplevel_implementation, + std::make_unique<WaylandToplevel>(xdg_toplevel_resource, resource)); +} + +void xdg_surface_get_popup(wl_client* client, + wl_resource* resource, + uint32_t id, + wl_resource* parent_resource, + wl_resource* positioner_resource) { + auto* shell_surface_data = GetUserDataAs<WaylandXdgSurface>(resource); + if (shell_surface_data->shell_surface->GetEnabled()) { + wl_resource_post_error(resource, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, + "surface has already been constructed"); + return; + } + + if (!parent_resource) { + wl_resource_post_error(resource, XDG_SURFACE_ERROR_NOT_CONSTRUCTED, + "popup parent not supplied"); + return; + } + + auto* parent_data = GetUserDataAs<WaylandXdgSurface>(parent_resource); + if (!parent_data->shell_surface->GetWidget()) { + wl_resource_post_error(resource, XDG_SURFACE_ERROR_NOT_CONSTRUCTED, + "popup parent not constructed"); + return; + } + + if (shell_surface_data->shell_surface->GetWidget()) { + wl_resource_post_error(resource, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, + "get_popup is called after constructed"); + return; + } + + display::Display display = + display::Screen::GetScreen()->GetDisplayNearestWindow( + parent_data->shell_surface->GetWidget()->GetNativeWindow()); + gfx::Rect work_area = display.work_area(); + wm::ConvertRectFromScreen( + parent_data->shell_surface->GetWidget()->GetNativeWindow(), &work_area); + + // Try layout using parent's flip state. + WaylandPositioner* positioner = + GetUserDataAs<WaylandPositioner>(positioner_resource); + WaylandPositioner::Result position = positioner->CalculatePosition( + work_area, parent_data->shell_surface->x_flipped(), + parent_data->shell_surface->y_flipped()); + + // Remember the new flip state for its child popups. + shell_surface_data->shell_surface->set_x_flipped(position.x_flipped); + shell_surface_data->shell_surface->set_y_flipped(position.y_flipped); + + // |position| is relative to the parent's contents view origin, and |origin| + // is in screen coordinates. + gfx::Point origin = position.origin; + views::View::ConvertPointToScreen(parent_data->shell_surface->GetWidget() + ->widget_delegate() + ->GetContentsView(), + &origin); + shell_surface_data->shell_surface->SetOrigin(origin); + shell_surface_data->shell_surface->SetSize(position.size); + shell_surface_data->shell_surface->DisableMovement(); + shell_surface_data->shell_surface->SetActivatable(false); + shell_surface_data->shell_surface->SetCanMinimize(false); + shell_surface_data->shell_surface->SetParent( + parent_data->shell_surface.get()); + shell_surface_data->shell_surface->SetPopup(); + shell_surface_data->shell_surface->SetEnabled(true); + + wl_resource* xdg_popup_resource = + wl_resource_create(client, &xdg_popup_interface, 1, id); + + SetImplementation( + xdg_popup_resource, &xdg_popup_implementation, + std::make_unique<WaylandPopup>(xdg_popup_resource, resource)); + + // We send the configure event here as this event needs x,y coordinates + // relative to the parent window. + xdg_popup_send_configure(xdg_popup_resource, position.origin.x(), + position.origin.y(), position.size.width(), + position.size.height()); +} + +void xdg_surface_set_window_geometry(wl_client* client, + wl_resource* resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height) { + GetUserDataAs<WaylandXdgSurface>(resource)->shell_surface->SetGeometry( + gfx::Rect(x, y, width, height)); +} + +void xdg_surface_ack_configure(wl_client* client, + wl_resource* resource, + uint32_t serial) { + GetUserDataAs<WaylandXdgSurface>(resource) + ->shell_surface->AcknowledgeConfigure(serial); +} + +const struct xdg_surface_interface xdg_surface_implementation = { + xdg_surface_destroy, xdg_surface_get_toplevel, xdg_surface_get_popup, + xdg_surface_set_window_geometry, xdg_surface_ack_configure}; + +//////////////////////////////////////////////////////////////////////////////// +// xdg_wm_base_interface: + +void xdg_wm_base_destroy(wl_client* client, wl_resource* resource) { + // Nothing to do here. +} + +void xdg_wm_base_create_positioner(wl_client* client, + wl_resource* resource, + uint32_t id) { + wl_resource* positioner_resource = + wl_resource_create(client, &xdg_positioner_interface, 1, id); + + SetImplementation( + positioner_resource, &xdg_positioner_implementation, + std::make_unique<WaylandPositioner>(WaylandPositioner::Version::STABLE)); +} + +void xdg_wm_base_get_xdg_surface(wl_client* client, + wl_resource* resource, + uint32_t id, + wl_resource* surface) { + auto* data = GetUserDataAs<WaylandXdgShell>(resource); + std::unique_ptr<XdgShellSurface> shell_surface = + data->display->CreateXdgShellSurface(GetUserDataAs<Surface>(surface)); + if (!shell_surface) { + wl_resource_post_error(resource, XDG_WM_BASE_ERROR_ROLE, + "surface has already been assigned a role"); + return; + } + + // Xdg shell surfaces are initially disabled and needs to be explicitly mapped + // before they are enabled and can become visible. + shell_surface->SetEnabled(false); + + std::unique_ptr<WaylandXdgSurface> wayland_shell_surface = + std::make_unique<WaylandXdgSurface>(std::move(shell_surface), + data->serial_tracker); + + wl_resource* xdg_surface_resource = + wl_resource_create(client, &xdg_surface_interface, 1, id); + + SetImplementation(xdg_surface_resource, &xdg_surface_implementation, + std::move(wayland_shell_surface)); +} + +void xdg_wm_base_pong(wl_client* client, + wl_resource* resource, + uint32_t serial) { + NOTIMPLEMENTED(); +} + +const struct xdg_wm_base_interface xdg_wm_base_implementation = { + xdg_wm_base_destroy, xdg_wm_base_create_positioner, + xdg_wm_base_get_xdg_surface, xdg_wm_base_pong}; + +} // namespace + +void bind_xdg_shell(wl_client* client, + void* data, + uint32_t version, + uint32_t id) { + wl_resource* resource = + wl_resource_create(client, &xdg_wm_base_interface, 1, id); + + wl_resource_set_implementation(resource, &xdg_wm_base_implementation, data, + nullptr); +} + +} // namespace wayland +} // namespace exo diff --git a/chromium/components/exo/wayland/xdg_shell.h b/chromium/components/exo/wayland/xdg_shell.h new file mode 100644 index 00000000000..9619efdea12 --- /dev/null +++ b/chromium/components/exo/wayland/xdg_shell.h @@ -0,0 +1,41 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_EXO_WAYLAND_XDG_SHELL_H_ +#define COMPONENTS_EXO_WAYLAND_XDG_SHELL_H_ + +#include <stdint.h> + +#include "base/macros.h" + +struct wl_client; + +namespace exo { +class Display; + +namespace wayland { +class SerialTracker; + +struct WaylandXdgShell { + WaylandXdgShell(Display* display, SerialTracker* serial_tracker) + : display(display), serial_tracker(serial_tracker) {} + + // Owned by WaylandServerController, which always outlives xdg_shell. + Display* const display; + + // Owned by Server, which always outlives xdg_shell. + SerialTracker* const serial_tracker; + + DISALLOW_COPY_AND_ASSIGN(WaylandXdgShell); +}; + +void bind_xdg_shell(wl_client* client, + void* data, + uint32_t version, + uint32_t id); + +} // namespace wayland +} // namespace exo + +#endif // COMPONENTS_EXO_WAYLAND_XDG_SHELL_H_ diff --git a/chromium/components/exo/wayland/zaura_shell.cc b/chromium/components/exo/wayland/zaura_shell.cc index a3b0a7b6fcd..b80e9ebb559 100644 --- a/chromium/components/exo/wayland/zaura_shell.cc +++ b/chromium/components/exo/wayland/zaura_shell.cc @@ -224,7 +224,7 @@ void AuraSurface::OnSurfaceDestroying(Surface* surface) { } void AuraSurface::OnWindowOcclusionChanged(Surface* surface) { - if (!surface_ || !surface_->is_tracking_occlusion()) + if (!surface_ || !surface_->IsTrackingOcclusion()) return; auto* window = surface_->window(); ComputeAndSendOcclusionFraction(window->occlusion_state(), @@ -241,7 +241,7 @@ void AuraSurface::OnWindowActivating(ActivationReason reason, // Check if this surface is a child of a window that is losing focus. auto* widget = views::Widget::GetTopLevelWidgetForNativeView(window); if (!widget || losing_active != widget->GetNativeWindow() || - !surface_->is_tracking_occlusion()) + !surface_->IsTrackingOcclusion()) return; // Result may be changed by animated windows, so compute it explicitly. diff --git a/chromium/components/exo/wayland/zaura_shell_unittest.cc b/chromium/components/exo/wayland/zaura_shell_unittest.cc index 4a7218ca626..90db54f3845 100644 --- a/chromium/components/exo/wayland/zaura_shell_unittest.cc +++ b/chromium/components/exo/wayland/zaura_shell_unittest.cc @@ -11,6 +11,7 @@ #include "ash/wm/desks/desks_util.h" #include "ash/wm/window_util.h" #include "base/time/time.h" +#include "components/exo/buffer.h" #include "components/exo/test/exo_test_base.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/aura/window_occlusion_tracker.h" @@ -67,7 +68,13 @@ class ZAuraSurfaceTest : public test::ExoTestBase, void SetUp() override { test::ExoTestBase::SetUp(); + gfx::Size buffer_size(10, 10); + std::unique_ptr<Buffer> buffer( + new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size))); + surface_.reset(new Surface); + surface_->Attach(buffer.get()); + aura_surface_.reset(new TestAuraSurface(surface_.get())); gfx::Transform transform; @@ -128,8 +135,25 @@ class ZAuraSurfaceTest : public test::ExoTestBase, DISALLOW_COPY_AND_ASSIGN(ZAuraSurfaceTest); }; +TEST_F(ZAuraSurfaceTest, OcclusionTrackingStartsAfterCommit) { + surface().OnWindowOcclusionChanged(); + + EXPECT_EQ(-1.0f, aura_surface().last_sent_occlusion_fraction()); + EXPECT_EQ(0, aura_surface().num_occlusion_updates()); + EXPECT_FALSE(surface().IsTrackingOcclusion()); + + auto widget = CreateOpaqueWidget(gfx::Rect(0, 0, 10, 10)); + widget->Show(); + surface().Commit(); + + EXPECT_EQ(0.2f, aura_surface().last_sent_occlusion_fraction()); + EXPECT_EQ(1, aura_surface().num_occlusion_updates()); + EXPECT_TRUE(surface().IsTrackingOcclusion()); +} + TEST_F(ZAuraSurfaceTest, LosingActivationWithNoAnimatingWindowsSendsCorrectOcclusionFraction) { + surface().Commit(); EXPECT_EQ(0.0f, aura_surface().last_sent_occlusion_fraction()); EXPECT_EQ(1, aura_surface().num_occlusion_updates()); ::wm::ActivateWindow(parent_widget().GetNativeWindow()); @@ -146,6 +170,7 @@ TEST_F(ZAuraSurfaceTest, TEST_F(ZAuraSurfaceTest, LosingActivationWithAnimatingWindowsSendsTargetOcclusionFraction) { + surface().Commit(); EXPECT_EQ(0.0f, aura_surface().last_sent_occlusion_fraction()); EXPECT_EQ(1, aura_surface().num_occlusion_updates()); ::wm::ActivateWindow(parent_widget().GetNativeWindow()); @@ -194,6 +219,7 @@ TEST_F(ZAuraSurfaceTest, TEST_F(ZAuraSurfaceTest, LosingActivationByTriggeringTheLockScreenDoesNotSendOccludedFraction) { + surface().Commit(); EXPECT_EQ(0.0f, aura_surface().last_sent_occlusion_fraction()); EXPECT_EQ(1, aura_surface().num_occlusion_updates()); ::wm::ActivateWindow(parent_widget().GetNativeWindow()); @@ -227,9 +253,16 @@ TEST_F(ZAuraSurfaceTest, TEST_F(ZAuraSurfaceTest, OcclusionIncludesOffScreenArea) { UpdateDisplay("150x150"); + + gfx::Size buffer_size(80, 100); + std::unique_ptr<Buffer> buffer( + new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size))); // This is scaled by 1.5 - set the bounds to (-60, 75, 120, 150) in screen // coordinates so 75% of it is outside of the 100x100 screen. surface().window()->SetBounds(gfx::Rect(-40, 50, 80, 100)); + surface().Attach(buffer.get()); + surface().Commit(); + surface().OnWindowOcclusionChanged(); EXPECT_EQ(0.75f, aura_surface().last_sent_occlusion_fraction()); @@ -238,6 +271,7 @@ TEST_F(ZAuraSurfaceTest, OcclusionIncludesOffScreenArea) { TEST_F(ZAuraSurfaceTest, ZeroSizeWindowSendsZeroOcclusionFraction) { // Zero sized window should not be occluded. surface().window()->SetBounds(gfx::Rect(0, 0, 0, 0)); + surface().Commit(); surface().OnWindowOcclusionChanged(); EXPECT_EQ(0.0f, aura_surface().last_sent_occlusion_fraction()); } diff --git a/chromium/components/exo/wayland/zcr_gaming_input.cc b/chromium/components/exo/wayland/zcr_gaming_input.cc index ad9a7464fad..a8d61c04d6d 100644 --- a/chromium/components/exo/wayland/zcr_gaming_input.cc +++ b/chromium/components/exo/wayland/zcr_gaming_input.cc @@ -8,6 +8,8 @@ #include <wayland-server-core.h> #include <wayland-server-protocol-core.h> +#include <memory> + #include "base/feature_list.h" #include "base/macros.h" #include "components/exo/gamepad_delegate.h" @@ -64,27 +66,30 @@ class WaylandGamepadDelegate : public GamepadDelegate { wl_resource_set_user_data(gamepad_resource_, nullptr); delete this; } - void OnAxis(int axis, double value) override { + void OnAxis(int axis, double value, base::TimeTicks time_stamp) override { if (!gamepad_resource_) { return; } - zcr_gamepad_v2_send_axis(gamepad_resource_, NowInMilliseconds(), axis, + zcr_gamepad_v2_send_axis(gamepad_resource_, + TimeTicksToMilliseconds(time_stamp), axis, wl_fixed_from_double(value)); } - void OnButton(int button, bool pressed) override { + void OnButton(int button, bool pressed, base::TimeTicks time_stamp) override { if (!gamepad_resource_) { return; } uint32_t state = pressed ? ZCR_GAMEPAD_V2_BUTTON_STATE_PRESSED : ZCR_GAMEPAD_V2_BUTTON_STATE_RELEASED; - zcr_gamepad_v2_send_button(gamepad_resource_, NowInMilliseconds(), button, + zcr_gamepad_v2_send_button(gamepad_resource_, + TimeTicksToMilliseconds(time_stamp), button, state, wl_fixed_from_double(0)); } - void OnFrame() override { + void OnFrame(base::TimeTicks time_stamp) override { if (!gamepad_resource_) { return; } - zcr_gamepad_v2_send_frame(gamepad_resource_, NowInMilliseconds()); + zcr_gamepad_v2_send_frame(gamepad_resource_, + TimeTicksToMilliseconds(time_stamp)); wl_client_flush(client()); } diff --git a/chromium/components/exo/wayland/zwp_text_input_manager.cc b/chromium/components/exo/wayland/zwp_text_input_manager.cc index 35df45bb43a..3d115a5b528 100644 --- a/chromium/components/exo/wayland/zwp_text_input_manager.cc +++ b/chromium/components/exo/wayland/zwp_text_input_manager.cc @@ -71,6 +71,7 @@ class WaylandTextInputDelegate : public TextInput::Delegate { style = ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_SELECTION; break; case ui::ImeTextSpan::Type::kMisspellingSuggestion: + case ui::ImeTextSpan::Type::kAutocorrect: style = ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_INCORRECT; break; } diff --git a/chromium/components/exo/wayland/zxdg_shell.cc b/chromium/components/exo/wayland/zxdg_shell.cc index fde5aec2fbc..a4284484676 100644 --- a/chromium/components/exo/wayland/zxdg_shell.cc +++ b/chromium/components/exo/wayland/zxdg_shell.cc @@ -632,14 +632,15 @@ void xdg_shell_v6_create_positioner(wl_client* client, wl_resource_create(client, &zxdg_positioner_v6_interface, 1, id); SetImplementation(positioner_resource, &xdg_positioner_v6_implementation, - std::make_unique<WaylandPositioner>()); + std::make_unique<WaylandPositioner>( + WaylandPositioner::Version::UNSTABLE)); } void xdg_shell_v6_get_xdg_surface(wl_client* client, wl_resource* resource, uint32_t id, wl_resource* surface) { - auto* data = GetUserDataAs<WaylandXdgShell>(resource); + auto* data = GetUserDataAs<WaylandZxdgShell>(resource); std::unique_ptr<XdgShellSurface> shell_surface = data->display->CreateXdgShellSurface(GetUserDataAs<Surface>(surface)); if (!shell_surface) { @@ -675,10 +676,10 @@ const struct zxdg_shell_v6_interface xdg_shell_v6_implementation = { } // namespace -void bind_xdg_shell_v6(wl_client* client, - void* data, - uint32_t version, - uint32_t id) { +void bind_zxdg_shell_v6(wl_client* client, + void* data, + uint32_t version, + uint32_t id) { wl_resource* resource = wl_resource_create(client, &zxdg_shell_v6_interface, 1, id); diff --git a/chromium/components/exo/wayland/zxdg_shell.h b/chromium/components/exo/wayland/zxdg_shell.h index f5112d36170..026a8bbc690 100644 --- a/chromium/components/exo/wayland/zxdg_shell.h +++ b/chromium/components/exo/wayland/zxdg_shell.h @@ -17,8 +17,8 @@ class Display; namespace wayland { class SerialTracker; -struct WaylandXdgShell { - WaylandXdgShell(Display* display, SerialTracker* serial_tracker) +struct WaylandZxdgShell { + WaylandZxdgShell(Display* display, SerialTracker* serial_tracker) : display(display), serial_tracker(serial_tracker) {} // Owned by WaylandServerController, which always outlives zxdg_shell. @@ -27,13 +27,13 @@ struct WaylandXdgShell { // Owned by Server, which always outlives zxdg_shell. SerialTracker* const serial_tracker; - DISALLOW_COPY_AND_ASSIGN(WaylandXdgShell); + DISALLOW_COPY_AND_ASSIGN(WaylandZxdgShell); }; -void bind_xdg_shell_v6(wl_client* client, - void* data, - uint32_t version, - uint32_t id); +void bind_zxdg_shell_v6(wl_client* client, + void* data, + uint32_t version, + uint32_t id); } // namespace wayland } // namespace exo |