diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 02c16b841b..8326294c75 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -105,7 +105,7 @@ ashpd = "0.7.0" # todo!(linux) - Technically do not use `randr`, but it doesn't compile otherwise xcb = { version = "1.3", features = ["as-raw-xcb-connection", "present", "randr", "xkb"] } wayland-client= { version = "0.31.2" } -wayland-protocols = { version = "0.31.2", features = ["client"] } +wayland-protocols = { version = "0.31.2", features = ["client", "staging"] } wayland-backend = { version = "0.3.3", features = ["client_system"] } xkbcommon = { version = "0.7", features = ["wayland", "x11"] } as-raw-xcb-connection = "1" diff --git a/crates/gpui/src/platform/linux/text_system.rs b/crates/gpui/src/platform/linux/text_system.rs index 574f65381d..683ef6a662 100644 --- a/crates/gpui/src/platform/linux/text_system.rs +++ b/crates/gpui/src/platform/linux/text_system.rs @@ -276,7 +276,7 @@ impl LinuxTextSystemState { CacheKey::new( font.id(), params.glyph_id.0 as u16, - params.font_size.into(), + (params.font_size * params.scale_factor).into(), (0.0, 0.0), ) .0, @@ -308,7 +308,7 @@ impl LinuxTextSystemState { CacheKey::new( font.id(), params.glyph_id.0 as u16, - params.font_size.into(), + (params.font_size * params.scale_factor).into(), (0.0, 0.0), ) .0, diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui/src/platform/linux/wayland/client.rs index 1d64d96e40..0f739af76d 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui/src/platform/linux/wayland/client.rs @@ -2,6 +2,7 @@ use std::rc::Rc; use std::sync::Arc; use parking_lot::Mutex; +use wayland_backend::client::ObjectId; use wayland_backend::protocol::WEnum; use wayland_client::protocol::wl_callback::WlCallback; use wayland_client::protocol::wl_pointer::AxisRelativeDirection; @@ -14,6 +15,10 @@ use wayland_client::{ }, Connection, Dispatch, EventQueue, Proxy, QueueHandle, }; +use wayland_protocols::wp::fractional_scale::v1::client::{ + wp_fractional_scale_manager_v1, wp_fractional_scale_v1, +}; +use wayland_protocols::wp::viewporter::client::{wp_viewport, wp_viewporter}; use wayland_protocols::xdg::shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base}; use xkbcommon::xkb; use xkbcommon::xkb::ffi::XKB_KEYMAP_FORMAT_TEXT_V1; @@ -36,6 +41,8 @@ pub(crate) struct WaylandClientState { compositor: Option, buffer: Option, wm_base: Option, + viewporter: Option, + fractional_scale_manager: Option, windows: Vec<(xdg_surface::XdgSurface, Rc)>, platform_inner: Rc, wl_seat: Option, @@ -62,6 +69,8 @@ impl WaylandClient { compositor: None, buffer: None, wm_base: None, + viewporter: None, + fractional_scale_manager: None, windows: Vec::new(), platform_inner: Rc::clone(&linux_platform_inner), wl_seat: None, @@ -135,16 +144,26 @@ impl Client for WaylandClient { let toplevel = xdg_surface.get_toplevel(&self.qh, ()); let wl_surface = Arc::new(wl_surface); + let viewport = state + .viewporter + .as_ref() + .map(|viewporter| viewporter.get_viewport(&wl_surface, &self.qh, ())); + wl_surface.frame(&self.qh, wl_surface.clone()); wl_surface.commit(); let window_state = Rc::new(WaylandWindowState::new( &self.conn, wl_surface.clone(), + viewport, Arc::new(toplevel), options, )); + if let Some(fractional_scale_manager) = state.fractional_scale_manager.as_ref() { + fractional_scale_manager.get_fractional_scale(&wl_surface, &self.qh, xdg_surface.id()); + } + state.windows.push((xdg_surface, Rc::clone(&window_state))); Box::new(WaylandWindow(window_state)) } @@ -177,6 +196,21 @@ impl Dispatch for WaylandClientState { let seat = registry.bind::(name, 1, qh, ()); state.wl_seat = Some(seat); } + "wp_fractional_scale_manager_v1" => { + let manager = registry + .bind::( + name, + 1, + qh, + (), + ); + state.fractional_scale_manager = Some(manager); + } + "wp_viewporter" => { + let view_porter = + registry.bind::(name, 1, qh, ()); + state.viewporter = Some(view_porter); + } _ => {} }; } @@ -188,6 +222,9 @@ delegate_noop!(WaylandClientState: ignore wl_surface::WlSurface); delegate_noop!(WaylandClientState: ignore wl_shm::WlShm); delegate_noop!(WaylandClientState: ignore wl_shm_pool::WlShmPool); delegate_noop!(WaylandClientState: ignore wl_buffer::WlBuffer); +delegate_noop!(WaylandClientState: ignore wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1); +delegate_noop!(WaylandClientState: ignore wp_viewporter::WpViewporter); +delegate_noop!(WaylandClientState: ignore wp_viewport::WpViewport); impl Dispatch> for WaylandClientState { fn event( @@ -599,3 +636,23 @@ impl Dispatch for WaylandClientState { } } } + +impl Dispatch for WaylandClientState { + fn event( + state: &mut Self, + _: &wp_fractional_scale_v1::WpFractionalScaleV1, + event: ::Event, + id: &ObjectId, + _: &Connection, + _: &QueueHandle, + ) { + if let wp_fractional_scale_v1::Event::PreferredScale { scale, .. } = event { + for window in &state.windows { + if window.0.id() == *id { + window.1.rescale(scale as f32 / 120.0); + return; + } + } + } + } +} diff --git a/crates/gpui/src/platform/linux/wayland/window.rs b/crates/gpui/src/platform/linux/wayland/window.rs index 18eb5aad55..3ebce8f21b 100644 --- a/crates/gpui/src/platform/linux/wayland/window.rs +++ b/crates/gpui/src/platform/linux/wayland/window.rs @@ -11,6 +11,7 @@ use raw_window_handle::{ DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle, WindowHandle, }; use wayland_client::{protocol::wl_surface, Proxy}; +use wayland_protocols::wp::viewporter::client::wp_viewport; use wayland_protocols::xdg::shell::client::xdg_toplevel; use crate::platform::blade::BladeRenderer; @@ -38,6 +39,7 @@ pub(crate) struct Callbacks { struct WaylandWindowInner { renderer: BladeRenderer, bounds: Bounds, + scale: f32, input_handler: Option, } @@ -92,6 +94,7 @@ impl WaylandWindowInner { Self { renderer: BladeRenderer::new(gpu, extent), bounds, + scale: 1.0, input_handler: None, } } @@ -103,12 +106,14 @@ pub(crate) struct WaylandWindowState { pub(crate) callbacks: Mutex, pub(crate) surface: Arc, pub(crate) toplevel: Arc, + viewport: Option, } impl WaylandWindowState { pub(crate) fn new( conn: &Arc, wl_surf: Arc, + viewport: Option, toplevel: Arc, options: WindowOptions, ) -> Self { @@ -135,6 +140,7 @@ impl WaylandWindowState { inner: Mutex::new(WaylandWindowInner::new(&Arc::clone(conn), &wl_surf, bounds)), callbacks: Mutex::new(Callbacks::default()), toplevel, + viewport, } } @@ -147,30 +153,40 @@ impl WaylandWindowState { } } - pub fn resize(&self, width: i32, height: i32) { - { - let mut inner = self.inner.lock(); - inner.bounds.size.width = width; - inner.bounds.size.height = height; - inner - .renderer - .update_drawable_size(size(width as f64, height as f64)); - } - let mut callbacks = self.callbacks.lock(); - if let Some(ref mut fun) = callbacks.resize { + pub fn set_size_and_scale(&self, width: i32, height: i32, scale: f32) { + self.inner.lock().scale = scale; + self.inner.lock().bounds.size.width = width; + self.inner.lock().bounds.size.height = height; + self.inner.lock().renderer.update_drawable_size(size( + width as f64 * scale as f64, + height as f64 * scale as f64, + )); + + if let Some(ref mut fun) = self.callbacks.lock().resize { fun( Size { width: px(width as f32), height: px(height as f32), }, - 1.0, + scale, ); } - if let Some(ref mut fun) = callbacks.moved { - fun() + + if let Some(viewport) = &self.viewport { + viewport.set_destination(width, height); } } + pub fn resize(&self, width: i32, height: i32) { + let scale = self.inner.lock().scale; + self.set_size_and_scale(width, height, scale); + } + + pub fn rescale(&self, scale: f32) { + let bounds = self.inner.lock().bounds; + self.set_size_and_scale(bounds.size.width, bounds.size.height, scale) + } + pub fn close(&self) { let mut callbacks = self.callbacks.lock(); if let Some(fun) = callbacks.close.take() { @@ -215,7 +231,6 @@ impl PlatformWindow for WaylandWindow { WindowBounds::Maximized } - // todo!(linux) fn content_size(&self) -> Size { let inner = self.0.inner.lock(); Size { @@ -224,9 +239,8 @@ impl PlatformWindow for WaylandWindow { } } - // todo!(linux) fn scale_factor(&self) -> f32 { - 1f32 + self.0.inner.lock().scale } //todo!(linux) @@ -263,7 +277,6 @@ impl PlatformWindow for WaylandWindow { self.0.inner.lock().input_handler = Some(input_handler); } - //todo!(linux) fn take_input_handler(&mut self) -> Option { self.0.inner.lock().input_handler.take() }