返回 DeepSeek-Reasonix
graphics.ts
根目录 / desktop / electron / src / main / graphics.ts
1 import { existsSync, readFileSync, renameSync, writeFileSync, mkdirSync } from "node:fs";
2 import { dirname, join } from "node:path";
3
4 export type GraphicsOverride = "none" | "environment" | "command-line";
5 export type GraphicsWarning = "invalid-config" | "unreadable-config" | "unsupported-version";
6 export interface GraphicsSettingsState {
7 hardwareAcceleration: boolean;
8 startupEnabled: boolean;
9 override: GraphicsOverride;
10 restartRequired: boolean;
11 writable: boolean;
12 warning: GraphicsWarning | null;
13 }
14 export interface GraphicsBootstrap {
15 state: GraphicsSettingsState;
16 shouldDisable: boolean;
17 configPath: string;
18 }
19
20 type Stored = { version: 1; hardwareAcceleration: boolean; [key: string]: unknown };
21
22 function parseStored(path: string): { value: Stored | null; warning: GraphicsWarning | null } {
23 if (!existsSync(path)) return { value: null, warning: null };
24 try {
25 const parsed = JSON.parse(readFileSync(path, "utf8")) as Record<string, unknown>;
26 if (parsed.version !== 1) return { value: null, warning: "unsupported-version" };
27 if (typeof parsed.hardwareAcceleration !== "boolean") return { value: null, warning: "invalid-config" };
28 return { value: parsed as Stored, warning: null };
29 } catch {
30 return { value: null, warning: "unreadable-config" };
31 }
32 }
33
34 export function loadGraphicsBootstrap(dataHome: string, env: NodeJS.ProcessEnv, argv: readonly string[]): GraphicsBootstrap {
35 // `dataHome/desktop-shell` is Electron's userData profile (set by
36 // claimShellInstance), so keep the preference directly in that profile.
37 const configPath = join(dataHome, "graphics.json");
38 const parsed = parseStored(configPath);
39 const hardwareAcceleration = parsed.value?.hardwareAcceleration ?? true;
40 const environmentOverride = env.REASONIX_DISABLE_GPU === "1";
41 const commandLineOverride = argv.includes("--disable-gpu");
42 const override: GraphicsOverride = environmentOverride ? "environment" : commandLineOverride ? "command-line" : "none";
43 const startupEnabled = override === "none" ? hardwareAcceleration : false;
44 return {
45 configPath,
46 shouldDisable: !startupEnabled,
47 state: {
48 hardwareAcceleration,
49 startupEnabled,
50 override,
51 restartRequired: override === "none" && hardwareAcceleration !== startupEnabled,
52 writable: parsed.warning !== "unsupported-version",
53 warning: parsed.warning,
54 },
55 };
56 }
57
58 export class GraphicsSettingsStore {
59 private stored: Stored | null;
60 constructor(private readonly path: string, bootstrap: GraphicsBootstrap) {
61 this.stored = parseStored(path).value ?? { version: 1, hardwareAcceleration: bootstrap.state.hardwareAcceleration };
62 this.state = bootstrap.state;
63 }
64 private state: GraphicsSettingsState;
65 private writeQueue: Promise<void> = Promise.resolve();
66 get current(): GraphicsSettingsState { return this.state; }
67 async setHardwareAcceleration(enabled: boolean): Promise<GraphicsSettingsState> {
68 if (typeof enabled !== "boolean") throw new Error("hardwareAcceleration must be boolean");
69 if (!this.state.writable) throw new Error("graphics settings are read-only");
70 const next: Stored = { ...this.stored, version: 1, hardwareAcceleration: enabled };
71 const write = this.writeQueue.catch(() => undefined).then(() => {
72 mkdirSync(dirname(this.path), { recursive: true });
73 const existing = parseStored(this.path);
74 if (existing.warning) {
75 let backup = `${this.path}.invalid`;
76 let suffix = 1;
77 while (existsSync(backup)) backup = `${this.path}.invalid.${suffix++}`;
78 renameSync(this.path, backup);
79 }
80 const temp = `${this.path}.tmp`;
81 writeFileSync(temp, `${JSON.stringify(next)}\n`, "utf8");
82 renameSync(temp, this.path);
83 });
84 this.writeQueue = write.catch(() => undefined);
85 await write;
86 this.stored = next;
87 this.state = { ...this.state, hardwareAcceleration: enabled, restartRequired: this.state.override === "none" && enabled !== this.state.startupEnabled, warning: null };
88 return this.state;
89 }
90 }
91
91 lines TYPESCRIPT