Skip to content

Commit

Permalink
fix(wayland): add client side decorations & fix error protocol 71 (#979)
Browse files Browse the repository at this point in the history
  • Loading branch information
Zamoca42 authored Sep 26, 2024
1 parent 2ee007a commit 4dcd231
Show file tree
Hide file tree
Showing 11 changed files with 167 additions and 42 deletions.
5 changes: 5 additions & 0 deletions .changes/improve-wayland-display.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": patch
---

On Linux Wayland, changed the event handling for maximizing to process events sequentially to avoid "Error 71(Protocol error): dispatching to Wayland display".
5 changes: 5 additions & 0 deletions .changes/wayland-dragging-header.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": patch
---

On Linux Wayland, fixed an issue where the window was not moving when dragging the header bar area.
5 changes: 5 additions & 0 deletions .changes/wayland-resize-window.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": patch
---

On Linux Wayland, fixed an issue where the window was not resizing when dragging the window borders.
5 changes: 5 additions & 0 deletions .changes/wayland-titlebar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": patch
---

On Linux Wayland, added buttons for maximize and minimize in the title bar.
7 changes: 7 additions & 0 deletions examples/window_debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ fn main() {
eprintln!(" (T) Toggle always on top");
eprintln!(" (B) Toggle always on bottom");
eprintln!(" (C) Toggle content protection");
eprintln!(" (R) Toggle resizable");
eprintln!(" (M) Toggle minimized");
eprintln!(" (X) Toggle maximized");
eprintln!(" (Q) Quit event loop");
Expand All @@ -44,6 +45,7 @@ fn main() {
let mut always_on_top = false;
let mut visible = true;
let mut content_protection = false;
let mut resizable = false;

event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
Expand Down Expand Up @@ -119,6 +121,11 @@ fn main() {
window.set_fullscreen(Some(Fullscreen::Borderless(None)));
}
}
"r" => {
resizable = !resizable;
window.set_resizable(resizable);
println!("Resizable: {}", resizable);
}
"m" => {
window.set_minimized(!window.is_minimized());
}
Expand Down
60 changes: 32 additions & 28 deletions src/platform_impl/linux/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ impl<T: 'static> EventLoop<T> {
};

let mut taskbar = TaskbarIndicator::new();
let is_wayland = window_target.is_wayland();

// Window Request
window_requests_rx.attach(Some(&context), move |(id, request)| {
Expand Down Expand Up @@ -292,9 +293,13 @@ impl<T: 'static> EventLoop<T> {
window.deiconify();
}
}
WindowRequest::Maximized(maximized) => {
WindowRequest::Maximized(maximized, resizable) => {
if maximized {
window.maximize();
let maximize_process = util::WindowMaximizeProcess::new(window.clone(), resizable);
glib::idle_add_local_full(glib::Priority::DEFAULT_IDLE, move || {
let mut maximize_process = maximize_process.borrow_mut();
maximize_process.next_step()
});
} else {
window.unmaximize();
}
Expand Down Expand Up @@ -462,35 +467,34 @@ impl<T: 'static> EventLoop<T> {
glib::Propagation::Proceed
});
window.connect_button_press_event(move |window, event| {
if !window.is_decorated()
const LMB: u32 = 1;
if (is_wayland || !window.is_decorated())
&& window.is_resizable()
&& !window.is_maximized()
&& event.button() == 1
&& event.button() == LMB
{
if let Some(window) = window.window() {
let (cx, cy) = event.root();
let (left, top) = window.position();
let (w, h) = (window.width(), window.height());
let (right, bottom) = (left + w, top + h);
let border = window.scale_factor() * 5;
let edge = crate::window::hit_test(
(left, top, right, bottom),
cx as _,
cy as _,
border,
border,
)
.map(|d| d.to_gtk_edge())
// we return `WindowEdge::__Unknown` to be ignored later.
// we must return 8 or bigger, otherwise it will be the same as one of the other 7 variants of `WindowEdge` enum.
.unwrap_or(WindowEdge::__Unknown(8));
// Ignore the `__Unknown` variant so the window receives the click correctly if it is not on the edges.
match edge {
WindowEdge::__Unknown(_) => (),
_ => {
// FIXME: calling `window.begin_resize_drag` uses the default cursor, it should show a resizing cursor instead
window.begin_resize_drag(edge, 1, cx as i32, cy as i32, event.time())
}
let (cx, cy) = event.root();
let (left, top) = window.position();
let (w, h) = window.size();
let (right, bottom) = (left + w, top + h);
let border = window.scale_factor() * 5;
let edge = crate::window::hit_test(
(left, top, right, bottom),
cx as _,
cy as _,
border,
border,
)
.map(|d| d.to_gtk_edge())
// we return `WindowEdge::__Unknown` to be ignored later.
// we must return 8 or bigger, otherwise it will be the same as one of the other 7 variants of `WindowEdge` enum.
.unwrap_or(WindowEdge::__Unknown(8));
// Ignore the `__Unknown` variant so the window receives the click correctly if it is not on the edges.
match edge {
WindowEdge::__Unknown(_) => (),
_ => {
// FIXME: calling `window.begin_resize_drag` uses the default cursor, it should show a resizing cursor instead
window.begin_resize_drag(edge, LMB as i32, cx as i32, cy as i32, event.time())
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ mod util;
mod window;

pub mod taskbar;
pub mod wayland;
pub mod x11;

pub use self::keycode::{keycode_from_scancode, keycode_to_scancode};
Expand Down
52 changes: 46 additions & 6 deletions src/platform_impl/linux/util.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
use crate::{
dpi::{LogicalPosition, LogicalSize, PhysicalPosition},
error::ExternalError,
window::WindowSizeConstraints,
};
use gtk::gdk::{
self,
prelude::{DeviceExt, SeatExt},
Display,
};
use gtk::traits::{GtkWindowExt, WidgetExt};

use crate::{
dpi::{LogicalPosition, LogicalSize, PhysicalPosition},
error::ExternalError,
window::WindowSizeConstraints,
use gtk::{
glib::{self},
traits::{GtkWindowExt, WidgetExt},
};
use std::cell::RefCell;
use std::rc::Rc;

#[inline]
pub fn cursor_position(is_wayland: bool) -> Result<PhysicalPosition<f64>, ExternalError> {
Expand Down Expand Up @@ -70,3 +74,39 @@ pub fn set_size_constraints<W: GtkWindowExt + WidgetExt>(
geom_mask,
)
}

pub struct WindowMaximizeProcess<W: GtkWindowExt + WidgetExt> {
window: W,
resizable: bool,
step: u8,
}

impl<W: GtkWindowExt + WidgetExt> WindowMaximizeProcess<W> {
pub fn new(window: W, resizable: bool) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(Self {
window,
resizable,
step: 0,
}))
}

pub fn next_step(&mut self) -> glib::ControlFlow {
match self.step {
0 => {
self.window.set_resizable(true);
self.step += 1;
glib::ControlFlow::Continue
}
1 => {
self.window.maximize();
self.step += 1;
glib::ControlFlow::Continue
}
2 => {
self.window.set_resizable(self.resizable);
glib::ControlFlow::Break
}
_ => glib::ControlFlow::Break,
}
}
}
36 changes: 36 additions & 0 deletions src/platform_impl/linux/wayland/header.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use gtk::{prelude::*, ApplicationWindow, EventBox, HeaderBar};

pub struct WlHeader;

impl WlHeader {
pub fn setup(window: &ApplicationWindow, title: &str) {
let header = HeaderBar::builder()
.show_close_button(true)
.decoration_layout("menu:minimize,maximize,close")
.title(title)
.build();

let event_box = EventBox::new();
event_box.set_above_child(true);
event_box.set_visible(true);
event_box.set_can_focus(false);
event_box.add(&header);

window.set_titlebar(Some(&event_box));
Self::connect_resize_window(&header, window);
}

fn connect_resize_window(header: &HeaderBar, window: &ApplicationWindow) {
let header_weak = header.downgrade();
window.connect_resizable_notify(move |window| {
if let Some(header) = header_weak.upgrade() {
let is_resizable = window.is_resizable();
header.set_decoration_layout(if !is_resizable {
Some("menu:minimize,close")
} else {
Some("menu:minimize,maximize,close")
});
}
});
}
}
5 changes: 5 additions & 0 deletions src/platform_impl/linux/wayland/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright 2014-2021 The winit contributors
// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0

pub mod header;
28 changes: 20 additions & 8 deletions src/platform_impl/linux/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::{
error::{ExternalError, NotSupportedError, OsError as RootOsError},
icon::Icon,
monitor::MonitorHandle as RootMonitorHandle,
platform_impl::wayland::header::WlHeader,
window::{
CursorIcon, Fullscreen, ProgressBarState, ResizeDirection, Theme, UserAttentionType,
WindowAttributes, WindowSizeConstraints,
Expand Down Expand Up @@ -78,6 +79,7 @@ impl Window {
let app = &event_loop_window_target.app;
let window_requests_tx = event_loop_window_target.window_requests_tx.clone();
let draw_tx = event_loop_window_target.draw_tx.clone();
let is_wayland = event_loop_window_target.is_wayland();

let mut window_builder = gtk::ApplicationWindow::builder()
.application(app)
Expand All @@ -88,6 +90,10 @@ impl Window {

let window = window_builder.build();

if is_wayland {
WlHeader::setup(&window, &attributes.title);
}

let window_id = WindowId(window.id());
event_loop_window_target
.windows
Expand All @@ -104,10 +110,15 @@ impl Window {
window.resize(width, height);

if attributes.maximized {
window.maximize();
let maximize_process = util::WindowMaximizeProcess::new(window.clone(), attributes.resizable);
glib::idle_add_local_full(glib::Priority::HIGH_IDLE, move || {
let mut maximize_process = maximize_process.borrow_mut();
maximize_process.next_step()
});
} else {
window.set_resizable(attributes.resizable);
}

window.set_resizable(attributes.resizable);
window.set_deletable(attributes.closable);

// Set Min/Max Size
Expand Down Expand Up @@ -578,10 +589,12 @@ impl Window {
}

pub fn set_maximized(&self, maximized: bool) {
if let Err(e) = self
.window_requests_tx
.send((self.window_id, WindowRequest::Maximized(maximized)))
{
let resizable = self.is_resizable();

if let Err(e) = self.window_requests_tx.send((
self.window_id,
WindowRequest::Maximized(maximized, resizable),
)) {
log::warn!("Fail to send maximized request: {}", e);
}
}
Expand Down Expand Up @@ -609,7 +622,6 @@ impl Window {
pub fn is_maximizable(&self) -> bool {
true
}

pub fn is_closable(&self) -> bool {
self.window.is_deletable()
}
Expand Down Expand Up @@ -995,7 +1007,7 @@ pub enum WindowRequest {
Resizable(bool),
Closable(bool),
Minimized(bool),
Maximized(bool),
Maximized(bool, bool),
DragWindow,
DragResizeWindow(ResizeDirection),
Fullscreen(Option<Fullscreen>),
Expand Down

0 comments on commit 4dcd231

Please sign in to comment.