Add working windows notification mechanism

This commit is contained in:
Federico Terzi 2019-09-08 12:31:36 +02:00
parent 108220e82b
commit 4e98e4801d
5 changed files with 73 additions and 16 deletions

View File

@ -277,7 +277,8 @@ int32_t get_active_window_executable(wchar_t * buffer, int32_t size) {
// UI // UI
const wchar_t* const notification_winclass = L"EspansoNotification"; const wchar_t* const notification_winclass = L"EspansoNotification";
HWND nw; HWND nw = NULL;
HWND hwnd_st_u = NULL;
HBITMAP g_espanso_icon = NULL; HBITMAP g_espanso_icon = NULL;
/* /*
@ -321,7 +322,8 @@ LRESULT CALLBACK notification_worker_procedure(HWND window, unsigned int msg, WP
hdcStatic = (HDC)wp; hdcStatic = (HDC)wp;
SetTextColor(hdcStatic, RGB(0, 0, 0)); SetTextColor(hdcStatic, RGB(0, 0, 0));
SetBkMode(hdcStatic, TRANSPARENT); SetBkColor(hdcStatic, RGB(255, 255, 255));
//SetBkMode(hdcStatic, OPAQUE);
return (LRESULT)GetStockObject(NULL_BRUSH); return (LRESULT)GetStockObject(NULL_BRUSH);
default: default:
@ -330,6 +332,11 @@ LRESULT CALLBACK notification_worker_procedure(HWND window, unsigned int msg, WP
} }
int32_t show_notification(wchar_t * message, wchar_t * icon_path) { int32_t show_notification(wchar_t * message, wchar_t * icon_path) {
if (nw != NULL) {
SetWindowText(hwnd_st_u, L" ");
SetWindowText(hwnd_st_u, message);
}
g_espanso_icon = (HBITMAP)LoadImage(NULL, icon_path, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); g_espanso_icon = (HBITMAP)LoadImage(NULL, icon_path, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE); SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
@ -370,8 +377,6 @@ int32_t show_notification(wchar_t * message, wchar_t * icon_path) {
if (nw) if (nw)
{ {
static HWND hwnd_st_u, hwnd_ed_u;
int x, w, y, h; int x, w, y, h;
y = 40; h = 30; y = 40; h = 30;
x = 100; w = 180; x = 100; w = 180;
@ -386,7 +391,7 @@ int32_t show_notification(wchar_t * message, wchar_t * icon_path) {
int posX = GetSystemMetrics(SM_CXSCREEN) - 350; int posX = GetSystemMetrics(SM_CXSCREEN) - 350;
int posY = GetSystemMetrics(SM_CYSCREEN) - 200; int posY = GetSystemMetrics(SM_CYSCREEN) - 200;
SetWindowPos(window, HWND_TOP, posX, posY, 0, 0, SWP_NOSIZE); SetWindowPos(nw, HWND_TOP, posX, posY, 0, 0, SWP_NOSIZE);
// Hide the window // Hide the window
ShowWindow(nw, SW_SHOW); ShowWindow(nw, SW_SHOW);
@ -403,3 +408,8 @@ int32_t show_notification(wchar_t * message, wchar_t * icon_path) {
return 1; return 1;
} }
void close_notification() {
SendMessage(nw, WM_CLOSE, 0, 0);
nw = NULL;
}

View File

@ -56,6 +56,15 @@ extern "C" int32_t get_active_window_executable(wchar_t * buffer, int32_t size);
// UI // UI
/*
* Show a window containing the notification.
*/
extern "C" int32_t show_notification(wchar_t * message, wchar_t * icon_path); extern "C" int32_t show_notification(wchar_t * message, wchar_t * icon_path);
/*
* Close the notification if present
*/
extern "C" void close_notification();
#endif //ESPANSO_BRIDGE_H #endif //ESPANSO_BRIDGE_H

View File

@ -9,6 +9,7 @@ extern {
// UI // UI
pub fn show_notification(message: *const u16, icon_path: *const u16) -> i32; pub fn show_notification(message: *const u16, icon_path: *const u16) -> i32;
pub fn close_notification();
// KEYBOARD // KEYBOARD
pub fn register_keypress_callback(s: *const c_void, pub fn register_keypress_callback(s: *const c_void,

View File

@ -5,7 +5,7 @@ use crate::matcher::scrolling::ScrollingMatcher;
use crate::engine::Engine; use crate::engine::Engine;
use crate::config::{ConfigSet, RuntimeConfigManager}; use crate::config::{ConfigSet, RuntimeConfigManager};
use crate::ui::UIManager; use crate::ui::UIManager;
use std::thread; use std::{thread, time};
use clap::{App, Arg}; use clap::{App, Arg};
use std::path::Path; use std::path::Path;
use std::sync::mpsc::Receiver; use std::sync::mpsc::Receiver;
@ -96,6 +96,8 @@ fn espanso_background(rxc: Receiver<KeyEvent>, config_set: ConfigSet) {
let ui_manager = ui::get_uimanager(); let ui_manager = ui::get_uimanager();
ui_manager.notify("Hello guys"); ui_manager.notify("Hello guys");
thread::sleep(time::Duration::from_millis(600));
ui_manager.notify("There");
let clipboard_manager = clipboard::get_manager(); let clipboard_manager = clipboard::get_manager();

View File

@ -1,23 +1,56 @@
use std::process::Command; use std::process::Command;
use crate::bridge::windows::show_notification; use crate::bridge::windows::{show_notification, close_notification};
use widestring::U16CString; use widestring::U16CString;
use std::fs; use std::{fs, thread, time};
use log::{info}; use log::{info, debug};
use std::sync::Mutex;
use std::sync::Arc;
const ICON_BINARY : &'static [u8] = include_bytes!("../res/win/espanso.bmp"); const ICON_BINARY : &'static [u8] = include_bytes!("../res/win/espanso.bmp");
pub struct WindowsUIManager { pub struct WindowsUIManager {
icon_file: String, icon_file: String,
id: Arc<Mutex<i32>>
} }
impl super::UIManager for WindowsUIManager { impl super::UIManager for WindowsUIManager {
fn notify(&self, message: &str) { fn notify(&self, message: &str) {
let current_id: i32 = {
let mut id = self.id.lock().unwrap();
*id += 1;
*id
};
// Setup a timeout to close the notification
let id = Arc::clone(&self.id);
thread::spawn(move || {
for i in 1..10 {
let duration = time::Duration::from_millis(200);
thread::sleep(duration);
let new_id = id.lock().unwrap();
if *new_id != current_id {
debug!("Cancelling notification close event with id {}", current_id);
return;
}
}
unsafe {
close_notification();
}
});
// Create and show a window notification
let message = message.to_owned();
let icon_file = self.icon_file.clone();
thread::spawn( move || {
unsafe { unsafe {
let message = U16CString::from_str(message).unwrap(); let message = U16CString::from_str(message).unwrap();
let icon_file = U16CString::from_str(&self.icon_file).unwrap(); let icon_file = U16CString::from_str(&icon_file).unwrap();
let res = show_notification(message.as_ptr(), icon_file.as_ptr()); show_notification(message.as_ptr(), icon_file.as_ptr());
info!("{}", res);
} }
});
} }
} }
@ -36,8 +69,10 @@ impl WindowsUIManager {
info!("Extracted cached icon to: {}", icon_file); info!("Extracted cached icon to: {}", icon_file);
let id = Arc::new(Mutex::new(0));
WindowsUIManager { WindowsUIManager {
icon_file icon_file,
id
} }
} }
} }