mirror of
https://github.com/italicsjenga/muda.git
synced 2025-01-10 20:01:31 +11:00
feat: implement NativeMenuItem::About
for windows and linux (#11)
* feat: implement NativeMenuItem::About * linux
This commit is contained in:
parent
421b00f597
commit
8f11761dee
48
src/lib.rs
48
src/lib.rs
|
@ -106,7 +106,7 @@ impl Menu {
|
|||
///
|
||||
/// ## Platform-specific:
|
||||
///
|
||||
/// - **Windows / Linux**: The menu label can containt `&` to indicate which letter should get a generated accelerator.
|
||||
/// - **Windows / Linux:** The menu label can containt `&` to indicate which letter should get a generated accelerator.
|
||||
/// For example, using `&File` for the File menu would result in the label gets an underline under the `F`,
|
||||
/// and the `&` character is not displayed on menu label.
|
||||
/// Then the menu can be activated by press `Alt+F`.
|
||||
|
@ -261,7 +261,7 @@ impl Submenu {
|
|||
///
|
||||
/// ## Platform-specific:
|
||||
///
|
||||
/// - **Windows / Linux**: The menu label can containt `&` to indicate which letter should get a generated accelerator.
|
||||
/// - **Windows / Linux:** The menu label can containt `&` to indicate which letter should get a generated accelerator.
|
||||
/// For example, using `&File` for the File menu would result in the label gets an underline under the `F`,
|
||||
/// and the `&` character is not displayed on menu label.
|
||||
/// Then the menu can be activated by press `F` when its parent menu is active.
|
||||
|
@ -273,7 +273,7 @@ impl Submenu {
|
|||
///
|
||||
/// ## Platform-specific:
|
||||
///
|
||||
/// - **Windows / Linux**: The menu item label can containt `&` to indicate which letter should get a generated accelerator.
|
||||
/// - **Windows / Linux:** The menu item label can containt `&` to indicate which letter should get a generated accelerator.
|
||||
/// For example, using `&Save` for the save menu item would result in the label gets an underline under the `S`,
|
||||
/// and the `&` character is not displayed on menu item label.
|
||||
/// Then the menu item can be activated by press `S` when its parent menu is active.
|
||||
|
@ -331,32 +331,32 @@ pub enum NativeMenuItem {
|
|||
///
|
||||
/// ## platform-specific:
|
||||
///
|
||||
/// - **macOS**: the metadata is ignore.
|
||||
/// - **Windows**: Not implemented.
|
||||
/// - **macOS:** the metadata is ignore.
|
||||
/// - **Windows:** Not implemented.
|
||||
About(String, AboutMetadata),
|
||||
/// A native “hide the app” menu item.
|
||||
///
|
||||
/// ## platform-specific:
|
||||
///
|
||||
/// - **Windows / Linux**: Unsupported.
|
||||
/// - **Windows / Linux:** Unsupported.
|
||||
Hide,
|
||||
/// A native “hide all other windows" menu item.
|
||||
///
|
||||
/// ## platform-specific:
|
||||
///
|
||||
/// - **Windows / Linux**: Unsupported.
|
||||
/// - **Windows / Linux:** Unsupported.
|
||||
HideOthers,
|
||||
/// A native "Show all windows for this app" menu item.
|
||||
///
|
||||
/// ## platform-specific:
|
||||
///
|
||||
/// - **Windows / Linux**: Unsupported.
|
||||
/// - **Windows / Linux:** Unsupported.
|
||||
ShowAll,
|
||||
/// A native "Services" menu item.
|
||||
///
|
||||
/// ## platform-specific:
|
||||
///
|
||||
/// - **Windows / Linux**: Unsupported.
|
||||
/// - **Windows / Linux:** Unsupported.
|
||||
Services,
|
||||
/// A native "Close current window" menu item.
|
||||
CloseWindow,
|
||||
|
@ -366,49 +366,49 @@ pub enum NativeMenuItem {
|
|||
///
|
||||
/// ## Platform-specific:
|
||||
///
|
||||
/// - **macOS**: macOS require this menu item to enable "Copy" keyboard shortcut for your app.
|
||||
/// - **Linux Wayland**: Not implmeneted.
|
||||
/// - **macOS:** macOS require this menu item to enable "Copy" keyboard shortcut for your app.
|
||||
/// - **Linux Wayland:** Not implmeneted.
|
||||
Copy,
|
||||
/// A native "Cut" menu item.
|
||||
///
|
||||
/// ## Platform-specific:
|
||||
///
|
||||
/// - **macOS**: macOS require this menu item to enable "Cut" keyboard shortcut for your app.
|
||||
/// - **Linux Wayland**: Not implmeneted.
|
||||
/// - **macOS:** macOS require this menu item to enable "Cut" keyboard shortcut for your app.
|
||||
/// - **Linux Wayland:** Not implmeneted.
|
||||
Cut,
|
||||
/// A native "Paste" menu item.
|
||||
///
|
||||
/// ## Platform-specific:
|
||||
///
|
||||
/// - **macOS**: macOS require this menu item to enable "Paste" keyboard shortcut for your app.
|
||||
/// - **Linux Wayland**: Not implmeneted.
|
||||
/// - **macOS:** macOS require this menu item to enable "Paste" keyboard shortcut for your app.
|
||||
/// - **Linux Wayland:** Not implmeneted.
|
||||
Paste,
|
||||
/// A native "Undo" menu item.
|
||||
///
|
||||
/// ## Platform-specific:
|
||||
///
|
||||
/// - **macOS**: macOS require this menu item to enable "Undo" keyboard shortcut for your app.
|
||||
/// - **Windows / Linux**: Unsupported.
|
||||
/// - **macOS:** macOS require this menu item to enable "Undo" keyboard shortcut for your app.
|
||||
/// - **Windows / Linux:** Unsupported.
|
||||
Undo,
|
||||
/// A native "Redo" menu item.
|
||||
///
|
||||
/// ## Platform-specific:
|
||||
///
|
||||
/// - **macOS**: macOS require this menu item to enable "Redo" keyboard shortcut for your app.
|
||||
/// - **Windows / Linux**: Unsupported.
|
||||
/// - **macOS:** macOS require this menu item to enable "Redo" keyboard shortcut for your app.
|
||||
/// - **Windows / Linux:** Unsupported.
|
||||
Redo,
|
||||
/// A native "Select All" menu item.
|
||||
///
|
||||
/// ## Platform-specific:
|
||||
///
|
||||
/// - **macOS**: macOS require this menu item to enable "Select All" keyboard shortcut for your app.
|
||||
/// - **Linux Wayland**: Not implmeneted.
|
||||
/// - **macOS:** macOS require this menu item to enable "Select All" keyboard shortcut for your app.
|
||||
/// - **Linux Wayland:** Not implmeneted.
|
||||
SelectAll,
|
||||
/// A native "Enter fullscreen" menu item.
|
||||
///
|
||||
/// ## platform-specific:
|
||||
///
|
||||
/// - **Windows / Linux**: Unsupported.
|
||||
/// - **Windows / Linux:** Unsupported.
|
||||
EnterFullScreen,
|
||||
/// A native "Minimize current window" menu item.
|
||||
Minimize,
|
||||
|
@ -416,7 +416,7 @@ pub enum NativeMenuItem {
|
|||
///
|
||||
/// ## platform-specific:
|
||||
///
|
||||
/// - **Windows / Linux**: Unsupported.
|
||||
/// - **Windows / Linux:** Unsupported.
|
||||
Zoom,
|
||||
/// Represends a Separator in the menu.
|
||||
Separator,
|
||||
|
@ -426,7 +426,7 @@ pub enum NativeMenuItem {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **macOS**: The metadata is ignored.
|
||||
/// - **macOS:** The metadata is ignored.
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Default)]
|
||||
pub struct AboutMetadata {
|
||||
/// The application name.
|
||||
|
|
|
@ -516,6 +516,46 @@ impl NativeMenuItem {
|
|||
item.show();
|
||||
gtk_menu.append(&item);
|
||||
}
|
||||
NativeMenuItem::About(app_name, metadata) => {
|
||||
let app_name = app_name.clone();
|
||||
let metadata = metadata.clone();
|
||||
let item = gtk::MenuItem::with_label(&format!("About {}", app_name));
|
||||
item.connect_activate(move |_| {
|
||||
let mut builder = gtk::builders::AboutDialogBuilder::new()
|
||||
.program_name(&app_name)
|
||||
.modal(true)
|
||||
.resizable(false);
|
||||
|
||||
if let Some(version) = &metadata.version {
|
||||
builder = builder.version(version);
|
||||
}
|
||||
if let Some(authors) = &metadata.authors {
|
||||
builder = builder.authors(authors.clone());
|
||||
}
|
||||
if let Some(comments) = &metadata.comments {
|
||||
builder = builder.comments(comments);
|
||||
}
|
||||
if let Some(copyright) = &metadata.copyright {
|
||||
builder = builder.copyright(copyright);
|
||||
}
|
||||
if let Some(license) = &metadata.license {
|
||||
builder = builder.license(license);
|
||||
}
|
||||
if let Some(website) = &metadata.website {
|
||||
builder = builder.website(website);
|
||||
}
|
||||
if let Some(website_label) = &metadata.website_label {
|
||||
builder = builder.website_label(website_label);
|
||||
}
|
||||
let about = builder.build();
|
||||
about.run();
|
||||
unsafe {
|
||||
about.destroy();
|
||||
}
|
||||
});
|
||||
item.show();
|
||||
gtk_menu.append(&item);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,8 @@ mod accelerator;
|
|||
mod util;
|
||||
|
||||
use crate::{counter::Counter, NativeMenuItem};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
use once_cell::sync::Lazy;
|
||||
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
||||
use util::{decode_wide, encode_wide, LOWORD};
|
||||
use windows_sys::Win32::{
|
||||
Foundation::{HWND, LPARAM, LRESULT, WPARAM},
|
||||
|
@ -13,19 +14,21 @@ use windows_sys::Win32::{
|
|||
Shell::{DefSubclassProc, RemoveWindowSubclass, SetWindowSubclass},
|
||||
WindowsAndMessaging::{
|
||||
AppendMenuW, CloseWindow, CreateAcceleratorTableW, CreateMenu, DrawMenuBar,
|
||||
EnableMenuItem, GetMenuItemInfoW, PostQuitMessage, SetMenu, SetMenuItemInfoW,
|
||||
ShowWindow, ACCEL, HACCEL, HMENU, MENUITEMINFOW, MFS_DISABLED, MF_DISABLED, MF_ENABLED,
|
||||
MF_GRAYED, MF_POPUP, MF_SEPARATOR, MF_STRING, MIIM_STATE, MIIM_STRING, SW_MINIMIZE,
|
||||
WM_COMMAND,
|
||||
EnableMenuItem, GetMenuItemInfoW, MessageBoxW, PostQuitMessage, SetMenu,
|
||||
SetMenuItemInfoW, ShowWindow, ACCEL, HACCEL, HMENU, MB_ICONINFORMATION, MENUITEMINFOW,
|
||||
MFS_DISABLED, MF_DISABLED, MF_ENABLED, MF_GRAYED, MF_POPUP, MF_SEPARATOR, MF_STRING,
|
||||
MIIM_STATE, MIIM_STRING, SW_MINIMIZE, WM_COMMAND,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
use self::accelerator::parse_accelerator;
|
||||
|
||||
const COUNTER_START: u64 = 563;
|
||||
static COUNTER: Counter = Counter::new_with_start(563);
|
||||
const MENU_SUBCLASS_ID: usize = 232;
|
||||
const MENU_SUBCLASS_ID: usize = 200;
|
||||
const COUNTER_START: u64 = 1000;
|
||||
static COUNTER: Counter = Counter::new_with_start(COUNTER_START);
|
||||
const ABOUT_COUNTER_START: u64 = 400;
|
||||
static ABOUT_COUNTER: Counter = Counter::new_with_start(ABOUT_COUNTER_START);
|
||||
|
||||
struct InnerMenu {
|
||||
hmenu: HMENU,
|
||||
|
@ -108,6 +111,8 @@ impl Menu {
|
|||
}
|
||||
}
|
||||
|
||||
static mut ABOUT_MENU_ITEMS: Lazy<HashMap<u64, NativeMenuItem>> = Lazy::new(|| HashMap::new());
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Submenu {
|
||||
hmenu: HMENU,
|
||||
|
@ -232,6 +237,19 @@ impl Submenu {
|
|||
NativeMenuItem::Minimize => ("&Minimize", MF_STRING),
|
||||
NativeMenuItem::CloseWindow => ("Close", MF_STRING),
|
||||
NativeMenuItem::Quit => ("Exit", MF_STRING),
|
||||
NativeMenuItem::About(ref app_name, _) => {
|
||||
let id = ABOUT_COUNTER.next();
|
||||
unsafe {
|
||||
AppendMenuW(
|
||||
self.hmenu,
|
||||
MF_STRING,
|
||||
id as _,
|
||||
encode_wide(format!("About {}", app_name)).as_ptr(),
|
||||
);
|
||||
ABOUT_MENU_ITEMS.insert(id, item);
|
||||
}
|
||||
return;
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
unsafe {
|
||||
|
@ -332,7 +350,7 @@ unsafe extern "system" fn menu_subclass_proc(
|
|||
let id = LOWORD(wparam as _) as u64;
|
||||
|
||||
// Custom menu items
|
||||
if COUNTER_START < id && id < COUNTER.current() {
|
||||
if COUNTER_START <= id && id <= COUNTER.current() {
|
||||
let _ = crate::MENU_CHANNEL.0.send(crate::MenuEvent { id });
|
||||
ret = 0;
|
||||
};
|
||||
|
@ -362,6 +380,39 @@ unsafe extern "system" fn menu_subclass_proc(
|
|||
_ if id == NativeMenuItem::Quit.id() => {
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
_ if ABOUT_MENU_ITEMS.get(&id).is_some() => {
|
||||
let item = ABOUT_MENU_ITEMS.get(&id).unwrap();
|
||||
if let NativeMenuItem::About(app_name, metadata) = item {
|
||||
MessageBoxW(
|
||||
hwnd,
|
||||
encode_wide(format!(
|
||||
r#"
|
||||
{}
|
||||
|
||||
version: {}
|
||||
authors: {}
|
||||
license: {}
|
||||
website: {} {}
|
||||
|
||||
{}
|
||||
|
||||
{}
|
||||
"#,
|
||||
app_name,
|
||||
metadata.version.as_deref().unwrap_or_default(),
|
||||
metadata.authors.as_deref().unwrap_or_default().join(","),
|
||||
metadata.license.as_deref().unwrap_or_default(),
|
||||
metadata.website_label.as_deref().unwrap_or_default(),
|
||||
metadata.website.as_deref().unwrap_or_default(),
|
||||
metadata.comments.as_deref().unwrap_or_default(),
|
||||
metadata.copyright.as_deref().unwrap_or_default(),
|
||||
))
|
||||
.as_ptr(),
|
||||
encode_wide(format!("About {}", &app_name)).as_ptr(),
|
||||
MB_ICONINFORMATION,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -407,8 +458,7 @@ fn execute_edit_command(command: EditCommand) {
|
|||
inputs[3].Anonymous.ki.wVk = VK_CONTROL;
|
||||
inputs[3].Anonymous.ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
|
||||
let ret = SendInput(4, &inputs as *const _, std::mem::size_of::<INPUT>() as _);
|
||||
dbg!(ret);
|
||||
SendInput(4, &inputs as *const _, std::mem::size_of::<INPUT>() as _);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -428,6 +478,6 @@ impl NativeMenuItem {
|
|||
}
|
||||
|
||||
fn is_id_of_native(id: u64) -> bool {
|
||||
(301..=308).contains(&id)
|
||||
(301..=308).contains(&id) || (ABOUT_COUNTER_START <= id && id <= ABOUT_COUNTER.current())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue