diff --git a/src/main/firstLaunch.ts b/src/main/firstLaunch.ts new file mode 100644 index 0000000..5690c60 --- /dev/null +++ b/src/main/firstLaunch.ts @@ -0,0 +1,73 @@ +/* + * SPDX-License-Identifier: GPL-3.0 + * Aerocord, a vesktop fork for older microsoft NT releases such as NT 6.0, 6.1, 6.2 and 6.3. + * Credits to vendicated and the rest of the vesktop contribuitors for making Vesktop! + */ + +import { app } from "electron"; +import { BrowserWindow } from "electron/main"; +import { copyFileSync, mkdirSync, readdirSync } from "fs"; +import { join } from "path"; +import { SplashProps } from "shared/browserWinProperties"; +import { ICON_PATH, VIEW_DIR } from "shared/paths"; + +import { autoStart } from "./autoStart"; +import { DATA_DIR } from "./constants"; +import { createWindows } from "./mainWindow"; +import { Settings, State } from "./settings"; +import { makeLinksOpenExternally } from "./utils/makeLinksOpenExternally"; + +interface Data { + minimizeToTray: boolean; + discordBranch: "stable" | "canary" | "ptb"; + autoStart: boolean; + importSettings: boolean; + richPresence: boolean; +} + +export function createFirstLaunchTour() { + const win = new BrowserWindow({ + ...SplashProps, + frame: true, + autoHideMenuBar: true, + height: 470, + width: 550, + icon: ICON_PATH + }); + + makeLinksOpenExternally(win); + + win.loadFile(join(VIEW_DIR, "first-launch.html")); + win.webContents.addListener("console-message", (_e, _l, msg) => { + if (msg === "cancel") return app.exit(); + + if (!msg.startsWith("form:")) return; + const data = JSON.parse(msg.slice(5)) as Data; + + State.store.firstLaunch = false; + Settings.store.minimizeToTray = data.minimizeToTray; + Settings.store.discordBranch = data.discordBranch; + Settings.store.arRPC = data.richPresence; + + if (data.autoStart) autoStart.enable(); + + if (data.importSettings) { + const from = join(app.getPath("userData"), "..", "Vencord", "settings"); + const to = join(DATA_DIR, "settings"); + try { + const files = readdirSync(from); + mkdirSync(to, { recursive: true }); + + for (const file of files) { + copyFileSync(join(from, file), join(to, file)); + } + } catch (e) { + console.error("Failed to import settings:", e); + } + } + + win.close(); + + createWindows(); + }); +} diff --git a/src/main/index.ts b/src/main/index.ts new file mode 100644 index 0000000..bc571d1 --- /dev/null +++ b/src/main/index.ts @@ -0,0 +1,108 @@ +/* + * SPDX-License-Identifier: GPL-3.0 + * Aerocord, a vesktop fork for older microsoft NT releases such as NT 6.0, 6.1, 6.2 and 6.3. + * Credits to vendicated and the rest of the vesktop contribuitors for making Vesktop! + */ + +import "./ipc"; + +import { app, BrowserWindow, nativeTheme } from "electron"; +import { checkUpdates } from "updater/main"; + +import { DATA_DIR } from "./constants"; +import { createFirstLaunchTour } from "./firstLaunch"; +import { createWindows, mainWin } from "./mainWindow"; +import { registerMediaPermissionsHandler } from "./mediaPermissions"; +import { registerScreenShareHandler } from "./screenShare"; +import { Settings, State } from "./settings"; +import { isDeckGameMode } from "./utils/steamOS"; + +if (IS_DEV) { + require("source-map-support").install(); +} + +// Make the Vencord files use our DATA_DIR +process.env.VENCORD_USER_DATA_DIR = DATA_DIR; + +function init() { + const { disableSmoothScroll, hardwareAcceleration } = Settings.store; + + const enabledFeatures = app.commandLine.getSwitchValue("enable-features").split(","); + const disabledFeatures = app.commandLine.getSwitchValue("disable-features").split(","); + + if (hardwareAcceleration === false) { + app.disableHardwareAcceleration(); + } else { + enabledFeatures.push("VaapiVideoDecodeLinuxGL", "VaapiVideoEncoder", "VaapiVideoDecoder"); + } + + if (disableSmoothScroll) { + app.commandLine.appendSwitch("disable-smooth-scrolling"); + } + + // work around chrome 66 disabling autoplay by default + app.commandLine.appendSwitch("autoplay-policy", "no-user-gesture-required"); + // WinRetrieveSuggestionsOnlyOnDemand: Work around electron 13 bug w/ async spellchecking on Windows. + // HardwareMediaKeyHandling,MediaSessionService: Prevent Discord from registering as a media service. + // + // WidgetLayering (Vencord Added): Fix DevTools context menus https://github.com/electron/electron/issues/38790 + disabledFeatures.push( + "WinRetrieveSuggestionsOnlyOnDemand", + "HardwareMediaKeyHandling", + "MediaSessionService", + "WidgetLayering" + ); + + app.commandLine.appendSwitch("enable-features", [...new Set(enabledFeatures)].filter(Boolean).join(",")); + app.commandLine.appendSwitch("disable-features", [...new Set(disabledFeatures)].filter(Boolean).join(",")); + + // In the Flatpak on SteamOS the theme is detected as light, but SteamOS only has a dark mode, so we just override it + if (isDeckGameMode) nativeTheme.themeSource = "dark"; + + app.on("second-instance", (_event, _cmdLine, _cwd, data: any) => { + if (data.IS_DEV) app.quit(); + else if (mainWin) { + if (mainWin.isMinimized()) mainWin.restore(); + if (!mainWin.isVisible()) mainWin.show(); + mainWin.focus(); + } + }); + + app.whenReady().then(async () => { + checkUpdates(); + if (process.platform === "win32") app.setAppUserModelId("dev.vencord.vesktop"); + + registerScreenShareHandler(); + registerMediaPermissionsHandler(); + + bootstrap(); + + app.on("activate", () => { + if (BrowserWindow.getAllWindows().length === 0) createWindows(); + }); + }); +} + +if (!app.requestSingleInstanceLock({ IS_DEV })) { + if (IS_DEV) { + console.log("Vesktop is already running. Quitting previous instance..."); + init(); + } else { + console.log("Vesktop is already running. Quitting..."); + app.quit(); + } +} else { + init(); +} + +async function bootstrap() { + if (!Object.hasOwn(State.store, "firstLaunch")) { + createFirstLaunchTour(); + } else { + createWindows(); + } +} + +app.on("window-all-closed", () => { + if (process.platform !== "darwin") app.quit(); +}); diff --git a/src/main/ipc.ts b/src/main/ipc.ts new file mode 100644 index 0000000..3a76ce0 --- /dev/null +++ b/src/main/ipc.ts @@ -0,0 +1,155 @@ +/* + * SPDX-License-Identifier: GPL-3.0 + * Aerocord, a vesktop fork for older microsoft NT releases such as NT 6.0, 6.1, 6.2 and 6.3. + * Credits to vendicated and the rest of the vesktop contribuitors for making Vesktop! + */ + +if (process.platform === "linux") import("./venmic"); + +import { execFile } from "child_process"; +import { app, BrowserWindow, clipboard, dialog, nativeImage, RelaunchOptions, session, shell } from "electron"; +import { mkdirSync, readFileSync, watch } from "fs"; +import { open, readFile } from "fs/promises"; +import { release } from "os"; +import { join } from "path"; +import { debounce } from "shared/utils/debounce"; + +import { IpcEvents } from "../shared/IpcEvents"; +import { setBadgeCount } from "./appBadge"; +import { autoStart } from "./autoStart"; +import { VENCORD_FILES_DIR, VENCORD_QUICKCSS_FILE, VENCORD_THEMES_DIR } from "./constants"; +import { mainWin } from "./mainWindow"; +import { Settings } from "./settings"; +import { handle, handleSync } from "./utils/ipcWrappers"; +import { PopoutWindows } from "./utils/popout"; +import { isDeckGameMode, showGamePage } from "./utils/steamOS"; +import { isValidVencordInstall } from "./utils/vencordLoader"; + +handleSync(IpcEvents.GET_VENCORD_PRELOAD_FILE, () => join(VENCORD_FILES_DIR, "vencordDesktopPreload.js")); +handleSync(IpcEvents.GET_VENCORD_RENDERER_SCRIPT, () => + readFileSync(join(VENCORD_FILES_DIR, "vencordDesktopRenderer.js"), "utf-8") +); + +handleSync(IpcEvents.GET_RENDERER_SCRIPT, () => readFileSync(join(__dirname, "renderer.js"), "utf-8")); +handleSync(IpcEvents.GET_RENDERER_CSS_FILE, () => join(__dirname, "renderer.css")); + +handleSync(IpcEvents.GET_SETTINGS, () => Settings.plain); +handleSync(IpcEvents.GET_VERSION, () => app.getVersion()); + +handleSync( + IpcEvents.SUPPORTS_WINDOWS_TRANSPARENCY, + () => process.platform === "win32" && Number(release().split(".").pop()) >= 22621 +); + +handleSync(IpcEvents.AUTOSTART_ENABLED, () => autoStart.isEnabled()); +handle(IpcEvents.ENABLE_AUTOSTART, autoStart.enable); +handle(IpcEvents.DISABLE_AUTOSTART, autoStart.disable); + +handle(IpcEvents.SET_SETTINGS, (_, settings: typeof Settings.store, path?: string) => { + Settings.setData(settings, path); +}); + +handle(IpcEvents.RELAUNCH, async () => { + const options: RelaunchOptions = { + args: process.argv.slice(1).concat(["--relaunch"]) + }; + if (isDeckGameMode) { + // We can't properly relaunch when running under gamescope, but we can at least navigate to our page in Steam. + await showGamePage(); + } else if (app.isPackaged && process.env.APPIMAGE) { + execFile(process.env.APPIMAGE, options.args); + } else { + app.relaunch(options); + } + app.exit(); +}); + +handle(IpcEvents.SHOW_ITEM_IN_FOLDER, (_, path) => { + shell.showItemInFolder(path); +}); + +handle(IpcEvents.FOCUS, () => { + mainWin.show(); + mainWin.setSkipTaskbar(false); +}); + +handle(IpcEvents.CLOSE, (e, key?: string) => { + const popout = PopoutWindows.get(key!); + if (popout) return popout.close(); + + const win = BrowserWindow.fromWebContents(e.sender) ?? e.sender; + win.close(); +}); + +handle(IpcEvents.MINIMIZE, e => { + mainWin.minimize(); +}); + +handle(IpcEvents.MAXIMIZE, e => { + if (mainWin.isMaximized()) { + mainWin.unmaximize(); + } else { + mainWin.maximize(); + } +}); + +handle(IpcEvents.SPELLCHECK_SET_LANGUAGES, (_, languages: string[]) => { + const ses = session.defaultSession; + + const available = ses.availableSpellCheckerLanguages; + const applicable = languages.filter(l => available.includes(l)).slice(0, 3); + if (applicable.length) ses.setSpellCheckerLanguages(applicable); +}); + +handle(IpcEvents.SPELLCHECK_REPLACE_MISSPELLING, (e, word: string) => { + e.sender.replaceMisspelling(word); +}); + +handle(IpcEvents.SPELLCHECK_ADD_TO_DICTIONARY, (e, word: string) => { + e.sender.session.addWordToSpellCheckerDictionary(word); +}); + +handle(IpcEvents.SELECT_VENCORD_DIR, async () => { + const res = await dialog.showOpenDialog(mainWin!, { + properties: ["openDirectory"] + }); + if (!res.filePaths.length) return "cancelled"; + + const dir = res.filePaths[0]; + if (!isValidVencordInstall(dir)) return "invalid"; + + return dir; +}); + +handle(IpcEvents.SET_BADGE_COUNT, (_, count: number) => setBadgeCount(count)); + +handle(IpcEvents.CLIPBOARD_COPY_IMAGE, async (_, buf: ArrayBuffer, src: string) => { + clipboard.write({ + html: ``, + image: nativeImage.createFromBuffer(Buffer.from(buf)) + }); +}); + +function readCss() { + return readFile(VENCORD_QUICKCSS_FILE, "utf-8").catch(() => ""); +} + +open(VENCORD_QUICKCSS_FILE, "a+").then(fd => { + fd.close(); + watch( + VENCORD_QUICKCSS_FILE, + { persistent: false }, + debounce(async () => { + mainWin?.webContents.postMessage("VencordQuickCssUpdate", await readCss()); + }, 50) + ); +}); + +mkdirSync(VENCORD_THEMES_DIR, { recursive: true }); +watch( + VENCORD_THEMES_DIR, + { persistent: false }, + debounce(() => { + mainWin?.webContents.postMessage("VencordThemeUpdate", void 0); + }) +); diff --git a/src/main/mainWindow.ts b/src/main/mainWindow.ts new file mode 100644 index 0000000..41dbed8 --- /dev/null +++ b/src/main/mainWindow.ts @@ -0,0 +1,488 @@ +/* + * SPDX-License-Identifier: GPL-3.0 + * Aerocord, a vesktop fork for older microsoft NT releases such as NT 6.0, 6.1, 6.2 and 6.3. + * Credits to vendicated and the rest of the vesktop contribuitors for making Vesktop! + */ + +import { + app, + BrowserWindow, + BrowserWindowConstructorOptions, + dialog, + Menu, + MenuItemConstructorOptions, + nativeTheme, + shell, + Tray +} from "electron"; +import { rm } from "fs/promises"; +import { join } from "path"; +import { IpcEvents } from "shared/IpcEvents"; +import { isTruthy } from "shared/utils/guards"; +import { once } from "shared/utils/once"; +import type { SettingsStore } from "shared/utils/SettingsStore"; + +import { ICON_PATH } from "../shared/paths"; +import { createAboutWindow } from "./about"; +import { initArRPC } from "./arrpc"; +import { + BrowserUserAgent, + DATA_DIR, + DEFAULT_HEIGHT, + DEFAULT_WIDTH, + MessageBoxChoice, + MIN_HEIGHT, + MIN_WIDTH, + VENCORD_FILES_DIR +} from "./constants"; +import { Settings, State, VencordSettings } from "./settings"; +import { createSplashWindow } from "./splash"; +import { makeLinksOpenExternally } from "./utils/makeLinksOpenExternally"; +import { applyDeckKeyboardFix, askToApplySteamLayout, isDeckGameMode } from "./utils/steamOS"; +import { downloadVencordFiles, ensureVencordFiles } from "./utils/vencordLoader"; + +let isQuitting = false; +let tray: Tray; + +applyDeckKeyboardFix(); + +app.on("before-quit", () => { + isQuitting = true; +}); + +export let mainWin: BrowserWindow; + +function makeSettingsListenerHelpers(o: SettingsStore) { + const listeners = new Map<(data: any) => void, PropertyKey>(); + + const addListener: typeof o.addChangeListener = (path, cb) => { + listeners.set(cb, path); + o.addChangeListener(path, cb); + }; + const removeAllListeners = () => { + for (const [listener, path] of listeners) { + o.removeChangeListener(path as any, listener); + } + + listeners.clear(); + }; + + return [addListener, removeAllListeners] as const; +} + +const [addSettingsListener, removeSettingsListeners] = makeSettingsListenerHelpers(Settings); +const [addVencordSettingsListener, removeVencordSettingsListeners] = makeSettingsListenerHelpers(VencordSettings); + +function initTray(win: BrowserWindow) { + const onTrayClick = () => { + if (Settings.store.clickTrayToShowHide && win.isVisible()) win.hide(); + else win.show(); + }; + const trayMenu = Menu.buildFromTemplate([ + { + label: "Open", + click() { + win.show(); + } + }, + { + label: "About and More", + click: createAboutWindow + }, + { + label: "Fix/Repair Vencord", + async click() { + await downloadVencordFiles(); + app.relaunch(); + app.quit(); + } + }, + { + label: "Reset User Data", + async click() { + await clearData(win); + } + }, + { + type: "separator" + }, + { + label: "Open Updater", + click() { + const updaterPath = join(app.getPath('exe'), '..', 'Updater.exe'); + shell.openPath(updaterPath); + } + }, + { + label: "Restart Aerocord", + click() { + app.relaunch(); + app.quit(); + } + }, + { + label: "Close Aerocord", + click() { + isQuitting = true; + app.quit(); + } + } + ]); + + tray = new Tray(ICON_PATH); + tray.setToolTip("Aerocord"); + tray.setContextMenu(trayMenu); + tray.on("click", onTrayClick); +} + +async function clearData(win: BrowserWindow) { + const { response } = await dialog.showMessageBox(win, { + message: "Are you sure you want to reset Aerocord?", + detail: "This will log you out, clear caches and reset all your settings!\n\nAerocord will automatically restart after this operation.", + buttons: ["Yes", "No"], + cancelId: MessageBoxChoice.Cancel, + defaultId: MessageBoxChoice.Default, + type: "warning" + }); + + if (response === MessageBoxChoice.Cancel) return; + + win.close(); + + await win.webContents.session.clearStorageData(); + await win.webContents.session.clearCache(); + await win.webContents.session.clearCodeCaches({}); + await rm(DATA_DIR, { force: true, recursive: true }); + + app.relaunch(); + app.quit(); +} + +type MenuItemList = Array; + +function initMenuBar(win: BrowserWindow) { + const isWindows = process.platform === "win32"; + const isDarwin = process.platform === "darwin"; + const wantCtrlQ = !isWindows || VencordSettings.store.winCtrlQ; + + const subMenu = [ + { + label: "About and Documentation", + click: createAboutWindow + }, + { + label: "Force Update Vencord", + async click() { + await downloadVencordFiles(); + app.relaunch(); + app.quit(); + }, + toolTip: "Aerocord will automatically restart after this operation" + }, + { + label: "Reset Aerocord", + async click() { + await clearData(win); + }, + toolTip: "Aerocord will automatically restart after this operation" + }, + { + label: "Relaunch", + accelerator: "CmdOrCtrl+Shift+R", + click() { + app.relaunch(); + app.quit(); + } + }, + ...(!isDarwin + ? [] + : ([ + { + type: "separator" + }, + { + label: "Settings", + accelerator: "CmdOrCtrl+,", + async click() { + mainWin.webContents.executeJavaScript( + "Vencord.Webpack.Common.SettingsRouter.open('My Account')" + ); + } + }, + { + type: "separator" + }, + { + role: "hide" + }, + { + role: "hideOthers" + }, + { + role: "unhide" + }, + { + type: "separator" + } + ] satisfies MenuItemList)), + { + label: "Quit", + accelerator: wantCtrlQ ? "CmdOrCtrl+Q" : void 0, + visible: !isWindows, + role: "quit", + click() { + app.quit(); + } + }, + isWindows && { + label: "Quit", + accelerator: "Alt+F4", + role: "quit", + click() { + app.quit(); + } + }, + // See https://github.com/electron/electron/issues/14742 and https://github.com/electron/electron/issues/5256 + { + label: "Zoom in (hidden, hack for Qwertz and others)", + accelerator: "CmdOrCtrl+=", + role: "zoomIn", + visible: false + } + ] satisfies MenuItemList; + + const menu = Menu.buildFromTemplate([ + { + label: "Vesktop", + role: "appMenu", + submenu: subMenu.filter(isTruthy) + }, + { role: "fileMenu" }, + { role: "editMenu" }, + { role: "viewMenu" }, + { role: "windowMenu" } + ]); + + Menu.setApplicationMenu(menu); +} + +function getWindowBoundsOptions(): BrowserWindowConstructorOptions { + // We want the default window behaivour to apply in game mode since it expects everything to be fullscreen and maximized. + if (isDeckGameMode) return {}; + + const { x, y, width, height } = State.store.windowBounds ?? {}; + + const options = { + width: width ?? DEFAULT_WIDTH, + height: height ?? DEFAULT_HEIGHT + } as BrowserWindowConstructorOptions; + + if (x != null && y != null) { + options.x = x; + options.y = y; + } + + if (!Settings.store.disableMinSize) { + options.minWidth = MIN_WIDTH; + options.minHeight = MIN_HEIGHT; + } + + return options; +} + +function getDarwinOptions(): BrowserWindowConstructorOptions { + const options = { + titleBarStyle: "hidden", + trafficLightPosition: { x: 10, y: 10 } + } as BrowserWindowConstructorOptions; + + const { splashTheming, splashBackground } = Settings.store; + const { macosTranslucency } = VencordSettings.store; + + if (macosTranslucency) { + options.vibrancy = "sidebar"; + options.backgroundColor = "#ffffff00"; + } else { + if (splashTheming) { + options.backgroundColor = splashBackground; + } else { + options.backgroundColor = nativeTheme.shouldUseDarkColors ? "#313338" : "#ffffff"; + } + } + + return options; +} + +function initWindowBoundsListeners(win: BrowserWindow) { + const saveState = () => { + State.store.maximized = win.isMaximized(); + State.store.minimized = win.isMinimized(); + }; + + win.on("maximize", saveState); + win.on("minimize", saveState); + win.on("unmaximize", saveState); + + const saveBounds = () => { + State.store.windowBounds = win.getBounds(); + }; + + win.on("resize", saveBounds); + win.on("move", saveBounds); +} + +function initSettingsListeners(win: BrowserWindow) { + addSettingsListener("tray", enable => { + if (enable) initTray(win); + else tray?.destroy(); + }); + addSettingsListener("disableMinSize", disable => { + if (disable) { + // 0 no work + win.setMinimumSize(1, 1); + } else { + win.setMinimumSize(MIN_WIDTH, MIN_HEIGHT); + + const { width, height } = win.getBounds(); + win.setBounds({ + width: Math.max(width, MIN_WIDTH), + height: Math.max(height, MIN_HEIGHT) + }); + } + }); + + addVencordSettingsListener("macosTranslucency", enabled => { + if (enabled) { + win.setVibrancy("sidebar"); + win.setBackgroundColor("#ffffff00"); + } else { + win.setVibrancy(null); + win.setBackgroundColor("#ffffff"); + } + }); + + addSettingsListener("enableMenu", enabled => { + win.setAutoHideMenuBar(enabled ?? false); + }); +} + +function initSpellCheck(win: BrowserWindow) { + win.webContents.on("context-menu", (_, data) => { + win.webContents.send(IpcEvents.SPELLCHECK_RESULT, data.misspelledWord, data.dictionarySuggestions); + }); +} + +function createMainWindow() { + // Clear up previous settings listeners + removeSettingsListeners(); + removeVencordSettingsListeners(); + + const { staticTitle, transparencyOption, enableMenu, customTitleBar } = Settings.store; + + const { frameless, transparent } = VencordSettings.store; + + const noFrame = frameless === true || customTitleBar === true; + + const win = (mainWin = new BrowserWindow({ + show: false, + webPreferences: { + nodeIntegration: false, + sandbox: false, + contextIsolation: true, + devTools: true, + preload: join(__dirname, "preload.js"), + spellcheck: true + }, + icon: ICON_PATH, + frame: !noFrame, + ...(transparent && { + transparent: true, + backgroundColor: "#00000000" + }), + ...(transparencyOption && + transparencyOption !== "none" && { + backgroundColor: "#00000000", + backgroundMaterial: transparencyOption + }), + // Fix transparencyOption for custom discord titlebar + ...(customTitleBar && + transparencyOption && + transparencyOption !== "none" && { + transparent: true + }), + ...(staticTitle && { title: "Vesktop" }), + ...(process.platform === "darwin" && getDarwinOptions()), + ...getWindowBoundsOptions(), + autoHideMenuBar: enableMenu + })); + win.setMenuBarVisibility(false); + + win.on("close", e => { + const useTray = !isDeckGameMode && Settings.store.minimizeToTray !== false && Settings.store.tray !== false; + if (isQuitting || (process.platform !== "darwin" && !useTray)) return; + + e.preventDefault(); + + if (process.platform === "darwin") app.hide(); + else win.hide(); + + return false; + }); + + if (Settings.store.staticTitle) win.on("page-title-updated", e => e.preventDefault()); + + initWindowBoundsListeners(win); + if (!isDeckGameMode && (Settings.store.tray ?? true) && process.platform !== "darwin") initTray(win); + initMenuBar(win); + makeLinksOpenExternally(win); + initSettingsListeners(win); + initSpellCheck(win); + + win.webContents.setUserAgent(BrowserUserAgent); + + const subdomain = + Settings.store.discordBranch === "canary" || Settings.store.discordBranch === "ptb" + ? `${Settings.store.discordBranch}.` + : ""; + + win.loadURL(`https://${subdomain}discord.com/app`); + + return win; +} + +const runVencordMain = once(() => require(join(VENCORD_FILES_DIR, "vencordDesktopMain.js"))); + +export async function createWindows() { + const startMinimized = process.argv.includes("--start-minimized"); + const splash = createSplashWindow(startMinimized); + // SteamOS letterboxes and scales it terribly, so just full screen it + if (isDeckGameMode) splash.setFullScreen(true); + await ensureVencordFiles(); + runVencordMain(); + + mainWin = createMainWindow(); + + mainWin.webContents.on("did-finish-load", () => { + splash.destroy(); + + if (!startMinimized) { + mainWin!.show(); + if (State.store.maximized && !isDeckGameMode) mainWin!.maximize(); + } + + if (isDeckGameMode) { + // always use entire display + mainWin!.setFullScreen(true); + + askToApplySteamLayout(mainWin); + } + + mainWin.once("show", () => { + if (State.store.maximized && !mainWin!.isMaximized() && !isDeckGameMode) { + mainWin!.maximize(); + } + }); + }); + + initArRPC(); +} diff --git a/src/main/mediaPermissions.ts b/src/main/mediaPermissions.ts new file mode 100644 index 0000000..f89aca5 --- /dev/null +++ b/src/main/mediaPermissions.ts @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: GPL-3.0 + * Aerocord, a vesktop fork for older microsoft NT releases such as NT 6.0, 6.1, 6.2 and 6.3. + * Credits to vendicated and the rest of the vesktop contribuitors for making Vesktop! + */ + +import { session, systemPreferences } from "electron"; + +export function registerMediaPermissionsHandler() { + if (process.platform !== "darwin") return; + + session.defaultSession.setPermissionRequestHandler(async (_webContents, permission, callback, details) => { + let granted = true; + + if (details.mediaTypes?.includes("audio")) { + granted = await systemPreferences.askForMediaAccess("microphone"); + } + if (details.mediaTypes?.includes("video")) { + granted &&= await systemPreferences.askForMediaAccess("camera"); + } + + callback(granted); + }); +}