mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-24 02:01:18 +07:00
Implement niri msg workspaces
This commit is contained in:
committed by
Ivan Molodetskikh
parent
a2f74c9bff
commit
36d3e70f11
@@ -31,6 +31,8 @@ pub enum Request {
|
|||||||
/// Configuration to apply.
|
/// Configuration to apply.
|
||||||
action: OutputAction,
|
action: OutputAction,
|
||||||
},
|
},
|
||||||
|
/// Request information about workspaces.
|
||||||
|
Workspaces,
|
||||||
/// Respond with an error (for testing error handling).
|
/// Respond with an error (for testing error handling).
|
||||||
ReturnError,
|
ReturnError,
|
||||||
}
|
}
|
||||||
@@ -60,6 +62,8 @@ pub enum Response {
|
|||||||
FocusedWindow(Option<Window>),
|
FocusedWindow(Option<Window>),
|
||||||
/// Output configuration change result.
|
/// Output configuration change result.
|
||||||
OutputConfigChanged(OutputConfigChanged),
|
OutputConfigChanged(OutputConfigChanged),
|
||||||
|
/// Information about workspaces.
|
||||||
|
Workspaces(Vec<Workspace>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Actions that niri can perform.
|
/// Actions that niri can perform.
|
||||||
@@ -484,6 +488,23 @@ pub enum OutputConfigChanged {
|
|||||||
OutputWasMissing,
|
OutputWasMissing,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A workspace.
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Workspace {
|
||||||
|
/// Index of the workspace on its monitor.
|
||||||
|
///
|
||||||
|
/// This is the same index you can use for requests like `niri msg action focus-workspace`.
|
||||||
|
pub idx: u8,
|
||||||
|
/// Optional name of the workspace.
|
||||||
|
pub name: Option<String>,
|
||||||
|
/// Name of the output that the workspace is on.
|
||||||
|
///
|
||||||
|
/// Can be `None` if no outputs are currently connected.
|
||||||
|
pub output: Option<String>,
|
||||||
|
/// Whether the workspace is currently active on its output.
|
||||||
|
pub is_active: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl FromStr for WorkspaceReferenceArg {
|
impl FromStr for WorkspaceReferenceArg {
|
||||||
type Err = &'static str;
|
type Err = &'static str;
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ pub enum Msg {
|
|||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
action: OutputAction,
|
action: OutputAction,
|
||||||
},
|
},
|
||||||
|
/// List workspaces.
|
||||||
|
Workspaces,
|
||||||
/// Request an error from the running niri instance.
|
/// Request an error from the running niri instance.
|
||||||
RequestError,
|
RequestError,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ pub fn handle_msg(msg: Msg, json: bool) -> anyhow::Result<()> {
|
|||||||
output: output.clone(),
|
output: output.clone(),
|
||||||
action: action.clone(),
|
action: action.clone(),
|
||||||
},
|
},
|
||||||
|
Msg::Workspaces => Request::Workspaces,
|
||||||
Msg::RequestError => Request::ReturnError,
|
Msg::RequestError => Request::ReturnError,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -260,6 +261,54 @@ pub fn handle_msg(msg: Msg, json: bool) -> anyhow::Result<()> {
|
|||||||
println!("The change will apply when it is connected.");
|
println!("The change will apply when it is connected.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Msg::Workspaces => {
|
||||||
|
let Response::Workspaces(mut response) = response else {
|
||||||
|
bail!("unexpected response: expected Workspaces, got {response:?}");
|
||||||
|
};
|
||||||
|
|
||||||
|
if json {
|
||||||
|
let response =
|
||||||
|
serde_json::to_string(&response).context("error formatting response")?;
|
||||||
|
println!("{response}");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if response.is_empty() {
|
||||||
|
println!("No workspaces.");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
response.sort_by_key(|ws| ws.idx);
|
||||||
|
response.sort_by(|a, b| a.output.cmp(&b.output));
|
||||||
|
|
||||||
|
let mut current_output = if let Some(output) = response[0].output.as_deref() {
|
||||||
|
println!("Output \"{output}\":");
|
||||||
|
Some(output)
|
||||||
|
} else {
|
||||||
|
println!("No output:");
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
for ws in &response {
|
||||||
|
if ws.output.as_deref() != current_output {
|
||||||
|
let output = ws.output.as_deref().context(
|
||||||
|
"invalid response: workspace with no output \
|
||||||
|
following a workspace with an output",
|
||||||
|
)?;
|
||||||
|
current_output = Some(output);
|
||||||
|
println!("\nOutput \"{output}\":");
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_active = if ws.is_active { " * " } else { " " };
|
||||||
|
let idx = ws.idx;
|
||||||
|
let name = if let Some(name) = ws.name.as_deref() {
|
||||||
|
format!(" \"{name}\"")
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
|
println!("{is_active}{idx}{name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -198,6 +198,16 @@ async fn process(ctx: &ClientCtx, request: Request) -> Reply {
|
|||||||
|
|
||||||
Response::OutputConfigChanged(response)
|
Response::OutputConfigChanged(response)
|
||||||
}
|
}
|
||||||
|
Request::Workspaces => {
|
||||||
|
let (tx, rx) = async_channel::bounded(1);
|
||||||
|
ctx.event_loop.insert_idle(move |state| {
|
||||||
|
let workspaces = state.niri.layout.ipc_workspaces();
|
||||||
|
let _ = tx.send_blocking(workspaces);
|
||||||
|
});
|
||||||
|
let result = rx.recv().await;
|
||||||
|
let workspaces = result.map_err(|_| String::from("error getting workspace info"))?;
|
||||||
|
Response::Workspaces(workspaces)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(response)
|
Ok(response)
|
||||||
|
|||||||
@@ -2278,6 +2278,41 @@ impl<W: LayoutElement> Layout<W> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ipc_workspaces(&self) -> Vec<niri_ipc::Workspace> {
|
||||||
|
match &self.monitor_set {
|
||||||
|
MonitorSet::Normal {
|
||||||
|
monitors,
|
||||||
|
primary_idx: _,
|
||||||
|
active_monitor_idx: _,
|
||||||
|
} => {
|
||||||
|
let mut workspaces = Vec::new();
|
||||||
|
|
||||||
|
for monitor in monitors {
|
||||||
|
for (idx, workspace) in monitor.workspaces.iter().enumerate() {
|
||||||
|
workspaces.push(niri_ipc::Workspace {
|
||||||
|
idx: u8::try_from(idx + 1).unwrap_or(u8::MAX),
|
||||||
|
name: workspace.name.clone(),
|
||||||
|
output: Some(monitor.output.name()),
|
||||||
|
is_active: monitor.active_workspace_idx == idx,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
workspaces
|
||||||
|
}
|
||||||
|
MonitorSet::NoOutputs { workspaces } => workspaces
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(idx, ws)| niri_ipc::Workspace {
|
||||||
|
idx: u8::try_from(idx + 1).unwrap_or(u8::MAX),
|
||||||
|
name: ws.name.clone(),
|
||||||
|
output: None,
|
||||||
|
is_active: false,
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: LayoutElement> Default for MonitorSet<W> {
|
impl<W: LayoutElement> Default for MonitorSet<W> {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use _server_decoration::server::org_kde_kwin_server_decoration_manager::Mode as
|
|||||||
use anyhow::{ensure, Context};
|
use anyhow::{ensure, Context};
|
||||||
use calloop::futures::Scheduler;
|
use calloop::futures::Scheduler;
|
||||||
use niri_config::{Config, Key, Modifiers, PreviewRender, TrackLayout, WorkspaceReference};
|
use niri_config::{Config, Key, Modifiers, PreviewRender, TrackLayout, WorkspaceReference};
|
||||||
|
use niri_ipc::Workspace;
|
||||||
use smithay::backend::allocator::Fourcc;
|
use smithay::backend::allocator::Fourcc;
|
||||||
use smithay::backend::renderer::damage::OutputDamageTracker;
|
use smithay::backend::renderer::damage::OutputDamageTracker;
|
||||||
use smithay::backend::renderer::element::memory::MemoryRenderBufferRenderElement;
|
use smithay::backend::renderer::element::memory::MemoryRenderBufferRenderElement;
|
||||||
@@ -3934,6 +3935,10 @@ impl Niri {
|
|||||||
self.queue_redraw_all();
|
self.queue_redraw_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ipc_workspaces(&self) -> Vec<Workspace> {
|
||||||
|
self.layout.ipc_workspaces()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ClientState {
|
pub struct ClientState {
|
||||||
|
|||||||
Reference in New Issue
Block a user