Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 0 additions & 5 deletions src/actor/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,11 +457,6 @@ impl State {
return Ok(false);
}

// If we don't know this window, nothing to verify.
if !self.windows.contains_key(&wid) {
return Ok(false);
}

// Trigger a visible windows refresh. If the window is gone, the reactor
// will detect it via missing membership and tear down state.
*request = Request::GetVisibleWindows;
Expand Down
25 changes: 14 additions & 11 deletions src/actor/reactor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod display_topology;
mod events;
mod main_window;
mod managers;
mod native_tabs;
mod query;
mod replay;
pub mod transaction_manager;
Expand Down Expand Up @@ -65,8 +66,8 @@ type Receiver = actor::Receiver<Event>;
pub use query::ReactorQueryHandle;

pub(crate) use crate::model::reactor::{
AppState, FullscreenSpaceTrack, FullscreenWindowTrack, PendingSpaceChange, WindowFilter,
WindowState,
AppState, FullscreenSpaceTrack, FullscreenWindowTrack, NativeTabMembership, NativeTabRole,
PendingSpaceChange, WindowFilter, WindowState,
};
pub use crate::model::reactor::{
Command, DisplaySelector, DragSession, DragState, MenuState, MissionControlState,
Expand Down Expand Up @@ -238,6 +239,7 @@ pub struct Reactor {
app_manager: managers::AppManager,
layout_manager: managers::LayoutManager,
window_manager: managers::WindowManager,
native_tab_manager: managers::NativeTabManager,
window_server_info_manager: managers::WindowServerInfoManager,
space_manager: managers::SpaceManager,
space_activation_policy: SpaceActivationPolicy,
Expand Down Expand Up @@ -318,6 +320,7 @@ impl Reactor {
visible_windows: HashSet::default(),
observed_window_server_ids: HashSet::default(),
},
native_tab_manager: managers::NativeTabManager::new(),
window_server_info_manager: managers::WindowServerInfoManager {
window_server_info: HashMap::default(),
},
Expand Down Expand Up @@ -972,6 +975,9 @@ impl Reactor {
self.set_login_window_active(false);
}
}
Event::ApplicationMainWindowChanged(pid, wid, quiet) => {
self.handle_native_tab_main_window_changed(pid, wid, quiet);
}
Event::ResyncAppForWindow(wsid) => {
AppEventHandler::handle_resync_app_for_window(self, wsid);
}
Expand Down Expand Up @@ -1682,13 +1688,6 @@ impl Reactor {
self.screen_for_point(window_center).map(|_| window_center)
}

fn has_visible_window_server_ids_for_pid(&self, pid: pid_t) -> bool {
self.window_manager
.visible_windows
.iter()
.any(|wsid| self.window_manager.window_ids.get(wsid).is_some_and(|wid| wid.pid == pid))
}

fn warp_mouse_to_space_center(&self, space: SpaceId) -> bool {
let Some(screen) = self.space_manager.screen_by_space(space) else {
return false;
Expand Down Expand Up @@ -1935,8 +1934,8 @@ impl Reactor {
window.ignore_app_rule = false;
}

let effective_floating = assignment.floating
|| (!assignment.prev_rule_decision && was_floating);
let effective_floating =
assignment.floating || (!assignment.prev_rule_decision && was_floating);
let needs_layout_refresh =
!was_assigned || was_floating != effective_floating || was_ignored;
if needs_layout_refresh {
Expand Down Expand Up @@ -2728,6 +2727,10 @@ impl Reactor {
self.maybe_send_menu_update();
}

fn refresh_all_windows_without_pending_refresh(&mut self) {
self.request_visible_windows_for_apps(false);
}

fn force_refresh_all_windows(&mut self) { self.request_visible_windows_for_apps(true); }

fn request_close_window(&mut self, wid: WindowId) {
Expand Down
76 changes: 74 additions & 2 deletions src/actor/reactor/animation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ impl AnimationManager {
let mut animated_count = 0;
let mut animated_wids_wsids: Vec<u32> = Vec::new();
let mut any_frame_changed = false;
let mut synced_native_tab_wids = Vec::new();

for &(wid, target_frame) in layout {
// Skip applying layout frames and animations for the window currently being dragged.
Expand All @@ -182,8 +183,16 @@ impl AnimationManager {
if target_frame.same_as(current_frame) {
continue;
}
let Some(wsid) = window.info.sys_id else {
trace!(
?wid,
?current_frame,
?target_frame,
"Skipping animation for window without window server id"
);
continue;
};
any_frame_changed = true;
let wsid = window.info.sys_id.unwrap();
let txid = reactor.transaction_manager.generate_next_txid(wsid);
(current_frame, Some(wsid), txid)
}
Expand All @@ -193,7 +202,7 @@ impl AnimationManager {
}
};

let Some(app_state) = &reactor.app_manager.apps.get(&wid.pid) else {
let Some(app_state) = reactor.app_manager.apps.get(&wid.pid) else {
debug!(?wid, "Skipping for window - app no longer exists");
continue;
};
Expand Down Expand Up @@ -234,6 +243,7 @@ impl AnimationManager {
if let Some(window) = reactor.window_manager.windows.get_mut(&wid) {
window.frame_monotonic = target_frame;
}
synced_native_tab_wids.push(wid);
}

if animated_count > 0 {
Expand All @@ -250,6 +260,9 @@ impl AnimationManager {
anim.run();
}
}
for wid in synced_native_tab_wids {
reactor.handle_native_tab_frame_changed(wid, true);
}

any_frame_changed
}
Expand Down Expand Up @@ -278,6 +291,15 @@ impl AnimationManager {
if target_frame.same_as(current_frame) {
continue;
}
if window.info.sys_id.is_none() {
trace!(
?wid,
?current_frame,
?target_frame,
"Skipping instant layout for window without window server id"
);
continue;
}
any_frame_changed = true;
trace!(
?wid,
Expand Down Expand Up @@ -339,9 +361,59 @@ impl AnimationManager {
if let Some(window) = reactor.window_manager.windows.get_mut(wid) {
window.frame_monotonic = *target_frame;
}
reactor.handle_native_tab_frame_changed(*wid, true);
}
}

any_frame_changed
}
}

#[cfg(test)]
mod tests {
use objc2_core_foundation::{CGPoint, CGRect, CGSize};

use super::AnimationManager;
use crate::actor::reactor::testing::{Apps, make_window, screen_params_event};
use crate::actor::reactor::{Reactor, WindowId};
use crate::layout_engine::LayoutEngine;
use crate::sys::screen::SpaceId;

#[test]
fn layout_application_skips_windows_without_window_server_ids() {
let mut apps = Apps::new();
let mut reactor = Reactor::new_for_test(LayoutEngine::new(
&crate::common::config::VirtualWorkspaceSettings::default(),
&crate::common::config::LayoutSettings::default(),
None,
));
let space = SpaceId::new(90);
reactor.handle_event(screen_params_event(
vec![CGRect::new(CGPoint::new(0., 0.), CGSize::new(1000., 1000.))],
vec![Some(space)],
vec![],
));

reactor.handle_events(apps.make_app(1, vec![make_window(1)]));
apps.simulate_until_quiet(&mut reactor);
let _ = apps.requests();

let wid = WindowId::new(1, 1);
let target = CGRect::new(CGPoint::new(300., 50.), CGSize::new(400., 700.));
reactor.window_manager.windows.get_mut(&wid).unwrap().info.sys_id = None;

assert!(!AnimationManager::animate_layout(
&mut reactor,
space,
&[(wid, target)],
false,
None,
));
assert!(!AnimationManager::instant_layout(
&mut reactor,
&[(wid, target)],
None,
));
assert!(apps.requests().is_empty());
}
}
1 change: 1 addition & 0 deletions src/actor/reactor/events/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ impl AppEventHandler {
}

pub fn handle_application_thread_terminated(reactor: &mut Reactor, pid: i32) {
reactor.handle_native_tab_app_terminated(pid);
reactor.app_manager.apps.remove(&pid);
reactor.send_layout_event(LayoutEvent::AppClosed(pid));
}
Expand Down
1 change: 1 addition & 0 deletions src/actor/reactor/events/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,7 @@ impl CommandEventHandler {
if let Some(state) = reactor.window_manager.windows.get_mut(&window_id) {
state.frame_monotonic = target_frame;
}
reactor.handle_native_tab_frame_changed(window_id, true);

let response = reactor.layout_manager.layout_engine.move_window_to_space(
source_space,
Expand Down
4 changes: 4 additions & 0 deletions src/actor/reactor/events/drag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub struct DragEventHandler;
impl DragEventHandler {
pub fn handle_mouse_up(reactor: &mut Reactor) {
let mut need_layout_refresh = false;
let dragged_wid = reactor.drag_manager.dragged();

let pending_swap = reactor.get_pending_drag_swap();

Expand Down Expand Up @@ -71,5 +72,8 @@ impl DragEventHandler {
}

reactor.drag_manager.skip_layout_for_window = None;
if let Some(wid) = dragged_wid {
reactor.handle_native_tab_frame_changed(wid, true);
}
}
}
24 changes: 21 additions & 3 deletions src/actor/reactor/events/space.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,16 @@ impl SpaceEventHandler {
return;
}

if reactor.stage_native_tab_destroy(wsid, sid) {
if let Some(&wid) = reactor.window_manager.window_ids.get(&wsid)
&& let Some(app_state) = reactor.app_manager.apps.get(&wid.pid)
&& let Err(e) = app_state.handle.send(Request::WindowMaybeDestroyed(wid))
{
warn!("Failed to send WindowMaybeDestroyed: {}", e);
}
return;
}

if let Some(&wid) = reactor.window_manager.window_ids.get(&wsid) {
reactor.window_manager.window_ids.remove(&wsid);
reactor.window_server_info_manager.window_server_info.remove(&wsid);
Expand Down Expand Up @@ -90,9 +100,17 @@ impl SpaceEventHandler {
wsid: WindowServerId,
sid: SpaceId,
) {
if reactor.window_server_info_manager.window_server_info.contains_key(&wsid)
|| reactor.window_manager.observed_window_server_ids.contains(&wsid)
let known_before =
reactor.window_server_info_manager.window_server_info.contains_key(&wsid)
|| reactor.window_manager.observed_window_server_ids.contains(&wsid);
let appearance_info = crate::sys::window_server::get_window(wsid);
if let Some(window_server_info) = appearance_info
&& reactor.note_native_tab_appearance(wsid, sid, window_server_info)
{
return;
}

if known_before {
debug!(
?wsid,
"Received WindowServerAppeared for known window - ignoring"
Expand All @@ -103,7 +121,7 @@ impl SpaceEventHandler {
reactor.window_manager.observed_window_server_ids.insert(wsid);
// TODO: figure out why this is happening, we should really know about this app,
// why dont we get notifications that its being launched?
if let Some(window_server_info) = crate::sys::window_server::get_window(wsid) {
if let Some(window_server_info) = appearance_info {
if window_server_info.layer != 0 {
trace!(
?wsid,
Expand Down
35 changes: 33 additions & 2 deletions src/actor/reactor/events/system.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use tracing::debug;
use tracing::{debug, warn};

use crate::actor::app::WindowId;
use crate::actor::app::{Request, WindowId};
use crate::actor::raise_manager;
use crate::actor::reactor::{MenuState, Reactor};
use crate::actor::wm_controller::Sender as WmSender;
use crate::common::collections::HashMap;

pub struct SystemEventHandler;

Expand Down Expand Up @@ -60,6 +61,36 @@ impl SystemEventHandler {
reactor.window_manager.window_ids.keys().map(|wsid| wsid.as_u32()).collect();
crate::sys::window_notify::update_window_notifications(&ids);
reactor.notification_manager.last_sls_notification_ids = ids;

// Sleep/wake can interrupt both deferred native-tab destroys and ordinary
// close/removal cleanup, leaving stale tracked slots in layout for still-running
// apps like Finder. Re-probe one tracked window per pid so the app actor emits a
// current visible-window snapshot even when the app itself remains alive.
let mut probe_windows_by_pid: HashMap<i32, WindowId> = reactor
.window_manager
.windows
.keys()
.copied()
.map(|wid| (wid.pid, wid))
.collect();
for pending in reactor.pending_native_tab_destroys() {
probe_windows_by_pid.entry(pending.window_id.pid).or_insert(pending.window_id);
}

for window_id in probe_windows_by_pid.into_values() {
let Some(app) = reactor.app_manager.apps.get(&window_id.pid) else {
continue;
};
if let Err(err) = app.handle.send(Request::WindowMaybeDestroyed(window_id)) {
warn!(
pid = window_id.pid,
wid = ?window_id,
?err,
"Failed to verify tracked windows after wake"
);
}
}
reactor.refresh_all_windows_without_pending_refresh();
}

pub fn handle_raise_completed(reactor: &mut Reactor, window_id: WindowId, sequence_id: u64) {
Expand Down
Loading
Loading