/* * Vencord, a modification for Discord's desktop app * Copyright (c) 2022 Vendicated and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import { onceDefined } from "@shared/onceDefined"; import electron, { app, BrowserWindowConstructorOptions, Menu } from "electron"; import { dirname, join } from "path"; import { RendererSettings } from "./settings"; import { patchTrayMenu } from "./trayMenu"; import { IS_VANILLA } from "./utils/constants"; console.log("[Equicord] Starting up..."); // Our injector file at app/index.js const injectorPath = require.main!.filename; // The original app.asar const asarPath = join(dirname(injectorPath), "..", "_app.asar"); const discordPkg = require(join(asarPath, "package.json")); require.main!.filename = join(asarPath, discordPkg.main); if (IS_VESKTOP || IS_EQUIBOP) require.main!.filename = join(dirname(injectorPath), "..", "..", "package.json"); // @ts-expect-error Untyped method? Dies from cringe app.setAppPath(asarPath); if (!IS_VANILLA) { const settings = RendererSettings.store; patchTrayMenu(); /* * re-apply the patch when discord ships a new host version. skipped * on vesktop and equibop because they manage their own updates. */ if (!IS_VESKTOP && !IS_EQUIBOP) { try { require("./hostUpdateHook").installHostUpdateHook(); } catch (err) { console.error("[Equicord] Failed to install host update hook", err); } } if (process.platform === "win32" && !IS_VESKTOP && !IS_EQUIBOP) { /* before-quit fallback for the rare case the hook above never sees discord_desktop_core get required */ require("./patchWin32Updater"); } if (process.platform === "win32") { if (settings.winCtrlQ) { const originalBuild = Menu.buildFromTemplate; Menu.buildFromTemplate = function (template) { if (template[0]?.label === "&File") { const { submenu } = template[0]; if (Array.isArray(submenu)) { submenu.push({ label: "Quit (Hidden)", visible: false, acceleratorWorksWhenHidden: true, accelerator: "Control+Q", click: () => app.quit() }); } } return originalBuild.call(this, template); }; } } class BrowserWindow extends electron.BrowserWindow { constructor(options: BrowserWindowConstructorOptions) { if (!options?.webPreferences?.preload || !options.title) { super(options); return; } const { frameless, mainWindowFrameless, winNativeTitleBar, disableMinSize, transparent, macosVibrancyStyle, windowsMaterial } = settings; const original = options.webPreferences.preload; const isMainWindow = options.title === "Discord"; options.webPreferences.preload = join(__dirname, "preload.js"); options.webPreferences.sandbox = false; // work around discord unloading when in background options.webPreferences.backgroundThrottling = false; if (mainWindowFrameless && isMainWindow) { options.frame = false; } else if (frameless) { options.frame = false; } else if (process.platform === "win32" && winNativeTitleBar) { delete options.frame; } if (disableMinSize) { options.minWidth = 0; options.minHeight = 0; } if (transparent) { options.transparent = true; options.backgroundColor = "#00000000"; } if (process.platform === "darwin" && macosVibrancyStyle) { options.vibrancy = macosVibrancyStyle; options.backgroundColor = "#00000000"; } if (process.platform === "win32" && windowsMaterial && windowsMaterial !== "none") { options.backgroundMaterial = windowsMaterial; options.backgroundColor = "#00000000"; } process.env.DISCORD_PRELOAD = original; super(options); if (disableMinSize) { // Disable the Electron call entirely so that Discord can't dynamically change the size this.setMinimumSize = (_width: number, _height: number) => { }; } } } Object.assign(BrowserWindow, electron.BrowserWindow); // esbuild may rename our BrowserWindow, which leads to it being excluded // from getFocusedWindow(), so this is necessary // https://github.com/discord/electron/blob/13-x-y/lib/browser/api/browser-window.ts#L60-L62 Object.defineProperty(BrowserWindow, "name", { value: "BrowserWindow", configurable: true }); // Replace electrons exports with our custom BrowserWindow const electronPath = require.resolve("electron"); delete require.cache[electronPath]!.exports; require.cache[electronPath]!.exports = { ...electron, BrowserWindow }; // Patch appSettings to force enable devtools onceDefined(global, "appSettings", s => { s.set("DANGEROUS_ENABLE_DEVTOOLS_ONLY_ENABLE_IF_YOU_KNOW_WHAT_YOURE_DOING", true); }); process.env.DATA_DIR = join(app.getPath("userData"), "..", "Equicord"); // Monkey patch commandLine to: // - disable WidgetLayering: Fix DevTools context menus https://github.com/electron/electron/issues/38790 // - disable UseEcoQoSForBackgroundProcess: Work around Discord unloading when in background const originalAppend = app.commandLine.appendSwitch; app.commandLine.appendSwitch = function (...args) { if (args[0] === "disable-features") { const disabledFeatures = new Set((args[1] ?? "").split(",")); disabledFeatures.add("WidgetLayering"); disabledFeatures.add("UseEcoQoSForBackgroundProcess"); args[1] += [...disabledFeatures].join(","); } return originalAppend.apply(this, args); }; // 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 // Work around discord unloading when in background // Discord also recently started adding these flags but only on windows for some reason dunno why, it happens on Linux too app.commandLine.appendSwitch("disable-renderer-backgrounding"); app.commandLine.appendSwitch("disable-background-timer-throttling"); app.commandLine.appendSwitch("disable-backgrounding-occluded-windows"); } else { console.log("[Equicord] Running in vanilla mode. Not loading Equicord"); } console.log("[Equicord] Loading original Discord app.asar"); require(require.main!.filename);