x11: HiDPI support (#11140)
Fixes https://github.com/zed-industries/zed/issues/11121 Release Notes: - N/A
This commit is contained in:
@@ -114,7 +114,13 @@ wayland-protocols = { version = "0.31.2", features = [
|
||||
oo7 = "0.3.0"
|
||||
open = "5.1.2"
|
||||
filedescriptor = "0.8.2"
|
||||
x11rb = { version = "0.13.0", features = ["allow-unsafe-code", "xkb", "randr", "xinput"] }
|
||||
x11rb = { version = "0.13.0", features = [
|
||||
"allow-unsafe-code",
|
||||
"xkb",
|
||||
"randr",
|
||||
"xinput",
|
||||
"resource_manager",
|
||||
] }
|
||||
xkbcommon = { version = "0.7", features = ["wayland", "x11"] }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
|
||||
@@ -16,6 +16,7 @@ use x11rb::protocol::xinput::{ConnectionExt, ScrollClass};
|
||||
use x11rb::protocol::xkb::ConnectionExt as _;
|
||||
use x11rb::protocol::xproto::ConnectionExt as _;
|
||||
use x11rb::protocol::{randr, xinput, xkb, xproto, Event};
|
||||
use x11rb::resource_manager::Database;
|
||||
use x11rb::xcb_ffi::XCBConnection;
|
||||
use xkbc::x11::ffi::{XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION};
|
||||
use xkbcommon::xkb as xkbc;
|
||||
@@ -23,9 +24,9 @@ use xkbcommon::xkb as xkbc;
|
||||
use crate::platform::linux::LinuxClient;
|
||||
use crate::platform::{LinuxCommon, PlatformWindow};
|
||||
use crate::{
|
||||
modifiers_from_xinput_info, px, AnyWindowHandle, Bounds, CursorStyle, DisplayId, Modifiers,
|
||||
ModifiersChangedEvent, Pixels, PlatformDisplay, PlatformInput, Point, ScrollDelta, Size,
|
||||
TouchPhase, WindowParams, X11Window,
|
||||
modifiers_from_xinput_info, point, px, AnyWindowHandle, Bounds, CursorStyle, DisplayId,
|
||||
Modifiers, ModifiersChangedEvent, Pixels, PlatformDisplay, PlatformInput, Point, ScrollDelta,
|
||||
Size, TouchPhase, WindowParams, X11Window,
|
||||
};
|
||||
|
||||
use super::{super::SCROLL_LINES, X11Display, X11WindowStatePtr, XcbAtoms};
|
||||
@@ -58,8 +59,11 @@ pub struct X11ClientState {
|
||||
pub(crate) last_location: Point<Pixels>,
|
||||
pub(crate) current_count: usize,
|
||||
|
||||
pub(crate) scale_factor: f32,
|
||||
|
||||
pub(crate) xcb_connection: Rc<XCBConnection>,
|
||||
pub(crate) x_root_index: usize,
|
||||
pub(crate) resource_database: Database,
|
||||
pub(crate) atoms: XcbAtoms,
|
||||
pub(crate) windows: HashMap<xproto::Window, WindowRef>,
|
||||
pub(crate) focused_window: Option<xproto::Window>,
|
||||
@@ -178,6 +182,31 @@ impl X11Client {
|
||||
xkbc::x11::state_new_from_device(&xkb_keymap, &xcb_connection, xkb_device_id)
|
||||
};
|
||||
|
||||
let screen = xcb_connection.setup().roots.get(x_root_index).unwrap();
|
||||
|
||||
// Values from `Database::GET_RESOURCE_DATABASE`
|
||||
let resource_manager = xcb_connection
|
||||
.get_property(
|
||||
false,
|
||||
screen.root,
|
||||
xproto::AtomEnum::RESOURCE_MANAGER,
|
||||
xproto::AtomEnum::STRING,
|
||||
0,
|
||||
100_000_000,
|
||||
)
|
||||
.unwrap();
|
||||
let resource_manager = resource_manager.reply().unwrap();
|
||||
|
||||
// todo(linux): read hostname
|
||||
let resource_database = Database::new_from_default(&resource_manager, "HOSTNAME".into());
|
||||
|
||||
let scale_factor = resource_database
|
||||
.get_value("Xft.dpi", "Xft.dpi")
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|dpi: f32| dpi / 96.0)
|
||||
.unwrap_or(1.0);
|
||||
|
||||
let clipboard = X11ClipboardContext::<Clipboard>::new().unwrap();
|
||||
let primary = X11ClipboardContext::<Primary>::new().unwrap();
|
||||
|
||||
@@ -212,9 +241,11 @@ impl X11Client {
|
||||
last_click: Instant::now(),
|
||||
last_location: Point::new(px(0.0), px(0.0)),
|
||||
current_count: 0,
|
||||
scale_factor,
|
||||
|
||||
xcb_connection,
|
||||
x_root_index,
|
||||
resource_database,
|
||||
atoms,
|
||||
windows: HashMap::default(),
|
||||
focused_window: None,
|
||||
@@ -345,8 +376,10 @@ impl X11Client {
|
||||
let mut state = self.0.borrow_mut();
|
||||
|
||||
let modifiers = modifiers_from_state(event.state);
|
||||
let position =
|
||||
Point::new((event.event_x as f32).into(), (event.event_y as f32).into());
|
||||
let position = point(
|
||||
px(event.event_x as f32 / state.scale_factor),
|
||||
px(event.event_y as f32 / state.scale_factor),
|
||||
);
|
||||
if let Some(button) = button_of_key(event.detail) {
|
||||
let click_elapsed = state.last_click.elapsed();
|
||||
|
||||
@@ -378,8 +411,10 @@ impl X11Client {
|
||||
let window = self.get_window(event.event)?;
|
||||
let state = self.0.borrow();
|
||||
let modifiers = modifiers_from_state(event.state);
|
||||
let position =
|
||||
Point::new((event.event_x as f32).into(), (event.event_y as f32).into());
|
||||
let position = point(
|
||||
px(event.event_x as f32 / state.scale_factor),
|
||||
px(event.event_y as f32 / state.scale_factor),
|
||||
);
|
||||
if let Some(button) = button_of_key(event.detail) {
|
||||
let click_count = state.current_count;
|
||||
drop(state);
|
||||
@@ -393,11 +428,12 @@ impl X11Client {
|
||||
}
|
||||
Event::XinputMotion(event) => {
|
||||
let window = self.get_window(event.event)?;
|
||||
|
||||
let position = Point::new(
|
||||
(event.event_x as f32 / u16::MAX as f32).into(),
|
||||
(event.event_y as f32 / u16::MAX as f32).into(),
|
||||
let state = self.0.borrow();
|
||||
let position = point(
|
||||
px(event.event_x as f32 / u16::MAX as f32 / state.scale_factor),
|
||||
px(event.event_y as f32 / u16::MAX as f32 / state.scale_factor),
|
||||
);
|
||||
drop(state);
|
||||
let modifiers = modifiers_from_xinput_info(event.mods);
|
||||
|
||||
let axisvalues = event
|
||||
@@ -471,10 +507,14 @@ impl X11Client {
|
||||
}
|
||||
Event::MotionNotify(event) => {
|
||||
let window = self.get_window(event.event)?;
|
||||
let state = self.0.borrow();
|
||||
let pressed_button = super::button_from_state(event.state);
|
||||
let position =
|
||||
Point::new((event.event_x as f32).into(), (event.event_y as f32).into());
|
||||
let position = point(
|
||||
px(event.event_x as f32 / state.scale_factor),
|
||||
px(event.event_y as f32 / state.scale_factor),
|
||||
);
|
||||
let modifiers = modifiers_from_state(event.state);
|
||||
drop(state);
|
||||
window.handle_input(PlatformInput::MouseMove(crate::MouseMoveEvent {
|
||||
pressed_button,
|
||||
position,
|
||||
@@ -483,10 +523,14 @@ impl X11Client {
|
||||
}
|
||||
Event::LeaveNotify(event) => {
|
||||
let window = self.get_window(event.event)?;
|
||||
let state = self.0.borrow();
|
||||
let pressed_button = super::button_from_state(event.state);
|
||||
let position =
|
||||
Point::new((event.event_x as f32).into(), (event.event_y as f32).into());
|
||||
let position = point(
|
||||
px(event.event_x as f32 / state.scale_factor),
|
||||
px(event.event_y as f32 / state.scale_factor),
|
||||
);
|
||||
let modifiers = modifiers_from_state(event.state);
|
||||
drop(state);
|
||||
window.handle_input(PlatformInput::MouseExited(crate::MouseExitEvent {
|
||||
pressed_button,
|
||||
position,
|
||||
@@ -553,6 +597,7 @@ impl LinuxClient for X11Client {
|
||||
state.x_root_index,
|
||||
x_window,
|
||||
&state.atoms,
|
||||
state.scale_factor,
|
||||
);
|
||||
|
||||
let screen_resources = state
|
||||
|
||||
@@ -17,6 +17,7 @@ use x11rb::{
|
||||
xinput,
|
||||
xproto::{self, ConnectionExt as _, CreateWindowAux},
|
||||
},
|
||||
resource_manager::Database,
|
||||
wrapper::ConnectionExt,
|
||||
xcb_ffi::XCBConnection,
|
||||
};
|
||||
@@ -27,6 +28,7 @@ use std::{
|
||||
iter::Zip,
|
||||
mem,
|
||||
num::NonZeroU32,
|
||||
ops::Div,
|
||||
ptr::NonNull,
|
||||
rc::Rc,
|
||||
sync::{self, Arc},
|
||||
@@ -128,6 +130,7 @@ impl rwh::HasDisplayHandle for X11Window {
|
||||
}
|
||||
|
||||
impl X11WindowState {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
client: X11ClientStatePtr,
|
||||
executor: ForegroundExecutor,
|
||||
@@ -136,6 +139,7 @@ impl X11WindowState {
|
||||
x_main_screen_index: usize,
|
||||
x_window: xproto::Window,
|
||||
atoms: &XcbAtoms,
|
||||
scale_factor: f32,
|
||||
) -> Self {
|
||||
let x_screen_index = params
|
||||
.display_id
|
||||
@@ -246,7 +250,7 @@ impl X11WindowState {
|
||||
display: Rc::new(X11Display::new(xcb_connection, x_screen_index).unwrap()),
|
||||
raw,
|
||||
bounds: params.bounds.map(|v| v.0),
|
||||
scale_factor: 1.0,
|
||||
scale_factor,
|
||||
renderer: BladeRenderer::new(gpu, gpu_extent),
|
||||
atoms: *atoms,
|
||||
|
||||
@@ -291,6 +295,7 @@ impl Drop for X11Window {
|
||||
}
|
||||
|
||||
impl X11Window {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
client: X11ClientStatePtr,
|
||||
executor: ForegroundExecutor,
|
||||
@@ -299,6 +304,7 @@ impl X11Window {
|
||||
x_main_screen_index: usize,
|
||||
x_window: xproto::Window,
|
||||
atoms: &XcbAtoms,
|
||||
scale_factor: f32,
|
||||
) -> Self {
|
||||
Self(X11WindowStatePtr {
|
||||
state: Rc::new(RefCell::new(X11WindowState::new(
|
||||
@@ -309,6 +315,7 @@ impl X11Window {
|
||||
x_main_screen_index,
|
||||
x_window,
|
||||
atoms,
|
||||
scale_factor,
|
||||
))),
|
||||
callbacks: Rc::new(RefCell::new(Callbacks::default())),
|
||||
xcb_connection: xcb_connection.clone(),
|
||||
@@ -402,7 +409,7 @@ impl X11WindowStatePtr {
|
||||
|
||||
impl PlatformWindow for X11Window {
|
||||
fn bounds(&self) -> Bounds<DevicePixels> {
|
||||
self.0.state.borrow_mut().bounds.map(|v| v.into())
|
||||
self.0.state.borrow().bounds.map(|v| v.into())
|
||||
}
|
||||
|
||||
// todo(linux)
|
||||
@@ -416,11 +423,16 @@ impl PlatformWindow for X11Window {
|
||||
}
|
||||
|
||||
fn content_size(&self) -> Size<Pixels> {
|
||||
self.0.state.borrow_mut().content_size()
|
||||
// We divide by the scale factor here because this value is queried to determine how much to draw,
|
||||
// but it will be multiplied later by the scale to adjust for scaling.
|
||||
let state = self.0.state.borrow();
|
||||
state
|
||||
.content_size()
|
||||
.map(|size| size.div(state.scale_factor))
|
||||
}
|
||||
|
||||
fn scale_factor(&self) -> f32 {
|
||||
self.0.state.borrow_mut().scale_factor
|
||||
self.0.state.borrow().scale_factor
|
||||
}
|
||||
|
||||
// todo(linux)
|
||||
|
||||
Reference in New Issue
Block a user