feat(info): add fallback title detection on macOS
This commit is contained in:
parent
35d931e49c
commit
e3dc943a73
|
@ -22,6 +22,7 @@ use std::os::raw::c_char;
|
|||
#[link(name = "espansoinfo", kind = "static")]
|
||||
extern "C" {
|
||||
pub fn info_get_title(buffer: *mut c_char, buffer_size: i32) -> i32;
|
||||
pub fn info_get_title_fallback(buffer: *mut c_char, buffer_size: i32) -> i32;
|
||||
pub fn info_get_exec(buffer: *mut c_char, buffer_size: i32) -> i32;
|
||||
pub fn info_get_class(buffer: *mut c_char, buffer_size: i32) -> i32;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ use std::{ffi::CStr, os::raw::c_char};
|
|||
|
||||
use crate::{AppInfo, AppInfoProvider};
|
||||
|
||||
use self::ffi::{info_get_class, info_get_exec, info_get_title};
|
||||
use self::ffi::{info_get_class, info_get_exec, info_get_title, info_get_title_fallback};
|
||||
|
||||
mod ffi;
|
||||
|
||||
|
@ -36,7 +36,7 @@ impl CocoaAppInfoProvider {
|
|||
impl AppInfoProvider for CocoaAppInfoProvider {
|
||||
fn get_info(&self) -> AppInfo {
|
||||
AppInfo {
|
||||
title: self.get_title(),
|
||||
title: self.get_title().or_else(|| self.get_title_fallback()),
|
||||
class: self.get_class(),
|
||||
exec: self.get_exec(),
|
||||
}
|
||||
|
@ -88,4 +88,20 @@ impl CocoaAppInfoProvider {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback using Accessibility API instead of Carbon
|
||||
fn get_title_fallback(&self) -> Option<String> {
|
||||
let mut buffer: [c_char; 2048] = [0; 2048];
|
||||
if unsafe { info_get_title_fallback(buffer.as_mut_ptr(), (buffer.len() - 1) as i32) } > 0 {
|
||||
let string = unsafe { CStr::from_ptr(buffer.as_ptr()) };
|
||||
let string = string.to_string_lossy();
|
||||
if !string.is_empty() {
|
||||
Some(string.to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
#include <stdint.h>
|
||||
|
||||
extern "C" int32_t info_get_title(char * buffer, int32_t buffer_size);
|
||||
extern "C" int32_t info_get_title_fallback(char * buffer, int32_t buffer_size);
|
||||
extern "C" int32_t info_get_exec(char * buffer, int32_t buffer_size);
|
||||
extern "C" int32_t info_get_class(char * buffer, int32_t buffer_size);
|
||||
|
||||
|
|
|
@ -51,6 +51,51 @@ int32_t info_get_title(char *buffer, int32_t buffer_size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Partially taken from: https://stackoverflow.com/questions/480866/get-the-title-of-the-current-active-window-document-in-mac-os-x/23451568#23451568
|
||||
int32_t info_get_title_fallback(char *buffer, int32_t buffer_size)
|
||||
{
|
||||
@autoreleasepool {
|
||||
// Get the process ID of the frontmost application.
|
||||
NSRunningApplication* app = [[NSWorkspace sharedWorkspace] frontmostApplication];
|
||||
pid_t pid = [app processIdentifier];
|
||||
|
||||
AXUIElementRef appElem = AXUIElementCreateApplication(pid);
|
||||
if (!appElem) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the accessibility element corresponding to the frontmost window
|
||||
// of the frontmost application.
|
||||
AXUIElementRef window = NULL;
|
||||
if (AXUIElementCopyAttributeValue(appElem,
|
||||
kAXFocusedWindowAttribute, (CFTypeRef*)&window) != kAXErrorSuccess) {
|
||||
CFRelease(appElem);
|
||||
return -2;
|
||||
}
|
||||
|
||||
// Finally, get the title of the frontmost window.
|
||||
CFStringRef title = NULL;
|
||||
AXError result = AXUIElementCopyAttributeValue(window, kAXTitleAttribute,
|
||||
(CFTypeRef*)&title);
|
||||
|
||||
// At this point, we don't need window and appElem anymore.
|
||||
CFRelease(window);
|
||||
CFRelease(appElem);
|
||||
|
||||
if (result != kAXErrorSuccess) {
|
||||
// Failed to get the window title.
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (CFStringGetCString(title, buffer, buffer_size, kCFStringEncodingUTF8)) {
|
||||
CFRelease(title);
|
||||
return 1;
|
||||
} else {
|
||||
return -4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t info_get_exec(char *buffer, int32_t buffer_size)
|
||||
{
|
||||
@autoreleasepool {
|
||||
|
|
Loading…
Reference in New Issue
Block a user