aboutsummaryrefslogtreecommitdiff
path: root/src/ipc
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-11-12 21:33:28 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2024-11-12 21:44:00 +0300
commit0e5e764c78421dc61c82ca6df630f33e8221005a (patch)
tree05599924f941d9dd04f5b19f96627e85229aba8e /src/ipc
parentdb1faecc9522dd4751344d3aa4e1d1e987dffc0c (diff)
downloadniri-0e5e764c78421dc61c82ca6df630f33e8221005a.tar.gz
niri-0e5e764c78421dc61c82ca6df630f33e8221005a.tar.bz2
niri-0e5e764c78421dc61c82ca6df630f33e8221005a.zip
Add niri msg layers
Diffstat (limited to 'src/ipc')
-rw-r--r--src/ipc/client.rs67
-rw-r--r--src/ipc/server.rs43
2 files changed, 110 insertions, 0 deletions
diff --git a/src/ipc/client.rs b/src/ipc/client.rs
index 112447f4..b2938b61 100644
--- a/src/ipc/client.rs
+++ b/src/ipc/client.rs
@@ -1,3 +1,6 @@
+use std::iter::Peekable;
+use std::slice;
+
use anyhow::{anyhow, bail, Context};
use niri_config::OutputName;
use niri_ipc::socket::Socket;
@@ -23,6 +26,7 @@ pub fn handle_msg(msg: Msg, json: bool) -> anyhow::Result<()> {
},
Msg::Workspaces => Request::Workspaces,
Msg::Windows => Request::Windows,
+ Msg::Layers => Request::Layers,
Msg::KeyboardLayouts => Request::KeyboardLayouts,
Msg::EventStream => Request::EventStream,
Msg::RequestError => Request::ReturnError,
@@ -168,6 +172,69 @@ pub fn handle_msg(msg: Msg, json: bool) -> anyhow::Result<()> {
println!();
}
}
+ Msg::Layers => {
+ let Response::Layers(mut layers) = response else {
+ bail!("unexpected response: expected Layers, got {response:?}");
+ };
+
+ if json {
+ let layers = serde_json::to_string(&layers).context("error formatting response")?;
+ println!("{layers}");
+ return Ok(());
+ }
+
+ layers.sort_by(|a, b| {
+ Ord::cmp(&a.output, &b.output)
+ .then_with(|| Ord::cmp(&a.layer, &b.layer))
+ .then_with(|| Ord::cmp(&a.namespace, &b.namespace))
+ });
+ let mut iter = layers.iter().peekable();
+
+ let print = |surface: &niri_ipc::LayerSurface| {
+ println!(" Surface:");
+ println!(" Namespace: \"{}\"", &surface.namespace);
+
+ let interactivity = match surface.keyboard_interactivity {
+ niri_ipc::LayerSurfaceKeyboardInteractivity::None => "none",
+ niri_ipc::LayerSurfaceKeyboardInteractivity::Exclusive => "exclusive",
+ niri_ipc::LayerSurfaceKeyboardInteractivity::OnDemand => "on-demand",
+ };
+ println!(" Keyboard interactivity: {interactivity}");
+ };
+
+ let print_layer = |iter: &mut Peekable<slice::Iter<niri_ipc::LayerSurface>>,
+ output: &str,
+ layer| {
+ let mut empty = true;
+ while let Some(surface) = iter.next_if(|s| s.output == output && s.layer == layer) {
+ empty = false;
+ println!();
+ print(surface);
+ }
+ if empty {
+ println!(" (empty)\n");
+ } else {
+ println!();
+ }
+ };
+
+ while let Some(surface) = iter.peek() {
+ let output = &surface.output;
+ println!("Output \"{output}\":");
+
+ print!(" Background layer:");
+ print_layer(&mut iter, output, niri_ipc::Layer::Background);
+
+ print!(" Bottom layer:");
+ print_layer(&mut iter, output, niri_ipc::Layer::Bottom);
+
+ print!(" Top layer:");
+ print_layer(&mut iter, output, niri_ipc::Layer::Top);
+
+ print!(" Overlay layer:");
+ print_layer(&mut iter, output, niri_ipc::Layer::Overlay);
+ }
+ }
Msg::FocusedOutput => {
let Response::FocusedOutput(output) = response else {
bail!("unexpected response: expected FocusedOutput, got {response:?}");
diff --git a/src/ipc/server.rs b/src/ipc/server.rs
index 91801028..16cc5524 100644
--- a/src/ipc/server.rs
+++ b/src/ipc/server.rs
@@ -16,9 +16,11 @@ use futures_util::{select_biased, AsyncBufReadExt, AsyncWrite, AsyncWriteExt, Fu
use niri_config::OutputName;
use niri_ipc::state::{EventStreamState, EventStreamStatePart as _};
use niri_ipc::{Event, KeyboardLayouts, OutputConfigChanged, Reply, Request, Response, Workspace};
+use smithay::desktop::layer_map_for_output;
use smithay::reexports::calloop::generic::Generic;
use smithay::reexports::calloop::{Interest, LoopHandle, Mode, PostAction};
use smithay::reexports::rustix::fs::unlink;
+use smithay::wayland::shell::wlr_layer::{KeyboardInteractivity, Layer};
use crate::backend::IpcOutputMap;
use crate::layout::workspace::WorkspaceId;
@@ -254,6 +256,47 @@ async fn process(ctx: &ClientCtx, request: Request) -> Reply {
let windows = state.windows.windows.values().cloned().collect();
Response::Windows(windows)
}
+ Request::Layers => {
+ let (tx, rx) = async_channel::bounded(1);
+ ctx.event_loop.insert_idle(move |state| {
+ let mut layers = Vec::new();
+ for output in state.niri.global_space.outputs() {
+ let name = output.name();
+ for surface in layer_map_for_output(output).layers() {
+ let layer = match surface.layer() {
+ Layer::Background => niri_ipc::Layer::Background,
+ Layer::Bottom => niri_ipc::Layer::Bottom,
+ Layer::Top => niri_ipc::Layer::Top,
+ Layer::Overlay => niri_ipc::Layer::Overlay,
+ };
+ let keyboard_interactivity =
+ match surface.cached_state().keyboard_interactivity {
+ KeyboardInteractivity::None => {
+ niri_ipc::LayerSurfaceKeyboardInteractivity::None
+ }
+ KeyboardInteractivity::Exclusive => {
+ niri_ipc::LayerSurfaceKeyboardInteractivity::Exclusive
+ }
+ KeyboardInteractivity::OnDemand => {
+ niri_ipc::LayerSurfaceKeyboardInteractivity::OnDemand
+ }
+ };
+
+ layers.push(niri_ipc::LayerSurface {
+ namespace: surface.namespace().to_owned(),
+ output: name.clone(),
+ layer,
+ keyboard_interactivity,
+ });
+ }
+ }
+
+ let _ = tx.send_blocking(layers);
+ });
+ let result = rx.recv().await;
+ let layers = result.map_err(|_| String::from("error getting layers info"))?;
+ Response::Layers(layers)
+ }
Request::KeyboardLayouts => {
let state = ctx.event_stream_state.borrow();
let layout = state.keyboard_layouts.keyboard_layouts.clone();