Skip to content

Commit 8d36d68

Browse files
authored
Update main.js
1 parent 3116225 commit 8d36d68

1 file changed

Lines changed: 73 additions & 93 deletions

File tree

main.js

Lines changed: 73 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,19 @@
1-
// main.js
1+
// main.js (ESM)
22
import { app, BrowserWindow, BrowserView } from 'electron';
33
import fs from 'node:fs';
44
import path from 'node:path';
55

6-
// ---- Runtime safety: reduce chances of "blank" windows on some GPUs/VMs
6+
// Improve compatibility with some enterprise GPUs/VMs
77
app.disableHardwareAcceleration();
88

9-
// -------- Globals
109
let mainWindow;
1110
let topView;
1211
let bottomView;
1312
let config;
1413
let cfgPathInUse = null;
1514
let defaultUA = { top: null, bottom: null };
1615

17-
// ---- Helpers
18-
19-
function getExeDir() {
20-
try {
21-
return path.dirname(app.getPath('exe'));
22-
} catch {
23-
return process.cwd();
24-
}
25-
}
26-
27-
function findConfigPath() {
28-
const exeDir = getExeDir();
29-
const candidates = [
30-
path.join(exeDir, 'config.json'), // portable / next to EXE (preferred)
31-
path.join(process.cwd(), 'config.json'), // dev fallback
32-
];
33-
for (const p of candidates) {
34-
try {
35-
if (fs.existsSync(p)) return p;
36-
} catch {}
37-
}
38-
// If none exist, default to exeDir for future writes/expectations
39-
return path.join(exeDir, 'config.json');
40-
}
16+
// ---------- Config loading ----------
4117

4218
function normalizeConfig(cfg) {
4319
return {
@@ -51,6 +27,35 @@ function normalizeConfig(cfg) {
5127
};
5228
}
5329

30+
function candidatesForConfig() {
31+
const portableDir = process.env.PORTABLE_EXECUTABLE_DIR; // electron-builder portable
32+
const exeDir = path.dirname(app.getPath('exe'));
33+
const cwd = process.cwd();
34+
const userData = app.getPath('userData'); // optional override location
35+
const resources = process.resourcesPath; // baked default (if you ship one inside asar)
36+
37+
const list = [];
38+
if (portableDir) list.push(path.join(portableDir, 'config.json'));
39+
list.push(
40+
path.join(exeDir, 'config.json'),
41+
path.join(cwd, 'config.json'),
42+
path.join(userData, 'config.json'),
43+
path.join(resources, 'config.json') // final fallback if bundled
44+
);
45+
return list;
46+
}
47+
48+
function findConfigPath() {
49+
for (const p of candidatesForConfig()) {
50+
try { if (fs.existsSync(p)) return p; } catch {}
51+
}
52+
// If nothing exists, prefer PORTABLE_EXECUTABLE_DIR (if present) for future writes
53+
if (process.env.PORTABLE_EXECUTABLE_DIR) {
54+
return path.join(process.env.PORTABLE_EXECUTABLE_DIR, 'config.json');
55+
}
56+
return path.join(path.dirname(app.getPath('exe')), 'config.json');
57+
}
58+
5459
function loadConfig() {
5560
const p = cfgPathInUse || findConfigPath();
5661
cfgPathInUse = p;
@@ -61,10 +66,12 @@ function loadConfig() {
6166
return normalizeConfig(parsed);
6267
}
6368
} catch {}
64-
// Fallback defaults (you can inline your own baked defaults here if desired)
69+
// Fallback defaults you can put your AWACS URLs here as a baked default if you want
6570
return normalizeConfig({});
6671
}
6772

73+
// ---------- Navigation guard ----------
74+
6875
function getOrigin(u) {
6976
try {
7077
const x = new URL(u);
@@ -87,16 +94,7 @@ function guardNavigation(view, initialUrl) {
8794
});
8895
}
8996

90-
// Simple debounce for file watcher
91-
function debounce(fn, ms = 250) {
92-
let t;
93-
return (...args) => {
94-
clearTimeout(t);
95-
t = setTimeout(() => fn(...args), ms);
96-
};
97-
}
98-
99-
// ---- Layout
97+
// ---------- Layout ----------
10098

