Skip to content
Merged
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
2 changes: 1 addition & 1 deletion apps/code/snapshots.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ snapshots:
archive-archivedtasksview--many-tasks--dark:
hash: v1.k4693efd2.40d24f07a24c6400c32ae68b39fd908a056beb5dc6df8bcb237ec2ab2b494f4a.l2vjfSQDalCPRtDNV7pbfTKGlMsQoI81jI-UdJfLHWE
archive-archivedtasksview--many-tasks--light:
hash: v1.k4693efd2.52ec9963bfe6f248ffcdaa4c26945d2b7e303115825b65d978aa5aefd4af1007.ZLtOfTZUrznhYeB-N2SIHzQWRzF6TDSaipNkfd8uzjM
hash: v1.k4693efd2.74c25b303262f2d4c0f22890d351e76f482827548548f7c023bc309327c927b8.DP9VVrvBz1naIJMwHORkfqm69BlO785ulOt4o6zFs94
archive-archivedtasksview--mixed-modes--dark:
hash: v1.k4693efd2.d94039b8cc17a4ad1b720364f41fee58a4843aa9a901443997ba62602f698794.441LWZhT-2WQZJHni4LoOgQsOSr2O103NZOk1pF8ME4
archive-archivedtasksview--mixed-modes--light:
Expand Down
95 changes: 90 additions & 5 deletions apps/code/src/main/zoom.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,20 @@ vi.mock("./utils/store", () => ({
import { adjustWindowZoom, restoreWindowZoom, setupWindowZoom } from "./zoom";

class FakeWebContents extends EventEmitter {
public destroyed = false;
public readonly setZoomLevelCalls: number[] = [];
public zoomLevel = 0;

public isDestroyed(): boolean {
return this.destroyed;
}

public getZoomLevel(): number {
return this.zoomLevel;
}

public setZoomLevel(level: number): void {
this.setZoomLevelCalls.push(level);
this.zoomLevel = level;
}
}
Expand Down Expand Up @@ -85,6 +96,30 @@ describe("window zoom", () => {
expect(window.webContents.zoomLevel).toBe(0.5);
});

it("restores the current level after an external window resize", () => {
const window = createWindow();
setupWindowZoom(window);

window.webContents.emit("zoom-changed", { preventDefault: vi.fn() }, "in");
vi.runAllTimers();
window.webContents.zoomLevel = 0;

window.emit("resize");
vi.runAllTimers();
const restoredZoomLevel = window.webContents.zoomLevel;
adjustWindowZoom(window, 0.5);

expect({
restoredZoomLevel,
zoomLevel: window.webContents.zoomLevel,
saved: store.save.mock.calls,
}).toEqual({
restoredZoomLevel: 1,
zoomLevel: 1.5,
saved: [[1], [1.5]],
});
});

it.each([
["in", 1],
["out", 0],
Expand All @@ -110,20 +145,70 @@ describe("window zoom", () => {
},
);

it("keeps wheel zoom after resizing", () => {
it.each(["resize", "resized"] as const)(
"keeps wheel zoom after %s",
(resizeEvent) => {
const window = createWindow();
setupWindowZoom(window);

window.webContents.emit(
"zoom-changed",
{ preventDefault: vi.fn() },
"in",
);
window.emit(resizeEvent);
vi.runAllTimers();

expect({
zoomLevel: window.webContents.zoomLevel,
saved: store.save.mock.calls,
}).toEqual({
zoomLevel: 1,
saved: [[1]],
});
},
);

it("skips redundant restoration during a resize storm", () => {
const window = createWindow();
setupWindowZoom(window);
window.webContents.zoomLevel = 0.5;

window.emit("resize");
vi.runAllTimers();
vi.advanceTimersByTime(16);
window.emit("resize");
vi.runAllTimers();
const callsBeforeReset = [...window.webContents.setZoomLevelCalls];

window.webContents.zoomLevel = 0;
window.emit("resize");
vi.runAllTimers();

expect({
callsBeforeReset,
callsAfterReset: window.webContents.setZoomLevelCalls,
}).toEqual({
callsBeforeReset: [],
callsAfterReset: [0.5],
});
});

it("ignores queued zoom work after the window is destroyed", () => {
const window = createWindow();
setupWindowZoom(window);

window.webContents.emit("zoom-changed", { preventDefault: vi.fn() }, "in");
window.emit("resized");
window.emit("resize");
window.webContents.destroyed = true;
vi.runAllTimers();

expect({
zoomLevel: window.webContents.zoomLevel,
zoomLevelCalls: window.webContents.setZoomLevelCalls,
saved: store.save.mock.calls,
}).toEqual({
zoomLevel: 1,
saved: [[1]],
zoomLevelCalls: [],
saved: [],
});
});

Expand Down
11 changes: 10 additions & 1 deletion apps/code/src/main/zoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const ZOOM_MIN = -3;
const ZOOM_MAX = 3;

interface ZoomWebContents {
getZoomLevel(): number;
isDestroyed(): boolean;
on(event: "did-finish-load", listener: () => void): void;
on(
event: "zoom-changed",
Expand All @@ -23,6 +25,7 @@ interface ZoomWindow {
| "enter-full-screen"
| "leave-full-screen"
| "maximize"
| "resize"
| "resized"
| "unmaximize",
listener: () => void,
Expand Down Expand Up @@ -62,6 +65,7 @@ function runAfterWheelZoom(window: ZoomWindow, action: () => void): void {
}

export function setWindowZoom(window: ZoomWindow, level: number): void {
if (window.webContents.isDestroyed()) return;
const nextLevel = clampZoomLevel(level);
const state = zoomStates.get(window);
if (state) state.currentZoomLevel = nextLevel;
Expand All @@ -82,7 +86,11 @@ export function adjustWindowZoom(

export function restoreWindowZoom(window: ZoomWindow): void {
runAfterWheelZoom(window, () => {
window.webContents.setZoomLevel(getCurrentZoomLevel(window));
if (window.webContents.isDestroyed()) return;
const zoomLevel = getCurrentZoomLevel(window);
if (window.webContents.getZoomLevel() !== zoomLevel) {
window.webContents.setZoomLevel(zoomLevel);
}
});
}

Expand Down Expand Up @@ -120,6 +128,7 @@ export function setupWindowZoom(window: ZoomWindow): void {

window.on("maximize", scheduleRestore);
window.on("unmaximize", scheduleRestore);
window.on("resize", scheduleRestore);
window.on("resized", scheduleRestore);
window.on("enter-full-screen", scheduleRestore);
window.on("leave-full-screen", scheduleRestore);
Expand Down
Loading