diff --git a/src/main/cli.ts b/src/main/cli.ts index 83f77cb..d7ad14a 100644 --- a/src/main/cli.ts +++ b/src/main/cli.ts @@ -42,6 +42,10 @@ const options = { type: "string", description: "Set User-Agent to a specific operating system. May trigger anti-spam or break voice chat", options: ["windows", "linux", "darwin"] + }, + repair: { + type: "boolean", + description: "Repair the application by re-downloading the latest Vencord files" } } satisfies Record; diff --git a/src/main/index.ts b/src/main/index.ts index 0c81512..181ef12 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,172 +1,17 @@ /* * Vesktop, a desktop app aiming to give you a snappier Discord Experience - * Copyright (c) 2023 Vendicated and Vencord contributors + * Copyright (c) 2026 Vendicated and Vesktop contributors * SPDX-License-Identifier: GPL-3.0-or-later */ -import "./cli"; -import "./updater"; -import "./ipc"; -import "./userAssets"; -import "./vesktopProtocol"; +import { app } from "electron"; -import { app, BrowserWindow, nativeTheme } from "electron"; +import { CommandLine } from "./cli"; +import { downloadVencordFiles } from "./utils/vencordLoader"; -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 { setAsDefaultProtocolClient } from "./utils/setAsDefaultProtocolClient"; -import { isDeckGameMode } from "./utils/steamOS"; - -console.log("Vesktop v" + app.getVersion()); - -// Make the Vencord files use our DATA_DIR -process.env.VENCORD_USER_DATA_DIR = DATA_DIR; - -const isLinux = process.platform === "linux"; - -export let enableHardwareAcceleration = true; - -function init() { - setAsDefaultProtocolClient("discord"); - - const { disableSmoothScroll, hardwareAcceleration, hardwareVideoAcceleration } = Settings.store; - - const enabledFeatures = new Set(app.commandLine.getSwitchValue("enable-features").split(",")); - const disabledFeatures = new Set(app.commandLine.getSwitchValue("disable-features").split(",")); - app.commandLine.removeSwitch("enable-features"); - app.commandLine.removeSwitch("disable-features"); - - if (hardwareAcceleration === false || process.argv.includes("--disable-gpu")) { - enableHardwareAcceleration = false; - app.disableHardwareAcceleration(); - } else { - if (hardwareVideoAcceleration) { - enabledFeatures.add("AcceleratedVideoEncoder"); - enabledFeatures.add("AcceleratedVideoDecoder"); - - if (isLinux) { - enabledFeatures.add("AcceleratedVideoDecodeLinuxGL"); - enabledFeatures.add("AcceleratedVideoDecodeLinuxZeroCopyGL"); - } - } - } - - if (disableSmoothScroll) { - app.commandLine.appendSwitch("disable-smooth-scrolling"); - } - - // disable renderer backgrounding to prevent the app from unloading when in the background - // https://github.com/electron/electron/issues/2822 - // https://github.com/GoogleChrome/chrome-launcher/blob/5a27dd574d47a75fec0fb50f7b774ebf8a9791ba/docs/chrome-flags-for-tools.md#task-throttling - app.commandLine.appendSwitch("disable-renderer-backgrounding"); - app.commandLine.appendSwitch("disable-background-timer-throttling"); - app.commandLine.appendSwitch("disable-backgrounding-occluded-windows"); - if (process.platform === "win32") { - disabledFeatures.add("CalculateNativeWinOcclusion"); - } - - // 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. - disabledFeatures.add("WinRetrieveSuggestionsOnlyOnDemand"); - disabledFeatures.add("HardwareMediaKeyHandling"); - disabledFeatures.add("MediaSessionService"); - - if (isLinux) { - // Support TTS on Linux using https://wiki.archlinux.org/title/Speech_dispatcher - app.commandLine.appendSwitch("enable-speech-dispatcher"); - - // This is needed to fix washed out colours - https://github.com/electron/electron/issues/49566 - // Supposed to be fixed already according to comments there, but it's just not lol, I can repro on Electron 43.0.0 - // when moving the window from my main monitor (HDR - not sure if this is relevant lol) to second monitor (SDR) and back - disabledFeatures.add("WaylandWpColorManagerV1"); - } - - disabledFeatures.forEach(feat => enabledFeatures.delete(feat)); - - const enabledFeaturesArray = enabledFeatures.values().filter(Boolean).toArray(); - const disabledFeaturesArray = disabledFeatures.values().filter(Boolean).toArray(); - - if (enabledFeaturesArray.length) { - app.commandLine.appendSwitch("enable-features", enabledFeaturesArray.join(",")); - console.log("Enabled Chromium features:", enabledFeaturesArray.join(", ")); - } - - if (disabledFeaturesArray.length) { - app.commandLine.appendSwitch("disable-features", disabledFeaturesArray.join(",")); - console.log("Disabled Chromium features:", disabledFeaturesArray.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 () => { - 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(); - } +if (CommandLine.values.repair) { + console.log("Repairing Vesktop..."); + downloadVencordFiles().then(() => app.quit()); } else { - init(); + require("./main"); } - -async function bootstrap() { - if (!Object.hasOwn(State.store, "firstLaunch")) { - createFirstLaunchTour(); - } else { - createWindows(); - } -} - -// MacOS only event -export let darwinURL: string | undefined; -app.on("open-url", (_, url) => { - darwinURL = url; -}); - -app.on("window-all-closed", () => { - if (process.platform !== "darwin") app.quit(); -}); - -// Sets the WebRTC IP handling policy for all current and future windows. -// Switching to "default_public_and_private_interfaces" may fix calls stuck at "DTLS Connecting" when using VPNs, Tailscale, etc. -// https://github.com/Vencord/Vesktop/issues/876 -app.on("web-contents-created", (_event, contents) => { - contents.setWebRTCIPHandlingPolicy(Settings.store.webRTCIPHandlingPolicy ?? "default"); -}); -Settings.addChangeListener("webRTCIPHandlingPolicy", () => { - for (const win of BrowserWindow.getAllWindows()) { - win.webContents.setWebRTCIPHandlingPolicy(Settings.store.webRTCIPHandlingPolicy ?? "default"); - } -}); diff --git a/src/main/ipc.ts b/src/main/ipc.ts index fde6762..395540b 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -20,13 +20,13 @@ import { } from "electron"; import { readFileSync, watch } from "fs"; import { readFile, stat } from "fs/promises"; -import { enableHardwareAcceleration } from "main"; import { release } from "os"; import { join } from "path"; import { IpcEvents } from "../shared/IpcEvents"; import { setBadgeCount } from "./appBadge"; import { autoStart } from "./autoStart"; +import { enableHardwareAcceleration } from "./main"; import { mainWin } from "./mainWindow"; import { Settings, State } from "./settings"; import { handle, handleSync } from "./utils/ipcWrappers"; diff --git a/src/main/main.ts b/src/main/main.ts new file mode 100644 index 0000000..0c81512 --- /dev/null +++ b/src/main/main.ts @@ -0,0 +1,172 @@ +/* + * Vesktop, a desktop app aiming to give you a snappier Discord Experience + * Copyright (c) 2023 Vendicated and Vencord contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import "./cli"; +import "./updater"; +import "./ipc"; +import "./userAssets"; +import "./vesktopProtocol"; + +import { app, BrowserWindow, nativeTheme } from "electron"; + +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 { setAsDefaultProtocolClient } from "./utils/setAsDefaultProtocolClient"; +import { isDeckGameMode } from "./utils/steamOS"; + +console.log("Vesktop v" + app.getVersion()); + +// Make the Vencord files use our DATA_DIR +process.env.VENCORD_USER_DATA_DIR = DATA_DIR; + +const isLinux = process.platform === "linux"; + +export let enableHardwareAcceleration = true; + +function init() { + setAsDefaultProtocolClient("discord"); + + const { disableSmoothScroll, hardwareAcceleration, hardwareVideoAcceleration } = Settings.store; + + const enabledFeatures = new Set(app.commandLine.getSwitchValue("enable-features").split(",")); + const disabledFeatures = new Set(app.commandLine.getSwitchValue("disable-features").split(",")); + app.commandLine.removeSwitch("enable-features"); + app.commandLine.removeSwitch("disable-features"); + + if (hardwareAcceleration === false || process.argv.includes("--disable-gpu")) { + enableHardwareAcceleration = false; + app.disableHardwareAcceleration(); + } else { + if (hardwareVideoAcceleration) { + enabledFeatures.add("AcceleratedVideoEncoder"); + enabledFeatures.add("AcceleratedVideoDecoder"); + + if (isLinux) { + enabledFeatures.add("AcceleratedVideoDecodeLinuxGL"); + enabledFeatures.add("AcceleratedVideoDecodeLinuxZeroCopyGL"); + } + } + } + + if (disableSmoothScroll) { + app.commandLine.appendSwitch("disable-smooth-scrolling"); + } + + // disable renderer backgrounding to prevent the app from unloading when in the background + // https://github.com/electron/electron/issues/2822 + // https://github.com/GoogleChrome/chrome-launcher/blob/5a27dd574d47a75fec0fb50f7b774ebf8a9791ba/docs/chrome-flags-for-tools.md#task-throttling + app.commandLine.appendSwitch("disable-renderer-backgrounding"); + app.commandLine.appendSwitch("disable-background-timer-throttling"); + app.commandLine.appendSwitch("disable-backgrounding-occluded-windows"); + if (process.platform === "win32") { + disabledFeatures.add("CalculateNativeWinOcclusion"); + } + + // 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. + disabledFeatures.add("WinRetrieveSuggestionsOnlyOnDemand"); + disabledFeatures.add("HardwareMediaKeyHandling"); + disabledFeatures.add("MediaSessionService"); + + if (isLinux) { + // Support TTS on Linux using https://wiki.archlinux.org/title/Speech_dispatcher + app.commandLine.appendSwitch("enable-speech-dispatcher"); + + // This is needed to fix washed out colours - https://github.com/electron/electron/issues/49566 + // Supposed to be fixed already according to comments there, but it's just not lol, I can repro on Electron 43.0.0 + // when moving the window from my main monitor (HDR - not sure if this is relevant lol) to second monitor (SDR) and back + disabledFeatures.add("WaylandWpColorManagerV1"); + } + + disabledFeatures.forEach(feat => enabledFeatures.delete(feat)); + + const enabledFeaturesArray = enabledFeatures.values().filter(Boolean).toArray(); + const disabledFeaturesArray = disabledFeatures.values().filter(Boolean).toArray(); + + if (enabledFeaturesArray.length) { + app.commandLine.appendSwitch("enable-features", enabledFeaturesArray.join(",")); + console.log("Enabled Chromium features:", enabledFeaturesArray.join(", ")); + } + + if (disabledFeaturesArray.length) { + app.commandLine.appendSwitch("disable-features", disabledFeaturesArray.join(",")); + console.log("Disabled Chromium features:", disabledFeaturesArray.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 () => { + 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(); + } +} + +// MacOS only event +export let darwinURL: string | undefined; +app.on("open-url", (_, url) => { + darwinURL = url; +}); + +app.on("window-all-closed", () => { + if (process.platform !== "darwin") app.quit(); +}); + +// Sets the WebRTC IP handling policy for all current and future windows. +// Switching to "default_public_and_private_interfaces" may fix calls stuck at "DTLS Connecting" when using VPNs, Tailscale, etc. +// https://github.com/Vencord/Vesktop/issues/876 +app.on("web-contents-created", (_event, contents) => { + contents.setWebRTCIPHandlingPolicy(Settings.store.webRTCIPHandlingPolicy ?? "default"); +}); +Settings.addChangeListener("webRTCIPHandlingPolicy", () => { + for (const win of BrowserWindow.getAllWindows()) { + win.webContents.setWebRTCIPHandlingPolicy(Settings.store.webRTCIPHandlingPolicy ?? "default"); + } +}); diff --git a/src/main/mainWindow.ts b/src/main/mainWindow.ts index 9acbe3d..979629d 100644 --- a/src/main/mainWindow.ts +++ b/src/main/mainWindow.ts @@ -26,8 +26,8 @@ import { initArRPC } from "./arrpc"; import { CommandLine } from "./cli"; import { BrowserUserAgent, DEFAULT_HEIGHT, DEFAULT_WIDTH, MIN_HEIGHT, MIN_WIDTH } from "./constants"; import { AppEvents } from "./events"; -import { darwinURL } from "./index"; import { sendRendererCommand } from "./ipcCommands"; +import { darwinURL } from "./main"; import { Settings, State, VencordSettings } from "./settings"; import { createSplashWindow, updateSplashMessage } from "./splash"; import { destroyTray, initTray } from "./tray";