diff --git a/espanso-info/build.rs b/espanso-info/build.rs index c67b678..e08980f 100644 --- a/espanso-info/build.rs +++ b/espanso-info/build.rs @@ -61,9 +61,9 @@ fn cc_config() { .cpp(true) .include("src/cocoa/native.h") .file("src/cocoa/native.mm") - .compile("espansoclipboard"); + .compile("espansoinfo"); println!("cargo:rustc-link-lib=dylib=c++"); - println!("cargo:rustc-link-lib=static=espansoclipboard"); + println!("cargo:rustc-link-lib=static=espansoinfo"); println!("cargo:rustc-link-lib=framework=Cocoa"); } diff --git a/espanso-info/src/cocoa/ffi.rs b/espanso-info/src/cocoa/ffi.rs new file mode 100644 index 0000000..4a94f7b --- /dev/null +++ b/espanso-info/src/cocoa/ffi.rs @@ -0,0 +1,27 @@ +/* + * This file is part of espanso. + * + * Copyright (C) 2019-2021 Federico Terzi + * + * espanso is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * espanso is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with espanso. If not, see . + */ + +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_exec(buffer: *mut c_char, buffer_size: i32) -> i32; + pub fn info_get_class(buffer: *mut c_char, buffer_size: i32) -> i32; +} diff --git a/espanso-info/src/cocoa/mod.rs b/espanso-info/src/cocoa/mod.rs new file mode 100644 index 0000000..4f45fcd --- /dev/null +++ b/espanso-info/src/cocoa/mod.rs @@ -0,0 +1,91 @@ +/* + * This file is part of espanso. + * + * Copyright (C) 2019-2021 Federico Terzi + * + * espanso is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * espanso is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with espanso. If not, see . + */ + +use std::{ffi::CStr, os::raw::c_char}; + +use crate::{AppInfo, AppInfoProvider}; + +use self::ffi::{info_get_class, info_get_exec, info_get_title}; + +mod ffi; + +pub struct CocoaAppInfoProvider {} + +impl CocoaAppInfoProvider { + pub fn new() -> Self { + Self {} + } +} + +impl AppInfoProvider for CocoaAppInfoProvider { + fn get_info(&self) -> AppInfo { + AppInfo { + title: self.get_title(), + class: self.get_class(), + exec: self.get_exec(), + } + } +} + +impl CocoaAppInfoProvider { + fn get_exec(&self) -> Option { + let mut buffer: [c_char; 2048] = [0; 2048]; + if unsafe { info_get_exec(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 + } + } + + fn get_class(&self) -> Option { + let mut buffer: [c_char; 2048] = [0; 2048]; + if unsafe { info_get_class(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 + } + } + + fn get_title(&self) -> Option { + let mut buffer: [c_char; 2048] = [0; 2048]; + if unsafe { info_get_title(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 + } + } +} \ No newline at end of file diff --git a/espanso-info/src/cocoa/native.h b/espanso-info/src/cocoa/native.h new file mode 100644 index 0000000..027299a --- /dev/null +++ b/espanso-info/src/cocoa/native.h @@ -0,0 +1,29 @@ +/* + * This file is part of espanso. + * + * Copyright (C) 2019-2021 Federico Terzi + * + * espanso is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * espanso is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with espanso. If not, see . + */ + +#ifndef ESPANSO_INFO_H +#define ESPANSO_INFO_H + +#include + +extern "C" int32_t info_get_title(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); + +#endif //ESPANSO_INFO_H \ No newline at end of file diff --git a/espanso-info/src/cocoa/native.mm b/espanso-info/src/cocoa/native.mm new file mode 100644 index 0000000..9e6306f --- /dev/null +++ b/espanso-info/src/cocoa/native.mm @@ -0,0 +1,76 @@ +/* + * This file is part of espanso. + * + * Copyright (C) 2019-2021 Federico Terzi + * + * espanso is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * espanso is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with espanso. If not, see . + */ + +#include "native.h" +#import +#import + +int32_t info_get_title(char *buffer, int32_t buffer_size) +{ + CFArrayRef windows = CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements | kCGWindowListOptionOnScreenOnly, kCGNullWindowID); + int32_t result = 0; + + if (windows) { + for (NSDictionary *window in (NSArray *)windows) { + NSNumber *ownerPid = window[(id) kCGWindowOwnerPID]; + + NSRunningApplication *currentApp = [NSRunningApplication runningApplicationWithProcessIdentifier: [ownerPid intValue]]; + + if ([currentApp isActive]) { + NSString *name = window[(id) kCGWindowName]; + if (name.length > 0) { + const char * title = [name UTF8String]; + snprintf(buffer, buffer_size, "%s", title); + result = 1; + } + break; + } + } + + CFRelease(windows); + } + + return result; +} + +int32_t info_get_exec(char *buffer, int32_t buffer_size) +{ + NSRunningApplication *frontApp = [[NSWorkspace sharedWorkspace] frontmostApplication]; + NSString *bundlePath = [frontApp bundleURL].path; + const char * path = [bundlePath UTF8String]; + + snprintf(buffer, buffer_size, "%s", path); + + [bundlePath release]; + + return 1; +} + +int32_t info_get_class(char *buffer, int32_t buffer_size) +{ + NSRunningApplication *frontApp = [[NSWorkspace sharedWorkspace] frontmostApplication]; + NSString *bundleId = frontApp.bundleIdentifier; + const char * bundle = [bundleId UTF8String]; + + snprintf(buffer, buffer_size, "%s", bundle); + + [bundleId release]; + + return 1; +} \ No newline at end of file diff --git a/espanso-info/src/lib.rs b/espanso-info/src/lib.rs index c65643f..715045d 100644 --- a/espanso-info/src/lib.rs +++ b/espanso-info/src/lib.rs @@ -52,9 +52,9 @@ pub fn get_provider() -> Result> { } #[cfg(target_os = "macos")] -pub fn get_clipboard(_: ClipboardOptions) -> Result> { - info!("using CocoaClipboard"); - Ok(Box::new(cocoa::CocoaClipboard::new()?)) +pub fn get_provider() -> Result> { + info!("using CocoaAppInfoProvider"); + Ok(Box::new(cocoa::CocoaAppInfoProvider::new())) } #[cfg(target_os = "linux")]