diff options
| author | Charlie Le <20309750+CharlieQLe@users.noreply.github.com> | 2025-05-09 11:01:01 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-09 18:01:01 +0300 |
| commit | 3cc67897afeabe6e0b1a6d035fde6f81010372d1 (patch) | |
| tree | c9cbf0f465885460700bfa2de1f3a57bda3f0055 | |
| parent | a99489c6c0e2ccf27825fd8ed1b68466c1eebb24 (diff) | |
| download | niri-3cc67897afeabe6e0b1a6d035fde6f81010372d1.tar.gz niri-3cc67897afeabe6e0b1a6d035fde6f81010372d1.tar.bz2 niri-3cc67897afeabe6e0b1a6d035fde6f81010372d1.zip | |
Implement IPC for the overview state (#1526)
* Implement IPC for the overview state
* Update Overview IPC to maintain naming consistency, renamed OverviewToggled to be more clear, simplify overview state request on the server, consolidate ipc refresh
* Fix Overview is_open in IPC client
* Change opened to is_open
* Update niri-ipc/src/lib.rs
Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com>
* Update niri-ipc/src/state.rs
Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com>
* Update src/ipc/client.rs
Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com>
* Update src/ipc/client.rs
Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com>
* Add overview state to EventStreamStatePart replicate and apply
* Fix formatting
* Rename Overview to OverviewState
---------
Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com>
| -rw-r--r-- | niri-ipc/src/lib.rs | 17 | ||||
| -rw-r--r-- | niri-ipc/src/state.rs | 30 | ||||
| -rw-r--r-- | src/cli.rs | 2 | ||||
| -rw-r--r-- | src/ipc/client.rs | 27 | ||||
| -rw-r--r-- | src/ipc/server.rs | 28 |
5 files changed, 101 insertions, 3 deletions
diff --git a/niri-ipc/src/lib.rs b/niri-ipc/src/lib.rs index 325cdef0..75d9a543 100644 --- a/niri-ipc/src/lib.rs +++ b/niri-ipc/src/lib.rs @@ -97,6 +97,8 @@ pub enum Request { EventStream, /// Respond with an error (for testing error handling). ReturnError, + /// Request information about the overview. + OverviewState, } /// Reply from niri to client. @@ -139,6 +141,16 @@ pub enum Response { PickedColor(Option<PickedColor>), /// Output configuration change result. OutputConfigChanged(OutputConfigChanged), + /// Information about the overview. + OverviewState(Overview), +} + +/// Overview information. +#[derive(Serialize, Deserialize, Debug, Clone)] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] +pub struct Overview { + /// Whether the overview is currently open. + pub is_open: bool, } /// Color picked from the screen. @@ -1269,6 +1281,11 @@ pub enum Event { /// Index of the newly active layout. idx: u8, }, + /// The overview was opened or closed. + OverviewOpenedOrClosed { + /// The new state of the overview. + is_open: bool, + }, } impl FromStr for WorkspaceReferenceArg { diff --git a/niri-ipc/src/state.rs b/niri-ipc/src/state.rs index 2ab58fc3..0689104d 100644 --- a/niri-ipc/src/state.rs +++ b/niri-ipc/src/state.rs @@ -40,6 +40,9 @@ pub struct EventStreamState { /// State of the keyboard layouts. pub keyboard_layouts: KeyboardLayoutsState, + + /// State of the overview. + pub overview: OverviewState, } /// The workspaces state communicated over the event stream. @@ -63,12 +66,20 @@ pub struct KeyboardLayoutsState { pub keyboard_layouts: Option<KeyboardLayouts>, } +/// The overview state communicated over the event stream. +#[derive(Debug, Default)] +pub struct OverviewState { + /// Whether the overview is currently open. + pub is_open: bool, +} + impl EventStreamStatePart for EventStreamState { fn replicate(&self) -> Vec<Event> { let mut events = Vec::new(); events.extend(self.workspaces.replicate()); events.extend(self.windows.replicate()); events.extend(self.keyboard_layouts.replicate()); + events.extend(self.overview.replicate()); events } @@ -76,6 +87,7 @@ impl EventStreamStatePart for EventStreamState { let event = self.workspaces.apply(event)?; let event = self.windows.apply(event)?; let event = self.keyboard_layouts.apply(event)?; + let event = self.overview.apply(event)?; Some(event) } } @@ -192,3 +204,21 @@ impl EventStreamStatePart for KeyboardLayoutsState { None } } + +impl EventStreamStatePart for OverviewState { + fn replicate(&self) -> Vec<Event> { + vec![Event::OverviewOpenedOrClosed { + is_open: self.is_open, + }] + } + + fn apply(&mut self, event: Event) -> Option<Event> { + match event { + Event::OverviewOpenedOrClosed { is_open } => { + self.is_open = is_open; + } + event => return Some(event), + } + None + } +} @@ -105,4 +105,6 @@ pub enum Msg { Version, /// Request an error from the running niri instance. RequestError, + /// Print the overview state. + OverviewState, } diff --git a/src/ipc/client.rs b/src/ipc/client.rs index d4165733..6f969703 100644 --- a/src/ipc/client.rs +++ b/src/ipc/client.rs @@ -5,8 +5,8 @@ use anyhow::{anyhow, bail, Context}; use niri_config::OutputName; use niri_ipc::socket::Socket; use niri_ipc::{ - Event, KeyboardLayouts, LogicalOutput, Mode, Output, OutputConfigChanged, Request, Response, - Transform, Window, + Event, KeyboardLayouts, LogicalOutput, Mode, Output, OutputConfigChanged, Overview, Request, + Response, Transform, Window, }; use serde_json::json; @@ -32,6 +32,7 @@ pub fn handle_msg(msg: Msg, json: bool) -> anyhow::Result<()> { Msg::KeyboardLayouts => Request::KeyboardLayouts, Msg::EventStream => Request::EventStream, Msg::RequestError => Request::ReturnError, + Msg::OverviewState => Request::OverviewState, }; let socket = Socket::connect().context("error connecting to the niri socket")?; @@ -435,9 +436,31 @@ pub fn handle_msg(msg: Msg, json: bool) -> anyhow::Result<()> { Event::KeyboardLayoutSwitched { idx } => { println!("Keyboard layout switched: {idx}"); } + Event::OverviewOpenedOrClosed { is_open: opened } => { + println!("Overview toggled: {opened}"); + } } } } + Msg::OverviewState => { + let Response::OverviewState(response) = response else { + bail!("unexpected response: expected Overview, got {response:?}"); + }; + + if json { + let response = + serde_json::to_string(&response).context("error formatting response")?; + println!("{response}"); + return Ok(()); + } + + let Overview { is_open } = response; + if is_open { + println!("Overview is open."); + } else { + println!("Overview is closed."); + } + } } Ok(()) diff --git a/src/ipc/server.rs b/src/ipc/server.rs index 2c948cac..06ff0fd1 100644 --- a/src/ipc/server.rs +++ b/src/ipc/server.rs @@ -16,7 +16,9 @@ use futures_util::io::{AsyncReadExt, BufReader}; use futures_util::{select_biased, AsyncBufReadExt, AsyncWrite, AsyncWriteExt, FutureExt as _}; use niri_config::OutputName; use niri_ipc::state::{EventStreamState, EventStreamStatePart as _}; -use niri_ipc::{Event, KeyboardLayouts, OutputConfigChanged, Reply, Request, Response, Workspace}; +use niri_ipc::{ + Event, KeyboardLayouts, OutputConfigChanged, Overview, Reply, Request, Response, Workspace, +}; use smithay::desktop::layer_map_for_output; use smithay::input::pointer::{ CursorIcon, CursorImageStatus, Focus, GrabStartData as PointerGrabStartData, @@ -428,6 +430,11 @@ async fn process(ctx: &ClientCtx, request: Request) -> Reply { Response::FocusedOutput(output) } Request::EventStream => Response::Handled, + Request::OverviewState => { + let state = ctx.event_stream_state.borrow(); + let is_open = state.overview.is_open; + Response::OverviewState(Overview { is_open }) + } }; Ok(response) @@ -524,6 +531,7 @@ impl State { pub fn ipc_refresh_layout(&mut self) { self.ipc_refresh_workspaces(); self.ipc_refresh_windows(); + self.ipc_refresh_overview(); } fn ipc_refresh_workspaces(&mut self) { @@ -690,4 +698,22 @@ impl State { server.send_event(event); } } + + pub fn ipc_refresh_overview(&mut self) { + let Some(server) = &self.niri.ipc_server else { + return; + }; + + let mut state = server.event_stream_state.borrow_mut(); + let state = &mut state.overview; + let is_open = self.niri.layout.is_overview_open(); + + if state.is_open == is_open { + return; + } + + let event = Event::OverviewOpenedOrClosed { is_open }; + state.apply(event.clone()); + server.send_event(event); + } } |
