Skip to content

Commit

Permalink
xwayland: allow windows to scale themselves
Browse files Browse the repository at this point in the history
  • Loading branch information
mahkoh committed Oct 8, 2024
1 parent cc8db84 commit 19b07fa
Show file tree
Hide file tree
Showing 40 changed files with 800 additions and 80 deletions.
5 changes: 5 additions & 0 deletions jay-config/src/_private/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use {
connector_type::{ConnectorType, CON_UNKNOWN},
Connector, DrmDevice, Format, GfxApi, Mode, TearingMode, Transform, VrrMode,
},
xwayland::XScalingMode,
Axis, Direction, ModifiedKeySym, PciId, Workspace,
},
bincode::Options,
Expand Down Expand Up @@ -816,6 +817,10 @@ impl Client {
(width, height)
}

pub fn set_x_scaling_mode(&self, mode: XScalingMode) {
self.send(&ClientMessage::SetXScalingMode { mode })
}

pub fn set_vrr_mode(&self, connector: Option<Connector>, mode: VrrMode) {
self.send(&ClientMessage::SetVrrMode { connector, mode })
}
Expand Down
4 changes: 4 additions & 0 deletions jay-config/src/_private/ipc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use {
},
Axis, Direction, PciId, Workspace,
_private::{PollableId, WireMode},
xwayland::XScalingMode,
},
serde::{Deserialize, Serialize},
std::time::Duration,
Expand Down Expand Up @@ -523,6 +524,9 @@ pub enum ClientMessage<'a> {
SetUiDragThreshold {
threshold: i32,
},
SetXScalingMode {
mode: XScalingMode,
},
}

#[derive(Serialize, Deserialize, Debug)]
Expand Down
1 change: 1 addition & 0 deletions jay-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ pub mod tasks;
pub mod theme;
pub mod timer;
pub mod video;
pub mod xwayland;

/// A planar direction.
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq)]
Expand Down
33 changes: 33 additions & 0 deletions jay-config/src/xwayland.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//! Tools for configuring Xwayland.
use serde::{Deserialize, Serialize};

/// The scaling mode of X windows.
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
pub struct XScalingMode(pub u32);

impl XScalingMode {
/// The default mode.
///
/// Currently this means that windows are rendered at the lowest scale and then
/// upscaled if necessary.
pub const DEFAULT: Self = Self(0);
/// Windows are rendered at the highest integer scale and then downscaled.
///
/// This has significant performance implications unless the window is running on the
/// output with the highest scale and that scale is an integer scale.
///
/// For example, on a 3840x2160 output with a 1.5 scale, a fullscreen window will be
/// rendered at 3840x2160 * 2 / 1.5 = 5120x2880 pixels and then downscaled to
/// 3840x2160. This overhead gets worse the lower the scale of the output is.
///
/// Additionally, this mode requires the X window to scale its contents itself. In the
/// example above, you might achieve this by setting the environment variable
/// `GDK_SCALE=2`.
pub const DOWNSCALED: Self = Self(1);
}

/// Sets the scaling mode for X windows.
pub fn set_x_scaling_mode(mode: XScalingMode) {
get!().set_x_scaling_mode(mode)
}
1 change: 1 addition & 0 deletions release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- Tiles and workspaces can now be dragged with the mouse.
- Vulkan is now the default renderer.
- Emulate vblank events on the nvidia driver.
- Allow X windows to scale themselves.

# 1.6.0 (2024-09-25)

Expand Down
9 changes: 8 additions & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ pub mod screenshot;
mod seat_test;
mod set_log_level;
mod unlock;
mod xwayland;

