refactor(mac): ask a Window for its frame instead of reading the AX element

Adds Window::frame(), the frame query (Backend::window_rect), and routes
the 28 sites that read a Window's frame through MacosApi::window_rect(&w.element)
(window.rs, window_manager.rs, workspace.rs, process_event.rs,
process_command.rs, settle.rs, macos_backend.rs) through it. frame() is the
same call on the same element, so nothing changes at runtime. Sites that hold
a bare element rather than a Window (tabs in process_event.rs, borders,
the animator, AdhocWindow) are left as they are.

Step 6 of the consolidation, macOS, one operation per revision.

Verified: macOS fake-CC type-check (tools/fast-check) PASS. Not verified:
cannot run or unit-test on Linux.
This commit is contained in:
LGUG2Z committed 2026-10-31 09:59:17 -07:00
1 parent 01b9cbed91
commit 796c3832b7
7 files changed
+33 -29

No files matched your search

@@ -140,7 +140,7 @@ impl MacosBackend {
id: WindowId::from_u32(window.id),
pid: window.application.process_id,
// the Accessibility position and size, in points; a failure leaves the default
rect: MacosApi::window_rect(&window.element)
rect: window.frame()
.map(Rect::from)
.unwrap_or_default(),
minimized,
@@ -637,7 +637,7 @@ impl WindowManager {
// Sort by window area
window_idx_pairs.sort_by_key(|(_, w)| {
let rect =
Rect::from(MacosApi::window_rect(&w.element).unwrap_or_default());
Rect::from(w.frame().unwrap_or_default());
rect.right * rect.bottom
});
window_idx_pairs.reverse();
@@ -707,7 +707,7 @@ impl WindowManager {
// Sort by window area
window_idx_pairs.sort_by_key(|w| {
let rect = Rect::from(
MacosApi::window_rect(&w.element).unwrap_or_default(),
w.frame().unwrap_or_default(),
);
rect.right * rect.bottom
});
@@ -260,7 +260,7 @@ impl WindowManager {
&& window.application.process_id == process_id
{
let tab_rect = MacosApi::window_rect(&element)?;
let main_rect = match MacosApi::window_rect(&window.element) {
let main_rect = match window.frame() {
Ok(rect) => rect,
Err(AccessibilityError::Api(
AccessibilityApiError::InvalidUIElement,
@@ -328,7 +328,7 @@ impl WindowManager {
&& window.application.process_id == process_id
{
let tab_rect = MacosApi::window_rect(&element)?;
let main_rect = match MacosApi::window_rect(&window.element) {
let main_rect = match window.frame() {
Ok(rect) => rect,
Err(AccessibilityError::Api(
AccessibilityApiError::InvalidUIElement,
@@ -553,7 +553,7 @@ impl WindowManager {
if window.application.name().unwrap_or_default() == application_name
{
let tab_rect = MacosApi::window_rect(element)?;
let main_rect = MacosApi::window_rect(&window.element)?;
let main_rect = window.frame()?;
// BOTH conditions must be true:
// 1. Geometry matches (original check - preserves existing behavior)
// 2. Window IDs match (new check - prevents false positives)
@@ -897,7 +897,7 @@ impl WindowManager {
{
// TODO: not sure about this clone
let window = window.clone();
let new_position = Rect::from(MacosApi::window_rect(&window.element)?);
let new_position = Rect::from(window.frame()?);
let old_position = *workspace
.latest_layout
.get(focused_container_idx)
@@ -1102,7 +1102,7 @@ impl WindowManager {
&& let Some(window) =
container.windows().iter().find(|w| w.id == window_id)
{
let started_from = Rect::from(MacosApi::window_rect(&window.element)?);
let started_from = Rect::from(window.frame()?);
let pending_resize_op = Arc::make_mut(&mut self.pending_resize_op);
*pending_resize_op = Option::from((window_id, Some(started_from)));
@@ -1162,7 +1162,7 @@ impl WindowManager {
&& let Some(window) =
container.windows().iter().find(|w| w.id == window_id)
{
let ended_at = Rect::from(MacosApi::window_rect(&window.element)?);
let ended_at = Rect::from(window.frame()?);
tracing::info!("resizing with mouse");
redraw |= self.resize_by_drag(window_id, started_from, ended_at)?;
+1 -2
View File
@@ -11,7 +11,6 @@
use crate::accessibility::AccessibilityApi;
use crate::animation::animator;
use crate::core::Rect;
use crate::macos_api::MacosApi;
use crate::window::Snapping;
use crate::window::dragged_window;
use crate::window::is_parked;
@@ -186,7 +185,7 @@ impl WindowManager {
}
let _ = AccessibilityApi::set_messaging_timeout(&window.element, LOOK_TIMEOUT);
let rect = MacosApi::window_rect(&window.element).map(Rect::from);
let rect = window.frame().map(Rect::from);
let _ = AccessibilityApi::set_messaging_timeout(&window.element, 0.0);
if let Ok(rect) = rect
+13 -8
View File
@@ -520,7 +520,7 @@ impl Serialize for Window {
state.serialize_field("id", &self.id)?;
state.serialize_field(
"rect",
&Rect::from(MacosApi::window_rect(&self.element).unwrap_or_default()),
&Rect::from(self.frame().unwrap_or_default()),
)?;
state.serialize_field("details", &WindowDetails::from(self))?;
state.end()
@@ -569,6 +569,11 @@ impl Window {
})
}
/// The frame query (`Backend::window_rect`): the Accessibility position and size, in points.
pub fn frame(&self) -> Result<CGRect, AccessibilityError> {
MacosApi::window_rect(&self.element)
}
pub fn is_valid(&self) -> bool {
AccessibilityApi::copy_attribute_names(&self.element).is_some()
}
@@ -622,7 +627,7 @@ impl Window {
// it happened to be when it was hidden
let rect = match animator::take_over(self.id) {
Some(target) => CGRect::from(target),
None => MacosApi::window_rect(&self.element)?,
None => self.frame()?,
};
let mut window_restore_positions = WINDOW_RESTORE_POSITIONS.lock();
@@ -706,7 +711,7 @@ impl Window {
let rect = match animator::target(self.id) {
Some(target) => CGRect::from(target),
None => MacosApi::window_rect(&self.element)?,
None => self.frame()?,
};
let Some(screen) = screen.or_else(|| CoreGraphicsApi::display_bounds_for_window_rect(rect))
@@ -956,7 +961,7 @@ impl Window {
// the window manager is waiting for this, and so is every window after this one
let _ = AccessibilityApi::set_messaging_timeout(&self.element, ARRIVAL_TIMEOUT);
match MacosApi::window_rect(&self.element) {
match self.frame() {
Ok(actual) => arrival::report(self.id, *target, Rect::from(actual)),
Err(error) => {
tracing::debug!(
@@ -985,7 +990,7 @@ impl Window {
return;
}
let Ok(current) = MacosApi::window_rect(&self.element) else {
let Ok(current) = self.frame() else {
return;
};
@@ -1077,7 +1082,7 @@ impl Window {
motion,
after: None,
},
|| MacosApi::window_rect(&self.element).map(Rect::from),
|| self.frame().map(Rect::from),
)
}
@@ -1192,7 +1197,7 @@ impl Window {
let target_width = (target_height * aspect_ratio_width) / aspect_ratio_height;
(target_width, target_height)
} else {
let current_rect = Rect::from(MacosApi::window_rect(&self.element)?);
let current_rect = Rect::from(self.frame()?);
(current_rect.right, current_rect.bottom)
};
@@ -1212,7 +1217,7 @@ impl Window {
current_area: &Rect,
target_area: &Rect,
) -> Result<(), AccessibilityError> {
let current_rect = Rect::from(MacosApi::window_rect(&self.element)?);
let current_rect = Rect::from(self.frame()?);
let x_diff = target_area.left - current_area.left;
let y_diff = target_area.top - current_area.top;
let x_ratio = f32::abs((target_area.right as f32) / (current_area.right as f32));
@@ -279,7 +279,7 @@ impl WindowManager {
.enumerate()
.flat_map(|(idx, w)| {
(w.id != focused_window_id).then_some(
MacosApi::window_rect(&w.element)
w.frame()
.ok()
.map(|r| (idx, Rect::from(r))),
)
@@ -305,7 +305,7 @@ impl WindowManager {
.enumerate()
.flat_map(|(idx, w)| {
(w.id != focused_window_id).then_some(
MacosApi::window_rect(&w.element)
w.frame()
.ok()
.map(|r| (idx, Rect::from(r))),
)
@@ -331,7 +331,7 @@ impl WindowManager {
.enumerate()
.flat_map(|(idx, w)| {
(w.id != focused_window_id).then_some(
MacosApi::window_rect(&w.element)
w.frame()
.ok()
.map(|r| (idx, Rect::from(r))),
)
@@ -357,7 +357,7 @@ impl WindowManager {
.enumerate()
.flat_map(|(idx, w)| {
(w.id != focused_window_id).then_some(
MacosApi::window_rect(&w.element)
w.frame()
.ok()
.map(|r| (idx, Rect::from(r))),
)
@@ -747,7 +747,7 @@ impl WindowManager {
MacosApi::foreground_window_id().ok_or_eyre("no foreground window")?;
for window in focused_workspace.floating_windows().iter() {
if window.id == focused_window_id {
let mut rect = Rect::from(MacosApi::window_rect(&window.element)?);
let mut rect = Rect::from(window.frame()?);
match direction {
OperationDirection::Left => {
if rect.left - delta < focused_monitor_work_area.left {
@@ -1475,7 +1475,7 @@ impl WindowManager {
.into_iter()
.flatten()
.filter_map(|window| {
MacosApi::window_rect(&window.element)
window.frame()
.ok()
.map(|rect| (window.id, Rect::from(rect)))
})
@@ -1696,7 +1696,7 @@ impl WindowManager {
for window in workspace.floating_windows().iter() {
if window.id == focused_window_id {
let mut rect = Rect::from(MacosApi::window_rect(&window.element)?);
let mut rect = Rect::from(window.frame()?);
match (direction, sizing) {
(OperationDirection::Left, Sizing::Increase) => {
if rect.left - delta < focused_monitor_work_area.left {
+3 -3
View File
@@ -553,7 +553,7 @@ impl Workspace {
&& focused_window.application.process_id == process_id
{
if !valid_window_ids.contains(&focused_window.id) {
if let Ok(rect) = MacosApi::window_rect(&focused_window.element) {
if let Ok(rect) = focused_window.frame() {
tracing::debug!(
"reaping window {} ({}): rect = {:?}",
focused_window.id,
@@ -578,7 +578,7 @@ impl Workspace {
if focused_window.application.process_id == process_id
&& !valid_window_ids.contains(&focused_window.id)
{
if let Ok(rect) = MacosApi::window_rect(&focused_window.element) {
if let Ok(rect) = focused_window.frame() {
tracing::debug!(
"reaping monocle window {} ({}): rect = {:?}",
focused_window.id,
@@ -599,7 +599,7 @@ impl Workspace {
for window in self.floating_windows() {
if window.application.process_id == process_id {
if !valid_window_ids.contains(&window.id) {
if let Ok(rect) = MacosApi::window_rect(&window.element) {
if let Ok(rect) = window.frame() {
tracing::debug!(
"reaping floating window {} ({}): rect = {:?}",
window.id,