diff options
Diffstat (limited to 'src/ipc')
| -rw-r--r-- | src/ipc/client.rs | 66 | ||||
| -rw-r--r-- | src/ipc/server.rs | 33 |
2 files changed, 93 insertions, 6 deletions
diff --git a/src/ipc/client.rs b/src/ipc/client.rs index 5ddefd3b..42fbbf75 100644 --- a/src/ipc/client.rs +++ b/src/ipc/client.rs @@ -7,7 +7,7 @@ use niri_config::OutputName; use niri_ipc::socket::Socket; use niri_ipc::{ Event, KeyboardLayouts, LogicalOutput, Mode, Output, OutputConfigChanged, Overview, Request, - Response, Transform, Window, + Response, Transform, Window, WindowLayout, }; use serde_json::json; @@ -447,6 +447,9 @@ pub fn handle_msg(msg: Msg, json: bool) -> anyhow::Result<()> { Event::WindowUrgencyChanged { id, urgent } => { println!("Window {id}: urgency changed to {urgent}"); } + Event::WindowLayoutsChanged { changes } => { + println!("Window layouts changed: {changes:?}"); + } Event::KeyboardLayoutsChanged { keyboard_layouts } => { println!("Keyboard layouts changed: {keyboard_layouts:?}"); } @@ -612,4 +615,65 @@ fn print_window(window: &Window) { } else { println!(" Workspace ID: (none)"); } + + let WindowLayout { + pos_in_scrolling_layout, + tile_size, + window_size, + tile_pos_in_workspace_view, + window_offset_in_tile, + } = window.layout; + + println!(" Layout:"); + println!( + " Tile size: {} x {}", + fmt_rounded(tile_size.0), + fmt_rounded(tile_size.1) + ); + + if let Some(pos) = pos_in_scrolling_layout { + println!(" Scrolling position: column {}, tile {}", pos.0, pos.1); + } + + if let Some(pos) = tile_pos_in_workspace_view { + println!( + " Workspace-view position: {}, {}", + fmt_rounded(pos.0), + fmt_rounded(pos.1) + ); + } + + println!(" Window size: {} x {}", window_size.0, window_size.1); + println!( + " Window offset in tile: {} x {}", + fmt_rounded(window_offset_in_tile.0), + fmt_rounded(window_offset_in_tile.1) + ); +} + +fn fmt_rounded(x: f64) -> String { + let r = x.round(); + if (r - x).abs() <= 0.005 { + format!("{r}") + } else { + format!("{x:.2}") + } +} + +#[cfg(test)] +mod tests { + use insta::assert_snapshot; + + use super::*; + + #[test] + fn test_fmt_rounded() { + assert_snapshot!(fmt_rounded(1.9), @"1.90"); + assert_snapshot!(fmt_rounded(1.994), @"1.99"); + assert_snapshot!(fmt_rounded(1.996), @"2"); + assert_snapshot!(fmt_rounded(2.0), @"2"); + assert_snapshot!(fmt_rounded(2.004), @"2"); + assert_snapshot!(fmt_rounded(2.006), @"2.01"); + assert_snapshot!(fmt_rounded(2.1), @"2.10"); + } } diff --git a/src/ipc/server.rs b/src/ipc/server.rs index cbcf3f67..464a2a13 100644 --- a/src/ipc/server.rs +++ b/src/ipc/server.rs @@ -17,7 +17,8 @@ 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, Overview, Reply, Request, Response, Workspace, + Event, KeyboardLayouts, OutputConfigChanged, Overview, Reply, Request, Response, WindowLayout, + Workspace, }; use smithay::desktop::layer_map_for_output; use smithay::input::pointer::{ @@ -477,7 +478,11 @@ async fn handle_event_stream_client(client: EventStreamClient) -> anyhow::Result Ok(()) } -fn make_ipc_window(mapped: &Mapped, workspace_id: Option<WorkspaceId>) -> niri_ipc::Window { +fn make_ipc_window( + mapped: &Mapped, + workspace_id: Option<WorkspaceId>, + layout: WindowLayout, +) -> niri_ipc::Window { with_toplevel_role(mapped.toplevel(), |role| niri_ipc::Window { id: mapped.id().get(), title: role.title.clone(), @@ -487,6 +492,7 @@ fn make_ipc_window(mapped: &Mapped, workspace_id: Option<WorkspaceId>) -> niri_i is_focused: mapped.is_focused(), is_floating: mapped.is_floating(), is_urgent: mapped.is_urgent(), + layout, }) } @@ -657,10 +663,12 @@ impl State { let mut events = Vec::new(); let layout = &self.niri.layout; + let mut batch_change_layouts: Vec<(u64, WindowLayout)> = Vec::new(); + // Check for window changes. let mut seen = HashSet::new(); let mut focused_id = None; - layout.with_windows(|mapped, _, ws_id| { + layout.with_windows(|mapped, _, ws_id, window_layout| { let id = mapped.id().get(); seen.insert(id); @@ -669,7 +677,7 @@ impl State { } let Some(ipc_win) = state.windows.get(&id) else { - let window = make_ipc_window(mapped, ws_id); + let window = make_ipc_window(mapped, ws_id, window_layout); events.push(Event::WindowOpenedOrChanged { window }); return; }; @@ -683,11 +691,15 @@ impl State { }); if changed { - let window = make_ipc_window(mapped, ws_id); + let window = make_ipc_window(mapped, ws_id, window_layout); events.push(Event::WindowOpenedOrChanged { window }); return; } + if ipc_win.layout != window_layout { + batch_change_layouts.push((id, window_layout)); + } + if mapped.is_focused() && !ipc_win.is_focused { events.push(Event::WindowFocusChanged { id: Some(id) }); } @@ -698,6 +710,17 @@ impl State { } }); + // It might make sense to push layout changes after closed windows (since windows about to + // be closed will occupy the same column/tile positions as the window that moved into this + // vacated space), but also we are already pushing some layout changes in + // WindowOpenedOrChanged above, meaning that the receiving end has to handle this case + // anyway. + if !batch_change_layouts.is_empty() { + events.push(Event::WindowLayoutsChanged { + changes: batch_change_layouts, + }); + } + // Check for closed windows. let mut ipc_focused_id = None; for (id, ipc_win) in &state.windows { |
