diff --git a/espanso-detect/build.rs b/espanso-detect/build.rs
index 9347e70..5ae16b0 100644
--- a/espanso-detect/build.rs
+++ b/espanso-detect/build.rs
@@ -59,10 +59,7 @@ fn cc_config() {
#[cfg(target_os = "macos")]
fn cc_config() {
- println!("cargo:rustc-link-lib=dylib=c++");
- println!("cargo:rustc-link-lib=static=macbridge");
- println!("cargo:rustc-link-lib=framework=Cocoa");
- println!("cargo:rustc-link-lib=framework=IOKit");
+ // TODO
}
fn main() {
diff --git a/espanso-ui/Cargo.toml b/espanso-ui/Cargo.toml
index 4130370..3f99bfe 100644
--- a/espanso-ui/Cargo.toml
+++ b/espanso-ui/Cargo.toml
@@ -16,6 +16,9 @@ thiserror = "1.0.23"
widestring = "0.4.3"
lazycell = "1.3.0"
+[target.'cfg(target_os="macos")'.dependencies]
+lazycell = "1.3.0"
+
[target.'cfg(target_os="linux")'.dependencies]
notify-rust = "4.2.2"
diff --git a/espanso-ui/build.rs b/espanso-ui/build.rs
index e93d4ee..1b36617 100644
--- a/espanso-ui/build.rs
+++ b/espanso-ui/build.rs
@@ -40,17 +40,24 @@ fn cc_config() {
#[cfg(target_os = "linux")]
fn cc_config() {
- // println!("cargo:rustc-link-search=native=/usr/lib/x86_64-linux-gnu/");
- // println!("cargo:rustc-link-lib=static=linuxbridge");
- // println!("cargo:rustc-link-lib=dylib=X11");
- // println!("cargo:rustc-link-lib=dylib=Xtst");
- // println!("cargo:rustc-link-lib=dylib=xdo");
+ // Nothing to link on linux
}
#[cfg(target_os = "macos")]
fn cc_config() {
+ println!("cargo:rerun-if-changed=src/mac/native.mm");
+ println!("cargo:rerun-if-changed=src/mac/native.h");
+ println!("cargo:rerun-if-changed=src/mac/AppDelegate.mm");
+ println!("cargo:rerun-if-changed=src/mac/AppDelegate.h");
+ cc::Build::new()
+ .cpp(true)
+ .include("src/mac/native.h")
+ .include("src/mac/AppDelegate.h")
+ .file("src/mac/native.mm")
+ .file("src/mac/AppDelegate.mm")
+ .compile("espansoui");
println!("cargo:rustc-link-lib=dylib=c++");
- println!("cargo:rustc-link-lib=static=macbridge");
+ println!("cargo:rustc-link-lib=static=espansoui");
println!("cargo:rustc-link-lib=framework=Cocoa");
println!("cargo:rustc-link-lib=framework=IOKit");
}
diff --git a/espanso-ui/src/lib.rs b/espanso-ui/src/lib.rs
index 6b05f82..914c536 100644
--- a/espanso-ui/src/lib.rs
+++ b/espanso-ui/src/lib.rs
@@ -7,3 +7,6 @@ pub mod win32;
#[cfg(target_os = "linux")]
pub mod linux;
+
+#[cfg(target_os = "macos")]
+pub mod mac;
\ No newline at end of file
diff --git a/espanso-ui/src/mac/AppDelegate.h b/espanso-ui/src/mac/AppDelegate.h
new file mode 100644
index 0000000..c36ccf3
--- /dev/null
+++ b/espanso-ui/src/mac/AppDelegate.h
@@ -0,0 +1,39 @@
+/*
+ * 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 .
+ */
+
+#import
+#import
+
+#include "native.h"
+
+@interface AppDelegate : NSObject {
+ @public NSStatusItem *statusItem;
+ @public UIOptions options;
+ @public void *rust_instance;
+ @public EventCallback event_callback;
+}
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
+- (void) setIcon: (int32_t) iconIndex;
+- (void) popupMenu: (NSString *) payload;
+- (void) showNotification: (NSString *) message withDelay:(double) delay;
+- (IBAction) statusIconClick: (id) sender;
+- (IBAction) contextMenuClick: (id) sender;
+
+@end
\ No newline at end of file
diff --git a/espanso-ui/src/mac/AppDelegate.mm b/espanso-ui/src/mac/AppDelegate.mm
new file mode 100644
index 0000000..7f70715
--- /dev/null
+++ b/espanso-ui/src/mac/AppDelegate.mm
@@ -0,0 +1,134 @@
+/*
+ * 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 .
+ */
+
+#import "AppDelegate.h"
+
+void addSeparatorMenu(NSMenu * parent);
+void addSingleMenu(NSMenu * parent, id item);
+void addSubMenu(NSMenu * parent, NSArray * items);
+
+@implementation AppDelegate
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
+{
+ if (options.show_icon) {
+ statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
+ [self setIcon: 0];
+ }
+
+ [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
+}
+
+- (void) setIcon: (int32_t)iconIndex {
+ if (options.show_icon) {
+ char * iconPath = options.icon_paths[iconIndex];
+ NSString *nsIconPath = [NSString stringWithUTF8String:iconPath];
+
+ NSImage *statusImage = [[NSImage alloc] initWithContentsOfFile:nsIconPath];
+ [statusImage setTemplate:YES];
+
+ [statusItem.button setImage:statusImage];
+ [statusItem setHighlightMode:YES];
+ [statusItem.button setAction:@selector(statusIconClick:)];
+ [statusItem.button setTarget:self];
+ }
+}
+
+- (IBAction) statusIconClick: (id) sender {
+ UIEvent event = {};
+ event.event_type = UI_EVENT_TYPE_ICON_CLICK;
+ if (event_callback && rust_instance) {
+ event_callback(rust_instance, event);
+ }
+}
+
+- (void) popupMenu: (NSString *) payload {
+ NSError *jsonError;
+ NSData *data = [payload dataUsingEncoding:NSUTF8StringEncoding];
+ NSArray *jsonMenuItems = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonError];
+ NSMenu *menu = [[NSMenu alloc] initWithTitle:@"Espanso"];
+ addSubMenu(menu, jsonMenuItems);
+ [statusItem popUpStatusItemMenu: menu];
+}
+
+- (IBAction) contextMenuClick: (id) sender {
+ NSInteger itemId = [[sender valueForKey:@"tag"] integerValue];
+
+ UIEvent event = {};
+ event.event_type = UI_EVENT_TYPE_CONTEXT_MENU_CLICK;
+ event.context_menu_id = (uint32_t) [itemId intValue];
+ if (event_callback && rust_instance) {
+ event_callback(rust_instance, event);
+ }
+}
+
+- (void) showNotification: (NSString *) message withDelay: (double) delay {
+ NSUserNotification *notification = [[NSUserNotification alloc] init];
+ notification.title = @"Espanso";
+ notification.informativeText = message;
+ notification.soundName = nil;
+
+ [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
+ [[NSUserNotificationCenter defaultUserNotificationCenter] performSelector:@selector(removeDeliveredNotification:) withObject:notification afterDelay:delay];
+}
+
+@end
+
+// Menu utility methods
+
+void addSeparatorMenu(NSMenu * parent)
+{
+ [parent addItem: [NSMenuItem separatorItem]];
+}
+
+void addSingleMenu(NSMenu * parent, id item)
+{
+ id label = [item objectForKey:@"label"];
+ id raw_id = [item objectForKey:@"raw_id"];
+ if (label == nil || raw_id == nil)
+ {
+ return;
+ }
+ NSMenuItem *newMenu = [[NSMenuItem alloc] initWithTitle:label action:@selector(contextMenuClick:) keyEquivalent:@""];
+ [newMenu setTag:(NSInteger)raw_id];
+ [parent addItem: newMenu];
+}
+
+void addSubMenu(NSMenu * parent, NSArray * items)
+{
+ for (id item in items) {
+ id type = [item objectForKey:@"type"];
+ if ([type isEqualToString:@"simple"])
+ {
+ addSingleMenu(parent, item);
+ }
+ else if ([type isEqualToString:@"separator"])
+ {
+ addSeparatorMenu(parent);
+ }
+ else if ([type isEqualToString:@"sub"])
+ {
+ NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:[item objectForKey:@"label"] action:nil keyEquivalent:@""];
+ NSMenu *subMenu = [[NSMenu alloc] init];
+ [parent addItem: menuItem];
+ addSubMenu(subMenu, [item objectForKey:@"items"]);
+ [menuItem setSubmenu: subMenu];
+ }
+ }
+}
\ No newline at end of file
diff --git a/espanso-ui/src/mac/mod.rs b/espanso-ui/src/mac/mod.rs
new file mode 100644
index 0000000..5142921
--- /dev/null
+++ b/espanso-ui/src/mac/mod.rs
@@ -0,0 +1,241 @@
+/*
+ * 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::{cmp::min, collections::HashMap, ffi::{CString}, os::raw::c_char, thread::ThreadId};
+
+use lazycell::LazyCell;
+use log::{error, trace};
+
+use crate::{event::UIEvent, icons::TrayIcon, menu::Menu};
+
+// IMPORTANT: if you change these, also edit the native.h file.
+const MAX_FILE_PATH: usize = 1024;
+const MAX_ICON_COUNT: usize = 3;
+
+const UI_EVENT_TYPE_ICON_CLICK: i32 = 1;
+const UI_EVENT_TYPE_CONTEXT_MENU_CLICK: i32 = 2;
+
+// Take a look at the native.h header file for an explanation of the fields
+#[repr(C)]
+pub struct RawUIOptions {
+ pub show_icon: i32,
+
+ pub icon_paths: [[u8; MAX_FILE_PATH]; MAX_ICON_COUNT],
+ pub icon_paths_count: i32,
+}
+// Take a look at the native.h header file for an explanation of the fields
+#[repr(C)]
+pub struct RawUIEvent {
+ pub event_type: i32,
+ pub context_menu_id: u32,
+}
+
+#[allow(improper_ctypes)]
+#[link(name = "espansoui", kind = "static")]
+extern "C" {
+ pub fn ui_initialize(
+ _self: *const MacEventLoop,
+ options: RawUIOptions,
+ );
+ pub fn ui_eventloop(
+ event_callback: extern "C" fn(_self: *mut MacEventLoop, event: RawUIEvent),
+ ) -> i32;
+ pub fn ui_update_tray_icon(index: i32);
+ pub fn ui_show_notification(message: *const c_char, delay: f64);
+ pub fn ui_show_context_menu(payload: *const c_char);
+}
+
+pub struct MacUIOptions<'a> {
+ pub show_icon: bool,
+ pub icon_paths: &'a Vec<(TrayIcon, String)>,
+}
+
+pub fn create(options: MacUIOptions) -> (MacRemote, MacEventLoop) {
+ // Validate icons
+ if options.icon_paths.len() > MAX_ICON_COUNT {
+ panic!("MacOS UI received too many icon paths, please increase the MAX_ICON_COUNT constant to support more");
+ }
+
+ // Convert the icon paths to the internal representation
+ let mut icon_indexes: HashMap = HashMap::new();
+ let mut icons = Vec::new();
+ for (index, (tray_icon, path)) in options.icon_paths.iter().enumerate() {
+ icon_indexes.insert(tray_icon.clone(), index);
+ icons.push(path.clone());
+ }
+
+ let eventloop = MacEventLoop::new(
+ icons,
+ options.show_icon,
+ );
+ let remote = MacRemote::new(icon_indexes);
+
+ (remote, eventloop)
+}
+
+pub type MacUIEventCallback = Box;
+
+pub struct MacEventLoop {
+ show_icon: bool,
+ icons: Vec,
+
+ // Internal
+ _event_callback: LazyCell,
+ _init_thread_id: LazyCell,
+}
+
+impl MacEventLoop {
+ pub(crate) fn new(
+ icons: Vec,
+ show_icon: bool,
+ ) -> Self {
+ Self {
+ icons,
+ show_icon,
+ _event_callback: LazyCell::new(),
+ _init_thread_id: LazyCell::new(),
+ }
+ }
+
+ pub fn initialize(&mut self) {
+ // Convert the icon paths to the raw representation
+ let mut icon_paths: [[u8; MAX_FILE_PATH]; MAX_ICON_COUNT] =
+ [[0; MAX_FILE_PATH]; MAX_ICON_COUNT];
+ for (i, icon_path) in icon_paths.iter_mut().enumerate().take(self.icons.len()) {
+ let c_path = CString::new(self.icons[i].clone()).expect("unable to create CString for UI tray icon path");
+ let len = min(c_path.as_bytes().len(), MAX_FILE_PATH - 1);
+ icon_path[0..len].clone_from_slice(&c_path.as_bytes()[..len]);
+ }
+
+ let options = RawUIOptions {
+ show_icon: if self.show_icon { 1 } else { 0 },
+ icon_paths,
+ icon_paths_count: self.icons.len() as i32,
+ };
+
+ unsafe { ui_initialize(self as *const MacEventLoop, options) };
+
+ // Make sure the run() method is called in the same thread as initialize()
+ self
+ ._init_thread_id
+ .fill(std::thread::current().id())
+ .expect("Unable to set initialization thread id");
+ }
+
+ pub fn run(&self, event_callback: MacUIEventCallback) {
+ // Make sure the run() method is called in the same thread as initialize()
+ if let Some(init_id) = self._init_thread_id.borrow() {
+ if init_id != &std::thread::current().id() {
+ panic!("MacEventLoop run() and initialize() methods should be called in the same thread");
+ }
+ }
+
+ if self._event_callback.fill(event_callback).is_err() {
+ panic!("Unable to set MacEventLoop callback");
+ }
+
+ extern "C" fn callback(_self: *mut MacEventLoop, event: RawUIEvent) {
+ if let Some(callback) = unsafe { (*_self)._event_callback.borrow() } {
+ let event: Option = event.into();
+ if let Some(event) = event {
+ callback(event)
+ } else {
+ trace!("Unable to convert raw event to input event");
+ }
+ }
+ }
+
+ let error_code = unsafe { ui_eventloop(callback) };
+
+ if error_code <= 0 {
+ panic!("MacEventLoop exited with <= 0 code")
+ }
+ }
+}
+
+pub struct MacRemote {
+ // Maps icon name to their index
+ icon_indexes: HashMap,
+}
+
+impl MacRemote {
+ pub(crate) fn new(
+ icon_indexes: HashMap,
+ ) -> Self {
+ Self {
+ icon_indexes,
+ }
+ }
+
+ pub fn update_tray_icon(&self, icon: TrayIcon) {
+ if let Some(index) = self.icon_indexes.get(&icon) {
+ unsafe { ui_update_tray_icon((*index) as i32) }
+ } else {
+ error!("Unable to update tray icon, invalid icon id");
+ }
+ }
+
+ pub fn show_notification(&self, message: &str) {
+ let c_string = CString::new(message);
+ match c_string {
+ Ok(message) => unsafe { ui_show_notification(message.as_ptr(), 3.0) },
+ Err(error) => {
+ error!(
+ "Unable to show notification {}",
+ error
+ );
+ }
+ }
+ }
+
+ pub fn show_context_menu(&self, menu: &Menu) {
+ match menu.to_json() {
+ Ok(payload) => {
+ let c_string = CString::new(payload);
+ match c_string {
+ Ok(c_string) => unsafe { ui_show_context_menu(c_string.as_ptr()) },
+ Err(error) => error!(
+ "Unable to show context menu, impossible to convert payload to c_string: {}",
+ error
+ ),
+ }
+ }
+ Err(error) => {
+ error!("Unable to show context menu, {}", error);
+ }
+ }
+ }
+}
+
+#[allow(clippy::single_match)] // TODO: remove after another match is used
+impl From for Option {
+ fn from(raw: RawUIEvent) -> Option {
+ match raw.event_type {
+ UI_EVENT_TYPE_ICON_CLICK => {
+ return Some(UIEvent::TrayIconClick);
+ }
+ UI_EVENT_TYPE_CONTEXT_MENU_CLICK => {
+ return Some(UIEvent::ContextMenuClick(raw.context_menu_id));
+ }
+ _ => {}
+ }
+
+ None
+ }
+}
\ No newline at end of file
diff --git a/espanso-ui/src/mac/native.h b/espanso-ui/src/mac/native.h
new file mode 100644
index 0000000..5b3b455
--- /dev/null
+++ b/espanso-ui/src/mac/native.h
@@ -0,0 +1,73 @@
+/*
+ * 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_UI_H
+#define ESPANSO_UI_H
+
+#include
+
+// Explicitly define this constant as we need to use it from the Rust side
+#define MAX_FILE_PATH 1024
+#define MAX_ICON_COUNT 3
+
+#define UI_EVENT_TYPE_ICON_CLICK 1
+#define UI_EVENT_TYPE_CONTEXT_MENU_CLICK 2
+
+typedef struct {
+ int32_t show_icon;
+
+ char icon_paths[MAX_ICON_COUNT][MAX_FILE_PATH];
+ int32_t icon_paths_count;
+} UIOptions;
+
+typedef struct {
+ int32_t event_type;
+ uint32_t context_menu_id;
+} UIEvent;
+
+typedef void (*EventCallback)(void * self, UIEvent data);
+
+typedef struct
+{
+ UIOptions options;
+
+ // Rust interop
+ void *rust_instance;
+ EventCallback event_callback;
+} UIVariables;
+
+// Initialize the Application delegate.
+extern "C" void ui_initialize(void * self, UIOptions options);
+
+// Run the event loop. Blocking call.
+extern "C" int32_t ui_eventloop(EventCallback callback);
+
+// Updates the tray icon to the given one. The method accepts an index that refers to
+// the icon within the UIOptions.icon_paths array.
+extern "C" void ui_update_tray_icon(int32_t index);
+
+// Show a native notification
+extern "C" void ui_show_notification(char * message, double delay);
+
+// Display the context menu on the tray icon.
+// Payload is passed as JSON as given the complex structure, parsing
+// this manually would have been complex.
+extern "C" void ui_show_context_menu(char * payload);
+
+#endif //ESPANSO_UI_H
\ No newline at end of file
diff --git a/espanso-ui/src/mac/native.mm b/espanso-ui/src/mac/native.mm
new file mode 100644
index 0000000..9ed2692
--- /dev/null
+++ b/espanso-ui/src/mac/native.mm
@@ -0,0 +1,72 @@
+/*
+ * 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"
+#include "AppDelegate.h"
+#import
+#include
+#include
+#include
+#include
+
+void ui_initialize(void *_self, UIOptions _options)
+{
+ AppDelegate *delegate = [[AppDelegate alloc] init];
+ delegate->options = _options;
+ delegate->rust_instance = _self;
+
+ NSApplication * application = [NSApplication sharedApplication];
+ [application setDelegate:delegate];
+}
+
+int32_t ui_eventloop(EventCallback _callback)
+{
+ AppDelegate *delegate = [[NSApplication sharedApplication] delegate];
+ delegate->event_callback = _callback;
+
+ [NSApp run];
+
+ return 1;
+}
+
+void ui_update_tray_icon(int32_t index)
+{
+ dispatch_async(dispatch_get_main_queue(), ^(void) {
+ AppDelegate *delegate = [[NSApplication sharedApplication] delegate];
+ [delegate setIcon: index];
+ });
+}
+
+void ui_show_notification(char *message, double delay)
+{
+ NSString *nsMessage = [NSString stringWithUTF8String:message];
+ dispatch_async(dispatch_get_main_queue(), ^(void) {
+ AppDelegate *delegate = [[NSApplication sharedApplication] delegate];
+ [delegate showNotification: nsMessage withDelay: delay];
+ });
+}
+
+void ui_show_context_menu(char *payload)
+{
+ NSString *nsPayload = [NSString stringWithUTF8String:payload];
+ dispatch_async(dispatch_get_main_queue(), ^(void) {
+ AppDelegate *delegate = [[NSApplication sharedApplication] delegate];
+ [delegate popupMenu: nsPayload];
+ });
+}
\ No newline at end of file
diff --git a/espanso/src/main.rs b/espanso/src/main.rs
index e51724e..5cc88bc 100644
--- a/espanso/src/main.rs
+++ b/espanso/src/main.rs
@@ -1,5 +1,5 @@
use espanso_detect::event::{InputEvent, Status};
-use espanso_ui::{linux::LinuxUIOptions, menu::*};
+use espanso_ui::{icons::TrayIcon, mac::*, menu::*, event::UIEvent::*};
use simplelog::{CombinedLogger, Config, LevelFilter, TermLogger, TerminalMode};
fn main() {
@@ -14,14 +14,24 @@ fn main() {
])
.unwrap();
+ // let icon_paths = vec![
+ // (
+ // espanso_ui::icons::TrayIcon::Normal,
+ // r"C:\Users\Freddy\AppData\Local\espanso\espanso.ico".to_string(),
+ // ),
+ // (
+ // espanso_ui::icons::TrayIcon::Disabled,
+ // r"C:\Users\Freddy\AppData\Local\espanso\espansored.ico".to_string(),
+ // ),
+ // ];
let icon_paths = vec![
(
espanso_ui::icons::TrayIcon::Normal,
- r"C:\Users\Freddy\AppData\Local\espanso\espanso.ico".to_string(),
+ r"/Users/freddy/Library/Application Support/espanso/icon.png".to_string(),
),
(
espanso_ui::icons::TrayIcon::Disabled,
- r"C:\Users\Freddy\AppData\Local\espanso\espansored.ico".to_string(),
+ r"/Users/freddy/Library/Application Support/espanso/icondisabled.png".to_string(),
),
];
@@ -32,44 +42,55 @@ fn main() {
// notification_icon_path: r"C:\Users\Freddy\Insync\Development\Espanso\Images\icongreensmall.png"
// .to_string(),
// });
- let (remote, mut eventloop) = espanso_ui::linux::create(LinuxUIOptions {
- notification_icon_path: r"/home/freddy/insync/Development/Espanso/Images/icongreensmall.png".to_owned(),
+ let (remote, mut eventloop) = espanso_ui::mac::create(MacUIOptions {
+ show_icon: true,
+ icon_paths: &icon_paths,
});
let handle = std::thread::spawn(move || {
+
//let mut source = espanso_detect::win32::Win32Source::new();
- let mut source = espanso_detect::evdev::EVDEVSource::new();
- source.initialize();
- source.eventloop(Box::new(move |event: InputEvent| {
- println!("ev {:?}", event);
- match event {
- InputEvent::Mouse(_) => {}
- InputEvent::Keyboard(evt) => {
- if evt.key == espanso_detect::event::Key::Shift && evt.status == Status::Pressed {
- //remote.update_tray_icon(espanso_ui::icons::TrayIcon::Disabled);
- remote.show_notification("Espanso is running!");
- }
- }
- }
- }));
+ //let mut source = espanso_detect::x11::X11Source::new();
+ // source.initialize();
+ // source.eventloop(Box::new(move |event: InputEvent| {
+ // println!("ev {:?}", event);
+ // match event {
+ // InputEvent::Mouse(_) => {}
+ // InputEvent::Keyboard(evt) => {
+ // if evt.key == espanso_detect::event::Key::Shift && evt.status == Status::Pressed {
+ // //remote.update_tray_icon(espanso_ui::icons::TrayIcon::Disabled);
+ // remote.show_notification("Espanso is running!");
+ // }
+ // }
+ // }
+ // }));
});
- // eventloop.initialize();
- // eventloop.run(Box::new(move |event| {
- // println!("ui {:?}", event);
- // let menu = Menu::from(vec![
- // MenuItem::Simple(SimpleMenuItem::new("open", "Open")),
- // MenuItem::Separator,
- // MenuItem::Sub(SubMenuItem::new(
- // "Sub",
- // vec![
- // MenuItem::Simple(SimpleMenuItem::new("sub1", "Sub 1")),
- // MenuItem::Simple(SimpleMenuItem::new("sub2", "Sub 2")),
- // ],
- // )),
- // ])
- // .unwrap();
- // remote.show_context_menu(&menu);
- // }))
- eventloop.run();
+ eventloop.initialize();
+ eventloop.run(Box::new(move |event| {
+ println!("ui {:?}", event);
+ let menu = Menu::from(vec![
+ MenuItem::Simple(SimpleMenuItem::new("open", "Open")),
+ MenuItem::Separator,
+ MenuItem::Sub(SubMenuItem::new(
+ "Sub",
+ vec![
+ MenuItem::Simple(SimpleMenuItem::new("sub1", "Sub 1")),
+ MenuItem::Simple(SimpleMenuItem::new("sub2", "Sub 2")),
+ ],
+ )),
+ ])
+ .unwrap();
+ match event {
+ TrayIconClick => {
+ remote.show_context_menu(&menu);
+ }
+ ContextMenuClick(raw_id) => {
+ //remote.update_tray_icon(TrayIcon::Disabled);
+ remote.show_notification("Hello there!");
+ println!("item {:?}", menu.get_item_id(raw_id));
+ }
+ }
+
+ }));
}
diff --git a/espanso/src/main_old.rs b/espanso/src/main_old2.rs
similarity index 97%
rename from espanso/src/main_old.rs
rename to espanso/src/main_old2.rs
index 8b2025f..e51724e 100644
--- a/espanso/src/main_old.rs
+++ b/espanso/src/main_old2.rs
@@ -38,7 +38,7 @@ fn main() {
let handle = std::thread::spawn(move || {
//let mut source = espanso_detect::win32::Win32Source::new();
- let mut source = espanso_detect::x11::X11Source::new();
+ let mut source = espanso_detect::evdev::EVDEVSource::new();
source.initialize();
source.eventloop(Box::new(move |event: InputEvent| {
println!("ev {:?}", event);