Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
79 changes: 78 additions & 1 deletion scripts/lib/upstream-patches.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export async function patchUpstreamApp(stageAppDir) {

const mainBundlePath = path.join(buildDir, mainBundleName);
const source = await fs.readFile(mainBundlePath, "utf8");
const patched = patchLinuxOpenTargetsSource(source);
const patched = patchUpstreamMainSource(source);

if (patched === source) {
return;
Expand All @@ -35,6 +35,15 @@ export async function patchUpstreamApp(stageAppDir) {
await fs.writeFile(mainBundlePath, patched);
}

export function patchUpstreamMainSource(source) {
let patched = source;

patched = patchLinuxOpenTargetsSource(patched);
patched = patchDisableTransparencySource(patched);

return patched;
}

export function patchLinuxOpenTargetsSource(source) {
let patched = source;

Expand All @@ -54,6 +63,74 @@ export function patchLinuxOpenTargetsSource(source) {
return patched;
}

export function patchDisableTransparencySource(source) {
let patched = source;

patched = patchLinuxWindowBackground(patched);
patched = patchLinuxWindowTransparency(patched);

return patched;
}

function patchLinuxWindowBackground(source) {
if (
/backgroundColor:[A-Za-z_$][\w$]*===`linux`\?\([A-Za-z_$][\w$]*\?[A-Za-z_$][\w$]*:[A-Za-z_$][\w$]*\):[A-Za-z_$][\w$]*,backgroundMaterial:null/.test(source)
) {
return source;
}

const match = source.match(
/function ([A-Za-z_$][\w$]*)\(\{platform:([A-Za-z_$][\w$]*),appearance:([A-Za-z_$][\w$]*),opaqueWindowsEnabled:([A-Za-z_$][\w$]*),prefersDarkColors:([A-Za-z_$][\w$]*)\}\)\{return \4&&!([A-Za-z_$][\w$]*)\(\3\)&&\(\2===`darwin`\|\|\2===`win32`\)\?\{backgroundColor:\5\?([A-Za-z_$][\w$]*):([A-Za-z_$][\w$]*),backgroundMaterial:\2===`win32`\?`none`:null\}:\2===`win32`&&!\6\(\3\)\?\{backgroundColor:([A-Za-z_$][\w$]*),backgroundMaterial:`mica`\}:\{backgroundColor:([A-Za-z_$][\w$]*),backgroundMaterial:null\}\}/
);

if (!match) {
throw new Error("Unable to apply upstream patch; missing window background helper");
}

const [
anchor,
,
platformVar,
,
,
prefersDarkVar,
,
darkColorVar,
lightColorVar,
,
fallbackColorVar
] = match;
const fallback = `{backgroundColor:${fallbackColorVar},backgroundMaterial:null}`;
const replacement = anchor.replace(
fallback,
`{backgroundColor:${platformVar}===\`linux\`?(${prefersDarkVar}?${darkColorVar}:${lightColorVar}):${fallbackColorVar},backgroundMaterial:null}`
);

return replaceOnce(source, anchor, replacement);
}

function patchLinuxWindowTransparency(source) {
if (/transparent:[A-Za-z_$][\w$]*===`linux`\?!1:[A-Za-z_$][\w$]*,hasShadow:/.test(source)) {
return source;
}

const match = source.match(
/function ([A-Za-z_$][\w$]*)\(\{alwaysOnTop:([A-Za-z_$][\w$]*),hasShadow:([A-Za-z_$][\w$]*)=!0,platform:([A-Za-z_$][\w$]*),resizable:([A-Za-z_$][\w$]*),thickFrame:([A-Za-z_$][\w$]*),transparent:([A-Za-z_$][\w$]*)=!0\}\)\{return\{frame:!1,transparent:\7,hasShadow:\3,/
);

if (!match) {
throw new Error("Unable to apply upstream patch; missing window transparency helper");
}

const [anchor, , , shadowVar, platformVar, , , transparentVar] = match;
const replacement = anchor.replace(
`transparent:${transparentVar},hasShadow:${shadowVar},`,
`transparent:${platformVar}===\`linux\`?!1:${transparentVar},hasShadow:${shadowVar},`
);

return replaceOnce(source, anchor, replacement);
}

function patchOpenTargetMap(source) {
if (source.includes("appPath:process.platform===`linux`")) {
return source;
Expand Down
35 changes: 34 additions & 1 deletion test/upstream-patches.test.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import test from "node:test";
import assert from "node:assert/strict";

import { patchLinuxOpenTargetsSource } from "../scripts/lib/upstream-patches.mjs";
import {
patchDisableTransparencySource,
patchLinuxOpenTargetsSource
} from "../scripts/lib/upstream-patches.mjs";

test("patchLinuxOpenTargetsSource adds Linux editor targets and exposes app paths", () => {
const source = [
Expand Down Expand Up @@ -109,3 +112,33 @@ test("patchLinuxOpenTargetsSource preserves native target spread variable", () =
);
assert.match(patched, /\}\)\),\.\.\.h\]/);
});

test("patchDisableTransparencySource disables Linux BrowserWindow transparency and background", () => {
const source = [
"function A2(e){return e===`avatarOverlay`||e===`browserCommentPopup`}",
"function I2({platform:e,appearance:t,opaqueWindowsEnabled:n,prefersDarkColors:r}){return n&&!A2(t)&&(e===`darwin`||e===`win32`)?{backgroundColor:r?a2:o2,backgroundMaterial:e===`win32`?`none`:null}:e===`win32`&&!A2(t)?{backgroundColor:i2,backgroundMaterial:`mica`}:{backgroundColor:i2,backgroundMaterial:null}}",
"function R2({alwaysOnTop:e,hasShadow:t=!0,platform:n,resizable:r,thickFrame:i,transparent:a=!0}){return{frame:!1,transparent:a,hasShadow:t,resizable:r,minimizable:!1,maximizable:!1,fullscreenable:!1,skipTaskbar:!0,...e?{alwaysOnTop:!0}:{},...n===`win32`?{accentColor:!1,roundedCorners:!1,...i==null?{}:{thickFrame:i}}:{},...n===`darwin`?{type:`panel`}:{}}}",
"function z2({appearance:e,platform:n}){switch(e){case`browserCommentPopup`:return R2({hasShadow:!1,platform:n,resizable:!1,thickFrame:!1,transparent:!0});case`avatarOverlay`:return R2({platform:n,resizable:!1})}}"
].join(";");

const patched = patchDisableTransparencySource(source);

assert.match(patched, /backgroundColor:e===`linux`\?\(r\?a2:o2\):i2,backgroundMaterial:null/);
assert.doesNotMatch(patched, /\{backgroundColor:i2,backgroundMaterial:null\}/);
assert.match(patched, /transparent:n===`linux`\?!1:a,hasShadow:t/);
assert.doesNotMatch(patched, /return\{frame:!1,transparent:a,hasShadow:t/);
});

test("patchDisableTransparencySource is idempotent", () => {
const source = [
"function A2(e){return e===`avatarOverlay`||e===`browserCommentPopup`}",
"function I2({platform:e,appearance:t,opaqueWindowsEnabled:n,prefersDarkColors:r}){return n&&!A2(t)&&(e===`darwin`||e===`win32`)?{backgroundColor:r?a2:o2,backgroundMaterial:e===`win32`?`none`:null}:e===`win32`&&!A2(t)?{backgroundColor:i2,backgroundMaterial:`mica`}:{backgroundColor:i2,backgroundMaterial:null}}",
"function R2({alwaysOnTop:e,hasShadow:t=!0,platform:n,resizable:r,thickFrame:i,transparent:a=!0}){return{frame:!1,transparent:a,hasShadow:t,resizable:r,minimizable:!1,maximizable:!1,fullscreenable:!1,skipTaskbar:!0,...e?{alwaysOnTop:!0}:{},...n===`win32`?{accentColor:!1,roundedCorners:!1,...i==null?{}:{thickFrame:i}}:{},...n===`darwin`?{type:`panel`}:{}}}",
"function z2({appearance:e,platform:n}){switch(e){case`browserCommentPopup`:return R2({hasShadow:!1,platform:n,resizable:!1,thickFrame:!1,transparent:!0});case`avatarOverlay`:return R2({platform:n,resizable:!1})}}"
].join(";");

const patched = patchDisableTransparencySource(source);
const repatched = patchDisableTransparencySource(patched);

assert.equal(repatched, patched);
});