mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-23 02:05:33 +07:00
Implement maximize-to-edges (true Wayland maximize)
This commit is contained in:
@@ -303,6 +303,9 @@ pub enum Action {
|
|||||||
#[knuffel(skip)]
|
#[knuffel(skip)]
|
||||||
SwitchPresetWindowHeightBackById(u64),
|
SwitchPresetWindowHeightBackById(u64),
|
||||||
MaximizeColumn,
|
MaximizeColumn,
|
||||||
|
MaximizeWindowToEdges,
|
||||||
|
#[knuffel(skip)]
|
||||||
|
MaximizeWindowToEdgesById(u64),
|
||||||
SetColumnWidth(#[knuffel(argument, str)] SizeChange),
|
SetColumnWidth(#[knuffel(argument, str)] SizeChange),
|
||||||
ExpandColumnToAvailableWidth,
|
ExpandColumnToAvailableWidth,
|
||||||
SwitchLayout(#[knuffel(argument, str)] LayoutSwitchTarget),
|
SwitchLayout(#[knuffel(argument, str)] LayoutSwitchTarget),
|
||||||
@@ -568,6 +571,10 @@ impl From<niri_ipc::Action> for Action {
|
|||||||
Self::SwitchPresetWindowHeightBackById(id)
|
Self::SwitchPresetWindowHeightBackById(id)
|
||||||
}
|
}
|
||||||
niri_ipc::Action::MaximizeColumn {} => Self::MaximizeColumn,
|
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::SetColumnWidth { change } => Self::SetColumnWidth(change),
|
||||||
niri_ipc::Action::ExpandColumnToAvailableWidth {} => Self::ExpandColumnToAvailableWidth,
|
niri_ipc::Action::ExpandColumnToAvailableWidth {} => Self::ExpandColumnToAvailableWidth,
|
||||||
niri_ipc::Action::SwitchLayout { layout } => Self::SwitchLayout(layout),
|
niri_ipc::Action::SwitchLayout { layout } => Self::SwitchLayout(layout),
|
||||||
|
|||||||
@@ -1578,6 +1578,7 @@ mod tests {
|
|||||||
open_maximized: Some(
|
open_maximized: Some(
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
|
open_maximized_to_edges: None,
|
||||||
open_fullscreen: Some(
|
open_fullscreen: Some(
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ pub struct WindowRule {
|
|||||||
#[knuffel(child, unwrap(argument))]
|
#[knuffel(child, unwrap(argument))]
|
||||||
pub open_maximized: Option<bool>,
|
pub open_maximized: Option<bool>,
|
||||||
#[knuffel(child, unwrap(argument))]
|
#[knuffel(child, unwrap(argument))]
|
||||||
|
pub open_maximized_to_edges: Option<bool>,
|
||||||
|
#[knuffel(child, unwrap(argument))]
|
||||||
pub open_fullscreen: Option<bool>,
|
pub open_fullscreen: Option<bool>,
|
||||||
#[knuffel(child, unwrap(argument))]
|
#[knuffel(child, unwrap(argument))]
|
||||||
pub open_floating: Option<bool>,
|
pub open_floating: Option<bool>,
|
||||||
|
|||||||
@@ -713,6 +713,14 @@ pub enum Action {
|
|||||||
},
|
},
|
||||||
/// Toggle the maximized state of the focused column.
|
/// Toggle the maximized state of the focused column.
|
||||||
MaximizeColumn {},
|
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.
|
/// Change the width of the focused column.
|
||||||
SetColumnWidth {
|
SetColumnWidth {
|
||||||
/// How to change the width.
|
/// How to change the width.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use niri::animation::Clock;
|
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::render_helpers::RenderTarget;
|
||||||
use niri_config::{Color, OutputName, PresetSize};
|
use niri_config::{Color, OutputName, PresetSize};
|
||||||
use smithay::backend::renderer::element::RenderElement;
|
use smithay::backend::renderer::element::RenderElement;
|
||||||
@@ -168,7 +168,7 @@ impl Layout {
|
|||||||
let max_size = window.max_size();
|
let max_size = window.max_size();
|
||||||
window.request_size(
|
window.request_size(
|
||||||
ws.new_window_size(width, None, false, window.rules(), (min_size, max_size)),
|
ws.new_window_size(width, None, false, window.rules(), (min_size, max_size)),
|
||||||
false,
|
SizingMode::Normal,
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@@ -197,7 +197,7 @@ impl Layout {
|
|||||||
let max_size = window.max_size();
|
let max_size = window.max_size();
|
||||||
window.request_size(
|
window.request_size(
|
||||||
ws.new_window_size(width, None, false, window.rules(), (min_size, max_size)),
|
ws.new_window_size(width, None, false, window.rules(), (min_size, max_size)),
|
||||||
false,
|
SizingMode::Normal,
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use niri::layout::LayoutElement;
|
use niri::layout::{LayoutElement, SizingMode};
|
||||||
use niri::render_helpers::RenderTarget;
|
use niri::render_helpers::RenderTarget;
|
||||||
use smithay::backend::renderer::element::RenderElement;
|
use smithay::backend::renderer::element::RenderElement;
|
||||||
use smithay::backend::renderer::gles::GlesRenderer;
|
use smithay::backend::renderer::gles::GlesRenderer;
|
||||||
@@ -14,14 +14,14 @@ pub struct Window {
|
|||||||
impl Window {
|
impl Window {
|
||||||
pub fn freeform(args: Args) -> Self {
|
pub fn freeform(args: Args) -> Self {
|
||||||
let mut window = TestWindow::freeform(0);
|
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();
|
window.communicate();
|
||||||
Self { window }
|
Self { window }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fixed_size(args: Args) -> Self {
|
pub fn fixed_size(args: Args) -> Self {
|
||||||
let mut window = TestWindow::fixed_size(0);
|
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();
|
window.communicate();
|
||||||
Self { window }
|
Self { window }
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ impl Window {
|
|||||||
pub fn fixed_size_with_csd_shadow(args: Args) -> Self {
|
pub fn fixed_size_with_csd_shadow(args: Args) -> Self {
|
||||||
let mut window = TestWindow::fixed_size(0);
|
let mut window = TestWindow::fixed_size(0);
|
||||||
window.set_csd_shadow_width(64);
|
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();
|
window.communicate();
|
||||||
Self { window }
|
Self { window }
|
||||||
}
|
}
|
||||||
@@ -38,7 +38,7 @@ impl Window {
|
|||||||
impl TestCase for Window {
|
impl TestCase for Window {
|
||||||
fn resize(&mut self, width: i32, height: i32) {
|
fn resize(&mut self, width: i32, height: i32) {
|
||||||
self.window
|
self.window
|
||||||
.request_size(Size::from((width, height)), false, false, None);
|
.request_size(Size::from((width, height)), SizingMode::Normal, false, None);
|
||||||
self.window.communicate();
|
self.window.communicate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use std::rc::Rc;
|
|||||||
|
|
||||||
use niri::layout::{
|
use niri::layout::{
|
||||||
ConfigureIntent, InteractiveResizeData, LayoutElement, LayoutElementRenderElement,
|
ConfigureIntent, InteractiveResizeData, LayoutElement, LayoutElementRenderElement,
|
||||||
LayoutElementRenderSnapshot,
|
LayoutElementRenderSnapshot, SizingMode,
|
||||||
};
|
};
|
||||||
use niri::render_helpers::offscreen::OffscreenData;
|
use niri::render_helpers::offscreen::OffscreenData;
|
||||||
use niri::render_helpers::renderer::NiriRenderer;
|
use niri::render_helpers::renderer::NiriRenderer;
|
||||||
@@ -24,7 +24,7 @@ struct TestWindowInner {
|
|||||||
min_size: Size<i32, Logical>,
|
min_size: Size<i32, Logical>,
|
||||||
max_size: Size<i32, Logical>,
|
max_size: Size<i32, Logical>,
|
||||||
buffer: SolidColorBuffer,
|
buffer: SolidColorBuffer,
|
||||||
pending_fullscreen: bool,
|
pending_sizing_mode: SizingMode,
|
||||||
csd_shadow_width: i32,
|
csd_shadow_width: i32,
|
||||||
csd_shadow_buffer: SolidColorBuffer,
|
csd_shadow_buffer: SolidColorBuffer,
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ impl TestWindow {
|
|||||||
min_size,
|
min_size,
|
||||||
max_size,
|
max_size,
|
||||||
buffer,
|
buffer,
|
||||||
pending_fullscreen: false,
|
pending_sizing_mode: SizingMode::Normal,
|
||||||
csd_shadow_width: 0,
|
csd_shadow_width: 0,
|
||||||
csd_shadow_buffer: SolidColorBuffer::new((0., 0.), [0., 0., 0., 0.3]),
|
csd_shadow_buffer: SolidColorBuffer::new((0., 0.), [0., 0., 0., 0.3]),
|
||||||
})),
|
})),
|
||||||
@@ -182,12 +182,12 @@ impl LayoutElement for TestWindow {
|
|||||||
fn request_size(
|
fn request_size(
|
||||||
&mut self,
|
&mut self,
|
||||||
size: Size<i32, Logical>,
|
size: Size<i32, Logical>,
|
||||||
is_fullscreen: bool,
|
mode: SizingMode,
|
||||||
_animate: bool,
|
_animate: bool,
|
||||||
_transaction: Option<Transaction>,
|
_transaction: Option<Transaction>,
|
||||||
) {
|
) {
|
||||||
self.inner.borrow_mut().requested_size = Some(size);
|
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> {
|
fn min_size(&self) -> Size<i32, Logical> {
|
||||||
@@ -232,12 +232,12 @@ impl LayoutElement for TestWindow {
|
|||||||
|
|
||||||
fn send_pending_configure(&mut self) {}
|
fn send_pending_configure(&mut self) {}
|
||||||
|
|
||||||
fn is_fullscreen(&self) -> bool {
|
fn pending_sizing_mode(&self) -> SizingMode {
|
||||||
false
|
self.inner.borrow().pending_sizing_mode
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_pending_fullscreen(&self) -> bool {
|
fn sizing_mode(&self) -> SizingMode {
|
||||||
self.inner.borrow().pending_fullscreen
|
SizingMode::Normal
|
||||||
}
|
}
|
||||||
|
|
||||||
fn requested_size(&self) -> Option<Size<i32, Logical>> {
|
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 super::xdg_shell::add_mapped_toplevel_pre_commit_hook;
|
||||||
use crate::handlers::XDG_ACTIVATION_TOKEN_TIMEOUT;
|
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::niri::{CastTarget, ClientState, LockState, State};
|
||||||
use crate::utils::transaction::Transaction;
|
use crate::utils::transaction::Transaction;
|
||||||
use crate::utils::{is_mapped, send_scale_transform};
|
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 toplevel = window.toplevel().expect("no X11 support");
|
||||||
|
|
||||||
let (rules, width, height, is_full_width, output, workspace_id) =
|
let (
|
||||||
if let InitialConfigureState::Configured {
|
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,
|
rules,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
floating_width: _,
|
|
||||||
floating_height: _,
|
|
||||||
is_full_width,
|
is_full_width,
|
||||||
output,
|
output,
|
||||||
workspace_name,
|
workspace_id,
|
||||||
} = state
|
is_pending_maximized,
|
||||||
{
|
)
|
||||||
// Check that the output is still connected.
|
} else {
|
||||||
let output =
|
// Can happen when a surface unmaps by attaching a null buffer while
|
||||||
output.filter(|o| self.niri.layout.monitor_for_output(o).is_some());
|
// there are in-flight pending configures.
|
||||||
|
debug!("window mapped without proper initial configure");
|
||||||
// Check that the workspace still exists.
|
(
|
||||||
let workspace_id = workspace_name
|
ResolvedWindowRules::empty(),
|
||||||
.as_deref()
|
None,
|
||||||
.and_then(|n| self.niri.layout.find_workspace_by_name(n))
|
None,
|
||||||
.map(|(_, ws)| ws.id());
|
false,
|
||||||
|
None,
|
||||||
(rules, width, height, is_full_width, output, workspace_id)
|
None,
|
||||||
} else {
|
false,
|
||||||
// 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)
|
|
||||||
};
|
|
||||||
|
|
||||||
// The GTK about dialog sets min/max size after the initial configure but
|
// 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
|
// 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());
|
.map(|(mapped, _)| mapped.window.clone());
|
||||||
|
|
||||||
// The mapped pre-commit hook deals with dma-bufs on its own.
|
// 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 hook = add_mapped_toplevel_pre_commit_hook(toplevel);
|
||||||
let mapped = Mapped::new(window, rules, hook);
|
let mapped = Mapped::new(window, rules, hook);
|
||||||
let window = mapped.window.clone();
|
let window = mapped.window.clone();
|
||||||
@@ -193,8 +217,21 @@ impl CompositorHandler for State {
|
|||||||
is_floating,
|
is_floating,
|
||||||
activate,
|
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);
|
self.niri.layout.start_open_animation_for_window(&window);
|
||||||
|
|
||||||
let new_focus = self.niri.layout.focus().map(|m| &m.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);
|
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);
|
delegate_foreign_toplevel!(State);
|
||||||
|
|
||||||
|
|||||||
+222
-12
@@ -428,18 +428,205 @@ impl XdgShellHandler for State {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maximize_request(&mut self, surface: ToplevelSurface) {
|
fn maximize_request(&mut self, toplevel: ToplevelSurface) {
|
||||||
// FIXME
|
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
|
let window = mapped.window.clone();
|
||||||
// wasn't sent, then we will send this as part of the initial configure later.
|
self.niri.layout.set_maximized(&window, true);
|
||||||
if surface.is_initial_configure_sent() {
|
} else if let Some(unmapped) = self.niri.unmapped_windows.get_mut(toplevel.wl_surface()) {
|
||||||
surface.send_configure();
|
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) {
|
fn unmaximize_request(&mut self, toplevel: ToplevelSurface) {
|
||||||
// FIXME
|
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(
|
fn fullscreen_request(
|
||||||
@@ -474,7 +661,9 @@ impl XdgShellHandler for State {
|
|||||||
self.niri.layout.set_fullscreen(&window, true);
|
self.niri.layout.set_fullscreen(&window, true);
|
||||||
} else if let Some(unmapped) = self.niri.unmapped_windows.get_mut(toplevel.wl_surface()) {
|
} else if let Some(unmapped) = self.niri.unmapped_windows.get_mut(toplevel.wl_surface()) {
|
||||||
match &mut unmapped.state {
|
match &mut unmapped.state {
|
||||||
InitialConfigureState::NotConfigured { wants_fullscreen } => {
|
InitialConfigureState::NotConfigured {
|
||||||
|
wants_fullscreen, ..
|
||||||
|
} => {
|
||||||
*wants_fullscreen = Some(requested_output);
|
*wants_fullscreen = Some(requested_output);
|
||||||
|
|
||||||
// The required configure will be the initial configure.
|
// The required configure will be the initial configure.
|
||||||
@@ -517,6 +706,7 @@ impl XdgShellHandler for State {
|
|||||||
if let Some(ws) = ws {
|
if let Some(ws) = ws {
|
||||||
toplevel.with_pending_state(|state| {
|
toplevel.with_pending_state(|state| {
|
||||||
state.states.set(xdg_toplevel::State::Fullscreen);
|
state.states.set(xdg_toplevel::State::Fullscreen);
|
||||||
|
state.states.unset(xdg_toplevel::State::Maximized);
|
||||||
});
|
});
|
||||||
ws.configure_new_window(&unmapped.window, None, None, false, rules);
|
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);
|
self.niri.layout.set_fullscreen(&window, false);
|
||||||
} else if let Some(unmapped) = self.niri.unmapped_windows.get_mut(toplevel.wl_surface()) {
|
} else if let Some(unmapped) = self.niri.unmapped_windows.get_mut(toplevel.wl_surface()) {
|
||||||
match &mut unmapped.state {
|
match &mut unmapped.state {
|
||||||
InitialConfigureState::NotConfigured { wants_fullscreen } => {
|
InitialConfigureState::NotConfigured {
|
||||||
|
wants_fullscreen, ..
|
||||||
|
} => {
|
||||||
*wants_fullscreen = None;
|
*wants_fullscreen = None;
|
||||||
|
|
||||||
// The required configure will be the initial configure.
|
// The required configure will be the initial configure.
|
||||||
@@ -559,6 +751,7 @@ impl XdgShellHandler for State {
|
|||||||
is_full_width,
|
is_full_width,
|
||||||
output,
|
output,
|
||||||
workspace_name,
|
workspace_name,
|
||||||
|
is_pending_maximized,
|
||||||
} => {
|
} => {
|
||||||
// Figure out the monitor following a similar logic to initial configure.
|
// Figure out the monitor following a similar logic to initial configure.
|
||||||
// FIXME: deduplicate.
|
// FIXME: deduplicate.
|
||||||
@@ -608,6 +801,10 @@ impl XdgShellHandler for State {
|
|||||||
if let Some(ws) = ws {
|
if let Some(ws) = ws {
|
||||||
toplevel.with_pending_state(|state| {
|
toplevel.with_pending_state(|state| {
|
||||||
state.states.unset(xdg_toplevel::State::Fullscreen);
|
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);
|
let is_floating = rules.compute_open_floating(&toplevel);
|
||||||
@@ -858,7 +1055,11 @@ impl State {
|
|||||||
|
|
||||||
let Unmapped { window, state, .. } = unmapped;
|
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()");
|
error!("window must not be already configured in send_initial_configure()");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -934,14 +1135,22 @@ impl State {
|
|||||||
.or_else(|| self.niri.layout.active_workspace())
|
.or_else(|| self.niri.layout.active_workspace())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let mut is_pending_maximized = false;
|
||||||
if let Some(ws) = ws {
|
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())
|
if (wants_fullscreen.is_some() && rules.open_fullscreen.is_none())
|
||||||
|| rules.open_fullscreen == Some(true)
|
|| rules.open_fullscreen == Some(true)
|
||||||
{
|
{
|
||||||
toplevel.with_pending_state(|state| {
|
toplevel.with_pending_state(|state| {
|
||||||
state.states.set(xdg_toplevel::State::Fullscreen);
|
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);
|
width = ws.resolve_default_width(rules.default_width, false);
|
||||||
@@ -979,6 +1188,7 @@ impl State {
|
|||||||
is_full_width,
|
is_full_width,
|
||||||
output,
|
output,
|
||||||
workspace_name: ws.and_then(|w| w.name().cloned()),
|
workspace_name: ws.and_then(|w| w.name().cloned()),
|
||||||
|
is_pending_maximized,
|
||||||
};
|
};
|
||||||
|
|
||||||
trace!(surface = %toplevel.wl_surface().id(), "sending initial configure");
|
trace!(surface = %toplevel.wl_surface().id(), "sending initial configure");
|
||||||
|
|||||||
@@ -1514,6 +1514,23 @@ impl State {
|
|||||||
Action::MaximizeColumn => {
|
Action::MaximizeColumn => {
|
||||||
self.niri.layout.toggle_full_width();
|
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 => {
|
Action::FocusMonitorLeft => {
|
||||||
if let Some(output) = self.niri.output_left() {
|
if let Some(output) = self.niri.output_left() {
|
||||||
self.niri.layout.focus_output(&output);
|
self.niri.layout.focus_output(&output);
|
||||||
|
|||||||
@@ -413,8 +413,8 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
|||||||
// unfullscreen it.
|
// unfullscreen it.
|
||||||
let floating_size = tile.floating_window_size;
|
let floating_size = tile.floating_window_size;
|
||||||
let win = tile.window_mut();
|
let win = tile.window_mut();
|
||||||
let mut size = if win.is_pending_fullscreen() {
|
let mut size = if !win.pending_sizing_mode().is_normal() {
|
||||||
// If the window was fullscreen without a floating size, ask for (0, 0).
|
// If the window was fullscreen or maximized without a floating size, ask for (0, 0).
|
||||||
floating_size.unwrap_or_default()
|
floating_size.unwrap_or_default()
|
||||||
} else {
|
} else {
|
||||||
// If the window wasn't fullscreen without a floating size (e.g. it was tiled before),
|
// 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());
|
assert_eq!(self.tiles.len(), self.data.len());
|
||||||
|
|
||||||
for (i, (tile, data)) in zip(&self.tiles, &self.data).enumerate() {
|
for (i, (tile, data)) in zip(&self.tiles, &self.data).enumerate() {
|
||||||
|
use crate::layout::SizingMode;
|
||||||
|
|
||||||
assert!(Rc::ptr_eq(&self.options, &tile.options));
|
assert!(Rc::ptr_eq(&self.options, &tile.options));
|
||||||
assert_eq!(self.view_size, tile.view_size());
|
assert_eq!(self.view_size, tile.view_size());
|
||||||
assert_eq!(self.clock, tile.clock);
|
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!(idx < self.options.layout.preset_window_heights.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(
|
assert_eq!(
|
||||||
!tile.window().is_pending_fullscreen(),
|
tile.window().pending_sizing_mode(),
|
||||||
"floating windows cannot be fullscreen"
|
SizingMode::Normal,
|
||||||
|
"floating windows cannot be maximized or fullscreen"
|
||||||
);
|
);
|
||||||
|
|
||||||
data.verify_invariants();
|
data.verify_invariants();
|
||||||
|
|||||||
+64
-9
@@ -118,6 +118,13 @@ niri_render_elements! {
|
|||||||
pub type LayoutElementRenderSnapshot =
|
pub type LayoutElementRenderSnapshot =
|
||||||
RenderSnapshot<BakedBuffer<TextureBuffer<GlesTexture>>, BakedBuffer<SolidColorBuffer>>;
|
RenderSnapshot<BakedBuffer<TextureBuffer<GlesTexture>>, BakedBuffer<SolidColorBuffer>>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum SizingMode {
|
||||||
|
Normal,
|
||||||
|
Maximized,
|
||||||
|
Fullscreen,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait LayoutElement {
|
pub trait LayoutElement {
|
||||||
/// Type that can be used as a unique ID of this element.
|
/// Type that can be used as a unique ID of this element.
|
||||||
type Id: PartialEq + std::fmt::Debug + Clone;
|
type Id: PartialEq + std::fmt::Debug + Clone;
|
||||||
@@ -185,14 +192,14 @@ pub trait LayoutElement {
|
|||||||
fn request_size(
|
fn request_size(
|
||||||
&mut self,
|
&mut self,
|
||||||
size: Size<i32, Logical>,
|
size: Size<i32, Logical>,
|
||||||
is_fullscreen: bool,
|
mode: SizingMode,
|
||||||
animate: bool,
|
animate: bool,
|
||||||
transaction: Option<Transaction>,
|
transaction: Option<Transaction>,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Requests the element to change size once, clearing the request afterwards.
|
/// Requests the element to change size once, clearing the request afterwards.
|
||||||
fn request_size_once(&mut self, size: Size<i32, Logical>, animate: bool) {
|
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>;
|
fn min_size(&self) -> Size<i32, Logical>;
|
||||||
@@ -214,15 +221,15 @@ pub trait LayoutElement {
|
|||||||
fn configure_intent(&self) -> ConfigureIntent;
|
fn configure_intent(&self) -> ConfigureIntent;
|
||||||
fn send_pending_configure(&mut self);
|
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.
|
/// 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.
|
/// 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()`].
|
/// Size previously requested through [`LayoutElement::request_size()`].
|
||||||
fn requested_size(&self) -> Option<Size<i32, Logical>>;
|
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.
|
/// 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>> {
|
fn expected_size(&self) -> Option<Size<i32, Logical>> {
|
||||||
if self.is_fullscreen() {
|
if self.sizing_mode().is_fullscreen() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -502,6 +509,23 @@ struct OverviewGesture {
|
|||||||
value: f64,
|
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> {
|
impl<W: LayoutElement> InteractiveMoveState<W> {
|
||||||
fn moving(&self) -> Option<&InteractiveMoveData<W>> {
|
fn moving(&self) -> Option<&InteractiveMoveData<W>> {
|
||||||
match self {
|
match self {
|
||||||
@@ -2321,7 +2345,7 @@ impl<W: LayoutElement> Layout<W> {
|
|||||||
}
|
}
|
||||||
InteractiveMoveState::Moving(move_) => {
|
InteractiveMoveState::Moving(move_) => {
|
||||||
assert_eq!(self.clock, move_.tile.clock);
|
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();
|
move_.tile.verify_invariants();
|
||||||
|
|
||||||
@@ -3456,7 +3480,7 @@ impl<W: LayoutElement> Layout<W> {
|
|||||||
|
|
||||||
pub fn toggle_windowed_fullscreen(&mut self, id: &W::Id) {
|
pub fn toggle_windowed_fullscreen(&mut self, id: &W::Id) {
|
||||||
let (_, window) = self.windows().find(|(_, win)| win.id() == id).unwrap();
|
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.
|
// Remove the real fullscreen.
|
||||||
for ws in self.workspaces_mut() {
|
for ws in self.workspaces_mut() {
|
||||||
if ws.has_window(id) {
|
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) {
|
pub fn workspace_switch_gesture_begin(&mut self, output: &Output, is_touchpad: bool) {
|
||||||
let monitors = match &mut self.monitor_set {
|
let monitors = match &mut self.monitor_set {
|
||||||
MonitorSet::Normal { monitors, .. } => monitors,
|
MonitorSet::Normal { monitors, .. } => monitors,
|
||||||
@@ -3845,6 +3899,7 @@ impl<W: LayoutElement> Layout<W> {
|
|||||||
.find(|ws| ws.has_window(&window_id))
|
.find(|ws| ws.has_window(&window_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
ws.set_fullscreen(window, false);
|
ws.set_fullscreen(window, false);
|
||||||
|
ws.set_maximized(window, false);
|
||||||
|
|
||||||
let RemovedTile {
|
let RemovedTile {
|
||||||
mut tile,
|
mut tile,
|
||||||
|
|||||||
+278
-85
@@ -18,6 +18,7 @@ use super::workspace::{InteractiveResize, ResolvedSize};
|
|||||||
use super::{ConfigureIntent, HitType, InteractiveResizeData, LayoutElement, Options, RemovedTile};
|
use super::{ConfigureIntent, HitType, InteractiveResizeData, LayoutElement, Options, RemovedTile};
|
||||||
use crate::animation::{Animation, Clock};
|
use crate::animation::{Animation, Clock};
|
||||||
use crate::input::swipe_tracker::SwipeTracker;
|
use crate::input::swipe_tracker::SwipeTracker;
|
||||||
|
use crate::layout::SizingMode;
|
||||||
use crate::niri_render_elements;
|
use crate::niri_render_elements;
|
||||||
use crate::render_helpers::renderer::NiriRenderer;
|
use crate::render_helpers::renderer::NiriRenderer;
|
||||||
use crate::render_helpers::RenderTarget;
|
use crate::render_helpers::RenderTarget;
|
||||||
@@ -62,8 +63,8 @@ pub struct ScrollingSpace<W: LayoutElement> {
|
|||||||
/// The value is the view offset that the previous column had before, to restore it.
|
/// The value is the view offset that the previous column had before, to restore it.
|
||||||
activate_prev_column_on_removal: Option<f64>,
|
activate_prev_column_on_removal: Option<f64>,
|
||||||
|
|
||||||
/// View offset to restore after unfullscreening.
|
/// View offset to restore after unfullscreening or unmaximizing.
|
||||||
view_offset_before_fullscreen: Option<f64>,
|
view_offset_to_restore: Option<f64>,
|
||||||
|
|
||||||
/// Windows in the closing animation.
|
/// Windows in the closing animation.
|
||||||
closing_windows: Vec<ClosingWindow>,
|
closing_windows: Vec<ClosingWindow>,
|
||||||
@@ -177,6 +178,13 @@ pub struct Column<W: LayoutElement> {
|
|||||||
/// take some time to catch up and actually unfullscreen.
|
/// take some time to catch up and actually unfullscreen.
|
||||||
is_pending_fullscreen: bool,
|
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.
|
/// How this column displays and arranges windows.
|
||||||
display_mode: ColumnDisplay,
|
display_mode: ColumnDisplay,
|
||||||
|
|
||||||
@@ -192,6 +200,11 @@ pub struct Column<W: LayoutElement> {
|
|||||||
/// Latest known working area for this column's workspace.
|
/// Latest known working area for this column's workspace.
|
||||||
working_area: Rectangle<f64, Logical>,
|
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 of the output the column is on (and rounds its sizes to).
|
||||||
scale: f64,
|
scale: f64,
|
||||||
|
|
||||||
@@ -285,7 +298,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
interactive_resize: None,
|
interactive_resize: None,
|
||||||
view_offset: ViewOffset::Static(0.),
|
view_offset: ViewOffset::Static(0.),
|
||||||
activate_prev_column_on_removal: None,
|
activate_prev_column_on_removal: None,
|
||||||
view_offset_before_fullscreen: None,
|
view_offset_to_restore: None,
|
||||||
closing_windows: Vec::new(),
|
closing_windows: Vec::new(),
|
||||||
view_size,
|
view_size,
|
||||||
working_area,
|
working_area,
|
||||||
@@ -306,7 +319,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
let working_area = compute_working_area(parent_area, scale, options.layout.struts);
|
let working_area = compute_working_area(parent_area, scale, options.layout.struts);
|
||||||
|
|
||||||
for (column, data) in zip(&mut self.columns, &mut self.data) {
|
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);
|
data.update(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,7 +453,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let col = &self.columns[self.active_column_idx];
|
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> {
|
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>,
|
target_x: Option<f64>,
|
||||||
col_x: f64,
|
col_x: f64,
|
||||||
width: f64,
|
width: f64,
|
||||||
is_fullscreen: bool,
|
mode: SizingMode,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
if is_fullscreen {
|
if mode.is_fullscreen() {
|
||||||
return 0.;
|
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 target_x = target_x.unwrap_or_else(|| self.target_view_pos());
|
||||||
|
|
||||||
let new_offset = compute_new_view_offset(
|
let new_offset =
|
||||||
target_x + self.working_area.loc.x,
|
compute_new_view_offset(target_x + area.loc.x, area.size.w, col_x, width, padding);
|
||||||
self.working_area.size.w,
|
|
||||||
col_x,
|
|
||||||
width,
|
|
||||||
self.options.layout.gaps,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Non-fullscreen windows are always offset at least by the working area position.
|
// 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(
|
fn compute_new_view_offset_centered(
|
||||||
@@ -558,18 +572,24 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
target_x: Option<f64>,
|
target_x: Option<f64>,
|
||||||
col_x: f64,
|
col_x: f64,
|
||||||
width: f64,
|
width: f64,
|
||||||
is_fullscreen: bool,
|
mode: SizingMode,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
if is_fullscreen {
|
if mode.is_fullscreen() {
|
||||||
return self.compute_new_view_offset_fit(target_x, col_x, width, 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).
|
// Columns wider than the view are left-aligned (the fit code can deal with that).
|
||||||
if self.working_area.size.w <= width {
|
if area.size.w <= width {
|
||||||
return self.compute_new_view_offset_fit(target_x, col_x, width, is_fullscreen);
|
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 {
|
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,
|
target_x,
|
||||||
self.column_x(idx),
|
self.column_x(idx),
|
||||||
col.width(),
|
col.width(),
|
||||||
col.is_fullscreen(),
|
col.sizing_mode(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -592,7 +612,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
target_x,
|
target_x,
|
||||||
self.column_x(idx),
|
self.column_x(idx),
|
||||||
col.width(),
|
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_x = self.column_x(idx);
|
||||||
let target_col_width = self.columns[idx].width();
|
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 {
|
let total_width = if source_col_x < target_col_x {
|
||||||
// Source is left from target.
|
// Source is left from target.
|
||||||
target_col_x - source_col_x + target_col_width
|
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.
|
// A different column was activated; reset the flag.
|
||||||
self.activate_prev_column_on_removal = None;
|
self.activate_prev_column_on_removal = None;
|
||||||
self.view_offset_before_fullscreen = None;
|
self.view_offset_to_restore = None;
|
||||||
self.interactive_resize = None;
|
self.interactive_resize = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -855,6 +877,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
tile,
|
tile,
|
||||||
self.view_size,
|
self.view_size,
|
||||||
self.working_area,
|
self.working_area,
|
||||||
|
self.parent_area,
|
||||||
self.scale,
|
self.scale,
|
||||||
width,
|
width,
|
||||||
is_full_width,
|
is_full_width,
|
||||||
@@ -956,6 +979,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
column.update_config(
|
column.update_config(
|
||||||
self.view_size,
|
self.view_size,
|
||||||
self.working_area,
|
self.working_area,
|
||||||
|
self.parent_area,
|
||||||
self.scale,
|
self.scale,
|
||||||
self.options.clone(),
|
self.options.clone(),
|
||||||
);
|
);
|
||||||
@@ -1059,15 +1083,15 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
tile.animate_alpha(0., 1., movement_config);
|
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);
|
let tile = column.tiles.remove(tile_idx);
|
||||||
column.data.remove(tile_idx);
|
column.data.remove(tile_idx);
|
||||||
|
|
||||||
// If an active column became non-fullscreen after removing the tile, clear the stored
|
// If an active column became non-fullscreen after removing the tile, clear the stored
|
||||||
// unfullscreen offset.
|
// unfullscreen offset.
|
||||||
if column_idx == self.active_column_idx && was_fullscreen && !column.is_fullscreen() {
|
if column_idx == self.active_column_idx && !was_normal && column.sizing_mode().is_normal() {
|
||||||
self.view_offset_before_fullscreen = None;
|
self.view_offset_to_restore = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If one window is left, reset its weight to 1.
|
// 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 {
|
if column_idx == self.active_column_idx {
|
||||||
self.view_offset_before_fullscreen = None;
|
self.view_offset_to_restore = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.columns.is_empty() {
|
if self.columns.is_empty() {
|
||||||
@@ -1225,7 +1249,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(_, col)| col.contains(window))
|
.find(|(_, col)| col.contains(window))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let was_fullscreen = column.is_fullscreen();
|
let was_normal = column.sizing_mode().is_normal();
|
||||||
let prev_origin = column.tiles_origin();
|
let prev_origin = column.tiles_origin();
|
||||||
|
|
||||||
let (tile_idx, tile) = column
|
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.
|
// When the active column goes fullscreen, store the view offset to restore later.
|
||||||
let is_fullscreen = self.columns[col_idx].is_fullscreen();
|
let is_normal = self.columns[col_idx].sizing_mode().is_normal();
|
||||||
if !was_fullscreen && is_fullscreen {
|
if was_normal && !is_normal {
|
||||||
self.view_offset_before_fullscreen = Some(self.view_offset.stationary());
|
self.view_offset_to_restore = Some(self.view_offset.stationary());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upon unfullscreening, restore the view offset.
|
// 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
|
// 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,
|
// 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.
|
// 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
|
// 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
|
// a view gesture. It shouldn't linger around because it's only valid for this
|
||||||
// particular unfullscreen.
|
// particular unfullscreen.
|
||||||
self.view_offset_before_fullscreen.take()
|
self.view_offset_to_restore.take()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@@ -2165,6 +2189,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
if col.display_mode != ColumnDisplay::Tabbed && col.tiles.len() > 1 {
|
if col.display_mode != ColumnDisplay::Tabbed && col.tiles.len() > 1 {
|
||||||
let window = col.tiles[col.active_tile_idx].window().id().clone();
|
let window = col.tiles[col.active_tile_idx].window().id().clone();
|
||||||
self.set_fullscreen(&window, false);
|
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)
|
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)> + '_ {
|
fn columns_mut(&mut self) -> impl Iterator<Item = (&mut Column<W>, f64)> + '_ {
|
||||||
let offsets = self.column_xs(self.data.iter().copied());
|
let offsets = self.column_xs(self.data.iter().copied());
|
||||||
zip(&mut self.columns, offsets)
|
zip(&mut self.columns, offsets)
|
||||||
@@ -2474,7 +2503,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
|
|
||||||
// Adjust for place-within-column tab indicator.
|
// Adjust for place-within-column tab indicator.
|
||||||
let origin_x = col.tiles_origin().x;
|
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
|
col.tab_indicator.extra_size(col.tiles.len(), col.scale).w
|
||||||
} else {
|
} else {
|
||||||
0.
|
0.
|
||||||
@@ -2491,9 +2520,14 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
// effect here.
|
// effect here.
|
||||||
if self.columns.is_empty() {
|
if self.columns.is_empty() {
|
||||||
let view_offset = if self.is_centering_focused_column() {
|
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 {
|
} 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;
|
hint_area.loc.x -= view_offset;
|
||||||
} else {
|
} else {
|
||||||
@@ -2693,7 +2727,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let col = &mut self.columns[self.active_column_idx];
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2709,6 +2743,9 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
return;
|
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.
|
// Consider the end of an ongoing animation because that's what compute to fit does too.
|
||||||
let view_x = self.target_view_pos();
|
let view_x = self.target_view_pos();
|
||||||
let working_x = self.working_area.loc.x;
|
let working_x = self.working_area.loc.x;
|
||||||
@@ -2812,6 +2849,37 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
true
|
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 {
|
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.
|
// Render above the top layer if we're on a fullscreen window and the view is stationary.
|
||||||
if self.columns.is_empty() {
|
if self.columns.is_empty() {
|
||||||
@@ -2822,7 +2890,9 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
return false;
|
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>(
|
pub fn render_elements<R: NiriRenderer>(
|
||||||
@@ -2902,7 +2972,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
let col_render_off = col.render_offset();
|
let col_render_off = col.render_offset();
|
||||||
|
|
||||||
// Hit the tab indicator.
|
// 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 = view_off + col_off + col_render_off;
|
||||||
let col_pos = col_pos.to_physical_precise_round(scale).to_logical(scale);
|
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 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() {
|
if self.is_centering_focused_column() {
|
||||||
let mut col_x = 0.;
|
let mut col_x = 0.;
|
||||||
for (col_idx, col) in self.columns.iter().enumerate() {
|
for (col_idx, col) in self.columns.iter().enumerate() {
|
||||||
let col_w = col.width();
|
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
|
col_x
|
||||||
} else if self.working_area.size.w <= col_w {
|
} else if area.size.w <= col_w {
|
||||||
col_x - left_strut
|
col_x - left_strut
|
||||||
} else {
|
} 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 });
|
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 view_width = self.view_size.w;
|
||||||
let working_area_width = self.working_area.size.w;
|
|
||||||
let gaps = self.options.layout.gaps;
|
let gaps = self.options.layout.gaps;
|
||||||
|
|
||||||
let snap_points =
|
let snap_points =
|
||||||
|col_x, col: &Column<W>, prev_col_w: Option<f64>, next_col_w: Option<f64>| {
|
|col_x, col: &Column<W>, prev_col_w: Option<f64>, next_col_w: Option<f64>| {
|
||||||
let col_w = col.width();
|
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
|
// Normal columns align with the working area, but fullscreen columns align with
|
||||||
// the view size.
|
// the view size.
|
||||||
if col.is_fullscreen() {
|
if mode.is_fullscreen() {
|
||||||
let left = col_x;
|
let left = col_x;
|
||||||
let right = col_x + col_w;
|
let right = left + col_w;
|
||||||
(left, right)
|
(left, right)
|
||||||
} else {
|
} else {
|
||||||
// Logic from compute_new_view_offset.
|
// 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
|
col_x - left_strut
|
||||||
} else {
|
} 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>| {
|
let is_overflowing = |adj_col_w: Option<f64>| {
|
||||||
center_on_overflow
|
center_on_overflow
|
||||||
&& adj_col_w
|
&& adj_col_w
|
||||||
.filter(|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
|
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()
|
.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
|
// 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).
|
// 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(
|
let leftmost_snap = snap_points(
|
||||||
0.,
|
0.,
|
||||||
&self.columns[0],
|
&self.columns[0],
|
||||||
@@ -3295,16 +3395,28 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
let col = &self.columns[col_idx];
|
let col = &self.columns[col_idx];
|
||||||
let col_x = self.column_x(col_idx);
|
let col_x = self.column_x(col_idx);
|
||||||
let col_w = col.width();
|
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 {
|
if target_snap.view_pos + self.view_size.w < col_x + col_w {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let padding = ((self.working_area.size.w - col_w) / 2.)
|
let padding = if mode.is_maximized() {
|
||||||
.clamp(0., self.options.layout.gaps);
|
0.
|
||||||
if target_snap.view_pos + left_strut + self.working_area.size.w
|
} else {
|
||||||
< col_x + col_w + padding
|
((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;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3317,14 +3429,27 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
let col = &self.columns[col_idx];
|
let col = &self.columns[col_idx];
|
||||||
let col_x = self.column_x(col_idx);
|
let col_x = self.column_x(col_idx);
|
||||||
let col_w = col.width();
|
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 {
|
if col_x < target_snap.view_pos {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let padding = ((self.working_area.size.w - col_w) / 2.)
|
let padding = if mode.is_maximized() {
|
||||||
.clamp(0., self.options.layout.gaps);
|
0.
|
||||||
|
} else {
|
||||||
|
((area.size.w - col_w) / 2.).clamp(0., self.options.layout.gaps)
|
||||||
|
};
|
||||||
|
|
||||||
if col_x - padding < target_snap.view_pos + left_strut {
|
if col_x - padding < target_snap.view_pos + left_strut {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3339,7 +3464,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
let delta = active_col_x - new_col_x;
|
let delta = active_col_x - new_col_x;
|
||||||
|
|
||||||
if self.active_column_idx != new_col_idx {
|
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;
|
self.active_column_idx = new_col_idx;
|
||||||
@@ -3391,7 +3516,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
.find(|col| col.contains(&window))
|
.find(|col| col.contains(&window))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
if col.is_pending_fullscreen {
|
if !col.pending_sizing_mode().is_normal() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3637,11 +3762,11 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
|
|
||||||
let col = &self.columns[self.active_column_idx];
|
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!(
|
assert!(
|
||||||
col.is_fullscreen(),
|
!col.sizing_mode().is_normal(),
|
||||||
"when view_offset_before_fullscreen is set, \
|
"when view_offset_to_restore is set, \
|
||||||
the active column must be fullscreen"
|
the active column must be fullscreen or maximized"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3796,6 +3921,7 @@ impl<W: LayoutElement> Column<W> {
|
|||||||
tile: Tile<W>,
|
tile: Tile<W>,
|
||||||
view_size: Size<f64, Logical>,
|
view_size: Size<f64, Logical>,
|
||||||
working_area: Rectangle<f64, Logical>,
|
working_area: Rectangle<f64, Logical>,
|
||||||
|
parent_area: Rectangle<f64, Logical>,
|
||||||
scale: f64,
|
scale: f64,
|
||||||
width: ColumnWidth,
|
width: ColumnWidth,
|
||||||
is_full_width: bool,
|
is_full_width: bool,
|
||||||
@@ -3815,29 +3941,33 @@ impl<W: LayoutElement> Column<W> {
|
|||||||
width,
|
width,
|
||||||
preset_width_idx: None,
|
preset_width_idx: None,
|
||||||
is_full_width,
|
is_full_width,
|
||||||
|
is_pending_maximized: false,
|
||||||
is_pending_fullscreen: false,
|
is_pending_fullscreen: false,
|
||||||
display_mode,
|
display_mode,
|
||||||
tab_indicator: TabIndicator::new(options.layout.tab_indicator),
|
tab_indicator: TabIndicator::new(options.layout.tab_indicator),
|
||||||
move_animation: None,
|
move_animation: None,
|
||||||
view_size,
|
view_size,
|
||||||
working_area,
|
working_area,
|
||||||
|
parent_area,
|
||||||
scale,
|
scale,
|
||||||
clock: tile.clock.clone(),
|
clock: tile.clock.clone(),
|
||||||
options,
|
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);
|
rv.add_tile_at(0, tile);
|
||||||
|
|
||||||
if is_pending_fullscreen {
|
match pending_sizing_mode {
|
||||||
rv.set_fullscreen(true);
|
SizingMode::Normal => (),
|
||||||
|
SizingMode::Maximized => rv.set_maximized(true),
|
||||||
|
SizingMode::Fullscreen => rv.set_fullscreen(true),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Animate the tab indicator for new columns.
|
// Animate the tab indicator for new columns.
|
||||||
if display_mode == ColumnDisplay::Tabbed
|
if display_mode == ColumnDisplay::Tabbed
|
||||||
&& !rv.options.layout.tab_indicator.hide_when_single_tab
|
&& !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
|
// Usually new columns are created together with window movement actions. For new
|
||||||
// windows, we handle that in start_open_animation().
|
// windows, we handle that in start_open_animation().
|
||||||
@@ -3852,12 +3982,16 @@ impl<W: LayoutElement> Column<W> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
view_size: Size<f64, Logical>,
|
view_size: Size<f64, Logical>,
|
||||||
working_area: Rectangle<f64, Logical>,
|
working_area: Rectangle<f64, Logical>,
|
||||||
|
parent_area: Rectangle<f64, Logical>,
|
||||||
scale: f64,
|
scale: f64,
|
||||||
options: Rc<Options>,
|
options: Rc<Options>,
|
||||||
) {
|
) {
|
||||||
let mut update_sizes = false;
|
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;
|
update_sizes = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3895,6 +4029,7 @@ impl<W: LayoutElement> Column<W> {
|
|||||||
.update_config(options.layout.tab_indicator);
|
.update_config(options.layout.tab_indicator);
|
||||||
self.view_size = view_size;
|
self.view_size = view_size;
|
||||||
self.working_area = working_area;
|
self.working_area = working_area;
|
||||||
|
self.parent_area = parent_area;
|
||||||
self.scale = scale;
|
self.scale = scale;
|
||||||
self.options = options;
|
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
|
// 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
|
// 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).
|
// 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(
|
self.tab_indicator.update_render_elements(
|
||||||
enabled,
|
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> {
|
pub fn render_offset(&self) -> Point<f64, Logical> {
|
||||||
let mut offset = Point::from((0., 0.));
|
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
|
/// - 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
|
/// non-fullscreen column. This can influence the code that saves/restores the unfullscreen
|
||||||
/// view offset.
|
/// view offset.
|
||||||
fn is_fullscreen(&self) -> bool {
|
fn sizing_mode(&self) -> SizingMode {
|
||||||
// Behaviors that we want:
|
// Behaviors that we want:
|
||||||
//
|
//
|
||||||
// 1. The common case: single tile in a column. Assume no animations. Fullscreening the tile
|
// 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).
|
// mode change applies instantly).
|
||||||
//
|
//
|
||||||
// The logic that satisfies these behaviors is to check if *any* tile is fullscreen.
|
// 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 {
|
pub fn contains(&self, window: &W::Id) -> bool {
|
||||||
@@ -4102,6 +4271,7 @@ impl<W: LayoutElement> Column<W> {
|
|||||||
|
|
||||||
if self.display_mode != ColumnDisplay::Tabbed {
|
if self.display_mode != ColumnDisplay::Tabbed {
|
||||||
self.is_pending_fullscreen = false;
|
self.is_pending_fullscreen = false;
|
||||||
|
self.is_pending_maximized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.data
|
self.data
|
||||||
@@ -4213,7 +4383,8 @@ impl<W: LayoutElement> Column<W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_tile_sizes_with_transaction(&mut self, animate: bool, transaction: Transaction) {
|
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() {
|
for (tile_idx, tile) in self.tiles.iter_mut().enumerate() {
|
||||||
// In tabbed mode, only the visible window participates in the transaction.
|
// In tabbed mode, only the visible window participates in the transaction.
|
||||||
let is_active = tile_idx == self.active_tile_idx;
|
let is_active = tile_idx == self.active_tile_idx;
|
||||||
@@ -4223,7 +4394,11 @@ impl<W: LayoutElement> Column<W> {
|
|||||||
Some(transaction.clone())
|
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;
|
return;
|
||||||
}
|
}
|
||||||
@@ -4510,7 +4685,7 @@ impl<W: LayoutElement> Column<W> {
|
|||||||
.map(NotNan::into_inner)
|
.map(NotNan::into_inner)
|
||||||
.unwrap();
|
.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);
|
let extra_size = self.tab_indicator.extra_size(self.tiles.len(), self.scale);
|
||||||
tiles_width += extra_size.w;
|
tiles_width += extra_size.w;
|
||||||
}
|
}
|
||||||
@@ -4875,6 +5050,19 @@ impl<W: LayoutElement> Column<W> {
|
|||||||
self.update_tile_sizes(true);
|
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) {
|
fn set_column_display(&mut self, display: ColumnDisplay) {
|
||||||
if self.display_mode == display {
|
if self.display_mode == display {
|
||||||
return;
|
return;
|
||||||
@@ -4936,8 +5124,13 @@ impl<W: LayoutElement> Column<W> {
|
|||||||
fn tiles_origin(&self) -> Point<f64, Logical> {
|
fn tiles_origin(&self) -> Point<f64, Logical> {
|
||||||
let mut origin = Point::from((0., 0.));
|
let mut origin = Point::from((0., 0.));
|
||||||
|
|
||||||
if self.is_fullscreen() {
|
match self.sizing_mode() {
|
||||||
return origin;
|
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;
|
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.
|
// Animate the appearance of the tab indicator.
|
||||||
if self.display_mode == ColumnDisplay::Tabbed
|
if self.display_mode == ColumnDisplay::Tabbed
|
||||||
&& !self.is_fullscreen()
|
&& self.sizing_mode().is_normal()
|
||||||
&& self.tiles.len() == 1
|
&& self.tiles.len() == 1
|
||||||
&& !self.tab_indicator.config().hide_when_single_tab
|
&& !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!(self.active_tile_idx < self.tiles.len());
|
||||||
assert_eq!(self.tiles.len(), self.data.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);
|
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.clock, tile.clock);
|
||||||
assert_eq!(self.scale, tile.scale());
|
assert_eq!(self.scale, tile.scale());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
self.is_pending_fullscreen,
|
self.pending_sizing_mode(),
|
||||||
tile.window().is_pending_fullscreen()
|
tile.window().pending_sizing_mode()
|
||||||
);
|
);
|
||||||
assert_eq!(self.view_size, tile.view_size());
|
assert_eq!(self.view_size, tile.view_size());
|
||||||
tile.verify_invariants();
|
tile.verify_invariants();
|
||||||
@@ -5178,7 +5371,7 @@ impl<W: LayoutElement> Column<W> {
|
|||||||
tile.tile_height_for_window_height(f64::from(requested_size.h));
|
tile.tile_height_for_window_height(f64::from(requested_size.h));
|
||||||
let min_tile_height = f64::max(1., tile.min_size_nonfullscreen().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
|
&& self.scale.round() == self.scale
|
||||||
&& working_size.h.round() == working_size.h
|
&& working_size.h.round() == working_size.h
|
||||||
&& gaps.round() == gaps
|
&& gaps.round() == gaps
|
||||||
|
|||||||
+142
-21
@@ -33,9 +33,9 @@ struct TestWindowInner {
|
|||||||
forced_size: Cell<Option<Size<i32, Logical>>>,
|
forced_size: Cell<Option<Size<i32, Logical>>>,
|
||||||
min_size: Size<i32, Logical>,
|
min_size: Size<i32, Logical>,
|
||||||
max_size: Size<i32, Logical>,
|
max_size: Size<i32, Logical>,
|
||||||
pending_fullscreen: Cell<bool>,
|
pending_sizing_mode: Cell<SizingMode>,
|
||||||
pending_activated: Cell<bool>,
|
pending_activated: Cell<bool>,
|
||||||
is_fullscreen: Cell<bool>,
|
sizing_mode: Cell<SizingMode>,
|
||||||
is_windowed_fullscreen: Cell<bool>,
|
is_windowed_fullscreen: Cell<bool>,
|
||||||
is_pending_windowed_fullscreen: Cell<bool>,
|
is_pending_windowed_fullscreen: Cell<bool>,
|
||||||
animate_next_configure: Cell<bool>,
|
animate_next_configure: Cell<bool>,
|
||||||
@@ -81,9 +81,9 @@ impl TestWindow {
|
|||||||
forced_size: Cell::new(None),
|
forced_size: Cell::new(None),
|
||||||
min_size: params.min_max_size.0,
|
min_size: params.min_max_size.0,
|
||||||
max_size: params.min_max_size.1,
|
max_size: params.min_max_size.1,
|
||||||
pending_fullscreen: Cell::new(false),
|
pending_sizing_mode: Cell::new(SizingMode::Normal),
|
||||||
pending_activated: Cell::new(false),
|
pending_activated: Cell::new(false),
|
||||||
is_fullscreen: Cell::new(false),
|
sizing_mode: Cell::new(SizingMode::Normal),
|
||||||
is_windowed_fullscreen: Cell::new(false),
|
is_windowed_fullscreen: Cell::new(false),
|
||||||
is_pending_windowed_fullscreen: Cell::new(false),
|
is_pending_windowed_fullscreen: Cell::new(false),
|
||||||
animate_next_configure: Cell::new(false),
|
animate_next_configure: Cell::new(false),
|
||||||
@@ -126,8 +126,8 @@ impl TestWindow {
|
|||||||
|
|
||||||
self.0.animate_next_configure.set(false);
|
self.0.animate_next_configure.set(false);
|
||||||
|
|
||||||
if self.0.is_fullscreen.get() != self.0.pending_fullscreen.get() {
|
if self.0.sizing_mode.get() != self.0.pending_sizing_mode.get() {
|
||||||
self.0.is_fullscreen.set(self.0.pending_fullscreen.get());
|
self.0.sizing_mode.set(self.0.pending_sizing_mode.get());
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ impl LayoutElement for TestWindow {
|
|||||||
fn request_size(
|
fn request_size(
|
||||||
&mut self,
|
&mut self,
|
||||||
size: Size<i32, Logical>,
|
size: Size<i32, Logical>,
|
||||||
is_fullscreen: bool,
|
mode: SizingMode,
|
||||||
_animate: bool,
|
_animate: bool,
|
||||||
_transaction: Option<Transaction>,
|
_transaction: Option<Transaction>,
|
||||||
) {
|
) {
|
||||||
@@ -184,9 +184,9 @@ impl LayoutElement for TestWindow {
|
|||||||
self.0.animate_next_configure.set(true);
|
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);
|
self.0.is_pending_windowed_fullscreen.set(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -235,20 +235,12 @@ impl LayoutElement for TestWindow {
|
|||||||
|
|
||||||
fn set_floating(&mut self, _floating: bool) {}
|
fn set_floating(&mut self, _floating: bool) {}
|
||||||
|
|
||||||
fn is_fullscreen(&self) -> bool {
|
fn sizing_mode(&self) -> SizingMode {
|
||||||
if self.0.is_windowed_fullscreen.get() {
|
self.0.sizing_mode.get()
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.0.is_fullscreen.get()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_pending_fullscreen(&self) -> bool {
|
fn pending_sizing_mode(&self) -> SizingMode {
|
||||||
if self.0.is_pending_windowed_fullscreen.get() {
|
self.0.pending_sizing_mode.get()
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.0.pending_fullscreen.get()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn requested_size(&self) -> Option<Size<i32, Logical>> {
|
fn requested_size(&self) -> Option<Size<i32, Logical>> {
|
||||||
@@ -585,6 +577,10 @@ enum Op {
|
|||||||
id: Option<usize>,
|
id: Option<usize>,
|
||||||
},
|
},
|
||||||
MaximizeColumn,
|
MaximizeColumn,
|
||||||
|
MaximizeWindowToEdges {
|
||||||
|
#[proptest(strategy = "proptest::option::of(1..=5usize)")]
|
||||||
|
id: Option<usize>,
|
||||||
|
},
|
||||||
SetColumnWidth(#[proptest(strategy = "arbitrary_size_change()")] SizeChange),
|
SetColumnWidth(#[proptest(strategy = "arbitrary_size_change()")] SizeChange),
|
||||||
SetWindowWidth {
|
SetWindowWidth {
|
||||||
#[proptest(strategy = "proptest::option::of(1..=5usize)")]
|
#[proptest(strategy = "proptest::option::of(1..=5usize)")]
|
||||||
@@ -1310,6 +1306,16 @@ impl Op {
|
|||||||
layout.toggle_window_height(id.as_ref(), false);
|
layout.toggle_window_height(id.as_ref(), false);
|
||||||
}
|
}
|
||||||
Op::MaximizeColumn => layout.toggle_full_width(),
|
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::SetColumnWidth(change) => layout.set_column_width(change),
|
||||||
Op::SetWindowWidth { id, change } => {
|
Op::SetWindowWidth { id, change } => {
|
||||||
let id = id.filter(|id| layout.has_window(id));
|
let id = id.filter(|id| layout.has_window(id));
|
||||||
@@ -1674,6 +1680,9 @@ fn operations_dont_panic() {
|
|||||||
Op::FullscreenWindow(1),
|
Op::FullscreenWindow(1),
|
||||||
Op::FullscreenWindow(2),
|
Op::FullscreenWindow(2),
|
||||||
Op::FullscreenWindow(3),
|
Op::FullscreenWindow(3),
|
||||||
|
Op::MaximizeWindowToEdges { id: Some(1) },
|
||||||
|
Op::MaximizeWindowToEdges { id: Some(2) },
|
||||||
|
Op::MaximizeWindowToEdges { id: Some(3) },
|
||||||
Op::FocusColumnLeft,
|
Op::FocusColumnLeft,
|
||||||
Op::FocusColumnRight,
|
Op::FocusColumnRight,
|
||||||
Op::FocusColumnRightOrFirst,
|
Op::FocusColumnRightOrFirst,
|
||||||
@@ -1829,6 +1838,9 @@ fn operations_from_starting_state_dont_panic() {
|
|||||||
Op::FullscreenWindow(1),
|
Op::FullscreenWindow(1),
|
||||||
Op::FullscreenWindow(2),
|
Op::FullscreenWindow(2),
|
||||||
Op::FullscreenWindow(3),
|
Op::FullscreenWindow(3),
|
||||||
|
Op::MaximizeWindowToEdges { id: Some(1) },
|
||||||
|
Op::MaximizeWindowToEdges { id: Some(2) },
|
||||||
|
Op::MaximizeWindowToEdges { id: Some(3) },
|
||||||
Op::SetFullscreenWindow {
|
Op::SetFullscreenWindow {
|
||||||
window: 1,
|
window: 1,
|
||||||
is_fullscreen: false,
|
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);
|
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 {
|
fn parent_id_causes_loop(layout: &Layout<TestWindow>, id: usize, mut parent_id: usize) -> bool {
|
||||||
if parent_id == id {
|
if parent_id == id {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+124
-47
@@ -16,6 +16,7 @@ use super::{
|
|||||||
SizeFrac, RESIZE_ANIMATION_THRESHOLD,
|
SizeFrac, RESIZE_ANIMATION_THRESHOLD,
|
||||||
};
|
};
|
||||||
use crate::animation::{Animation, Clock};
|
use crate::animation::{Animation, Clock};
|
||||||
|
use crate::layout::SizingMode;
|
||||||
use crate::niri_render_elements;
|
use crate::niri_render_elements;
|
||||||
use crate::render_helpers::border::BorderRenderElement;
|
use crate::render_helpers::border::BorderRenderElement;
|
||||||
use crate::render_helpers::clipped_surface::{ClippedSurfaceRenderElement, RoundedCornerDamage};
|
use crate::render_helpers::clipped_surface::{ClippedSurfaceRenderElement, RoundedCornerDamage};
|
||||||
@@ -45,17 +46,17 @@ pub struct Tile<W: LayoutElement> {
|
|||||||
/// The shadow around the window.
|
/// The shadow around the window.
|
||||||
shadow: Shadow,
|
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,
|
/// This will update only when the `window` actually goes maximized or fullscreen, rather than
|
||||||
/// to avoid black backdrop flicker before the window has had a chance to resize.
|
/// right away, to avoid black backdrop flicker before the window has had a chance to resize.
|
||||||
is_fullscreen: bool,
|
sizing_mode: SizingMode,
|
||||||
|
|
||||||
/// The black backdrop for fullscreen windows.
|
/// The black backdrop for fullscreen windows.
|
||||||
fullscreen_backdrop: SolidColorBuffer,
|
fullscreen_backdrop: SolidColorBuffer,
|
||||||
|
|
||||||
/// Whether the tile should float upon unfullscreening.
|
/// 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.
|
/// 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,
|
// 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.
|
// for example when issuing a new resize during an unfullscreen resize.
|
||||||
fullscreen_progress: Option<Animation>,
|
fullscreen_progress: Option<Animation>,
|
||||||
|
// Similar to above but for fullscreen-or-maximized.
|
||||||
|
expanded_progress: Option<Animation>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -178,16 +181,16 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
let border_config = options.layout.border.merged_with(&rules.border);
|
let border_config = options.layout.border.merged_with(&rules.border);
|
||||||
let focus_ring_config = options.layout.focus_ring.merged_with(&rules.focus_ring);
|
let focus_ring_config = options.layout.focus_ring.merged_with(&rules.focus_ring);
|
||||||
let shadow_config = options.layout.shadow.merged_with(&rules.shadow);
|
let shadow_config = options.layout.shadow.merged_with(&rules.shadow);
|
||||||
let is_fullscreen = window.is_fullscreen();
|
let sizing_mode = window.sizing_mode();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
window,
|
window,
|
||||||
border: FocusRing::new(border_config.into()),
|
border: FocusRing::new(border_config.into()),
|
||||||
focus_ring: FocusRing::new(focus_ring_config),
|
focus_ring: FocusRing::new(focus_ring_config),
|
||||||
shadow: Shadow::new(shadow_config),
|
shadow: Shadow::new(shadow_config),
|
||||||
is_fullscreen,
|
sizing_mode,
|
||||||
fullscreen_backdrop: SolidColorBuffer::new((0., 0.), [0., 0., 0., 1.]),
|
fullscreen_backdrop: SolidColorBuffer::new((0., 0.), [0., 0., 0., 1.]),
|
||||||
unfullscreen_to_floating: false,
|
restore_to_floating: false,
|
||||||
floating_window_size: None,
|
floating_window_size: None,
|
||||||
floating_pos: None,
|
floating_pos: None,
|
||||||
floating_preset_width_idx: None,
|
floating_preset_width_idx: None,
|
||||||
@@ -248,8 +251,8 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_window(&mut self) {
|
pub fn update_window(&mut self) {
|
||||||
let was_fullscreen = self.is_fullscreen;
|
let prev_sizing_mode = self.sizing_mode;
|
||||||
self.is_fullscreen = self.window.is_fullscreen();
|
self.sizing_mode = self.window.sizing_mode();
|
||||||
|
|
||||||
if let Some(animate_from) = self.window.take_animation_snapshot() {
|
if let Some(animate_from) = self.window.take_animation_snapshot() {
|
||||||
let params = if let Some(resize) = self.resize_animation.take() {
|
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;
|
size.h = size_from.h + (size.h - size_from.h) * val;
|
||||||
|
|
||||||
let mut tile_size = animate_from.size;
|
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.w = f64::max(tile_size.w, self.view_size.w);
|
||||||
tile_size.h = f64::max(tile_size.h, self.view_size.h);
|
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();
|
let width = self.border.width();
|
||||||
tile_size.w += width * 2.;
|
tile_size.w += width * 2.;
|
||||||
tile_size.h += width * 2.;
|
tile_size.h += width * 2.;
|
||||||
@@ -280,29 +283,56 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
let fullscreen_from = resize
|
let fullscreen_from = resize
|
||||||
.fullscreen_progress
|
.fullscreen_progress
|
||||||
.map(|anim| anim.clamped_value().clamp(0., 1.))
|
.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.
|
// 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 {
|
} else {
|
||||||
let size = animate_from.size;
|
let size = animate_from.size;
|
||||||
|
|
||||||
// Compute like in tile_size().
|
// Compute like in tile_size().
|
||||||
let mut tile_size = 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.w = f64::max(tile_size.w, self.view_size.w);
|
||||||
tile_size.h = f64::max(tile_size.h, self.view_size.h);
|
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();
|
let width = self.border.width();
|
||||||
tile_size.w += width * 2.;
|
tile_size.w += width * 2.;
|
||||||
tile_size.h += 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 = self.window.size().to_f64().to_point() - size_from.to_point();
|
||||||
let change = f64::max(change.x.abs(), change.y.abs());
|
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,
|
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)
|
let fullscreen_progress = (fullscreen_from != fullscreen_to)
|
||||||
.then(|| anim.restarted(fullscreen_from, fullscreen_to, 0.));
|
.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 {
|
self.resize_animation = Some(ResizeAnimation {
|
||||||
anim,
|
anim,
|
||||||
@@ -329,6 +366,7 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
offscreen,
|
offscreen,
|
||||||
tile_size_from,
|
tile_size_from,
|
||||||
fullscreen_progress,
|
fullscreen_progress,
|
||||||
|
expanded_progress,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
self.resize_animation = None;
|
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>) {
|
pub fn update_render_elements(&mut self, is_active: bool, view_rect: Rectangle<f64, Logical>) {
|
||||||
let rules = self.window.rules();
|
let rules = self.window.rules();
|
||||||
let animated_tile_size = self.animated_tile_size();
|
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
|
let draw_border_with_background = rules
|
||||||
.draw_border_with_background
|
.draw_border_with_background
|
||||||
@@ -425,7 +463,7 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
.map_or(CornerRadius::default(), |radius| {
|
.map_or(CornerRadius::default(), |radius| {
|
||||||
radius.expanded_by(border_width as f32)
|
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(
|
self.border.update_render_elements(
|
||||||
border_window_size,
|
border_window_size,
|
||||||
is_active,
|
is_active,
|
||||||
@@ -437,7 +475,7 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
),
|
),
|
||||||
radius,
|
radius,
|
||||||
self.scale,
|
self.scale,
|
||||||
1. - fullscreen_progress as f32,
|
1. - expanded_progress as f32,
|
||||||
);
|
);
|
||||||
|
|
||||||
let radius = if self.visual_border_width().is_some() {
|
let radius = if self.visual_border_width().is_some() {
|
||||||
@@ -446,17 +484,17 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
rules
|
rules
|
||||||
.geometry_corner_radius
|
.geometry_corner_radius
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.scaled_by(1. - fullscreen_progress as f32)
|
.scaled_by(1. - expanded_progress as f32)
|
||||||
};
|
};
|
||||||
self.shadow.update_render_elements(
|
self.shadow.update_render_elements(
|
||||||
animated_tile_size,
|
animated_tile_size,
|
||||||
is_active,
|
is_active,
|
||||||
radius,
|
radius,
|
||||||
self.scale,
|
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
|
draw_border_with_background
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@@ -470,7 +508,7 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
view_rect,
|
view_rect,
|
||||||
radius,
|
radius,
|
||||||
self.scale,
|
self.scale,
|
||||||
1. - fullscreen_progress as f32,
|
1. - expanded_progress as f32,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.fullscreen_backdrop.resize(animated_tile_size);
|
self.fullscreen_backdrop.resize(animated_tile_size);
|
||||||
@@ -609,8 +647,8 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
&mut self.window
|
&mut self.window
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_fullscreen(&self) -> bool {
|
pub fn sizing_mode(&self) -> SizingMode {
|
||||||
self.is_fullscreen
|
self.sizing_mode
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fullscreen_progress(&self) -> f64 {
|
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.
|
1.
|
||||||
} else {
|
} else {
|
||||||
0.
|
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.
|
/// Returns `None` if the border is hidden and `Some(width)` if it should be shown.
|
||||||
pub fn effective_border_width(&self) -> Option<f64> {
|
pub fn effective_border_width(&self) -> Option<f64> {
|
||||||
if self.is_fullscreen {
|
if !self.sizing_mode.is_normal() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -645,10 +697,10 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
return None;
|
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.
|
// Only hide the border when fully expanded to avoid jarring border appearance.
|
||||||
if fullscreen_progress == 1. {
|
if expanded_progress == 1. {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -688,7 +740,7 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
pub fn tile_size(&self) -> Size<f64, Logical> {
|
pub fn tile_size(&self) -> Size<f64, Logical> {
|
||||||
let mut size = self.window_size();
|
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
|
// 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.
|
// nicer if a fullscreen window is bigger than the fullscreen size for some reason.
|
||||||
size.w = f64::max(size.w, self.view_size.w);
|
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> {
|
pub fn tile_expected_or_current_size(&self) -> Size<f64, Logical> {
|
||||||
let mut size = self.window_expected_or_current_size();
|
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
|
// 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.
|
// nicer if a fullscreen window is bigger than the fullscreen size for some reason.
|
||||||
size.w = f64::max(size.w, self.view_size.w);
|
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
|
// 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
|
// round to avoid situations where proportionally-sized columns don't fit on the screen
|
||||||
// exactly.
|
// exactly.
|
||||||
self.window
|
self.window.request_size(
|
||||||
.request_size(size.to_i32_floor(), false, animate, transaction);
|
size.to_i32_floor(),
|
||||||
|
SizingMode::Normal,
|
||||||
|
animate,
|
||||||
|
transaction,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tile_width_for_window_width(&self, size: f64) -> f64 {
|
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>) {
|
pub fn request_fullscreen(&mut self, animate: bool, transaction: Option<Transaction>) {
|
||||||
self.window
|
self.window.request_size(
|
||||||
.request_size(self.view_size.to_i32_round(), true, animate, transaction);
|
self.view_size.to_i32_round(),
|
||||||
|
SizingMode::Fullscreen,
|
||||||
|
animate,
|
||||||
|
transaction,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn min_size_nonfullscreen(&self) -> Size<f64, Logical> {
|
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 scale = Scale::from(self.scale);
|
||||||
let fullscreen_progress = self.fullscreen_progress();
|
let fullscreen_progress = self.fullscreen_progress();
|
||||||
|
let expanded_progress = self.expanded_progress();
|
||||||
|
|
||||||
let win_alpha = if self.window.is_ignoring_opacity_window_rule() {
|
let win_alpha = if self.window.is_ignoring_opacity_window_rule() {
|
||||||
1.
|
1.
|
||||||
@@ -968,7 +1043,7 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
let radius = rules
|
let radius = rules
|
||||||
.geometry_corner_radius
|
.geometry_corner_radius
|
||||||
.unwrap_or_default()
|
.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.
|
// If we're resizing, try to render a shader, or a fallback.
|
||||||
let mut resize_shader = None;
|
let mut resize_shader = None;
|
||||||
@@ -1153,7 +1228,7 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
.map_or(CornerRadius::default(), |radius| {
|
.map_or(CornerRadius::default(), |radius| {
|
||||||
radius.expanded_by(border_width as f32)
|
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 size = self.fullscreen_backdrop.size();
|
||||||
let color = self.fullscreen_backdrop.color();
|
let color = self.fullscreen_backdrop.color();
|
||||||
@@ -1191,13 +1266,15 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
});
|
});
|
||||||
let rv = rv.chain(elem.into_iter().flatten());
|
let rv = rv.chain(elem.into_iter().flatten());
|
||||||
|
|
||||||
// Hide the focus ring when fullscreened. It's not normally visible anyway due to being
|
// Hide the focus ring when maximized/fullscreened. It's not normally visible anyway due to
|
||||||
// outside the monitor, but it is visible in the overview (which is a bit weird).
|
// being outside the monitor or obscured by a solid colored bar, but it is visible under
|
||||||
let elem = (focus_ring && fullscreen_progress < 1.)
|
// 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));
|
.then(|| self.focus_ring.render(renderer, location).map(Into::into));
|
||||||
let rv = rv.chain(elem.into_iter().flatten());
|
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));
|
.then(|| self.shadow.render(renderer, location).map(Into::into));
|
||||||
rv.chain(elem.into_iter().flatten())
|
rv.chain(elem.into_iter().flatten())
|
||||||
}
|
}
|
||||||
@@ -1328,7 +1405,7 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
pub fn verify_invariants(&self) {
|
pub fn verify_invariants(&self) {
|
||||||
use approx::assert_abs_diff_eq;
|
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 scale = self.scale;
|
||||||
let size = self.tile_size();
|
let size = self.tile_size();
|
||||||
|
|||||||
+106
-25
@@ -611,16 +611,16 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
is_floating: bool,
|
is_floating: bool,
|
||||||
) {
|
) {
|
||||||
self.enter_output_for_window(tile.window());
|
self.enter_output_for_window(tile.window());
|
||||||
tile.unfullscreen_to_floating = is_floating;
|
tile.restore_to_floating = is_floating;
|
||||||
|
|
||||||
match target {
|
match target {
|
||||||
WorkspaceAddWindowTarget::Auto => {
|
WorkspaceAddWindowTarget::Auto => {
|
||||||
// Don't steal focus from an active fullscreen window.
|
// Don't steal focus from an active fullscreen window.
|
||||||
let activate = activate.map_smart(|| !self.is_active_pending_fullscreen());
|
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
|
// If the tile is pending maximized or fullscreen, open it in the scrolling layout
|
||||||
// go fullscreen.
|
// where it can do that.
|
||||||
if is_floating && !tile.window().is_pending_fullscreen() {
|
if is_floating && tile.window().pending_sizing_mode().is_normal() {
|
||||||
self.floating.add_tile(tile, activate);
|
self.floating.add_tile(tile, activate);
|
||||||
|
|
||||||
if activate || self.scrolling.is_empty() {
|
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);
|
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 {
|
if floating_has_window {
|
||||||
self.floating.add_tile_above(next_to, tile, activate);
|
self.floating.add_tile_above(next_to, tile, activate);
|
||||||
} else {
|
} else {
|
||||||
@@ -869,6 +869,8 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
toplevel.with_pending_state(|state| {
|
toplevel.with_pending_state(|state| {
|
||||||
if state.states.contains(xdg_toplevel::State::Fullscreen) {
|
if state.states.contains(xdg_toplevel::State::Fullscreen) {
|
||||||
state.size = Some(self.view_size.to_i32_round());
|
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 {
|
} else {
|
||||||
let size =
|
let size =
|
||||||
self.new_window_size(width, height, is_floating, rules, (min_size, max_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) {
|
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 self.floating.has_window(window) {
|
||||||
if is_fullscreen {
|
if is_fullscreen {
|
||||||
unfullscreen_to_floating = true;
|
restore_to_floating = true;
|
||||||
self.toggle_window_floating(Some(window));
|
self.toggle_window_floating(Some(window));
|
||||||
} else {
|
} else {
|
||||||
// Floating windows are never fullscreen, so this is an unfullscreen request for an
|
// 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
|
// 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
|
// indeed fullscreen (i.e. this isn't a duplicate unfullscreen request), then we may
|
||||||
// need to unfullscreen into floating.
|
// need to unfullscreen into floating.
|
||||||
let tile = self
|
let col = self
|
||||||
.scrolling
|
.scrolling
|
||||||
.tiles()
|
.columns()
|
||||||
.find(|tile| tile.window().id() == window)
|
.find(|col| col.contains(window))
|
||||||
.unwrap();
|
.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
|
// When going from fullscreen to maximized, don't consider restore_to_floating yet.
|
||||||
// (0, 0) size, rather than the scrolling column size.
|
if col.is_pending_fullscreen() && !col.is_pending_maximized() {
|
||||||
self.toggle_window_floating(Some(window));
|
let (tile, _) = col
|
||||||
return;
|
.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.
|
self.scrolling.set_fullscreen(window, is_fullscreen);
|
||||||
if changed && is_fullscreen {
|
|
||||||
let tile = self
|
|
||||||
.scrolling
|
|
||||||
.tiles_mut()
|
|
||||||
.find(|tile| tile.window().id() == window)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
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()
|
.tiles()
|
||||||
.find(|tile| tile.window().id() == window)
|
.find(|tile| tile.window().id() == window)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let current = tile.window().is_pending_fullscreen();
|
let current = tile.window().pending_sizing_mode().is_fullscreen();
|
||||||
self.set_fullscreen(window, !current);
|
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>) {
|
pub fn toggle_window_floating(&mut self, id: Option<&W::Id>) {
|
||||||
let active_id = self.active_window().map(|win| win.id().clone());
|
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());
|
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 compositor_state = CompositorState::new_v6::<State>(&display_handle);
|
||||||
let xdg_shell_state = XdgShellState::new_with_capabilities::<State>(
|
let xdg_shell_state = XdgShellState::new_with_capabilities::<State>(
|
||||||
&display_handle,
|
&display_handle,
|
||||||
[WmCapabilities::Fullscreen],
|
[WmCapabilities::Fullscreen, WmCapabilities::Maximize],
|
||||||
);
|
);
|
||||||
let xdg_decoration_state =
|
let xdg_decoration_state =
|
||||||
XdgDecorationState::new_with_filter::<State, _>(&display_handle, |client| {
|
XdgDecorationState::new_with_filter::<State, _>(&display_handle, |client| {
|
||||||
@@ -5545,11 +5545,12 @@ impl Niri {
|
|||||||
let _span = tracy_client::span!("Niri::screenshot_window");
|
let _span = tracy_client::span!("Niri::screenshot_window");
|
||||||
|
|
||||||
let scale = Scale::from(output.current_scale().fractional_scale());
|
let scale = Scale::from(output.current_scale().fractional_scale());
|
||||||
let alpha = if mapped.is_fullscreen() || mapped.is_ignoring_opacity_window_rule() {
|
let alpha =
|
||||||
1.
|
if mapped.sizing_mode().is_fullscreen() || mapped.is_ignoring_opacity_window_rule() {
|
||||||
} else {
|
1.
|
||||||
mapped.rules().opacity.unwrap_or(1.).clamp(0., 1.)
|
} else {
|
||||||
};
|
mapped.rules().opacity.unwrap_or(1.).clamp(0., 1.)
|
||||||
|
};
|
||||||
// FIXME: pointer.
|
// FIXME: pointer.
|
||||||
let elements = mapped.render(
|
let elements = mapped.render(
|
||||||
renderer,
|
renderer,
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ pub trait ForeignToplevelHandler {
|
|||||||
fn close(&mut self, wl_surface: WlSurface);
|
fn close(&mut self, wl_surface: WlSurface);
|
||||||
fn set_fullscreen(&mut self, wl_surface: WlSurface, wl_output: Option<WlOutput>);
|
fn set_fullscreen(&mut self, wl_surface: WlSurface, wl_output: Option<WlOutput>);
|
||||||
fn unset_fullscreen(&mut self, wl_surface: WlSurface);
|
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 {
|
struct ToplevelData {
|
||||||
@@ -388,8 +390,10 @@ where
|
|||||||
let surface = surface.clone();
|
let surface = surface.clone();
|
||||||
|
|
||||||
match request {
|
match request {
|
||||||
zwlr_foreign_toplevel_handle_v1::Request::SetMaximized => (),
|
zwlr_foreign_toplevel_handle_v1::Request::SetMaximized => state.set_maximized(surface),
|
||||||
zwlr_foreign_toplevel_handle_v1::Request::UnsetMaximized => (),
|
zwlr_foreign_toplevel_handle_v1::Request::UnsetMaximized => {
|
||||||
|
state.unset_maximized(surface)
|
||||||
|
}
|
||||||
zwlr_foreign_toplevel_handle_v1::Request::SetMinimized => (),
|
zwlr_foreign_toplevel_handle_v1::Request::SetMinimized => (),
|
||||||
zwlr_foreign_toplevel_handle_v1::Request::UnsetMinimized => (),
|
zwlr_foreign_toplevel_handle_v1::Request::UnsetMinimized => (),
|
||||||
zwlr_foreign_toplevel_handle_v1::Request::Activate { .. } => {
|
zwlr_foreign_toplevel_handle_v1::Request::Activate { .. } => {
|
||||||
|
|||||||
@@ -357,6 +357,14 @@ impl Window {
|
|||||||
self.xdg_toplevel.unset_fullscreen();
|
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>) {
|
pub fn set_parent(&self, parent: Option<&XdgToplevel>) {
|
||||||
self.xdg_toplevel.set_parent(parent);
|
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]
|
#[test]
|
||||||
fn resize_during_interactive_move_propagates_to_floating() {
|
fn resize_during_interactive_move_propagates_to_floating() {
|
||||||
let (mut f, id, surface) = set_up();
|
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]
|
#[test]
|
||||||
fn floating_respects_non_fixed_min_max_rule() {
|
fn floating_respects_non_fixed_min_max_rule() {
|
||||||
let config = r##"
|
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]
|
#[test]
|
||||||
fn unfullscreen_to_same_size_floating() {
|
fn unfullscreen_to_same_size_floating() {
|
||||||
let (mut f, id, surface) = set_up();
|
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]
|
#[test]
|
||||||
fn unfullscreen_to_same_size_windowed_fullscreen_floating() {
|
fn unfullscreen_to_same_size_windowed_fullscreen_floating() {
|
||||||
let (mut f, id, surface) = set_up();
|
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]
|
#[test]
|
||||||
fn unfullscreen_to_same_size_same_bounds_floating() {
|
fn unfullscreen_to_same_size_same_bounds_floating() {
|
||||||
let config = r##"
|
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]
|
#[test]
|
||||||
fn repeated_size_request() {
|
fn repeated_size_request() {
|
||||||
let (mut f, id, surface) = set_up();
|
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;
|
let mapped = f.niri().layout.windows().next().unwrap().1;
|
||||||
format!(
|
format!(
|
||||||
"fs {}, wfs {}",
|
"fs {}, wfs {}",
|
||||||
mapped.is_fullscreen(),
|
mapped.sizing_mode().is_fullscreen(),
|
||||||
mapped.is_windowed_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]"
|
@"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