Skip to content

Commit

Permalink
Add native context menu (#463)
Browse files Browse the repository at this point in the history
* Add interop to open system context menu

* Allow default context menu pos (at cursor)

* Add text context menu

- Replaces earlier incarnation of system context menu
  • Loading branch information
webfiltered authored Dec 11, 2024
1 parent 9b85bde commit 82df3cf
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const IPC_CHANNELS = {
VALIDATE_COMFYUI_SOURCE: 'validate-comfyui-source',
SHOW_DIRECTORY_PICKER: 'show-directory-picker',
INSTALL_COMFYUI: 'install-comfyui',
SHOW_CONTEXT_MENU: 'show-context-menu',
} as const;

export enum ProgressStatus {
Expand Down
25 changes: 23 additions & 2 deletions src/main-process/appWindow.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
import { BrowserWindow, screen, app, shell, ipcMain, Tray, Menu, dialog, MenuItem } from 'electron';
import { BrowserWindow, screen, app, shell, ipcMain, Tray, Menu, dialog, MenuItem, type Point } from 'electron';
import path from 'node:path';
import Store from 'electron-store';
import { AppWindowSettings } from '../store';
import log from 'electron-log/main';
import { IPC_CHANNELS, ProgressStatus, ServerArgs } from '../constants';
import { getAppResourcesPath } from '../install/resourcePaths';
import { DesktopConfig } from '../store/desktopConfig';
import type { ElectronContextMenuOptions } from '../preload';

/**
* Creates a single application window that displays the renderer and encapsulates all the logic for sending messages to the renderer.
* Closes the application when the window is closed.
*/
export class AppWindow {
private window: BrowserWindow;
/** Volatile store containing window config - saves window state between launches. */
private store: Store<AppWindowSettings>;
private messageQueue: Array<{ channel: string; data: any }> = [];
private rendererReady: boolean = false;
/** The application menu. */
private menu: Electron.Menu | null;
/** The "edit" menu - cut/copy/paste etc. */
private editMenu?: Menu;

public constructor() {
const installed = DesktopConfig.store.get('installState') === 'installed';
Expand Down Expand Up @@ -55,7 +61,8 @@ export class AppWindow {
this.setupAppEvents();
this.sendQueuedEventsOnReady();
this.setupTray();
this.buildMenu();
this.menu = this.buildMenu();
this.buildTextMenu();
}

public isReady(): boolean {
Expand Down Expand Up @@ -224,6 +231,14 @@ export class AppWindow {
});
}

showSystemContextMenu(options?: ElectronContextMenuOptions): void {
if (options?.type === 'text') {
this.editMenu?.popup(options.pos);
} else {
this.menu?.popup(options?.pos);
}
}

setupTray() {
// Set icon for the tray
// I think there is a way to packaged the icon in so you don't need to reference resourcesPath
Expand Down Expand Up @@ -277,6 +292,11 @@ export class AppWindow {
return tray;
}

buildTextMenu() {
// Electron bug - strongly typed to the incorrect case.
this.editMenu = Menu.getApplicationMenu()?.items.find((x) => x.role?.toLowerCase() === 'editmenu')?.submenu;
}

buildMenu() {
const menu = Menu.getApplicationMenu();
if (menu) {
Expand Down Expand Up @@ -306,5 +326,6 @@ export class AppWindow {
Menu.setApplicationMenu(menu);
}
}
return menu;
}
}
7 changes: 5 additions & 2 deletions src/main-process/comfyDesktopApp.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { app, dialog, ipcMain } from 'electron';
import { app, dialog, ipcMain, type Point } from 'electron';
import log from 'electron-log/main';
import * as Sentry from '@sentry/electron/main';
import { graphics } from 'systeminformation';
Expand All @@ -9,7 +9,7 @@ import { AppWindow } from './appWindow';
import { ComfyServer } from './comfyServer';
import { ComfyServerConfig } from '../config/comfyServerConfig';
import fs from 'fs';
import { InstallOptions } from '../preload';
import { InstallOptions, type ElectronContextMenuOptions } from '../preload';
import path from 'path';
import { getModelsDirectory, validateHardware } from '../utils';
import { DownloadManager } from '../models/DownloadManager';
Expand Down Expand Up @@ -92,6 +92,9 @@ export class ComfyDesktopApp {
}

registerIPCHandlers(): void {
ipcMain.on(IPC_CHANNELS.SHOW_CONTEXT_MENU, (_event, options?: ElectronContextMenuOptions) => {
this.appWindow.showSystemContextMenu(options);
});
ipcMain.on(IPC_CHANNELS.OPEN_DEV_TOOLS, () => {
this.appWindow.openDevTools();
});
Expand Down
14 changes: 14 additions & 0 deletions src/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ export interface DownloadProgressUpdate {
message?: string;
}

export interface ElectronContextMenuOptions {
type: 'system' | 'text' | 'image';
pos?: Electron.Point;
}

const electronAPI = {
/**
* Callback for progress updates from the main process for starting ComfyUI.
Expand Down Expand Up @@ -215,6 +220,15 @@ const electronAPI = {
installComfyUI: (installOptions: InstallOptions) => {
ipcRenderer.send(IPC_CHANNELS.INSTALL_COMFYUI, installOptions);
},
/**
* Opens native context menus.
*
* {@link ElectronContextMenuOptions} contains the various options to control the menu type.
* @param options Define which type of menu to use, position, etc.
*/
showContextMenu: (options?: ElectronContextMenuOptions): void => {
return ipcRenderer.send(IPC_CHANNELS.SHOW_CONTEXT_MENU, options);
},
} as const;

export type ElectronAPI = typeof electronAPI;
Expand Down

0 comments on commit 82df3cf

Please sign in to comment.