Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions source/common/modules/window-register/application-menu-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ export default function showPopupMenu (position: Point|Rect, items: AnyMenuItem[
appMenu.classList.add('application-menu')
appMenu.style.zIndex = '99999' // Ensure it always stays on top of anything

let activeSubmenuClose: null | (() => void) = null

for (const item of items) {
const menuItem = renderMenuItem(item)

Expand Down Expand Up @@ -266,6 +268,7 @@ export default function showPopupMenu (position: Point|Rect, items: AnyMenuItem[
}

closeSubmenu = showPopupMenu(target, item.submenu, subCB, false) // NOTE: Prevent cleanup ONLY here!
activeSubmenuClose = closeSubmenu
} else if (
pointInRect(point, menuRect) &&
!pointInRect(point, rect) &&
Expand All @@ -274,6 +277,7 @@ export default function showPopupMenu (position: Point|Rect, items: AnyMenuItem[
// It's within the menu but not over our item, so hide again
closeSubmenu()
closeSubmenu = null
activeSubmenuClose = null
} // Else: Keep it open
})

Expand Down Expand Up @@ -328,16 +332,32 @@ export default function showPopupMenu (position: Point|Rect, items: AnyMenuItem[
// on the window, because this indicates that the menu should be closed.
// Clicks on any menu item will be handled before the event bubbles up to the
// window so we don't need additional checks.
const clickCallback = (event?: MouseEvent): void => {
const closeMenu = (event?: Event): void => {
if (event instanceof KeyboardEvent && event.key !== 'Escape') {
return
}

if (activeSubmenuClose !== null) {
activeSubmenuClose()
activeSubmenuClose = null
}

appMenu.parentElement?.removeChild(appMenu)
window.removeEventListener('mousedown', clickCallback)
window.removeEventListener('mousedown', closeMenu)
if (cleanup) {
window.removeEventListener('keydown', closeMenu, true)
}
}

window.addEventListener('mousedown', closeMenu)
if (cleanup) {
window.addEventListener('keydown', closeMenu, true)
}
window.addEventListener('mousedown', clickCallback)

// Return a close-callback for the caller to programmatically close the menu
return () => {
// When the closing function is called, remove the menu again
clickCallback()
closeMenu()
}
}

Expand Down
27 changes: 19 additions & 8 deletions source/common/vue/window/WindowMenubar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
*/

import showPopupMenu, { type AnyMenuItem, type SubmenuItem } from '@common/modules/window-register/application-menu-helper'
import { ref, onBeforeMount } from 'vue'
import { ref, onBeforeMount, onBeforeUnmount } from 'vue'

const ipcRenderer = window.ipc

Expand All @@ -42,6 +42,17 @@ const menuCloseCallback = ref<null|(() => void)|null>(null)
// Can contain a target if a submenu is right now being requested
const targetElement = ref<HTMLElement|null>(null)

const resetState = (event?: Event) => {
if (event instanceof KeyboardEvent && event.key !== 'Escape') {
return
}
// The closing will be handled automatically by the menu handler
if (menuCloseCallback.value !== null) {
menuCloseCallback.value = null
currentSubmenu.value = null
}
}

onBeforeMount(() => {
// Listen to messages from the menu provider
type MenuMessage = { command: 'application-menu', payload: SubmenuItem[] }
Expand All @@ -59,13 +70,13 @@ onBeforeMount(() => {
ipcRenderer.send('menu-provider', { command: 'get-application-menu' })

// Also make sure to reset the internal state if necessary
window.addEventListener('mousedown', (_event) => {
// The closing will be handled automatically by the menu handler
if (menuCloseCallback.value !== null) {
menuCloseCallback.value = null
currentSubmenu.value = null
}
})
window.addEventListener('mousedown', resetState)
window.addEventListener('keydown', resetState)
Comment thread
Polymorph0us marked this conversation as resolved.
})

onBeforeUnmount(() => {
window.removeEventListener('mousedown', resetState)
window.removeEventListener('keydown', resetState)
})

function getSubmenu (menuID: string, target: HTMLElement): void {
Expand Down