diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2024-03-19 14:41:17 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2024-03-19 18:29:13 +0400 |
| commit | 3963f537a4182dbcd8e1e2f262ee105473facc56 (patch) | |
| tree | 942f802863d1f8f63bbe68b53ab2d091e3c7dda9 /src | |
| parent | f31e105043a9fae0fae3dcfe0feb7ea1193d5f77 (diff) | |
| download | niri-3963f537a4182dbcd8e1e2f262ee105473facc56.tar.gz niri-3963f537a4182dbcd8e1e2f262ee105473facc56.tar.bz2 niri-3963f537a4182dbcd8e1e2f262ee105473facc56.zip | |
Wrap mapped windows in a Mapped
Diffstat (limited to 'src')
| -rw-r--r-- | src/handlers/compositor.rs | 35 | ||||
| -rw-r--r-- | src/handlers/mod.rs | 21 | ||||
| -rw-r--r-- | src/handlers/xdg_shell.rs | 25 | ||||
| -rw-r--r-- | src/input.rs | 25 | ||||
| -rw-r--r-- | src/layout/mod.rs | 177 | ||||
| -rw-r--r-- | src/layout/tile.rs | 4 | ||||
| -rw-r--r-- | src/layout/workspace.rs | 18 | ||||
| -rw-r--r-- | src/niri.rs | 32 | ||||
| -rw-r--r-- | src/protocols/foreign_toplevel.rs | 6 | ||||
| -rw-r--r-- | src/utils/mod.rs | 4 | ||||
| -rw-r--r-- | src/window/mapped.rs | 159 | ||||
| -rw-r--r-- | src/window/mod.rs | 3 |
12 files changed, 285 insertions, 224 deletions
diff --git a/src/handlers/compositor.rs b/src/handlers/compositor.rs index 52c5a193..188ba831 100644 --- a/src/handlers/compositor.rs +++ b/src/handlers/compositor.rs @@ -17,8 +17,7 @@ use smithay::wayland::shm::{ShmHandler, ShmState}; use smithay::{delegate_compositor, delegate_shm}; use crate::niri::{ClientState, State}; -use crate::utils::clone2; -use crate::window::{InitialConfigureState, Unmapped}; +use crate::window::{InitialConfigureState, Mapped, ResolvedWindowRules, Unmapped}; impl CompositorHandler for State { fn compositor_state(&mut self) -> &mut CompositorState { @@ -109,22 +108,22 @@ impl CompositorHandler for State { window.on_commit(); - let (width, is_full_width, output) = + let (rules, width, is_full_width, output) = if let InitialConfigureState::Configured { + rules, width, is_full_width, output, - .. } = state { // Check that the output is still connected. let output = output.filter(|o| self.niri.layout.monitor_for_output(o).is_some()); - (width, is_full_width, output) + (rules, width, is_full_width, output) } else { error!("window map must happen after initial configure"); - (None, false, None) + (ResolvedWindowRules::default(), None, false, None) }; let parent = window @@ -141,29 +140,30 @@ impl CompositorHandler for State { .filter(|(_, parent_output)| { output.is_none() || output.as_ref() == Some(*parent_output) }) - .map(|(window, _)| window.clone()); + .map(|(mapped, _)| mapped.window.clone()); - let window = window.clone(); - let win = window.clone(); + let mapped = Mapped::new(window, rules); + let window = mapped.window.clone(); let output = if let Some(p) = parent { // Open dialogs immediately to the right of their parent window. self.niri .layout - .add_window_right_of(&p, win, width, is_full_width) + .add_window_right_of(&p, mapped, width, is_full_width) } else if let Some(output) = &output { self.niri .layout - .add_window_on_output(output, win, width, is_full_width); + .add_window_on_output(output, mapped, width, is_full_width); Some(output) } else { - self.niri.layout.add_window(win, width, is_full_width) + self.niri.layout.add_window(mapped, width, is_full_width) }; if let Some(output) = output.cloned() { self.niri.layout.start_open_animation_for_window(&window); - let new_active_window = self.niri.layout.active_window().map(|(w, _)| w); + let new_active_window = + self.niri.layout.active_window().map(|(m, _)| &m.window); if new_active_window == Some(&window) { self.maybe_warp_cursor_to_focus(); } @@ -183,8 +183,9 @@ impl CompositorHandler for State { } // This is a commit of a previously-mapped root or a non-toplevel root. - if let Some(win_out) = self.niri.layout.find_window_and_output(surface) { - let (window, output) = clone2(win_out); + if let Some((mapped, output)) = self.niri.layout.find_window_and_output(surface) { + let window = mapped.window.clone(); + let output = output.clone(); window.on_commit(); @@ -224,7 +225,9 @@ impl CompositorHandler for State { // This is a commit of a non-root or a non-toplevel root. let root_window_output = self.niri.layout.find_window_and_output(&root_surface); - if let Some((window, output)) = root_window_output.map(clone2) { + if let Some((mapped, output)) = root_window_output { + let window = mapped.window.clone(); + let output = output.clone(); window.on_commit(); self.niri.layout.update_window(&window); self.niri.queue_redraw(output); diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index 4d3a606f..46ee79b6 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -144,7 +144,7 @@ impl InputMethodHandler for State { self.niri .layout .find_window_and_output(parent) - .map(|(window, _)| window.geometry()) + .map(|(mapped, _)| mapped.window.geometry()) .unwrap_or_default() } } @@ -333,25 +333,24 @@ impl ForeignToplevelHandler for State { } fn activate(&mut self, wl_surface: WlSurface) { - if let Some((window, _)) = self.niri.layout.find_window_and_output(&wl_surface) { - let window = window.clone(); + if let Some((mapped, _)) = self.niri.layout.find_window_and_output(&wl_surface) { + let window = mapped.window.clone(); self.niri.layout.activate_window(&window); self.niri.queue_redraw_all(); } } fn close(&mut self, wl_surface: WlSurface) { - if let Some((window, _)) = self.niri.layout.find_window_and_output(&wl_surface) { - window.toplevel().expect("no x11 support").send_close(); + if let Some((mapped, _)) = self.niri.layout.find_window_and_output(&wl_surface) { + mapped.toplevel().send_close(); } } fn set_fullscreen(&mut self, wl_surface: WlSurface, wl_output: Option<WlOutput>) { - if let Some((window, current_output)) = self.niri.layout.find_window_and_output(&wl_surface) + if let Some((mapped, current_output)) = self.niri.layout.find_window_and_output(&wl_surface) { - if !window + if !mapped .toplevel() - .expect("no x11 support") .current_state() .capabilities .contains(xdg_toplevel::WmCapabilities::Fullscreen) @@ -359,7 +358,7 @@ impl ForeignToplevelHandler for State { return; } - let window = window.clone(); + let window = mapped.window.clone(); if let Some(requested_output) = wl_output.as_ref().and_then(Output::from_resource) { if &requested_output != current_output { @@ -374,8 +373,8 @@ impl ForeignToplevelHandler for State { } fn unset_fullscreen(&mut self, wl_surface: WlSurface) { - if let Some((window, _)) = self.niri.layout.find_window_and_output(&wl_surface) { - let window = window.clone(); + if let Some((mapped, _)) = self.niri.layout.find_window_and_output(&wl_surface) { + let window = mapped.window.clone(); self.niri.layout.set_fullscreen(&window, false); } } diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs index 66c3dea4..4d31645c 100644 --- a/src/handlers/xdg_shell.rs +++ b/src/handlers/xdg_shell.rs @@ -29,7 +29,6 @@ use smithay::{ use crate::layout::workspace::ColumnWidth; use crate::niri::{PopupGrabState, State}; -use crate::utils::clone2; use crate::window::{InitialConfigureState, ResolvedWindowRules, Unmapped}; fn window_matches(role: &XdgToplevelSurfaceRoleAttributes, m: &Match) -> bool { @@ -213,9 +212,7 @@ impl XdgShellHandler for State { } let layout_focus = self.niri.layout.focus(); - if Some(&root) - != layout_focus.map(|win| win.toplevel().expect("no x11 support").wl_surface()) - { + if Some(&root) != layout_focus.map(|win| win.toplevel().wl_surface()) { let _ = PopupManager::dismiss_popup(&root, &popup); return; } @@ -278,12 +275,12 @@ impl XdgShellHandler for State { ) { let requested_output = wl_output.as_ref().and_then(Output::from_resource); - if let Some((window, current_output)) = self + if let Some((mapped, current_output)) = self .niri .layout .find_window_and_output(toplevel.wl_surface()) { - let window = window.clone(); + let window = mapped.window.clone(); if let Some(requested_output) = requested_output { if &requested_output != current_output { @@ -358,12 +355,12 @@ impl XdgShellHandler for State { } fn unfullscreen_request(&mut self, toplevel: ToplevelSurface) { - if let Some((window, _)) = self + if let Some((mapped, _)) = self .niri .layout .find_window_and_output(toplevel.wl_surface()) { - let window = window.clone(); + let window = mapped.window.clone(); self.niri.layout.set_fullscreen(&window, false); // A configure is required in response to this event regardless if there are pending @@ -453,14 +450,16 @@ impl XdgShellHandler for State { .layout .find_window_and_output(surface.wl_surface()); - let Some((window, output)) = win_out.map(clone2) else { + let Some((mapped, output)) = win_out else { // I have no idea how this can happen, but I saw it happen once, in a weird interaction // involving laptop going to sleep and resuming. error!("toplevel missing from both unmapped_windows and layout"); return; }; + let window = mapped.window.clone(); + let output = output.clone(); - let active_window = self.niri.layout.active_window().map(|(w, _)| w); + let active_window = self.niri.layout.active_window().map(|(m, _)| &m.window); let was_active = active_window == Some(&window); self.niri.layout.remove_window(&window); @@ -733,8 +732,8 @@ impl State { }; // Figure out if the root is a window or a layer surface. - if let Some((window, output)) = self.niri.layout.find_window_and_output(&root) { - self.unconstrain_window_popup(popup, window, output); + if let Some((mapped, output)) = self.niri.layout.find_window_and_output(&root) { + self.unconstrain_window_popup(popup, &mapped.window, output); } else if let Some((layer_surface, output)) = self.niri.layout.outputs().find_map(|o| { let map = layer_map_for_output(o); let layer_surface = map.layer_for_surface(&root, WindowSurfaceType::TOPLEVEL)?; @@ -814,6 +813,8 @@ impl State { if let InitialConfigureState::Configured { rules, .. } = &mut unmapped.state { *rules = resolve(); } + } else if let Some(mapped) = self.niri.layout.find_window_mut(toplevel.wl_surface()) { + mapped.rules = resolve(); } } } diff --git a/src/input.rs b/src/input.rs index 35a612bc..11a84878 100644 --- a/src/input.rs +++ b/src/input.rs @@ -379,21 +379,24 @@ impl State { } Action::ScreenshotWindow => { let active = self.niri.layout.active_window(); - if let Some((window, output)) = active { + if let Some((mapped, output)) = active { self.backend.with_primary_renderer(|renderer| { - if let Err(err) = self.niri.screenshot_window(renderer, output, window) { + if let Err(err) = + self.niri + .screenshot_window(renderer, output, &mapped.window) + { warn!("error taking screenshot: {err:?}"); } }); } } Action::CloseWindow => { - if let Some(window) = self.niri.layout.focus() { - window.toplevel().expect("no x11 support").send_close(); + if let Some(mapped) = self.niri.layout.focus() { + mapped.toplevel().send_close(); } } Action::FullscreenWindow => { - let focus = self.niri.layout.focus().cloned(); + let focus = self.niri.layout.focus().map(|m| m.window.clone()); if let Some(window) = focus { self.niri.layout.toggle_fullscreen(&window); // FIXME: granular @@ -1017,8 +1020,8 @@ impl State { let button_state = event.state(); if ButtonState::Pressed == button_state { - if let Some(window) = self.niri.window_under_cursor() { - let window = window.clone(); + if let Some(mapped) = self.niri.window_under_cursor() { + let window = mapped.window.clone(); self.niri.layout.activate_window(&window); // FIXME: granular. @@ -1177,8 +1180,8 @@ impl State { tool.tip_down(serial, event.time_msec()); if let Some(pos) = self.niri.tablet_cursor_location { - if let Some(window) = self.niri.window_under(pos) { - let window = window.clone(); + if let Some(mapped) = self.niri.window_under(pos) { + let window = mapped.window.clone(); self.niri.layout.activate_window(&window); // FIXME: granular. @@ -1535,8 +1538,8 @@ impl State { .output_under(touch_location) .next() .cloned(); - if let Some(window) = self.niri.window_under(touch_location) { - let window = window.clone(); + if let Some(mapped) = self.niri.window_under(touch_location) { + let window = mapped.window.clone(); self.niri.layout.activate_window(&window); // FIXME: granular. diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 24720435..86ce5c85 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -38,21 +38,14 @@ use niri_config::{CenterFocusedColumn, Config, Struts}; use niri_ipc::SizeChange; use smithay::backend::renderer::element::solid::SolidColorRenderElement; use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement; -use smithay::backend::renderer::element::{AsRenderElements, Id}; -use smithay::desktop::space::SpaceElement; -use smithay::desktop::Window; +use smithay::backend::renderer::element::Id; use smithay::output::Output; -use smithay::reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1; -use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel; use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; -use smithay::utils::{Logical, Point, Rectangle, Scale, Size, Transform}; -use smithay::wayland::compositor::{send_surface_state, with_states}; -use smithay::wayland::shell::xdg::SurfaceCachedState; +use smithay::utils::{Logical, Point, Scale, Size, Transform}; use self::monitor::Monitor; pub use self::monitor::MonitorRenderElement; use self::workspace::{compute_working_area, Column, ColumnWidth, OutputId, Workspace}; -use crate::niri::WindowOffscreenId; use crate::niri_render_elements; use crate::render_helpers::renderer::NiriRenderer; use crate::utils::output_size; @@ -229,148 +222,6 @@ impl Options { } } -impl LayoutElement for Window { - type Id = Self; - - fn id(&self) -> &Self::Id { - self - } - - fn size(&self) -> Size<i32, Logical> { - self.geometry().size - } - - fn buf_loc(&self) -> Point<i32, Logical> { - Point::from((0, 0)) - self.geometry().loc - } - - fn is_in_input_region(&self, point: Point<f64, Logical>) -> bool { - let surface_local = point + self.geometry().loc.to_f64(); - SpaceElement::is_in_input_region(self, &surface_local) - } - - fn render<R: NiriRenderer>( - &self, - renderer: &mut R, - location: Point<i32, Logical>, - scale: Scale<f64>, - ) -> Vec<LayoutElementRenderElement<R>> { - let buf_pos = location - self.geometry().loc; - self.render_elements( - renderer, - buf_pos.to_physical_precise_round(scale), - scale, - 1., - ) - } - - fn request_size(&self, size: Size<i32, Logical>) { - self.toplevel() - .expect("no x11 support") - .with_pending_state(|state| { - state.size = Some(size); - state.states.unset(xdg_toplevel::State::Fullscreen); - }); - } - - fn request_fullscreen(&self, size: Size<i32, Logical>) { - self.toplevel() - .expect("no x11 support") - .with_pending_state(|state| { - state.size = Some(size); - state.states.set(xdg_toplevel::State::Fullscreen); - }); - } - - fn min_size(&self) -> Size<i32, Logical> { - with_states( - self.toplevel().expect("no x11 support").wl_surface(), - |state| { - let curr = state.cached_state.current::<SurfaceCachedState>(); - curr.min_size - }, - ) - } - - fn max_size(&self) -> Size<i32, Logical> { - with_states( - self.toplevel().expect("no x11 support").wl_surface(), - |state| { - let curr = state.cached_state.current::<SurfaceCachedState>(); - curr.max_size - }, - ) - } - - fn is_wl_surface(&self, wl_surface: &WlSurface) -> bool { - self.toplevel().expect("no x11 support").wl_surface() == wl_surface - } - - fn set_preferred_scale_transform(&self, scale: i32, transform: Transform) { - self.with_surfaces(|surface, data| { - send_surface_state(surface, data, scale, transform); - }); - } - - fn has_ssd(&self) -> bool { - self.toplevel() - .expect("no x11 support") - .current_state() - .decoration_mode - == Some(zxdg_toplevel_decoration_v1::Mode::ServerSide) - } - - fn output_enter(&self, output: &Output) { - let overlap = Rectangle::from_loc_and_size((0, 0), (i32::MAX, i32::MAX)); - SpaceElement::output_enter(self, output, overlap) - } - - fn output_leave(&self, output: &Output) { - SpaceElement::output_leave(self, output) - } - - fn set_offscreen_element_id(&self, id: Option<Id>) { - let data = self.user_data().get_or_insert(WindowOffscreenId::default); - data.0.replace(id); - } - - fn set_activated(&self, active: bool) { - Window::set_activated(self, active); - } - - fn set_bounds(&self, bounds: Size<i32, Logical>) { - self.toplevel() - .expect("no x11 support") - .with_pending_state(|state| { - state.bounds = Some(bounds); - }); - } - - fn send_pending_configure(&self) { - self.toplevel() - .expect("no x11 support") - .send_pending_configure(); - } - - fn is_fullscreen(&self) -> bool { - self.toplevel() - .expect("no x11 support") - .current_state() - .states - .contains(xdg_toplevel::State::Fullscreen) - } - - fn is_pending_fullscreen(&self) -> bool { - self.toplevel() - .expect("no x11 support") - .with_pending_state(|state| state.states.contains(xdg_toplevel::State::Fullscreen)) - } - - fn refresh(&self) { - SpaceElement::refresh(self) - } -} - impl<W: LayoutElement> Layout<W> { pub fn new(config: &Config) -> Self { Self::with_options(Options::from_config(config)) @@ -792,6 +643,29 @@ impl<W: LayoutElement> Layout<W> { } } + pub fn find_window_mut(&mut self, wl_surface: &WlSurface) -> Option<&mut W> { + match &mut self.monitor_set { + MonitorSet::Normal { monitors, .. } => { + for mon in monitors { + for ws in &mut mon.workspaces { + if let Some(window) = ws.find_wl_surface_mut(wl_surface) { + return Some(window); + } + } + } + } + MonitorSet::NoOutputs { workspaces } => { + for ws in workspaces { + if let Some(window) = ws.find_wl_surface_mut(wl_surface) { + return Some(window); + } + } + } + } + + None + } + pub fn find_window_and_output(&self, wl_surface: &WlSurface) -> Option<(&W, &Output)> { if let MonitorSet::Normal { monitors, .. } = &self.monitor_set { for mon in monitors { @@ -1866,6 +1740,7 @@ mod tests { use proptest::prelude::*; use proptest_derive::Arbitrary; use smithay::output::{Mode, PhysicalProperties, Subpixel}; + use smithay::utils::Rectangle; use super::*; diff --git a/src/layout/tile.rs b/src/layout/tile.rs index 505a6ccd..589b2fc0 100644 --- a/src/layout/tile.rs +++ b/src/layout/tile.rs @@ -121,6 +121,10 @@ impl<W: LayoutElement> Tile<W> { &self.window } + pub fn window_mut(&mut self) -> &mut W { + &mut self.window + } + pub fn into_window(self) -> W { self.window } diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs index 9a0f10e5..03868dc0 100644 --- a/src/layout/workspace.rs +++ b/src/layout/workspace.rs @@ -10,6 +10,7 @@ use smithay::output::Output; use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel; use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; use smithay::utils::{Logical, Point, Rectangle, Scale, Size}; +use smithay::wayland::compositor::send_surface_state; use super::tile::{Tile, TileRenderElement}; use super::{LayoutElement, Options}; @@ -299,6 +300,13 @@ impl<W: LayoutElement> Workspace<W> { .map(Tile::window) } + pub fn windows_mut(&mut self) -> impl Iterator<Item = &mut W> + '_ { + self.columns + .iter_mut() + .flat_map(|col| col.tiles.iter_mut()) + .map(Tile::window_mut) + } + pub fn set_output(&mut self, output: Option<Output>) { if self.output == output { return; @@ -407,7 +415,11 @@ impl<W: LayoutElement> Workspace<W> { pub fn configure_new_window(&self, window: &Window, width: Option<ColumnWidth>) { if let Some(output) = self.output.as_ref() { - set_preferred_scale_transform(window, output); + let scale = output.current_scale().integer_scale(); + let transform = output.current_transform(); + window.with_surfaces(|surface, data| { + send_surface_state(surface, data, scale, transform); + }); } window @@ -584,6 +596,10 @@ impl<W: LayoutElement> Workspace<W> { self.windows().find(|win| win.is_wl_surface(wl_surface)) } + pub fn find_wl_surface_mut(&mut self, wl_surface: &WlSurface) -> Option<&mut W> { + self.windows_mut().find(|win| win.is_wl_surface(wl_surface)) + } + /// Computes the X position of the windows in the given column, in logical coordinates. fn column_x(&self, column_idx: usize) -> i32 { let mut x = 0; diff --git a/src/niri.rs b/src/niri.rs index b87ce915..13aa6409 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -114,7 +114,7 @@ use crate::utils::spawning::CHILD_ENV; use crate::utils::{ center, center_f64, get_monotonic_time, make_screenshot_path, output_size, write_png_rgba8, }; -use crate::window::Unmapped; +use crate::window::{Mapped, Unmapped}; use crate::{animation, niri_render_elements}; const CLEAR_COLOR: [f32; 4] = [0.2, 0.2, 0.2, 1.]; @@ -138,7 +138,7 @@ pub struct Niri { // Each workspace corresponds to a Space. Each workspace generally has one Output mapped to it, // however it may have none (when there are no outputs connected) or mutiple (when mirroring). - pub layout: Layout<Window>, + pub layout: Layout<Mapped>, // This space does not actually contain any windows, but all outputs are mapped into it // according to their global position. @@ -631,7 +631,7 @@ impl State { self.niri .layout .focus() - .map(|win| win.toplevel().expect("no x11 support").wl_surface().clone()) + .map(|win| win.toplevel().wl_surface().clone()) .map(|surface| KeyboardFocus::Layout { surface: Some(surface), }) @@ -1591,7 +1591,7 @@ impl Niri { /// /// The cursor may be inside the window's activation region, but not within the window's input /// region. - pub fn window_under(&self, pos: Point<f64, Logical>) -> Option<&Window> { + pub fn window_under(&self, pos: Point<f64, Logical>) -> Option<&Mapped> { if self.is_locked() || self.screenshot_ui.is_open() { return None; } @@ -1618,7 +1618,7 @@ impl Niri { /// /// The cursor may be inside the window's activation region, but not within the window's input /// region. - pub fn window_under_cursor(&self) -> Option<&Window> { + pub fn window_under_cursor(&self) -> Option<&Mapped> { let pos = self.seat.get_pointer().unwrap().current_location(); self.window_under(pos) } @@ -1684,8 +1684,9 @@ impl Niri { let window_under = || { self.layout .window_under(output, pos_within_output) - .and_then(|(window, win_pos_within_output)| { + .and_then(|(mapped, win_pos_within_output)| { let win_pos_within_output = win_pos_within_output?; + let window = &mapped.window; window .surface_under( pos_within_output - win_pos_within_output.to_f64(), @@ -2409,7 +2410,8 @@ impl Niri { // The reason to do this at all is that it keeps track of whether the surface is visible or // not in a unified way with the pointer surfaces, which makes the logic elsewhere simpler. - for win in self.layout.windows_for_output(output) { + for mapped in self.layout.windows_for_output(output) { + let win = &mapped.window; let offscreen_id = win .user_data() .get_or_insert(WindowOffscreenId::default) @@ -2480,8 +2482,8 @@ impl Niri { // We can unconditionally send the current output's feedback to regular and layer-shell // surfaces, as they can only be displayed on a single output at a time. Even if a surface // is currently invisible, this is the DMABUF feedback that it should know about. - for win in self.layout.windows_for_output(output) { - win.send_dmabuf_feedback( + for mapped in self.layout.windows_for_output(output) { + mapped.window.send_dmabuf_feedback( output, |_, _| Some(output.clone()), |surface, _| { @@ -2600,8 +2602,8 @@ impl Niri { let frame_callback_time = get_monotonic_time(); - for win in self.layout.windows_for_output(output) { - win.send_frame( + for mapped in self.layout.windows_for_output(output) { + mapped.window.send_frame( output, frame_callback_time, FRAME_CALLBACK_THROTTLE, @@ -2666,8 +2668,8 @@ impl Niri { let frame_callback_time = get_monotonic_time(); - self.layout.with_windows(|win, _| { - win.send_frame( + self.layout.with_windows(|mapped, _| { + mapped.window.send_frame( output, frame_callback_time, FRAME_CALLBACK_THROTTLE, @@ -2746,8 +2748,8 @@ impl Niri { ); } - for win in self.layout.windows_for_output(output) { - win.take_presentation_feedback( + for mapped in self.layout.windows_for_output(output) { + mapped.window.take_presentation_feedback( &mut feedback, surface_primary_scanout_output, |surface, _| { diff --git a/src/protocols/foreign_toplevel.rs b/src/protocols/foreign_toplevel.rs index 67dff830..af2be711 100644 --- a/src/protocols/foreign_toplevel.rs +++ b/src/protocols/foreign_toplevel.rs @@ -95,8 +95,8 @@ pub fn refresh(state: &mut State) { // Save the focused window for last, this way when the focus changes, we will first deactivate // the previous window and only then activate the newly focused window. let mut focused = None; - state.niri.layout.with_windows(|window, output| { - let wl_surface = window.toplevel().expect("no x11 support").wl_surface(); + state.niri.layout.with_windows(|mapped, output| { + let wl_surface = mapped.toplevel().wl_surface(); with_states(wl_surface, |states| { let role = states @@ -107,7 +107,7 @@ pub fn refresh(state: &mut State) { .unwrap(); if state.niri.keyboard_focus.surface() == Some(wl_surface) { - focused = Some((window.clone(), output.cloned())); + focused = Some((mapped.window.clone(), output.cloned())); } else { refresh_toplevel(protocol_state, wl_surface, &role, output, false); } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 4902bd3a..acd37b20 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -20,10 +20,6 @@ pub mod watcher; pub static IS_SYSTEMD_SERVICE: AtomicBool = AtomicBool::new(false); -pub fn clone2<T: Clone, U: Clone>(t: (&T, &U)) -> (T, U) { - (t.0.clone(), t.1.clone()) -} - pub fn version() -> String { format!( "{} ({})", diff --git a/src/window/mapped.rs b/src/window/mapped.rs new file mode 100644 index 00000000..4476dede --- /dev/null +++ b/src/window/mapped.rs @@ -0,0 +1,159 @@ +use smithay::backend::renderer::element::{AsRenderElements as _, Id}; +use smithay::desktop::space::SpaceElement as _; +use smithay::desktop::Window; +use smithay::output::Output; +use smithay::reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1; +use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel; +use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; +use smithay::utils::{Logical, Point, Rectangle, Scale, Size, Transform}; +use smithay::wayland::compositor::{send_surface_state, with_states}; +use smithay::wayland::shell::xdg::{SurfaceCachedState, ToplevelSurface}; + +use super::ResolvedWindowRules; +use crate::layout::{LayoutElement, LayoutElementRenderElement}; +use crate::niri::WindowOffscreenId; +use crate::render_helpers::renderer::NiriRenderer; + +#[derive(Debug)] +pub struct Mapped { + pub window: Window, + + /// Up-to-date rules. + pub rules: ResolvedWindowRules, +} + +impl Mapped { + pub fn new(window: Window, rules: ResolvedWindowRules) -> Self { + Self { window, rules } + } + + pub fn toplevel(&self) -> &ToplevelSurface { + self.window.toplevel().expect("no X11 support") + } +} + +impl LayoutElement for Mapped { + type Id = Window; + + fn id(&self) -> &Self::Id { + &self.window + } + + fn size(&self) -> Size<i32, Logical> { + self.window.geometry().size + } + + fn buf_loc(&self) -> Point<i32, Logical> { + Point::from((0, 0)) - self.window.geometry().loc + } + + fn is_in_input_region(&self, point: Point<f64, Logical>) -> bool { + let surface_local = point + self.window.geometry().loc.to_f64(); + self.window.is_in_input_region(&surface_local) + } + + fn render<R: NiriRenderer>( + &self, + renderer: &mut R, + location: Point<i32, Logical>, + scale: Scale<f64>, + ) -> Vec<LayoutElementRenderElement<R>> { + let buf_pos = location - self.window.geometry().loc; + self.window.render_elements( + renderer, + buf_pos.to_physical_precise_round(scale), + scale, + 1., + ) + } + + fn request_size(&self, size: Size<i32, Logical>) { + self.toplevel().with_pending_state(|state| { + state.size = Some(size); + state.states.unset(xdg_toplevel::State::Fullscreen); + } |
