mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-21 02:01:55 +07:00
Implement maximize-to-edges (true Wayland maximize)
This commit is contained in:
@@ -303,6 +303,9 @@ pub enum Action {
|
||||
#[knuffel(skip)]
|
||||
SwitchPresetWindowHeightBackById(u64),
|
||||
MaximizeColumn,
|
||||
MaximizeWindowToEdges,
|
||||
#[knuffel(skip)]
|
||||
MaximizeWindowToEdgesById(u64),
|
||||
SetColumnWidth(#[knuffel(argument, str)] SizeChange),
|
||||
ExpandColumnToAvailableWidth,
|
||||
SwitchLayout(#[knuffel(argument, str)] LayoutSwitchTarget),
|
||||
@@ -568,6 +571,10 @@ impl From<niri_ipc::Action> for Action {
|
||||
Self::SwitchPresetWindowHeightBackById(id)
|
||||
}
|
||||
niri_ipc::Action::MaximizeColumn {} => Self::MaximizeColumn,
|
||||
niri_ipc::Action::MaximizeWindowToEdges { id: None } => Self::MaximizeWindowToEdges,
|
||||
niri_ipc::Action::MaximizeWindowToEdges { id: Some(id) } => {
|
||||
Self::MaximizeWindowToEdgesById(id)
|
||||
}
|
||||
niri_ipc::Action::SetColumnWidth { change } => Self::SetColumnWidth(change),
|
||||
niri_ipc::Action::ExpandColumnToAvailableWidth {} => Self::ExpandColumnToAvailableWidth,
|
||||
niri_ipc::Action::SwitchLayout { layout } => Self::SwitchLayout(layout),
|
||||
|
||||
@@ -1578,6 +1578,7 @@ mod tests {
|
||||
open_maximized: Some(
|
||||
true,
|
||||
),
|
||||
open_maximized_to_edges: None,
|
||||
open_fullscreen: Some(
|
||||
false,
|
||||
),
|
||||
|
||||
@@ -24,6 +24,8 @@ pub struct WindowRule {
|
||||
#[knuffel(child, unwrap(argument))]
|
||||
pub open_maximized: Option<bool>,
|
||||
#[knuffel(child, unwrap(argument))]
|
||||
pub open_maximized_to_edges: Option<bool>,
|
||||
#[knuffel(child, unwrap(argument))]
|
||||
pub open_fullscreen: Option<bool>,
|
||||
#[knuffel(child, unwrap(argument))]
|
||||
pub open_floating: Option<bool>,
|
||||
|
||||
@@ -713,6 +713,14 @@ pub enum Action {
|
||||
},
|
||||
/// Toggle the maximized state of the focused column.
|
||||
MaximizeColumn {},
|
||||
/// Toggle the maximized-to-edges state of the focused window.
|
||||
MaximizeWindowToEdges {
|
||||
/// Id of the window to maximize.
|
||||
///
|
||||
/// If `None`, uses the focused window.
|
||||
#[cfg_attr(feature = "clap", arg(long))]
|
||||
id: Option<u64>,
|
||||
},
|
||||
/// Change the width of the focused column.
|
||||
SetColumnWidth {
|
||||
/// How to change the width.
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
|
||||
use niri::animation::Clock;
|
||||
use niri::layout::{ActivateWindow, AddWindowTarget, LayoutElement as _, Options};
|
||||
use niri::layout::{ActivateWindow, AddWindowTarget, LayoutElement as _, Options, SizingMode};
|
||||
use niri::render_helpers::RenderTarget;
|
||||
use niri_config::{Color, OutputName, PresetSize};
|
||||
use smithay::backend::renderer::element::RenderElement;
|
||||
@@ -168,7 +168,7 @@ impl Layout {
|
||||
let max_size = window.max_size();
|
||||
window.request_size(
|
||||
ws.new_window_size(width, None, false, window.rules(), (min_size, max_size)),
|
||||
false,
|
||||
SizingMode::Normal,
|
||||
false,
|
||||
None,
|
||||
);
|
||||
@@ -197,7 +197,7 @@ impl Layout {
|
||||
let max_size = window.max_size();
|
||||
window.request_size(
|
||||
ws.new_window_size(width, None, false, window.rules(), (min_size, max_size)),
|
||||
false,
|
||||
SizingMode::Normal,
|
||||
false,
|
||||
None,
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use niri::layout::LayoutElement;
|
||||
use niri::layout::{LayoutElement, SizingMode};
|
||||
use niri::render_helpers::RenderTarget;
|
||||
use smithay::backend::renderer::element::RenderElement;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
@@ -14,14 +14,14 @@ pub struct Window {
|
||||
impl Window {
|
||||
pub fn freeform(args: Args) -> Self {
|
||||
let mut window = TestWindow::freeform(0);
|
||||
window.request_size(args.size, false, false, None);
|
||||
window.request_size(args.size, SizingMode::Normal, false, None);
|
||||
window.communicate();
|
||||
Self { window }
|
||||
}
|
||||
|
||||
pub fn fixed_size(args: Args) -> Self {
|
||||
let mut window = TestWindow::fixed_size(0);
|
||||
window.request_size(args.size, false, false, None);
|
||||
window.request_size(args.size, SizingMode::Normal, false, None);
|
||||
window.communicate();
|
||||
Self { window }
|
||||
}
|
||||
@@ -29,7 +29,7 @@ impl Window {
|
||||
pub fn fixed_size_with_csd_shadow(args: Args) -> Self {
|
||||
let mut window = TestWindow::fixed_size(0);
|
||||
window.set_csd_shadow_width(64);
|
||||
window.request_size(args.size, false, false, None);
|
||||
window.request_size(args.size, SizingMode::Normal, false, None);
|
||||
window.communicate();
|
||||
Self { window }
|
||||
}
|
||||
@@ -38,7 +38,7 @@ impl Window {
|
||||
impl TestCase for Window {
|
||||
fn resize(&mut self, width: i32, height: i32) {
|
||||
self.window
|
||||
.request_size(Size::from((width, height)), false, false, None);
|
||||
.request_size(Size::from((width, height)), SizingMode::Normal, false, None);
|
||||
self.window.communicate();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::rc::Rc;
|
||||
|
||||
use niri::layout::{
|
||||
ConfigureIntent, InteractiveResizeData, LayoutElement, LayoutElementRenderElement,
|
||||
LayoutElementRenderSnapshot,
|
||||
LayoutElementRenderSnapshot, SizingMode,
|
||||
};
|
||||
use niri::render_helpers::offscreen::OffscreenData;
|
||||
use niri::render_helpers::renderer::NiriRenderer;
|
||||
@@ -24,7 +24,7 @@ struct TestWindowInner {
|
||||
min_size: Size<i32, Logical>,
|
||||
max_size: Size<i32, Logical>,
|
||||
buffer: SolidColorBuffer,
|
||||
pending_fullscreen: bool,
|
||||
pending_sizing_mode: SizingMode,
|
||||
csd_shadow_width: i32,
|
||||
csd_shadow_buffer: SolidColorBuffer,
|
||||
}
|
||||
@@ -50,7 +50,7 @@ impl TestWindow {
|
||||
min_size,
|
||||
max_size,
|
||||
buffer,
|
||||
pending_fullscreen: false,
|
||||
pending_sizing_mode: SizingMode::Normal,
|
||||
csd_shadow_width: 0,
|
||||
csd_shadow_buffer: SolidColorBuffer::new((0., 0.), [0., 0., 0., 0.3]),
|
||||
})),
|
||||
@@ -182,12 +182,12 @@ impl LayoutElement for TestWindow {
|
||||
fn request_size(
|
||||
&mut self,
|
||||
size: Size<i32, Logical>,
|
||||
is_fullscreen: bool,
|
||||
mode: SizingMode,
|
||||
_animate: bool,
|
||||
_transaction: Option<Transaction>,
|
||||
) {
|
||||
self.inner.borrow_mut().requested_size = Some(size);
|
||||
self.inner.borrow_mut().pending_fullscreen = is_fullscreen;
|
||||
self.inner.borrow_mut().pending_sizing_mode = mode;
|
||||
}
|
||||
|
||||
fn min_size(&self) -> Size<i32, Logical> {
|
||||
@@ -232,12 +232,12 @@ impl LayoutElement for TestWindow {
|
||||
|
||||
fn send_pending_configure(&mut self) {}
|
||||
|
||||
fn is_fullscreen(&self) -> bool {
|
||||
false
|
||||
fn pending_sizing_mode(&self) -> SizingMode {
|
||||
self.inner.borrow().pending_sizing_mode
|
||||
}
|
||||
|
||||
fn is_pending_fullscreen(&self) -> bool {
|
||||
self.inner.borrow().pending_fullscreen
|
||||
fn sizing_mode(&self) -> SizingMode {
|
||||
SizingMode::Normal
|
||||
}
|
||||
|
||||
fn requested_size(&self) -> Option<Size<i32, Logical>> {
|
||||
|
||||
+64
-27
@@ -20,7 +20,7 @@ use smithay::{delegate_compositor, delegate_shm};
|
||||
|
||||
use super::xdg_shell::add_mapped_toplevel_pre_commit_hook;
|
||||
use crate::handlers::XDG_ACTIVATION_TOKEN_TIMEOUT;
|
||||
use crate::layout::{ActivateWindow, AddWindowTarget};
|
||||
use crate::layout::{ActivateWindow, AddWindowTarget, LayoutElement as _};
|
||||
use crate::niri::{CastTarget, ClientState, LockState, State};
|
||||
use crate::utils::transaction::Transaction;
|
||||
use crate::utils::{is_mapped, send_scale_transform};
|
||||
@@ -91,35 +91,59 @@ impl CompositorHandler for State {
|
||||
|
||||
let toplevel = window.toplevel().expect("no X11 support");
|
||||
|
||||
let (rules, width, height, is_full_width, output, workspace_id) =
|
||||
if let InitialConfigureState::Configured {
|
||||
let (
|
||||
rules,
|
||||
width,
|
||||
height,
|
||||
is_full_width,
|
||||
output,
|
||||
workspace_id,
|
||||
is_pending_maximized,
|
||||
) = if let InitialConfigureState::Configured {
|
||||
rules,
|
||||
width,
|
||||
height,
|
||||
floating_width: _,
|
||||
floating_height: _,
|
||||
is_full_width,
|
||||
output,
|
||||
workspace_name,
|
||||
is_pending_maximized,
|
||||
} = state
|
||||
{
|
||||
// Check that the output is still connected.
|
||||
let output =
|
||||
output.filter(|o| self.niri.layout.monitor_for_output(o).is_some());
|
||||
|
||||
// Check that the workspace still exists.
|
||||
let workspace_id = workspace_name
|
||||
.as_deref()
|
||||
.and_then(|n| self.niri.layout.find_workspace_by_name(n))
|
||||
.map(|(_, ws)| ws.id());
|
||||
|
||||
(
|
||||
rules,
|
||||
width,
|
||||
height,
|
||||
floating_width: _,
|
||||
floating_height: _,
|
||||
is_full_width,
|
||||
output,
|
||||
workspace_name,
|
||||
} = state
|
||||
{
|
||||
// Check that the output is still connected.
|
||||
let output =
|
||||
output.filter(|o| self.niri.layout.monitor_for_output(o).is_some());
|
||||
|
||||
// Check that the workspace still exists.
|
||||
let workspace_id = workspace_name
|
||||
.as_deref()
|
||||
.and_then(|n| self.niri.layout.find_workspace_by_name(n))
|
||||
.map(|(_, ws)| ws.id());
|
||||
|
||||
(rules, width, height, is_full_width, output, workspace_id)
|
||||
} else {
|
||||
// Can happen when a surface unmaps by attaching a null buffer while
|
||||
// there are in-flight pending configures.
|
||||
debug!("window mapped without proper initial configure");
|
||||
(ResolvedWindowRules::empty(), None, None, false, None, None)
|
||||
};
|
||||
workspace_id,
|
||||
is_pending_maximized,
|
||||
)
|
||||
} else {
|
||||
// Can happen when a surface unmaps by attaching a null buffer while
|
||||
// there are in-flight pending configures.
|
||||
debug!("window mapped without proper initial configure");
|
||||
(
|
||||
ResolvedWindowRules::empty(),
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
)
|
||||
};
|
||||
|
||||
// The GTK about dialog sets min/max size after the initial configure but
|
||||
// before mapping, so we need to compute open_floating at the last possible
|
||||
@@ -169,7 +193,7 @@ impl CompositorHandler for State {
|
||||
.map(|(mapped, _)| mapped.window.clone());
|
||||
|
||||
// The mapped pre-commit hook deals with dma-bufs on its own.
|
||||
self.remove_default_dmabuf_pre_commit_hook(toplevel.wl_surface());
|
||||
self.remove_default_dmabuf_pre_commit_hook(surface);
|
||||
let hook = add_mapped_toplevel_pre_commit_hook(toplevel);
|
||||
let mapped = Mapped::new(window, rules, hook);
|
||||
let window = mapped.window.clone();
|
||||
@@ -193,8 +217,21 @@ impl CompositorHandler for State {
|
||||
is_floating,
|
||||
activate,
|
||||
);
|
||||
let output = output.cloned();
|
||||
|
||||
if let Some(output) = output.cloned() {
|
||||
// The window state cannot contain Fullscreen and Maximized at once. Therefore,
|
||||
// if the window ended up fullscreen, then we only know that it is also
|
||||
// maximized from the is_pending_maximized variable. Tell the layout about it
|
||||
// here so that unfullscreening the window makes it maximized.
|
||||
if let Some((mapped, _)) = self.niri.layout.find_window_and_output(surface) {
|
||||
if mapped.pending_sizing_mode().is_fullscreen() && is_pending_maximized {
|
||||
self.niri.layout.set_maximized(&window, true);
|
||||
}
|
||||
} else {
|
||||
error!("layout is missing the window that we just added");
|
||||
}
|
||||
|
||||
if let Some(output) = output {
|
||||
self.niri.layout.start_open_animation_for_window(&window);
|
||||
|
||||
let new_focus = self.niri.layout.focus().map(|m| &m.window);
|
||||
|
||||
@@ -550,6 +550,20 @@ impl ForeignToplevelHandler for State {
|
||||
self.niri.layout.set_fullscreen(&window, false);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_maximized(&mut self, wl_surface: WlSurface) {
|
||||
if let Some((mapped, _)) = self.niri.layout.find_window_and_output(&wl_surface) {
|
||||
let window = mapped.window.clone();
|
||||
self.niri.layout.set_maximized(&window, true);
|
||||
}
|
||||
}
|
||||
|
||||
fn unset_maximized(&mut self, wl_surface: WlSurface) {
|
||||
if let Some((mapped, _)) = self.niri.layout.find_window_and_output(&wl_surface) {
|
||||
let window = mapped.window.clone();
|
||||
self.niri.layout.set_maximized(&window, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
delegate_foreign_toplevel!(State);
|
||||
|
||||
|
||||
+222
-12
@@ -428,18 +428,205 @@ impl XdgShellHandler for State {
|
||||
});
|
||||
}
|
||||
|
||||
fn maximize_request(&mut self, surface: ToplevelSurface) {
|
||||
// FIXME
|
||||
fn maximize_request(&mut self, toplevel: ToplevelSurface) {
|
||||
if let Some((mapped, _)) = self
|
||||
.niri
|
||||
.layout
|
||||
.find_window_and_output_mut(toplevel.wl_surface())
|
||||
{
|
||||
// A configure is required in response to this event regardless if there are pending
|
||||
// changes.
|
||||
mapped.set_needs_configure();
|
||||
|
||||
// A configure is required in response to this event. However, if an initial configure
|
||||
// wasn't sent, then we will send this as part of the initial configure later.
|
||||
if surface.is_initial_configure_sent() {
|
||||
surface.send_configure();
|
||||
let window = mapped.window.clone();
|
||||
self.niri.layout.set_maximized(&window, true);
|
||||
} else if let Some(unmapped) = self.niri.unmapped_windows.get_mut(toplevel.wl_surface()) {
|
||||
match &mut unmapped.state {
|
||||
InitialConfigureState::NotConfigured {
|
||||
wants_maximized, ..
|
||||
} => {
|
||||
*wants_maximized = true;
|
||||
|
||||
// The required configure will be the initial configure.
|
||||
}
|
||||
InitialConfigureState::Configured {
|
||||
rules,
|
||||
output,
|
||||
is_pending_maximized,
|
||||
..
|
||||
} => {
|
||||
// Figure out the monitor following a similar logic to initial configure.
|
||||
// FIXME: deduplicate.
|
||||
let mon = output
|
||||
.as_ref()
|
||||
.and_then(|o| self.niri.layout.monitor_for_output(o))
|
||||
.map(|mon| (mon, false))
|
||||
// If not, check if we have a parent with a monitor.
|
||||
.or_else(|| {
|
||||
toplevel
|
||||
.parent()
|
||||
.and_then(|parent| self.niri.layout.find_window_and_output(&parent))
|
||||
.and_then(|(_win, output)| output)
|
||||
.and_then(|o| self.niri.layout.monitor_for_output(o))
|
||||
.map(|mon| (mon, true))
|
||||
})
|
||||
// If not, fall back to the active monitor.
|
||||
.or_else(|| {
|
||||
self.niri
|
||||
.layout
|
||||
.active_monitor_ref()
|
||||
.map(|mon| (mon, false))
|
||||
});
|
||||
|
||||
*output = mon
|
||||
.filter(|(_, parent)| !parent)
|
||||
.map(|(mon, _)| mon.output().clone());
|
||||
let mon = mon.map(|(mon, _)| mon);
|
||||
|
||||
let ws = mon
|
||||
.map(|mon| mon.active_workspace_ref())
|
||||
.or_else(|| self.niri.layout.active_workspace());
|
||||
|
||||
if let Some(ws) = ws {
|
||||
// If the window is pending fullscreen, then this will do nothing. But
|
||||
// that's expected: the window remains fullscreen, and we simply remember
|
||||
// that it is now pending maximized.
|
||||
*is_pending_maximized = true;
|
||||
toplevel.with_pending_state(|state| {
|
||||
if !state.states.contains(xdg_toplevel::State::Fullscreen) {
|
||||
state.states.set(xdg_toplevel::State::Maximized);
|
||||
}
|
||||
});
|
||||
ws.configure_new_window(&unmapped.window, None, None, false, rules);
|
||||
}
|
||||
|
||||
// We already sent the initial configure, so we need to reconfigure.
|
||||
toplevel.send_configure();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error!("couldn't find the toplevel in maximize_request()");
|
||||
toplevel.send_configure();
|
||||
}
|
||||
}
|
||||
|
||||
fn unmaximize_request(&mut self, _surface: ToplevelSurface) {
|
||||
// FIXME
|
||||
fn unmaximize_request(&mut self, toplevel: ToplevelSurface) {
|
||||
if let Some((mapped, _)) = self
|
||||
.niri
|
||||
.layout
|
||||
.find_window_and_output_mut(toplevel.wl_surface())
|
||||
{
|
||||
// A configure is required in response to this event regardless if there are pending
|
||||
// changes.
|
||||
mapped.set_needs_configure();
|
||||
|
||||
let window = mapped.window.clone();
|
||||
self.niri.layout.set_maximized(&window, false);
|
||||
} else if let Some(unmapped) = self.niri.unmapped_windows.get_mut(toplevel.wl_surface()) {
|
||||
match &mut unmapped.state {
|
||||
InitialConfigureState::NotConfigured {
|
||||
wants_maximized, ..
|
||||
} => {
|
||||
*wants_maximized = false;
|
||||
|
||||
// The required configure will be the initial configure.
|
||||
}
|
||||
InitialConfigureState::Configured {
|
||||
rules,
|
||||
width,
|
||||
height,
|
||||
floating_width,
|
||||
floating_height,
|
||||
is_full_width,
|
||||
output,
|
||||
workspace_name,
|
||||
is_pending_maximized,
|
||||
} => {
|
||||
// Figure out the monitor following a similar logic to initial configure.
|
||||
// FIXME: deduplicate.
|
||||
let mon = workspace_name
|
||||
.as_deref()
|
||||
.and_then(|name| self.niri.layout.monitor_for_workspace(name))
|
||||
.map(|mon| (mon, false));
|
||||
|
||||
let mon = mon.or_else(|| {
|
||||
output
|
||||
.as_ref()
|
||||
.and_then(|o| self.niri.layout.monitor_for_output(o))
|
||||
.map(|mon| (mon, false))
|
||||
// If not, check if we have a parent with a monitor.
|
||||
.or_else(|| {
|
||||
toplevel
|
||||
.parent()
|
||||
.and_then(|parent| {
|
||||
self.niri.layout.find_window_and_output(&parent)
|
||||
})
|
||||
.and_then(|(_win, output)| output)
|
||||
.and_then(|o| self.niri.layout.monitor_for_output(o))
|
||||
.map(|mon| (mon, true))
|
||||
})
|
||||
// If not, fall back to the active monitor.
|
||||
.or_else(|| {
|
||||
self.niri
|
||||
.layout
|
||||
.active_monitor_ref()
|
||||
.map(|mon| (mon, false))
|
||||
})
|
||||
});
|
||||
|
||||
*output = mon
|
||||
.filter(|(_, parent)| !parent)
|
||||
.map(|(mon, _)| mon.output().clone());
|
||||
let mon = mon.map(|(mon, _)| mon);
|
||||
|
||||
let ws = workspace_name
|
||||
.as_deref()
|
||||
.and_then(|name| mon.map(|mon| mon.find_named_workspace(name)))
|
||||
.unwrap_or_else(|| {
|
||||
mon.map(|mon| mon.active_workspace_ref())
|
||||
.or_else(|| self.niri.layout.active_workspace())
|
||||
});
|
||||
|
||||
if let Some(ws) = ws {
|
||||
// If the window is pending fullscreen, then this will do nothing since
|
||||
// then the Maximized state is already unset. But that's expected: the
|
||||
// window remains fullscreen, and we simply remember that it is no
|
||||
// longer pending maximized.
|
||||
*is_pending_maximized = false;
|
||||
toplevel.with_pending_state(|state| {
|
||||
state.states.unset(xdg_toplevel::State::Maximized);
|
||||
});
|
||||
|
||||
let is_floating = rules.compute_open_floating(&toplevel);
|
||||
let configure_width = if is_floating {
|
||||
*floating_width
|
||||
} else if *is_full_width {
|
||||
Some(PresetSize::Proportion(1.))
|
||||
} else {
|
||||
*width
|
||||
};
|
||||
let configure_height = if is_floating {
|
||||
*floating_height
|
||||
} else {
|
||||
*height
|
||||
};
|
||||
ws.configure_new_window(
|
||||
&unmapped.window,
|
||||
configure_width,
|
||||
configure_height,
|
||||
is_floating,
|
||||
rules,
|
||||
);
|
||||
}
|
||||
|
||||
// We already sent the initial configure, so we need to reconfigure.
|
||||
toplevel.send_configure();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error!("couldn't find the toplevel in unmaximize_request()");
|
||||
toplevel.send_configure();
|
||||
}
|
||||
}
|
||||
|
||||
fn fullscreen_request(
|
||||
@@ -474,7 +661,9 @@ impl XdgShellHandler for State {
|
||||
self.niri.layout.set_fullscreen(&window, true);
|
||||
} else if let Some(unmapped) = self.niri.unmapped_windows.get_mut(toplevel.wl_surface()) {
|
||||
match &mut unmapped.state {
|
||||
InitialConfigureState::NotConfigured { wants_fullscreen } => {
|
||||
InitialConfigureState::NotConfigured {
|
||||
wants_fullscreen, ..
|
||||
} => {
|
||||
*wants_fullscreen = Some(requested_output);
|
||||
|
||||
// The required configure will be the initial configure.
|
||||
@@ -517,6 +706,7 @@ impl XdgShellHandler for State {
|
||||
if let Some(ws) = ws {
|
||||
toplevel.with_pending_state(|state| {
|
||||
state.states.set(xdg_toplevel::State::Fullscreen);
|
||||
state.states.unset(xdg_toplevel::State::Maximized);
|
||||
});
|
||||
ws.configure_new_window(&unmapped.window, None, None, false, rules);
|
||||
}
|
||||
@@ -545,7 +735,9 @@ impl XdgShellHandler for State {
|
||||
self.niri.layout.set_fullscreen(&window, false);
|
||||
} else if let Some(unmapped) = self.niri.unmapped_windows.get_mut(toplevel.wl_surface()) {
|
||||
match &mut unmapped.state {
|
||||
InitialConfigureState::NotConfigured { wants_fullscreen } => {
|
||||
InitialConfigureState::NotConfigured {
|
||||
wants_fullscreen, ..
|
||||
} => {
|
||||
*wants_fullscreen = None;
|
||||
|
||||
// The required configure will be the initial configure.
|
||||
@@ -559,6 +751,7 @@ impl XdgShellHandler for State {
|
||||
is_full_width,
|
||||
output,
|
||||
workspace_name,
|
||||
is_pending_maximized,
|
||||
} => {
|
||||
// Figure out the monitor following a similar logic to initial configure.
|
||||
// FIXME: deduplicate.
|
||||
@@ -608,6 +801,10 @@ impl XdgShellHandler for State {
|
||||
if let Some(ws) = ws {
|
||||
toplevel.with_pending_state(|state| {
|
||||
state.states.unset(xdg_toplevel::State::Fullscreen);
|
||||
|
||||
if *is_pending_maximized {
|
||||
state.states.set(xdg_toplevel::State::Maximized);
|
||||
}
|
||||
});
|
||||
|
||||
let is_floating = rules.compute_open_floating(&toplevel);
|
||||
@@ -858,7 +1055,11 @@ impl State {
|
||||
|
||||
let Unmapped { window, state, .. } = unmapped;
|
||||
|
||||
let InitialConfigureState::NotConfigured { wants_fullscreen } = state else {
|
||||
let InitialConfigureState::NotConfigured {
|
||||
wants_fullscreen,
|
||||
wants_maximized,
|
||||
} = state
|
||||
else {
|
||||
error!("window must not be already configured in send_initial_configure()");
|
||||
return;
|
||||
};
|
||||
@@ -934,14 +1135,22 @@ impl State {
|
||||
.or_else(|| self.niri.layout.active_workspace())
|
||||
});
|
||||
|
||||
let mut is_pending_maximized = false;
|
||||
if let Some(ws) = ws {
|
||||
// Set a fullscreen state based on window request and window rule.
|
||||
// Set a fullscreen and maximized state based on window request and window rule.
|
||||
is_pending_maximized = (*wants_maximized && rules.open_maximized_to_edges.is_none())
|
||||
|| rules.open_maximized_to_edges == Some(true);
|
||||
|
||||
if (wants_fullscreen.is_some() && rules.open_fullscreen.is_none())
|
||||
|| rules.open_fullscreen == Some(true)
|
||||
{
|
||||
toplevel.with_pending_state(|state| {
|
||||
state.states.set(xdg_toplevel::State::Fullscreen);
|
||||
});
|
||||
} else if is_pending_maximized {
|
||||
toplevel.with_pending_state(|state| {
|
||||
state.states.set(xdg_toplevel::State::Maximized);
|
||||
});
|
||||
}
|
||||
|
||||
width = ws.resolve_default_width(rules.default_width, false);
|
||||
@@ -979,6 +1188,7 @@ impl State {
|
||||
is_full_width,
|
||||
output,
|
||||
workspace_name: ws.and_then(|w| w.name().cloned()),
|
||||
is_pending_maximized,
|
||||
};
|
||||
|
||||
trace!(surface = %toplevel.wl_surface().id(), "sending initial configure");
|
||||
|
||||
@@ -1514,6 +1514,23 @@ impl State {
|
||||
Action::MaximizeColumn => {
|
||||
self.niri.layout.toggle_full_width();
|
||||
}
|
||||
Action::MaximizeWindowToEdges => {
|
||||
let focus = self.niri.layout.focus().map(|m| m.window.clone());
|
||||
if let Some(window) = focus {
|
||||
self.niri.layout.toggle_maximized(&window);
|
||||
// FIXME: granular
|
||||
self.niri.queue_redraw_all();
|
||||
}
|
||||
}
|
||||
Action::MaximizeWindowToEdgesById(id) => {
|
||||
let window = self.niri.layout.windows().find(|(_, m)| m.id().get() == id);
|
||||
let window = window.map(|(_, m)| m.window.clone());
|
||||
if let Some(window) = window {
|
||||
self.niri.layout.toggle_maximized(&window);
|
||||
// FIXME: granular
|
||||
self.niri.queue_redraw_all();
|
||||
}
|
||||
}
|
||||
Action::FocusMonitorLeft => {
|
||||
if let Some(output) = self.niri.output_left() {
|
||||
self.niri.layout.focus_output(&output);
|
||||
|
||||
@@ -413,8 +413,8 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
// unfullscreen it.
|
||||
let floating_size = tile.floating_window_size;
|
||||
let win = tile.window_mut();
|
||||
let mut size = if win.is_pending_fullscreen() {
|
||||
// If the window was fullscreen without a floating size, ask for (0, 0).
|
||||
let mut size = if !win.pending_sizing_mode().is_normal() {
|
||||
// If the window was fullscreen or maximized without a floating size, ask for (0, 0).
|
||||
floating_size.unwrap_or_default()
|
||||
} else {
|
||||
// If the window wasn't fullscreen without a floating size (e.g. it was tiled before),
|
||||
@@ -1312,6 +1312,8 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
assert_eq!(self.tiles.len(), self.data.len());
|
||||
|
||||
for (i, (tile, data)) in zip(&self.tiles, &self.data).enumerate() {
|
||||
use crate::layout::SizingMode;
|
||||
|
||||
assert!(Rc::ptr_eq(&self.options, &tile.options));
|
||||
assert_eq!(self.view_size, tile.view_size());
|
||||
assert_eq!(self.clock, tile.clock);
|
||||
@@ -1325,9 +1327,10 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
assert!(idx < self.options.layout.preset_window_heights.len());
|
||||
}
|
||||
|
||||
assert!(
|
||||
!tile.window().is_pending_fullscreen(),
|
||||
"floating windows cannot be fullscreen"
|
||||
assert_eq!(
|
||||
tile.window().pending_sizing_mode(),
|
||||
SizingMode::Normal,
|
||||
"floating windows cannot be maximized or fullscreen"
|
||||
);
|
||||
|
||||
data.verify_invariants();
|
||||
|
||||
+64
-9
@@ -118,6 +118,13 @@ niri_render_elements! {
|
||||
pub type LayoutElementRenderSnapshot =
|
||||
RenderSnapshot<BakedBuffer<TextureBuffer<GlesTexture>>, BakedBuffer<SolidColorBuffer>>;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SizingMode {
|
||||
Normal,
|
||||
Maximized,
|
||||
Fullscreen,
|
||||
}
|
||||
|
||||
pub trait LayoutElement {
|
||||
/// Type that can be used as a unique ID of this element.
|
||||
type Id: PartialEq + std::fmt::Debug + Clone;
|
||||
@@ -185,14 +192,14 @@ pub trait LayoutElement {
|
||||
fn request_size(
|
||||
&mut self,
|
||||
size: Size<i32, Logical>,
|
||||
is_fullscreen: bool,
|
||||
mode: SizingMode,
|
||||
animate: bool,
|
||||
transaction: Option<Transaction>,
|
||||
);
|
||||
|
||||
/// Requests the element to change size once, clearing the request afterwards.
|
||||
fn request_size_once(&mut self, size: Size<i32, Logical>, animate: bool) {
|
||||
self.request_size(size, false, animate, None);
|
||||
self.request_size(size, SizingMode::Normal, animate, None);
|
||||
}
|
||||
|
||||
fn min_size(&self) -> Size<i32, Logical>;
|
||||
@@ -214,15 +221,15 @@ pub trait LayoutElement {
|
||||
fn configure_intent(&self) -> ConfigureIntent;
|
||||
fn send_pending_configure(&mut self);
|
||||
|
||||
/// Whether the element is currently fullscreen.
|
||||
/// The element's current sizing mode.
|
||||
///
|
||||
/// This will *not* switch immediately after a [`LayoutElement::request_size()`] call.
|
||||
fn is_fullscreen(&self) -> bool;
|
||||
fn sizing_mode(&self) -> SizingMode;
|
||||
|
||||
/// Whether we're requesting the element to be fullscreen.
|
||||
/// The sizing mode that we're requesting the element to assume.
|
||||
///
|
||||
/// This *will* switch immediately after a [`LayoutElement::request_size()`] call.
|
||||
fn is_pending_fullscreen(&self) -> bool;
|
||||
fn pending_sizing_mode(&self) -> SizingMode;
|
||||
|
||||
/// Size previously requested through [`LayoutElement::request_size()`].
|
||||
fn requested_size(&self) -> Option<Size<i32, Logical>>;
|
||||
@@ -240,7 +247,7 @@ pub trait LayoutElement {
|
||||
///
|
||||
/// The default impl is for testing only, it will not preserve the window's own size changes.
|
||||
fn expected_size(&self) -> Option<Size<i32, Logical>> {
|
||||
if self.is_fullscreen() {
|
||||
if self.sizing_mode().is_fullscreen() {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -502,6 +509,23 @@ struct OverviewGesture {
|
||||
value: f64,
|
||||
}
|
||||
|
||||
impl SizingMode {
|
||||
#[must_use]
|
||||
pub fn is_normal(&self) -> bool {
|
||||
matches!(self, Self::Normal)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_fullscreen(&self) -> bool {
|
||||
matches!(self, Self::Fullscreen)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_maximized(&self) -> bool {
|
||||
matches!(self, Self::Maximized)
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: LayoutElement> InteractiveMoveState<W> {
|
||||
fn moving(&self) -> Option<&InteractiveMoveData<W>> {
|
||||
match self {
|
||||
@@ -2321,7 +2345,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
}
|
||||
InteractiveMoveState::Moving(move_) => {
|
||||
assert_eq!(self.clock, move_.tile.clock);
|
||||
assert!(!move_.tile.window().is_pending_fullscreen());
|
||||
assert!(move_.tile.window().pending_sizing_mode().is_normal());
|
||||
|
||||
move_.tile.verify_invariants();
|
||||
|
||||
@@ -3456,7 +3480,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
|
||||
pub fn toggle_windowed_fullscreen(&mut self, id: &W::Id) {
|
||||
let (_, window) = self.windows().find(|(_, win)| win.id() == id).unwrap();
|
||||
if window.is_pending_fullscreen() {
|
||||
if window.pending_sizing_mode().is_fullscreen() {
|
||||
// Remove the real fullscreen.
|
||||
for ws in self.workspaces_mut() {
|
||||
if ws.has_window(id) {
|
||||
@@ -3474,6 +3498,36 @@ impl<W: LayoutElement> Layout<W> {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_maximized(&mut self, id: &W::Id, maximize: bool) {
|
||||
if let Some(InteractiveMoveState::Moving(move_)) = &self.interactive_move {
|
||||
if move_.tile.window().id() == id {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for ws in self.workspaces_mut() {
|
||||
if ws.has_window(id) {
|
||||
ws.set_maximized(id, maximize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_maximized(&mut self, id: &W::Id) {
|
||||
if let Some(InteractiveMoveState::Moving(move_)) = &self.interactive_move {
|
||||
if move_.tile.window().id() == id {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for ws in self.workspaces_mut() {
|
||||
if ws.has_window(id) {
|
||||
ws.toggle_maximized(id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn workspace_switch_gesture_begin(&mut self, output: &Output, is_touchpad: bool) {
|
||||
let monitors = match &mut self.monitor_set {
|
||||
MonitorSet::Normal { monitors, .. } => monitors,
|
||||
@@ -3845,6 +3899,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
.find(|ws| ws.has_window(&window_id))
|
||||
.unwrap();
|
||||
ws.set_fullscreen(window, false);
|
||||
ws.set_maximized(window, false);
|
||||
|
||||
let RemovedTile {
|
||||
mut tile,
|
||||
|
||||
+278
-85
@@ -18,6 +18,7 @@ use super::workspace::{InteractiveResize, ResolvedSize};
|
||||
use super::{ConfigureIntent, HitType, InteractiveResizeData, LayoutElement, Options, RemovedTile};
|
||||
use crate::animation::{Animation, Clock};
|
||||
use crate::input::swipe_tracker::SwipeTracker;
|
||||
use crate::layout::SizingMode;
|
||||
use crate::niri_render_elements;
|
||||
use crate::render_helpers::renderer::NiriRenderer;
|
||||
use crate::render_helpers::RenderTarget;
|
||||
@@ -62,8 +63,8 @@ pub struct ScrollingSpace<W: LayoutElement> {
|
||||
/// The value is the view offset that the previous column had before, to restore it.
|
||||
activate_prev_column_on_removal: Option<f64>,
|
||||
|
||||
/// View offset to restore after unfullscreening.
|
||||
view_offset_before_fullscreen: Option<f64>,
|
||||
/// View offset to restore after unfullscreening or unmaximizing.
|
||||
view_offset_to_restore: Option<f64>,
|
||||
|
||||
/// Windows in the closing animation.
|
||||
closing_windows: Vec<ClosingWindow>,
|
||||
@@ -177,6 +178,13 @@ pub struct Column<W: LayoutElement> {
|
||||
/// take some time to catch up and actually unfullscreen.
|
||||
is_pending_fullscreen: bool,
|
||||
|
||||
/// Whether this column is going to be maximized.
|
||||
///
|
||||
/// Can be `true` together with `is_pending_fullscreen`, which means that the column is
|
||||
/// effectively pending fullscreen, but unfullscreening should go back to maximized state,
|
||||
/// rather than normal.
|
||||
is_pending_maximized: bool,
|
||||
|
||||
/// How this column displays and arranges windows.
|
||||
display_mode: ColumnDisplay,
|
||||
|
||||
@@ -192,6 +200,11 @@ pub struct Column<W: LayoutElement> {
|
||||
/// Latest known working area for this column's workspace.
|
||||
working_area: Rectangle<f64, Logical>,
|
||||
|
||||
/// Working area for this column's workspace excluding struts.
|
||||
///
|
||||
/// Used for maximize-to-edges.
|
||||
parent_area: Rectangle<f64, Logical>,
|
||||
|
||||
/// Scale of the output the column is on (and rounds its sizes to).
|
||||
scale: f64,
|
||||
|
||||
@@ -285,7 +298,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
interactive_resize: None,
|
||||
view_offset: ViewOffset::Static(0.),
|
||||
activate_prev_column_on_removal: None,
|
||||
view_offset_before_fullscreen: None,
|
||||
view_offset_to_restore: None,
|
||||
closing_windows: Vec::new(),
|
||||
view_size,
|
||||
working_area,
|
||||
@@ -306,7 +319,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
let working_area = compute_working_area(parent_area, scale, options.layout.struts);
|
||||
|
||||
for (column, data) in zip(&mut self.columns, &mut self.data) {
|
||||
column.update_config(view_size, working_area, scale, options.clone());
|
||||
column.update_config(view_size, working_area, parent_area, scale, options.clone());
|
||||
data.update(column);
|
||||
}
|
||||
|
||||
@@ -440,7 +453,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
}
|
||||
|
||||
let col = &self.columns[self.active_column_idx];
|
||||
col.is_pending_fullscreen
|
||||
col.pending_sizing_mode().is_fullscreen()
|
||||
}
|
||||
|
||||
pub fn new_window_toplevel_bounds(&self, rules: &ResolvedWindowRules) -> Size<i32, Logical> {
|
||||
@@ -533,24 +546,25 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
target_x: Option<f64>,
|
||||
col_x: f64,
|
||||
width: f64,
|
||||
is_fullscreen: bool,
|
||||
mode: SizingMode,
|
||||
) -> f64 {
|
||||
if is_fullscreen {
|
||||
if mode.is_fullscreen() {
|
||||
return 0.;
|
||||
}
|
||||
|
||||
let (area, padding) = if mode.is_maximized() {
|
||||
(self.parent_area, 0.)
|
||||
} else {
|
||||
(self.working_area, self.options.layout.gaps)
|
||||
};
|
||||
|
||||
let target_x = target_x.unwrap_or_else(|| self.target_view_pos());
|
||||
|
||||
let new_offset = compute_new_view_offset(
|
||||
target_x + self.working_area.loc.x,
|
||||
self.working_area.size.w,
|
||||
col_x,
|
||||
width,
|
||||
self.options.layout.gaps,
|
||||
);
|
||||
let new_offset =
|
||||
compute_new_view_offset(target_x + area.loc.x, area.size.w, col_x, width, padding);
|
||||
|
||||
// Non-fullscreen windows are always offset at least by the working area position.
|
||||
new_offset - self.working_area.loc.x
|
||||
new_offset - area.loc.x
|
||||
}
|
||||
|
||||
fn compute_new_view_offset_centered(
|
||||
@@ -558,18 +572,24 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
target_x: Option<f64>,
|
||||
col_x: f64,
|
||||
width: f64,
|
||||
is_fullscreen: bool,
|
||||
mode: SizingMode,
|
||||
) -> f64 {
|
||||
if is_fullscreen {
|
||||
return self.compute_new_view_offset_fit(target_x, col_x, width, is_fullscreen);
|
||||
if mode.is_fullscreen() {
|
||||
return self.compute_new_view_offset_fit(target_x, col_x, width, mode);
|
||||
}
|
||||
|
||||
let area = if mode.is_maximized() {
|
||||
self.parent_area
|
||||
} else {
|
||||
self.working_area
|
||||
};
|
||||
|
||||
// Columns wider than the view are left-aligned (the fit code can deal with that).
|
||||
if self.working_area.size.w <= width {
|
||||
return self.compute_new_view_offset_fit(target_x, col_x, width, is_fullscreen);
|
||||
if area.size.w <= width {
|
||||
return self.compute_new_view_offset_fit(target_x, col_x, width, mode);
|
||||
}
|
||||
|
||||
-(self.working_area.size.w - width) / 2. - self.working_area.loc.x
|
||||
-(area.size.w - width) / 2. - area.loc.x
|
||||
}
|
||||
|
||||
fn compute_new_view_offset_for_column_fit(&self, target_x: Option<f64>, idx: usize) -> f64 {
|
||||
@@ -578,7 +598,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
target_x,
|
||||
self.column_x(idx),
|
||||
col.width(),
|
||||
col.is_fullscreen(),
|
||||
col.sizing_mode(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -592,7 +612,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
target_x,
|
||||
self.column_x(idx),
|
||||
col.width(),
|
||||
col.is_fullscreen(),
|
||||
col.sizing_mode(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -633,6 +653,8 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
let target_col_x = self.column_x(idx);
|
||||
let target_col_width = self.columns[idx].width();
|
||||
|
||||
// NOTE: This logic won't work entirely correctly with small fixed-size maximized
|
||||
// windows (they have a different area and padding).
|
||||
let total_width = if source_col_x < target_col_x {
|
||||
// Source is left from target.
|
||||
target_col_x - source_col_x + target_col_width
|
||||
@@ -770,7 +792,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
|
||||
// A different column was activated; reset the flag.
|
||||
self.activate_prev_column_on_removal = None;
|
||||
self.view_offset_before_fullscreen = None;
|
||||
self.view_offset_to_restore = None;
|
||||
self.interactive_resize = None;
|
||||
}
|
||||
}
|
||||
@@ -855,6 +877,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
tile,
|
||||
self.view_size,
|
||||
self.working_area,
|
||||
self.parent_area,
|
||||
self.scale,
|
||||
width,
|
||||
is_full_width,
|
||||
@@ -956,6 +979,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
column.update_config(
|
||||
self.view_size,
|
||||
self.working_area,
|
||||
self.parent_area,
|
||||
self.scale,
|
||||
self.options.clone(),
|
||||
);
|
||||
@@ -1059,15 +1083,15 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
tile.animate_alpha(0., 1., movement_config);
|
||||
}
|
||||
|
||||
let was_fullscreen = column.is_fullscreen();
|
||||
let was_normal = column.sizing_mode().is_normal();
|
||||
|
||||
let tile = column.tiles.remove(tile_idx);
|
||||
column.data.remove(tile_idx);
|
||||
|
||||
// If an active column became non-fullscreen after removing the tile, clear the stored
|
||||
// unfullscreen offset.
|
||||
if column_idx == self.active_column_idx && was_fullscreen && !column.is_fullscreen() {
|
||||
self.view_offset_before_fullscreen = None;
|
||||
if column_idx == self.active_column_idx && !was_normal && column.sizing_mode().is_normal() {
|
||||
self.view_offset_to_restore = None;
|
||||
}
|
||||
|
||||
// If one window is left, reset its weight to 1.
|
||||
@@ -1171,7 +1195,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
}
|
||||
|
||||
if column_idx == self.active_column_idx {
|
||||
self.view_offset_before_fullscreen = None;
|
||||
self.view_offset_to_restore = None;
|
||||
}
|
||||
|
||||
if self.columns.is_empty() {
|
||||
@@ -1225,7 +1249,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
.enumerate()
|
||||
.find(|(_, col)| col.contains(window))
|
||||
.unwrap();
|
||||
let was_fullscreen = column.is_fullscreen();
|
||||
let was_normal = column.sizing_mode().is_normal();
|
||||
let prev_origin = column.tiles_origin();
|
||||
|
||||
let (tile_idx, tile) = column
|
||||
@@ -1337,9 +1361,9 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
}
|
||||
|
||||
// When the active column goes fullscreen, store the view offset to restore later.
|
||||
let is_fullscreen = self.columns[col_idx].is_fullscreen();
|
||||
if !was_fullscreen && is_fullscreen {
|
||||
self.view_offset_before_fullscreen = Some(self.view_offset.stationary());
|
||||
let is_normal = self.columns[col_idx].sizing_mode().is_normal();
|
||||
if was_normal && !is_normal {
|
||||
self.view_offset_to_restore = Some(self.view_offset.stationary());
|
||||
}
|
||||
|
||||
// Upon unfullscreening, restore the view offset.
|
||||
@@ -1348,11 +1372,11 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
// will unfullscreen one by one, and the column width will shrink only when the
|
||||
// last tile unfullscreens. This is when we want to restore the view offset,
|
||||
// otherwise it will immediately reset back by the animate_view_offset below.
|
||||
let unfullscreen_offset = if was_fullscreen && !is_fullscreen {
|
||||
let unfullscreen_offset = if !was_normal && is_normal {
|
||||
// Take the value unconditionally, even if the view is currently frozen by
|
||||
// a view gesture. It shouldn't linger around because it's only valid for this
|
||||
// particular unfullscreen.
|
||||
self.view_offset_before_fullscreen.take()
|
||||
self.view_offset_to_restore.take()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -2165,6 +2189,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
if col.display_mode != ColumnDisplay::Tabbed && col.tiles.len() > 1 {
|
||||
let window = col.tiles[col.active_tile_idx].window().id().clone();
|
||||
self.set_fullscreen(&window, false);
|
||||
self.set_maximized(&window, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2307,6 +2332,10 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
iter::once(active_pos).chain(offsets)
|
||||
}
|
||||
|
||||
pub fn columns(&self) -> impl Iterator<Item = &Column<W>> {
|
||||
self.columns.iter()
|
||||
}
|
||||
|
||||
fn columns_mut(&mut self) -> impl Iterator<Item = (&mut Column<W>, f64)> + '_ {
|
||||
let offsets = self.column_xs(self.data.iter().copied());
|
||||
zip(&mut self.columns, offsets)
|
||||
@@ -2474,7 +2503,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
|
||||
// Adjust for place-within-column tab indicator.
|
||||
let origin_x = col.tiles_origin().x;
|
||||
let extra_w = if is_tabbed && !col.is_fullscreen() {
|
||||
let extra_w = if is_tabbed && col.sizing_mode().is_normal() {
|
||||
col.tab_indicator.extra_size(col.tiles.len(), col.scale).w
|
||||
} else {
|
||||
0.
|
||||
@@ -2491,9 +2520,14 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
// effect here.
|
||||
if self.columns.is_empty() {
|
||||
let view_offset = if self.is_centering_focused_column() {
|
||||
self.compute_new_view_offset_centered(Some(0.), 0., hint_area.size.w, false)
|
||||
self.compute_new_view_offset_centered(
|
||||
Some(0.),
|
||||
0.,
|
||||
hint_area.size.w,
|
||||
SizingMode::Normal,
|
||||
)
|
||||
} else {
|
||||
self.compute_new_view_offset_fit(Some(0.), 0., hint_area.size.w, false)
|
||||
self.compute_new_view_offset_fit(Some(0.), 0., hint_area.size.w, SizingMode::Normal)
|
||||
};
|
||||
hint_area.loc.x -= view_offset;
|
||||
} else {
|
||||
@@ -2693,7 +2727,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
}
|
||||
|
||||
let col = &mut self.columns[self.active_column_idx];
|
||||
if col.is_pending_fullscreen || col.is_full_width {
|
||||
if !col.pending_sizing_mode().is_normal() || col.is_full_width {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2709,6 +2743,9 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: This logic won't work entirely correctly with small fixed-size maximized windows
|
||||
// (they have a different area and padding).
|
||||
|
||||
// Consider the end of an ongoing animation because that's what compute to fit does too.
|
||||
let view_x = self.target_view_pos();
|
||||
let working_x = self.working_area.loc.x;
|
||||
@@ -2812,6 +2849,37 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn set_maximized(&mut self, window: &W::Id, maximize: bool) -> bool {
|
||||
let mut col_idx = self
|
||||
.columns
|
||||
.iter()
|
||||
.position(|col| col.contains(window))
|
||||
.unwrap();
|
||||
|
||||
if maximize == self.columns[col_idx].is_pending_maximized {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut col = &mut self.columns[col_idx];
|
||||
let is_tabbed = col.display_mode == ColumnDisplay::Tabbed;
|
||||
|
||||
cancel_resize_for_column(&mut self.interactive_resize, col);
|
||||
|
||||
if maximize && (col.tiles.len() > 1 && !is_tabbed) {
|
||||
// This wasn't the only window in its column; extract it into a separate column.
|
||||
self.consume_or_expel_window_right(Some(window));
|
||||
col_idx += 1;
|
||||
col = &mut self.columns[col_idx];
|
||||
}
|
||||
|
||||
col.set_maximized(maximize);
|
||||
|
||||
// With place_within_column, the tab indicator changes the column size immediately.
|
||||
self.data[col_idx].update(col);
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn render_above_top_layer(&self) -> bool {
|
||||
// Render above the top layer if we're on a fullscreen window and the view is stationary.
|
||||
if self.columns.is_empty() {
|
||||
@@ -2822,7 +2890,9 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.columns[self.active_column_idx].is_fullscreen()
|
||||
self.columns[self.active_column_idx]
|
||||
.sizing_mode()
|
||||
.is_fullscreen()
|
||||
}
|
||||
|
||||
pub fn render_elements<R: NiriRenderer>(
|
||||
@@ -2902,7 +2972,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
let col_render_off = col.render_offset();
|
||||
|
||||
// Hit the tab indicator.
|
||||
if col.display_mode == ColumnDisplay::Tabbed && !col.is_fullscreen() {
|
||||
if col.display_mode == ColumnDisplay::Tabbed && col.sizing_mode().is_normal() {
|
||||
let col_pos = view_off + col_off + col_render_off;
|
||||
let col_pos = col_pos.to_physical_precise_round(scale).to_logical(scale);
|
||||
|
||||
@@ -3134,20 +3204,26 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
|
||||
let mut snapping_points = Vec::new();
|
||||
|
||||
let left_strut = self.working_area.loc.x;
|
||||
let right_strut = self.view_size.w - self.working_area.size.w - self.working_area.loc.x;
|
||||
|
||||
if self.is_centering_focused_column() {
|
||||
let mut col_x = 0.;
|
||||
for (col_idx, col) in self.columns.iter().enumerate() {
|
||||
let col_w = col.width();
|
||||
let mode = col.sizing_mode();
|
||||
|
||||
let view_pos = if col.is_fullscreen() {
|
||||
let area = if mode.is_maximized() {
|
||||
self.parent_area
|
||||
} else {
|
||||
self.working_area
|
||||
};
|
||||
|
||||
let left_strut = area.loc.x;
|
||||
|
||||
let view_pos = if mode.is_fullscreen() {
|
||||
col_x
|
||||
} else if self.working_area.size.w <= col_w {
|
||||
} else if area.size.w <= col_w {
|
||||
col_x - left_strut
|
||||
} else {
|
||||
col_x - (self.working_area.size.w - col_w) / 2. - left_strut
|
||||
col_x - (area.size.w - col_w) / 2. - left_strut
|
||||
};
|
||||
snapping_points.push(Snap { view_pos, col_idx });
|
||||
|
||||
@@ -3160,34 +3236,50 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
);
|
||||
|
||||
let view_width = self.view_size.w;
|
||||
let working_area_width = self.working_area.size.w;
|
||||
let gaps = self.options.layout.gaps;
|
||||
|
||||
let snap_points =
|
||||
|col_x, col: &Column<W>, prev_col_w: Option<f64>, next_col_w: Option<f64>| {
|
||||
let col_w = col.width();
|
||||
let mode = col.sizing_mode();
|
||||
|
||||
let area = if mode.is_maximized() {
|
||||
self.parent_area
|
||||
} else {
|
||||
self.working_area
|
||||
};
|
||||
|
||||
let left_strut = area.loc.x;
|
||||
let right_strut = self.view_size.w - area.size.w - area.loc.x;
|
||||
|
||||
// Normal columns align with the working area, but fullscreen columns align with
|
||||
// the view size.
|
||||
if col.is_fullscreen() {
|
||||
if mode.is_fullscreen() {
|
||||
let left = col_x;
|
||||
let right = col_x + col_w;
|
||||
let right = left + col_w;
|
||||
(left, right)
|
||||
} else {
|
||||
// Logic from compute_new_view_offset.
|
||||
let padding = ((working_area_width - col_w) / 2.).clamp(0., gaps);
|
||||
let padding = if mode.is_maximized() {
|
||||
0.
|
||||
} else {
|
||||
((area.size.w - col_w) / 2.).clamp(0., gaps)
|
||||
};
|
||||
|
||||
let center = if self.working_area.size.w <= col_w {
|
||||
let center = if area.size.w <= col_w {
|
||||
col_x - left_strut
|
||||
} else {
|
||||
col_x - (self.working_area.size.w - col_w) / 2. - left_strut
|
||||
col_x - (area.size.w - col_w) / 2. - left_strut
|
||||
};
|
||||
let is_overflowing = |adj_col_w: Option<f64>| {
|
||||
center_on_overflow
|
||||
&& adj_col_w
|
||||
.filter(|adj_col_w| {
|
||||
// NOTE: This logic won't work entirely correctly with small
|
||||
// fixed-size maximized windows (they have a different area
|
||||
// and padding).
|
||||
center_on_overflow
|
||||
&& adj_col_w + 3.0 * gaps + col_w > working_area_width
|
||||
&& adj_col_w + 3.0 * gaps + col_w > area.size.w
|
||||
})
|
||||
.is_some()
|
||||
};
|
||||
@@ -3211,6 +3303,14 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
//
|
||||
// It's ok if leftmost_snap is > rightmost_snap (this happens if the columns on a
|
||||
// workspace total up to less than the workspace width).
|
||||
|
||||
// The first column's left snap isn't actually guaranteed to be the *leftmost* snap.
|
||||
// With weird enough left strut and perhaps a maximized small fixed-size window, you
|
||||
// can make the second window's left snap be further to the left than the first
|
||||
// window's. The same goes for the rightmost snap.
|
||||
//
|
||||
// This isn't actually a big problem because it's very much an obscure edge case. Just
|
||||
// need to make sure the code doesn't panic when that happens.
|
||||
let leftmost_snap = snap_points(
|
||||
0.,
|
||||
&self.columns[0],
|
||||
@@ -3295,16 +3395,28 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
let col = &self.columns[col_idx];
|
||||
let col_x = self.column_x(col_idx);
|
||||
let col_w = col.width();
|
||||
let mode = col.sizing_mode();
|
||||
|
||||
if col.is_fullscreen() {
|
||||
let area = if mode.is_maximized() {
|
||||
self.parent_area
|
||||
} else {
|
||||
self.working_area
|
||||
};
|
||||
|
||||
let left_strut = area.loc.x;
|
||||
|
||||
if mode.is_fullscreen() {
|
||||
if target_snap.view_pos + self.view_size.w < col_x + col_w {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
let padding = ((self.working_area.size.w - col_w) / 2.)
|
||||
.clamp(0., self.options.layout.gaps);
|
||||
if target_snap.view_pos + left_strut + self.working_area.size.w
|
||||
< col_x + col_w + padding
|
||||
let padding = if mode.is_maximized() {
|
||||
0.
|
||||
} else {
|
||||
((area.size.w - col_w) / 2.).clamp(0., self.options.layout.gaps)
|
||||
};
|
||||
|
||||
if target_snap.view_pos + left_strut + area.size.w < col_x + col_w + padding
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -3317,14 +3429,27 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
let col = &self.columns[col_idx];
|
||||
let col_x = self.column_x(col_idx);
|
||||
let col_w = col.width();
|
||||
let mode = col.sizing_mode();
|
||||
|
||||
if col.is_fullscreen() {
|
||||
let area = if mode.is_maximized() {
|
||||
self.parent_area
|
||||
} else {
|
||||
self.working_area
|
||||
};
|
||||
|
||||
let left_strut = area.loc.x;
|
||||
|
||||
if mode.is_fullscreen() {
|
||||
if col_x < target_snap.view_pos {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
let padding = ((self.working_area.size.w - col_w) / 2.)
|
||||
.clamp(0., self.options.layout.gaps);
|
||||
let padding = if mode.is_maximized() {
|
||||
0.
|
||||
} else {
|
||||
((area.size.w - col_w) / 2.).clamp(0., self.options.layout.gaps)
|
||||
};
|
||||
|
||||
if col_x - padding < target_snap.view_pos + left_strut {
|
||||
break;
|
||||
}
|
||||
@@ -3339,7 +3464,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
let delta = active_col_x - new_col_x;
|
||||
|
||||
if self.active_column_idx != new_col_idx {
|
||||
self.view_offset_before_fullscreen = None;
|
||||
self.view_offset_to_restore = None;
|
||||
}
|
||||
|
||||
self.active_column_idx = new_col_idx;
|
||||
@@ -3391,7 +3516,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
.find(|col| col.contains(&window))
|
||||
.unwrap();
|
||||
|
||||
if col.is_pending_fullscreen {
|
||||
if !col.pending_sizing_mode().is_normal() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3637,11 +3762,11 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
|
||||
let col = &self.columns[self.active_column_idx];
|
||||
|
||||
if self.view_offset_before_fullscreen.is_some() {
|
||||
if self.view_offset_to_restore.is_some() {
|
||||
assert!(
|
||||
col.is_fullscreen(),
|
||||
"when view_offset_before_fullscreen is set, \
|
||||
the active column must be fullscreen"
|
||||
!col.sizing_mode().is_normal(),
|
||||
"when view_offset_to_restore is set, \
|
||||
the active column must be fullscreen or maximized"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3796,6 +3921,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
tile: Tile<W>,
|
||||
view_size: Size<f64, Logical>,
|
||||
working_area: Rectangle<f64, Logical>,
|
||||
parent_area: Rectangle<f64, Logical>,
|
||||
scale: f64,
|
||||
width: ColumnWidth,
|
||||
is_full_width: bool,
|
||||
@@ -3815,29 +3941,33 @@ impl<W: LayoutElement> Column<W> {
|
||||
width,
|
||||
preset_width_idx: None,
|
||||
is_full_width,
|
||||
is_pending_maximized: false,
|
||||
is_pending_fullscreen: false,
|
||||
display_mode,
|
||||
tab_indicator: TabIndicator::new(options.layout.tab_indicator),
|
||||
move_animation: None,
|
||||
view_size,
|
||||
working_area,
|
||||
parent_area,
|
||||
scale,
|
||||
clock: tile.clock.clone(),
|
||||
options,
|
||||
};
|
||||
|
||||
let is_pending_fullscreen = tile.window().is_pending_fullscreen();
|
||||
let pending_sizing_mode = tile.window().pending_sizing_mode();
|
||||
|
||||
rv.add_tile_at(0, tile);
|
||||
|
||||
if is_pending_fullscreen {
|
||||
rv.set_fullscreen(true);
|
||||
match pending_sizing_mode {
|
||||
SizingMode::Normal => (),
|
||||
SizingMode::Maximized => rv.set_maximized(true),
|
||||
SizingMode::Fullscreen => rv.set_fullscreen(true),
|
||||
}
|
||||
|
||||
// Animate the tab indicator for new columns.
|
||||
if display_mode == ColumnDisplay::Tabbed
|
||||
&& !rv.options.layout.tab_indicator.hide_when_single_tab
|
||||
&& !rv.is_fullscreen()
|
||||
&& rv.sizing_mode().is_normal()
|
||||
{
|
||||
// Usually new columns are created together with window movement actions. For new
|
||||
// windows, we handle that in start_open_animation().
|
||||
@@ -3852,12 +3982,16 @@ impl<W: LayoutElement> Column<W> {
|
||||
&mut self,
|
||||
view_size: Size<f64, Logical>,
|
||||
working_area: Rectangle<f64, Logical>,
|
||||
parent_area: Rectangle<f64, Logical>,
|
||||
scale: f64,
|
||||
options: Rc<Options>,
|
||||
) {
|
||||
let mut update_sizes = false;
|
||||
|
||||
if self.view_size != view_size || self.working_area != working_area {
|
||||
if self.view_size != view_size
|
||||
|| self.working_area != working_area
|
||||
|| self.parent_area != parent_area
|
||||
{
|
||||
update_sizes = true;
|
||||
}
|
||||
|
||||
@@ -3895,6 +4029,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
.update_config(options.layout.tab_indicator);
|
||||
self.view_size = view_size;
|
||||
self.working_area = working_area;
|
||||
self.parent_area = parent_area;
|
||||
self.scale = scale;
|
||||
self.options = options;
|
||||
|
||||
@@ -3954,7 +4089,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
// you don't want that to happen in fullscreen. Also, laying things out correctly when the
|
||||
// tab indicator is within the column and the column goes fullscreen, would require too
|
||||
// many changes to the code for too little benefit (it's mostly invisible anyway).
|
||||
let enabled = self.display_mode == ColumnDisplay::Tabbed && !self.is_fullscreen();
|
||||
let enabled = self.display_mode == ColumnDisplay::Tabbed && self.sizing_mode().is_normal();
|
||||
|
||||
self.tab_indicator.update_render_elements(
|
||||
enabled,
|
||||
@@ -3967,6 +4102,24 @@ impl<W: LayoutElement> Column<W> {
|
||||
);
|
||||
}
|
||||
|
||||
pub fn is_pending_fullscreen(&self) -> bool {
|
||||
self.is_pending_fullscreen
|
||||
}
|
||||
|
||||
pub fn is_pending_maximized(&self) -> bool {
|
||||
self.is_pending_maximized
|
||||
}
|
||||
|
||||
pub fn pending_sizing_mode(&self) -> SizingMode {
|
||||
if self.is_pending_fullscreen {
|
||||
SizingMode::Fullscreen
|
||||
} else if self.is_pending_maximized {
|
||||
SizingMode::Maximized
|
||||
} else {
|
||||
SizingMode::Normal
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_offset(&self) -> Point<f64, Logical> {
|
||||
let mut offset = Point::from((0., 0.));
|
||||
|
||||
@@ -4040,7 +4193,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
/// - is_fullscreen() can suddenly change when consuming/expelling a fullscreen tile into/from a
|
||||
/// non-fullscreen column. This can influence the code that saves/restores the unfullscreen
|
||||
/// view offset.
|
||||
fn is_fullscreen(&self) -> bool {
|
||||
fn sizing_mode(&self) -> SizingMode {
|
||||
// Behaviors that we want:
|
||||
//
|
||||
// 1. The common case: single tile in a column. Assume no animations. Fullscreening the tile
|
||||
@@ -4058,7 +4211,23 @@ impl<W: LayoutElement> Column<W> {
|
||||
// mode change applies instantly).
|
||||
//
|
||||
// The logic that satisfies these behaviors is to check if *any* tile is fullscreen.
|
||||
self.tiles.iter().any(|tile| tile.is_fullscreen())
|
||||
let mut any_fullscreen = false;
|
||||
let mut any_maximized = false;
|
||||
for tile in &self.tiles {
|
||||
match tile.sizing_mode() {
|
||||
SizingMode::Normal => (),
|
||||
SizingMode::Maximized => any_maximized = true,
|
||||
SizingMode::Fullscreen => any_fullscreen = true,
|
||||
}
|
||||
}
|
||||
|
||||
if any_fullscreen {
|
||||
SizingMode::Fullscreen
|
||||
} else if any_maximized {
|
||||
SizingMode::Maximized
|
||||
} else {
|
||||
SizingMode::Normal
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains(&self, window: &W::Id) -> bool {
|
||||
@@ -4102,6 +4271,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
|
||||
if self.display_mode != ColumnDisplay::Tabbed {
|
||||
self.is_pending_fullscreen = false;
|
||||
self.is_pending_maximized = false;
|
||||
}
|
||||
|
||||
self.data
|
||||
@@ -4213,7 +4383,8 @@ impl<W: LayoutElement> Column<W> {
|
||||
}
|
||||
|
||||
fn update_tile_sizes_with_transaction(&mut self, animate: bool, transaction: Transaction) {
|
||||
if self.is_pending_fullscreen {
|
||||
let sizing_mode = self.pending_sizing_mode();
|
||||
if matches!(sizing_mode, SizingMode::Fullscreen | SizingMode::Maximized) {
|
||||
for (tile_idx, tile) in self.tiles.iter_mut().enumerate() {
|
||||
// In tabbed mode, only the visible window participates in the transaction.
|
||||
let is_active = tile_idx == self.active_tile_idx;
|
||||
@@ -4223,7 +4394,11 @@ impl<W: LayoutElement> Column<W> {
|
||||
Some(transaction.clone())
|
||||
};
|
||||
|
||||
tile.request_fullscreen(animate, transaction);
|
||||
if matches!(sizing_mode, SizingMode::Fullscreen) {
|
||||
tile.request_fullscreen(animate, transaction);
|
||||
} else {
|
||||
tile.request_maximized(self.parent_area.size, animate, transaction);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -4510,7 +4685,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
.map(NotNan::into_inner)
|
||||
.unwrap();
|
||||
|
||||
if self.display_mode == ColumnDisplay::Tabbed && !self.is_fullscreen() {
|
||||
if self.display_mode == ColumnDisplay::Tabbed && self.sizing_mode().is_normal() {
|
||||
let extra_size = self.tab_indicator.extra_size(self.tiles.len(), self.scale);
|
||||
tiles_width += extra_size.w;
|
||||
}
|
||||
@@ -4875,6 +5050,19 @@ impl<W: LayoutElement> Column<W> {
|
||||
self.update_tile_sizes(true);
|
||||
}
|
||||
|
||||
fn set_maximized(&mut self, maximize: bool) {
|
||||
if self.is_pending_maximized == maximize {
|
||||
return;
|
||||
}
|
||||
|
||||
if maximize {
|
||||
assert!(self.tiles.len() == 1 || self.display_mode == ColumnDisplay::Tabbed);
|
||||
}
|
||||
|
||||
self.is_pending_maximized = maximize;
|
||||
self.update_tile_sizes(true);
|
||||
}
|
||||
|
||||
fn set_column_display(&mut self, display: ColumnDisplay) {
|
||||
if self.display_mode == display {
|
||||
return;
|
||||
@@ -4936,8 +5124,13 @@ impl<W: LayoutElement> Column<W> {
|
||||
fn tiles_origin(&self) -> Point<f64, Logical> {
|
||||
let mut origin = Point::from((0., 0.));
|
||||
|
||||
if self.is_fullscreen() {
|
||||
return origin;
|
||||
match self.sizing_mode() {
|
||||
SizingMode::Normal => (),
|
||||
SizingMode::Maximized => {
|
||||
origin.y += self.parent_area.loc.y;
|
||||
return origin;
|
||||
}
|
||||
SizingMode::Fullscreen => return origin,
|
||||
}
|
||||
|
||||
origin.y += self.working_area.loc.y + self.options.layout.gaps;
|
||||
@@ -5096,7 +5289,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
|
||||
// Animate the appearance of the tab indicator.
|
||||
if self.display_mode == ColumnDisplay::Tabbed
|
||||
&& !self.is_fullscreen()
|
||||
&& self.sizing_mode().is_normal()
|
||||
&& self.tiles.len() == 1
|
||||
&& !self.tab_indicator.config().hide_when_single_tab
|
||||
{
|
||||
@@ -5119,7 +5312,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
assert!(self.active_tile_idx < self.tiles.len());
|
||||
assert_eq!(self.tiles.len(), self.data.len());
|
||||
|
||||
if self.is_pending_fullscreen {
|
||||
if !self.pending_sizing_mode().is_normal() {
|
||||
assert!(self.tiles.len() == 1 || self.display_mode == ColumnDisplay::Tabbed);
|
||||
}
|
||||
|
||||
@@ -5151,8 +5344,8 @@ impl<W: LayoutElement> Column<W> {
|
||||
assert_eq!(self.clock, tile.clock);
|
||||
assert_eq!(self.scale, tile.scale());
|
||||
assert_eq!(
|
||||
self.is_pending_fullscreen,
|
||||
tile.window().is_pending_fullscreen()
|
||||
self.pending_sizing_mode(),
|
||||
tile.window().pending_sizing_mode()
|
||||
);
|
||||
assert_eq!(self.view_size, tile.view_size());
|
||||
tile.verify_invariants();
|
||||
@@ -5178,7 +5371,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
tile.tile_height_for_window_height(f64::from(requested_size.h));
|
||||
let min_tile_height = f64::max(1., tile.min_size_nonfullscreen().h);
|
||||
|
||||
if !self.is_pending_fullscreen
|
||||
if self.pending_sizing_mode().is_normal()
|
||||
&& self.scale.round() == self.scale
|
||||
&& working_size.h.round() == working_size.h
|
||||
&& gaps.round() == gaps
|
||||
|
||||
+142
-21
@@ -33,9 +33,9 @@ struct TestWindowInner {
|
||||
forced_size: Cell<Option<Size<i32, Logical>>>,
|
||||
min_size: Size<i32, Logical>,
|
||||
max_size: Size<i32, Logical>,
|
||||
pending_fullscreen: Cell<bool>,
|
||||
pending_sizing_mode: Cell<SizingMode>,
|
||||
pending_activated: Cell<bool>,
|
||||
is_fullscreen: Cell<bool>,
|
||||
sizing_mode: Cell<SizingMode>,
|
||||
is_windowed_fullscreen: Cell<bool>,
|
||||
is_pending_windowed_fullscreen: Cell<bool>,
|
||||
animate_next_configure: Cell<bool>,
|
||||
@@ -81,9 +81,9 @@ impl TestWindow {
|
||||
forced_size: Cell::new(None),
|
||||
min_size: params.min_max_size.0,
|
||||
max_size: params.min_max_size.1,
|
||||
pending_fullscreen: Cell::new(false),
|
||||
pending_sizing_mode: Cell::new(SizingMode::Normal),
|
||||
pending_activated: Cell::new(false),
|
||||
is_fullscreen: Cell::new(false),
|
||||
sizing_mode: Cell::new(SizingMode::Normal),
|
||||
is_windowed_fullscreen: Cell::new(false),
|
||||
is_pending_windowed_fullscreen: Cell::new(false),
|
||||
animate_next_configure: Cell::new(false),
|
||||
@@ -126,8 +126,8 @@ impl TestWindow {
|
||||
|
||||
self.0.animate_next_configure.set(false);
|
||||
|
||||
if self.0.is_fullscreen.get() != self.0.pending_fullscreen.get() {
|
||||
self.0.is_fullscreen.set(self.0.pending_fullscreen.get());
|
||||
if self.0.sizing_mode.get() != self.0.pending_sizing_mode.get() {
|
||||
self.0.sizing_mode.set(self.0.pending_sizing_mode.get());
|
||||
changed = true;
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ impl LayoutElement for TestWindow {
|
||||
fn request_size(
|
||||
&mut self,
|
||||
size: Size<i32, Logical>,
|
||||
is_fullscreen: bool,
|
||||
mode: SizingMode,
|
||||
_animate: bool,
|
||||
_transaction: Option<Transaction>,
|
||||
) {
|
||||
@@ -184,9 +184,9 @@ impl LayoutElement for TestWindow {
|
||||
self.0.animate_next_configure.set(true);
|
||||
}
|
||||
|
||||
self.0.pending_fullscreen.set(is_fullscreen);
|
||||
self.0.pending_sizing_mode.set(mode);
|
||||
|
||||
if is_fullscreen {
|
||||
if mode.is_fullscreen() {
|
||||
self.0.is_pending_windowed_fullscreen.set(false);
|
||||
}
|
||||
}
|
||||
@@ -235,20 +235,12 @@ impl LayoutElement for TestWindow {
|
||||
|
||||
fn set_floating(&mut self, _floating: bool) {}
|
||||
|
||||
fn is_fullscreen(&self) -> bool {
|
||||
if self.0.is_windowed_fullscreen.get() {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.0.is_fullscreen.get()
|
||||
fn sizing_mode(&self) -> SizingMode {
|
||||
self.0.sizing_mode.get()
|
||||
}
|
||||
|
||||
fn is_pending_fullscreen(&self) -> bool {
|
||||
if self.0.is_pending_windowed_fullscreen.get() {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.0.pending_fullscreen.get()
|
||||
fn pending_sizing_mode(&self) -> SizingMode {
|
||||
self.0.pending_sizing_mode.get()
|
||||
}
|
||||
|
||||
fn requested_size(&self) -> Option<Size<i32, Logical>> {
|
||||
@@ -585,6 +577,10 @@ enum Op {
|
||||
id: Option<usize>,
|
||||
},
|
||||
MaximizeColumn,
|
||||
MaximizeWindowToEdges {
|
||||
#[proptest(strategy = "proptest::option::of(1..=5usize)")]
|
||||
id: Option<usize>,
|
||||
},
|
||||
SetColumnWidth(#[proptest(strategy = "arbitrary_size_change()")] SizeChange),
|
||||
SetWindowWidth {
|
||||
#[proptest(strategy = "proptest::option::of(1..=5usize)")]
|
||||
@@ -1310,6 +1306,16 @@ impl Op {
|
||||
layout.toggle_window_height(id.as_ref(), false);
|
||||
}
|
||||
Op::MaximizeColumn => layout.toggle_full_width(),
|
||||
Op::MaximizeWindowToEdges { id } => {
|
||||
let id = id.or_else(|| layout.focus().map(|win| *win.id()));
|
||||
let Some(id) = id else {
|
||||
return;
|
||||
};
|
||||
if !layout.has_window(&id) {
|
||||
return;
|
||||
}
|
||||
layout.toggle_maximized(&id);
|
||||
}
|
||||
Op::SetColumnWidth(change) => layout.set_column_width(change),
|
||||
Op::SetWindowWidth { id, change } => {
|
||||
let id = id.filter(|id| layout.has_window(id));
|
||||
@@ -1674,6 +1680,9 @@ fn operations_dont_panic() {
|
||||
Op::FullscreenWindow(1),
|
||||
Op::FullscreenWindow(2),
|
||||
Op::FullscreenWindow(3),
|
||||
Op::MaximizeWindowToEdges { id: Some(1) },
|
||||
Op::MaximizeWindowToEdges { id: Some(2) },
|
||||
Op::MaximizeWindowToEdges { id: Some(3) },
|
||||
Op::FocusColumnLeft,
|
||||
Op::FocusColumnRight,
|
||||
Op::FocusColumnRightOrFirst,
|
||||
@@ -1829,6 +1838,9 @@ fn operations_from_starting_state_dont_panic() {
|
||||
Op::FullscreenWindow(1),
|
||||
Op::FullscreenWindow(2),
|
||||
Op::FullscreenWindow(3),
|
||||
Op::MaximizeWindowToEdges { id: Some(1) },
|
||||
Op::MaximizeWindowToEdges { id: Some(2) },
|
||||
Op::MaximizeWindowToEdges { id: Some(3) },
|
||||
Op::SetFullscreenWindow {
|
||||
window: 1,
|
||||
is_fullscreen: false,
|
||||
@@ -3492,6 +3504,115 @@ fn move_column_to_workspace_focus_false_on_floating_window() {
|
||||
assert_eq!(monitors[0].active_workspace_idx, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn restore_to_floating_persists_across_fullscreen_maximize() {
|
||||
let ops = [
|
||||
Op::AddOutput(1),
|
||||
Op::AddWindow {
|
||||
params: TestWindowParams::new(1),
|
||||
},
|
||||
Op::ToggleWindowFloating { id: None },
|
||||
// Maximize then fullscreen.
|
||||
Op::MaximizeWindowToEdges { id: None },
|
||||
Op::FullscreenWindow(1),
|
||||
// Unfullscreen.
|
||||
Op::FullscreenWindow(1),
|
||||
];
|
||||
|
||||
let mut layout = check_ops(ops);
|
||||
|
||||
// Unfullscreening should return the window to the maximized state.
|
||||
let scrolling = layout.active_workspace().unwrap().scrolling();
|
||||
assert!(scrolling.tiles().next().is_some());
|
||||
|
||||
let ops = [
|
||||
// Unmaximize.
|
||||
Op::MaximizeWindowToEdges { id: None },
|
||||
];
|
||||
check_ops_on_layout(&mut layout, ops);
|
||||
|
||||
// Unmaximize should return the window back to floating.
|
||||
let scrolling = layout.active_workspace().unwrap().scrolling();
|
||||
assert!(scrolling.tiles().next().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unmaximize_during_fullscreen_does_not_float() {
|
||||
let ops = [
|
||||
Op::AddOutput(1),
|
||||
Op::AddWindow {
|
||||
params: TestWindowParams::new(1),
|
||||
},
|
||||
Op::ToggleWindowFloating { id: None },
|
||||
// Maximize then fullscreen.
|
||||
Op::MaximizeWindowToEdges { id: None },
|
||||
Op::FullscreenWindow(1),
|
||||
// Unmaximize.
|
||||
Op::MaximizeWindowToEdges { id: None },
|
||||
];
|
||||
|
||||
let mut layout = check_ops(ops);
|
||||
|
||||
// Unmaximize shouldn't have changed the window state since it's fullscreen.
|
||||
let scrolling = layout.active_workspace().unwrap().scrolling();
|
||||
assert!(scrolling.tiles().next().is_some());
|
||||
|
||||
let ops = [
|
||||
// Unfullscreen.
|
||||
Op::FullscreenWindow(1),
|
||||
];
|
||||
check_ops_on_layout(&mut layout, ops);
|
||||
|
||||
// Unfullscreen should return the window back to floating.
|
||||
let scrolling = layout.active_workspace().unwrap().scrolling();
|
||||
assert!(scrolling.tiles().next().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn move_column_to_workspace_maximize_and_fullscreen() {
|
||||
let ops = [
|
||||
Op::AddOutput(1),
|
||||
Op::AddWindow {
|
||||
params: TestWindowParams::new(1),
|
||||
},
|
||||
Op::MaximizeWindowToEdges { id: None },
|
||||
Op::FullscreenWindow(1),
|
||||
Op::MoveColumnToWorkspaceDown(true),
|
||||
Op::FullscreenWindow(1),
|
||||
];
|
||||
|
||||
let layout = check_ops(ops);
|
||||
let (_, win) = layout.windows().next().unwrap();
|
||||
|
||||
// Unfullscreening should return to maximized because the window was maximized before.
|
||||
assert_eq!(win.pending_sizing_mode(), SizingMode::Maximized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn move_window_to_workspace_maximize_and_fullscreen() {
|
||||
let ops = [
|
||||
Op::AddOutput(1),
|
||||
Op::AddWindow {
|
||||
params: TestWindowParams::new(1),
|
||||
},
|
||||
Op::MaximizeWindowToEdges { id: None },
|
||||
Op::FullscreenWindow(1),
|
||||
Op::MoveWindowToWorkspaceDown(true),
|
||||
Op::FullscreenWindow(1),
|
||||
];
|
||||
|
||||
let layout = check_ops(ops);
|
||||
let (_, win) = layout.windows().next().unwrap();
|
||||
|
||||
// Unfullscreening should return to maximized because the window was maximized before.
|
||||
//
|
||||
// FIXME: it currently doesn't because windows themselves can only be either fullscreen or
|
||||
// maximized. So when a window is fullscreen, whether it is also maximized or not is stored in
|
||||
// the column. MoveWindowToWorkspace removes the window from the column and this information is
|
||||
// forgotten.
|
||||
assert_eq!(win.pending_sizing_mode(), SizingMode::Normal);
|
||||
}
|
||||
|
||||
fn parent_id_causes_loop(layout: &Layout<TestWindow>, id: usize, mut parent_id: usize) -> bool {
|
||||
if parent_id == id {
|
||||
return true;
|
||||
|
||||
+124
-47
@@ -16,6 +16,7 @@ use super::{
|
||||
SizeFrac, RESIZE_ANIMATION_THRESHOLD,
|
||||
};
|
||||
use crate::animation::{Animation, Clock};
|
||||
use crate::layout::SizingMode;
|
||||
use crate::niri_render_elements;
|
||||
use crate::render_helpers::border::BorderRenderElement;
|
||||
use crate::render_helpers::clipped_surface::{ClippedSurfaceRenderElement, RoundedCornerDamage};
|
||||
@@ -45,17 +46,17 @@ pub struct Tile<W: LayoutElement> {
|
||||
/// The shadow around the window.
|
||||
shadow: Shadow,
|
||||
|
||||
/// Whether this tile is fullscreen.
|
||||
/// This tile's current sizing mode.
|
||||
///
|
||||
/// This will update only when the `window` actually goes fullscreen, rather than right away,
|
||||
/// to avoid black backdrop flicker before the window has had a chance to resize.
|
||||
is_fullscreen: bool,
|
||||
/// This will update only when the `window` actually goes maximized or fullscreen, rather than
|
||||
/// right away, to avoid black backdrop flicker before the window has had a chance to resize.
|
||||
sizing_mode: SizingMode,
|
||||
|
||||
/// The black backdrop for fullscreen windows.
|
||||
fullscreen_backdrop: SolidColorBuffer,
|
||||
|
||||
/// Whether the tile should float upon unfullscreening.
|
||||
pub(super) unfullscreen_to_floating: bool,
|
||||
pub(super) restore_to_floating: bool,
|
||||
|
||||
/// The size that the window should assume when going floating.
|
||||
///
|
||||
@@ -146,6 +147,8 @@ struct ResizeAnimation {
|
||||
// Note that this can be set even if this specific resize is between two non-fullscreen states,
|
||||
// for example when issuing a new resize during an unfullscreen resize.
|
||||
fullscreen_progress: Option<Animation>,
|
||||
// Similar to above but for fullscreen-or-maximized.
|
||||
expanded_progress: Option<Animation>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -178,16 +181,16 @@ impl<W: LayoutElement> Tile<W> {
|
||||
let border_config = options.layout.border.merged_with(&rules.border);
|
||||
let focus_ring_config = options.layout.focus_ring.merged_with(&rules.focus_ring);
|
||||
let shadow_config = options.layout.shadow.merged_with(&rules.shadow);
|
||||
let is_fullscreen = window.is_fullscreen();
|
||||
let sizing_mode = window.sizing_mode();
|
||||
|
||||
Self {
|
||||
window,
|
||||
border: FocusRing::new(border_config.into()),
|
||||
focus_ring: FocusRing::new(focus_ring_config),
|
||||
shadow: Shadow::new(shadow_config),
|
||||
is_fullscreen,
|
||||
sizing_mode,
|
||||
fullscreen_backdrop: SolidColorBuffer::new((0., 0.), [0., 0., 0., 1.]),
|
||||
unfullscreen_to_floating: false,
|
||||
restore_to_floating: false,
|
||||
floating_window_size: None,
|
||||
floating_pos: None,
|
||||
floating_preset_width_idx: None,
|
||||
@@ -248,8 +251,8 @@ impl<W: LayoutElement> Tile<W> {
|
||||
}
|
||||
|
||||
pub fn update_window(&mut self) {
|
||||
let was_fullscreen = self.is_fullscreen;
|
||||
self.is_fullscreen = self.window.is_fullscreen();
|
||||
let prev_sizing_mode = self.sizing_mode;
|
||||
self.sizing_mode = self.window.sizing_mode();
|
||||
|
||||
if let Some(animate_from) = self.window.take_animation_snapshot() {
|
||||
let params = if let Some(resize) = self.resize_animation.take() {
|
||||
@@ -265,10 +268,10 @@ impl<W: LayoutElement> Tile<W> {
|
||||
size.h = size_from.h + (size.h - size_from.h) * val;
|
||||
|
||||
let mut tile_size = animate_from.size;
|
||||
if was_fullscreen {
|
||||
if prev_sizing_mode.is_fullscreen() {
|
||||
tile_size.w = f64::max(tile_size.w, self.view_size.w);
|
||||
tile_size.h = f64::max(tile_size.h, self.view_size.h);
|
||||
} else if !self.border.is_off() {
|
||||
} else if prev_sizing_mode.is_normal() && !self.border.is_off() {
|
||||
let width = self.border.width();
|
||||
tile_size.w += width * 2.;
|
||||
tile_size.h += width * 2.;
|
||||
@@ -280,29 +283,56 @@ impl<W: LayoutElement> Tile<W> {
|
||||
let fullscreen_from = resize
|
||||
.fullscreen_progress
|
||||
.map(|anim| anim.clamped_value().clamp(0., 1.))
|
||||
.unwrap_or(if was_fullscreen { 1. } else { 0. });
|
||||
.unwrap_or(if prev_sizing_mode.is_fullscreen() {
|
||||
1.
|
||||
} else {
|
||||
0.
|
||||
});
|
||||
|
||||
let expanded_from = resize
|
||||
.expanded_progress
|
||||
.map(|anim| anim.clamped_value().clamp(0., 1.))
|
||||
.unwrap_or(if prev_sizing_mode.is_normal() { 0. } else { 1. });
|
||||
|
||||
// Also try to reuse the existing offscreen buffer if we have one.
|
||||
(size, tile_size, fullscreen_from, resize.offscreen)
|
||||
(
|
||||
size,
|
||||
tile_size,
|
||||
fullscreen_from,
|
||||
expanded_from,
|
||||
resize.offscreen,
|
||||
)
|
||||
} else {
|
||||
let size = animate_from.size;
|
||||
|
||||
// Compute like in tile_size().
|
||||
let mut tile_size = size;
|
||||
if was_fullscreen {
|
||||
if prev_sizing_mode.is_fullscreen() {
|
||||
tile_size.w = f64::max(tile_size.w, self.view_size.w);
|
||||
tile_size.h = f64::max(tile_size.h, self.view_size.h);
|
||||
} else if !self.border.is_off() {
|
||||
} else if prev_sizing_mode.is_normal() && !self.border.is_off() {
|
||||
let width = self.border.width();
|
||||
tile_size.w += width * 2.;
|
||||
tile_size.h += width * 2.;
|
||||
}
|
||||
|
||||
let fullscreen_from = if was_fullscreen { 1. } else { 0. };
|
||||
let fullscreen_from = if prev_sizing_mode.is_fullscreen() {
|
||||
1.
|
||||
} else {
|
||||
0.
|
||||
};
|
||||
|
||||
(size, tile_size, fullscreen_from, OffscreenBuffer::default())
|
||||
let expanded_from = if prev_sizing_mode.is_normal() { 0. } else { 1. };
|
||||
|
||||
(
|
||||
size,
|
||||
tile_size,
|
||||
fullscreen_from,
|
||||
expanded_from,
|
||||
OffscreenBuffer::default(),
|
||||
)
|
||||
};
|
||||
let (size_from, tile_size_from, fullscreen_from, offscreen) = params;
|
||||
let (size_from, tile_size_from, fullscreen_from, expanded_from, offscreen) = params;
|
||||
|
||||
let change = self.window.size().to_f64().to_point() - size_from.to_point();
|
||||
let change = f64::max(change.x.abs(), change.y.abs());
|
||||
@@ -318,9 +348,16 @@ impl<W: LayoutElement> Tile<W> {
|
||||
self.options.animations.window_resize.anim,
|
||||
);
|
||||
|
||||
let fullscreen_to = if self.is_fullscreen { 1. } else { 0. };
|
||||
let fullscreen_to = if self.sizing_mode.is_fullscreen() {
|
||||
1.
|
||||
} else {
|
||||
0.
|
||||
};
|
||||
let expanded_to = if self.sizing_mode.is_normal() { 0. } else { 1. };
|
||||
let fullscreen_progress = (fullscreen_from != fullscreen_to)
|
||||
.then(|| anim.restarted(fullscreen_from, fullscreen_to, 0.));
|
||||
let expanded_progress = (expanded_from != expanded_to)
|
||||
.then(|| anim.restarted(expanded_from, expanded_to, 0.));
|
||||
|
||||
self.resize_animation = Some(ResizeAnimation {
|
||||
anim,
|
||||
@@ -329,6 +366,7 @@ impl<W: LayoutElement> Tile<W> {
|
||||
offscreen,
|
||||
tile_size_from,
|
||||
fullscreen_progress,
|
||||
expanded_progress,
|
||||
});
|
||||
} else {
|
||||
self.resize_animation = None;
|
||||
@@ -406,7 +444,7 @@ impl<W: LayoutElement> Tile<W> {
|
||||
pub fn update_render_elements(&mut self, is_active: bool, view_rect: Rectangle<f64, Logical>) {
|
||||
let rules = self.window.rules();
|
||||
let animated_tile_size = self.animated_tile_size();
|
||||
let fullscreen_progress = self.fullscreen_progress();
|
||||
let expanded_progress = self.expanded_progress();
|
||||
|
||||
let draw_border_with_background = rules
|
||||
.draw_border_with_background
|
||||
@@ -425,7 +463,7 @@ impl<W: LayoutElement> Tile<W> {
|
||||
.map_or(CornerRadius::default(), |radius| {
|
||||
radius.expanded_by(border_width as f32)
|
||||
})
|
||||
.scaled_by(1. - fullscreen_progress as f32);
|
||||
.scaled_by(1. - expanded_progress as f32);
|
||||
self.border.update_render_elements(
|
||||
border_window_size,
|
||||
is_active,
|
||||
@@ -437,7 +475,7 @@ impl<W: LayoutElement> Tile<W> {
|
||||
),
|
||||
radius,
|
||||
self.scale,
|
||||
1. - fullscreen_progress as f32,
|
||||
1. - expanded_progress as f32,
|
||||
);
|
||||
|
||||
let radius = if self.visual_border_width().is_some() {
|
||||
@@ -446,17 +484,17 @@ impl<W: LayoutElement> Tile<W> {
|
||||
rules
|
||||
.geometry_corner_radius
|
||||
.unwrap_or_default()
|
||||
.scaled_by(1. - fullscreen_progress as f32)
|
||||
.scaled_by(1. - expanded_progress as f32)
|
||||
};
|
||||
self.shadow.update_render_elements(
|
||||
animated_tile_size,
|
||||
is_active,
|
||||
radius,
|
||||
self.scale,
|
||||
1. - fullscreen_progress as f32,
|
||||
1. - expanded_progress as f32,
|
||||
);
|
||||
|
||||
let draw_focus_ring_with_background = if self.border.is_off() && fullscreen_progress < 1. {
|
||||
let draw_focus_ring_with_background = if self.border.is_off() {
|
||||
draw_border_with_background
|
||||
} else {
|
||||
false
|
||||
@@ -470,7 +508,7 @@ impl<W: LayoutElement> Tile<W> {
|
||||
view_rect,
|
||||
radius,
|
||||
self.scale,
|
||||
1. - fullscreen_progress as f32,
|
||||
1. - expanded_progress as f32,
|
||||
);
|
||||
|
||||
self.fullscreen_backdrop.resize(animated_tile_size);
|
||||
@@ -609,8 +647,8 @@ impl<W: LayoutElement> Tile<W> {
|
||||
&mut self.window
|
||||
}
|
||||
|
||||
pub fn is_fullscreen(&self) -> bool {
|
||||
self.is_fullscreen
|
||||
pub fn sizing_mode(&self) -> SizingMode {
|
||||
self.sizing_mode
|
||||
}
|
||||
|
||||
fn fullscreen_progress(&self) -> f64 {
|
||||
@@ -620,16 +658,30 @@ impl<W: LayoutElement> Tile<W> {
|
||||
}
|
||||
}
|
||||
|
||||
if self.is_fullscreen {
|
||||
if self.sizing_mode.is_fullscreen() {
|
||||
1.
|
||||
} else {
|
||||
0.
|
||||
}
|
||||
}
|
||||
|
||||
fn expanded_progress(&self) -> f64 {
|
||||
if let Some(resize) = &self.resize_animation {
|
||||
if let Some(anim) = &resize.expanded_progress {
|
||||
return anim.clamped_value().clamp(0., 1.);
|
||||
}
|
||||
}
|
||||
|
||||
if self.sizing_mode.is_normal() {
|
||||
0.
|
||||
} else {
|
||||
1.
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `None` if the border is hidden and `Some(width)` if it should be shown.
|
||||
pub fn effective_border_width(&self) -> Option<f64> {
|
||||
if self.is_fullscreen {
|
||||
if !self.sizing_mode.is_normal() {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -645,10 +697,10 @@ impl<W: LayoutElement> Tile<W> {
|
||||
return None;
|
||||
}
|
||||
|
||||
let fullscreen_progress = self.fullscreen_progress();
|
||||
let expanded_progress = self.expanded_progress();
|
||||
|
||||
// Only hide the border when fully fullscreen to avoid jarring border appearance.
|
||||
if fullscreen_progress == 1. {
|
||||
// Only hide the border when fully expanded to avoid jarring border appearance.
|
||||
if expanded_progress == 1. {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -688,7 +740,7 @@ impl<W: LayoutElement> Tile<W> {
|
||||
pub fn tile_size(&self) -> Size<f64, Logical> {
|
||||
let mut size = self.window_size();
|
||||
|
||||
if self.is_fullscreen {
|
||||
if self.sizing_mode.is_fullscreen() {
|
||||
// Normally we'd just return the fullscreen size here, but this makes things a bit
|
||||
// nicer if a fullscreen window is bigger than the fullscreen size for some reason.
|
||||
size.w = f64::max(size.w, self.view_size.w);
|
||||
@@ -707,7 +759,7 @@ impl<W: LayoutElement> Tile<W> {
|
||||
pub fn tile_expected_or_current_size(&self) -> Size<f64, Logical> {
|
||||
let mut size = self.window_expected_or_current_size();
|
||||
|
||||
if self.is_fullscreen {
|
||||
if self.sizing_mode.is_fullscreen() {
|
||||
// Normally we'd just return the fullscreen size here, but this makes things a bit
|
||||
// nicer if a fullscreen window is bigger than the fullscreen size for some reason.
|
||||
size.w = f64::max(size.w, self.view_size.w);
|
||||
@@ -836,8 +888,12 @@ impl<W: LayoutElement> Tile<W> {
|
||||
// The size request has to be i32 unfortunately, due to Wayland. We floor here instead of
|
||||
// round to avoid situations where proportionally-sized columns don't fit on the screen
|
||||
// exactly.
|
||||
self.window
|
||||
.request_size(size.to_i32_floor(), false, animate, transaction);
|
||||
self.window.request_size(
|
||||
size.to_i32_floor(),
|
||||
SizingMode::Normal,
|
||||
animate,
|
||||
transaction,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn tile_width_for_window_width(&self, size: f64) -> f64 {
|
||||
@@ -872,9 +928,27 @@ impl<W: LayoutElement> Tile<W> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_maximized(
|
||||
&mut self,
|
||||
size: Size<f64, Logical>,
|
||||
animate: bool,
|
||||
transaction: Option<Transaction>,
|
||||
) {
|
||||
self.window.request_size(
|
||||
size.to_i32_round(),
|
||||
SizingMode::Maximized,
|
||||
animate,
|
||||
transaction,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn request_fullscreen(&mut self, animate: bool, transaction: Option<Transaction>) {
|
||||
self.window
|
||||
.request_size(self.view_size.to_i32_round(), true, animate, transaction);
|
||||
self.window.request_size(
|
||||
self.view_size.to_i32_round(),
|
||||
SizingMode::Fullscreen,
|
||||
animate,
|
||||
transaction,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn min_size_nonfullscreen(&self) -> Size<f64, Logical> {
|
||||
@@ -933,6 +1007,7 @@ impl<W: LayoutElement> Tile<W> {
|
||||
|
||||
let scale = Scale::from(self.scale);
|
||||
let fullscreen_progress = self.fullscreen_progress();
|
||||
let expanded_progress = self.expanded_progress();
|
||||
|
||||
let win_alpha = if self.window.is_ignoring_opacity_window_rule() {
|
||||
1.
|
||||
@@ -968,7 +1043,7 @@ impl<W: LayoutElement> Tile<W> {
|
||||
let radius = rules
|
||||
.geometry_corner_radius
|
||||
.unwrap_or_default()
|
||||
.scaled_by(1. - fullscreen_progress as f32);
|
||||
.scaled_by(1. - expanded_progress as f32);
|
||||
|
||||
// If we're resizing, try to render a shader, or a fallback.
|
||||
let mut resize_shader = None;
|
||||
@@ -1153,7 +1228,7 @@ impl<W: LayoutElement> Tile<W> {
|
||||
.map_or(CornerRadius::default(), |radius| {
|
||||
radius.expanded_by(border_width as f32)
|
||||
})
|
||||
.scaled_by(1. - fullscreen_progress as f32);
|
||||
.scaled_by(1. - expanded_progress as f32);
|
||||
|
||||
let size = self.fullscreen_backdrop.size();
|
||||
let color = self.fullscreen_backdrop.color();
|
||||
@@ -1191,13 +1266,15 @@ impl<W: LayoutElement> Tile<W> {
|
||||
});
|
||||
let rv = rv.chain(elem.into_iter().flatten());
|
||||
|
||||
// Hide the focus ring when fullscreened. It's not normally visible anyway due to being
|
||||
// outside the monitor, but it is visible in the overview (which is a bit weird).
|
||||
let elem = (focus_ring && fullscreen_progress < 1.)
|
||||
// Hide the focus ring when maximized/fullscreened. It's not normally visible anyway due to
|
||||
// being outside the monitor or obscured by a solid colored bar, but it is visible under
|
||||
// semitransparent bars in maximized state (which is a bit weird) and in the overview (also
|
||||
// a bit weird).
|
||||
let elem = (focus_ring && expanded_progress < 1.)
|
||||
.then(|| self.focus_ring.render(renderer, location).map(Into::into));
|
||||
let rv = rv.chain(elem.into_iter().flatten());
|
||||
|
||||
let elem = (fullscreen_progress < 1.)
|
||||
let elem = (expanded_progress < 1.)
|
||||
.then(|| self.shadow.render(renderer, location).map(Into::into));
|
||||
rv.chain(elem.into_iter().flatten())
|
||||
}
|
||||
@@ -1328,7 +1405,7 @@ impl<W: LayoutElement> Tile<W> {
|
||||
pub fn verify_invariants(&self) {
|
||||
use approx::assert_abs_diff_eq;
|
||||
|
||||
assert_eq!(self.is_fullscreen, self.window.is_fullscreen());
|
||||
assert_eq!(self.sizing_mode, self.window.sizing_mode());
|
||||
|
||||
let scale = self.scale;
|
||||
let size = self.tile_size();
|
||||
|
||||
+106
-25
@@ -611,16 +611,16 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
is_floating: bool,
|
||||
) {
|
||||
self.enter_output_for_window(tile.window());
|
||||
tile.unfullscreen_to_floating = is_floating;
|
||||
tile.restore_to_floating = is_floating;
|
||||
|
||||
match target {
|
||||
WorkspaceAddWindowTarget::Auto => {
|
||||
// Don't steal focus from an active fullscreen window.
|
||||
let activate = activate.map_smart(|| !self.is_active_pending_fullscreen());
|
||||
|
||||
// If the tile is pending fullscreen, open it in the scrolling layout where it can
|
||||
// go fullscreen.
|
||||
if is_floating && !tile.window().is_pending_fullscreen() {
|
||||
// If the tile is pending maximized or fullscreen, open it in the scrolling layout
|
||||
// where it can do that.
|
||||
if is_floating && tile.window().pending_sizing_mode().is_normal() {
|
||||
self.floating.add_tile(tile, activate);
|
||||
|
||||
if activate || self.scrolling.is_empty() {
|
||||
@@ -649,7 +649,7 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
|
||||
let floating_has_window = self.floating.has_window(next_to);
|
||||
|
||||
if is_floating && !tile.window().is_pending_fullscreen() {
|
||||
if is_floating && tile.window().pending_sizing_mode().is_normal() {
|
||||
if floating_has_window {
|
||||
self.floating.add_tile_above(next_to, tile, activate);
|
||||
} else {
|
||||
@@ -869,6 +869,8 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
toplevel.with_pending_state(|state| {
|
||||
if state.states.contains(xdg_toplevel::State::Fullscreen) {
|
||||
state.size = Some(self.view_size.to_i32_round());
|
||||
} else if state.states.contains(xdg_toplevel::State::Maximized) {
|
||||
state.size = Some(self.working_area.size.to_i32_round());
|
||||
} else {
|
||||
let size =
|
||||
self.new_window_size(width, height, is_floating, rules, (min_size, max_size));
|
||||
@@ -1257,10 +1259,10 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
}
|
||||
|
||||
pub fn set_fullscreen(&mut self, window: &W::Id, is_fullscreen: bool) {
|
||||
let mut unfullscreen_to_floating = false;
|
||||
let mut restore_to_floating = false;
|
||||
if self.floating.has_window(window) {
|
||||
if is_fullscreen {
|
||||
unfullscreen_to_floating = true;
|
||||
restore_to_floating = true;
|
||||
self.toggle_window_floating(Some(window));
|
||||
} else {
|
||||
// Floating windows are never fullscreen, so this is an unfullscreen request for an
|
||||
@@ -1271,30 +1273,44 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
// The window is in the scrolling layout and we're requesting an unfullscreen. If it is
|
||||
// indeed fullscreen (i.e. this isn't a duplicate unfullscreen request), then we may
|
||||
// need to unfullscreen into floating.
|
||||
let tile = self
|
||||
let col = self
|
||||
.scrolling
|
||||
.tiles()
|
||||
.find(|tile| tile.window().id() == window)
|
||||
.columns()
|
||||
.find(|col| col.contains(window))
|
||||
.unwrap();
|
||||
if tile.window().is_pending_fullscreen() && tile.unfullscreen_to_floating {
|
||||
// Unfullscreen and float in one call so it has a chance to notice and request a
|
||||
// (0, 0) size, rather than the scrolling column size.
|
||||
self.toggle_window_floating(Some(window));
|
||||
return;
|
||||
|
||||
// When going from fullscreen to maximized, don't consider restore_to_floating yet.
|
||||
if col.is_pending_fullscreen() && !col.is_pending_maximized() {
|
||||
let (tile, _) = col
|
||||
.tiles()
|
||||
.find(|(tile, _)| tile.window().id() == window)
|
||||
.unwrap();
|
||||
if tile.restore_to_floating {
|
||||
// Unfullscreen and float in one call so it has a chance to notice and request a
|
||||
// (0, 0) size, rather than the scrolling column size.
|
||||
self.toggle_window_floating(Some(window));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let changed = self.scrolling.set_fullscreen(window, is_fullscreen);
|
||||
let tile = self
|
||||
.scrolling
|
||||
.tiles()
|
||||
.find(|tile| tile.window().id() == window)
|
||||
.unwrap();
|
||||
let was_normal = tile.window().pending_sizing_mode().is_normal();
|
||||
|
||||
// When going to fullscreen, remember if we should unfullscreen to floating.
|
||||
if changed && is_fullscreen {
|
||||
let tile = self
|
||||
.scrolling
|
||||
.tiles_mut()
|
||||
.find(|tile| tile.window().id() == window)
|
||||
.unwrap();
|
||||
self.scrolling.set_fullscreen(window, is_fullscreen);
|
||||
|
||||
tile.unfullscreen_to_floating = unfullscreen_to_floating;
|
||||
// When going from normal to fullscreen, remember if we should unfullscreen to floating.
|
||||
let tile = self
|
||||
.scrolling
|
||||
.tiles_mut()
|
||||
.find(|tile| tile.window().id() == window)
|
||||
.unwrap();
|
||||
if was_normal && !tile.window().pending_sizing_mode().is_normal() {
|
||||
tile.restore_to_floating = restore_to_floating;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1303,10 +1319,75 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
.tiles()
|
||||
.find(|tile| tile.window().id() == window)
|
||||
.unwrap();
|
||||
let current = tile.window().is_pending_fullscreen();
|
||||
let current = tile.window().pending_sizing_mode().is_fullscreen();
|
||||
self.set_fullscreen(window, !current);
|
||||
}
|
||||
|
||||
pub fn set_maximized(&mut self, window: &W::Id, maximize: bool) {
|
||||
let mut restore_to_floating = false;
|
||||
if self.floating.has_window(window) {
|
||||
if maximize {
|
||||
restore_to_floating = true;
|
||||
self.toggle_window_floating(Some(window));
|
||||
} else {
|
||||
// Floating windows are never maximized, so this is an unmaximize request for an
|
||||
// already unmaximized window.
|
||||
return;
|
||||
}
|
||||
} else if !maximize {
|
||||
// The window is in the scrolling layout and we're requesting to unmaximize. If it is
|
||||
// indeed maximized (i.e. this isn't a duplicate unmaximize request), then we may
|
||||
// need to unmaximize into floating.
|
||||
let tile = self
|
||||
.scrolling
|
||||
.tiles()
|
||||
.find(|tile| tile.window().id() == window)
|
||||
.unwrap();
|
||||
// The tile cannot unmaximize into fullscreen (pending_sizing_mode() will be fullscreen
|
||||
// in that case and not maximized), so this check works.
|
||||
if tile.window().pending_sizing_mode().is_maximized() && tile.restore_to_floating {
|
||||
// Unmaximize and float in one call so it has a chance to notice and request a
|
||||
// (0, 0) size, rather than the scrolling column size.
|
||||
self.toggle_window_floating(Some(window));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let tile = self
|
||||
.scrolling
|
||||
.tiles()
|
||||
.find(|tile| tile.window().id() == window)
|
||||
.unwrap();
|
||||
let was_normal = tile.window().pending_sizing_mode().is_normal();
|
||||
|
||||
self.scrolling.set_maximized(window, maximize);
|
||||
|
||||
// When going from normal to maximized, remember if we should unmaximize to floating.
|
||||
let tile = self
|
||||
.scrolling
|
||||
.tiles_mut()
|
||||
.find(|tile| tile.window().id() == window)
|
||||
.unwrap();
|
||||
if was_normal && !tile.window().pending_sizing_mode().is_normal() {
|
||||
tile.restore_to_floating = restore_to_floating;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_maximized(&mut self, window: &W::Id) {
|
||||
let mut current = false;
|
||||
|
||||
// We have to check the column property in case the window is in the scrolling layout and
|
||||
// both maximized and fullscreen. In this case, only the column knows whether it's
|
||||
// maximized.
|
||||
//
|
||||
// In the floating layout, windows cannot be maximized.
|
||||
if let Some(col) = self.scrolling.columns().find(|col| col.contains(window)) {
|
||||
current = col.is_pending_maximized();
|
||||
}
|
||||
|
||||
self.set_maximized(window, !current);
|
||||
}
|
||||
|
||||
pub fn toggle_window_floating(&mut self, id: Option<&W::Id>) {
|
||||
let active_id = self.active_window().map(|win| win.id().clone());
|
||||
let target_is_active = id.map_or(true, |id| Some(id) == active_id.as_ref());
|
||||
|
||||
+7
-6
@@ -2339,7 +2339,7 @@ impl Niri {
|
||||
let compositor_state = CompositorState::new_v6::<State>(&display_handle);
|
||||
let xdg_shell_state = XdgShellState::new_with_capabilities::<State>(
|
||||
&display_handle,
|
||||
[WmCapabilities::Fullscreen],
|
||||
[WmCapabilities::Fullscreen, WmCapabilities::Maximize],
|
||||
);
|
||||
let xdg_decoration_state =
|
||||
XdgDecorationState::new_with_filter::<State, _>(&display_handle, |client| {
|
||||
@@ -5545,11 +5545,12 @@ impl Niri {
|
||||
let _span = tracy_client::span!("Niri::screenshot_window");
|
||||
|
||||
let scale = Scale::from(output.current_scale().fractional_scale());
|
||||
let alpha = if mapped.is_fullscreen() || mapped.is_ignoring_opacity_window_rule() {
|
||||
1.
|
||||
} else {
|
||||
mapped.rules().opacity.unwrap_or(1.).clamp(0., 1.)
|
||||
};
|
||||
let alpha =
|
||||
if mapped.sizing_mode().is_fullscreen() || mapped.is_ignoring_opacity_window_rule() {
|
||||
1.
|
||||
} else {
|
||||
mapped.rules().opacity.unwrap_or(1.).clamp(0., 1.)
|
||||
};
|
||||
// FIXME: pointer.
|
||||
let elements = mapped.render(
|
||||
renderer,
|
||||
|
||||
@@ -37,6 +37,8 @@ pub trait ForeignToplevelHandler {
|
||||
fn close(&mut self, wl_surface: WlSurface);
|
||||
fn set_fullscreen(&mut self, wl_surface: WlSurface, wl_output: Option<WlOutput>);
|
||||
fn unset_fullscreen(&mut self, wl_surface: WlSurface);
|
||||
fn set_maximized(&mut self, wl_surface: WlSurface);
|
||||
fn unset_maximized(&mut self, wl_surface: WlSurface);
|
||||
}
|
||||
|
||||
struct ToplevelData {
|
||||
@@ -388,8 +390,10 @@ where
|
||||
let surface = surface.clone();
|
||||
|
||||
match request {
|
||||
zwlr_foreign_toplevel_handle_v1::Request::SetMaximized => (),
|
||||
zwlr_foreign_toplevel_handle_v1::Request::UnsetMaximized => (),
|
||||
zwlr_foreign_toplevel_handle_v1::Request::SetMaximized => state.set_maximized(surface),
|
||||
zwlr_foreign_toplevel_handle_v1::Request::UnsetMaximized => {
|
||||
state.unset_maximized(surface)
|
||||
}
|
||||
zwlr_foreign_toplevel_handle_v1::Request::SetMinimized => (),
|
||||
zwlr_foreign_toplevel_handle_v1::Request::UnsetMinimized => (),
|
||||
zwlr_foreign_toplevel_handle_v1::Request::Activate { .. } => {
|
||||
|
||||
@@ -357,6 +357,14 @@ impl Window {
|
||||
self.xdg_toplevel.unset_fullscreen();
|
||||
}
|
||||
|
||||
pub fn set_maximized(&self) {
|
||||
self.xdg_toplevel.set_maximized();
|
||||
}
|
||||
|
||||
pub fn unset_maximized(&self) {
|
||||
self.xdg_toplevel.unset_maximized();
|
||||
}
|
||||
|
||||
pub fn set_parent(&self, parent: Option<&XdgToplevel>) {
|
||||
self.xdg_toplevel.set_parent(parent);
|
||||
}
|
||||
|
||||
@@ -458,6 +458,55 @@ fn interactive_move_unfullscreen_to_floating_restores_size() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interactive_move_unmaximize_to_floating_restores_size() {
|
||||
let (mut f, id, surface) = set_up();
|
||||
|
||||
f.niri().layout.toggle_window_floating(None);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// Change size while we're floating and commit.
|
||||
let window = f.client(id).window(&surface);
|
||||
window.set_size(200, 200);
|
||||
window.ack_last_and_commit();
|
||||
f.double_roundtrip(id);
|
||||
|
||||
let _ = f.client(id).window(&surface).recent_configures();
|
||||
|
||||
let niri = f.niri();
|
||||
let mapped = niri.layout.windows().next().unwrap().1;
|
||||
let window = mapped.window.clone();
|
||||
niri.layout.set_maximized(&window, true);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// This should request a maximized size.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 1920 × 1080, bounds: 1888 × 1048, states: [Activated, Maximized]"
|
||||
);
|
||||
|
||||
// Start an interactive move which causes an unmaximize into floating.
|
||||
let output = f.niri_output(1);
|
||||
let niri = f.niri();
|
||||
let mapped = niri.layout.windows().next().unwrap().1;
|
||||
let window = mapped.window.clone();
|
||||
niri.layout
|
||||
.interactive_move_begin(window.clone(), &output, Point::default());
|
||||
niri.layout.interactive_move_update(
|
||||
&window,
|
||||
Point::from((1000., 0.)),
|
||||
output,
|
||||
Point::default(),
|
||||
);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// This should request the stored floating size (200 × 200).
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 200 × 200, bounds: 1920 × 1080, states: [Activated]"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resize_during_interactive_move_propagates_to_floating() {
|
||||
let (mut f, id, surface) = set_up();
|
||||
@@ -791,6 +840,66 @@ fn floating_doesnt_store_fullscreen_size() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn floating_doesnt_store_maximized_size() {
|
||||
let mut f = Fixture::new();
|
||||
f.add_output(1, (1920, 1080));
|
||||
f.add_output(2, (1280, 720));
|
||||
|
||||
// Open a window maximized.
|
||||
let id = f.add_client();
|
||||
let window = f.client(id).create_window();
|
||||
let surface = window.surface.clone();
|
||||
window.set_maximized();
|
||||
window.commit();
|
||||
f.roundtrip(id);
|
||||
|
||||
let window = f.client(id).window(&surface);
|
||||
window.attach_new_buffer();
|
||||
window.set_size(1920, 1080);
|
||||
window.ack_last_and_commit();
|
||||
f.double_roundtrip(id);
|
||||
|
||||
let _ = f.client(id).window(&surface).recent_configures();
|
||||
|
||||
// Make it floating.
|
||||
f.niri().layout.toggle_window_floating(None);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// This should request 0 × 0 to unmaximize.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 0 × 0, bounds: 1920 × 1080, states: [Activated]"
|
||||
);
|
||||
|
||||
// Without committing, make it tiling again. We never committed while floating, so there's no
|
||||
// floating size to remember.
|
||||
f.niri().layout.toggle_window_floating(None);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// This should request the tiled size.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 1920 × 1048, bounds: 1888 × 1048, states: [Activated]"
|
||||
);
|
||||
|
||||
// Commit in response.
|
||||
let window = f.client(id).window(&surface);
|
||||
window.set_size(100, 100);
|
||||
window.ack_last_and_commit();
|
||||
f.roundtrip(id);
|
||||
|
||||
// Make the window floating again.
|
||||
f.niri().layout.toggle_window_floating(None);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// This shouldn't request any size change, particularly not the maximized size.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 100 × 100, bounds: 1920 × 1080, states: [Activated]"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn floating_respects_non_fixed_min_max_rule() {
|
||||
let config = r##"
|
||||
@@ -888,6 +997,33 @@ fn unfullscreen_to_floating_doesnt_send_extra_configure() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unmaximize_to_floating_doesnt_send_extra_configure() {
|
||||
let (mut f, id, surface) = set_up();
|
||||
|
||||
// Make it floating.
|
||||
f.niri().layout.toggle_window_floating(None);
|
||||
f.roundtrip(id);
|
||||
|
||||
// Maximize.
|
||||
let window = f.client(id).window(&surface);
|
||||
window.set_maximized();
|
||||
f.double_roundtrip(id);
|
||||
|
||||
let _ = f.client(id).window(&surface).recent_configures();
|
||||
|
||||
// Unmaximzie via the window request which requires a configure response.
|
||||
let window = f.client(id).window(&surface);
|
||||
window.unset_maximized();
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// This should configure only once and not twice.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 936 × 1048, bounds: 1920 × 1080, states: [Activated]"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unfullscreen_to_same_size_floating() {
|
||||
let (mut f, id, surface) = set_up();
|
||||
@@ -926,6 +1062,44 @@ fn unfullscreen_to_same_size_floating() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unmaximize_to_same_size_floating() {
|
||||
let (mut f, id, surface) = set_up();
|
||||
|
||||
// Make it floating.
|
||||
f.niri().layout.toggle_window_floating(None);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// Change size to the same as maximized, make niri remember it.
|
||||
let window = f.client(id).window(&surface);
|
||||
window.set_size(1920, 1080);
|
||||
window.ack_last_and_commit();
|
||||
f.double_roundtrip(id);
|
||||
|
||||
let _ = f.client(id).window(&surface).recent_configures();
|
||||
|
||||
// Maximize.
|
||||
let window = f.client(id).window(&surface);
|
||||
window.set_maximized();
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// The maximize configure.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 1920 × 1080, bounds: 1888 × 1048, states: [Activated, Maximized]"
|
||||
);
|
||||
|
||||
// Unmaximize into floating.
|
||||
f.niri().layout.toggle_window_floating(None);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// We should see a configure with the same size and no maximized state.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 1920 × 1080, bounds: 1920 × 1080, states: [Activated]"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unfullscreen_to_same_size_windowed_fullscreen_floating() {
|
||||
let (mut f, id, surface) = set_up();
|
||||
@@ -967,6 +1141,67 @@ fn unfullscreen_to_same_size_windowed_fullscreen_floating() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unmaximize_to_same_size_windowed_fullscreen_floating() {
|
||||
let (mut f, id, surface) = set_up();
|
||||
|
||||
let mapped = f.niri().layout.windows().next().unwrap().1;
|
||||
let window_id = mapped.window.clone();
|
||||
|
||||
// Make it floating.
|
||||
f.niri().layout.toggle_window_floating(None);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// Change size to the same as maximized, make niri remember it.
|
||||
let window = f.client(id).window(&surface);
|
||||
window.set_size(1920, 1080);
|
||||
window.ack_last_and_commit();
|
||||
f.double_roundtrip(id);
|
||||
|
||||
let _ = f.client(id).window(&surface).recent_configures();
|
||||
|
||||
// Maximize.
|
||||
let window = f.client(id).window(&surface);
|
||||
window.set_maximized();
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// The maximize configure.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 1920 × 1080, bounds: 1888 × 1048, states: [Activated, Maximized]"
|
||||
);
|
||||
|
||||
// Enable windowed-fullscreen.
|
||||
f.niri().layout.toggle_windowed_fullscreen(&window_id);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// The windowed-fullscreen configure.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 1920 × 1080, bounds: 1888 × 1048, states: [Activated, Fullscreen]"
|
||||
);
|
||||
|
||||
// Go back to windowed-fullscreen floating.
|
||||
f.niri().layout.toggle_window_floating(None);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// Should send configure because the bounds have changed.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 1920 × 1080, bounds: 1920 × 1080, states: [Activated, Fullscreen]"
|
||||
);
|
||||
|
||||
// Disable windowed-fullscreen.
|
||||
f.niri().layout.toggle_windowed_fullscreen(&window_id);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// Should send configure dropping the Fullscreen state.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 1920 × 1080, bounds: 1920 × 1080, states: [Activated]"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unfullscreen_to_same_size_same_bounds_floating() {
|
||||
let config = r##"
|
||||
@@ -1011,6 +1246,50 @@ layout {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unmaximize_to_same_size_same_bounds_floating() {
|
||||
let config = r##"
|
||||
layout {
|
||||
gaps 0
|
||||
}
|
||||
"##;
|
||||
let config = Config::parse_mem(config).unwrap();
|
||||
let (mut f, id, surface) = set_up_with_config(config);
|
||||
|
||||
// Make it floating.
|
||||
f.niri().layout.toggle_window_floating(None);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// Change size to the same as fullscreen, make niri remember it.
|
||||
let window = f.client(id).window(&surface);
|
||||
window.set_size(1920, 1080);
|
||||
window.ack_last_and_commit();
|
||||
f.double_roundtrip(id);
|
||||
|
||||
let _ = f.client(id).window(&surface).recent_configures();
|
||||
|
||||
// Maximize.
|
||||
let window = f.client(id).window(&surface);
|
||||
window.set_maximized();
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// The maximize configure.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 1920 × 1080, bounds: 1920 × 1080, states: [Activated, Maximized]"
|
||||
);
|
||||
|
||||
// Unmaximize into floating.
|
||||
f.niri().layout.toggle_window_floating(None);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// We should see a configure with the same size and no Maximized state.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 1920 × 1080, bounds: 1920 × 1080, states: [Activated]"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn repeated_size_request() {
|
||||
let (mut f, id, surface) = set_up();
|
||||
|
||||
+41
-1
@@ -127,7 +127,7 @@ fn windowed_fullscreen_chain() {
|
||||
let mapped = f.niri().layout.windows().next().unwrap().1;
|
||||
format!(
|
||||
"fs {}, wfs {}",
|
||||
mapped.is_fullscreen(),
|
||||
mapped.sizing_mode().is_fullscreen(),
|
||||
mapped.is_windowed_fullscreen()
|
||||
)
|
||||
};
|
||||
@@ -255,3 +255,43 @@ fn interactive_move_unfullscreen_to_scrolling_restores_size() {
|
||||
@"size: 936 × 1048, bounds: 1920 × 1080, states: [Activated]"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interactive_move_unmaximize_to_scrolling_restores_size() {
|
||||
let (mut f, id, surface) = set_up();
|
||||
|
||||
let _ = f.client(id).window(&surface).recent_configures();
|
||||
|
||||
let niri = f.niri();
|
||||
let mapped = niri.layout.windows().next().unwrap().1;
|
||||
let window = mapped.window.clone();
|
||||
niri.layout.set_maximized(&window, true);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// This should request a maximized size.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 1920 × 1080, bounds: 1888 × 1048, states: [Activated, Maximized]"
|
||||
);
|
||||
|
||||
// Start an interactive move which causes an unmaximize.
|
||||
let output = f.niri_output(1);
|
||||
let niri = f.niri();
|
||||
let mapped = niri.layout.windows().next().unwrap().1;
|
||||
let window = mapped.window.clone();
|
||||
niri.layout
|
||||
.interactive_move_begin(window.clone(), &output, Point::default());
|
||||
niri.layout.interactive_move_update(
|
||||
&window,
|
||||
Point::from((1000., 0.)),
|
||||
output,
|
||||
Point::default(),
|
||||
);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// This should request the tiled size.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 936 × 1048, bounds: 1920 × 1080, states: [Activated]"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "config:\nwindow-rule {\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AN\nwant maximized: A\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen, Activated]
|
||||
|
||||
unfullscreen configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Activated, Maximized]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AN\nwant maximized: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen, Activated]
|
||||
|
||||
unfullscreen configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AN\nwant maximized: B\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen, Activated]
|
||||
|
||||
unfullscreen configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AN\nwant maximized: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen, Activated]
|
||||
|
||||
unfullscreen configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AN\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen, Activated]
|
||||
|
||||
unfullscreen configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AU\nwant maximized: A\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AU\nwant maximized: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AU\nwant maximized: B\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AU\nwant maximized: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BN\nwant maximized: A\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BN\nwant maximized: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BN\nwant maximized: B\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BN\nwant maximized: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BN\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BU\nwant maximized: A\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BU\nwant maximized: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BU\nwant maximized: B\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BU\nwant maximized: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want maximized: A\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want maximized: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want maximized: B\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want maximized: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "config:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AN\nwant maximized: A\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen, Activated]
|
||||
|
||||
unfullscreen configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Activated, Maximized]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AN\nwant maximized: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen, Activated]
|
||||
|
||||
unfullscreen configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AN\nwant maximized: B\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen, Activated]
|
||||
|
||||
unfullscreen configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Activated, Maximized]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AN\nwant maximized: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen, Activated]
|
||||
|
||||
unfullscreen configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Activated, Maximized]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AN\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen, Activated]
|
||||
|
||||
unfullscreen configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Activated, Maximized]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AU\nwant maximized: A\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AU\nwant maximized: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AU\nwant maximized: B\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AU\nwant maximized: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BN\nwant maximized: A\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BN\nwant maximized: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BN\nwant maximized: B\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BN\nwant maximized: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BN\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BU\nwant maximized: A\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BU\nwant maximized: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BU\nwant maximized: B\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BU\nwant maximized: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want maximized: A\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want maximized: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want maximized: B\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want maximized: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "config:\nwindow-rule {\n open-fullscreen false\n open-maximized-to-edges true\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AN\nwant maximized: A\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen, Activated]
|
||||
|
||||
unfullscreen configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Activated, Maximized]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AN\nwant maximized: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen, Activated]
|
||||
|
||||
unfullscreen configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AN\nwant maximized: B\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen, Activated]
|
||||
|
||||
unfullscreen configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Activated, Maximized]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AN\nwant maximized: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen, Activated]
|
||||
|
||||
unfullscreen configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AN\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen, Activated]
|
||||
|
||||
unfullscreen configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AU\nwant maximized: A\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AU\nwant maximized: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AU\nwant maximized: B\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AU\nwant maximized: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BN\nwant maximized: A\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BN\nwant maximized: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BN\nwant maximized: B\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BN\nwant maximized: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BN\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BU\nwant maximized: A\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BU\nwant maximized: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BU\nwant maximized: B\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BU\nwant maximized: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want maximized: A\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want maximized: AU\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want maximized: B\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Maximized, Activated]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want maximized: BU\nconfig:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "config:\nwindow-rule {\n open-fullscreen false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: []
|
||||
|
||||
post-map configures:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AN\nwant maximized: A\nconfig:\nwindow-rule {\n open-fullscreen true\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen, Activated]
|
||||
|
||||
unfullscreen configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Activated, Maximized]
|
||||
|
||||
unmaximize configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
---
|
||||
source: src/tests/window_opening.rs
|
||||
description: "want fullscreen: AN\nwant maximized: AU\nconfig:\nwindow-rule {\n open-fullscreen true\n open-maximized-to-edges false\n}"
|
||||
expression: snapshot
|
||||
---
|
||||
initial configure:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen, Activated]
|
||||
|
||||
unfullscreen configure:
|
||||
size: 616 × 688, bounds: 1248 × 688, states: [Activated]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user