10199
function layout() {
102100
if (!mainWindow || !topView || !bottomView) return;
@@ -108,97 +106,90 @@ function layout() {
108106
bottomView.setAutoResize({ width: true, height: true });
109107
}
110108

111-
// ---- Apply config changes live
109+
// ---------- Live apply changes ----------
112110

113111
function applyConfigChanges(next) {
114-
// Determine what changed
115-
const urlsChanged =
116-
next.topUrl !== config.topUrl || next.bottomUrl !== config.bottomUrl;
112+
const urlsChanged = next.topUrl !== config.topUrl || next.bottomUrl !== config.bottomUrl;
117113
const ratioChanged = next.dividerRatio !== config.dividerRatio;
118114
const uaChanged = next.userAgent !== config.userAgent;
119115
const lockChanged = next.lockToInitialOrigin !== config.lockToInitialOrigin;
120116

121117
config = next;
122118

123-
// Update user agent on each view if changed
124119
if (uaChanged && topView && bottomView) {
125120
try {
126121
if (config.userAgent) {
127122
topView.webContents.setUserAgent(config.userAgent);
128123
bottomView.webContents.setUserAgent(config.userAgent);
129124
} else {
130-
// Restore defaults if we captured them
131125
if (defaultUA.top) topView.webContents.setUserAgent(defaultUA.top);
132126
if (defaultUA.bottom) bottomView.webContents.setUserAgent(defaultUA.bottom);
133127
}
134128
} catch {}
135129
}
136130

137-
// Re-guard navigation if lock setting changed
138131
if (lockChanged) {
139-
// Remove old handlers by recreating views is heavy; instead, rely on handler logic
140-
// Since we only ever *tighten* rules, we can add guards now if they weren't present
132+
// Re-apply guards (handlers are additive; we only tighten rules when enabled)
141133
guardNavigation(topView, config.topUrl);
142134
guardNavigation(bottomView, config.bottomUrl);
143135
}
144136

145-
// Reload URLs if changed or UA changed (UA affects next navigation)
146137
if (urlsChanged || uaChanged) {
147138
const loadOpts = config.userAgent ? { userAgent: config.userAgent } : undefined;
148139
if (topView && topView.webContents.getURL() !== config.topUrl) {
149140
topView.webContents.loadURL(config.topUrl, loadOpts).catch(() => {});
150141
} else if (uaChanged && topView) {
151142
topView.webContents.reload();
152143
}
144+
153145
if (bottomView && bottomView.webContents.getURL() !== config.bottomUrl) {
154146
bottomView.webContents.loadURL(config.bottomUrl, loadOpts).catch(() => {});
155147
} else if (uaChanged && bottomView) {
156148
bottomView.webContents.reload();
157149
}
158150
}
159151

160-
// Re-apply layout if divider changed
161152
if (ratioChanged) layout();
162153
}
163154

164155
function watchConfigFile() {
165156
if (!cfgPathInUse) return;
166-
try {
167-
const handler = debounce(() => {
168-
try {
169-
const next = loadConfig();
170-
applyConfigChanges(next);
171-
} catch {
172-
// Ignore transient parse errors while file is being saved
173-
}
174-
}, 300);
175157

176-
// Prefer fs.watch; if it fails on network shares, fall back to watchFile
177-
const watcher = fs.watch(cfgPathInUse, { persistent: false }, handler);
178-
// On some filesystems, rename events may fire; also handle errors silently
158+
const tryApply = debounce(() => {
159+
try {
160+
const next = loadConfig();
161+
applyConfigChanges(next);
162+
} catch {
163+
// ignore transient parse errors while saving
164+
}
165+
}, 300);
166+
167+
try {
168+
const watcher = fs.watch(cfgPathInUse, { persistent: false }, tryApply);
179169
watcher.on('error', () => {
180-
try {
181-
fs.unwatchFile(cfgPathInUse);
182-
} catch {}
183-
try {
184-
fs.watchFile(cfgPathInUse, { interval: 500 }, handler);
185-
} catch {}
170+
try { fs.unwatchFile(cfgPathInUse); } catch {}
171+
try { fs.watchFile(cfgPathInUse, { interval: 500 }, tryApply); } catch {}
186172
});
187173
} catch {
188-
// Fallback: polling
189-
try {
190-
fs.watchFile(cfgPathInUse, { interval: 500 }, debounce(() => {
191-
const next = loadConfig();
192-
applyConfigChanges(next);
193-
}, 300));
194-
} catch {}
174+
try { fs.watchFile(cfgPathInUse, { interval: 500 }, tryApply); } catch {}
195175
}
196176
}
197177

198-
// ---- Create window and views
178+
function debounce(fn, ms = 250) {
179+
let t;
180+
return (...args) => {
181+
clearTimeout(t);
182+
t = setTimeout(() => fn(...args), ms);
183+
};
184+
}
185+
186+
// ---------- Create window ----------
199187

200188
function createWindow() {
201189
config = loadConfig();
190+
console.log('[TwoSites] Using config at:', cfgPathInUse);
191+
console.log('[TwoSites] Top URL:', config.topUrl);
192+
console.log('[TwoSites] Bottom URL:', config.bottomUrl);
202193

203194
mainWindow = new BrowserWindow({
204195
width: 1200,
@@ -207,8 +198,8 @@ function createWindow() {
207198
minWidth: config.minWidth,
208199
minHeight: config.minHeight,
209200
backgroundColor: '#111111',
210-
show: true, // show immediately
211-
autoHideMenuBar: true, // no menu (no address bar)
201+
show: true, // show immediately
202+
autoHideMenuBar: true, // no address bar/menu
212203
webPreferences: {
213204
nodeIntegration: false,
214205
contextIsolation: true,
@@ -220,57 +211,46 @@ function createWindow() {
220211
// Safety net: ensure it shows even if pages hang
221212
setTimeout(() => { try { mainWindow.show(); } catch {} }, 1500);
222213

223-
// Create the two panes
224-
topView = new BrowserView({
225-
webPreferences: { contextIsolation: true, sandbox: true },
226-
});
227-
bottomView = new BrowserView({
228-
webPreferences: { contextIsolation: true, sandbox: true },
229-
});
214+
topView = new BrowserView({ webPreferences: { contextIsolation: true, sandbox: true } });
215+
bottomView = new BrowserView({ webPreferences: { contextIsolation: true, sandbox: true } });
230216

231217
mainWindow.setBrowserView(topView);
232218
mainWindow.addBrowserView(bottomView);
233219

234-
// Capture default UA strings before any overrides
220+
// capture default UA
235221
try {
236222
defaultUA.top = topView.webContents.getUserAgent?.() || null;
237223
defaultUA.bottom = bottomView.webContents.getUserAgent?.() || null;
238224
} catch {}
239225

240-
// Optional custom UA
241226
if (config.userAgent) {
242227
try {
243228
topView.webContents.setUserAgent(config.userAgent);
244229
bottomView.webContents.setUserAgent(config.userAgent);
245230
} catch {}
246231
}
247232

248-
// Load URLs
249233
const loadOpts = config.userAgent ? { userAgent: config.userAgent } : undefined;
250234
topView.webContents.loadURL(config.topUrl, loadOpts).catch(() => {});
251235
bottomView.webContents.loadURL(config.bottomUrl, loadOpts).catch(() => {});
252-
253-
// Navigation guard (optional, per config)
254236
guardNavigation(topView, config.topUrl);
255237
guardNavigation(bottomView, config.bottomUrl);
256238

257-
// Layout now and on resize
258239
mainWindow.on('resize', layout);
259240
mainWindow.once('ready-to-show', () => { layout(); try { mainWindow.show(); } catch {} });
260241

261-
// Useful diagnostics if something fails to load
242+
// diagnostics
262243
for (const wc of [topView.webContents, bottomView.webContents]) {
263244
wc.on('did-fail-load', (_e, code, desc, validatedURL) => {
264245
console.error('did-fail-load', code, desc, validatedURL);
265246
});
266247
wc.on('crashed', () => console.error('webContents crashed'));
267248
}
268249

269-
// Start watching config.json for live updates
270250
watchConfigFile();
271251
}
272252

273-
// ---- App lifecycle
253+
// ---------- App lifecycle ----------
274254

275255
app.whenReady().then(() => {
276256
createWindow();

0 commit comments

Comments
 (0)