From 1eb0d3e17373f2c6a628bd8796ab0b6ade34ab3d Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sun, 17 Apr 2022 17:59:45 +0200 Subject: [PATCH] autocommit 2022-04-17 17:59:45 CEST --- default-config/src/lib.rs | 22 ++-- src/cli.rs | 2 +- src/cli/idle.rs | 45 +++++--- src/compositor.rs | 4 + src/globals.rs | 16 ++- src/ifs.rs | 3 +- src/ifs/jay_compositor.rs | 3 +- src/ifs/jay_idle.rs | 13 +-- src/ifs/wl_compositor.rs | 6 +- src/ifs/wl_seat/kb_owner.rs | 6 +- src/ifs/wl_surface.rs | 30 +++-- src/ifs/wl_surface/xwindow.rs | 35 ++++-- src/ifs/wl_surface/zwp_idle_inhibitor_v1.rs | 82 +++++++++++++ src/ifs/zwp_idle_inhibit_manager_v1.rs | 122 ++++++++++++++++++++ src/macros.rs | 11 +- src/state.rs | 23 +++- src/tasks/idle.rs | 29 ++++- src/xwayland.rs | 12 +- src/xwayland/xwm.rs | 4 +- wire/zwp_idle_inhibit_manager_v1.txt | 8 ++ wire/zwp_idle_inhibitor_v1.txt | 3 + 21 files changed, 392 insertions(+), 87 deletions(-) create mode 100644 src/ifs/wl_surface/zwp_idle_inhibitor_v1.rs create mode 100644 src/ifs/zwp_idle_inhibit_manager_v1.rs create mode 100644 wire/zwp_idle_inhibit_manager_v1.txt create mode 100644 wire/zwp_idle_inhibitor_v1.txt diff --git a/default-config/src/lib.rs b/default-config/src/lib.rs index 5d6e4c74..54211b9f 100644 --- a/default-config/src/lib.rs +++ b/default-config/src/lib.rs @@ -12,10 +12,11 @@ use { keyboard::{ mods::{Modifiers, ALT, CTRL, SHIFT}, syms::{ - SYM_Super_L, SYM_b, SYM_c, SYM_d, SYM_f, SYM_h, SYM_j, SYM_k, SYM_l, SYM_m, SYM_p, - SYM_q, SYM_t, SYM_v, SYM_y, SYM_F1, SYM_F10, SYM_F11, SYM_F12, SYM_F13, SYM_F14, - SYM_F15, SYM_F16, SYM_F17, SYM_F18, SYM_F19, SYM_F2, SYM_F20, SYM_F21, SYM_F22, - SYM_F23, SYM_F24, SYM_F25, SYM_F3, SYM_F4, SYM_F5, SYM_F6, SYM_F7, SYM_F8, SYM_F9, + SYM_Super_L, SYM_a, SYM_b, SYM_c, SYM_d, SYM_e, SYM_f, SYM_h, SYM_j, SYM_k, SYM_l, + SYM_m, SYM_o, SYM_p, SYM_q, SYM_t, SYM_v, SYM_y, SYM_F1, SYM_F10, SYM_F11, SYM_F12, + SYM_F13, SYM_F14, SYM_F15, SYM_F16, SYM_F17, SYM_F18, SYM_F19, SYM_F2, SYM_F20, + SYM_F21, SYM_F22, SYM_F23, SYM_F24, SYM_F25, SYM_F3, SYM_F4, SYM_F5, SYM_F6, + SYM_F7, SYM_F8, SYM_F9, }, }, quit, set_env, @@ -27,7 +28,6 @@ use { }, std::time::Duration, }; -use jay_config::keyboard::syms::{SYM_a, SYM_e, SYM_o}; const MOD: Modifiers = ALT; @@ -78,9 +78,15 @@ fn configure_seat(s: Seat) { s.bind(MOD | sym, move || s.show_workspace(ws)); } - s.bind(MOD | SYM_a, || Command::new("spotify-remote").arg("a").spawn()); - s.bind(MOD | SYM_o, || Command::new("spotify-remote").arg("o").spawn()); - s.bind(MOD | SYM_e, || Command::new("spotify-remote").arg("e").spawn()); + s.bind(MOD | SYM_a, || { + Command::new("spotify-remote").arg("a").spawn() + }); + s.bind(MOD | SYM_o, || { + Command::new("spotify-remote").arg("o").spawn() + }); + s.bind(MOD | SYM_e, || { + Command::new("spotify-remote").arg("e").spawn() + }); fn do_grab(s: Seat, grab: bool) { for device in s.input_devices() { diff --git a/src/cli.rs b/src/cli.rs index 787e253f..130b8358 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,9 +1,9 @@ mod generate; +mod idle; mod log; mod quit; mod screenshot; mod set_log_level; -mod idle; use { crate::compositor::start_compositor, diff --git a/src/cli/idle.rs b/src/cli/idle.rs index 84080165..a64cdd3d 100644 --- a/src/cli/idle.rs +++ b/src/cli/idle.rs @@ -1,17 +1,16 @@ -use std::cell::Cell; -use std::collections::VecDeque; -use std::rc::Rc; -use std::str::FromStr; -use crate::cli::{GlobalArgs, IdleArgs, IdleCmd, IdleSetArgs}; -use crate::tools::tool_client::{Handle, ToolClient}; -use crate::utils::errorfmt::ErrorFmt; -use crate::wire::{jay_compositor, jay_idle, JayIdleId}; +use { + crate::{ + cli::{GlobalArgs, IdleArgs, IdleCmd, IdleSetArgs}, + tools::tool_client::{Handle, ToolClient}, + utils::errorfmt::ErrorFmt, + wire::{jay_compositor, jay_idle, JayIdleId}, + }, + std::{cell::Cell, collections::VecDeque, rc::Rc, str::FromStr}, +}; pub fn main(global: GlobalArgs, args: IdleArgs) { let tc = ToolClient::new(global.log_level.into()); - let idle = Idle { - tc: tc.clone(), - }; + let idle = Idle { tc: tc.clone() }; tc.run(idle.run(args)); } @@ -36,9 +35,7 @@ impl Idle { async fn status(self, idle: JayIdleId) { let tc = &self.tc; - tc.send(jay_idle::GetStatus { - self_id: idle, - }); + tc.send(jay_idle::GetStatus { self_id: idle }); let interval = Rc::new(Cell::new(0u64)); jay_idle::Interval::handle(tc, idle, interval.clone(), |iv, msg| { iv.set(msg.interval); @@ -65,15 +62,25 @@ impl Idle { let mut pending_num = None; for comp in comp { match comp { - Component::Number(_) if pending_num.is_some() => fatal!("missing number unit after {}", pending_num.unwrap()), + Component::Number(_) if pending_num.is_some() => { + fatal!("missing number unit after {}", pending_num.unwrap()) + } Component::Number(n) => pending_num = Some(n), - Component::Minutes(n) if pending_num.is_none() => fatal!("`{}` must be preceded by a number", n), - Component::Minutes(_) if minutes.is_some() => fatal!("minutes specified multiple times"), + Component::Minutes(n) if pending_num.is_none() => { + fatal!("`{}` must be preceded by a number", n) + } + Component::Minutes(_) if minutes.is_some() => { + fatal!("minutes specified multiple times") + } Component::Minutes(_) => minutes = pending_num.take(), - Component::Seconds(n) if pending_num.is_none() => fatal!("`{}` must be preceded by a number", n), - Component::Seconds(_) if seconds.is_some() => fatal!("seconds specified multiple times"), + Component::Seconds(n) if pending_num.is_none() => { + fatal!("`{}` must be preceded by a number", n) + } + Component::Seconds(_) if seconds.is_some() => { + fatal!("seconds specified multiple times") + } Component::Seconds(_) => seconds = pending_num.take(), } } diff --git a/src/compositor.rs b/src/compositor.rs index 5940d5bb..edd5149a 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -140,6 +140,8 @@ fn start_compositor2( change: Default::default(), timeout: Cell::new(Duration::from_secs(10 * 60)), timeout_changed: Default::default(), + inhibitors: Default::default(), + inhibitors_changed: Default::default(), }, run_args, xwayland: XWaylandState { @@ -149,6 +151,7 @@ fn start_compositor2( }, socket_path: Default::default(), serial: Default::default(), + idle_inhibitor_ids: Default::default(), }); create_dummy_output(&state); let socket_path = Acceptor::install(&state)?; @@ -176,6 +179,7 @@ async fn start_compositor3(state: Rc) { } }; state.backend.set(backend.clone()); + state.globals.add_singletons(&backend); if backend.is_freestanding() { import_environment(&state, WAYLAND_DISPLAY, &state.socket_path.get()); diff --git a/src/globals.rs b/src/globals.rs index e8c7834e..638c8425 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -1,5 +1,6 @@ use { crate::{ + backend::Backend, client::Client, ifs::{ ipc::{ @@ -17,6 +18,7 @@ use { wl_subcompositor::WlSubcompositorGlobal, xdg_wm_base::XdgWmBaseGlobal, zwlr_layer_shell_v1::ZwlrLayerShellV1Global, + zwp_idle_inhibit_manager_v1::ZwpIdleInhibitManagerV1Global, zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1Global, zxdg_decoration_manager_v1::ZxdgDecorationManagerV1Global, zxdg_output_manager_v1::ZxdgOutputManagerV1Global, @@ -102,15 +104,18 @@ pub struct Globals { impl Globals { pub fn new() -> Self { - let slf = Self { + Self { next_name: NumCell::new(1), registry: CopyHashMap::new(), outputs: Default::default(), seats: Default::default(), - }; + } + } + + pub fn add_singletons(&self, backend: &Rc) { macro_rules! add_singleton { ($name:ident) => { - slf.add_global_no_broadcast(&Rc::new($name::new(slf.name()))); + self.add_global_no_broadcast(&Rc::new($name::new(self.name()))); }; } add_singleton!(WlCompositorGlobal); @@ -126,7 +131,10 @@ impl Globals { add_singleton!(ZwlrLayerShellV1Global); add_singleton!(ZxdgOutputManagerV1Global); add_singleton!(JayCompositorGlobal); - slf + + if backend.supports_idle() { + add_singleton!(ZwpIdleInhibitManagerV1Global); + } } pub fn name(&self) -> GlobalName { diff --git a/src/ifs.rs b/src/ifs.rs index cde08a51..96064b88 100644 --- a/src/ifs.rs +++ b/src/ifs.rs @@ -1,5 +1,6 @@ pub mod ipc; pub mod jay_compositor; +pub mod jay_idle; pub mod jay_log_file; pub mod jay_screenshot; pub mod org_kde_kwin_server_decoration; @@ -20,10 +21,10 @@ pub mod wl_surface; pub mod xdg_positioner; pub mod xdg_wm_base; pub mod zwlr_layer_shell_v1; +pub mod zwp_idle_inhibit_manager_v1; pub mod zwp_linux_buffer_params_v1; pub mod zwp_linux_dmabuf_v1; pub mod zxdg_decoration_manager_v1; pub mod zxdg_output_manager_v1; pub mod zxdg_output_v1; pub mod zxdg_toplevel_decoration_v1; -pub mod jay_idle; diff --git a/src/ifs/jay_compositor.rs b/src/ifs/jay_compositor.rs index 3f4f0ffc..c2b9f20a 100644 --- a/src/ifs/jay_compositor.rs +++ b/src/ifs/jay_compositor.rs @@ -3,7 +3,7 @@ use { cli::CliLogLevel, client::{Client, ClientError}, globals::{Global, GlobalName}, - ifs::{jay_log_file::JayLogFile, jay_screenshot::JayScreenshot}, + ifs::{jay_idle::JayIdle, jay_log_file::JayLogFile, jay_screenshot::JayScreenshot}, leaks::Tracker, object::Object, screenshoter::take_screenshot, @@ -17,7 +17,6 @@ use { std::{ops::Deref, rc::Rc}, thiserror::Error, }; -use crate::ifs::jay_idle::JayIdle; pub struct JayCompositorGlobal { name: GlobalName, diff --git a/src/ifs/jay_idle.rs b/src/ifs/jay_idle.rs index 7e6d3716..d67d68de 100644 --- a/src/ifs/jay_idle.rs +++ b/src/ifs/jay_idle.rs @@ -1,17 +1,14 @@ -use std::time::Duration; -use thiserror::Error; use { crate::{ - client::Client, + client::{Client, ClientError}, leaks::Tracker, object::Object, - wire::{jay_idle::*}, + utils::buffd::{MsgParser, MsgParserError}, + wire::{jay_idle::*, JayIdleId}, }, - std::rc::Rc, + std::{rc::Rc, time::Duration}, + thiserror::Error, }; -use crate::client::ClientError; -use crate::utils::buffd::{MsgParser, MsgParserError}; -use crate::wire::JayIdleId; pub struct JayIdle { pub id: JayIdleId, diff --git a/src/ifs/wl_compositor.rs b/src/ifs/wl_compositor.rs index f6490270..cb32cdaa 100644 --- a/src/ifs/wl_compositor.rs +++ b/src/ifs/wl_compositor.rs @@ -54,7 +54,11 @@ impl WlCompositor { track!(self.client, surface); self.client.add_client_obj(&surface)?; if self.client.is_xwayland { - self.client.state.xwayland.queue.push(XWaylandEvent::SurfaceCreated(surface.clone())); + self.client + .state + .xwayland + .queue + .push(XWaylandEvent::SurfaceCreated(surface.clone())); } Ok(()) } diff --git a/src/ifs/wl_seat/kb_owner.rs b/src/ifs/wl_seat/kb_owner.rs index 3e71bd4b..258ad579 100644 --- a/src/ifs/wl_seat/kb_owner.rs +++ b/src/ifs/wl_seat/kb_owner.rs @@ -1,8 +1,10 @@ use { - crate::{ifs::wl_seat::WlSeatGlobal, tree::Node, utils::clonecell::CloneCell}, + crate::{ + ifs::wl_seat::WlSeatGlobal, tree::Node, utils::clonecell::CloneCell, + xwayland::XWaylandEvent, + }, std::rc::Rc, }; -use crate::xwayland::XWaylandEvent; pub struct KbOwnerHolder { default: Rc, diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index 668a6a8d..ba52ea2e 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -3,6 +3,7 @@ pub mod wl_subsurface; pub mod xdg_surface; pub mod xwindow; pub mod zwlr_layer_surface_v1; +pub mod zwp_idle_inhibitor_v1; use { crate::{ @@ -46,6 +47,7 @@ use { rc::Rc, }, thiserror::Error, + zwp_idle_inhibitor_v1::ZwpIdleInhibitorV1, }; #[allow(dead_code)] @@ -103,6 +105,7 @@ pub struct WlSurface { cursors: SmallMap, 1>, pub dnd_icons: SmallMap, 1>, pub tracker: Tracker, + idle_inhibitor: CloneCell>>, } impl Debug for WlSurface { @@ -200,25 +203,26 @@ impl WlSurface { id, node_id: client.state.node_ids.next(), client: client.clone(), - visible: Cell::new(false), + visible: Default::default(), role: Cell::new(SurfaceRole::None), pending: Default::default(), - input_region: Cell::new(None), - opaque_region: Cell::new(None), + input_region: Default::default(), + opaque_region: Default::default(), extents: Default::default(), buffer_abs_pos: Cell::new(Default::default()), - need_extents_update: Cell::new(false), - buffer: CloneCell::new(None), + need_extents_update: Default::default(), + buffer: Default::default(), buf_x: Default::default(), buf_y: Default::default(), children: Default::default(), ext: CloneCell::new(client.state.none_surface_ext.clone()), - frame_requests: RefCell::new(vec![]), + frame_requests: Default::default(), seat_state: Default::default(), toplevel: Default::default(), cursors: Default::default(), dnd_icons: Default::default(), tracker: Default::default(), + idle_inhibitor: Default::default(), } } @@ -367,7 +371,7 @@ impl WlSurface { self.unset_dnd_icons(); self.unset_cursors(); self.ext.get().on_surface_destroy()?; - self.node_destroy(true); + self.destroy_node(true); { let mut children = self.children.borrow_mut(); if let Some(children) = &mut *children { @@ -385,6 +389,7 @@ impl WlSurface { self.frame_requests.borrow_mut().clear(); self.toplevel.set(None); self.client.remove_obj(self)?; + self.idle_inhibitor.take(); Ok(()) } @@ -622,6 +627,7 @@ impl Object for WlSurface { mem::take(self.frame_requests.borrow_mut().deref_mut()); self.buffer.set(None); self.toplevel.set(None); + self.idle_inhibitor.take(); } } @@ -638,6 +644,9 @@ impl SizedNode for WlSurface { } fn destroy_node(&self, _detach: bool) { + if let Some(inhibitor) = self.idle_inhibitor.get() { + inhibitor.deactivate(); + } let children = self.children.borrow(); if let Some(ch) = children.deref() { for ss in ch.subsurfaces.values() { @@ -682,6 +691,13 @@ impl SizedNode for WlSurface { fn set_visible(&self, visible: bool) { self.visible.set(visible); + if let Some(inhibitor) = self.idle_inhibitor.get() { + if visible { + inhibitor.activate(); + } else { + inhibitor.deactivate(); + } + } let children = self.children.borrow_mut(); if let Some(children) = children.deref() { for child in children.subsurfaces.values() { diff --git a/src/ifs/wl_surface/xwindow.rs b/src/ifs/wl_surface/xwindow.rs index 4fa40e7b..aeed9127 100644 --- a/src/ifs/wl_surface/xwindow.rs +++ b/src/ifs/wl_surface/xwindow.rs @@ -203,10 +203,7 @@ pub enum Change { } impl Xwindow { - pub fn new( - data: &Rc, - surface: &Rc, - ) -> Self { + pub fn new(data: &Rc, surface: &Rc) -> Self { Self { id: data.state.node_ids.next(), seat_state: Default::default(), @@ -323,7 +320,11 @@ impl SurfaceExt for Xwindow { self.surface.unset_ext(); self.data.window.set(None); self.data.surface_id.set(None); - self.data.state.xwayland.queue.push(XWaylandEvent::SurfaceDestroyed(self.surface.id)); + self.data + .state + .xwayland + .queue + .push(XWaylandEvent::SurfaceDestroyed(self.surface.id)); Ok(()) } @@ -389,7 +390,11 @@ impl SizedNode for Xwindow { } fn close(&self) { - self.data.state.xwayland.queue.push(XWaylandEvent::Close(self.data.clone())); + self.data + .state + .xwayland + .queue + .push(XWaylandEvent::Close(self.data.clone())); } fn absolute_position(&self) -> Rect { @@ -427,7 +432,11 @@ impl SizedNode for Xwindow { let old = self.data.info.extents.replace(*rect); if old != *rect { if !self.data.info.override_redirect.get() { - self.data.state.xwayland.queue.push(XWaylandEvent::Configure(self.clone())); + self.data + .state + .xwayland + .queue + .push(XWaylandEvent::Configure(self.clone())); } if old.position() != rect.position() { self.surface.set_absolute_position(rect.x1(), rect.y1()); @@ -482,7 +491,11 @@ impl ToplevelNode for Xwindow { } fn activate(&self) { - self.data.state.xwayland.queue.push(XWaylandEvent::Activate(self.data.clone())); + self.data + .state + .xwayland + .queue + .push(XWaylandEvent::Activate(self.data.clone())); } fn toggle_floating(self: Rc) { @@ -503,7 +516,11 @@ impl ToplevelNode for Xwindow { } fn close(&self) { - self.data.state.xwayland.queue.push(XWaylandEvent::Close(self.data.clone())); + self.data + .state + .xwayland + .queue + .push(XWaylandEvent::Close(self.data.clone())); } } diff --git a/src/ifs/wl_surface/zwp_idle_inhibitor_v1.rs b/src/ifs/wl_surface/zwp_idle_inhibitor_v1.rs new file mode 100644 index 00000000..af8e6e18 --- /dev/null +++ b/src/ifs/wl_surface/zwp_idle_inhibitor_v1.rs @@ -0,0 +1,82 @@ +use { + crate::{ + client::{Client, ClientError}, + ifs::wl_surface::WlSurface, + leaks::Tracker, + object::Object, + utils::buffd::{MsgParser, MsgParserError}, + wire::{zwp_idle_inhibitor_v1::*, WlSurfaceId, ZwpIdleInhibitorV1Id}, + }, + std::rc::Rc, + thiserror::Error, +}; + +linear_ids!(IdleInhibitorIds, IdleInhibitorId, u64); + +pub struct ZwpIdleInhibitorV1 { + pub id: ZwpIdleInhibitorV1Id, + pub inhibit_id: IdleInhibitorId, + pub client: Rc, + pub surface: Rc, + pub tracker: Tracker, +} + +impl ZwpIdleInhibitorV1 { + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), ZwpIdleInhibitorV1Error> { + let _req: Destroy = self.client.parse(self, parser)?; + self.client.remove_obj(self)?; + if self.surface.idle_inhibitor.take().is_some() { + self.deactivate(); + } + Ok(()) + } + + pub fn install(self: &Rc) -> Result<(), ZwpIdleInhibitorV1Error> { + if self.surface.idle_inhibitor.get().is_some() { + return Err(ZwpIdleInhibitorV1Error::MultipleInhibitors(self.surface.id)); + } + self.surface.idle_inhibitor.set(Some(self.clone())); + if self.surface.visible.get() { + self.activate(); + } + Ok(()) + } + + pub fn activate(self: &Rc) { + self.client.state.idle.add_inhibitor(self); + } + + pub fn deactivate(&self) { + self.client.state.idle.remove_inhibitor(self); + } +} + +object_base2! { + ZwpIdleInhibitorV1; + + DESTROY => destroy, +} + +impl Object for ZwpIdleInhibitorV1 { + fn num_requests(&self) -> u32 { + DESTROY + 1 + } + + fn break_loops(&self) { + self.deactivate(); + } +} + +simple_add_obj!(ZwpIdleInhibitorV1); + +#[derive(Debug, Error)] +pub enum ZwpIdleInhibitorV1Error { + #[error("Parsing failed")] + MsgParserError(#[source] Box), + #[error(transparent)] + ClientError(Box), + #[error("The surface {0} already has an inhibitor attached")] + MultipleInhibitors(WlSurfaceId), +} +efrom!(ZwpIdleInhibitorV1Error, ClientError); +efrom!(ZwpIdleInhibitorV1Error, MsgParserError); diff --git a/src/ifs/zwp_idle_inhibit_manager_v1.rs b/src/ifs/zwp_idle_inhibit_manager_v1.rs new file mode 100644 index 00000000..ee7dd835 --- /dev/null +++ b/src/ifs/zwp_idle_inhibit_manager_v1.rs @@ -0,0 +1,122 @@ +use { + crate::{ + client::{Client, ClientError}, + globals::{Global, GlobalName}, + ifs::{ + wl_surface::zwp_idle_inhibitor_v1::{ZwpIdleInhibitorV1, ZwpIdleInhibitorV1Error}, + zxdg_decoration_manager_v1::ZxdgDecorationManagerV1Error, + }, + leaks::Tracker, + object::Object, + utils::buffd::{MsgParser, MsgParserError}, + wire::{zwp_idle_inhibit_manager_v1::*, ZwpIdleInhibitManagerV1Id}, + }, + std::rc::Rc, + thiserror::Error, +}; + +pub struct ZwpIdleInhibitManagerV1Global { + name: GlobalName, +} + +impl ZwpIdleInhibitManagerV1Global { + pub fn new(name: GlobalName) -> Self { + Self { name } + } + + fn bind_( + self: Rc, + id: ZwpIdleInhibitManagerV1Id, + client: &Rc, + version: u32, + ) -> Result<(), ZxdgDecorationManagerV1Error> { + let obj = Rc::new(ZwpIdleInhibitManagerV1 { + id, + client: client.clone(), + _version: version, + tracker: Default::default(), + }); + track!(client, obj); + client.add_client_obj(&obj)?; + Ok(()) + } +} + +global_base!( + ZwpIdleInhibitManagerV1Global, + ZwpIdleInhibitManagerV1, + ZwpIdleInhibitManagerV1Error +); + +impl Global for ZwpIdleInhibitManagerV1Global { + fn singleton(&self) -> bool { + true + } + + fn version(&self) -> u32 { + 1 + } +} + +simple_add_global!(ZwpIdleInhibitManagerV1Global); + +pub struct ZwpIdleInhibitManagerV1 { + pub id: ZwpIdleInhibitManagerV1Id, + pub client: Rc, + pub _version: u32, + pub tracker: Tracker, +} + +impl ZwpIdleInhibitManagerV1 { + pub fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), ZwpIdleInhibitManagerV1Error> { + let _req: Destroy = self.client.parse(self, parser)?; + self.client.remove_obj(self)?; + Ok(()) + } + + pub fn create_inhibitor( + &self, + parser: MsgParser<'_, '_>, + ) -> Result<(), ZwpIdleInhibitManagerV1Error> { + let req: CreateInhibitor = self.client.parse(self, parser)?; + let surface = self.client.lookup(req.surface)?; + let inhibit = Rc::new(ZwpIdleInhibitorV1 { + id: req.id, + inhibit_id: self.client.state.idle_inhibitor_ids.next(), + client: self.client.clone(), + surface, + tracker: Default::default(), + }); + track!(self.client, inhibit); + self.client.add_client_obj(&inhibit)?; + inhibit.install()?; + Ok(()) + } +} + +object_base2! { + ZwpIdleInhibitManagerV1; + + DESTROY => destroy, + CREATE_INHIBITOR => create_inhibitor, +} + +impl Object for ZwpIdleInhibitManagerV1 { + fn num_requests(&self) -> u32 { + CREATE_INHIBITOR + 1 + } +} + +simple_add_obj!(ZwpIdleInhibitManagerV1); + +#[derive(Debug, Error)] +pub enum ZwpIdleInhibitManagerV1Error { + #[error("Parsing failed")] + MsgParserError(#[source] Box), + #[error(transparent)] + ClientError(Box), + #[error(transparent)] + ZwpIdleInhibitorV1Error(#[from] ZwpIdleInhibitorV1Error), +} +efrom!(ZwpIdleInhibitManagerV1Error, ClientError); +efrom!(ZwpIdleInhibitManagerV1Error, MsgParserError); diff --git a/src/macros.rs b/src/macros.rs index c0e62d1a..05f9ccf3 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -180,8 +180,11 @@ macro_rules! id { macro_rules! linear_ids { ($ids:ident, $id:ident) => { + linear_ids!($ids, $id, u32); + }; + ($ids:ident, $id:ident, $ty:ty) => { pub struct $ids { - next: crate::utils::numcell::NumCell, + next: crate::utils::numcell::NumCell<$ty>, } impl Default for $ids { @@ -199,16 +202,16 @@ macro_rules! linear_ids { } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] - pub struct $id(u32); + pub struct $id($ty); impl $id { #[allow(dead_code)] - pub fn raw(&self) -> u32 { + pub fn raw(&self) -> $ty { self.0 } #[allow(dead_code)] - pub fn from_raw(id: u32) -> Self { + pub fn from_raw(id: $ty) -> Self { Self(id) } } diff --git a/src/state.rs b/src/state.rs index f80e9fc3..b7d55326 100644 --- a/src/state.rs +++ b/src/state.rs @@ -15,7 +15,10 @@ use { globals::{Globals, GlobalsError, WaylandGlobal}, ifs::{ wl_seat::{SeatIds, WlSeatGlobal}, - wl_surface::NoneSurfaceExt, + wl_surface::{ + zwp_idle_inhibitor_v1::{IdleInhibitorId, IdleInhibitorIds, ZwpIdleInhibitorV1}, + NoneSurfaceExt, + }, }, logger::Logger, rect::Rect, @@ -32,7 +35,7 @@ use { }, wheel::Wheel, xkbcommon::{XkbContext, XkbKeymap}, - xwayland, + xwayland::{self, XWaylandEvent}, }, ahash::AHashMap, jay_config::Direction, @@ -44,7 +47,6 @@ use { time::Duration, }, }; -use crate::xwayland::XWaylandEvent; pub struct State { pub xkb_ctx: XkbContext, @@ -60,6 +62,7 @@ pub struct State { pub globals: Globals, pub connector_ids: ConnectorIds, pub seat_ids: SeatIds, + pub idle_inhibitor_ids: IdleInhibitorIds, pub input_device_ids: InputDeviceIds, pub node_ids: NodeIds, pub root: Rc, @@ -101,6 +104,8 @@ pub struct IdleState { pub change: AsyncEvent, pub timeout: Cell, pub timeout_changed: Cell, + pub inhibitors: CopyHashMap>, + pub inhibitors_changed: Cell, } impl IdleState { @@ -109,6 +114,18 @@ impl IdleState { self.timeout_changed.set(true); self.change.trigger(); } + + pub fn add_inhibitor(&self, inhibitor: &Rc) { + self.inhibitors.set(inhibitor.inhibit_id, inhibitor.clone()); + self.inhibitors_changed.set(true); + self.change.trigger(); + } + + pub fn remove_inhibitor(&self, inhibitor: &ZwpIdleInhibitorV1) { + self.inhibitors.remove(&inhibitor.inhibit_id); + self.inhibitors_changed.set(true); + self.change.trigger(); + } } pub struct InputDeviceData { diff --git a/src/tasks/idle.rs b/src/tasks/idle.rs index 85724a50..334afcf4 100644 --- a/src/tasks/idle.rs +++ b/src/tasks/idle.rs @@ -29,6 +29,7 @@ pub async fn idle(state: Rc, backend: Rc) { timer, idle: false, dead: false, + is_inhibited: false, last_input: now(), }; idle.run().await; @@ -40,6 +41,7 @@ struct Idle { timer: Timer, idle: bool, dead: bool, + is_inhibited: bool, last_input: c::timespec, } @@ -63,28 +65,43 @@ impl Idle { let timeout = self.state.idle.timeout.get(); let since = duration_since(self.last_input); if since >= timeout { - self.backend.set_idle(true); - self.idle = true; + if !timeout.is_zero() && !self.is_inhibited { + self.backend.set_idle(true); + self.idle = true; + } } else { - self.program_timer(timeout - since); + self.program_timer2(timeout - since); } } fn handle_idle_changes(&mut self) { + if self.state.idle.inhibitors_changed.replace(false) { + let is_inhibited = self.state.idle.inhibitors.len() > 0; + if self.is_inhibited != is_inhibited { + self.is_inhibited = is_inhibited; + if !self.is_inhibited { + self.program_timer(); + } + } + } if self.state.idle.timeout_changed.replace(false) { - self.program_timer(self.state.idle.timeout.get()); + self.program_timer(); } if self.state.idle.input.replace(false) { self.last_input = now(); if self.idle { self.backend.set_idle(false); self.idle = false; - self.program_timer(self.state.idle.timeout.get()); + self.program_timer(); } } } - fn program_timer(&mut self, timeout: Duration) { + fn program_timer(&mut self) { + self.program_timer2(self.state.idle.timeout.get()); + } + + fn program_timer2(&mut self, timeout: Duration) { if let Err(e) = self.timer.program(Some(timeout), None) { log::error!("Could not program idle timer: {}", ErrorFmt(e)); self.dead = true; diff --git a/src/xwayland.rs b/src/xwayland.rs index e50f03e3..5b178f21 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -168,15 +168,9 @@ async fn run( Err(e) => return Err(XWaylandError::ExecFailed(e)), }; let client_id = state.clients.id(); - let client = state.clients.spawn2( - client_id, - state, - client1, - 9999, - 9999, - true, - true, - ); + let client = state + .clients + .spawn2(client_id, state, client1, 9999, 9999, true, true); let client = match client { Ok(c) => c, Err(e) => return Err(XWaylandError::SpawnClient(e)), diff --git a/src/xwayland/xwm.rs b/src/xwayland/xwm.rs index 2cf2b5f3..543b4196 100644 --- a/src/xwayland/xwm.rs +++ b/src/xwayland/xwm.rs @@ -8,9 +8,7 @@ use { rect::Rect, state::State, tree::{Node, SizedNode}, - utils::{ - bitflags::BitflagsExt, errorfmt::ErrorFmt, linkedlist::LinkedList, - }, + utils::{bitflags::BitflagsExt, errorfmt::ErrorFmt, linkedlist::LinkedList}, wire::WlSurfaceId, wire_xcon::{ ChangeProperty, ChangeWindowAttributes, ClientMessage, CompositeRedirectSubwindows, diff --git a/wire/zwp_idle_inhibit_manager_v1.txt b/wire/zwp_idle_inhibit_manager_v1.txt new file mode 100644 index 00000000..68981458 --- /dev/null +++ b/wire/zwp_idle_inhibit_manager_v1.txt @@ -0,0 +1,8 @@ +# requests + +msg destroy = 0 { } + +msg create_inhibitor = 1 { + id: id(zwp_idle_inhibitor_v1), + surface: id(wl_surface), +} diff --git a/wire/zwp_idle_inhibitor_v1.txt b/wire/zwp_idle_inhibitor_v1.txt new file mode 100644 index 00000000..ed027a17 --- /dev/null +++ b/wire/zwp_idle_inhibitor_v1.txt @@ -0,0 +1,3 @@ +# requests + +msg destroy = 0 { }