mirror of
https://github.com/italicsjenga/muda.git
synced 2024-12-23 12:01:31 +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")]
|
||||
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")]
|
||||
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")]
|
||||
|
|
|
@ -324,7 +324,7 @@ impl ContextMenu for Menu {
|
|||
#[cfg(target_os = "windows")]
|
||||
fn show_context_menu_for_hwnd(&self, hwnd: isize, position: Option<Position>) {
|
||||
self.inner
|
||||
.borrow()
|
||||
.borrow_mut()
|
||||
.show_context_menu_for_hwnd(hwnd, position)
|
||||
}
|
||||
|
||||
|
|
|
@ -34,11 +34,11 @@ use windows_sys::Win32::{
|
|||
AppendMenuW, CreateAcceleratorTableW, CreateMenu, CreatePopupMenu,
|
||||
DestroyAcceleratorTable, DestroyMenu, DrawMenuBar, EnableMenuItem, GetCursorPos,
|
||||
GetMenu, GetMenuItemInfoW, InsertMenuW, PostQuitMessage, RemoveMenu, SendMessageW,
|
||||
SetMenu, SetMenuItemInfoW, ShowWindow, TrackPopupMenu, HACCEL, HMENU, MENUITEMINFOW,
|
||||
MFS_CHECKED, MFS_DISABLED, MF_BYCOMMAND, MF_BYPOSITION, MF_CHECKED, MF_DISABLED,
|
||||
MF_ENABLED, MF_GRAYED, MF_POPUP, MF_SEPARATOR, MF_STRING, MF_UNCHECKED, MIIM_BITMAP,
|
||||
MIIM_STATE, MIIM_STRING, SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE, TPM_LEFTALIGN, WM_CLOSE,
|
||||
WM_COMMAND,
|
||||
SetForegroundWindow, SetMenu, SetMenuItemInfoW, ShowWindow, TrackPopupMenu, HACCEL,
|
||||
HMENU, MENUITEMINFOW, MFS_CHECKED, MFS_DISABLED, MF_BYCOMMAND, MF_BYPOSITION,
|
||||
MF_CHECKED, MF_DISABLED, MF_ENABLED, MF_GRAYED, MF_POPUP, MF_SEPARATOR, MF_STRING,
|
||||
MF_UNCHECKED, MIIM_BITMAP, MIIM_STATE, MIIM_STRING, SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE,
|
||||
TPM_LEFTALIGN, WM_CLOSE, WM_COMMAND,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -100,6 +100,7 @@ pub(crate) struct Menu {
|
|||
hmenu: HMENU,
|
||||
hpopupmenu: HMENU,
|
||||
hwnds: Vec<HWND>,
|
||||
context_hwnds: Vec<HWND>,
|
||||
haccel_store: Rc<RefCell<AccelWrapper>>,
|
||||
children: Vec<Rc<RefCell<MenuChild>>>,
|
||||
}
|
||||
|
@ -136,6 +137,14 @@ impl Drop for Menu {
|
|||
}
|
||||
|
||||
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.hpopupmenu);
|
||||
}
|
||||
|
@ -153,6 +162,7 @@ impl Menu {
|
|||
haccel_store: Rc::new(RefCell::new((0, HashMap::new()))),
|
||||
children: Vec::new(),
|
||||
hwnds: Vec::new(),
|
||||
context_hwnds: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -320,12 +330,14 @@ impl Menu {
|
|||
self.hwnds.push(hwnd);
|
||||
unsafe {
|
||||
SetMenu(hwnd, self.hmenu);
|
||||
SetWindowSubclass(
|
||||
hwnd,
|
||||
Some(menu_subclass_proc),
|
||||
MENU_SUBCLASS_ID,
|
||||
Box::into_raw(Box::new(self)) as _,
|
||||
);
|
||||
if !self.context_hwnds.iter().any(|h| *h == hwnd) {
|
||||
SetWindowSubclass(
|
||||
hwnd,
|
||||
Some(menu_subclass_proc),
|
||||
MENU_SUBCLASS_ID,
|
||||
Box::into_raw(Box::new(self)) as _,
|
||||
);
|
||||
}
|
||||
DrawMenuBar(hwnd);
|
||||
};
|
||||
|
||||
|
@ -340,7 +352,9 @@ impl Menu {
|
|||
.ok_or(crate::Error::NotInitialized)?;
|
||||
self.hwnds.remove(index);
|
||||
unsafe {
|
||||
RemoveWindowSubclass(hwnd, Some(menu_subclass_proc), MENU_SUBCLASS_ID);
|
||||
if !self.context_hwnds.iter().any(|h| *h == hwnd) {
|
||||
RemoveWindowSubclass(hwnd, Some(menu_subclass_proc), MENU_SUBCLASS_ID);
|
||||
}
|
||||
SetMenu(hwnd, 0);
|
||||
DrawMenuBar(hwnd);
|
||||
}
|
||||
|
@ -399,8 +413,21 @@ impl Menu {
|
|||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn show_context_menu_for_hwnd(&self, hwnd: isize, position: Option<Position>) {
|
||||
show_context_menu(hwnd, self.hpopupmenu, position)
|
||||
pub fn show_context_menu_for_hwnd(&mut self, hwnd: isize, position: Option<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,
|
||||
hpopupmenu: HMENU,
|
||||
pub children: Option<Vec<Rc<RefCell<MenuChild>>>>,
|
||||
context_hwnds: Option<Vec<HWND>>,
|
||||
}
|
||||
|
||||
impl Drop for MenuChild {
|
||||
fn drop(&mut self) {
|
||||
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 {
|
||||
DestroyMenu(self.hmenu);
|
||||
DestroyMenu(self.hpopupmenu);
|
||||
|
@ -475,6 +510,7 @@ impl MenuChild {
|
|||
children: None,
|
||||
hmenu: 0,
|
||||
hpopupmenu: 0,
|
||||
context_hwnds: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -495,6 +531,7 @@ impl MenuChild {
|
|||
icon: None,
|
||||
checked: false,
|
||||
accelerator: None,
|
||||
context_hwnds: Some(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -515,6 +552,7 @@ impl MenuChild {
|
|||
children: None,
|
||||
hmenu: 0,
|
||||
hpopupmenu: 0,
|
||||
context_hwnds: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -541,6 +579,7 @@ impl MenuChild {
|
|||
children: None,
|
||||
hmenu: 0,
|
||||
hpopupmenu: 0,
|
||||
context_hwnds: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -567,6 +606,7 @@ impl MenuChild {
|
|||
children: None,
|
||||
hmenu: 0,
|
||||
hpopupmenu: 0,
|
||||
context_hwnds: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -593,6 +633,7 @@ impl MenuChild {
|
|||
children: None,
|
||||
hmenu: 0,
|
||||
hpopupmenu: 0,
|
||||
context_hwnds: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -889,8 +930,26 @@ impl MenuChild {
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub fn show_context_menu_for_hwnd(&self, hwnd: isize, position: Option<Position>) {
|
||||
show_context_menu(hwnd, self.hpopupmenu, position)
|
||||
pub fn show_context_menu_for_hwnd(&mut self, hwnd: isize, position: Option<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) {
|
||||
|
@ -952,6 +1011,7 @@ fn show_context_menu(hwnd: HWND, hmenu: HMENU, position: Option<Position>) {
|
|||
GetCursorPos(&mut pt);
|
||||
pt
|
||||
};
|
||||
SetForegroundWindow(hwnd);
|
||||
TrackPopupMenu(hmenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hwnd, std::ptr::null());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue