Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: regression in layouting with fullscreen state and various taskbar alignments #823

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions packages/wm/src/common/commands/platform_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use tokio::task;
use tracing::warn;

use crate::{
common::{platform::Platform, DisplayState},
common::{platform::Platform, DisplayState, Rect},
containers::{
traits::{CommonGetters, PositionGetters},
Container, WindowContainer,
Expand Down Expand Up @@ -125,9 +125,17 @@ fn redraw_containers(state: &mut WmState) -> anyhow::Result<()> {
},
);

let rect = window
.to_rect()?
.apply_delta(&window.total_border_delta()?, None);
let current_rect = window.to_rect()?;
let current_rect_width = current_rect.width();
let current_rect_height = current_rect.height();

let total_border_delta = &window.total_border_delta()?;
let new_rect = Rect::from_ltrb(
current_rect.left - total_border_delta.left.to_px(current_rect_width, None),
current_rect.top - total_border_delta.top.to_px(current_rect_height, None),
current_rect.right + total_border_delta.right.to_px(current_rect_width, None),
current_rect.bottom + total_border_delta.bottom.to_px(current_rect_height, None),
);

let is_visible = matches!(
window.display_state(),
Expand All @@ -136,7 +144,7 @@ fn redraw_containers(state: &mut WmState) -> anyhow::Result<()> {

if let Err(err) = window.native().set_position(
&window.state(),
&rect,
&new_rect,
is_visible,
window.has_pending_dpi_adjustment(),
) {
Expand Down
18 changes: 14 additions & 4 deletions packages/wm/src/common/events/handle_window_focused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ use anyhow::Context;
use tracing::info;

use crate::{
common::{platform::NativeWindow, DisplayState},
common::{
platform::NativeWindow,
DisplayState
},
containers::{commands::set_focused_descendant, traits::CommonGetters},
user_config::{UserConfig, WindowRuleEvent},
windows::{commands::run_window_rules, traits::WindowGetters},
windows::{commands::{run_window_rules, update_window_state}, traits::WindowGetters, WindowState},
wm_state::WmState,
workspaces::{commands::focus_workspace, WorkspaceTarget},
workspaces::{commands::focus_workspace, WorkspaceTarget}
};

pub fn handle_window_focused(
Expand All @@ -27,9 +30,16 @@ pub fn handle_window_focused(
return Ok(());
}

// Handle minimizing fullscreen window if another non-floating window container is being focused
if let Some(fullscreen_window) = window.workspace().unwrap().get_fullscreen_window() {
if !matches!(window.state(), WindowState::Floating(_)) {
update_window_state(fullscreen_window, WindowState::Minimized, state, config)?;
}
}

// TODO: Log window details.
info!("Window focused");

// Handle overriding focus on close/minimize. After a window is closed
// or minimized, the OS or the closed application might automatically
// switch focus to a different window. To force focus to go to the WM's
Expand Down
2 changes: 1 addition & 1 deletion packages/wm/src/common/events/handle_window_hidden.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub fn handle_window_hidden(
return Ok(());
}

// Unmanage the window if it's not in a display state transition. Also,
// Unmanage thed window if it's not in a display state transition. Also,
// since window events are not 100% guaranteed to be in correct order,
// we need to ignore events where the window is not actually hidden.
if window.display_state() == DisplayState::Shown
Expand Down
24 changes: 9 additions & 15 deletions packages/wm/src/common/events/handle_window_location_changed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
common::{platform::NativeWindow, Rect},
containers::{
commands::{flatten_split_container, move_container_within_tree},
traits::{CommonGetters, PositionGetters},
traits::CommonGetters,
WindowContainer,
},
try_warn,
Expand All @@ -26,6 +26,7 @@ pub fn handle_window_location_changed(

// Update the window's state to be fullscreen or toggled from fullscreen.
if let Some(window) = found_window {

let old_frame_position = window.native().frame_position()?;
let frame_position =
try_warn!(window.native().refresh_frame_position());
Expand All @@ -49,21 +50,13 @@ pub fn handle_window_location_changed(
config,
)?;
}

let monitor_rect = if config.has_outer_gaps() {
nearest_monitor.native().working_rect()?.clone()
} else {
nearest_monitor.to_rect()?
};

let is_fullscreen = window.native().is_fullscreen(&monitor_rect)?;

match window.state() {
WindowState::Fullscreen(fullscreen_state) => {
// A fullscreen window that gets minimized can hit this arm, so
// A full working area window that gets minimized can hit this arm, so
// ignore such events and let it be handled by the handler for
// `PlatformEvent::WindowMinimized` instead.
if !(is_fullscreen || is_maximized || !is_minimized) {
let is_full_work_area = window.native().is_full_work_area(&nearest_monitor.native())?;
if !(is_full_work_area || is_maximized) && !is_minimized {
info!("Window restored");

let target_state = window
Expand Down Expand Up @@ -92,9 +85,10 @@ pub fn handle_window_location_changed(
}
_ => {
// Update the window to be fullscreen if there's been a change in
// maximized state or if the window is now fullscreen.
if (is_maximized && old_is_maximized != is_maximized)
|| is_fullscreen
// maximized state
let is_fullscreen = window.native()
.is_fullscreen(&nearest_monitor.native())?;
if (is_maximized && old_is_maximized != is_maximized) || is_fullscreen
{
info!("Window fullscreened");

Expand Down
15 changes: 9 additions & 6 deletions packages/wm/src/common/events/handle_window_minimize_ended.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
use tracing::info;

use crate::{
common::platform::NativeWindow,
try_warn,
user_config::UserConfig,
windows::{
common::platform::NativeWindow, containers::traits::CommonGetters, try_warn, user_config::UserConfig, windows::{
commands::update_window_state, traits::WindowGetters, WindowState,
},
wm_state::WmState,
}, wm_state::WmState
};

pub fn handle_window_minimize_ended(
Expand All @@ -24,6 +20,13 @@ pub fn handle_window_minimize_ended(
if !is_minimized && window.state() == WindowState::Minimized {
// TODO: Log window details.
info!("Window minimize ended");

// Handle minimizing fullscreen window if another non-floating window container is ending being minimized
if let Some(fullscreen_window) = window.workspace().unwrap().get_fullscreen_window() {
if !matches!(window.state(), WindowState::Floating(_)) {
update_window_state(fullscreen_window, WindowState::Minimized, state, config)?;
}
}

let target_state = window
.prev_state()
Expand Down
36 changes: 19 additions & 17 deletions packages/wm/src/common/platform/native_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ use crate::{
windows::WindowState,
};

use super::NativeMonitor;

#[derive(Debug, Clone)]
pub struct NativeWindow {
pub handle: isize,
Expand Down Expand Up @@ -258,28 +260,28 @@ impl NativeWindow {
self.has_window_style(WS_THICKFRAME)
}

/// Whether the window is fullscreen.
///
/// Returns `false` if the window is maximized.
pub fn is_fullscreen(
&self,
monitor_rect: &Rect,
) -> anyhow::Result<bool> {
if self.is_maximized()? {
return Ok(false);
}

let position = self.frame_position()?;
fn is_fullscreen_rect(&self, rect: &Rect) -> anyhow::Result<bool> {
let window_position = self.frame_position()?;

// Allow for 1px of leeway around edges of monitor.
Ok(
position.left <= monitor_rect.left + 1
&& position.top <= monitor_rect.top + 1
&& position.right >= monitor_rect.right - 1
&& position.bottom >= monitor_rect.bottom - 1,
window_position.left <= rect.left &&
window_position.top <= rect.top &&
window_position.right >= rect.right &&
window_position.bottom >= rect.bottom
)
}

// Whether the window fully fills work area of specified monitor.
pub fn is_full_work_area(&self, monitor: &NativeMonitor) -> anyhow::Result<bool> {
return Ok(self.is_fullscreen_rect(monitor.working_rect()?)?);
}

/// Whether the window is fullscreen on specified monitor.
pub fn is_fullscreen(&self, monitor: &NativeMonitor) -> anyhow::Result<bool> {
return Ok(self.is_fullscreen_rect(monitor.rect()?)?);
}

pub fn set_foreground(&self) -> anyhow::Result<()> {
let input = [INPUT {
r#type: INPUT_MOUSE,
Expand Down Expand Up @@ -474,7 +476,7 @@ impl NativeWindow {
let current_style =
unsafe { GetWindowLongPtrW(HWND(self.handle), GWL_STYLE) };

(current_style & style.0 as isize) != 0
(current_style & (style.0 as isize)) != 0
}

fn has_window_style_ex(&self, style: WINDOW_EX_STYLE) -> bool {
Expand Down
26 changes: 0 additions & 26 deletions packages/wm/src/common/rect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,32 +125,6 @@ impl Rect {
}
}

pub fn apply_delta(
&self,
delta: &RectDelta,
scale_factor: Option<f32>,
) -> Self {
Self::from_ltrb(
self.left - delta.left.to_px(self.width(), scale_factor),
self.top - delta.top.to_px(self.height(), scale_factor),
self.right + delta.right.to_px(self.width(), scale_factor),
self.bottom + delta.bottom.to_px(self.height(), scale_factor),
)
}

pub fn apply_inverse_delta(
&self,
delta: &RectDelta,
scale_factor: Option<f32>,
) -> Self {
Self::from_ltrb(
self.left + delta.left.to_px(self.width(), scale_factor),
self.top + delta.top.to_px(self.height(), scale_factor),
self.right - delta.right.to_px(self.width(), scale_factor),
self.bottom - delta.bottom.to_px(self.height(), scale_factor),
)
}

// Gets whether the x-coordinate overlaps with the x-coordinate of the
// other rect.
pub fn has_overlap_x(&self, other: &Rect) -> bool {
Expand Down
10 changes: 0 additions & 10 deletions packages/wm/src/user_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,16 +330,6 @@ impl UserConfig {
self.workspace_config_index(&workspace.config().name)
});
}

pub fn has_outer_gaps(&self) -> bool {
let outer_gap = &self.value.gaps.outer_gap;

// Allow for 1px/1% of leeway.
outer_gap.bottom.amount > 1.0
|| outer_gap.left.amount > 1.0
|| outer_gap.right.amount > 1.0
|| outer_gap.top.amount > 1.0
}
}

#[derive(Clone, Debug, Deserialize, Serialize)]
Expand Down
17 changes: 9 additions & 8 deletions packages/wm/src/windows/commands/manage_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
try_warn,
user_config::{UserConfig, WindowRuleEvent},
windows::{
commands::run_window_rules, traits::WindowGetters, NonTilingWindow,
commands::{run_window_rules, update_window_state}, traits::WindowGetters, NonTilingWindow,
TilingWindow, WindowState,
},
wm_event::WmEvent,
Expand Down Expand Up @@ -46,6 +46,13 @@ pub fn manage_window(
// TODO: Log window details.
info!("New window managed");

// Handle minimizing fullscreen window if another non-floating window container is being managed
if let Some(fullscreen_window) = window.workspace().unwrap().get_fullscreen_window() {
if !matches!(window.state(), WindowState::Floating(_)) {
update_window_state(fullscreen_window, WindowState::Minimized, state, config)?;
}
}

state.emit_event(WmEvent::WindowManaged {
managed_window: window.to_dto()?,
});
Expand Down Expand Up @@ -182,13 +189,7 @@ fn window_state_to_create(
return Ok(WindowState::Minimized);
}

let monitor_rect = if config.has_outer_gaps() {
nearest_monitor.native().working_rect()?.clone()
} else {
nearest_monitor.to_rect()?
};

if native_window.is_fullscreen(&monitor_rect)? {
if native_window.is_fullscreen(&nearest_monitor.native())? {
return Ok(WindowState::Fullscreen(
config
.value
Expand Down
7 changes: 7 additions & 0 deletions packages/wm/src/windows/commands/update_window_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ pub fn update_window_state(

info!("Updating window state: {:?}.", target_state);

// Handle minimizing fullscreen window if floating window container is changing its state to non-floating state
if let Some(fullscreen_window) = window.workspace().unwrap().get_fullscreen_window() {
if window != fullscreen_window && !matches!(target_state, WindowState::Floating(_)) && matches!(window.state(), WindowState::Floating(_)) {
update_window_state(fullscreen_window, WindowState::Minimized, state, config)?;
}
}

match target_state {
WindowState::Tiling => set_tiling(window, state, config),
_ => set_non_tiling(window, target_state, state),
Expand Down
6 changes: 5 additions & 1 deletion packages/wm/src/windows/non_tiling_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,11 @@ impl PositionGetters for NonTilingWindow {
fn to_rect(&self) -> anyhow::Result<Rect> {
match self.state() {
WindowState::Fullscreen(_) => {
self.monitor().context("No monitor.")?.to_rect()
let native_monitor = self.monitor().context("No monitor.")?.native();
Ok(match self.native().is_fullscreen(&native_monitor)? {
true => native_monitor.rect()?.clone(),
false => native_monitor.working_rect()?.clone()
})
}
_ => Ok(self.floating_placement()),
}
Expand Down
Loading