From a8300832bc781188d1a2660988affa3cfda36d75 Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Wed, 11 Sep 2019 15:51:45 +0200 Subject: [PATCH] First draft of context menu on windows --- native/libwinbridge/bridge.cpp | 87 ++++++++++++++++++++++++++++++--- native/libwinbridge/bridge.h | 21 +++++++- src/bridge/windows.rs | 12 ++++- src/res/win/espanso.ico | Bin 0 -> 28522 bytes src/ui/windows.rs | 84 ++++++++++++++++++++++++------- 5 files changed, 177 insertions(+), 27 deletions(-) create mode 100644 src/res/win/espanso.ico diff --git a/native/libwinbridge/bridge.cpp b/native/libwinbridge/bridge.cpp index a9302ac..154e927 100644 --- a/native/libwinbridge/bridge.cpp +++ b/native/libwinbridge/bridge.cpp @@ -7,6 +7,8 @@ #define UNICODE #include +#include +#include // How many milliseconds must pass between keystrokes to refresh the keyboard layout const long refreshKeyboardLayoutInterval = 2000; @@ -275,11 +277,21 @@ int32_t get_active_window_executable(wchar_t * buffer, int32_t size) { } // UI +#define APPWM_ICONNOTIFY (WM_APP + 1) const wchar_t* const notification_winclass = L"EspansoNotification"; HWND nw = NULL; HWND hwnd_st_u = NULL; -HBITMAP g_espanso_icon = NULL; +HBITMAP g_espanso_bmp = NULL; +HICON g_espanso_ico = NULL; + +MenuItemCallback menu_item_callback = NULL; +void * ui_manager_instance; + +void register_menu_item_callback(void *self, MenuItemCallback callback) { + menu_item_callback = callback; + ui_manager_instance = self; +} /* * Message handler procedure for the notification window @@ -293,8 +305,49 @@ LRESULT CALLBACK notification_worker_procedure(HWND window, unsigned int msg, WP case WM_DESTROY: std::cout << "\ndestroying window\n"; PostQuitMessage(0); - DeleteObject(g_espanso_icon); + DeleteObject(g_espanso_bmp); return 0L; + case WM_MENUSELECT: + { + HMENU hmenu = (HMENU)lp; + UINT idItem = (UINT)LOWORD(wp); + UINT flags = (UINT)HIWORD(wp); + + if (flags & MF_CHECKED) { + // TODO: callback + } + + break; + } + case APPWM_ICONNOTIFY: + { + switch (lp) + { + case WM_LBUTTONUP: + case WM_RBUTTONUP: + HMENU hPopupMenu = CreatePopupMenu(); + + // Create the menu + + int32_t count; + MenuItem items[100]; + + // Load the items + menu_item_callback(ui_manager_instance, items, &count); + + for (int i = 0; i i32; // UI - pub fn initialize_ui(icon_path: *const u16) -> i32; + pub fn initialize_ui(ico_path: *const u16, bmp_path: *const u16) -> i32; pub fn show_notification(message: *const u16) -> i32; pub fn close_notification(); + pub fn register_menu_item_callback(s: *const c_void, + cb: extern fn(_self: *mut c_void, *mut WindowsMenuItem, + *mut i32)); // KEYBOARD pub fn register_keypress_callback(s: *const c_void, diff --git a/src/res/win/espanso.ico b/src/res/win/espanso.ico new file mode 100644 index 0000000000000000000000000000000000000000..1d1c06c7ef5bf408ce91222819c303d8c22201a0 GIT binary patch literal 28522 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 } @@ -51,31 +53,79 @@ impl super::UIManager for WindowsUIManager { impl WindowsUIManager { pub fn new() -> WindowsUIManager { - let res = dirs::cache_dir(); - let mut icon_file:String = "".to_owned(); - if let Some(cache_dir) = res { - let espanso_icon_file = cache_dir.join("espansoicon.bmp"); + let data_dir = dirs::data_dir().expect("Can't obtain data_dir(), terminating."); - fs::write(&espanso_icon_file, ICON_BINARY) - .expect("Unable to write windows icon file"); + let espanso_dir = data_dir.join("espanso"); - icon_file = espanso_icon_file.to_str().unwrap_or(&"".to_owned()).to_owned(); + let res = create_dir_all(&espanso_dir); + + info!("Initializing Espanso resources in {}", espanso_dir.as_path().display()); + + let espanso_bmp_image = espanso_dir.join("espansoicon.bmp"); + if espanso_bmp_image.exists() { + info!("BMP already initialized, skipping."); + }else { + fs::write(&espanso_bmp_image, BMP_BINARY) + .expect("Unable to write windows bmp file"); + + info!("Extracted bmp icon to: {}", espanso_bmp_image.to_str().unwrap_or("error")); } - info!("Extracted cached icon to: {}", icon_file); + let espanso_ico_image = espanso_dir.join("espanso.ico"); + if espanso_ico_image.exists() { + info!("ICO already initialized, skipping."); + }else { + fs::write(&espanso_ico_image, ICO_BINARY) + .expect("Unable to write windows ico file"); + + info!("Extracted 'ico' icon to: {}", espanso_ico_image.to_str().unwrap_or("error")); + } + + let bmp_icon = espanso_bmp_image.to_str().unwrap_or_default(); + let ico_icon = espanso_ico_image.to_str().unwrap_or_default(); let id = Arc::new(Mutex::new(0)); - let icon_file_c = U16CString::from_str(&icon_file).unwrap(); + let ico_file_c = U16CString::from_str(ico_icon).unwrap(); + let bmp_file_c = U16CString::from_str(bmp_icon).unwrap(); + + let manager = WindowsUIManager { + id + }; + + // Setup the menu item callback + unsafe { + let self_ptr = &manager as *const WindowsUIManager as *const c_void; + register_menu_item_callback(self_ptr, menu_item_callback); + } thread::spawn(move || { unsafe { - initialize_ui(icon_file_c.as_ptr()); + initialize_ui(ico_file_c.as_ptr(), bmp_file_c.as_ptr()); } }); - WindowsUIManager { - icon_file, - id - } + manager + } +} + +// NATIVE + +extern fn menu_item_callback(_self: *mut c_void, items: *mut WindowsMenuItem, count: *mut i32) { + unsafe { + let _self = _self as *mut WindowsUIManager; + + let str = U16CString::from_str("Test").unwrap_or_default(); + let mut str_buff : [u16; 100] = [0; 100]; + std::ptr::copy(str.as_ptr(), str_buff.as_mut_ptr(), str.len()); + let item = WindowsMenuItem { + item_id: 1, + item_type: 1, + item_name: str_buff, + }; + + let items = unsafe { std::slice::from_raw_parts_mut(items, 100) }; + + items[0] = item; + *count = 1; } } \ No newline at end of file