diff --git a/apps/desktop/src/app/app.component.ts b/apps/desktop/src/app/app.component.ts index d3829d4e63..320c93a05e 100644 --- a/apps/desktop/src/app/app.component.ts +++ b/apps/desktop/src/app/app.component.ts @@ -10,6 +10,7 @@ import { } from "@angular/core"; import { DomSanitizer } from "@angular/platform-browser"; import { Router } from "@angular/router"; +import { ipcRenderer } from "electron"; import { IndividualConfig, ToastrService } from "ngx-toastr"; import { firstValueFrom, Subject, takeUntil } from "rxjs"; @@ -221,7 +222,7 @@ export class AppComponent implements OnInit, OnDestroy { this.systemService.cancelProcessReload(); break; case "reloadProcess": - (window.location as any).reload(true); + ipcRenderer.send("reload-process"); break; case "syncStarted": break; diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index 9dfcd9776a..9f15d0d24d 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -98,6 +98,7 @@ export class Main { this.windowMain = new WindowMain( this.stateService, this.logService, + this.storageService, (arg) => this.processDeepLink(arg), (win) => this.trayMain.setupWindowListeners(win) ); diff --git a/apps/desktop/src/main/window.main.ts b/apps/desktop/src/main/window.main.ts index 5e976bb93c..6faac0c684 100644 --- a/apps/desktop/src/main/window.main.ts +++ b/apps/desktop/src/main/window.main.ts @@ -1,11 +1,13 @@ +import { once } from "node:events"; import * as path from "path"; import * as url from "url"; -import { app, BrowserWindow, screen } from "electron"; +import { app, BrowserWindow, ipcMain, nativeTheme, screen, session } from "electron"; import { WindowState } from "@bitwarden/common/models/domain/window-state"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; +import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service"; import { cleanUserAgent, isDev, isMacAppStore, isSnapStore } from "../utils"; @@ -19,6 +21,7 @@ export class WindowMain { private windowStateChangeTimer: NodeJS.Timer; private windowStates: { [key: string]: WindowState } = {}; private enableAlwaysOnTop = false; + private session: Electron.Session; readonly defaultWidth = 950; readonly defaultHeight = 600; @@ -26,11 +29,26 @@ export class WindowMain { constructor( private stateService: StateService, private logService: LogService, + private storageService: AbstractStorageService, private argvCallback: (argv: string[]) => void = null, private createWindowCallback: (win: BrowserWindow) => void ) {} init(): Promise { + // Perform a hard reload of the render process by crashing it. This is suboptimal but ensures that all memory gets + // cleared, as the process itself will be completely garbage collected. + ipcMain.on("reload-process", async () => { + // User might have changed theme, ensure the window is updated. + this.win.setBackgroundColor(await this.getBackgroundColor()); + + const crashEvent = once(this.win.webContents, "render-process-gone"); + this.win.webContents.forcefullyCrashRenderer(); + await crashEvent; + + this.win.webContents.reloadIgnoringCache(); + this.session.clearCache(); + }); + return new Promise((resolve, reject) => { try { if (!isMacAppStore() && !isSnapStore()) { @@ -108,6 +126,8 @@ export class WindowMain { ); this.enableAlwaysOnTop = await this.stateService.getEnableAlwaysOnTop(); + this.session = session.fromPartition("persist:bitwarden", { cache: false }); + // Create the browser window. this.win = new BrowserWindow({ width: this.windowStates[mainWindowSizeKey].width, @@ -120,13 +140,14 @@ export class WindowMain { icon: process.platform === "linux" ? path.join(__dirname, "/images/icon.png") : undefined, titleBarStyle: process.platform === "darwin" ? "hiddenInset" : undefined, show: false, - backgroundColor: "#fff", + backgroundColor: await this.getBackgroundColor(), alwaysOnTop: this.enableAlwaysOnTop, webPreferences: { spellcheck: false, nodeIntegration: true, backgroundThrottling: false, contextIsolation: false, + session: this.session, }, }); @@ -201,6 +222,26 @@ export class WindowMain { } } + // Retrieve the background color + // Resolves background color missmatch when starting the application. + async getBackgroundColor(): Promise { + const data: { theme?: string } = await this.storageService.get("global"); + let theme = data?.theme; + + if (theme == null || theme === "system") { + theme = nativeTheme.shouldUseDarkColors ? "dark" : "light"; + } + + switch (theme) { + case "light": + return "#ededed"; + case "dark": + return "#222222"; + case "nord": + return "#3b4252"; + } + } + async toggleAlwaysOnTop() { this.enableAlwaysOnTop = !this.win.isAlwaysOnTop(); this.win.setAlwaysOnTop(this.enableAlwaysOnTop); diff --git a/apps/desktop/src/scss/base.scss b/apps/desktop/src/scss/base.scss index 1a2eddca68..31be3f1bcc 100644 --- a/apps/desktop/src/scss/base.scss +++ b/apps/desktop/src/scss/base.scss @@ -16,7 +16,10 @@ body { body { color: $text-color; - background-color: $background-color-alt2; + + // We initially rely on electron to provide the appropiate background color. + // This ensures the background color while reloading is correct to avoid a jarring missmatch. + background-color: transparent; @include themify($themes) { color: themed("textColor"); diff --git a/apps/desktop/src/scss/variables.scss b/apps/desktop/src/scss/variables.scss index 65f1e6b2e9..439eff2f2f 100644 --- a/apps/desktop/src/scss/variables.scss +++ b/apps/desktop/src/scss/variables.scss @@ -28,7 +28,7 @@ $brand-primary-accent: #1252a3; $background-color: white; $background-color-alt: #f9f9f9; -$background-color-alt2: #ededed; +$background-color-alt2: #ededed; // Ensure the `window.main.ts` is updated with this value $box-background-color: $background-color; $box-background-hover-color: $list-item-hover; @@ -50,6 +50,7 @@ $themes: ( backgroundColor: $background-color, borderColorAlt: $border-color-alt, backgroundColorAlt: $background-color-alt, + // Ensure the `window.main.ts` is updated with this value backgroundColorAlt2: $background-color-alt2, scrollbarColor: rgba(100, 100, 100, 0.2), scrollbarHoverColor: rgba(100, 100, 100, 0.4), @@ -107,6 +108,7 @@ $themes: ( backgroundColor: #363636, borderColorAlt: #6e788a, backgroundColorAlt: #3d3d3d, + // Ensure the `window.main.ts` is updated with this value backgroundColorAlt2: #222222, scrollbarColor: #4d4d4d, scrollbarHoverColor: #5f5f5f, @@ -164,6 +166,7 @@ $themes: ( backgroundColor: $nord2, borderColorAlt: $nord5, backgroundColorAlt: $nord1, + // Ensure the `window.main.ts` is updated with this value backgroundColorAlt2: $nord1, scrollbarColor: $nord4, scrollbarHoverColor: $nord6,