diff --git a/cmake/build.cmake b/cmake/build.cmake index e97728f..cde9cc9 100644 --- a/cmake/build.cmake +++ b/cmake/build.cmake @@ -63,6 +63,11 @@ else() CODE_FILE "${_wayland_protocols_src_dir}/presentation-time-protocol.c" HEADER_FILE "${_wayland_protocols_src_dir}/presentation-time-protocol.h") + generate_wayland_client_protocol( + PROTOCOL_FILE "${_wayland_protocols_xml_dir}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" + CODE_FILE "${_wayland_protocols_src_dir}/xdg-decoration-unstable-v1-protocol.c" + HEADER_FILE "${_wayland_protocols_src_dir}/xdg-decoration-unstable-v1-protocol.h") + add_definitions(-DFLUTTER_TARGET_BACKEND_WAYLAND) add_definitions(-DDISPLAY_BACKEND_TYPE_WAYLAND) set(DISPLAY_BACKEND_SRC @@ -70,6 +75,7 @@ else() "${_wayland_protocols_src_dir}/text-input-unstable-v1-protocol.c" "${_wayland_protocols_src_dir}/text-input-unstable-v3-protocol.c" "${_wayland_protocols_src_dir}/presentation-time-protocol.c" + "${_wayland_protocols_src_dir}/xdg-decoration-unstable-v1-protocol.c" "src/flutter/shell/platform/linux_embedded/window/elinux_window_wayland.cc" "src/flutter/shell/platform/linux_embedded/window/native_window_wayland.cc" "src/flutter/shell/platform/linux_embedded/window/native_window_wayland_decoration.cc" diff --git a/src/flutter/shell/platform/linux_embedded/window/elinux_window_wayland.cc b/src/flutter/shell/platform/linux_embedded/window/elinux_window_wayland.cc index 2e684e5..5d5ee1b 100644 --- a/src/flutter/shell/platform/linux_embedded/window/elinux_window_wayland.cc +++ b/src/flutter/shell/platform/linux_embedded/window/elinux_window_wayland.cc @@ -23,6 +23,7 @@ namespace flutter { namespace { constexpr char kZwpTextInputManagerV1[] = "zwp_text_input_manager_v1"; constexpr char kZwpTextInputManagerV3[] = "zwp_text_input_manager_v3"; +constexpr char kZxdgDecorationManagerV1[] = "zxdg_decoration_manager_v1"; constexpr char kWlCursorThemeBottomLeftCorner[] = "bottom_left_corner"; constexpr char kWlCursorThemeBottomRightCorner[] = "bottom_right_corner"; @@ -73,7 +74,7 @@ const xdg_surface_listener ELinuxWindowWayland::kXdgSurfaceListener = { auto self = reinterpret_cast(data); constexpr int32_t x = 0; int32_t y = 0; - if (self->view_properties_.use_window_decoration) { + if (self->window_decorations_) { // TODO: Moves the window to the bottom to show the window // decorations, but the bottom area of the window will be hidden // because of this shifting. @@ -851,6 +852,28 @@ const wl_data_source_listener ELinuxWindowWayland::kWlDataSourceListener = { uint32_t dnd_action) -> void {}, }; +const zxdg_toplevel_decoration_v1_listener + ELinuxWindowWayland::kZxdgToplevelDecorationV1Listener = { + .configure = + [](void* data, + struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1, + uint32_t mode) -> void { + ELINUX_LOG(INFO) + << "zxdg_toplevel_decoration_v1_listener.configure: mode is " + << ((mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE) + ? "server-side" + : "client-side"); + auto self = reinterpret_cast(data); + if (self->view_properties_.use_window_decoration && + mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE && + !self->window_decorations_) { + int32_t width_dip = self->view_properties_.width; + int32_t height_dip = self->view_properties_.height; + self->CreateDecoration(width_dip, height_dip); + } + }, +}; + ELinuxWindowWayland::ELinuxWindowWayland( FlutterDesktopViewProperties view_properties) : cursor_info_({"", 0, nullptr}), @@ -973,6 +996,18 @@ ELinuxWindowWayland::~ELinuxWindowWayland() { } } + { + if (zxdg_decoration_manager_v1_) { + zxdg_decoration_manager_v1_destroy(zxdg_decoration_manager_v1_); + zxdg_decoration_manager_v1_ = nullptr; + } + + if (zxdg_toplevel_decoration_v1_) { + zxdg_toplevel_decoration_v1_destroy(zxdg_toplevel_decoration_v1_); + zxdg_toplevel_decoration_v1_ = nullptr; + } + } + if (wl_data_offer_) { wl_data_offer_destroy(wl_data_offer_); wl_data_offer_ = nullptr; @@ -1149,6 +1184,8 @@ bool ELinuxWindowWayland::DispatchEvent() { bool ELinuxWindowWayland::CreateRenderSurface(int32_t width_px, int32_t height_px, bool enable_impeller) { + enable_impeller_ = enable_impeller; + if (!display_valid_) { ELINUX_LOG(ERROR) << "Wayland display is invalid."; return false; @@ -1230,12 +1267,22 @@ bool ELinuxWindowWayland::CreateRenderSurface(int32_t width_px, render_surface_->SetNativeWindow(native_window_.get()); if (view_properties_.use_window_decoration) { - int32_t width_dip = width_px / current_scale_; - int32_t height_dip = height_px / current_scale_; - window_decorations_ = std::make_unique( - wl_display_, wl_compositor_, wl_subcompositor_, - native_window_->Surface(), width_dip, height_dip, current_scale_, - enable_impeller); + if (zxdg_decoration_manager_v1_) { + ELINUX_LOG(INFO) << "Use server-side xdg-decoration mode"; + zxdg_toplevel_decoration_v1_ = + zxdg_decoration_manager_v1_get_toplevel_decoration( + zxdg_decoration_manager_v1_, xdg_toplevel_); + zxdg_toplevel_decoration_v1_set_mode( + zxdg_toplevel_decoration_v1_, + ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + zxdg_toplevel_decoration_v1_add_listener( + zxdg_toplevel_decoration_v1_, &kZxdgToplevelDecorationV1Listener, + this); + } else { + int32_t width_dip = width_px / current_scale_; + int32_t height_dip = height_px / current_scale_; + CreateDecoration(width_dip, height_dip); + } } // Wait for making sure that xdg_surface has been configured. @@ -1246,6 +1293,18 @@ bool ELinuxWindowWayland::CreateRenderSurface(int32_t width_px, return true; } +void ELinuxWindowWayland::CreateDecoration(int32_t width_dip, + int32_t height_dip) { + if (window_decorations_) { + ELINUX_LOG(WARNING) << "Window decoration has already created"; + return; + } + + window_decorations_ = std::make_unique( + wl_display_, wl_compositor_, wl_subcompositor_, native_window_->Surface(), + width_dip, height_dip, current_scale_, enable_impeller_); +} + void ELinuxWindowWayland::DestroyRenderSurface() { // destroy the main surface before destroying the client window on Wayland. if (window_decorations_) { @@ -1463,6 +1522,15 @@ void ELinuxWindowWayland::WlRegistryHandler(wl_registry* wl_registry, this); return; } + + if (!strcmp(interface, kZxdgDecorationManagerV1)) { + constexpr uint32_t kMaxVersion = 1; + zxdg_decoration_manager_v1_ = + static_cast(wl_registry_bind( + wl_registry, name, &zxdg_decoration_manager_v1_interface, + std::min(kMaxVersion, version))); + return; + } } void ELinuxWindowWayland::WlUnRegistryHandler(wl_registry* wl_registry, diff --git a/src/flutter/shell/platform/linux_embedded/window/elinux_window_wayland.h b/src/flutter/shell/platform/linux_embedded/window/elinux_window_wayland.h index fad7dc1..6ba5f72 100644 --- a/src/flutter/shell/platform/linux_embedded/window/elinux_window_wayland.h +++ b/src/flutter/shell/platform/linux_embedded/window/elinux_window_wayland.h @@ -24,6 +24,7 @@ extern "C" { #include "wayland/protocols/presentation-time-protocol.h" #include "wayland/protocols/text-input-unstable-v1-client-protocol.h" #include "wayland/protocols/text-input-unstable-v3-client-protocol.h" +#include "wayland/protocols/xdg-decoration-unstable-v1-protocol.h" #include "wayland/protocols/xdg-shell-client-protocol.h" } @@ -107,6 +108,8 @@ class ELinuxWindowWayland : public ELinuxWindow, public WindowBindingHandler { // Updates the surface scale of the window from the list of entered outputs. void UpdateWindowScale(); + void CreateDecoration(int32_t width_dip, int32_t height_dip); + // Get window decorations height in physical pixels. uint32_t WindowDecorationsPhysicalHeight() const; @@ -128,6 +131,8 @@ class ELinuxWindowWayland : public ELinuxWindow, public WindowBindingHandler { static const wp_presentation_listener kWpPresentationListener; static const wp_presentation_feedback_listener kWpPresentationFeedbackListener; + static const zxdg_toplevel_decoration_v1_listener + kZxdgToplevelDecorationV1Listener; static constexpr size_t kDefaultPointerSize = 24; // A pointer to a FlutterWindowsView that can be used to update engine @@ -151,6 +156,7 @@ class ELinuxWindowWayland : public ELinuxWindow, public WindowBindingHandler { bool request_redraw_ = false; bool maximised_; uint32_t last_frame_time_; + bool enable_impeller_ = false; // Indicates that exists a keyboard show request from Flutter Engine. bool is_requested_show_virtual_keyboard_; @@ -175,6 +181,10 @@ class ELinuxWindowWayland : public ELinuxWindow, public WindowBindingHandler { zwp_text_input_v1* zwp_text_input_v1_; zwp_text_input_v3* zwp_text_input_v3_; + // xdg-decoration protocol for window decoration (server-side). + zxdg_decoration_manager_v1* zxdg_decoration_manager_v1_ = nullptr; + zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1_ = nullptr; + // Frame information for Vsync events. wp_presentation* wp_presentation_; uint32_t wp_presentation_clk_id_;