Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

xwayland: allow windows to scale themselves #287

Merged
merged 1 commit into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading