First steps in windows notification
This commit is contained in:
parent
cd2c159696
commit
108220e82b
|
@ -272,4 +272,134 @@ int32_t get_active_window_executable(wchar_t * buffer, int32_t size) {
|
||||||
CloseHandle(process);
|
CloseHandle(process);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UI
|
||||||
|
|
||||||
|
const wchar_t* const notification_winclass = L"EspansoNotification";
|
||||||
|
HWND nw;
|
||||||
|
HBITMAP g_espanso_icon = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Message handler procedure for the notification window
|
||||||
|
*/
|
||||||
|
LRESULT CALLBACK notification_worker_procedure(HWND window, unsigned int msg, WPARAM wp, LPARAM lp)
|
||||||
|
{
|
||||||
|
HDC hdcStatic = NULL;
|
||||||
|
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
|
case WM_CREATE:
|
||||||
|
g_espanso_icon = (HBITMAP)LoadImage(NULL, L"C:\\Users\\fredd\\Documents\\espanso.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
|
||||||
|
break;
|
||||||
|
case WM_DESTROY:
|
||||||
|
std::cout << "\ndestroying window\n";
|
||||||
|
PostQuitMessage(0);
|
||||||
|
DeleteObject(g_espanso_icon);
|
||||||
|
return 0L;
|
||||||
|
case WM_PAINT:
|
||||||
|
{
|
||||||
|
BITMAP bm;
|
||||||
|
PAINTSTRUCT ps;
|
||||||
|
|
||||||
|
HDC hdc = BeginPaint(window, &ps);
|
||||||
|
|
||||||
|
HDC hdcMem = CreateCompatibleDC(hdc);
|
||||||
|
HBITMAP hbmOld = (HBITMAP) SelectObject(hdcMem, g_espanso_icon);
|
||||||
|
|
||||||
|
GetObject(g_espanso_icon, sizeof(bm), &bm);
|
||||||
|
|
||||||
|
BitBlt(hdc, 10, 10, 80, 80, hdcMem, 0, 0, SRCCOPY);
|
||||||
|
|
||||||
|
SelectObject(hdcMem, hbmOld);
|
||||||
|
DeleteDC(hdcMem);
|
||||||
|
|
||||||
|
EndPaint(window, &ps);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_CTLCOLORSTATIC:
|
||||||
|
|
||||||
|
hdcStatic = (HDC)wp;
|
||||||
|
SetTextColor(hdcStatic, RGB(0, 0, 0));
|
||||||
|
SetBkMode(hdcStatic, TRANSPARENT);
|
||||||
|
|
||||||
|
return (LRESULT)GetStockObject(NULL_BRUSH);
|
||||||
|
default:
|
||||||
|
return DefWindowProc(window, msg, wp, lp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t show_notification(wchar_t * message, wchar_t * icon_path) {
|
||||||
|
g_espanso_icon = (HBITMAP)LoadImage(NULL, icon_path, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
|
||||||
|
|
||||||
|
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
|
||||||
|
|
||||||
|
// Docs: https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa
|
||||||
|
WNDCLASSEX wndclass = {
|
||||||
|
sizeof(WNDCLASSEX), // cbSize: Size of this structure
|
||||||
|
0, // style: Class styles
|
||||||
|
notification_worker_procedure, // lpfnWndProc: Pointer to the window procedure
|
||||||
|
0, // cbClsExtra: Number of extra bytes to allocate following the window-class structure
|
||||||
|
0, // cbWndExtra: The number of extra bytes to allocate following the window instance.
|
||||||
|
GetModuleHandle(0), // hInstance: A handle to the instance that contains the window procedure for the class.
|
||||||
|
NULL, // hIcon: A handle to the class icon.
|
||||||
|
LoadCursor(0,IDC_ARROW), // hCursor: A handle to the class cursor.
|
||||||
|
NULL, // hbrBackground: A handle to the class background brush.
|
||||||
|
NULL, // lpszMenuName: Pointer to a null-terminated character string that specifies the resource name of the class menu
|
||||||
|
notification_winclass, // lpszClassName: A pointer to a null-terminated string or is an atom.
|
||||||
|
NULL // hIconSm: A handle to a small icon that is associated with the window class.
|
||||||
|
};
|
||||||
|
|
||||||
|
if (RegisterClassEx(&wndclass))
|
||||||
|
{
|
||||||
|
// Docs: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createwindowexw
|
||||||
|
nw = CreateWindowEx(
|
||||||
|
WS_EX_TOOLWINDOW, // dwExStyle: The extended window style of the window being created.
|
||||||
|
notification_winclass, // lpClassName: A null-terminated string or a class atom created by a previous call to the RegisterClass
|
||||||
|
L"Espanso Notification", // lpWindowName: The window name.
|
||||||
|
WS_POPUPWINDOW, // dwStyle: The style of the window being created.
|
||||||
|
CW_USEDEFAULT, // X: The initial horizontal position of the window.
|
||||||
|
CW_USEDEFAULT, // Y: The initial vertical position of the window.
|
||||||
|
300, // nWidth: The width, in device units, of the window.
|
||||||
|
100, // nHeight: The height, in device units, of the window.
|
||||||
|
NULL, // hWndParent: handle to the parent or owner window of the window being created.
|
||||||
|
NULL, // hMenu: A handle to a menu, or specifies a child-window identifier, depending on the window style.
|
||||||
|
GetModuleHandle(0), // hInstance: A handle to the instance of the module to be associated with the window.
|
||||||
|
NULL // lpParam: Pointer to a value to be passed to the window
|
||||||
|
);
|
||||||
|
|
||||||
|
if (nw)
|
||||||
|
{
|
||||||
|
|
||||||
|
static HWND hwnd_st_u, hwnd_ed_u;
|
||||||
|
int x, w, y, h;
|
||||||
|
y = 40; h = 30;
|
||||||
|
x = 100; w = 180;
|
||||||
|
hwnd_st_u = CreateWindowEx(0, L"static", L"ST_U",
|
||||||
|
WS_CHILD | WS_VISIBLE | WS_TABSTOP | SS_CENTER,
|
||||||
|
x, y, w, h,
|
||||||
|
nw, (HMENU)(501),
|
||||||
|
(HINSTANCE)GetWindowLong(nw, GWLP_HINSTANCE), NULL);
|
||||||
|
|
||||||
|
SetWindowText(hwnd_st_u, message);
|
||||||
|
|
||||||
|
int posX = GetSystemMetrics(SM_CXSCREEN) - 350;
|
||||||
|
int posY = GetSystemMetrics(SM_CYSCREEN) - 200;
|
||||||
|
|
||||||
|
SetWindowPos(window, HWND_TOP, posX, posY, 0, 0, SWP_NOSIZE);
|
||||||
|
|
||||||
|
// Hide the window
|
||||||
|
ShowWindow(nw, SW_SHOW);
|
||||||
|
|
||||||
|
// Enter the Event loop
|
||||||
|
MSG msg;
|
||||||
|
while (GetMessage(&msg, 0, 0, 0)) DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Something went wrong, error.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
|
@ -54,4 +54,8 @@ extern "C" int32_t get_active_window_name(wchar_t * buffer, int32_t size);
|
||||||
*/
|
*/
|
||||||
extern "C" int32_t get_active_window_executable(wchar_t * buffer, int32_t size);
|
extern "C" int32_t get_active_window_executable(wchar_t * buffer, int32_t size);
|
||||||
|
|
||||||
|
// UI
|
||||||
|
|
||||||
|
extern "C" int32_t show_notification(wchar_t * message, wchar_t * icon_path);
|
||||||
|
|
||||||
#endif //ESPANSO_BRIDGE_H
|
#endif //ESPANSO_BRIDGE_H
|
|
@ -3,9 +3,14 @@ use std::os::raw::{c_void};
|
||||||
#[allow(improper_ctypes)]
|
#[allow(improper_ctypes)]
|
||||||
#[link(name="winbridge", kind="static")]
|
#[link(name="winbridge", kind="static")]
|
||||||
extern {
|
extern {
|
||||||
|
// SYSTEM
|
||||||
pub fn get_active_window_name(buffer: *mut u16, size: i32) -> i32;
|
pub fn get_active_window_name(buffer: *mut u16, size: i32) -> i32;
|
||||||
pub fn get_active_window_executable(buffer: *mut u16, size: i32) -> i32;
|
pub fn get_active_window_executable(buffer: *mut u16, size: i32) -> i32;
|
||||||
|
|
||||||
|
// UI
|
||||||
|
pub fn show_notification(message: *const u16, icon_path: *const u16) -> i32;
|
||||||
|
|
||||||
|
// KEYBOARD
|
||||||
pub fn register_keypress_callback(s: *const c_void,
|
pub fn register_keypress_callback(s: *const c_void,
|
||||||
cb: extern fn(_self: *mut c_void, *const i32,
|
cb: extern fn(_self: *mut c_void, *const i32,
|
||||||
i32, i32, i32));
|
i32, i32, i32));
|
||||||
|
|
BIN
src/res/win/espanso.bmp
Normal file
BIN
src/res/win/espanso.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
|
@ -8,7 +8,6 @@ mod linux;
|
||||||
mod macos;
|
mod macos;
|
||||||
|
|
||||||
pub trait UIManager {
|
pub trait UIManager {
|
||||||
fn initialize(&self);
|
|
||||||
fn notify(&self, message: &str);
|
fn notify(&self, message: &str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +30,5 @@ pub fn get_uimanager() -> impl UIManager {
|
||||||
// WINDOWS IMPLEMENTATION
|
// WINDOWS IMPLEMENTATION
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub fn get_uimanager() -> impl UIManager {
|
pub fn get_uimanager() -> impl UIManager {
|
||||||
let manager = windows::WindowsUIManager{};
|
windows::WindowsUIManager::new()
|
||||||
manager.initialize();
|
|
||||||
manager
|
|
||||||
}
|
}
|
|
@ -1,19 +1,43 @@
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
use crate::bridge::windows::show_notification;
|
||||||
|
use widestring::U16CString;
|
||||||
|
use std::fs;
|
||||||
|
use log::{info};
|
||||||
|
|
||||||
|
const ICON_BINARY : &'static [u8] = include_bytes!("../res/win/espanso.bmp");
|
||||||
|
|
||||||
pub struct WindowsUIManager {
|
pub struct WindowsUIManager {
|
||||||
|
icon_file: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::UIManager for WindowsUIManager {
|
impl super::UIManager for WindowsUIManager {
|
||||||
fn initialize(&self) {
|
|
||||||
// TODO: check if notify-send is present and log an error otherwise.
|
|
||||||
}
|
|
||||||
|
|
||||||
fn notify(&self, message: &str) {
|
fn notify(&self, message: &str) {
|
||||||
|
unsafe {
|
||||||
|
let message = U16CString::from_str(message).unwrap();
|
||||||
|
let icon_file = U16CString::from_str(&self.icon_file).unwrap();
|
||||||
|
let res = show_notification(message.as_ptr(), icon_file.as_ptr());
|
||||||
|
info!("{}", res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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");
|
||||||
|
|
||||||
|
fs::write(&espanso_icon_file, ICON_BINARY)
|
||||||
|
.expect("Unable to write windows icon file");
|
||||||
|
|
||||||
|
icon_file = espanso_icon_file.to_str().unwrap_or(&"".to_owned()).to_owned();
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Extracted cached icon to: {}", icon_file);
|
||||||
|
|
||||||
|
WindowsUIManager {
|
||||||
|
icon_file
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user