提交 27b7b13f 编写于 作者: M Matt Bierner 提交者: Benjamin Pasero

Fix context menu retrigger race (#59059)

Fixes #58711

When a context menu is triggered from inside another context menu, we have a race condition related to ipc. This is cause by the `close` event for context menus being global. In the retrigger case, `close` ends up being fired after the second context menu is created. This ends up removing the click handler for the new context menu

Fix is to add a menu id to the close event.
上级 45200866
......@@ -8,16 +8,21 @@
import { ipcRenderer, Event } from 'electron';
import { IContextMenuItem, ISerializableContextMenuItem, CONTEXT_MENU_CLOSE_CHANNEL, CONTEXT_MENU_CHANNEL, IPopupOptions, IContextMenuEvent } from 'vs/base/parts/contextmenu/common/contextmenu';
let onClickChannelIds = 0;
let contextMenuIdPool = 0;
export function popup(items: IContextMenuItem[], options?: IPopupOptions): void {
const processedItems: IContextMenuItem[] = [];
const onClickChannel = `vscode:onContextMenu${onClickChannelIds++}`;
const onClickChannelHandler = (event: Event, itemId: number, context: IContextMenuEvent) => processedItems[itemId].click(context);
const contextMenuId = contextMenuIdPool++;
const onClickChannel = `vscode:onContextMenu${contextMenuId}`;
const onClickChannelHandler = (_event: Event, itemId: number, context: IContextMenuEvent) => processedItems[itemId].click(context);
ipcRenderer.once(onClickChannel, onClickChannelHandler);
ipcRenderer.once(CONTEXT_MENU_CLOSE_CHANNEL, () => {
ipcRenderer.once(CONTEXT_MENU_CLOSE_CHANNEL, (_event: Event, closedContextMenuId: number) => {
if (closedContextMenuId !== contextMenuId) {
return;
}
ipcRenderer.removeListener(onClickChannel, onClickChannelHandler);
if (options && options.onHide) {
......@@ -25,7 +30,7 @@ export function popup(items: IContextMenuItem[], options?: IPopupOptions): void
}
});
ipcRenderer.send(CONTEXT_MENU_CHANNEL, items.map(item => createItem(item, processedItems)), onClickChannel, options);
ipcRenderer.send(CONTEXT_MENU_CHANNEL, contextMenuId, items.map(item => createItem(item, processedItems)), onClickChannel, options);
}
function createItem(item: IContextMenuItem, processedItems: IContextMenuItem[]): ISerializableContextMenuItem {
......
......@@ -9,7 +9,7 @@ import { Menu, MenuItem, BrowserWindow, Event, ipcMain } from 'electron';
import { ISerializableContextMenuItem, CONTEXT_MENU_CLOSE_CHANNEL, CONTEXT_MENU_CHANNEL, IPopupOptions } from 'vs/base/parts/contextmenu/common/contextmenu';
export function registerContextMenuListener(): void {
ipcMain.on(CONTEXT_MENU_CHANNEL, (event: Event, items: ISerializableContextMenuItem[], onClickChannel: string, options?: IPopupOptions) => {
ipcMain.on(CONTEXT_MENU_CHANNEL, (event: Event, contextMenuId: number, items: ISerializableContextMenuItem[], onClickChannel: string, options?: IPopupOptions) => {
const menu = createMenu(event, onClickChannel, items);
menu.popup({
......@@ -18,7 +18,7 @@ export function registerContextMenuListener(): void {
y: options ? options.y : void 0,
positioningItem: options ? options.positioningItem : void 0,
callback: () => {
event.sender.send(CONTEXT_MENU_CLOSE_CHANNEL);
event.sender.send(CONTEXT_MENU_CLOSE_CHANNEL, contextMenuId);
}
});
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册