1
0
Fork 0
forked from wry/wry

config: allow disabling color-management

This commit is contained in:
Julian Orth 2025-02-26 16:16:38 +01:00
parent c66f5798b7
commit 248eb324a5
24 changed files with 388 additions and 9 deletions

View file

@ -763,6 +763,10 @@ impl Client {
self.send(&ClientMessage::SetUiDragThreshold { threshold }); self.send(&ClientMessage::SetUiDragThreshold { threshold });
} }
pub fn set_color_management_enabled(&self, enabled: bool) {
self.send(&ClientMessage::SetColorManagementEnabled { enabled });
}
pub fn connector_connected(&self, connector: Connector) -> bool { pub fn connector_connected(&self, connector: Connector) -> bool {
let res = self.send_with_response(&ClientMessage::ConnectorConnected { connector }); let res = self.send_with_response(&ClientMessage::ConnectorConnected { connector });
get_response!(res, false, ConnectorConnected { connected }); get_response!(res, false, ConnectorConnected { connected });

View file

@ -530,6 +530,9 @@ pub enum ClientMessage<'a> {
SetIdleGracePeriod { SetIdleGracePeriod {
period: Duration, period: Duration,
}, },
SetColorManagementEnabled {
enabled: bool,
},
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]

View file

@ -264,3 +264,12 @@ pub fn set_ui_drag_enabled(enabled: bool) {
pub fn set_ui_drag_threshold(threshold: i32) { pub fn set_ui_drag_threshold(threshold: i32) {
get!().set_ui_drag_threshold(threshold); get!().set_ui_drag_threshold(threshold);
} }
/// Enables or disables the color-management protocol.
///
/// The default is `false`.
///
/// Affected applications must be restarted for this to take effect.
pub fn set_color_management_enabled(enabled: bool) {
get!().set_color_management_enabled(enabled);
}

View file

@ -1,4 +1,5 @@
mod color; mod color;
mod color_management;
mod damage_tracking; mod damage_tracking;
mod duration; mod duration;
mod generate; mod generate;
@ -17,8 +18,8 @@ mod xwayland;
use { use {
crate::{ crate::{
cli::{ cli::{
damage_tracking::DamageTrackingArgs, idle::IdleCmd, input::InputArgs, randr::RandrArgs, color_management::ColorManagementArgs, damage_tracking::DamageTrackingArgs,
xwayland::XwaylandArgs, idle::IdleCmd, input::InputArgs, randr::RandrArgs, xwayland::XwaylandArgs,
}, },
compositor::start_compositor, compositor::start_compositor,
format::{Format, ref_formats}, format::{Format, ref_formats},
@ -78,6 +79,8 @@ pub enum Cmd {
DamageTracking(DamageTrackingArgs), DamageTracking(DamageTrackingArgs),
/// Inspect/modify xwayland settings. /// Inspect/modify xwayland settings.
Xwayland(XwaylandArgs), Xwayland(XwaylandArgs),
/// Inspect/modify the color-management settings.
ColorManagement(ColorManagementArgs),
#[cfg(feature = "it")] #[cfg(feature = "it")]
RunTests, RunTests,
} }
@ -235,6 +238,7 @@ pub fn main() {
Cmd::Input(a) => input::main(cli.global, a), Cmd::Input(a) => input::main(cli.global, a),
Cmd::DamageTracking(a) => damage_tracking::main(cli.global, a), Cmd::DamageTracking(a) => damage_tracking::main(cli.global, a),
Cmd::Xwayland(a) => xwayland::main(cli.global, a), Cmd::Xwayland(a) => xwayland::main(cli.global, a),
Cmd::ColorManagement(a) => color_management::main(cli.global, a),
#[cfg(feature = "it")] #[cfg(feature = "it")]
Cmd::RunTests => crate::it::run_tests(), Cmd::RunTests => crate::it::run_tests(),
} }

View file

@ -0,0 +1,75 @@
use {
crate::{
cli::GlobalArgs,
tools::tool_client::{Handle, ToolClient, with_tool_client},
wire::{JayColorManagementId, jay_color_management, jay_compositor},
},
clap::{Args, Subcommand},
std::{cell::Cell, rc::Rc},
};
#[derive(Args, Debug)]
pub struct ColorManagementArgs {
#[clap(subcommand)]
pub command: Option<ColorManagementCmd>,
}
#[derive(Subcommand, Debug, Default)]
pub enum ColorManagementCmd {
/// Print the color-management status.
#[default]
Status,
/// Enable the color-management protocol.
Enable,
/// Disable the color-management protocol.
Disable,
}
pub fn main(global: GlobalArgs, args: ColorManagementArgs) {
with_tool_client(global.log_level.into(), |tc| async move {
let cm = ColorManagement { tc: tc.clone() };
cm.run(args).await;
});
}
struct ColorManagement {
tc: Rc<ToolClient>,
}
impl ColorManagement {
async fn run(self, args: ColorManagementArgs) {
let tc = &self.tc;
let comp = tc.jay_compositor().await;
let id = tc.id();
tc.send(jay_compositor::GetColorManagement { self_id: comp, id });
match args.command.unwrap_or_default() {
ColorManagementCmd::Status => self.status(id).await,
ColorManagementCmd::Enable => self.set_enabled(id, true).await,
ColorManagementCmd::Disable => self.set_enabled(id, false).await,
}
}
async fn status(self, id: JayColorManagementId) {
let tc = &self.tc;
tc.send(jay_color_management::Get { self_id: id });
let enabled = Rc::new(Cell::new(false));
jay_color_management::Enabled::handle(tc, id, enabled.clone(), |iv, msg| {
iv.set(msg.enabled != 0);
});
tc.round_trip().await;
if enabled.get() {
println!("Enabled");
} else {
println!("Disabled");
}
}
async fn set_enabled(self, id: JayColorManagementId, enabled: bool) {
let tc = &self.tc;
tc.send(jay_color_management::SetEnabled {
self_id: id,
enabled: enabled as _,
});
tc.round_trip().await;
}
}

View file

@ -283,6 +283,7 @@ fn start_compositor2(
tray_item_ids: Default::default(), tray_item_ids: Default::default(),
data_control_device_ids: Default::default(), data_control_device_ids: Default::default(),
workspace_managers: Default::default(), workspace_managers: Default::default(),
color_management_enabled: Cell::new(false),
}); });
state.tracker.register(ClientId::from_raw(0)); state.tracker.register(ClientId::from_raw(0));
create_dummy_output(&state); create_dummy_output(&state);

View file

@ -926,6 +926,10 @@ impl ConfigProxyHandler {
self.state.explicit_sync_enabled.set(enabled); self.state.explicit_sync_enabled.set(enabled);
} }
fn handle_set_color_management_enabled(&self, enabled: bool) {
self.state.color_management_enabled.set(enabled);
}
fn handle_get_socket_path(&self) { fn handle_get_socket_path(&self) {
match self.state.acceptor.get() { match self.state.acceptor.get() {
Some(a) => { Some(a) => {
@ -1986,6 +1990,9 @@ impl ConfigProxyHandler {
ClientMessage::SetIdleGracePeriod { period } => { ClientMessage::SetIdleGracePeriod { period } => {
self.handle_set_idle_grace_period(period) self.handle_set_idle_grace_period(period)
} }
ClientMessage::SetColorManagementEnabled { enabled } => {
self.handle_set_color_management_enabled(enabled)
}
} }
Ok(()) Ok(())
} }

View file

@ -135,6 +135,10 @@ pub trait Global: GlobalBase {
fn xwayland_only(&self) -> bool { fn xwayland_only(&self) -> bool {
false false
} }
fn exposed(&self, state: &State) -> bool {
let _ = state;
true
}
} }
pub struct Globals { pub struct Globals {
@ -297,7 +301,8 @@ impl Globals {
($singleton:expr) => { ($singleton:expr) => {
for global in globals.values() { for global in globals.values() {
if global.singleton() == $singleton { if global.singleton() == $singleton {
if caps.contains(global.required_caps()) if global.exposed(&registry.client.state)
&& caps.contains(global.required_caps())
&& (xwayland || !global.xwayland_only()) && (xwayland || !global.xwayland_only())
{ {
registry.send_global(global); registry.send_global(global);

View file

@ -10,6 +10,7 @@ pub mod ext_output_image_capture_source_manager_v1;
pub mod ext_session_lock_manager_v1; pub mod ext_session_lock_manager_v1;
pub mod ext_session_lock_v1; pub mod ext_session_lock_v1;
pub mod ipc; pub mod ipc;
pub mod jay_color_management;
pub mod jay_compositor; pub mod jay_compositor;
pub mod jay_damage_tracking; pub mod jay_damage_tracking;
pub mod jay_ei_session; pub mod jay_ei_session;

View file

@ -14,6 +14,7 @@ use {
}, },
leaks::Tracker, leaks::Tracker,
object::{Object, Version}, object::{Object, Version},
state::State,
wire::{ wire::{
WpColorManagerV1Id, WpColorManagerV1Id,
wp_color_manager_v1::{SupportedIntent, *}, wp_color_manager_v1::{SupportedIntent, *},
@ -198,6 +199,10 @@ impl Global for WpColorManagerV1Global {
fn version(&self) -> u32 { fn version(&self) -> u32 {
1 1
} }
fn exposed(&self, state: &State) -> bool {
state.color_management_enabled.get()
}
} }
simple_add_global!(WpColorManagerV1Global); simple_add_global!(WpColorManagerV1Global);

View file

@ -0,0 +1,64 @@
use {
crate::{
client::{Client, ClientError},
leaks::Tracker,
object::{Object, Version},
wire::{JayColorManagementId, jay_color_management::*},
},
std::rc::Rc,
thiserror::Error,
};
pub struct JayColorManagement {
pub id: JayColorManagementId,
pub client: Rc<Client>,
pub tracker: Tracker<Self>,
pub version: Version,
}
impl JayColorManagement {
fn send_enabled(&self) {
self.client.event(Enabled {
self_id: self.id,
enabled: self.client.state.color_management_enabled.get() as u32,
});
}
}
impl JayColorManagementRequestHandler for JayColorManagement {
type Error = JayColorManagementError;
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.client.remove_obj(self)?;
Ok(())
}
fn get(&self, _req: Get, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.send_enabled();
Ok(())
}
fn set_enabled(&self, req: SetEnabled, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.client
.state
.color_management_enabled
.set(req.enabled != 0);
Ok(())
}
}
object_base! {
self = JayColorManagement;
version = self.version;
}
impl Object for JayColorManagement {}
simple_add_obj!(JayColorManagement);
#[derive(Debug, Error)]
pub enum JayColorManagementError {
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(JayColorManagementError, ClientError);

View file

@ -4,6 +4,7 @@ use {
client::{CAP_JAY_COMPOSITOR, Client, ClientCaps, ClientError}, client::{CAP_JAY_COMPOSITOR, Client, ClientCaps, ClientError},
globals::{Global, GlobalName}, globals::{Global, GlobalName},
ifs::{ ifs::{
jay_color_management::JayColorManagement,
jay_ei_session_builder::JayEiSessionBuilder, jay_ei_session_builder::JayEiSessionBuilder,
jay_idle::JayIdle, jay_idle::JayIdle,
jay_input::JayInput, jay_input::JayInput,
@ -72,7 +73,7 @@ impl Global for JayCompositorGlobal {
} }
fn version(&self) -> u32 { fn version(&self) -> u32 {
13 14
} }
fn required_caps(&self) -> ClientCaps { fn required_caps(&self) -> ClientCaps {
@ -439,6 +440,22 @@ impl JayCompositorRequestHandler for JayCompositor {
obj.done(tl); obj.done(tl);
Ok(()) Ok(())
} }
fn get_color_management(
&self,
req: GetColorManagement,
_slf: &Rc<Self>,
) -> Result<(), Self::Error> {
let obj = Rc::new(JayColorManagement {
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! { object_base! {

View file

@ -233,6 +233,7 @@ pub struct State {
pub tray_item_ids: TrayItemIds, pub tray_item_ids: TrayItemIds,
pub data_control_device_ids: DataControlDeviceIds, pub data_control_device_ids: DataControlDeviceIds,
pub workspace_managers: WorkspaceManagerState, pub workspace_managers: WorkspaceManagerState,
pub color_management_enabled: Cell<bool>,
} }
// impl Drop for State { // impl Drop for State {

View file

@ -332,7 +332,7 @@ impl ToolClient {
self_id: s.registry, self_id: s.registry,
name: s.jay_compositor.0, name: s.jay_compositor.0,
interface: JayCompositor.name(), interface: JayCompositor.name(),
version: s.jay_compositor.1.min(13), version: s.jay_compositor.1.min(14),
id: id.into(), id: id.into(),
}); });
self.jay_compositor.set(Some(id)); self.jay_compositor.set(Some(id));

View file

@ -11,7 +11,10 @@ use {
crate::{ crate::{
config::{ config::{
context::Context, context::Context,
parsers::config::{ConfigParser, ConfigParserError}, parsers::{
color_management::ColorManagement,
config::{ConfigParser, ConfigParserError},
},
}, },
toml::{self}, toml::{self},
}, },
@ -358,6 +361,7 @@ pub struct Config {
pub libei: Libei, pub libei: Libei,
pub ui_drag: UiDrag, pub ui_drag: UiDrag,
pub xwayland: Option<Xwayland>, pub xwayland: Option<Xwayland>,
pub color_management: Option<ColorManagement>,
} }
#[derive(Debug, Error)] #[derive(Debug, Error)]

View file

@ -8,6 +8,7 @@ use {
pub mod action; pub mod action;
mod color; mod color;
pub mod color_management;
pub mod config; pub mod config;
mod connector; mod connector;
mod connector_match; mod connector_match;

View file

@ -0,0 +1,48 @@
use {
crate::{
config::{
context::Context,
extractor::{Extractor, ExtractorError, bol, opt},
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
},
toml::{
toml_span::{DespanExt, Span, Spanned},
toml_value::Value,
},
},
indexmap::IndexMap,
thiserror::Error,
};
#[derive(Debug, Error)]
pub enum ColorManagementParserError {
#[error(transparent)]
Expected(#[from] UnexpectedDataType),
#[error(transparent)]
Extract(#[from] ExtractorError),
}
pub struct ColorManagementParser<'a>(pub &'a Context<'a>);
#[derive(Clone, Debug)]
pub struct ColorManagement {
pub enabled: Option<bool>,
}
impl Parser for ColorManagementParser<'_> {
type Value = ColorManagement;
type Error = ColorManagementParserError;
const EXPECTED: &'static [DataType] = &[DataType::Table];
fn parse_table(
&mut self,
span: Span,
table: &IndexMap<Spanned<String>, Spanned<Value>>,
) -> ParseResult<Self> {
let mut ext = Extractor::new(self.0, span, table);
let (enabled,) = ext.extract((opt(bol("enabled")),))?;
Ok(ColorManagement {
enabled: enabled.despan(),
})
}
}

View file

@ -7,6 +7,7 @@ use {
parser::{DataType, ParseResult, Parser, UnexpectedDataType}, parser::{DataType, ParseResult, Parser, UnexpectedDataType},
parsers::{ parsers::{
action::ActionParser, action::ActionParser,
color_management::ColorManagementParser,
connector::ConnectorsParser, connector::ConnectorsParser,
drm_device::DrmDevicesParser, drm_device::DrmDevicesParser,
drm_device_match::DrmDeviceMatchParser, drm_device_match::DrmDeviceMatchParser,
@ -117,6 +118,7 @@ impl Parser for ConfigParser<'_> {
ui_drag_val, ui_drag_val,
xwayland_val, xwayland_val,
), ),
(color_management_val,),
) = ext.extract(( ) = ext.extract((
( (
opt(val("keymap")), opt(val("keymap")),
@ -154,6 +156,7 @@ impl Parser for ConfigParser<'_> {
opt(val("ui-drag")), opt(val("ui-drag")),
opt(val("xwayland")), opt(val("xwayland")),
), ),
(opt(val("color-management")),),
))?; ))?;
let mut keymap = None; let mut keymap = None;
if let Some(value) = keymap_val { if let Some(value) = keymap_val {
@ -366,6 +369,18 @@ impl Parser for ConfigParser<'_> {
} }
} }
} }
let mut color_management = None;
if let Some(value) = color_management_val {
match value.parse(&mut ColorManagementParser(self.0)) {
Ok(v) => color_management = Some(v),
Err(e) => {
log::warn!(
"Could not parse the color-management settings: {}",
self.0.error(e)
);
}
}
}
Ok(Config { Ok(Config {
keymap, keymap,
repeat_rate, repeat_rate,
@ -396,6 +411,7 @@ impl Parser for ConfigParser<'_> {
libei, libei,
ui_drag, ui_drag,
xwayland, xwayland,
color_management,
}) })
} }
} }

View file

@ -23,9 +23,9 @@ use {
is_reload, is_reload,
keyboard::{Keymap, ModifiedKeySym}, keyboard::{Keymap, ModifiedKeySym},
logging::set_log_level, logging::set_log_level,
on_devices_enumerated, on_idle, quit, reload, set_default_workspace_capture, on_devices_enumerated, on_idle, quit, reload, set_color_management_enabled,
set_explicit_sync_enabled, set_idle, set_idle_grace_period, set_ui_drag_enabled, set_default_workspace_capture, set_explicit_sync_enabled, set_idle, set_idle_grace_period,
set_ui_drag_threshold, set_ui_drag_enabled, set_ui_drag_threshold,
status::{set_i3bar_separator, set_status, set_status_command, unset_status_command}, status::{set_i3bar_separator, set_status, set_status_command, unset_status_command},
switch_to_vt, switch_to_vt,
theme::{reset_colors, reset_font, reset_sizes, set_font}, theme::{reset_colors, reset_font, reset_sizes, set_font},
@ -1078,6 +1078,11 @@ fn load_config(initial_load: bool, persistent: &Rc<PersistentState>) {
set_x_scaling_mode(mode); set_x_scaling_mode(mode);
} }
} }
if let Some(cm) = config.color_management {
if let Some(enabled) = cm.enabled {
set_color_management_enabled(enabled);
}
}
} }
fn create_command(exec: &Exec) -> Command { fn create_command(exec: &Exec) -> Command {

View file

@ -427,6 +427,17 @@
"type": "string", "type": "string",
"description": "A color.\n\nThe format should be one of the following:\n\n- `#rgb`\n- `#rrggbb`\n- `#rgba`\n- `#rrggbba`\n" "description": "A color.\n\nThe format should be one of the following:\n\n- `#rgb`\n- `#rrggbb`\n- `#rgba`\n- `#rrggbba`\n"
}, },
"ColorManagement": {
"description": "Describes color-management settings.\n\n- Example:\n\n ```toml\n [color-management]\n enabled = true\n ```\n",
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"description": "Whether the color management protocol is enabled.\n\nThis has no effect on running applications.\n\nThe default is `false`.\n"
}
},
"required": []
},
"ComplexShortcut": { "ComplexShortcut": {
"description": "Describes a complex shortcut.\n\n- Example:\n\n ```toml\n [complex-shortcuts.XF86AudioRaiseVolume]\n mod-mask = \"alt\"\n action = { type = \"exec\", exec = [\"pactl\", \"set-sink-volume\", \"0\", \"+10%\"] }\n ```\n", "description": "Describes a complex shortcut.\n\n- Example:\n\n ```toml\n [complex-shortcuts.XF86AudioRaiseVolume]\n mod-mask = \"alt\"\n action = { type = \"exec\", exec = [\"pactl\", \"set-sink-volume\", \"0\", \"+10%\"] }\n ```\n",
"type": "object", "type": "object",
@ -597,6 +608,10 @@
"xwayland": { "xwayland": {
"description": "Configures the Xwayland settings.\n\n- Example:\n\n ```toml\n xwayland = { scaling-mode = \"downscaled\" }\n ```\n", "description": "Configures the Xwayland settings.\n\n- Example:\n\n ```toml\n xwayland = { scaling-mode = \"downscaled\" }\n ```\n",
"$ref": "#/$defs/Xwayland" "$ref": "#/$defs/Xwayland"
},
"color-management": {
"description": "Configures the color-management settings.\n\n- Example:\n\n ```toml\n [color-management]\n enabled = true\n ```\n",
"$ref": "#/$defs/ColorManagement"
} }
}, },
"required": [] "required": []

View file

@ -590,6 +590,33 @@ The format should be one of the following:
Values of this type should be strings. Values of this type should be strings.
<a name="types-ColorManagement"></a>
### `ColorManagement`
Describes color-management settings.
- Example:
```toml
[color-management]
enabled = true
```
Values of this type should be tables.
The table has the following fields:
- `enabled` (optional):
Whether the color management protocol is enabled.
This has no effect on running applications.
The default is `false`.
The value of this field should be a boolean.
<a name="types-ComplexShortcut"></a> <a name="types-ComplexShortcut"></a>
### `ComplexShortcut` ### `ComplexShortcut`
@ -1178,6 +1205,19 @@ The table has the following fields:
The value of this field should be a [Xwayland](#types-Xwayland). The value of this field should be a [Xwayland](#types-Xwayland).
- `color-management` (optional):
Configures the color-management settings.
- Example:
```toml
[color-management]
enabled = true
```
The value of this field should be a [ColorManagement](#types-ColorManagement).
<a name="types-Connector"></a> <a name="types-Connector"></a>
### `Connector` ### `Connector`

View file

@ -2286,6 +2286,18 @@ Config:
```toml ```toml
xwayland = { scaling-mode = "downscaled" } xwayland = { scaling-mode = "downscaled" }
``` ```
color-management:
ref: ColorManagement
required: false
description: |
Configures the color-management settings.
- Example:
```toml
[color-management]
enabled = true
```
Idle: Idle:
@ -2727,3 +2739,26 @@ XScalingMode:
Additionally, this mode requires the X window to scale its contents itself. In the 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 example above, you might achieve this by setting the environment variable
`GDK_SCALE=2`. `GDK_SCALE=2`.
ColorManagement:
kind: table
description: |
Describes color-management settings.
- Example:
```toml
[color-management]
enabled = true
```
fields:
enabled:
description: |
Whether the color management protocol is enabled.
This has no effect on running applications.
The default is `false`.
kind: boolean
required: false

View file

@ -0,0 +1,15 @@
request destroy {
}
request get {
}
request set_enabled {
enabled: u32,
}
event enabled {
enabled: u32,
}

View file

@ -101,6 +101,10 @@ request get_toplevel (since = 12) {
toplevel_id: str, toplevel_id: str,
} }
request get_color_management (since = 14) {
id: id(jay_color_management),
}
# events # events
event client_id { event client_id {