Wayland fractional scaling (#7961)
This PR adds support for fractional scaling on Wayland. Release Notes: - N/A
This commit is contained in:
parent
4e1e26b696
commit
bd137b01ad
4 changed files with 91 additions and 21 deletions
|
@ -105,7 +105,7 @@ ashpd = "0.7.0"
|
||||||
# todo!(linux) - Technically do not use `randr`, but it doesn't compile otherwise
|
# 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"] }
|
xcb = { version = "1.3", features = ["as-raw-xcb-connection", "present", "randr", "xkb"] }
|
||||||
wayland-client= { version = "0.31.2" }
|
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"] }
|
wayland-backend = { version = "0.3.3", features = ["client_system"] }
|
||||||
xkbcommon = { version = "0.7", features = ["wayland", "x11"] }
|
xkbcommon = { version = "0.7", features = ["wayland", "x11"] }
|
||||||
as-raw-xcb-connection = "1"
|
as-raw-xcb-connection = "1"
|
||||||
|
|
|
@ -276,7 +276,7 @@ impl LinuxTextSystemState {
|
||||||
CacheKey::new(
|
CacheKey::new(
|
||||||
font.id(),
|
font.id(),
|
||||||
params.glyph_id.0 as u16,
|
params.glyph_id.0 as u16,
|
||||||
params.font_size.into(),
|
(params.font_size * params.scale_factor).into(),
|
||||||
(0.0, 0.0),
|
(0.0, 0.0),
|
||||||
)
|
)
|
||||||
.0,
|
.0,
|
||||||
|
@ -308,7 +308,7 @@ impl LinuxTextSystemState {
|
||||||
CacheKey::new(
|
CacheKey::new(
|
||||||
font.id(),
|
font.id(),
|
||||||
params.glyph_id.0 as u16,
|
params.glyph_id.0 as u16,
|
||||||
params.font_size.into(),
|
(params.font_size * params.scale_factor).into(),
|
||||||
(0.0, 0.0),
|
(0.0, 0.0),
|
||||||
)
|
)
|
||||||
.0,
|
.0,
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
use wayland_backend::client::ObjectId;
|
||||||
use wayland_backend::protocol::WEnum;
|
use wayland_backend::protocol::WEnum;
|
||||||
use wayland_client::protocol::wl_callback::WlCallback;
|
use wayland_client::protocol::wl_callback::WlCallback;
|
||||||
use wayland_client::protocol::wl_pointer::AxisRelativeDirection;
|
use wayland_client::protocol::wl_pointer::AxisRelativeDirection;
|
||||||
|
@ -14,6 +15,10 @@ use wayland_client::{
|
||||||
},
|
},
|
||||||
Connection, Dispatch, EventQueue, Proxy, QueueHandle,
|
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 wayland_protocols::xdg::shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base};
|
||||||
use xkbcommon::xkb;
|
use xkbcommon::xkb;
|
||||||
use xkbcommon::xkb::ffi::XKB_KEYMAP_FORMAT_TEXT_V1;
|
use xkbcommon::xkb::ffi::XKB_KEYMAP_FORMAT_TEXT_V1;
|
||||||
|
@ -36,6 +41,8 @@ pub(crate) struct WaylandClientState {
|
||||||
compositor: Option<wl_compositor::WlCompositor>,
|
compositor: Option<wl_compositor::WlCompositor>,
|
||||||
buffer: Option<wl_buffer::WlBuffer>,
|
buffer: Option<wl_buffer::WlBuffer>,
|
||||||
wm_base: Option<xdg_wm_base::XdgWmBase>,
|
wm_base: Option<xdg_wm_base::XdgWmBase>,
|
||||||
|
viewporter: Option<wp_viewporter::WpViewporter>,
|
||||||
|
fractional_scale_manager: Option<wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1>,
|
||||||
windows: Vec<(xdg_surface::XdgSurface, Rc<WaylandWindowState>)>,
|
windows: Vec<(xdg_surface::XdgSurface, Rc<WaylandWindowState>)>,
|
||||||
platform_inner: Rc<LinuxPlatformInner>,
|
platform_inner: Rc<LinuxPlatformInner>,
|
||||||
wl_seat: Option<wl_seat::WlSeat>,
|
wl_seat: Option<wl_seat::WlSeat>,
|
||||||
|
@ -62,6 +69,8 @@ impl WaylandClient {
|
||||||
compositor: None,
|
compositor: None,
|
||||||
buffer: None,
|
buffer: None,
|
||||||
wm_base: None,
|
wm_base: None,
|
||||||
|
viewporter: None,
|
||||||
|
fractional_scale_manager: None,
|
||||||
windows: Vec::new(),
|
windows: Vec::new(),
|
||||||
platform_inner: Rc::clone(&linux_platform_inner),
|
platform_inner: Rc::clone(&linux_platform_inner),
|
||||||
wl_seat: None,
|
wl_seat: None,
|
||||||
|
@ -135,16 +144,26 @@ impl Client for WaylandClient {
|
||||||
let toplevel = xdg_surface.get_toplevel(&self.qh, ());
|
let toplevel = xdg_surface.get_toplevel(&self.qh, ());
|
||||||
let wl_surface = Arc::new(wl_surface);
|
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.frame(&self.qh, wl_surface.clone());
|
||||||
wl_surface.commit();
|
wl_surface.commit();
|
||||||
|
|
||||||
let window_state = Rc::new(WaylandWindowState::new(
|
let window_state = Rc::new(WaylandWindowState::new(
|
||||||
&self.conn,
|
&self.conn,
|
||||||
wl_surface.clone(),
|
wl_surface.clone(),
|
||||||
|
viewport,
|
||||||
Arc::new(toplevel),
|
Arc::new(toplevel),
|
||||||
options,
|
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)));
|
state.windows.push((xdg_surface, Rc::clone(&window_state)));
|
||||||
Box::new(WaylandWindow(window_state))
|
Box::new(WaylandWindow(window_state))
|
||||||
}
|
}
|
||||||
|
@ -177,6 +196,21 @@ impl Dispatch<wl_registry::WlRegistry, ()> for WaylandClientState {
|
||||||
let seat = registry.bind::<wl_seat::WlSeat, _, _>(name, 1, qh, ());
|
let seat = registry.bind::<wl_seat::WlSeat, _, _>(name, 1, qh, ());
|
||||||
state.wl_seat = Some(seat);
|
state.wl_seat = Some(seat);
|
||||||
}
|
}
|
||||||
|
"wp_fractional_scale_manager_v1" => {
|
||||||
|
let manager = registry
|
||||||
|
.bind::<wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1, _, _>(
|
||||||
|
name,
|
||||||
|
1,
|
||||||
|
qh,
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
state.fractional_scale_manager = Some(manager);
|
||||||
|
}
|
||||||
|
"wp_viewporter" => {
|
||||||
|
let view_porter =
|
||||||
|
registry.bind::<wp_viewporter::WpViewporter, _, _>(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::WlShm);
|
||||||
delegate_noop!(WaylandClientState: ignore wl_shm_pool::WlShmPool);
|
delegate_noop!(WaylandClientState: ignore wl_shm_pool::WlShmPool);
|
||||||
delegate_noop!(WaylandClientState: ignore wl_buffer::WlBuffer);
|
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<WlCallback, Arc<WlSurface>> for WaylandClientState {
|
impl Dispatch<WlCallback, Arc<WlSurface>> for WaylandClientState {
|
||||||
fn event(
|
fn event(
|
||||||
|
@ -599,3 +636,23 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Dispatch<wp_fractional_scale_v1::WpFractionalScaleV1, ObjectId> for WaylandClientState {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
_: &wp_fractional_scale_v1::WpFractionalScaleV1,
|
||||||
|
event: <wp_fractional_scale_v1::WpFractionalScaleV1 as Proxy>::Event,
|
||||||
|
id: &ObjectId,
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ use raw_window_handle::{
|
||||||
DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle, WindowHandle,
|
DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle, WindowHandle,
|
||||||
};
|
};
|
||||||
use wayland_client::{protocol::wl_surface, Proxy};
|
use wayland_client::{protocol::wl_surface, Proxy};
|
||||||
|
use wayland_protocols::wp::viewporter::client::wp_viewport;
|
||||||
use wayland_protocols::xdg::shell::client::xdg_toplevel;
|
use wayland_protocols::xdg::shell::client::xdg_toplevel;
|
||||||
|
|
||||||
use crate::platform::blade::BladeRenderer;
|
use crate::platform::blade::BladeRenderer;
|
||||||
|
@ -38,6 +39,7 @@ pub(crate) struct Callbacks {
|
||||||
struct WaylandWindowInner {
|
struct WaylandWindowInner {
|
||||||
renderer: BladeRenderer,
|
renderer: BladeRenderer,
|
||||||
bounds: Bounds<i32>,
|
bounds: Bounds<i32>,
|
||||||
|
scale: f32,
|
||||||
input_handler: Option<PlatformInputHandler>,
|
input_handler: Option<PlatformInputHandler>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +94,7 @@ impl WaylandWindowInner {
|
||||||
Self {
|
Self {
|
||||||
renderer: BladeRenderer::new(gpu, extent),
|
renderer: BladeRenderer::new(gpu, extent),
|
||||||
bounds,
|
bounds,
|
||||||
|
scale: 1.0,
|
||||||
input_handler: None,
|
input_handler: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,12 +106,14 @@ pub(crate) struct WaylandWindowState {
|
||||||
pub(crate) callbacks: Mutex<Callbacks>,
|
pub(crate) callbacks: Mutex<Callbacks>,
|
||||||
pub(crate) surface: Arc<wl_surface::WlSurface>,
|
pub(crate) surface: Arc<wl_surface::WlSurface>,
|
||||||
pub(crate) toplevel: Arc<xdg_toplevel::XdgToplevel>,
|
pub(crate) toplevel: Arc<xdg_toplevel::XdgToplevel>,
|
||||||
|
viewport: Option<wp_viewport::WpViewport>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WaylandWindowState {
|
impl WaylandWindowState {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
conn: &Arc<wayland_client::Connection>,
|
conn: &Arc<wayland_client::Connection>,
|
||||||
wl_surf: Arc<wl_surface::WlSurface>,
|
wl_surf: Arc<wl_surface::WlSurface>,
|
||||||
|
viewport: Option<wp_viewport::WpViewport>,
|
||||||
toplevel: Arc<xdg_toplevel::XdgToplevel>,
|
toplevel: Arc<xdg_toplevel::XdgToplevel>,
|
||||||
options: WindowOptions,
|
options: WindowOptions,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -135,6 +140,7 @@ impl WaylandWindowState {
|
||||||
inner: Mutex::new(WaylandWindowInner::new(&Arc::clone(conn), &wl_surf, bounds)),
|
inner: Mutex::new(WaylandWindowInner::new(&Arc::clone(conn), &wl_surf, bounds)),
|
||||||
callbacks: Mutex::new(Callbacks::default()),
|
callbacks: Mutex::new(Callbacks::default()),
|
||||||
toplevel,
|
toplevel,
|
||||||
|
viewport,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,30 +153,40 @@ impl WaylandWindowState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize(&self, width: i32, height: i32) {
|
pub fn set_size_and_scale(&self, width: i32, height: i32, scale: f32) {
|
||||||
{
|
self.inner.lock().scale = scale;
|
||||||
let mut inner = self.inner.lock();
|
self.inner.lock().bounds.size.width = width;
|
||||||
inner.bounds.size.width = width;
|
self.inner.lock().bounds.size.height = height;
|
||||||
inner.bounds.size.height = height;
|
self.inner.lock().renderer.update_drawable_size(size(
|
||||||
inner
|
width as f64 * scale as f64,
|
||||||
.renderer
|
height as f64 * scale as f64,
|
||||||
.update_drawable_size(size(width as f64, height as f64));
|
));
|
||||||
}
|
|
||||||
let mut callbacks = self.callbacks.lock();
|
if let Some(ref mut fun) = self.callbacks.lock().resize {
|
||||||
if let Some(ref mut fun) = callbacks.resize {
|
|
||||||
fun(
|
fun(
|
||||||
Size {
|
Size {
|
||||||
width: px(width as f32),
|
width: px(width as f32),
|
||||||
height: px(height 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) {
|
pub fn close(&self) {
|
||||||
let mut callbacks = self.callbacks.lock();
|
let mut callbacks = self.callbacks.lock();
|
||||||
if let Some(fun) = callbacks.close.take() {
|
if let Some(fun) = callbacks.close.take() {
|
||||||
|
@ -215,7 +231,6 @@ impl PlatformWindow for WaylandWindow {
|
||||||
WindowBounds::Maximized
|
WindowBounds::Maximized
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo!(linux)
|
|
||||||
fn content_size(&self) -> Size<Pixels> {
|
fn content_size(&self) -> Size<Pixels> {
|
||||||
let inner = self.0.inner.lock();
|
let inner = self.0.inner.lock();
|
||||||
Size {
|
Size {
|
||||||
|
@ -224,9 +239,8 @@ impl PlatformWindow for WaylandWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo!(linux)
|
|
||||||
fn scale_factor(&self) -> f32 {
|
fn scale_factor(&self) -> f32 {
|
||||||
1f32
|
self.0.inner.lock().scale
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo!(linux)
|
//todo!(linux)
|
||||||
|
@ -263,7 +277,6 @@ impl PlatformWindow for WaylandWindow {
|
||||||
self.0.inner.lock().input_handler = Some(input_handler);
|
self.0.inner.lock().input_handler = Some(input_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo!(linux)
|
|
||||||
fn take_input_handler(&mut self) -> Option<PlatformInputHandler> {
|
fn take_input_handler(&mut self) -> Option<PlatformInputHandler> {
|
||||||
self.0.inner.lock().input_handler.take()
|
self.0.inner.lock().input_handler.take()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue