Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add transparency option #540

Open
wants to merge 49 commits into
base: v4.9.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
b166253
Add transparent window feature
EastArctica Jul 22, 2023
69e56ba
Merge branch 'replugged-org:main' into transparency-button
EastArctica Aug 4, 2023
7f3ae10
Merge 'upstream/main' into transparency-button
EastArctica Aug 22, 2023
0fb2d3b
Require discord restart for transparency change
EastArctica Aug 22, 2023
71a57e8
Move transparency button
EastArctica Aug 22, 2023
895e002
move readSettingsSync to src/util.mts
EastArctica Aug 22, 2023
d47630a
Merge branch 'v4.7.0' into transparency-button
asportnoy Aug 23, 2023
27e0e9f
At platform specific notices
EastArctica Aug 23, 2023
db444eb
Fix transparency on Windows
EastArctica Aug 23, 2023
45955b0
Merge branch 'v4.7.0' into pr/540/transparency-button
asportnoy Aug 24, 2023
4846af3
BrowserWindow rework
EastArctica Aug 25, 2023
c528f00
MacOS Auto-Maximize
EastArctica Aug 25, 2023
d3f01c5
Merge branch 'transparency-button' of https://github.com/EastArctica/…
EastArctica Aug 25, 2023
d4b4bf1
Merge upstream/main
EastArctica Sep 9, 2023
f496111
Add transparent window feature
EastArctica Jul 22, 2023
9136954
Merge branch 'v4.8.0' into transparency-button
EastArctica Jan 31, 2024
f57657a
I'm impressively bad at rebasing
EastArctica Jan 31, 2024
f0b6a47
Add vibe for transparency
EastArctica Feb 4, 2024
8212850
Merge branch 'main' of https://github.com/replugged-org/replugged int…
EastArctica Feb 4, 2024
ff9b4cc
Use unified acrylic and auto set theme + background color
EastArctica Feb 10, 2024
9a76a78
Merge remote-tracking branch 'upstream/main' into transparency-button
EastArctica Feb 10, 2024
bfe5f72
Add transparency IPC
EastArctica Feb 17, 2024
445e4df
Linux support(ish) & Clean up errors
EastArctica Feb 17, 2024
cd70df7
Fix Prettier
EastArctica Feb 17, 2024
51c4d2d
Vibrancy & win32 effect IPC
EastArctica Feb 21, 2024
90c0e39
Transparency coremod
EastArctica Feb 21, 2024
91db00f
Platform specific transparency in BrowserWindow
EastArctica Feb 21, 2024
8520f45
Unity todo messages and general cleaning
EastArctica Feb 21, 2024
0f121a5
Fix Transparency IPC
EastArctica Feb 21, 2024
b1658b3
Fix comment issues
EastArctica Feb 21, 2024
7f9e614
Fix reading of transparency styles
EastArctica Feb 22, 2024
a62f1b4
Fix advanced settings crash
EastArctica Mar 1, 2024
e8eabae
Use built in electron blur if available.
EastArctica Mar 1, 2024
a5451bf
Fix applyEffect
EastArctica Mar 10, 2024
9d0e1bd
Fix vibe import
EastArctica Mar 10, 2024
c047b44
Move from import to require
EastArctica Mar 10, 2024
aa5d8e5
Fix inverted if
EastArctica Mar 10, 2024
052b1cd
Merge branch 'main' of https://github.com/replugged-org/replugged int…
EastArctica Jan 14, 2025
04c3c4a
Remove vibe and implement setBackgroundMaterial
EastArctica Jan 15, 2025
3e31d98
Remove old cspell definitions
EastArctica Jan 15, 2025
aa992d0
Remove cspell blurbehind definition
EastArctica Jan 15, 2025
b2a8066
Add unmaximize cspell and prettier
EastArctica Jan 15, 2025
ff063ca
"hook" (un)maximize more cleanly
EastArctica Jan 16, 2025
3551af4
Add note about maximization
EastArctica Jan 16, 2025
36932d9
Add ColorPicker component
EastArctica Jan 16, 2025
b0bd3a8
Abstract transparency coremod functions
EastArctica Jan 16, 2025
e18ff13
Export transparency coremod functions
EastArctica Jan 16, 2025
744e991
Implement override settings for transparency
EastArctica Jan 16, 2025
693efd7
Prettier
EastArctica Jan 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
"uninject",
"uninjector",
"uninjectors",
"unmaximize",
"unmaximized",
"Vendicated",
"webauthn",
"weblate",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,4 @@
"bin": {
"replugged": "bin.mjs"
}
}
}
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion src/globals.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="standalone-electron-types"/>

// TODO: Scope global types to each component
// @todo: Scope global types to each component

import type { WebpackChunkGlobal } from "./types/discord";
import * as replugged from "./renderer/replugged";
Expand Down Expand Up @@ -37,6 +37,9 @@ declare global {
paste: () => void;
read: () => string;
};
process: {
platform: string;
};
};

export const _: typeof Lodash;
Expand Down
149 changes: 121 additions & 28 deletions src/main/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { dirname, join } from "path";

import electron from "electron";
import { CONFIG_PATHS } from "src/util.mjs";
import { CONFIG_PATHS, readSettingsSync } from "src/util.mjs";
import type { RepluggedWebContents } from "../types";
import { getSetting } from "./ipc/settings";

const settings = readSettingsSync("dev.replugged.Settings");
const electronPath = require.resolve("electron");
const discordPath = join(dirname(require.main!.filename), "..", "app.orig.asar");
const discordPackage = require(join(discordPath, "package.json"));
Expand All @@ -23,42 +23,135 @@ Object.defineProperty(global, "appSettings", {
configurable: true,
});

enum DiscordWindowType {
UNKNOWN,
POP_OUT,
SPLASH_SCREEN,
OVERLAY,
DISCORD_CLIENT,
}

type InternalBrowserWindowConstructorOptions = electron.BrowserWindowConstructorOptions & {
webContents?: electron.WebContents;
webPreferences?: {
nativeWindowOpen: boolean;
};
};

function windowTypeFromOpts(opts: InternalBrowserWindowConstructorOptions): DiscordWindowType {
if (opts.webContents) {
return DiscordWindowType.POP_OUT;
} else if (opts.webPreferences?.nodeIntegration) {
return DiscordWindowType.SPLASH_SCREEN;
} else if (opts.webPreferences?.offscreen) {
return DiscordWindowType.OVERLAY;
} else if (opts.webPreferences?.preload) {
if (opts.webPreferences.nativeWindowOpen) {
return DiscordWindowType.DISCORD_CLIENT;
} else {
// Splash Screen on macOS (Host 0.0.262+) & Windows (Host 0.0.293 / 1.0.17+)
return DiscordWindowType.DISCORD_CLIENT;
}
}

return DiscordWindowType.UNKNOWN;
}

// This class has to be named "BrowserWindow" exactly
// https://github.com/discord/electron/blob/13-x-y/lib/browser/api/browser-window.ts#L60-L62
// Thank you, Ven, for pointing this out!
class BrowserWindow extends electron.BrowserWindow {
public constructor(
opts: electron.BrowserWindowConstructorOptions & {
webContents?: electron.WebContents;
webPreferences?: {
nativeWindowOpen: boolean;
};
},
) {
public constructor(opts: InternalBrowserWindowConstructorOptions) {
const originalPreload = opts.webPreferences?.preload;

if (opts.webContents) {
// General purpose pop-outs used by Discord
} else if (opts.webPreferences?.nodeIntegration) {
// Splash Screen
// opts.webPreferences.preload = join(__dirname, './preloadSplash.js');
} else if (opts.webPreferences?.offscreen) {
// Overlay
// originalPreload = opts.webPreferences.preload;
// opts.webPreferences.preload = join(__dirname, './preload.js');
} else if (opts.webPreferences?.preload) {
// originalPreload = opts.webPreferences.preload;
if (opts.webPreferences.nativeWindowOpen) {
// Discord Client
opts.webPreferences.preload = join(__dirname, "./preload.js");
// opts.webPreferences.contextIsolation = false; // shrug
} else {
// Splash Screen on macOS (Host 0.0.262+) & Windows (Host 0.0.293 / 1.0.17+)
opts.webPreferences.preload = join(__dirname, "./preload.js");
const currentWindow = windowTypeFromOpts(opts);

switch (currentWindow) {
case DiscordWindowType.DISCORD_CLIENT: {
opts.webPreferences!.preload = join(__dirname, "./preload.js");

if (settings.get("transparentWindow")) {
switch (process.platform) {
case "win32":
opts.transparent = true;
break;
case "linux":
opts.transparent = true;
break;
}
}
break;
}
case DiscordWindowType.SPLASH_SCREEN: {
// opts.webPreferences.preload = join(__dirname, "./preloadSplash.js");
break;
}
case DiscordWindowType.OVERLAY: {
// opts.webPreferences.preload = join(__dirname, "./preload.js");
break;
}
}

super(opts);

// Center the unmaximized location
if (settings.get("transparentWindow")) {
let lastBounds = this.getBounds();
// Default to the center of the screen at 1440x810 scale for a 1080p monitor (75%)
let primaryDisplaySize = electron.screen.getPrimaryDisplay().workAreaSize;
let lastLastBounds = {
width: primaryDisplaySize.width * 0.75,
height: primaryDisplaySize.height * 0.75,
x: primaryDisplaySize.width / 2 - (primaryDisplaySize.width * 0.75) / 2,
y: primaryDisplaySize.height / 2 - (primaryDisplaySize.height * 0.75) / 2,
};
let lastResize = Date.now();
this.on("resize", () => {
const bounds = this.getBounds();
lastLastBounds = lastBounds;
lastBounds = bounds;
lastResize = Date.now();
});

this.on("maximize", () => {
// Get the display at the center of the window
const screenBounds = this.getBounds();
const windowDisplay = electron.screen.getDisplayNearestPoint({
x: screenBounds.x + screenBounds.width / 2,
y: screenBounds.y + screenBounds.height / 2,
});
const workAreaSize = windowDisplay.workArea;

const isSizeMaximized =
lastBounds.width === workAreaSize.width && lastBounds.height === workAreaSize.height;
const isPositionMaximized =
lastBounds.x === workAreaSize.x + 1 && lastBounds.y === workAreaSize.y + 1;

// if we haven't resized in the last few ms, we probably didn't actually maximize and should instead unmaximize
if (lastResize < Date.now() - 10 || (isSizeMaximized && isPositionMaximized)) {
// Calculate new x, y to be in the center of the monitor
this.setBounds({
x: workAreaSize.width / 2 - lastLastBounds.width / 2 + workAreaSize.x,
y: workAreaSize.height / 2 - lastLastBounds.height / 2 + workAreaSize.y,
width: lastLastBounds.width,
height: lastLastBounds.height,
});

lastResize = Date.now();
return;
}

// Move the window to 1,1 to mitigate the window going grey when maximized
// Note that the window doesn't seem to visually be at 1,1, but that's enough to prevent the greying
this.setBounds({
x: workAreaSize.x + 1,
y: workAreaSize.y + 1,
width: screenBounds.width,
height: screenBounds.height,
});
});
}

(this.webContents as RepluggedWebContents).originalPreload = originalPreload;
}
}
Expand Down
1 change: 1 addition & 0 deletions src/main/ipc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import "./quick-css";
import "./react-devtools";
import "./settings";
import "./themes";
import "./transparency";

ipcMain.on(RepluggedIpcChannels.GET_DISCORD_PRELOAD, (event) => {
event.returnValue = (event.sender as RepluggedWebContents).originalPreload;
Expand Down
67 changes: 67 additions & 0 deletions src/main/ipc/transparency.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { BrowserWindow, ipcMain } from "electron";
import { RepluggedIpcChannels } from "../../types";

let backgroundMaterial: "auto" | "none" | "mica" | "acrylic" | "tabbed" | null = null;
ipcMain.handle(
RepluggedIpcChannels.GET_BACKGROUND_MATERIAL,
(): "auto" | "none" | "mica" | "acrylic" | "tabbed" | null => {
if (process.platform !== "win32") {
console.warn("GET_BACKGROUND_MATERIAL only works on Windows");
}

return backgroundMaterial;
},
);

ipcMain.handle(
RepluggedIpcChannels.SET_BACKGROUND_MATERIAL,
(_, material: "auto" | "none" | "mica" | "acrylic" | "tabbed" | null) => {
if (process.platform !== "win32") {
console.warn("SET_BACKGROUND_MATERIAL only works on Windows");
return;
}

let windows = BrowserWindow.getAllWindows();
windows.forEach((window) => {
// @ts-expect-error standalone-electron-types is not updated to have this.
window.setBackgroundMaterial(typeof material === "string" ? material : "none");
});
backgroundMaterial = material;
},
);

let currentVibrancy: Parameters<typeof BrowserWindow.prototype.setVibrancy>[0] = null;
ipcMain.handle(
RepluggedIpcChannels.GET_VIBRANCY,
(): Parameters<typeof BrowserWindow.prototype.setVibrancy>[0] => currentVibrancy,
);

ipcMain.handle(
RepluggedIpcChannels.SET_VIBRANCY,
(_, vibrancy: Parameters<typeof BrowserWindow.prototype.setVibrancy>[0]) => {
let windows = BrowserWindow.getAllWindows();

windows.forEach((window) => window.setVibrancy(vibrancy));
currentVibrancy = vibrancy;
},
);

let currentBackgroundColor = "#00000000";
ipcMain.handle(RepluggedIpcChannels.GET_BACKGROUND_COLOR, (): string => {
if (process.platform !== "win32") {
console.warn("SET_BACKGROUND_COLOR only works on Windows");
}

return currentBackgroundColor;
});

ipcMain.handle(RepluggedIpcChannels.SET_BACKGROUND_COLOR, (_, color: string | undefined) => {
if (process.platform !== "win32") {
console.warn("SET_BACKGROUND_COLOR only works on Windows");
return;
}

let windows = BrowserWindow.getAllWindows();
windows.forEach((window) => window.setBackgroundColor(color || "#00000000"));
currentBackgroundColor = color || "#00000000";
});
21 changes: 20 additions & 1 deletion src/preload.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
BrowserWindow,
type BrowserWindowConstructorOptions,
contextBridge,
ipcRenderer,
Expand Down Expand Up @@ -102,12 +103,30 @@ const RepluggedNative = {
ipcRenderer.invoke(RepluggedIpcChannels.DOWNLOAD_REACT_DEVTOOLS),
},

transparency: {
getBackgroundMaterial: (): Promise<"auto" | "none" | "mica" | "acrylic" | "tabbed"> =>
ipcRenderer.invoke(RepluggedIpcChannels.GET_BACKGROUND_MATERIAL),
setBackgroundMaterial: (
effect: "auto" | "none" | "mica" | "acrylic" | "tabbed",
): Promise<void> => ipcRenderer.invoke(RepluggedIpcChannels.SET_BACKGROUND_MATERIAL, effect),
getBackgroundColor: (): Promise<string> =>
ipcRenderer.invoke(RepluggedIpcChannels.GET_BACKGROUND_COLOR),
setBackgroundColor: (color: string): Promise<void> =>
ipcRenderer.invoke(RepluggedIpcChannels.SET_BACKGROUND_COLOR, color),
getVibrancy: (): Promise<Parameters<typeof BrowserWindow.prototype.setVibrancy>[0]> =>
ipcRenderer.invoke(RepluggedIpcChannels.GET_VIBRANCY),
setVibrancy: (
vibrancy: Parameters<typeof BrowserWindow.prototype.setVibrancy>[0],
): Promise<void> => ipcRenderer.invoke(RepluggedIpcChannels.SET_VIBRANCY, vibrancy),
// visualEffectState does not need to be implemented until https://github.com/electron/electron/issues/25513 is implemented.
},

getVersion: () => version,

// eslint-disable-next-line @typescript-eslint/no-unused-vars
openBrowserWindow: (opts: BrowserWindowConstructorOptions) => {}, // later

// @todo We probably want to move these somewhere else, but I'm putting them here for now because I'm too lazy to set anything else up
// @todo: We probably want to move these somewhere else, but I'm putting them here for now because I'm too lazy to set anything else up
};

export type RepluggedNativeType = typeof RepluggedNative;
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/coremods/experiments/plaintextPatches.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { init } from "src/renderer/apis/settings";
import { type GeneralSettings, type PlaintextPatch, defaultSettings } from "src/types";

// TODO: see if we can import this from General.tsx
// @todo: see if we can import this from General.tsx
const generalSettings = await init<GeneralSettings, keyof typeof defaultSettings>(
"dev.replugged.Settings",
defaultSettings,
Expand Down
Loading
Loading