mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-24 02:01:18 +07:00
Implement window close transaction
Mainly visible with disabled animations.
This commit is contained in:
@@ -20,6 +20,7 @@ use smithay::{delegate_compositor, delegate_shm};
|
|||||||
use super::xdg_shell::add_mapped_toplevel_pre_commit_hook;
|
use super::xdg_shell::add_mapped_toplevel_pre_commit_hook;
|
||||||
use crate::niri::{ClientState, State};
|
use crate::niri::{ClientState, State};
|
||||||
use crate::utils::send_scale_transform;
|
use crate::utils::send_scale_transform;
|
||||||
|
use crate::utils::transaction::Transaction;
|
||||||
use crate::window::{InitialConfigureState, Mapped, ResolvedWindowRules, Unmapped};
|
use crate::window::{InitialConfigureState, Mapped, ResolvedWindowRules, Unmapped};
|
||||||
|
|
||||||
impl CompositorHandler for State {
|
impl CompositorHandler for State {
|
||||||
@@ -193,11 +194,13 @@ impl CompositorHandler for State {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Must start the close animation before window.on_commit().
|
// Must start the close animation before window.on_commit().
|
||||||
|
let transaction = Transaction::new();
|
||||||
if !is_mapped {
|
if !is_mapped {
|
||||||
|
let blocker = transaction.blocker();
|
||||||
self.backend.with_primary_renderer(|renderer| {
|
self.backend.with_primary_renderer(|renderer| {
|
||||||
self.niri
|
self.niri
|
||||||
.layout
|
.layout
|
||||||
.start_close_animation_for_window(renderer, &window);
|
.start_close_animation_for_window(renderer, &window, blocker);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +219,7 @@ impl CompositorHandler for State {
|
|||||||
id: u64::from(id.get()),
|
id: u64::from(id.get()),
|
||||||
});
|
});
|
||||||
|
|
||||||
self.niri.layout.remove_window(&window);
|
self.niri.layout.remove_window(&window, transaction);
|
||||||
self.add_default_dmabuf_pre_commit_hook(surface);
|
self.add_default_dmabuf_pre_commit_hook(surface);
|
||||||
|
|
||||||
if was_active {
|
if was_active {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ use crate::input::resize_grab::ResizeGrab;
|
|||||||
use crate::input::DOUBLE_CLICK_TIME;
|
use crate::input::DOUBLE_CLICK_TIME;
|
||||||
use crate::layout::workspace::ColumnWidth;
|
use crate::layout::workspace::ColumnWidth;
|
||||||
use crate::niri::{PopupGrabState, State};
|
use crate::niri::{PopupGrabState, State};
|
||||||
|
use crate::utils::transaction::Transaction;
|
||||||
use crate::utils::{get_monotonic_time, send_scale_transform, ResizeEdge};
|
use crate::utils::{get_monotonic_time, send_scale_transform, ResizeEdge};
|
||||||
use crate::window::{InitialConfigureState, ResolvedWindowRules, Unmapped, WindowRef};
|
use crate::window::{InitialConfigureState, ResolvedWindowRules, Unmapped, WindowRef};
|
||||||
|
|
||||||
@@ -485,16 +486,19 @@ impl XdgShellHandler for State {
|
|||||||
self.backend.with_primary_renderer(|renderer| {
|
self.backend.with_primary_renderer(|renderer| {
|
||||||
self.niri.layout.store_unmap_snapshot(renderer, &window);
|
self.niri.layout.store_unmap_snapshot(renderer, &window);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let transaction = Transaction::new();
|
||||||
|
let blocker = transaction.blocker();
|
||||||
self.backend.with_primary_renderer(|renderer| {
|
self.backend.with_primary_renderer(|renderer| {
|
||||||
self.niri
|
self.niri
|
||||||
.layout
|
.layout
|
||||||
.start_close_animation_for_window(renderer, &window);
|
.start_close_animation_for_window(renderer, &window, blocker);
|
||||||
});
|
});
|
||||||
|
|
||||||
let active_window = self.niri.layout.active_window().map(|(m, _)| &m.window);
|
let active_window = self.niri.layout.active_window().map(|(m, _)| &m.window);
|
||||||
let was_active = active_window == Some(&window);
|
let was_active = active_window == Some(&window);
|
||||||
|
|
||||||
self.niri.layout.remove_window(&window);
|
self.niri.layout.remove_window(&window, transaction);
|
||||||
self.add_default_dmabuf_pre_commit_hook(surface.wl_surface());
|
self.add_default_dmabuf_pre_commit_hook(surface.wl_surface());
|
||||||
|
|
||||||
if was_active {
|
if was_active {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use smithay::backend::renderer::element::{Kind, RenderElement};
|
|||||||
use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture, Uniform};
|
use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture, Uniform};
|
||||||
use smithay::backend::renderer::Texture;
|
use smithay::backend::renderer::Texture;
|
||||||
use smithay::utils::{Logical, Point, Rectangle, Scale, Size, Transform};
|
use smithay::utils::{Logical, Point, Rectangle, Scale, Size, Transform};
|
||||||
|
use smithay::wayland::compositor::{Blocker, BlockerState};
|
||||||
|
|
||||||
use crate::animation::Animation;
|
use crate::animation::Animation;
|
||||||
use crate::niri_render_elements;
|
use crate::niri_render_elements;
|
||||||
@@ -21,6 +22,7 @@ use crate::render_helpers::shaders::{mat3_uniform, ProgramType, Shaders};
|
|||||||
use crate::render_helpers::snapshot::RenderSnapshot;
|
use crate::render_helpers::snapshot::RenderSnapshot;
|
||||||
use crate::render_helpers::texture::{TextureBuffer, TextureRenderElement};
|
use crate::render_helpers::texture::{TextureBuffer, TextureRenderElement};
|
||||||
use crate::render_helpers::{render_to_encompassing_texture, RenderTarget};
|
use crate::render_helpers::{render_to_encompassing_texture, RenderTarget};
|
||||||
|
use crate::utils::transaction::TransactionBlocker;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ClosingWindow {
|
pub struct ClosingWindow {
|
||||||
@@ -46,7 +48,7 @@ pub struct ClosingWindow {
|
|||||||
blocked_out_buffer_offset: Point<f64, Logical>,
|
blocked_out_buffer_offset: Point<f64, Logical>,
|
||||||
|
|
||||||
/// The closing animation.
|
/// The closing animation.
|
||||||
anim: Animation,
|
anim_state: AnimationState,
|
||||||
|
|
||||||
/// Random seed for the shader.
|
/// Random seed for the shader.
|
||||||
random_seed: f32,
|
random_seed: f32,
|
||||||
@@ -59,6 +61,29 @@ niri_render_elements! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum AnimationState {
|
||||||
|
Waiting {
|
||||||
|
/// Blocker for a transaction before starting the animation.
|
||||||
|
blocker: TransactionBlocker,
|
||||||
|
anim: Animation,
|
||||||
|
},
|
||||||
|
Animating(Animation),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnimationState {
|
||||||
|
pub fn new(blocker: TransactionBlocker, anim: Animation) -> Self {
|
||||||
|
if blocker.state() == BlockerState::Pending {
|
||||||
|
Self::Waiting { blocker, anim }
|
||||||
|
} else {
|
||||||
|
// This actually doesn't normally happen because the window is removed only after the
|
||||||
|
// closing animation is created. Though, it does happen with disable-transactions debug
|
||||||
|
// flag.
|
||||||
|
Self::Animating(anim)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ClosingWindow {
|
impl ClosingWindow {
|
||||||
pub fn new<E: RenderElement<GlesRenderer>>(
|
pub fn new<E: RenderElement<GlesRenderer>>(
|
||||||
renderer: &mut GlesRenderer,
|
renderer: &mut GlesRenderer,
|
||||||
@@ -66,6 +91,7 @@ impl ClosingWindow {
|
|||||||
scale: Scale<f64>,
|
scale: Scale<f64>,
|
||||||
geo_size: Size<f64, Logical>,
|
geo_size: Size<f64, Logical>,
|
||||||
pos: Point<f64, Logical>,
|
pos: Point<f64, Logical>,
|
||||||
|
blocker: TransactionBlocker,
|
||||||
anim: Animation,
|
anim: Animation,
|
||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Self> {
|
||||||
let _span = tracy_client::span!("ClosingWindow::new");
|
let _span = tracy_client::span!("ClosingWindow::new");
|
||||||
@@ -107,17 +133,29 @@ impl ClosingWindow {
|
|||||||
pos,
|
pos,
|
||||||
buffer_offset,
|
buffer_offset,
|
||||||
blocked_out_buffer_offset,
|
blocked_out_buffer_offset,
|
||||||
anim,
|
anim_state: AnimationState::new(blocker, anim),
|
||||||
random_seed: fastrand::f32(),
|
random_seed: fastrand::f32(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn advance_animations(&mut self, current_time: Duration) {
|
pub fn advance_animations(&mut self, current_time: Duration) {
|
||||||
self.anim.set_current_time(current_time);
|
match &mut self.anim_state {
|
||||||
|
AnimationState::Waiting { blocker, anim } => {
|
||||||
|
if blocker.state() != BlockerState::Pending {
|
||||||
|
let mut anim = anim.restarted(0., 1., 0.);
|
||||||
|
anim.set_current_time(current_time);
|
||||||
|
self.anim_state = AnimationState::Animating(anim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnimationState::Animating(anim) => anim.set_current_time(current_time),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn are_animations_ongoing(&self) -> bool {
|
pub fn are_animations_ongoing(&self) -> bool {
|
||||||
!self.anim.is_done()
|
match &self.anim_state {
|
||||||
|
AnimationState::Waiting { .. } => true,
|
||||||
|
AnimationState::Animating(anim) => !anim.is_done(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(
|
pub fn render(
|
||||||
@@ -127,15 +165,42 @@ impl ClosingWindow {
|
|||||||
scale: Scale<f64>,
|
scale: Scale<f64>,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
) -> ClosingWindowRenderElement {
|
) -> ClosingWindowRenderElement {
|
||||||
let progress = self.anim.value();
|
|
||||||
let clamped_progress = self.anim.clamped_value().clamp(0., 1.);
|
|
||||||
|
|
||||||
let (buffer, offset) = if target.should_block_out(self.block_out_from) {
|
let (buffer, offset) = if target.should_block_out(self.block_out_from) {
|
||||||
(&self.blocked_out_buffer, self.blocked_out_buffer_offset)
|
(&self.blocked_out_buffer, self.blocked_out_buffer_offset)
|
||||||
} else {
|
} else {
|
||||||
(&self.buffer, self.buffer_offset)
|
(&self.buffer, self.buffer_offset)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let anim = match &self.anim_state {
|
||||||
|
AnimationState::Waiting { .. } => {
|
||||||
|
let elem = TextureRenderElement::from_texture_buffer(
|
||||||
|
buffer.clone(),
|
||||||
|
Point::from((0., 0.)),
|
||||||
|
1.,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Kind::Unspecified,
|
||||||
|
);
|
||||||
|
|
||||||
|
let elem = PrimaryGpuTextureRenderElement(elem);
|
||||||
|
let elem = RescaleRenderElement::from_element(elem, Point::from((0, 0)), 1.);
|
||||||
|
|
||||||
|
let mut location = self.pos + offset;
|
||||||
|
location.x -= view_rect.loc.x;
|
||||||
|
let elem = RelocateRenderElement::from_element(
|
||||||
|
elem,
|
||||||
|
location.to_physical_precise_round(scale),
|
||||||
|
Relocate::Relative,
|
||||||
|
);
|
||||||
|
|
||||||
|
return elem.into();
|
||||||
|
}
|
||||||
|
AnimationState::Animating(anim) => anim,
|
||||||
|
};
|
||||||
|
|
||||||
|
let progress = anim.value();
|
||||||
|
let clamped_progress = anim.clamped_value().clamp(0., 1.);
|
||||||
|
|
||||||
if Shaders::get(renderer).program(ProgramType::Close).is_some() {
|
if Shaders::get(renderer).program(ProgramType::Close).is_some() {
|
||||||
let area_loc = Vec2::new(view_rect.loc.x as f32, view_rect.loc.y as f32);
|
let area_loc = Vec2::new(view_rect.loc.x as f32, view_rect.loc.y as f32);
|
||||||
let area_size = Vec2::new(view_rect.size.w as f32, view_rect.size.h as f32);
|
let area_size = Vec2::new(view_rect.size.w as f32, view_rect.size.h as f32);
|
||||||
|
|||||||
+18
-14
@@ -52,7 +52,7 @@ use crate::render_helpers::snapshot::RenderSnapshot;
|
|||||||
use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement};
|
use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement};
|
||||||
use crate::render_helpers::texture::TextureBuffer;
|
use crate::render_helpers::texture::TextureBuffer;
|
||||||
use crate::render_helpers::{BakedBuffer, RenderTarget, SplitElements};
|
use crate::render_helpers::{BakedBuffer, RenderTarget, SplitElements};
|
||||||
use crate::utils::transaction::Transaction;
|
use crate::utils::transaction::{Transaction, TransactionBlocker};
|
||||||
use crate::utils::{output_size, round_logical_in_physical_max1, ResizeEdge};
|
use crate::utils::{output_size, round_logical_in_physical_max1, ResizeEdge};
|
||||||
use crate::window::ResolvedWindowRules;
|
use crate::window::ResolvedWindowRules;
|
||||||
|
|
||||||
@@ -752,15 +752,13 @@ impl<W: LayoutElement> Layout<W> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_window(&mut self, window: &W::Id) -> Option<W> {
|
pub fn remove_window(&mut self, window: &W::Id, transaction: Transaction) -> Option<W> {
|
||||||
let mut rv = None;
|
|
||||||
|
|
||||||
match &mut self.monitor_set {
|
match &mut self.monitor_set {
|
||||||
MonitorSet::Normal { monitors, .. } => {
|
MonitorSet::Normal { monitors, .. } => {
|
||||||
for mon in monitors {
|
for mon in monitors {
|
||||||
for (idx, ws) in mon.workspaces.iter_mut().enumerate() {
|
for (idx, ws) in mon.workspaces.iter_mut().enumerate() {
|
||||||
if ws.has_window(window) {
|
if ws.has_window(window) {
|
||||||
rv = Some(ws.remove_window(window));
|
let win = ws.remove_window(window, transaction);
|
||||||
|
|
||||||
// Clean up empty workspaces that are not active and not last.
|
// Clean up empty workspaces that are not active and not last.
|
||||||
if !ws.has_windows()
|
if !ws.has_windows()
|
||||||
@@ -776,7 +774,7 @@ impl<W: LayoutElement> Layout<W> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
return Some(win);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -784,20 +782,20 @@ impl<W: LayoutElement> Layout<W> {
|
|||||||
MonitorSet::NoOutputs { workspaces, .. } => {
|
MonitorSet::NoOutputs { workspaces, .. } => {
|
||||||
for (idx, ws) in workspaces.iter_mut().enumerate() {
|
for (idx, ws) in workspaces.iter_mut().enumerate() {
|
||||||
if ws.has_window(window) {
|
if ws.has_window(window) {
|
||||||
rv = Some(ws.remove_window(window));
|
let win = ws.remove_window(window, transaction);
|
||||||
|
|
||||||
// Clean up empty workspaces.
|
// Clean up empty workspaces.
|
||||||
if !ws.has_windows() && workspaces[idx].name.is_none() {
|
if !ws.has_windows() && workspaces[idx].name.is_none() {
|
||||||
workspaces.remove(idx);
|
workspaces.remove(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
return Some(win);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rv
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_window(&mut self, window: &W::Id, serial: Option<Serial>) {
|
pub fn update_window(&mut self, window: &W::Id, serial: Option<Serial>) {
|
||||||
@@ -1970,7 +1968,12 @@ impl<W: LayoutElement> Layout<W> {
|
|||||||
let width = column.width;
|
let width = column.width;
|
||||||
let is_full_width = column.is_full_width;
|
let is_full_width = column.is_full_width;
|
||||||
let window = ws
|
let window = ws
|
||||||
.remove_tile_by_idx(ws.active_column_idx, column.active_tile_idx, None)
|
.remove_tile_by_idx(
|
||||||
|
ws.active_column_idx,
|
||||||
|
column.active_tile_idx,
|
||||||
|
Transaction::new(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
.into_window();
|
.into_window();
|
||||||
|
|
||||||
let workspace_idx = monitors[new_idx].active_workspace_idx;
|
let workspace_idx = monitors[new_idx].active_workspace_idx;
|
||||||
@@ -2022,7 +2025,7 @@ impl<W: LayoutElement> Layout<W> {
|
|||||||
|
|
||||||
let Some(width) = width else { return };
|
let Some(width) = width else { return };
|
||||||
|
|
||||||
let window = self.remove_window(window).unwrap();
|
let window = self.remove_window(window, Transaction::new()).unwrap();
|
||||||
|
|
||||||
if let MonitorSet::Normal { monitors, .. } = &mut self.monitor_set {
|
if let MonitorSet::Normal { monitors, .. } = &mut self.monitor_set {
|
||||||
let new_idx = monitors
|
let new_idx = monitors
|
||||||
@@ -2425,6 +2428,7 @@ impl<W: LayoutElement> Layout<W> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
renderer: &mut GlesRenderer,
|
renderer: &mut GlesRenderer,
|
||||||
window: &W::Id,
|
window: &W::Id,
|
||||||
|
blocker: TransactionBlocker,
|
||||||
) {
|
) {
|
||||||
let _span = tracy_client::span!("Layout::start_close_animation_for_window");
|
let _span = tracy_client::span!("Layout::start_close_animation_for_window");
|
||||||
|
|
||||||
@@ -2433,7 +2437,7 @@ impl<W: LayoutElement> Layout<W> {
|
|||||||
for mon in monitors {
|
for mon in monitors {
|
||||||
for ws in &mut mon.workspaces {
|
for ws in &mut mon.workspaces {
|
||||||
if ws.has_window(window) {
|
if ws.has_window(window) {
|
||||||
ws.start_close_animation_for_window(renderer, window);
|
ws.start_close_animation_for_window(renderer, window, blocker);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2442,7 +2446,7 @@ impl<W: LayoutElement> Layout<W> {
|
|||||||
MonitorSet::NoOutputs { workspaces, .. } => {
|
MonitorSet::NoOutputs { workspaces, .. } => {
|
||||||
for ws in workspaces {
|
for ws in workspaces {
|
||||||
if ws.has_window(window) {
|
if ws.has_window(window) {
|
||||||
ws.start_close_animation_for_window(renderer, window);
|
ws.start_close_animation_for_window(renderer, window, blocker);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3143,7 +3147,7 @@ mod tests {
|
|||||||
layout.add_window_to_named_workspace(&ws_name, win, None, false);
|
layout.add_window_to_named_workspace(&ws_name, win, None, false);
|
||||||
}
|
}
|
||||||
Op::CloseWindow(id) => {
|
Op::CloseWindow(id) => {
|
||||||
layout.remove_window(&id);
|
layout.remove_window(&id, Transaction::new());
|
||||||
}
|
}
|
||||||
Op::FullscreenWindow(id) => {
|
Op::FullscreenWindow(id) => {
|
||||||
layout.toggle_fullscreen(&id);
|
layout.toggle_fullscreen(&id);
|
||||||
|
|||||||
+19
-3
@@ -19,6 +19,7 @@ use crate::input::swipe_tracker::SwipeTracker;
|
|||||||
use crate::render_helpers::renderer::NiriRenderer;
|
use crate::render_helpers::renderer::NiriRenderer;
|
||||||
use crate::render_helpers::RenderTarget;
|
use crate::render_helpers::RenderTarget;
|
||||||
use crate::rubber_band::RubberBand;
|
use crate::rubber_band::RubberBand;
|
||||||
|
use crate::utils::transaction::Transaction;
|
||||||
use crate::utils::{output_size, to_physical_precise_round, ResizeEdge};
|
use crate::utils::{output_size, to_physical_precise_round, ResizeEdge};
|
||||||
|
|
||||||
/// Amount of touchpad movement to scroll the height of one workspace.
|
/// Amount of touchpad movement to scroll the height of one workspace.
|
||||||
@@ -442,7 +443,12 @@ impl<W: LayoutElement> Monitor<W> {
|
|||||||
let width = column.width;
|
let width = column.width;
|
||||||
let is_full_width = column.is_full_width;
|
let is_full_width = column.is_full_width;
|
||||||
let window = workspace
|
let window = workspace
|
||||||
.remove_tile_by_idx(workspace.active_column_idx, column.active_tile_idx, None)
|
.remove_tile_by_idx(
|
||||||
|
workspace.active_column_idx,
|
||||||
|
column.active_tile_idx,
|
||||||
|
Transaction::new(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
.into_window();
|
.into_window();
|
||||||
|
|
||||||
self.add_window(new_idx, window, true, width, is_full_width);
|
self.add_window(new_idx, window, true, width, is_full_width);
|
||||||
@@ -465,7 +471,12 @@ impl<W: LayoutElement> Monitor<W> {
|
|||||||
let width = column.width;
|
let width = column.width;
|
||||||
let is_full_width = column.is_full_width;
|
let is_full_width = column.is_full_width;
|
||||||
let window = workspace
|
let window = workspace
|
||||||
.remove_tile_by_idx(workspace.active_column_idx, column.active_tile_idx, None)
|
.remove_tile_by_idx(
|
||||||
|
workspace.active_column_idx,
|
||||||
|
column.active_tile_idx,
|
||||||
|
Transaction::new(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
.into_window();
|
.into_window();
|
||||||
|
|
||||||
self.add_window(new_idx, window, true, width, is_full_width);
|
self.add_window(new_idx, window, true, width, is_full_width);
|
||||||
@@ -488,7 +499,12 @@ impl<W: LayoutElement> Monitor<W> {
|
|||||||
let width = column.width;
|
let width = column.width;
|
||||||
let is_full_width = column.is_full_width;
|
let is_full_width = column.is_full_width;
|
||||||
let window = workspace
|
let window = workspace
|
||||||
.remove_tile_by_idx(workspace.active_column_idx, column.active_tile_idx, None)
|
.remove_tile_by_idx(
|
||||||
|
workspace.active_column_idx,
|
||||||
|
column.active_tile_idx,
|
||||||
|
Transaction::new(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
.into_window();
|
.into_window();
|
||||||
|
|
||||||
self.add_window(new_idx, window, true, width, is_full_width);
|
self.add_window(new_idx, window, true, width, is_full_width);
|
||||||
|
|||||||
+46
-11
@@ -22,7 +22,7 @@ use crate::niri_render_elements;
|
|||||||
use crate::render_helpers::renderer::NiriRenderer;
|
use crate::render_helpers::renderer::NiriRenderer;
|
||||||
use crate::render_helpers::RenderTarget;
|
use crate::render_helpers::RenderTarget;
|
||||||
use crate::utils::id::IdCounter;
|
use crate::utils::id::IdCounter;
|
||||||
use crate::utils::transaction::Transaction;
|
use crate::utils::transaction::{Transaction, TransactionBlocker};
|
||||||
use crate::utils::{output_size, send_scale_transform, ResizeEdge};
|
use crate::utils::{output_size, send_scale_transform, ResizeEdge};
|
||||||
use crate::window::ResolvedWindowRules;
|
use crate::window::ResolvedWindowRules;
|
||||||
|
|
||||||
@@ -1098,6 +1098,7 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
column_idx: usize,
|
column_idx: usize,
|
||||||
window_idx: usize,
|
window_idx: usize,
|
||||||
|
transaction: Transaction,
|
||||||
anim_config: Option<niri_config::Animation>,
|
anim_config: Option<niri_config::Animation>,
|
||||||
) -> Tile<W> {
|
) -> Tile<W> {
|
||||||
let offset = self.column_x(column_idx + 1) - self.column_x(column_idx);
|
let offset = self.column_x(column_idx + 1) - self.column_x(column_idx);
|
||||||
@@ -1139,7 +1140,7 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
offset
|
offset
|
||||||
} else {
|
} else {
|
||||||
column.active_tile_idx = min(column.active_tile_idx, column.tiles.len() - 1);
|
column.active_tile_idx = min(column.active_tile_idx, column.tiles.len() - 1);
|
||||||
column.update_tile_sizes(true);
|
column.update_tile_sizes_with_transaction(true, transaction);
|
||||||
self.data[column_idx].update(column);
|
self.data[column_idx].update(column);
|
||||||
|
|
||||||
prev_width - column.width()
|
prev_width - column.width()
|
||||||
@@ -1294,7 +1295,7 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
column
|
column
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_window(&mut self, window: &W::Id) -> W {
|
pub fn remove_window(&mut self, window: &W::Id, transaction: Transaction) -> W {
|
||||||
let column_idx = self
|
let column_idx = self
|
||||||
.columns
|
.columns
|
||||||
.iter()
|
.iter()
|
||||||
@@ -1303,7 +1304,7 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
let column = &self.columns[column_idx];
|
let column = &self.columns[column_idx];
|
||||||
|
|
||||||
let window_idx = column.position(window).unwrap();
|
let window_idx = column.position(window).unwrap();
|
||||||
self.remove_tile_by_idx(column_idx, window_idx, None)
|
self.remove_tile_by_idx(column_idx, window_idx, transaction, None)
|
||||||
.into_window()
|
.into_window()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1490,6 +1491,7 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
renderer: &mut GlesRenderer,
|
renderer: &mut GlesRenderer,
|
||||||
window: &W::Id,
|
window: &W::Id,
|
||||||
|
blocker: TransactionBlocker,
|
||||||
) {
|
) {
|
||||||
let output_scale = Scale::from(self.scale.fractional_scale());
|
let output_scale = Scale::from(self.scale.fractional_scale());
|
||||||
|
|
||||||
@@ -1542,7 +1544,21 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
|
|
||||||
let anim = Animation::new(0., 1., 0., self.options.animations.window_close.anim);
|
let anim = Animation::new(0., 1., 0., self.options.animations.window_close.anim);
|
||||||
|
|
||||||
let res = ClosingWindow::new(renderer, snapshot, output_scale, tile_size, tile_pos, anim);
|
let blocker = if self.options.disable_transactions {
|
||||||
|
TransactionBlocker::completed()
|
||||||
|
} else {
|
||||||
|
blocker
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = ClosingWindow::new(
|
||||||
|
renderer,
|
||||||
|
snapshot,
|
||||||
|
output_scale,
|
||||||
|
tile_size,
|
||||||
|
tile_pos,
|
||||||
|
blocker,
|
||||||
|
anim,
|
||||||
|
);
|
||||||
match res {
|
match res {
|
||||||
Ok(closing) => {
|
Ok(closing) => {
|
||||||
self.closing_windows.push(closing);
|
self.closing_windows.push(closing);
|
||||||
@@ -1781,6 +1797,7 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
let tile = self.remove_tile_by_idx(
|
let tile = self.remove_tile_by_idx(
|
||||||
source_col_idx,
|
source_col_idx,
|
||||||
0,
|
0,
|
||||||
|
Transaction::new(),
|
||||||
Some(self.options.animations.window_movement.0),
|
Some(self.options.animations.window_movement.0),
|
||||||
);
|
);
|
||||||
self.enter_output_for_window(tile.window());
|
self.enter_output_for_window(tile.window());
|
||||||
@@ -1813,7 +1830,12 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
|
|
||||||
let mut offset = Point::from((source_column.render_offset().x, 0.));
|
let mut offset = Point::from((source_column.render_offset().x, 0.));
|
||||||
|
|
||||||
let tile = self.remove_tile_by_idx(source_col_idx, source_column.active_tile_idx, None);
|
let tile = self.remove_tile_by_idx(
|
||||||
|
source_col_idx,
|
||||||
|
source_column.active_tile_idx,
|
||||||
|
Transaction::new(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
self.add_tile_at(
|
self.add_tile_at(
|
||||||
self.active_column_idx,
|
self.active_column_idx,
|
||||||
@@ -1861,6 +1883,7 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
let tile = self.remove_tile_by_idx(
|
let tile = self.remove_tile_by_idx(
|
||||||
source_col_idx,
|
source_col_idx,
|
||||||
0,
|
0,
|
||||||
|
Transaction::new(),
|
||||||
Some(self.options.animations.window_movement.0),
|
Some(self.options.animations.window_movement.0),
|
||||||
);
|
);
|
||||||
self.enter_output_for_window(tile.window());
|
self.enter_output_for_window(tile.window());
|
||||||
@@ -1888,7 +1911,12 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
let width = source_column.width;
|
let width = source_column.width;
|
||||||
let is_full_width = source_column.is_full_width;
|
let is_full_width = source_column.is_full_width;
|
||||||
|
|
||||||
let tile = self.remove_tile_by_idx(source_col_idx, source_column.active_tile_idx, None);
|
let tile = self.remove_tile_by_idx(
|
||||||
|
source_col_idx,
|
||||||
|
source_column.active_tile_idx,
|
||||||
|
Transaction::new(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
self.add_tile(
|
self.add_tile(
|
||||||
tile,
|
tile,
|
||||||
@@ -1921,7 +1949,7 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
let mut offset = Point::from((offset, 0.));
|
let mut offset = Point::from((offset, 0.));
|
||||||
let prev_off = self.columns[source_column_idx].tile_offset(0);
|
let prev_off = self.columns[source_column_idx].tile_offset(0);
|
||||||
|
|
||||||
let tile = self.remove_tile_by_idx(source_column_idx, 0, None);
|
let tile = self.remove_tile_by_idx(source_column_idx, 0, Transaction::new(), None);
|
||||||
self.enter_output_for_window(tile.window());
|
self.enter_output_for_window(tile.window());
|
||||||
|
|
||||||
let prev_next_x = self.column_x(self.active_column_idx + 1);
|
let prev_next_x = self.column_x(self.active_column_idx + 1);
|
||||||
@@ -1970,8 +1998,12 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
|
|
||||||
let width = source_column.width;
|
let width = source_column.width;
|
||||||
let is_full_width = source_column.is_full_width;
|
let is_full_width = source_column.is_full_width;
|
||||||
let tile =
|
let tile = self.remove_tile_by_idx(
|
||||||
self.remove_tile_by_idx(self.active_column_idx, source_column.active_tile_idx, None);
|
self.active_column_idx,
|
||||||
|
source_column.active_tile_idx,
|
||||||
|
Transaction::new(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
self.add_tile(
|
self.add_tile(
|
||||||
tile,
|
tile,
|
||||||
@@ -3031,6 +3063,10 @@ impl<W: LayoutElement> Column<W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_tile_sizes(&mut self, animate: bool) {
|
fn update_tile_sizes(&mut self, animate: bool) {
|
||||||
|
self.update_tile_sizes_with_transaction(animate, Transaction::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_tile_sizes_with_transaction(&mut self, animate: bool, transaction: Transaction) {
|
||||||
if self.is_fullscreen {
|
if self.is_fullscreen {
|
||||||
self.tiles[0].request_fullscreen(self.view_size);
|
self.tiles[0].request_fullscreen(self.view_size);
|
||||||
return;
|
return;
|
||||||
@@ -3195,7 +3231,6 @@ impl<W: LayoutElement> Column<W> {
|
|||||||
assert_eq!(auto_tiles_left, 0);
|
assert_eq!(auto_tiles_left, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let transaction = Transaction::new();
|
|
||||||
for (tile, h) in zip(&mut self.tiles, heights) {
|
for (tile, h) in zip(&mut self.tiles, heights) {
|
||||||
let WindowHeight::Fixed(height) = h else {
|
let WindowHeight::Fixed(height) = h else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
|||||||
@@ -148,6 +148,12 @@ impl Drop for Transaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TransactionBlocker {
|
||||||
|
pub fn completed() -> Self {
|
||||||
|
Self(Weak::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Blocker for TransactionBlocker {
|
impl Blocker for TransactionBlocker {
|
||||||
fn state(&self) -> BlockerState {
|
fn state(&self) -> BlockerState {
|
||||||
if self.0.upgrade().map_or(true, |x| x.is_completed()) {
|
if self.0.upgrade().map_or(true, |x| x.is_completed()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user