electron#BrowserWindowConstructorOptions TypeScript Examples

The following examples show how to use electron#BrowserWindowConstructorOptions. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.ts    From TidGi-Desktop with Mozilla Public License 2.0 6 votes vote down vote up
private async handleCreateBasicWindow(windowName: WindowNames, windowConfig: BrowserWindowConstructorOptions): Promise<BrowserWindow> {
    const newWindow = new BrowserWindow(windowConfig);

    this.windows[windowName] = newWindow;

    const unregisterContextMenu = await this.menuService.initContextMenuForWindowWebContents(newWindow.webContents);
    newWindow.on('closed', () => {
      this.windows[windowName] = undefined;
      unregisterContextMenu();
    });
    let webContentLoadingPromise: Promise<void> | undefined;
    if (windowName === WindowNames.main) {
      // handle window show and Webview/browserView show
      webContentLoadingPromise = new Promise<void>((resolve) => {
        newWindow.once('ready-to-show', async () => {
          const mainWindow = this.get(WindowNames.main);
          if (mainWindow === undefined) return;
          const { wasOpenedAsHidden } = app.getLoginItemSettings();
          if (!wasOpenedAsHidden) {
            mainWindow.show();
          }
          // ensure redux is loaded first
          // if not, redux might not be able catch changes sent from ipcMain
          if (!mainWindow.webContents.isLoading()) {
            return resolve();
          }
          mainWindow.webContents.once('did-stop-loading', () => {
            resolve();
          });
        });
      });
    }
    await this.updateWindowBackground(newWindow);
    // This loading will wait for a while
    await newWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);
    await webContentLoadingPromise;
    return newWindow;
  }
Example #2
Source File: app-window.ts    From kliveide with MIT License 5 votes vote down vote up
/**
   * Gets the options this window should be created
   * @param savedWindowState
   * @returns
   */
  getWindowOptions(
    savedWindowState: any,
    showWindow: boolean
  ): BrowserWindowConstructorOptions {
    const windowOptions: BrowserWindowConstructorOptions = {
      x: savedWindowState.x,
      y: savedWindowState.y,
      width: savedWindowState.width,
      height: savedWindowState.height,
      minWidth: this.minimumWidth,
      minHeight: this.minimumHeight,
      show: showWindow,
      // --- This fixes subpixel aliasing on Windows
      // --- See https://github.com/atom/atom/commit/683bef5b9d133cb194b476938c77cc07fd05b972
      backgroundColor: "#fff",
      webPreferences: {
        webSecurity: false,
        devTools: process.env.NODE_ENV === "production" ? false : true,
        contextIsolation: true,
        preload: path.join(__dirname, "preload.bundled.js"),
      },
      acceptFirstMouse: true,
      icon: path.join(__dirname, "icons/spectnet-logo.png"),
    };

    // --- Additional options depending on the host platform
    if (__DARWIN__) {
      windowOptions.frame = true;
    } else if (__WIN32__) {
      windowOptions.frame = true;
    } else if (__LINUX__) {
      windowOptions.icon = path.join(__dirname, "icons/spectnet-logo.png");
    }
    return windowOptions;
  }
Example #3
Source File: window.ts    From SideQuest with MIT License 5 votes vote down vote up
private createWindow(state?: WindowState) {
        const [windowState, hasMultipleDisplays] = this.restoreWindowState(state);

        const isMaximized = windowState.mode === 'maximized';
        const showAfterSetup = isMaximized;

        const options: BrowserWindowConstructorOptions = {
            width: windowState.width,
            height: windowState.height,
            x: windowState.x,
            y: windowState.y,
            minWidth: 800,
            minHeight: 480,
            show: !showAfterSetup,
            frame: false,
            webPreferences: {
                webviewTag: true,
                nodeIntegration: true,
                contextIsolation: false,
            },
        };
        this._window = new BrowserWindow(options);

        // (Electron 4 regression): when running on multiple displays where the target display
        // to open the window has a larger resolution than the primary display, the window will not size
        // correctly unless we set the bounds again
        const isMacintosh = process.platform === 'darwin';
        if (isMacintosh && hasMultipleDisplays) {
            const hasAllBoundsValues = [windowState.width, windowState.height, windowState.x, windowState.y].every(
                value => typeof value === 'number'
            );
            if (hasAllBoundsValues) {
                this._window.setBounds({
                    width: windowState.width,
                    height: windowState.height,
                    x: windowState.x,
                    y: windowState.y,
                });
            }
        }

        if (isMaximized) {
            this._window.maximize();

            if (!this._window.isVisible()) {
                this._window.show();
            }
        }
    }
