Lightcord/modules/discord_desktop_core/core/app/mainScreen.js

981 lines
30 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getMainWindowId = getMainWindowId;
exports.webContentsSend = webContentsSend;
exports.init = init;
exports.handleOpenUrl = handleOpenUrl;
exports.setMainWindowVisible = setMainWindowVisible;
exports.setBlurType = setBlurType
exports.setVibrancy = setVibrancy
const events = exports.events = new (require("events").EventEmitter)()
const VIBRANCY_TYPES = [
"titlebar",
"selection",
"menu",
"popover",
"sidebar",
"header",
"sheet",
"window",
"hud",
"fullscreen-ui",
"tooltip",
"content",
"under-window",
"under-page",
"none"
]
const BLUR_TYPES = ["blurbehind", "acrylic", "transparent"]
var glasstron = require("glasstron")
var _electron = require("electron");
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _url = _interopRequireDefault(require("url"));
var _Backoff = _interopRequireDefault(require("../common/Backoff"));
var _securityUtils = require("../common/securityUtils");
var appBadge = _interopRequireWildcard(require("./appBadge"));
var appConfig = _interopRequireWildcard(require("./appConfig"));
var _appSettings = require("./appSettings");
var _buildInfo = _interopRequireDefault(require("./buildInfo"));
var _ipcMain = _interopRequireDefault(require("./ipcMain"));
var legacyModuleUpdater = _interopRequireWildcard(require("./moduleUpdater"));
var _updater = _interopRequireDefault(require("./updater"));
var notificationScreen = _interopRequireWildcard(require("./notificationScreen"));
var paths = _interopRequireWildcard(require("./paths"));
var popoutWindows = _interopRequireWildcard(require("./popoutWindows"));
var splashScreen = _interopRequireWildcard(require("./splashScreen"));
var systemTray = _interopRequireWildcard(require("./systemTray"));
var _Constants = require("./Constants");
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const settings = (0, _appSettings.getSettings)();
const connectionBackoff = new _Backoff.default(1000, 20000);
const DISCORD_NAMESPACE = 'DISCORD_';
let isTabs = false
const getWebappEndpoint = () => {
isTabs = settings.get("isTabs", false)
if(!isTabs){
let endpoint = settings.get('WEBAPP_ENDPOINT');
if (!endpoint) {
if (_buildInfo.default.releaseChannel === 'stable') {
endpoint = 'https://discord.com';
} else if (_buildInfo.default.releaseChannel === 'development') {
endpoint = 'https://canary.discord.com';
} else {
endpoint = `https://${_buildInfo.default.releaseChannel}.discord.com`;
}
}
return endpoint;
}else{
return "file://"+_path.default.join(__dirname, "tabs", "index.html")
}
};
const WEBAPP_ENDPOINT = getWebappEndpoint();
function checkUrlOriginMatches(urlA, urlB) {
let parsedUrlA;
let parsedUrlB;
try {
parsedUrlA = _url.default.parse(urlA);
parsedUrlB = _url.default.parse(urlB);
} catch (_) {
return false;
}
return parsedUrlA.protocol === parsedUrlB.protocol && parsedUrlA.slashes === parsedUrlB.slashes && parsedUrlA.host === parsedUrlB.host;
}
function getSanitizedPath(path) {
// using the whatwg URL api, get a sanitized pathname from given path
// this is because url.parse's `path` may not always have a slash
// in front of it
return new _url.default.URL(path, WEBAPP_ENDPOINT).pathname;
}
function getSanitizedProtocolPath(url_) {
try {
const parsedURL = _url.default.parse(url_);
if (parsedURL.protocol === 'discord:') {
return getSanitizedPath(parsedURL.path);
}
} catch (_) {} // protect against URIError: URI malformed
return null;
} // TODO: These should probably be thrown in constants.
const WEBAPP_PATH = settings.get('WEBAPP_PATH', `/app?_=${Date.now()}`);
const URL_TO_LOAD = `${WEBAPP_ENDPOINT}${WEBAPP_PATH}`;
const MIN_WIDTH = settings.get('MIN_WIDTH', 940);
const MIN_HEIGHT = settings.get('MIN_HEIGHT', 500);
const DEFAULT_WIDTH = 1280;
const DEFAULT_HEIGHT = 720; // TODO: document this var's purpose
const MIN_VISIBLE_ON_SCREEN = 32;
let mainWindow = null;
let mainWindowId = _Constants.DEFAULT_MAIN_WINDOW_ID;
let mainWindowInitialPath = null;
let mainWindowDidFinishLoad = false; // whether we are in an intermediate auth process outside of our normal login screen (for e.g. internal builds)
let insideAuthFlow = false; // last time the main app renderer has crashed ('crashed' event)
let lastCrashed = 0; // whether we failed to load a page outside of the intermediate auth flow
// used to reload the page after a delay
let lastPageLoadFailed = false;
function getMainWindowId() {
return mainWindowId;
}
function webContentsSend(...args) {
if (mainWindow != null && mainWindow.webContents != null) {
const [event, ...options] = args;
mainWindow.webContents.send(`${DISCORD_NAMESPACE}${event}`, ...options);
}
}
function saveWindowConfig(browserWindow) {
try {
if (!browserWindow) {
return;
}
if(settings.get("NO_WINDOWS_BOUND"))return
settings.set('IS_MAXIMIZED', browserWindow.isMaximized());
settings.set('IS_MINIMIZED', browserWindow.isMinimized());
if (!settings.get('IS_MAXIMIZED') && !settings.get('IS_MINIMIZED')) {
settings.set('WINDOW_BOUNDS', browserWindow.getBounds());
}
settings.save();
} catch (e) {
console.error(e);
}
}
function setBlur(blur){
if(!mainWindow)return
if(typeof blur !== "boolean")throw new TypeError("INVALID ARGUMENT: blur")
mainWindow.setBlur(blur)
}
function setVibrancy(vibrancy){
if(!mainWindow)return
if(!VIBRANCY_TYPES.includes(vibrancy))throw new TypeError("INVALID ARGUMENT: vibrancy")
mainWindow.setVibrancy(vibrancy)
settings.set("GLASSTRON_VIBRANCY", vibrancy)
}
function setBlurType(blurType){
if(!mainWindow)return
if(!BLUR_TYPES.includes(blurType))throw new TypeError("INVALID ARGUMENT: blurType")
mainWindow.blurType = blurType
settings.set("GLASSTRON_BLUR", blurType)
}
function setDefaultBlur(){
if(!mainWindow)return
let blurType = settings.get("GLASSTRON_BLUR", "blurbehind")
if(!BLUR_TYPES.includes(blurType)){
blurType = "blurbehind"
settings.set("GLASSTRON_BLUR", blurType)
}
setBlurType(blurType)
let vibrancy = settings.get("GLASSTRON_VIBRANCY", "fullscreen-ui")
if(!VIBRANCY_TYPES.includes(vibrancy)){
vibrancy = "fullscreen-ui"
settings.set("GLASSTRON_VIBRANCY", vibrancy)
}
setVibrancy(vibrancy)
setBlur(true)
}
function setWindowVisible(isVisible, andUnminimize) {
if (mainWindow == null) {
return;
}
if (isVisible) {
if (andUnminimize || !mainWindow.isMinimized()) {
mainWindow.show();
webContentsSend('MAIN_WINDOW_FOCUS');
}
} else {
webContentsSend('MAIN_WINDOW_BLUR');
mainWindow.hide();
if (systemTray.hasInit) {
systemTray.displayHowToCloseHint();
}
}
mainWindow.setSkipTaskbar(!isVisible);
}
function doAABBsOverlap(a, b) {
const ax1 = a.x + a.width;
const bx1 = b.x + b.width;
const ay1 = a.y + a.height;
const by1 = b.y + b.height; // clamp a to b, see if it is non-empty
const cx0 = a.x < b.x ? b.x : a.x;
const cx1 = ax1 < bx1 ? ax1 : bx1;
if (cx1 - cx0 > 0) {
const cy0 = a.y < b.y ? b.y : a.y;
const cy1 = ay1 < by1 ? ay1 : by1;
if (cy1 - cy0 > 0) {
return true;
}
}
return false;
}
function applyWindowBoundsToConfig(mainWindowOptions) {
if (!settings.get('WINDOW_BOUNDS')) {
mainWindowOptions.center = true;
return;
}
const bounds = settings.get('WINDOW_BOUNDS');
bounds.width = Math.max(MIN_WIDTH, bounds.width);
bounds.height = Math.max(MIN_HEIGHT, bounds.height);
let isVisibleOnAnyScreen = false;
const displays = _electron.screen.getAllDisplays();
displays.forEach(display => {
if (isVisibleOnAnyScreen) {
return;
}
const displayBound = display.workArea;
displayBound.x += MIN_VISIBLE_ON_SCREEN;
displayBound.y += MIN_VISIBLE_ON_SCREEN;
displayBound.width -= 2 * MIN_VISIBLE_ON_SCREEN;
displayBound.height -= 2 * MIN_VISIBLE_ON_SCREEN;
isVisibleOnAnyScreen = doAABBsOverlap(bounds, displayBound);
});
if (isVisibleOnAnyScreen) {
mainWindowOptions.width = bounds.width;
mainWindowOptions.height = bounds.height;
mainWindowOptions.x = bounds.x;
mainWindowOptions.y = bounds.y;
} else {
mainWindowOptions.center = true;
}
} // this can be called multiple times (due to recreating the main app window),
// so we only want to update existing if we already initialized it
function setupNotificationScreen(mainWindow) {
if (!notificationScreen.hasInit) {
notificationScreen.init({
mainWindow,
title: 'Lightcord Notifications',
maxVisible: 5,
screenPosition: 'bottom'
});
notificationScreen.events.on(notificationScreen.NOTIFICATION_CLICK, () => {
setWindowVisible(true, true);
});
} else {
notificationScreen.setMainWindow(mainWindow);
}
} // this can be called multiple times (due to recreating the main app window),
// so we only want to update existing if we already initialized it
function setupSystemTray() {
if (!systemTray.hasInit) {
systemTray.init({
onCheckForUpdates: () => {
const updater = _updater.default === null || _updater.default === void 0 ? void 0 : _updater.default.getUpdater();
if (updater != null) {
checkForUpdatesWithUpdater(updater);
} else {
legacyModuleUpdater.checkForUpdates();
}
},
onTrayClicked: () => setWindowVisible(true, true),
onOpenVoiceSettings: openVoiceSettings,
onToggleMute: toggleMute,
onToggleDeafen: toggleDeafen,
onLaunchApplication: launchApplication
});
}
} // this can be called multiple times (due to recreating the main app window),
// so we only want to update existing if we already initialized it
function setupAppBadge() {
if (!appBadge.hasInit) {
appBadge.init();
}
} // this can be called multiple times (due to recreating the main app window),
// so we only want to update existing if we already initialized it
function setupAppConfig() {
if (!appConfig.hasInit) {
appConfig.init();
}
} // this can be called multiple times (due to recreating the main app window),
// so we only want to update existing if we already initialized it
function setupPopouts() {
if (!popoutWindows.hasInit) {
popoutWindows.init();
}
}
function openVoiceSettings() {
setWindowVisible(true, true);
webContentsSend('SYSTEM_TRAY_OPEN_VOICE_SETTINGS');
}
function toggleMute() {
webContentsSend('SYSTEM_TRAY_TOGGLE_MUTE');
}
function toggleDeafen() {
webContentsSend('SYSTEM_TRAY_TOGGLE_DEAFEN');
}
function launchApplication(applicationId) {
webContentsSend('LAUNCH_APPLICATION', applicationId);
}
const loadMainPage = () => {
lastPageLoadFailed = false;
mainWindow.loadURL(URL_TO_LOAD);
};
const DEFAULT_BACKGROUND_COLOR = '#2f3136';
const BACKGROUND_COLOR_KEY = 'BACKGROUND_COLOR';
function getBackgroundColor() {
return settings.get(BACKGROUND_COLOR_KEY, DEFAULT_BACKGROUND_COLOR);
}
function setBackgroundColor(color) {
settings.set(BACKGROUND_COLOR_KEY, color);
//mainWindow.setBackgroundColor(color);
settings.save();
} // launch main app window; could be called multiple times for various reasons
function launchMainAppWindow(isVisible) {
if (mainWindow) {
// TODO: message here?
mainWindow.destroy();
}
const mainWindowOptions = {
title: 'Lightcord',
width: DEFAULT_WIDTH,
height: DEFAULT_HEIGHT,
minWidth: MIN_WIDTH,
minHeight: MIN_HEIGHT,
transparent: false,
frame: false,
resizable: true,
show: isVisible,
webPreferences: {
blinkFeatures: 'EnumerateDevices,AudioOutputDevices',
nativeWindowOpen: true,
enableRemoteModule: true,
spellcheck: true,
contextIsolation: false,
...(isTabs ? {
nodeIntegration: true,
webviewTag: true
} : {
nodeIntegration: false,
webviewTag: false,
contextIsolation: false,
preload: _path.default.join(__dirname, 'mainScreenPreload.js')
}),
// NB: this is required in order to give popouts (or any child window opened via window.open w/ nativeWindowOpen)
// a chance at a node environment (i.e. they run the preload, have an isolated context, etc.) when
// `app.allowRendererProcessReuse === false` (default in Electron 7).
additionalArguments: ['--enable-node-leakage-in-renderers']
},
icon: _path.default.join(__dirname, "images", 'discord.png')
};
if (process.platform === 'linux') {
mainWindowOptions.frame = true;
}
if(!settings.get("NO_WINDOWS_BOUND", false))applyWindowBoundsToConfig(mainWindowOptions);
const useGlasstron = settings.get("GLASSTRON", true)
const BrowserWindow = useGlasstron ? glasstron.BrowserWindow : _electron.BrowserWindow
mainWindow = new BrowserWindow(mainWindowOptions);
mainWindowId = mainWindow.id;
global.mainWindowId = mainWindowId;
if(useGlasstron)setDefaultBlur()
mainWindow.webContents.session.webRequest.onHeadersReceived(function(details, callback) {
if (!details.responseHeaders["content-security-policy-report-only"] && !details.responseHeaders["content-security-policy"]) return callback({cancel: false});
delete details.responseHeaders["content-security-policy-report-only"];
delete details.responseHeaders["content-security-policy"];
callback({cancel: false, responseHeaders: details.responseHeaders});
});
mainWindow.setMenuBarVisibility(false);
if(!settings.get("NO_WINDOWS_BOUND", false)){
if (settings.get('IS_MAXIMIZED')) {
mainWindow.maximize();
}
if (settings.get('IS_MINIMIZED')) {
mainWindow.minimize();
}
}
mainWindow.webContents.on('new-window', (e, windowURL, frameName, disposition, options) => {
e.preventDefault();
if (frameName.startsWith(DISCORD_NAMESPACE) && checkUrlOriginMatches(windowURL, WEBAPP_ENDPOINT) && getSanitizedPath(windowURL) === '/popout') {
popoutWindows.openOrFocusWindow(e, windowURL, frameName, options);
return;
}
(0, _securityUtils.saferShellOpenExternal)(windowURL);
});
mainWindow.webContents.on('did-fail-load', (e, errCode, errDesc, validatedUrl) => {
if (insideAuthFlow) {
return;
}
if (validatedUrl !== URL_TO_LOAD) {
return;
} // -3 (ABORTED) means we are reloading the page before it has finished loading
// 0 (???) seems to also mean the same thing
if (errCode === -3 || errCode === 0) return;
lastPageLoadFailed = true;
console.error('[WebContents] did-fail-load', errCode, errDesc, `retry in ${connectionBackoff.current} ms`);
connectionBackoff.fail(() => {
console.log('[WebContents] retrying load', URL_TO_LOAD);
loadMainPage();
});
});
mainWindow.webContents.on('did-finish-load', () => {
if (insideAuthFlow && mainWindow.webContents && checkUrlOriginMatches(mainWindow.webContents.getURL(), WEBAPP_ENDPOINT)) {
insideAuthFlow = false;
}
mainWindowDidFinishLoad = true; // if this is a first open and there's an initial path, direct user to that path
if (mainWindowInitialPath != null) {
webContentsSend('MAIN_WINDOW_PATH', mainWindowInitialPath);
mainWindowInitialPath = null;
}
webContentsSend(mainWindow != null && mainWindow.isFocused() ? 'MAIN_WINDOW_FOCUS' : 'MAIN_WINDOW_BLUR');
if (!lastPageLoadFailed) {
connectionBackoff.succeed();
}
events.emit("ready")
});
mainWindow.webContents.on('crashed', (e, killed) => {
if (killed) {
_electron.app.quit();
return;
} // if we just crashed under 5 seconds ago, we are probably in a loop, so just die.
const crashTime = Date.now();
if (crashTime - lastCrashed < 5 * 1000) {
console.error('[WebContents] double crashed... RIP =(');
_electron.app.quit();
return;
}
lastCrashed = crashTime;
console.error('[WebContents] crashed... reloading');
launchMainAppWindow(true);
}); // Prevent navigation when links or files are dropping into the app, turning it into a browser.
// https://github.com/discord/discord/pull/278
mainWindow.webContents.on('will-navigate', (evt, url) => {
if (!insideAuthFlow && !checkUrlOriginMatches(url, WEBAPP_ENDPOINT)) {
evt.preventDefault();
}
}); // track intermediate auth flow
mainWindow.webContents.on('did-get-redirect-request', (event, oldUrl, newUrl) => {
if (checkUrlOriginMatches(oldUrl, WEBAPP_ENDPOINT) && checkUrlOriginMatches(newUrl, 'https://accounts.google.com/')) {
insideAuthFlow = true;
}
});
mainWindow.webContents.on('context-menu', (_, params) => {
webContentsSend('SPELLCHECK_RESULT', params.misspelledWord, params.dictionarySuggestions);
});
mainWindow.webContents.on('devtools-opened', () => {
webContentsSend('WINDOW_DEVTOOLS_OPENED');
});
mainWindow.webContents.on('devtools-closed', () => {
webContentsSend('WINDOW_DEVTOOLS_CLOSED');
});
mainWindow.on('focus', () => {
webContentsSend('MAIN_WINDOW_FOCUS');
});
mainWindow.on('blur', () => {
webContentsSend('MAIN_WINDOW_BLUR');
});
mainWindow.on('page-title-updated', (e, title) => {
if (mainWindow === null) {
return;
}
e.preventDefault();
if (!title.endsWith('Lightcord')) {
title += ' - Lightcord';
}
mainWindow.setTitle(title);
});
mainWindow.on('leave-html-full-screen', () => {
// fixes a bug wherein embedded videos returning from full screen cause our menu to be visible.
mainWindow.setMenuBarVisibility(false);
});
mainWindow.webContents.on('did-navigate-in-page', (_, eventUrl) => {
let parsedUrl;
try {
parsedUrl = _url.default.parse(eventUrl);
} catch (_) {
return;
} // Prevent back navigation from revisting the login page after logging in,
// or being able to navigate back after signing out.
if (parsedUrl && parsedUrl.pathname === '/login') {
mainWindow.webContents.clearHistory();
}
}); // 'swipe' only works if the classic 3 finger swipe style is enabled in
// 'System Preferences > Trackpad > More Gestures.' The more modern 2 finger
// gesture should be added when Electron adds support.
mainWindow.on('swipe', (_, direction) => {
switch (direction) {
case 'left':
webContentsSend('NAVIGATE_BACK', 'SWIPE');
break;
case 'right':
webContentsSend('NAVIGATE_FORWARD', 'SWIPE');
break;
}
}); // Windows/Linux media keys and 4th/5th mouse buttons.
mainWindow.on('app-command', (_, cmd) => {
switch (cmd) {
case 'browser-backward':
webContentsSend('NAVIGATE_BACK', 'BROWSER');
break;
case 'browser-forward':
webContentsSend('NAVIGATE_FORWARD', 'BROWSER');
break;
}
});
if (process.platform === 'win32') {
setupNotificationScreen(mainWindow);
}
setupSystemTray();
setupAppBadge();
setupAppConfig();
setupPopouts();
if (process.platform === 'linux' || process.platform === 'win32') {
systemTray.show();
mainWindow.on('close', e => {
if (mainWindow === null) {
// this means we're quitting
popoutWindows.closePopouts();
return;
}
webContentsSend('MAIN_WINDOW_BLUR'); // Save our app settings
saveWindowConfig(mainWindow); // Quit app if that's the setting
if (!settings.get('MINIMIZE_TO_TRAY', true)) {
_electron.app.quit();
return;
} // Else, minimize to tray
setWindowVisible(false);
e.preventDefault();
});
}
loadMainPage();
}
let updaterState = _Constants.UpdaterEvents.UPDATE_NOT_AVAILABLE;
function handleModuleUpdateCheckFinished(succeeded, updateCount, manualRequired) {
if (!succeeded) {
updaterState = _Constants.UpdaterEvents.UPDATE_NOT_AVAILABLE;
webContentsSend(_Constants.UpdaterEvents.UPDATE_ERROR);
return;
}
if (updateCount === 0) {
updaterState = _Constants.UpdaterEvents.UPDATE_NOT_AVAILABLE;
} else if (manualRequired) {
updaterState = _Constants.UpdaterEvents.UPDATE_MANUALLY;
} else {
updaterState = _Constants.UpdaterEvents.UPDATE_AVAILABLE;
}
webContentsSend(updaterState);
}
function handleModuleUpdateDownloadProgress(name, progress) {
if (mainWindow) {
mainWindow.setProgressBar(progress);
}
webContentsSend(_Constants.UpdaterEvents.MODULE_INSTALL_PROGRESS, name, progress);
}
function handleModuleUpdateDownloadsFinished(succeeded, failed) {
if (mainWindow) {
mainWindow.setProgressBar(-1);
}
if (updaterState === _Constants.UpdaterEvents.UPDATE_AVAILABLE) {
if (failed > 0) {
updaterState = _Constants.UpdaterEvents.UPDATE_NOT_AVAILABLE;
webContentsSend(_Constants.UpdaterEvents.UPDATE_ERROR);
} else {
updaterState = _Constants.UpdaterEvents.UPDATE_DOWNLOADED;
webContentsSend(updaterState);
}
}
}
function handleModuleUpdateInstalledModule(name, current, total, succeeded) {
if (mainWindow) {
mainWindow.setProgressBar(-1);
}
webContentsSend(_Constants.UpdaterEvents.MODULE_INSTALLED, name, succeeded);
}
function setUpdaterState(newUpdaterState) {
updaterState = newUpdaterState;
webContentsSend(updaterState);
}
async function checkForUpdatesWithUpdater(updater) {
if (updaterState === _Constants.UpdaterEvents.UPDATE_NOT_AVAILABLE) {
setUpdaterState(_Constants.UpdaterEvents.CHECKING_FOR_UPDATES);
try {
let installedAnything = false;
await updater.updateToLatest(progress => {
const task = progress.task.HostInstall || progress.task.ModuleInstall;
if (task != null && progress.state === 'Complete') {
if (!installedAnything) {
installedAnything = true;
setUpdaterState(_Constants.UpdaterEvents.UPDATE_AVAILABLE);
}
}
});
setUpdaterState(installedAnything ? _Constants.UpdaterEvents.UPDATE_DOWNLOADED : _Constants.UpdaterEvents.UPDATE_NOT_AVAILABLE);
} catch (e) {
console.error('Update to latest failed: ', e);
updaterState = _Constants.UpdaterEvents.UPDATE_NOT_AVAILABLE;
webContentsSend(_Constants.UpdaterEvents.UPDATE_FAILED);
}
} else {
webContentsSend(updaterState);
}
} // Setup handling of events related to updates using the new updater.
function setupUpdaterEventsWithUpdater(updater) {
_electron.app.on(_Constants.MenuEvents.CHECK_FOR_UPDATES, () => checkForUpdatesWithUpdater());
_ipcMain.default.on(_Constants.UpdaterEvents.CHECK_FOR_UPDATES, () => {
return checkForUpdatesWithUpdater(updater);
});
_ipcMain.default.on(_Constants.UpdaterEvents.QUIT_AND_INSTALL, () => {
saveWindowConfig(mainWindow);
mainWindow = null; // TODO(eiz): This is a workaround for old Linux host versions whose host
// updater did not have a quitAndInstall() method, which causes the module
// updater to crash if a host update is available and we try to restart to
// install modules. Remove when all hosts are updated.
try {
legacyModuleUpdater.quitAndInstallUpdates();
} catch (e) {
_electron.app.relaunch();
_electron.app.quit();
}
});
_ipcMain.default.on(_Constants.UpdaterEvents.UPDATER_HISTORY_QUERY_AND_TRUNCATE, () => {
if (updater.queryAndTruncateHistory != null) {
webContentsSend(_Constants.UpdaterEvents.UPDATER_HISTORY_RESPONSE, updater.queryAndTruncateHistory());
} else {
webContentsSend(_Constants.UpdaterEvents.UPDATER_HISTORY_RESPONSE, []);
}
});
} // Setup events related to updates using the old module updater.
//
// sets up event listeners between the browser window and the app to send
// and listen to update-related events
function setupLegacyUpdaterEvents() {
_electron.app.on(_Constants.MenuEvents.CHECK_FOR_UPDATES, () => legacyModuleUpdater.checkForUpdates());
legacyModuleUpdater.events.on(legacyModuleUpdater.CHECKING_FOR_UPDATES, () => {
updaterState = _Constants.UpdaterEvents.CHECKING_FOR_UPDATES;
webContentsSend(updaterState);
}); // TODO(eiz): We currently still need to handle the old style non-object-based
// updater events to allow discord_desktop_core to be newer than the host asar,
// which contains the updater itself.
//
// Once all clients have updated to a sufficiently new host, we can delete this.
if (legacyModuleUpdater.supportsEventObjects) {
legacyModuleUpdater.events.on(legacyModuleUpdater.UPDATE_CHECK_FINISHED, ({
succeeded,
updateCount,
manualRequired
}) => {
handleModuleUpdateCheckFinished(succeeded, updateCount, manualRequired);
});
legacyModuleUpdater.events.on(legacyModuleUpdater.DOWNLOADING_MODULE_PROGRESS, ({
name,
progress
}) => {
handleModuleUpdateDownloadProgress(name, progress);
});
legacyModuleUpdater.events.on(legacyModuleUpdater.DOWNLOADING_MODULES_FINISHED, ({
succeeded,
failed
}) => {
handleModuleUpdateDownloadsFinished(succeeded, failed);
});
legacyModuleUpdater.events.on(legacyModuleUpdater.INSTALLED_MODULE, ({
name,
current,
total,
succeeded
}) => {
handleModuleUpdateInstalledModule(name, current, total, succeeded);
});
} else {
legacyModuleUpdater.events.on(legacyModuleUpdater.UPDATE_CHECK_FINISHED, (succeeded, updateCount, manualRequired) => {
handleModuleUpdateCheckFinished(succeeded, updateCount, manualRequired);
});
legacyModuleUpdater.events.on(legacyModuleUpdater.DOWNLOADING_MODULE_PROGRESS, (name, progress) => {
handleModuleUpdateDownloadProgress(name, progress);
});
legacyModuleUpdater.events.on(legacyModuleUpdater.DOWNLOADING_MODULES_FINISHED, (succeeded, failed) => {
handleModuleUpdateDownloadsFinished(succeeded, failed);
});
legacyModuleUpdater.events.on(legacyModuleUpdater.INSTALLED_MODULE, (name, current, total, succeeded) => {
handleModuleUpdateInstalledModule(name, current, total, succeeded);
});
}
_ipcMain.default.on(_Constants.UpdaterEvents.CHECK_FOR_UPDATES, () => {
if (updaterState === _Constants.UpdaterEvents.UPDATE_NOT_AVAILABLE) {
legacyModuleUpdater.checkForUpdates();
} else {
webContentsSend(updaterState);
}
});
_ipcMain.default.on(_Constants.UpdaterEvents.QUIT_AND_INSTALL, () => {
saveWindowConfig(mainWindow);
mainWindow = null; // TODO(eiz): This is a workaround for old Linux host versions whose host
// updater did not have a quitAndInstall() method, which causes the module
// updater to crash if a host update is available and we try to restart to
// install modules. Remove when all hosts are updated.
try {
legacyModuleUpdater.quitAndInstallUpdates();
} catch (e) {
_electron.app.relaunch();
_electron.app.quit();
}
});
_ipcMain.default.on(_Constants.UpdaterEvents.MODULE_INSTALL, (_event, name) => {
// NOTE: do NOT allow options to be passed in, as this enables a client to downgrade its modules to potentially
// insecure versions.
legacyModuleUpdater.install(name, false);
});
_ipcMain.default.on(_Constants.UpdaterEvents.MODULE_QUERY, (_event, name) => {
webContentsSend(_Constants.UpdaterEvents.MODULE_INSTALLED, name, legacyModuleUpdater.isInstalled(name));
});
_ipcMain.default.on(_Constants.UpdaterEvents.UPDATER_HISTORY_QUERY_AND_TRUNCATE, () => {
webContentsSend(_Constants.UpdaterEvents.UPDATER_HISTORY_RESPONSE, legacyModuleUpdater.events.history);
legacyModuleUpdater.events.history = [];
});
}
function init() {
// electron default behavior is to app.quit here, so long as there are no other listeners. we handle quitting
// or minimizing to system tray ourselves via mainWindow.on('closed') so this is simply to disable the electron
// default behavior.
_electron.app.on('window-all-closed', () => {});
_electron.app.on('before-quit', () => {
saveWindowConfig(mainWindow);
mainWindow = null;
notificationScreen.close();
}); // TODO: move this to main startup
_electron.app.on('gpu-process-crashed', (e, killed) => {
if (killed) {
_electron.app.quit();
}
});
_electron.app.on('accessibility-support-changed', (_event, accessibilitySupportEnabled) => webContentsSend('ACCESSIBILITY_SUPPORT_CHANGED', accessibilitySupportEnabled));
_electron.app.on(_Constants.MenuEvents.OPEN_HELP, () => webContentsSend('HELP_OPEN'));
_electron.app.on(_Constants.MenuEvents.OPEN_SETTINGS, () => webContentsSend('USER_SETTINGS_OPEN')); // TODO: this hotpatches an issue with focusing the app from background.
// delete this after next stable electron release.
_electron.app.on('second-instance', (_event, args) => {
// if the second instance is the uninstaller, the bootstrap listener will quit the running app
if (args != null && args.indexOf('--squirrel-uninstall') > -1) {
return;
} // if the current instance is multi instance, we want to leave the window alone
if (process.argv != null && process.argv.slice(1).includes('--multi-instance')) {
return;
}
if (mainWindow == null) {
return;
}
setWindowVisible(true, false);
mainWindow.focus();
});
_ipcMain.default.on('SETTINGS_UPDATE_BACKGROUND_COLOR', (_event, backgroundColor) => {
if (getBackgroundColor() !== backgroundColor) {
setBackgroundColor(backgroundColor);
}
});
const updater = _updater.default === null || _updater.default === void 0 ? void 0 : _updater.default.getUpdater();
if (updater != null) {
setupUpdaterEventsWithUpdater(updater);
} else {
setupLegacyUpdaterEvents();
}
launchMainAppWindow(false);
}
function handleOpenUrl(url) {
const path = getSanitizedProtocolPath(url);
if (path != null) {
if (!mainWindowDidFinishLoad) {
mainWindowInitialPath = path;
}
webContentsSend('MAIN_WINDOW_PATH', path);
}
if (mainWindow == null) {
return;
}
setWindowVisible(true, false);
mainWindow.focus();
}
function setMainWindowVisible(visible) {
setWindowVisible(visible, false);
}