Commit 15eeea605449
tarball8 files changed+107-45
@@ -39,13 +39,13 @@ urgent = "#ebcb8b"
3939
# Variable refresh rate on outputs that support it, off, on, or fullscreen.4040
vrr = "fullscreen"4141
42
-# Per connector, or [output.nested] for the nested backend's window. transform,43
-# position and scale follow a reload, mode needs a replug. transform is normal,44
-# 90, 180, 270, flipped, flipped-90, flipped-180 or flipped-270. Outputs without45
-# a position line up left to right. position is in logical pixels, the size of46
-# the output divided by its scale. scale is 0.5 to 4.0 and fractional values47
-# are rounded to the nearest 1/120. X11 clients are drawn at scale 1 and48
-# stretched.42
+# Per connector. transform, position and scale follow a reload, mode needs a43
+# replug. transform is normal, 90, 180, 270, flipped, flipped-90, flipped-180 or44
+# flipped-270. Outputs without a position line up left to right. position is in45
+# logical pixels, the size of the output divided by its scale. scale is 0.5 to46
+# 4.0 and is rounded to the nearest 1/120. X11 clients are drawn at scale 1 and47
+# stretched. The nested backend's window is [output.nested], where only scale48
+# applies.4949
# [output.DP-1]5050
# transform = "90"5151
# position = [2560, 0]@@ -3,9 +3,10 @@
33
44
use crate::drm::Drm;55
use crate::nested::Host;6
-use monolith_layout::OutputId;6
+use monolith_layout::{OutputId, Rect};77
use smithay::backend::drm::DrmNode;88
use smithay::output::Output;9
+use smithay::utils::{Logical, Physical, Point, Size, Transform};910
use smithay::wayland::drm_syncobj::DrmSyncobjState;1011
1112
pub enum Backend {@@ -62,3 +63,20 @@ impl Backend {
6263
self.drm_mut()?.syncobj.as_mut()6364
}6465
}66
+67
+/// An output's rectangle in the global logical space. A mode counts physical68
+/// pixels, and `scale` of them make one logical pixel.69
+pub fn logical_area(70
+ position: Point<i32, Logical>,71
+ mode: Size<i32, Physical>,72
+ transform: Transform,73
+ scale: f64,74
+) -> Rect {75
+ let size = transform.transform_size(mode);76
+ Rect::new(77
+ f64::from(position.x),78
+ f64::from(position.y),79
+ f64::from(size.w) / scale,80
+ f64::from(size.h) / scale,81
+ )82
+}@@ -244,6 +244,7 @@ impl State {
244244
drm.devices.reconfigure(&self.settings.config.input);245245
}246246
crate::drm::reconfigure_outputs(self);247
+ crate::nested::reconfigure(self);247248
self.configure_idle();248249
tracing::info!("config reloaded");249250
Ok(())@@ -2,7 +2,7 @@
22
//! connectors, libinput for input, and one smithay DRM output per connector,33
//! each rendered when its own vblank lands.44
5
-use crate::backend::Backend;5
+use crate::backend::{Backend, logical_area};66
use crate::devices::Devices;77
use crate::scene::Draw;88
use crate::state::Services;@@ -412,12 +412,13 @@ fn connect(state: &mut State, connector: connector::Info, crtc: crtc::Handle) {
412412
.fold(0.0, f64::max);413413
let position = match config.position {414414
Some([x, y]) => Point::from((x, y)),415
- None => Point::from((right as i32, 0)),415
+ None => Point::from((right.ceil() as i32, 0)),416416
};417
+ let scale = config.scale();417418
output.change_current_state(418419
Some(wl_mode),419420
Some(transform),420
- Some(Scale::Integer(1)),421
+ Some(Scale::Fractional(scale)),421422
Some(position),422423
);423424
output.set_preferred(wl_mode);@@ -451,20 +452,13 @@ fn connect(state: &mut State, connector: connector::Info, crtc: crtc::Handle) {
451452
let global = output.create_global::<State>(&core.display);452453
space.map_output(&output, position);453454
let (w, h) = mode.size();454
- let size = transform.transform_size(455
- smithay::utils::Size::<i32, smithay::utils::Logical>::from((i32::from(w), i32::from(h))),456
- );457
- let area = Rect::new(458
- f64::from(position.x),459
- f64::from(position.y),460
- f64::from(size.w),461
- f64::from(size.h),462
- );455
+ let area = logical_area(position, wl_mode.size, transform, scale);463456
let id = layout.add_output(&name, area);464457
tracing::info!(465458
name,466459
w,467460
h,461
+ scale,468462
refresh = mode.vrefresh(),469463
?transform,470464
x = position.x,@@ -565,30 +559,33 @@ pub fn reconfigure_outputs(state: &mut State) {
565559
continue;566560
};567561
let transform = transform(config.transform);568
- let size = transform.transform_size(mode.size);562
+ let scale = config.scale();569563
let position: Point<i32, Logical> = match config.position {570564
Some([x, y]) => (x, y).into(),571565
None => (right, 0).into(),572566
};573
- right = right.max(position.x + size.w);574
- if s.output.current_transform() == transform && s.output.current_location() == position {567
+ let area = logical_area(position, mode.size, transform, scale);568
+ right = right.max(area.right().ceil() as i32);569
+ if s.output.current_transform() == transform570
+ && s.output.current_location() == position571
+ && s.output.current_scale().fractional_scale() == scale572
+ {575573
continue;576574
}577
- s.output578
- .change_current_state(None, Some(transform), None, Some(position));579
- space.map_output(&s.output, position);580
- let area = Rect::new(581
- f64::from(position.x),582
- f64::from(position.y),583
- f64::from(size.w),584
- f64::from(size.h),575
+ s.output.change_current_state(576
+ None,577
+ Some(transform),578
+ Some(Scale::Fractional(scale)),579
+ Some(position),585580
);581
+ space.map_output(&s.output, position);586582
layout.set_output_area(s.id, area);587583
s.redraw = true;588584
changed = true;589585
tracing::info!(590586
name = s.output.name(),591587
?transform,588
+ scale,592589
x = position.x,593590
y = position.y,594591
"output reconfigured"@@ -94,7 +94,12 @@ fn configure(surface: &LockSurface, output: &Output) {
9494
let Some(mode) = output.current_mode() else {9595
return;9696
};97
- let size = output.current_transform().transform_size(mode.size);97
+ let logical = mode98
+ .size99
+ .to_f64()100
+ .to_logical(output.current_scale().fractional_scale())101
+ .to_i32_round::<i32>();102
+ let size = output.current_transform().transform_size(logical);98103
let size = (size.w as u32, size.h as u32);99104
surface.with_pending_state(|s| s.size = Some(size.into()));100105
surface.send_configure();@@ -51,7 +51,14 @@ impl Dispatch<wl_pointer::WlPointer, ()> for State {
5151
surface_x,5252
surface_y,5353
..54
- } => state.pointer_to(Point::from((surface_x, surface_y)), time),54
+ } => {55
+ let scale = state56
+ .backend57
+ .nested()58
+ .map_or(1.0, |h| h.output.current_scale().fractional_scale());59
+ let pos = Point::from((surface_x / scale, surface_y / scale));60
+ state.pointer_to(pos, time);61
+ }5562
wl_pointer::Event::Button {5663
button,5764
state: WEnum::Value(pressed),@@ -5,17 +5,17 @@
55
66
mod input;77
8
-use crate::backend::Backend;8
+use crate::backend::{Backend, logical_area};99
use crate::state::Services;1010
use crate::state::State;1111
use calloop_wayland_source::WaylandSource;12
-use monolith_layout::{OutputId, Rect};12
+use monolith_layout::OutputId;1313
use monolith_render_vk::VulkanAllocator;1414
use smithay::backend::allocator::dmabuf::Dmabuf;1515
use smithay::backend::allocator::{Format, Fourcc, Modifier, Slot, Swapchain};1616
use smithay::backend::renderer::Bind;1717
use smithay::backend::renderer::damage::OutputDamageTracker;18
-use smithay::output::{Mode, Output, PhysicalProperties, Subpixel};18
+use smithay::output::{Mode, Output, PhysicalProperties, Scale, Subpixel};1919
use smithay::reexports::calloop::EventLoop;2020
use smithay::utils::{Logical, Size, Transform};2121
use wayland_client::globals::{GlobalListContents, registry_queue_init};@@ -122,20 +122,16 @@ pub fn init(
122122
size: DEFAULT_SIZE.into(),123123
refresh: 60_000,124124
};125
+ let scale = configured_scale(state);125126
output.change_current_state(126127
Some(mode),127128
Some(Transform::Normal),128
- None,129
+ Some(Scale::Fractional(scale)),129130
Some((0, 0).into()),130131
);131132
output.set_preferred(mode);132133
state.wm.space.map_output(&output, (0, 0));133
- let area = Rect::new(134
- 0.0,135
- 0.0,136
- f64::from(DEFAULT_SIZE.0),137
- f64::from(DEFAULT_SIZE.1),138
- );134
+ let area = logical_area((0, 0).into(), mode.size, Transform::Normal, scale);139135
let output_id = state.wm.layout.add_output("nested", area);140136
141137
state.backend = Backend::Nested(Box::new(Host {@@ -166,6 +162,42 @@ pub fn init(
166162
Ok(())167163
}168164
165
+fn configured_scale(state: &State) -> f64 {166
+ state167
+ .settings168
+ .config169
+ .output170
+ .named171
+ .get("nested")172
+ .map_or(1.0, |c| c.scale())173
+}174
+175
+/// Applies a reloaded config's scale to the window's output.176
+pub fn reconfigure(state: &mut State) {177
+ let scale = configured_scale(state);178
+ let Some(host) = state.backend.nested() else {179
+ return;180
+ };181
+ if host.output.current_scale().fractional_scale() == scale {182
+ return;183
+ }184
+ let (o, size) = (host.output_id, host.size);185
+ host.output186
+ .change_current_state(None, None, Some(Scale::Fractional(scale)), None);187
+ let area = logical_area(188
+ (0, 0).into(),189
+ (size.w, size.h).into(),190
+ Transform::Normal,191
+ scale,192
+ );193
+ state.wm.layout.set_output_area(o, area);194
+ tracing::info!(scale, "output reconfigured");195
+ state.dirty.redraw = true;196
+ state.reserve_layers();197
+ state.reconfigure_lock();198
+ state.apply_layout();199
+}200
+169201
/// Renders a frame if something changed and the host is ready for one.170202
pub fn render(state: &mut State) {171203
let State {@@ -1,4 +1,5 @@
11
use crate::anim::Animator;2
+use crate::backend::logical_area;23
use crate::commands::Binds;34
use crate::focus::Focus;45
use crate::globals::Protocols;@@ -18,7 +19,7 @@ use smithay::reexports::calloop::{EventLoop, Interest, LoopSignal, Mode, PostAct
1819
use smithay::reexports::wayland_server::backend::{ClientData, ClientId, DisconnectReason};1920
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;2021
use smithay::reexports::wayland_server::{Display, DisplayHandle};21
-use smithay::utils::{Clock, Logical, Monotonic, Point, SERIAL_COUNTER, Size};22
+use smithay::utils::{Clock, Logical, Monotonic, Point, SERIAL_COUNTER, Size, Transform};2223
use smithay::wayland::compositor::CompositorClientState;2324
use smithay::wayland::shell::wlr_layer::Layer;2425
use smithay::wayland::socket::ListeningSocketSource;@@ -254,11 +255,12 @@ impl State {
254255
pub fn resize_output(&mut self, size: Size<i32, Logical>) {255256
if let Some(host) = self.backend.nested() {256257
let o = host.output_id;257
- let area = Rect::new(0.0, 0.0, f64::from(size.w), f64::from(size.h));258258
let mode = smithay::output::Mode {259259
size: (size.w, size.h).into(),260260
refresh: 60_000,261261
};262
+ let scale = host.output.current_scale().fractional_scale();263
+ let area = logical_area((0, 0).into(), mode.size, Transform::Normal, scale);262264
host.output263265
.change_current_state(Some(mode), None, None, None);264266
self.wm.layout.set_output_area(o, area);