aboutsummaryrefslogtreecommitdiff
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
parentdb1faecc9522dd4751344d3aa4e1d1e987dffc0c (diff)
downloadniri-0e5e764c78421dc61c82ca6df630f33e8221005a.tar.gz
niri-0e5e764c78421dc61c82ca6df630f33e8221005a.tar.bz2
niri-0e5e764c78421dc61c82ca6df630f33e8221005a.zip
Add niri msg layers
-rw-r--r--niri-ipc/src/lib.rs44
-rw-r--r--src/cli.rs2
-rw-r--r--src/ipc/client.rs67
-rw-r--r--src/ipc/server.rs43
4 files changed, 156 insertions, 0 deletions
diff --git a/niri-ipc/src/lib.rs b/niri-ipc/src/lib.rs
index 900cc441..b4dad8df 100644
--- a/niri-ipc/src/lib.rs
+++ b/niri-ipc/src/lib.rs
@@ -55,6 +55,8 @@ pub enum Request {
Workspaces,
/// Request information about open windows.
Windows,
+ /// Request information about layer-shell surfaces.
+ Layers,
/// Request information about the configured keyboard layouts.
KeyboardLayouts,
/// Request information about the focused output.
@@ -119,6 +121,8 @@ pub enum Response {
Workspaces(Vec<Workspace>),
/// Information about open windows.
Windows(Vec<Window>),
+ /// Information about layer-shell surfaces.
+ Layers(Vec<LayerSurface>),
/// Information about the keyboard layout.
KeyboardLayouts(KeyboardLayouts),
/// Information about the focused output.
@@ -767,6 +771,46 @@ pub struct KeyboardLayouts {
pub current_idx: u8,
}
+/// A layer-shell layer.
+#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
+pub enum Layer {
+ /// The background layer.
+ Background,
+ /// The bottom layer.
+ Bottom,
+ /// The top layer.
+ Top,
+ /// The overlay layer.
+ Overlay,
+}
+
+/// Keyboard interactivity modes for a layer-shell surface.
+#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
+#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
+pub enum LayerSurfaceKeyboardInteractivity {
+ /// Surface cannot receive keyboard focus.
+ None,
+ /// Surface receives keyboard focus whenever possible.
+ Exclusive,
+ /// Surface receives keyboard focus on demand, e.g. when clicked.
+ OnDemand,
+}
+
+/// A layer-shell surface.
+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
+pub struct LayerSurface {
+ /// Namespace provided by the layer-shell client.
+ pub namespace: String,
+ /// Name of the output the surface is on.
+ pub output: String,
+ /// Layer that the surface is on.
+ pub layer: Layer,
+ /// The surface's keyboard interactivity mode.
+ pub keyboard_interactivity: LayerSurfaceKeyboardInteractivity,
+}
+
/// A compositor event.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
diff --git a/src/cli.rs b/src/cli.rs
index b260e6c3..041b0343 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -64,6 +64,8 @@ pub enum Msg {
Workspaces,
/// List open windows.
Windows,
+ /// List open layer-shell surfaces.
+ Layers,
/// Get the configured keyboard layouts.
KeyboardLayouts,
/// Print information about the focused output.
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();