aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlie Le <20309750+CharlieQLe@users.noreply.github.com>2025-05-09 11:01:01 -0400
committerGitHub <noreply@github.com>2025-05-09 18:01:01 +0300
commit3cc67897afeabe6e0b1a6d035fde6f81010372d1 (patch)
treec9cbf0f465885460700bfa2de1f3a57bda3f0055
parenta99489c6c0e2ccf27825fd8ed1b68466c1eebb24 (diff)
downloadniri-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.rs17
-rw-r--r--niri-ipc/src/state.rs30
-rw-r--r--src/cli.rs2
-rw-r--r--src/ipc/client.rs27
-rw-r--r--src/ipc/server.rs28
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
+ }
+}
diff --git a/src/cli.rs b/src/cli.rs
index ea8c422d..cb3cc0ab 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -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);
+ }
}