Example #4
Source File: window.ts    From noteworthy with GNU Affero General Public License v3.0 5 votes vote down vote up
constructor(name: string, options: BrowserWindowConstructorOptions = {}, stateOptions: windowStateKeeper.Options = {}){
		this.name = name;
		this.options = options;
		this.stateOptions = stateOptions;
	}
Example #5
Source File: window.ts    From noteworthy with GNU Affero General Public License v3.0 5 votes vote down vote up
options: BrowserWindowConstructorOptions;
Example #6
Source File: main.ts    From WowUp with GNU General Public License v3.0 4 votes vote down vote up
function createWindow(): BrowserWindow {
  if (win) {
    win.destroy();
  }

  // Main object for managing window state
  // Initialize with a window name and default size
  const mainWindowManager = windowStateManager("main", {
    width: WINDOW_DEFAULT_WIDTH,
    height: WINDOW_DEFAULT_HEIGHT,
  });

  const windowOptions: BrowserWindowConstructorOptions = {
    width: mainWindowManager.width,
    height: mainWindowManager.height,
    x: mainWindowManager.x,
    y: mainWindowManager.y,
    minWidth: WINDOW_MIN_WIDTH,
    minHeight: WINDOW_MIN_HEIGHT,
    center: mainWindowManager.centered === true,
    transparent: false,
    resizable: true,
    backgroundColor: getBackgroundColor(),
    title: "WowUp",
    titleBarStyle: "hidden",
    webPreferences: {
      preload: join(__dirname, "preload.js"),
      nodeIntegration: true,
      contextIsolation: false,
      allowRunningInsecureContent: argv.serve,
      webSecurity: false,
      additionalArguments: [
        `--log-path=${LOG_PATH}`,
        `--user-data-path=${app.getPath("userData")}`,
        `--base-bg-color=${getBackgroundColor()}`,
      ],
      webviewTag: true,
    },
    show: false,
  };

  if (platform.isWin || platform.isLinux) {
    windowOptions.frame = false;
  }

  // Attempt to fix the missing icon issue on Ubuntu
  if (platform.isLinux) {
    windowOptions.icon = join(__dirname, "assets", WOWUP_LOGO_FILENAME);
  }

  // Create the browser window.
  win = new BrowserWindow(windowOptions);

  appUpdater.init(win);

  initializeIpcHandlers(win);
  initializeStoreIpcHandlers();

  pushEvents.on(PUSH_NOTIFICATION_EVENT, (data) => {
    win.webContents.send(IPC_PUSH_NOTIFICATION, data);
  });

  // Keep track of window state
  mainWindowManager.monitorState(win);

  win.on("blur", () => {
    win.webContents.send("blur");
  });

  win.on("focus", () => {
    win.webContents.send("focus");
  });

  win.webContents.userAgent = USER_AGENT;

  win.webContents.on("will-attach-webview", (evt, webPreferences) => {
    log.debug("will-attach-webview");

    webPreferences.additionalArguments = [`--log-path=${LOG_PATH}`];
    webPreferences.contextIsolation = true;
    webPreferences.plugins = false;
    webPreferences.webgl = false;
  });

  win.webContents.on("did-attach-webview", (evt, webContents) => {
    webContents.session.setUserAgent(webContents.userAgent);

    webContents.on("preload-error", (evt) => {
      log.error("[webview] preload-error", evt);
    });

    webContents.on("did-fail-provisional-load", (evt) => {
      log.error("[webview] did-fail-provisional-load", evt);
    });

    webContents.session.setPermissionRequestHandler((contents, permission, callback) => {
      log.warn("setPermissionRequestHandler", permission);
      return callback(false);
    });

    webContents.session.setPermissionCheckHandler((contents, permission, origin) => {
      if (["background-sync"].includes(permission)) {
        return true;
      }

      log.warn("setPermissionCheckHandler", permission, origin);
      return false;
    });

    webContents.on("did-fail-load", (evt, code, desc, url) => {
      log.error("[webview] did-fail-load", code, desc, url);
      setTimeout(() => {
        log.error("[webview] reload");
        webContents.reload();
      }, 2000);
    });

    webContents.on("will-navigate", (evt, url) => {
      log.debug("[webview] will-navigate", url);
      if (webContents.getURL() === url) {
        log.debug(`[webview] reload detected`);
      } else {
        evt.preventDefault(); // block the webview from navigating at all
      }
    });

    // webview allowpopups must be enabled for any link to work
    // https://www.electronjs.org/docs/latest/api/webview-tag#allowpopups
    webContents.setWindowOpenHandler((details) => {
      log.debug("[webview] setWindowOpenHandler");
      win.webContents.send("webview-new-window", details); // forward this new window to the app for processing
      return { action: "deny" };
    });
  });

  win.webContents.on("zoom-changed", (evt, zoomDirection) => {
    sendEventToContents(win, "zoom-changed", zoomDirection);
  });

  // See https://www.electronjs.org/docs/api/web-contents#event-render-process-gone
  win.webContents.on("render-process-gone", (evt, details) => {
    log.error("webContents render-process-gone");
    log.error(details);

    // If something killed the process, quit
    if (details.reason === "killed") {
      win?.destroy();
      app.quit();
      return;
    }

    // If process crashes too quickly, kill the app
    const crashTime = Date.now();
    if (crashTime - lastCrash < 5000) {
      log.error("Crash loop detected");
      win?.destroy();
      app.quit();
      return;
    }

    lastCrash = crashTime;
    log.info("Restarting main window");
  });

  // See https://www.electronjs.org/docs/api/web-contents#event-unresponsive
  win.webContents.on("unresponsive", () => {
    log.error("webContents unresponsive");
  });

  // See https://www.electronjs.org/docs/api/web-contents#event-responsive
  win.webContents.on("responsive", () => {
    log.error("webContents responsive");
  });

  win.once("ready-to-show", () => {
    if (canStartHidden()) {
      return;
    }

    // win.webContents.session.setPermissionRequestHandler((contents, permission, callback) => {
    //   log.warn("win setPermissionRequestHandler", permission);
    //   return callback(false);
    // });

    // win.webContents.session.setPermissionCheckHandler((contents, permission, origin) => {
    //   log.warn("win setPermissionCheckHandler", permission, origin);
    //   return false;
    // });

    win.show();
  });

  win.once("show", () => {
    // win.webContents.openDevTools();

    if (mainWindowManager.isFullScreen) {
      win.setFullScreen(true);
    } else if (mainWindowManager.isMaximized) {
      win.maximize();
    }

    appUpdater.checkForUpdates().catch((e) => console.error(e));

    win.on("show", () => {
      win?.webContents?.send(IPC_WINDOW_RESUME);
    });
  });

  win.on("close", (e) => {
    if (appIsQuitting || preferenceStore.get(COLLAPSE_TO_TRAY_PREFERENCE_KEY) !== "true") {
      pushEvents.removeAllListeners(PUSH_NOTIFICATION_EVENT);
      return;
    }
    e.preventDefault();
    win.hide();
    win.setSkipTaskbar(true);

    if (platform.isMac) {
      app.setBadgeCount(0);
      app.dock.hide();
    }
  });

  win.once("closed", () => {
    win = null;
  });

  win.on("maximize", () => {
    win?.webContents?.send(IPC_WINDOW_MAXIMIZED);
  });

  win.on("unmaximize", () => {
    win?.webContents?.send(IPC_WINDOW_UNMAXIMIZED);
  });

  win.on("minimize", () => {
    win?.webContents?.send(IPC_WINDOW_MINIMIZED);
  });

  win.on("enter-full-screen", () => {
    win?.webContents?.send(IPC_WINDOW_ENTER_FULLSCREEN);
  });

  win.on("leave-full-screen", () => {
    win?.webContents?.send(IPC_WINDOW_LEAVE_FULLSCREEN);
  });

  win.webContents.on("did-fail-load", () => {
    log.info("did-fail-load");
    if (loadFailCount < 5) {
      loadFailCount += 1;
      loadMainUrl(win).catch((e) => log.error(e));
    } else {
      log.error(`Failed to load too many times, exiting`);
      app.quit();
    }
  });

  log.info(`Loading app URL: ${Date.now() - startedAt}ms`);
  if (argv.serve) {
    require("electron-reload")(__dirname, {
      electron: require(join(__dirname, "..", "node_modules", "electron")),
    });
    win.loadURL("http://localhost:4200").catch((e) => log.error(e));
  } else {
    loadMainUrl(win).catch((e) => log.error(e));
  }

  return win;
}
Example #7
Source File: setupViewEventHandlers.ts    From TidGi-Desktop with Mozilla Public License 2.0 4 votes vote down vote up
function handleNewWindow(
  nextUrl: string,
  newWindowContext: INewWindowContext,
  disposition: 'default' | 'new-window' | 'foreground-tab' | 'background-tab' | 'save-to-disk' | 'other',
  parentWebContents: Electron.WebContents,
):
  | {
      action: 'deny';
    }
  | {
      action: 'allow';
      overrideBrowserWindowOptions?: Electron.BrowserWindowConstructorOptions | undefined;
    } {
  const nextDomain = extractDomain(nextUrl);
  // open external url in browser
  if (nextDomain !== undefined && (disposition === 'foreground-tab' || disposition === 'background-tab')) {
    logger.debug('handleNewWindow() openExternal', { nextUrl, nextDomain, disposition });
    void shell.openExternal(nextUrl).catch((error) => logger.error(`handleNewWindow() openExternal error ${(error as Error).message}`, error));
    return {
      action: 'deny',
    };
  }
  const workspaceService = container.get<IWorkspaceService>(serviceIdentifier.Workspace);
  logger.debug('handleNewWindow()', { newWindowContext });
  const { view, workspace, sharedWebPreferences } = newWindowContext;
  const currentUrl = view.webContents.getURL();
  /** Conditions are listed by order of priority
  if global.forceNewWindow = true
  or regular new-window event
  or if in Google Drive app, open Google Docs files internally https://github.com/atomery/webcatalog/issues/800
  the next external link request will be opened in new window */
  const clickOpenNewWindow = newWindowContext.meta.forceNewWindow || disposition === 'new-window' || disposition === 'default';
  /** App tries to open external link using JS
  nextURL === 'about:blank' but then window will redirect to the external URL
  https://github.com/quanglam2807/webcatalog/issues/467#issuecomment-569857721 */
  const isExternalLinkUsingJS = nextDomain === null && (disposition === 'foreground-tab' || disposition === 'background-tab');
  if (clickOpenNewWindow || isExternalLinkUsingJS) {
    // https://gist.github.com/Gvozd/2cec0c8c510a707854e439fb15c561b0
    // if 'new-window' is triggered with Cmd+Click
    // options is undefined
    // https://github.com/atomery/webcatalog/issues/842
    const browserViewMetaData: IBrowserViewMetaData = {
      isPopup: true,
      ...(JSON.parse(
        decodeURIComponent(sharedWebPreferences?.additionalArguments?.[1]?.replace(MetaDataChannel.browserViewMetaData, '') ?? '{}'),
      ) as IBrowserViewMetaData),
    };
    logger.debug(`handleNewWindow() ${newWindowContext.meta.forceNewWindow ? 'forceNewWindow' : 'disposition'}`, {
      browserViewMetaData,
      disposition,
      nextUrl,
      nextDomain,
    });
    newWindowContext.meta.forceNewWindow = false;
    const metadataConfig = {
      additionalArguments: [
        `${MetaDataChannel.browserViewMetaData}${WindowNames.newWindow}`,
        `${MetaDataChannel.browserViewMetaData}${encodeURIComponent(JSON.stringify(browserViewMetaData))}`,
      ],
      preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
    };
    const windowWithBrowserViewState = windowStateKeeper({
      file: 'window-state-open-in-new-window.json',
      path: SETTINGS_FOLDER,
      defaultWidth: windowDimension[WindowNames.main].width,
      defaultHeight: windowDimension[WindowNames.main].height,
    });
    let newOptions: BrowserWindowConstructorOptions = {
      x: windowWithBrowserViewState.x,
      y: windowWithBrowserViewState.y,
      width: windowWithBrowserViewState.width,
      height: windowWithBrowserViewState.height,
      webPreferences: metadataConfig,
      autoHideMenuBar: true,
    };

    if (isExternalLinkUsingJS) {
      newOptions = { ...newOptions, show: false };
    }
    parentWebContents.once('did-create-window', (childWindow) => {
      childWindow.setMenuBarVisibility(false);
      childWindow.webContents.setWindowOpenHandler((details: Electron.HandlerDetails) =>
        handleNewWindow(details.url, newWindowContext, details.disposition, parentWebContents),
      );
      childWindow.webContents.once('will-navigate', async (_event, url) => {
        // if the window is used for the current app, then use default behavior
        let appUrl = (await workspaceService.get(workspace.id))?.homeUrl;
        if (appUrl === undefined) {
          throw new Error(`Workspace ${workspace.id} not existed, or don't have homeUrl setting`);
        }
        appUrl = await getLocalHostUrlWithActualIP(appUrl);
        if (isInternalUrl(url, [appUrl, currentUrl])) {
          childWindow.show();
        } else {
          // if not, open in browser
          _event.preventDefault();
          void shell.openExternal(url);
          childWindow.close();
        }
      });
      windowWithBrowserViewState.manage(childWindow);
      const menuService = container.get<IMenuService>(serviceIdentifier.MenuService);
      void menuService.initContextMenuForWindowWebContents(view.webContents).then((unregisterContextMenu) => {
        childWindow.webContents.on('destroyed', () => {
          unregisterContextMenu();
        });
      });
    });
    return {
      action: 'allow',
      overrideBrowserWindowOptions: newOptions,
    };
  }

  return { action: 'allow' };
}
Example #8
Source File: index.ts    From TidGi-Desktop with Mozilla Public License 2.0 4 votes vote down vote up
public async open<N extends WindowNames>(
    windowName: N,
    meta: WindowMeta[N] = {} as WindowMeta[N],
    config?: {
      recreate?: boolean | ((windowMeta: WindowMeta[N]) => boolean);
    },
  ): Promise<void> {
    const { recreate = false } = config ?? {};
    const existedWindow = this.get(windowName);
    // update window meta
    await this.setWindowMeta(windowName, meta);
    const existedWindowMeta = await this.getWindowMeta(windowName);

    if (existedWindow !== undefined) {
      if (recreate === true || (typeof recreate === 'function' && existedWindowMeta !== undefined && recreate(existedWindowMeta))) {
        existedWindow.close();
      } else {
        return existedWindow.show();
      }
    }

    // create new window
    let windowWithBrowserViewConfig: Partial<BrowserWindowConstructorOptions> = {};
    let windowWithBrowserViewState: windowStateKeeperState | undefined;
    const isWindowWithBrowserView = windowName === WindowNames.main || windowName === WindowNames.menuBar;
    if (isWindowWithBrowserView) {
      windowWithBrowserViewState = windowStateKeeper({
        file: windowName === WindowNames.main ? 'window-state-main-window.json' : 'window-state-menubar.json',
        path: SETTINGS_FOLDER,
        defaultWidth: windowDimension[WindowNames.main].width,
        defaultHeight: windowDimension[WindowNames.main].height,
      });
      windowWithBrowserViewConfig = {
        x: windowWithBrowserViewState.x,
        y: windowWithBrowserViewState.y,
        width: windowWithBrowserViewState.width,
        height: windowWithBrowserViewState.height,
      };
    }
    const windowConfig: BrowserWindowConstructorOptions = {
      ...windowDimension[windowName],
      ...windowWithBrowserViewConfig,
      resizable: true,
      maximizable: true,
      minimizable: true,
      fullscreenable: true,
      autoHideMenuBar: false,
      titleBarStyle: (await this.preferenceService.get('titleBar')) ? 'default' : 'hidden',
      alwaysOnTop:
        windowName === WindowNames.menuBar ? await this.preferenceService.get('menuBarAlwaysOnTop') : await this.preferenceService.get('alwaysOnTop'),
      webPreferences: {
        devTools: !isTest,
        nodeIntegration: false,
        webSecurity: false,
        allowRunningInsecureContent: true,
        contextIsolation: true,
        preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
        additionalArguments: [
          `${MetaDataChannel.browserViewMetaData}${windowName}`,
          `${MetaDataChannel.browserViewMetaData}${encodeURIComponent(JSON.stringify(meta))}`,
        ],
      },
      parent: isWindowWithBrowserView ? undefined : this.get(WindowNames.main),
    };
    let newWindow: BrowserWindow;
    if (windowName === WindowNames.menuBar) {
      this.mainWindowMenuBar = await this.handleAttachToMenuBar(windowConfig);
      if (this.mainWindowMenuBar.window === undefined) {
        throw new Error('MenuBar failed to create window.');
      }
      newWindow = this.mainWindowMenuBar.window;
    } else {
      newWindow = await this.handleCreateBasicWindow(windowName, windowConfig);
      if (isWindowWithBrowserView) {
        this.registerMainWindowListeners(newWindow);
        // calling this to redundantly setBounds BrowserView
        // after the UI is fully loaded
        // if not, BrowserView mouseover event won't work correctly
        // https://github.com/atomery/webcatalog/issues/812
        await this.workspaceViewService.realignActiveWorkspace();
      } else {
        newWindow.setMenuBarVisibility(false);
      }
    }
    windowWithBrowserViewState?.manage(newWindow);
  }