use {
crate::{
cli::{damage_tracking::DamageTrackingArgs, input::InputArgs, randr::RandrArgs},
cli::{
damage_tracking::DamageTrackingArgs, input::InputArgs, randr::RandrArgs,
xwayland::XwaylandArgs,
},
compositor::start_compositor,
format::{ref_formats, Format},
portal,
Expand Down Expand Up @@ -72,6 +76,8 @@ pub enum Cmd {
/// Modify damage tracking settings. (Only for debugging.)
#[clap(hide = true)]
DamageTracking(DamageTrackingArgs),
/// Inspect/modify xwayland settings.
Xwayland(XwaylandArgs),
#[cfg(feature = "it")]
RunTests,
}
Expand Down Expand Up @@ -259,6 +265,7 @@ pub fn main() {
Cmd::Randr(a) => randr::main(cli.global, a),
Cmd::Input(a) => input::main(cli.global, a),
Cmd::DamageTracking(a) => damage_tracking::main(cli.global, a),
Cmd::Xwayland(a) => xwayland::main(cli.global, a),
#[cfg(feature = "it")]
Cmd::RunTests => crate::it::run_tests(),
}
Expand Down
106 changes: 106 additions & 0 deletions src/cli/xwayland.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use {
crate::{
cli::GlobalArgs,
tools::tool_client::{with_tool_client, Handle, ToolClient},
wire::{jay_compositor, jay_xwayland, JayXwaylandId},
},
clap::{Args, Subcommand, ValueEnum},
jay_config::xwayland::XScalingMode,
std::{cell::Cell, rc::Rc},
};

#[derive(Args, Debug)]
pub struct XwaylandArgs {
#[clap(subcommand)]
pub command: Option<XwaylandCmd>,
}

#[derive(Subcommand, Debug, Default)]
pub enum XwaylandCmd {
/// Print the Xwayland status.
#[default]
Status,
/// Set the Xwayland scaling mode.
SetScalingMode(SetScalingModeArgs),
}

#[derive(Args, Debug)]
pub struct SetScalingModeArgs {
#[clap(value_enum)]
pub mode: CliScalingMode,
}

#[derive(ValueEnum, Debug, Copy, Clone, Hash, PartialEq)]
pub enum CliScalingMode {
/// The default mode.
Default,
/// Windows are rendered at the highest integer scale and then downscaled.
Downscaled,
}

pub fn main(global: GlobalArgs, args: XwaylandArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
let xwayland = Xwayland { tc: tc.clone() };
xwayland.run(args).await;
});
}

struct Xwayland {
tc: Rc<ToolClient>,
}

impl Xwayland {
async fn run(self, args: XwaylandArgs) {
let tc = &self.tc;
let comp = tc.jay_compositor().await;
let xwayland = tc.id();
tc.send(jay_compositor::GetXwayland {
self_id: comp,
id: xwayland,
});
match args.command.unwrap_or_default() {
XwaylandCmd::Status => self.status(xwayland).await,
XwaylandCmd::SetScalingMode(args) => self.set_scaling_mode(xwayland, args).await,
}
}

async fn status(self, xwayland: JayXwaylandId) {
let tc = &self.tc;
tc.send(jay_xwayland::GetScaling { self_id: xwayland });
let mode = Rc::new(Cell::new(0));
let scale = Rc::new(Cell::new(None));
jay_xwayland::ScalingMode::handle(tc, xwayland, mode.clone(), |iv, msg| {
iv.set(msg.mode);
});
jay_xwayland::ImpliedScale::handle(tc, xwayland, scale.clone(), |iv, msg| {
iv.set(Some(msg.scale));
});
tc.round_trip().await;
let mode_str;
let mode = match XScalingMode(mode.get()) {
XScalingMode::DEFAULT => "default",
XScalingMode::DOWNSCALED => "downscaled",
o => {
mode_str = format!("unknown ({})", o.0);
&mode_str
}
};
println!("scaling mode: {}", mode);
if let Some(scale) = scale.get() {
println!("implied scale: {}", scale);
}
}

async fn set_scaling_mode(self, xwayland: JayXwaylandId, args: SetScalingModeArgs) {
let tc = &self.tc;
let mode = match args.mode {
CliScalingMode::Default => XScalingMode::DEFAULT,
CliScalingMode::Downscaled => XScalingMode::DOWNSCALED,
};
tc.send(jay_xwayland::SetScalingMode {
self_id: xwayland,
mode: mode.0,
});
tc.round_trip().await;
}
}
2 changes: 2 additions & 0 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ impl Clients {
&global.wait_for_sync_obj,
&global.ring,
)),
wire_scale: Default::default(),
});
track!(data, data);
let display = Rc::new(WlDisplay::new(&data));
Expand Down Expand Up @@ -282,6 +283,7 @@ pub struct Client {
pub surfaces_by_xwayland_serial: CopyHashMap<u64, Rc<WlSurface>>,
pub activation_tokens: RefCell<VecDeque<ActivationToken>>,
pub commit_timelines: Rc<CommitTimelines>,
pub wire_scale: Cell<Option<i32>>,
}

