| // Copyright 2021 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 "ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h" |
| |
| #include <xdg-decoration-unstable-v1-client-protocol.h> |
| #include <xdg-shell-client-protocol.h> |
| #include <xdg-shell-unstable-v6-client-protocol.h> |
| |
| #include "base/logging.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "ui/base/hit_test.h" |
| #include "ui/ozone/platform/wayland/common/wayland_util.h" |
| #include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h" |
| #include "ui/ozone/platform/wayland/host/wayland_connection.h" |
| #include "ui/ozone/platform/wayland/host/wayland_window.h" |
| #include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h" |
| |
| namespace ui { |
| |
| namespace { |
| |
| XDGToplevelWrapperImpl::DecorationMode ToDecorationMode(uint32_t mode) { |
| switch (mode) { |
| case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE: |
| return XDGToplevelWrapperImpl::DecorationMode::kClientSide; |
| case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE: |
| return XDGToplevelWrapperImpl::DecorationMode::kServerSide; |
| default: |
| NOTREACHED(); |
| return XDGToplevelWrapperImpl::DecorationMode::kClientSide; |
| } |
| } |
| |
| uint32_t ToInt32(XDGToplevelWrapperImpl::DecorationMode mode) { |
| switch (mode) { |
| case XDGToplevelWrapperImpl::DecorationMode::kClientSide: |
| return ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; |
| case XDGToplevelWrapperImpl::DecorationMode::kServerSide: |
| return ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; |
| default: |
| NOTREACHED(); |
| return ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; |
| } |
| } |
| |
| } // namespace |
| |
| XDGToplevelWrapperImpl::XDGToplevelWrapperImpl( |
| std::unique_ptr<XDGSurfaceWrapperImpl> surface, |
| WaylandWindow* wayland_window, |
| WaylandConnection* connection) |
| : xdg_surface_wrapper_(std::move(surface)), |
| wayland_window_(wayland_window), |
| connection_(connection), |
| decoration_mode_(DecorationMode::kNone) {} |
| |
| XDGToplevelWrapperImpl::~XDGToplevelWrapperImpl() = default; |
| |
| bool XDGToplevelWrapperImpl::Initialize() { |
| if (!connection_->shell()) { |
| NOTREACHED() << "Wrong shell protocol"; |
| return false; |
| } |
| |
| static const xdg_toplevel_listener xdg_toplevel_listener = { |
| &XDGToplevelWrapperImpl::ConfigureTopLevel, |
| &XDGToplevelWrapperImpl::CloseTopLevel, |
| }; |
| |
| if (!xdg_surface_wrapper_) |
| return false; |
| |
| xdg_toplevel_.reset( |
| xdg_surface_get_toplevel(xdg_surface_wrapper_->xdg_surface())); |
| if (!xdg_toplevel_) { |
| LOG(ERROR) << "Failed to create xdg_toplevel"; |
| return false; |
| } |
| |
| xdg_toplevel_add_listener(xdg_toplevel_.get(), &xdg_toplevel_listener, this); |
| |
| InitializeXdgDecoration(); |
| |
| wayland_window_->root_surface()->Commit(); |
| connection_->ScheduleFlush(); |
| return true; |
| } |
| |
| void XDGToplevelWrapperImpl::SetMaximized() { |
| DCHECK(xdg_toplevel_); |
| xdg_toplevel_set_maximized(xdg_toplevel_.get()); |
| } |
| |
| void XDGToplevelWrapperImpl::UnSetMaximized() { |
| DCHECK(xdg_toplevel_); |
| xdg_toplevel_unset_maximized(xdg_toplevel_.get()); |
| } |
| |
| void XDGToplevelWrapperImpl::SetFullscreen() { |
| DCHECK(xdg_toplevel_); |
| xdg_toplevel_set_fullscreen(xdg_toplevel_.get(), nullptr); |
| } |
| |
| void XDGToplevelWrapperImpl::UnSetFullscreen() { |
| DCHECK(xdg_toplevel_); |
| xdg_toplevel_unset_fullscreen(xdg_toplevel_.get()); |
| } |
| |
| void XDGToplevelWrapperImpl::SetMinimized() { |
| DCHECK(xdg_toplevel_); |
| xdg_toplevel_set_minimized(xdg_toplevel_.get()); |
| } |
| |
| void XDGToplevelWrapperImpl::SurfaceMove(WaylandConnection* connection) { |
| DCHECK(xdg_toplevel_); |
| xdg_toplevel_move(xdg_toplevel_.get(), connection->seat(), |
| connection->serial()); |
| } |
| |
| void XDGToplevelWrapperImpl::SurfaceResize(WaylandConnection* connection, |
| uint32_t hittest) { |
| DCHECK(xdg_toplevel_); |
| xdg_toplevel_resize(xdg_toplevel_.get(), connection->seat(), |
| connection->serial(), |
| wl::IdentifyDirection(*connection, hittest)); |
| } |
| |
| void XDGToplevelWrapperImpl::SetTitle(const std::u16string& title) { |
| DCHECK(xdg_toplevel_); |
| xdg_toplevel_set_title(xdg_toplevel_.get(), base::UTF16ToUTF8(title).c_str()); |
| } |
| |
| void XDGToplevelWrapperImpl::SetWindowGeometry(const gfx::Rect& bounds) { |
| xdg_surface_wrapper_->SetWindowGeometry(bounds); |
| } |
| |
| void XDGToplevelWrapperImpl::SetMinSize(int32_t width, int32_t height) { |
| DCHECK(xdg_toplevel_); |
| xdg_toplevel_set_min_size(xdg_toplevel_.get(), width, height); |
| } |
| |
| void XDGToplevelWrapperImpl::SetMaxSize(int32_t width, int32_t height) { |
| DCHECK(xdg_toplevel_); |
| xdg_toplevel_set_max_size(xdg_toplevel_.get(), width, height); |
| } |
| |
| void XDGToplevelWrapperImpl::SetAppId(const std::string& app_id) { |
| DCHECK(xdg_toplevel_); |
| xdg_toplevel_set_app_id(xdg_toplevel_.get(), app_id.c_str()); |
| } |
| |
| void XDGToplevelWrapperImpl::SetDecoration(DecorationMode decoration) { |
| SetTopLevelDecorationMode(decoration); |
| } |
| |
| void XDGToplevelWrapperImpl::AckConfigure(uint32_t serial) { |
| DCHECK(xdg_surface_wrapper_); |
| xdg_surface_wrapper_->AckConfigure(serial); |
| } |
| |
| bool XDGToplevelWrapperImpl::IsConfigured() { |
| DCHECK(xdg_surface_wrapper_); |
| return xdg_surface_wrapper_->IsConfigured(); |
| } |
| |
| // static |
| void XDGToplevelWrapperImpl::ConfigureTopLevel( |
| void* data, |
| struct xdg_toplevel* xdg_toplevel, |
| int32_t width, |
| int32_t height, |
| struct wl_array* states) { |
| auto* surface = static_cast<XDGToplevelWrapperImpl*>(data); |
| DCHECK(surface); |
| |
| bool is_maximized = |
| CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_MAXIMIZED); |
| bool is_fullscreen = |
| CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_FULLSCREEN); |
| bool is_activated = |
| CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_ACTIVATED); |
| |
| surface->wayland_window_->HandleToplevelConfigure( |
| width, height, is_maximized, is_fullscreen, is_activated); |
| } |
| |
| // static |
| void XDGToplevelWrapperImpl::CloseTopLevel(void* data, |
| struct xdg_toplevel* xdg_toplevel) { |
| auto* surface = static_cast<XDGToplevelWrapperImpl*>(data); |
| DCHECK(surface); |
| surface->wayland_window_->OnCloseRequest(); |
| } |
| |
| void XDGToplevelWrapperImpl::SetTopLevelDecorationMode( |
| DecorationMode requested_mode) { |
| if (!zxdg_toplevel_decoration_ || requested_mode == decoration_mode_) |
| return; |
| |
| zxdg_toplevel_decoration_v1_set_mode(zxdg_toplevel_decoration_.get(), |
| ToInt32(requested_mode)); |
| } |
| |
| // static |
| void XDGToplevelWrapperImpl::ConfigureDecoration( |
| void* data, |
| struct zxdg_toplevel_decoration_v1* decoration, |
| uint32_t mode) { |
| auto* surface = static_cast<XDGToplevelWrapperImpl*>(data); |
| DCHECK(surface); |
| surface->decoration_mode_ = ToDecorationMode(mode); |
| surface->AckConfigure(surface->connection_->serial()); |
| } |
| |
| void XDGToplevelWrapperImpl::InitializeXdgDecoration() { |
| if (connection_->xdg_decoration_manager_v1()) { |
| DCHECK(!zxdg_toplevel_decoration_); |
| static const zxdg_toplevel_decoration_v1_listener decoration_listener = { |
| &XDGToplevelWrapperImpl::ConfigureDecoration, |
| }; |
| zxdg_toplevel_decoration_.reset( |
| zxdg_decoration_manager_v1_get_toplevel_decoration( |
| connection_->xdg_decoration_manager_v1(), xdg_toplevel_.get())); |
| zxdg_toplevel_decoration_v1_add_listener(zxdg_toplevel_decoration_.get(), |
| &decoration_listener, this); |
| } |
| } |
| |
| XDGSurfaceWrapperImpl* XDGToplevelWrapperImpl::xdg_surface_wrapper() const { |
| DCHECK(xdg_surface_wrapper_.get()); |
| return xdg_surface_wrapper_.get(); |
| } |
| |
| } // namespace ui |