mirror of
https://github.com/italicsjenga/muda.git
synced 2024-12-23 20:11:29 +11:00
fix(windows): attach subclass for context menu if window doesn't have a menu bar (#105)
This commit is contained in:
parent
93a93a699e
commit
4701bb836e
5
.changes/windows-context-menu.md
Normal file
5
.changes/windows-context-menu.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"muda": "patch"
|
||||||
|
---
|
||||||
|
|
||||||
|
On Windows, fix menu items inside a context menu not firing events if the context menu was used on a Window that doesn't have a menu bar.
|
|
@ -207,12 +207,12 @@ impl ContextMenu for Submenu {
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
fn attach_menu_subclass_for_hwnd(&self, hwnd: isize) {
|
fn attach_menu_subclass_for_hwnd(&self, hwnd: isize) {
|
||||||
self.inner.borrow_mut().attach_menu_subclass_for_hwnd(hwnd)
|
self.inner.borrow().attach_menu_subclass_for_hwnd(hwnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
fn detach_menu_subclass_from_hwnd(&self, hwnd: isize) {
|
fn detach_menu_subclass_from_hwnd(&self, hwnd: isize) {
|
||||||
self.inner.borrow_mut().detach_menu_subclass_from_hwnd(hwnd)
|
self.inner.borrow().detach_menu_subclass_from_hwnd(hwnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
|
|
|
@ -324,7 +324,7 @@ impl ContextMenu for Menu {
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
fn show_context_menu_for_hwnd(&self, hwnd: isize, position: Option<Position>) {
|
fn show_context_menu_for_hwnd(&self, hwnd: isize, position: Option<Position>) {
|
||||||
self.inner
|
self.inner
|
||||||
.borrow()
|
.borrow_mut()
|
||||||
.show_context_menu_for_hwnd(hwnd, position)
|
.show_context_menu_for_hwnd(hwnd, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,11 @@ use windows_sys::Win32::{
|
||||||
AppendMenuW, CreateAcceleratorTableW, CreateMenu, CreatePopupMenu,
|
AppendMenuW, CreateAcceleratorTableW, CreateMenu, CreatePopupMenu,
|
||||||
DestroyAcceleratorTable, DestroyMenu, DrawMenuBar, EnableMenuItem, GetCursorPos,
|
DestroyAcceleratorTable, DestroyMenu, DrawMenuBar, EnableMenuItem, GetCursorPos,
|
||||||
GetMenu, GetMenuItemInfoW, InsertMenuW, PostQuitMessage, RemoveMenu, SendMessageW,
|
GetMenu, GetMenuItemInfoW, InsertMenuW, PostQuitMessage, RemoveMenu, SendMessageW,
|
||||||
SetMenu, SetMenuItemInfoW, ShowWindow, TrackPopupMenu, HACCEL, HMENU, MENUITEMINFOW,
|
SetForegroundWindow, SetMenu, SetMenuItemInfoW, ShowWindow, TrackPopupMenu, HACCEL,
|
||||||
MFS_CHECKED, MFS_DISABLED, MF_BYCOMMAND, MF_BYPOSITION, MF_CHECKED, MF_DISABLED,
|
HMENU, MENUITEMINFOW, MFS_CHECKED, MFS_DISABLED, MF_BYCOMMAND, MF_BYPOSITION,
|
||||||
MF_ENABLED, MF_GRAYED, MF_POPUP, MF_SEPARATOR, MF_STRING, MF_UNCHECKED, MIIM_BITMAP,
|
MF_CHECKED, MF_DISABLED, MF_ENABLED, MF_GRAYED, MF_POPUP, MF_SEPARATOR, MF_STRING,
|
||||||
MIIM_STATE, MIIM_STRING, SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE, TPM_LEFTALIGN, WM_CLOSE,
|
MF_UNCHECKED, MIIM_BITMAP, MIIM_STATE, MIIM_STRING, SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE,
|
||||||
WM_COMMAND,
|
TPM_LEFTALIGN, WM_CLOSE, WM_COMMAND,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -100,6 +100,7 @@ pub(crate) struct Menu {
|
||||||
hmenu: HMENU,
|
hmenu: HMENU,
|
||||||
hpopupmenu: HMENU,
|
hpopupmenu: HMENU,
|
||||||
hwnds: Vec<HWND>,
|
hwnds: Vec<HWND>,
|
||||||
|
context_hwnds: Vec<HWND>,
|
||||||
haccel_store: Rc<RefCell<AccelWrapper>>,
|
haccel_store: Rc<RefCell<AccelWrapper>>,
|
||||||
children: Vec<Rc<RefCell<MenuChild>>>,
|
children: Vec<Rc<RefCell<MenuChild>>>,
|
||||||
}
|
}
|
||||||
|
@ -136,6 +137,14 @@ impl Drop for Menu {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
for hwnd in &self.hwnds {
|
||||||
|
SetMenu(*hwnd, 0);
|
||||||
|
RemoveWindowSubclass(*hwnd, Some(menu_subclass_proc), MENU_SUBCLASS_ID);
|
||||||
|
}
|
||||||
|
for hwnd in &self.context_hwnds {
|
||||||
|
SetMenu(*hwnd, 0);
|
||||||
|
RemoveWindowSubclass(*hwnd, Some(menu_subclass_proc), MENU_SUBCLASS_ID);
|
||||||
|
}
|
||||||
DestroyMenu(self.hmenu);
|
DestroyMenu(self.hmenu);
|
||||||
DestroyMenu(self.hpopupmenu);
|
DestroyMenu(self.hpopupmenu);
|
||||||
}
|
}
|
||||||
|
@ -153,6 +162,7 @@ impl Menu {
|
||||||
haccel_store: Rc::new(RefCell::new((0, HashMap::new()))),
|
haccel_store: Rc::new(RefCell::new((0, HashMap::new()))),
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
hwnds: Vec::new(),
|
hwnds: Vec::new(),
|
||||||
|
context_hwnds: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,12 +330,14 @@ impl Menu {
|
||||||
self.hwnds.push(hwnd);
|
self.hwnds.push(hwnd);
|
||||||
unsafe {
|
unsafe {
|
||||||
SetMenu(hwnd, self.hmenu);
|
SetMenu(hwnd, self.hmenu);
|
||||||
|
if !self.context_hwnds.iter().any(|h| *h == hwnd) {
|
||||||
SetWindowSubclass(
|
SetWindowSubclass(
|
||||||
hwnd,
|
hwnd,
|
||||||
Some(menu_subclass_proc),
|
Some(menu_subclass_proc),
|
||||||
MENU_SUBCLASS_ID,
|
MENU_SUBCLASS_ID,
|
||||||
Box::into_raw(Box::new(self)) as _,
|
Box::into_raw(Box::new(self)) as _,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
DrawMenuBar(hwnd);
|
DrawMenuBar(hwnd);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -340,7 +352,9 @@ impl Menu {
|
||||||
.ok_or(crate::Error::NotInitialized)?;
|
.ok_or(crate::Error::NotInitialized)?;
|
||||||
self.hwnds.remove(index);
|
self.hwnds.remove(index);
|
||||||
unsafe {
|
unsafe {
|
||||||
|
if !self.context_hwnds.iter().any(|h| *h == hwnd) {
|
||||||
RemoveWindowSubclass(hwnd, Some(menu_subclass_proc), MENU_SUBCLASS_ID);
|
RemoveWindowSubclass(hwnd, Some(menu_subclass_proc), MENU_SUBCLASS_ID);
|
||||||
|
}
|
||||||
SetMenu(hwnd, 0);
|
SetMenu(hwnd, 0);
|
||||||
DrawMenuBar(hwnd);
|
DrawMenuBar(hwnd);
|
||||||
}
|
}
|
||||||
|
@ -399,8 +413,21 @@ impl Menu {
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_context_menu_for_hwnd(&self, hwnd: isize, position: Option<Position>) {
|
pub fn show_context_menu_for_hwnd(&mut self, hwnd: isize, position: Option<Position>) {
|
||||||
show_context_menu(hwnd, self.hpopupmenu, position)
|
let hpopupmenu = self.hpopupmenu;
|
||||||
|
if !self.context_hwnds.iter().any(|h| *h == hwnd) && !self.hwnds.iter().any(|h| *h == hwnd)
|
||||||
|
{
|
||||||
|
self.context_hwnds.push(hwnd);
|
||||||
|
unsafe {
|
||||||
|
SetWindowSubclass(
|
||||||
|
hwnd,
|
||||||
|
Some(menu_subclass_proc),
|
||||||
|
MENU_SUBCLASS_ID,
|
||||||
|
Box::into_raw(Box::new(self)) as _,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
show_context_menu(hwnd, hpopupmenu, position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,11 +459,19 @@ pub(crate) struct MenuChild {
|
||||||
hmenu: HMENU,
|
hmenu: HMENU,
|
||||||
hpopupmenu: HMENU,
|
hpopupmenu: HMENU,
|
||||||
pub children: Option<Vec<Rc<RefCell<MenuChild>>>>,
|
pub children: Option<Vec<Rc<RefCell<MenuChild>>>>,
|
||||||
|
context_hwnds: Option<Vec<HWND>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for MenuChild {
|
impl Drop for MenuChild {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if self.item_type == MenuItemType::Submenu {
|
if self.item_type == MenuItemType::Submenu {
|
||||||
|
for hwnd in self.context_hwnds.as_ref().unwrap() {
|
||||||
|
unsafe {
|
||||||
|
SetMenu(*hwnd, 0);
|
||||||
|
RemoveWindowSubclass(*hwnd, Some(menu_subclass_proc), SUBMENU_SUBCLASS_ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
DestroyMenu(self.hmenu);
|
DestroyMenu(self.hmenu);
|
||||||
DestroyMenu(self.hpopupmenu);
|
DestroyMenu(self.hpopupmenu);
|
||||||
|
@ -475,6 +510,7 @@ impl MenuChild {
|
||||||
children: None,
|
children: None,
|
||||||
hmenu: 0,
|
hmenu: 0,
|
||||||
hpopupmenu: 0,
|
hpopupmenu: 0,
|
||||||
|
context_hwnds: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,6 +531,7 @@ impl MenuChild {
|
||||||
icon: None,
|
icon: None,
|
||||||
checked: false,
|
checked: false,
|
||||||
accelerator: None,
|
accelerator: None,
|
||||||
|
context_hwnds: Some(Vec::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,6 +552,7 @@ impl MenuChild {
|
||||||
children: None,
|
children: None,
|
||||||
hmenu: 0,
|
hmenu: 0,
|
||||||
hpopupmenu: 0,
|
hpopupmenu: 0,
|
||||||
|
context_hwnds: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,6 +579,7 @@ impl MenuChild {
|
||||||
children: None,
|
children: None,
|
||||||
hmenu: 0,
|
hmenu: 0,
|
||||||
hpopupmenu: 0,
|
hpopupmenu: 0,
|
||||||
|
context_hwnds: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -567,6 +606,7 @@ impl MenuChild {
|
||||||
children: None,
|
children: None,
|
||||||
hmenu: 0,
|
hmenu: 0,
|
||||||
hpopupmenu: 0,
|
hpopupmenu: 0,
|
||||||
|
context_hwnds: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,6 +633,7 @@ impl MenuChild {
|
||||||
children: None,
|
children: None,
|
||||||
hmenu: 0,
|
hmenu: 0,
|
||||||
hpopupmenu: 0,
|
hpopupmenu: 0,
|
||||||
|
context_hwnds: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -889,8 +930,26 @@ impl MenuChild {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_context_menu_for_hwnd(&self, hwnd: isize, position: Option<Position>) {
|
pub fn show_context_menu_for_hwnd(&mut self, hwnd: isize, position: Option<Position>) {
|
||||||
show_context_menu(hwnd, self.hpopupmenu, position)
|
let hpopupmenu = self.hpopupmenu;
|
||||||
|
unsafe {
|
||||||
|
if !self
|
||||||
|
.context_hwnds
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.any(|h| *h == hwnd)
|
||||||
|
{
|
||||||
|
self.context_hwnds.as_mut().unwrap().push(hwnd);
|
||||||
|
SetWindowSubclass(
|
||||||
|
hwnd,
|
||||||
|
Some(menu_subclass_proc),
|
||||||
|
SUBMENU_SUBCLASS_ID,
|
||||||
|
Box::into_raw(Box::new(self)) as _,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
show_context_menu(hwnd, hpopupmenu, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attach_menu_subclass_for_hwnd(&self, hwnd: isize) {
|
pub fn attach_menu_subclass_for_hwnd(&self, hwnd: isize) {
|
||||||
|
@ -952,6 +1011,7 @@ fn show_context_menu(hwnd: HWND, hmenu: HMENU, position: Option<Position>) {
|
||||||
GetCursorPos(&mut pt);
|
GetCursorPos(&mut pt);
|
||||||
pt
|
pt
|
||||||
};
|
};
|
||||||
|
SetForegroundWindow(hwnd);
|
||||||
TrackPopupMenu(hmenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hwnd, std::ptr::null());
|
TrackPopupMenu(hmenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hwnd, std::ptr::null());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue