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")]
|
#[link(name = "espansoinfo", kind = "static")]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn info_get_title(buffer: *mut c_char, buffer_size: i32) -> i32;
|
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_exec(buffer: *mut c_char, buffer_size: i32) -> i32;
|
||||||
pub fn info_get_class(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 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;
|
mod ffi;
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ impl CocoaAppInfoProvider {
|
||||||
impl AppInfoProvider for CocoaAppInfoProvider {
|
impl AppInfoProvider for CocoaAppInfoProvider {
|
||||||
fn get_info(&self) -> AppInfo {
|
fn get_info(&self) -> AppInfo {
|
||||||
AppInfo {
|
AppInfo {
|
||||||
title: self.get_title(),
|
title: self.get_title().or_else(|| self.get_title_fallback()),
|
||||||
class: self.get_class(),
|
class: self.get_class(),
|
||||||
exec: self.get_exec(),
|
exec: self.get_exec(),
|
||||||
}
|
}
|
||||||
|
@ -88,4 +88,20 @@ impl CocoaAppInfoProvider {
|
||||||
None
|
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>
|
#include <stdint.h>
|
||||||
|
|
||||||
extern "C" int32_t info_get_title(char * buffer, int32_t buffer_size);
|
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_exec(char * buffer, int32_t buffer_size);
|
||||||
extern "C" int32_t info_get_class(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;
|
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)
|
int32_t info_get_exec(char *buffer, int32_t buffer_size)
|
||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user