Skip to content
Merged
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
11 changes: 4 additions & 7 deletions src/app_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
},
config::{GlyphlowConfig, RoleOfInterest, VisibilityCheckingLevel, WorkFlow, WorkFlowAction},
drawer::GlyphlowDrawingLayer,
os_util::get_focused_pid,
os_util::{get_focused, get_system_alarm_window},
util::{Frame, HintBox, estimate_frame_for_text, hint_boxes_from_frames, select_range_helper},
};
use accessibility::{AXUIElement, AXUIElementActions, AXUIElementAttributes};
Expand Down Expand Up @@ -460,9 +460,7 @@ impl AppExecutor {
let screen_frame = Frame::from_origion(self.screen_size);

// NOTE: prioritize system alarms
if let Ok(app) = AXUIElement::application_with_bundle("com.apple.coreservices.uiagent")
&& let Ok(window) = app.focused_window()
{
if let Some(window) = get_system_alarm_window() {
let frame = window.get_frame(screen_frame);
self.last_window_frame = frame;
self.is_electron = false;
Expand All @@ -477,9 +475,8 @@ impl AppExecutor {
return Some(frame);
}

let (pid, is_electron) = get_focused_pid()?;
let (pid, focused_app, is_electron) = get_focused()?;
self.is_electron = is_electron;
let focused_app = AXUIElement::application(pid);

// HACK: need this to bootstrap UI tree generation for some electron apps,
// e.g. Discord
Expand Down Expand Up @@ -1273,7 +1270,7 @@ impl AppExecutor {
..
}) = self.selected.as_ref()
else {
panic!("An element is supposed to be selected before entering Mode::Scrolling!")
return;
};

if *role == RoleOfInterest::ScrollBar {
Expand Down
22 changes: 14 additions & 8 deletions src/ax_element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,13 @@ impl GetAttribute for AXUIElement {

msg.push_str(&format!("Role: {}\n", fp.role));

if let Some(f) = fp.frame {
let CGPoint { x, y } = f.top_left;
msg.push_str(&format!("pos: x: {x}, y: {y}\n"));
let (w, h) = f.size();
msg.push_str(&format!("size: width: {w}, height: {h}\n"));
}

if let Ok(t) = self.title() {
msg.push_str(&format!("title: {}\n", t));
}
Expand All @@ -439,13 +446,6 @@ impl GetAttribute for AXUIElement {
msg.push_str(&format!("value: {:?}\n", v));
}

if let Some(f) = fp.frame {
let CGPoint { x, y } = f.top_left;
msg.push_str(&format!("pos: x: {x}, y: {y}\n"));
let (w, h) = f.size();
msg.push_str(&format!("size: width: {w}, height: {h}\n"));
}

msg
// for attr in &self.attribute_names().unwrap() {
// println!(
Expand Down Expand Up @@ -770,7 +770,13 @@ pub fn traverse_elements(
}
// NOTE: don't do it for AXSectionList, e.g. Apple Music
kAXListRole if element.subrole().is_ok_and(|r| r == kAXContentListSubrole) => {
if let Some(area_frame) = ele_fp.frame.and_then(|f| f.intersect(&window_frame)) {
if let Some(area_frame) = ele_fp.frame.and_then(|f| f.intersect(&window_frame))
&& {
let (w, h) = area_frame.size();
// HACK: Some content lists may have fake sizes, e.g. Slack
w > 10.0 && h > 10.0
}
{
window_frame = area_frame;
};
}
Expand Down
25 changes: 23 additions & 2 deletions src/os_util.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::path::PathBuf;

use accessibility::{AXUIElement, AXUIElementAttributes};
use accessibility_sys::{AXIsProcessTrustedWithOptions, kAXTrustedCheckOptionPrompt};
use core_foundation::{
base::TCFType, boolean::CFBoolean, dictionary::CFDictionary, string::CFString,
Expand Down Expand Up @@ -27,12 +28,32 @@ fn check_is_electron_app(app: &Retained<NSRunningApplication>) -> Option<bool> {
Some(false)
}

pub fn get_focused_pid() -> Option<(i32, bool)> {
const APPLE_ALARM_BUNDLE_IDS: [&str; 3] = [
"com.apple.coreservices.uiagent",
"com.apple.accessibility.universalAccessAuthWarn",
"com.apple.CoreLocationAgent",
];

pub fn get_system_alarm_window() -> Option<AXUIElement> {
for bundle_id in APPLE_ALARM_BUNDLE_IDS {
if let Ok(app) = AXUIElement::application_with_bundle(bundle_id)
&& let Ok(window) = app.focused_window()
{
return Some(window);
}
}
None
}

pub fn get_focused() -> Option<(i32, AXUIElement, bool)> {
let workspace = NSWorkspace::sharedWorkspace();
let app = workspace.frontmostApplication()?;
// eprintln!("Focused app: {:?}", app.bundleIdentifier());

let pid = app.processIdentifier();
Some((
app.processIdentifier(),
pid,
AXUIElement::application(pid),
check_is_electron_app(&app).unwrap_or_default(),
))
}
Expand Down
Loading