Example #9
Source File: index.ts    From TidGi-Desktop with Mozilla Public License 2.0 4 votes vote down vote up
private async handleAttachToMenuBar(windowConfig: BrowserWindowConstructorOptions): Promise<Menubar> {
    // setImage after Tray instance is created to avoid
    // "Segmentation fault (core dumped)" bug on Linux
    // https://github.com/electron/electron/issues/22137#issuecomment-586105622
    // https://github.com/atomery/translatium/issues/164
    const tray = new Tray(nativeImage.createEmpty());
    // icon template is not supported on Windows & Linux
    tray.setImage(MENUBAR_ICON_PATH);

    const menuBar = menubar({
      index: MAIN_WINDOW_WEBPACK_ENTRY,
      tray,
      activateWithApp: false,
      preloadWindow: true,
      tooltip: i18n.t('Menu.TidGiMenuBar'),
      browserWindow: mergeDeep(windowConfig, {
        show: false,
        minHeight: 100,
        minWidth: 250,
      }),
    });

    menuBar.on('after-create-window', () => {
      if (menuBar.window !== undefined) {
        menuBar.window.on('focus', () => {
          const view = menuBar.window?.getBrowserView();
          if (view?.webContents !== undefined) {
            view.webContents.focus();
          }
        });
        menuBar.window.removeAllListeners('close');
        menuBar.window.on('close', (event) => {
          event.preventDefault();
          menuBar.hideWindow();
        });
      }
    });
    // https://github.com/maxogden/menubar/issues/120
    menuBar.on('after-hide', () => {
      if (process.platform === 'darwin') {
        menuBar.app.hide();
      }
    });

    return await new Promise<Menubar>((resolve) => {
      menuBar.on('ready', async () => {
        // right on tray icon
        menuBar.tray.on('right-click', () => {
          // TODO: restore updater options here
          const contextMenu = Menu.buildFromTemplate([
            {
              label: i18n.t('ContextMenu.OpenTidGi'),
              click: async () => await this.open(WindowNames.main),
            },
            {
              label: i18n.t('ContextMenu.OpenTidGiMenuBar'),
              click: async () => await menuBar.showWindow(),
            },
            {
              type: 'separator',
            },
            {
              label: i18n.t('ContextMenu.About'),
              click: async () => await this.open(WindowNames.about),
            },
            { type: 'separator' },
            {
              label: i18n.t('ContextMenu.Preferences'),
              click: async () => await this.open(WindowNames.preferences),
            },
            {
              label: i18n.t('ContextMenu.Notifications'),
              click: async () => await this.open(WindowNames.notifications),
            },
            { type: 'separator' },
            {
              label: i18n.t('ContextMenu.Quit'),
              click: () => {
                menuBar.app.quit();
              },
            },
          ]);

          menuBar.tray.popUpContextMenu(contextMenu);
        });

        // right click on window content
        if (menuBar.window?.webContents !== undefined) {
          const unregisterContextMenu = await this.menuService.initContextMenuForWindowWebContents(menuBar.window.webContents);
          menuBar.on('after-close', () => {
            unregisterContextMenu();
          });
        }

        resolve(menuBar);
      });
    });
  }