Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(wayland): fix the inaccurately applied inner_size when creating a new window. #984

Open
wants to merge 14 commits into
base: dev
Choose a base branch
from
Open
5 changes: 5 additions & 0 deletions .changes/wayland-inner-size.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": patch
---

On Linux Wayland, fixed the inaccurately applied `inner_size` when creating a new window.
8 changes: 7 additions & 1 deletion src/platform_impl/linux/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,13 @@ impl<T: 'static> EventLoop<T> {
log::warn!("Failed to send window moved event to event channel: {}", e);
}

let (w, h) = event.size();
let (w, h) = if let Some(child) = window.child() {
let allocation = child.allocation();
(allocation.width() as u32, allocation.height() as u32)
} else {
event.size()
};

amrbashir marked this conversation as resolved.
Show resolved Hide resolved
if let Err(e) = tx_clone.send(Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::Resized(
Expand Down
45 changes: 41 additions & 4 deletions src/platform_impl/linux/wayland/header.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,62 @@
use gtk::{prelude::*, ApplicationWindow, EventBox, HeaderBar};
use gtk::{
glib::{self},
pango,
prelude::*,
Align, ApplicationWindow, EventBox, HeaderBar, Label,
};

pub struct WlHeader;

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

let title_label = Label::new(Some(title));
title_label.set_ellipsize(gtk::pango::EllipsizeMode::End);
title_label.set_single_line_mode(true);
title_label.set_halign(Align::Center);

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);

let header_clone = header.clone();
let event_box_clone = event_box.clone();
glib::idle_add_local_full(glib::Priority::HIGH_IDLE, move || {
let allocated_height = header_clone.allocated_height();
event_box_clone.set_size_request(min_width, allocated_height);
header_clone.set_size_request(min_width, allocated_height);
glib::ControlFlow::Break
});

header.set_custom_title(Some(&title_label));
event_box.add(&header);
window.set_titlebar(Some(&event_box));

//Set title font width
let context = title_label.pango_context();
let font_description = context.font_description().unwrap();
let font_size = (font_description.size() / pango::SCALE) as f64;
let char_width = font_size * 2.0;

Self::connect_configure_event(window, &title_label, char_width);
Self::connect_resize_window(&header, window);
}

fn connect_configure_event(window: &ApplicationWindow, title_label: &Label, char_width: f64) {
let title_label_clone = title_label.clone();
window.connect_configure_event(move |_, event| {
let (width, _) = event.size();
let max_chars = (width as f64 / char_width).floor() as i32;
title_label_clone.set_max_width_chars(if width < 220 { 0 } else { max_chars });
false
});
}

fn connect_resize_window(header: &HeaderBar, window: &ApplicationWindow) {
Comment on lines +50 to +59
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resizing here makes the window create with a smaller size than expected, and then after a brief moment, it will jump into the requested size

Previously, the header’s title affected the inner size, which made the size appear to jump.

before.mov

I added an event to prevent the title from affecting the inner size.

after.mov

Additionally, the number of title characters displayed is updated when the window is resized based on its width.

resize.mov

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can still see the size changes, see this gif
a

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I was unable to reproduce the issue.
The only potentially suspicious part I can think of is the priority when creating a new window, so I’ve tried setting all related priorities to a higher level.
Could you check if this makes a difference?

let header_weak = header.downgrade();
window.connect_resizable_notify(move |window| {
Expand Down
35 changes: 23 additions & 12 deletions src/platform_impl/linux/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,15 @@ impl Window {
}

let window = window_builder.build();
let win_scale_factor = window.scale_factor();
let min_inner_size = attributes
.inner_size_constraints
.min_size_physical::<i32>(win_scale_factor as f64);
let min_width = min_inner_size.width.max(1);
let min_height = min_inner_size.height.max(1);

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

let window_id = WindowId(window.id());
Expand All @@ -105,13 +111,17 @@ impl Window {
.insert(window_id);

// Set Width/Height & Resizable
let win_scale_factor = window.scale_factor();
let (width, height) = attributes
.inner_size
.map(|size| size.to_logical::<f64>(win_scale_factor as f64).into())
.unwrap_or((800, 600));
window.set_default_size(1, 1);
window.resize(width, height);

let window_clone = window.clone();
glib::idle_add_local_full(glib::Priority::HIGH_IDLE, move || {
window_clone.set_default_size(min_width, min_height);
window_clone.resize(width, height);
amrbashir marked this conversation as resolved.
Show resolved Hide resolved
glib::ControlFlow::Break
});

if attributes.maximized {
let maximize_process = util::WindowMaximizeProcess::new(window.clone(), attributes.resizable);
Expand All @@ -128,6 +138,15 @@ impl Window {
// Set Min/Max Size
util::set_size_constraints(&window, attributes.inner_size_constraints);

let default_vbox = if pl_attribs.default_vbox {
let box_ = gtk::Box::new(gtk::Orientation::Vertical, 0);
box_.set_size_request(min_width, min_height);
window.add(&box_);
Some(box_)
} else {
None
};

// Set Position
if let Some(position) = attributes.position {
let (x, y): (i32, i32) = position.to_logical::<i32>(win_scale_factor as f64).into();
Expand Down Expand Up @@ -159,14 +178,6 @@ impl Window {
}
}

let default_vbox = if pl_attribs.default_vbox {
let box_ = gtk::Box::new(gtk::Orientation::Vertical, 0);
window.add(&box_);
Some(box_)
} else {
None
};

// Rest attributes
window.set_title(&attributes.title);
if let Some(Fullscreen::Borderless(m)) = &attributes.fullscreen {
Expand Down
Loading