pub const NUM_CACHED_SERIAL_RANGES: usize = 64;
Expand Down
2 changes: 2 additions & 0 deletions src/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ fn start_compositor2(
handler: Default::default(),
queue: Default::default(),
ipc_device_ids: Default::default(),
use_wire_scale: Default::default(),
wire_scale: Default::default(),
},
acceptor: Default::default(),
serial: Default::default(),
Expand Down
17 changes: 17 additions & 0 deletions src/config/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ use {
Connector, DrmDevice, Format as ConfigFormat, GfxApi, TearingMode as ConfigTearingMode,
Transform, VrrMode as ConfigVrrMode,
},
xwayland::XScalingMode,
Axis, Direction, Workspace,
},
libloading::Library,
Expand Down Expand Up @@ -759,6 +760,17 @@ impl ConfigProxyHandler {
Ok(())
}

fn handle_set_x_scaling_mode(&self, mode: XScalingMode) -> Result<(), CphError> {
let use_wire_scale = match mode {
XScalingMode::DEFAULT => false,
XScalingMode::DOWNSCALED => true,
_ => return Err(CphError::UnknownXScalingMode(mode)),
};
self.state.xwayland.use_wire_scale.set(use_wire_scale);
self.state.update_xwayland_wire_scale();
Ok(())
}

fn handle_set_ui_drag_enabled(&self, enabled: bool) {
self.state.ui_drag_enabled.set(enabled);
}
Expand Down Expand Up @@ -1965,6 +1977,9 @@ impl ConfigProxyHandler {
ClientMessage::SetUiDragThreshold { threshold } => {
self.handle_set_ui_drag_threshold(threshold)
}
ClientMessage::SetXScalingMode { mode } => self
.handle_set_x_scaling_mode(mode)
.wrn("set_x_scaling_mode")?,
}
Ok(())
}
Expand Down Expand Up @@ -2034,6 +2049,8 @@ enum CphError {
UnknownTearingMode(ConfigTearingMode),
#[error("The format {0:?} is unknown")]
UnknownFormat(ConfigFormat),
#[error("Unknown x scaling mode {0:?}")]
UnknownXScalingMode(XScalingMode),
}

trait WithRequestName {
Expand Down
18 changes: 17 additions & 1 deletion src/fixed.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{
cmp::Ordering,
fmt::{Debug, Display, Formatter},
ops::{Add, AddAssign, Sub, SubAssign},
ops::{Add, AddAssign, Div, Mul, Sub, SubAssign},
};

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
Expand Down Expand Up @@ -108,6 +108,22 @@ impl Add<i32> for Fixed {
}
}

impl Mul<i32> for Fixed {
type Output = Self;

fn mul(self, rhs: i32) -> Self::Output {
Self(self.0 * rhs)
}
}

impl Div<i32> for Fixed {
type Output = Self;

fn div(self, rhs: i32) -> Self::Output {
Self(self.0 / rhs)
}
}

impl AddAssign for Fixed {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
Expand Down
1 change: 1 addition & 0 deletions src/ifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub mod jay_select_workspace;
pub mod jay_toplevel;
pub mod jay_workspace;
pub mod jay_workspace_watcher;
pub mod jay_xwayland;
pub mod org_kde_kwin_server_decoration;
pub mod org_kde_kwin_server_decoration_manager;
pub mod wl_buffer;
Expand Down
15 changes: 14 additions & 1 deletion src/ifs/jay_compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use {
jay_select_toplevel::{JaySelectToplevel, JayToplevelSelector},
jay_select_workspace::{JaySelectWorkspace, JayWorkspaceSelector},
jay_workspace_watcher::JayWorkspaceWatcher,
jay_xwayland::JayXwayland,
},
leaks::Tracker,
object::{Object, Version},
Expand Down Expand Up @@ -70,7 +71,7 @@ impl Global for JayCompositorGlobal {
}

fn version(&self) -> u32 {
10
11
}

fn required_caps(&self) -> ClientCaps {
Expand Down Expand Up @@ -409,6 +410,18 @@ impl JayCompositorRequestHandler for JayCompositor {
self.client.add_client_obj(&obj)?;
Ok(())
}

fn get_xwayland(&self, req: GetXwayland, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let obj = Rc::new(JayXwayland {
id: req.id,
client: self.client.clone(),
tracker: Default::default(),
version: self.version,
});
track!(self.client, obj);
self.client.add_client_obj(&obj)?;
Ok(())
}
}

object_base! {
Expand Down
Loading

0 comments on commit 19b07fa

Please sign in to comment.