Skip to content

Commit

Permalink
wayland: add xdg-decoration support (#358)
Browse files Browse the repository at this point in the history
I've tested this change on Sway.

Fixed #216

Signed-off-by: Hidenori Matsubayashi <[email protected]>
  • Loading branch information
HidenoriMatsubayashi authored Aug 5, 2023
1 parent bfcffb3 commit 0703025
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 7 deletions.
6 changes: 6 additions & 0 deletions cmake/build.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,19 @@ 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
"${_wayland_protocols_src_dir}/xdg-shell-protocol.c"
"${_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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -73,7 +74,7 @@ const xdg_surface_listener ELinuxWindowWayland::kXdgSurfaceListener = {
auto self = reinterpret_cast<ELinuxWindowWayland*>(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.
Expand Down Expand Up @@ -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<ELinuxWindowWayland*>(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}),
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<WindowDecorationsWayland>(
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.
Expand All @@ -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<WindowDecorationsWayland>(
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_) {
Expand Down Expand Up @@ -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<decltype(zxdg_decoration_manager_v1_)>(wl_registry_bind(
wl_registry, name, &zxdg_decoration_manager_v1_interface,
std::min(kMaxVersion, version)));
return;
}
}

void ELinuxWindowWayland::WlUnRegistryHandler(wl_registry* wl_registry,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}

Expand Down Expand Up @@ -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;

Expand All @@ -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
Expand All @@ -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_;
Expand All @@ -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_;
Expand Down

0 comments on commit 0703025

Please sign in to comment.