Add working windows notification mechanism
This commit is contained in:
parent
108220e82b
commit
4e98e4801d
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user