Adjust Linux wallpaper test mode

This commit is contained in:
Scott Idem
2026-05-13 18:57:27 -04:00
parent c8fdb8b1e7
commit 1008a55ec3
3 changed files with 87 additions and 40 deletions

View File

@@ -221,18 +221,41 @@ function registerSystemHandlers() {
} }
} }
if (os.platform() === 'linux') { if (os.platform() === 'linux') {
let img_path = imagePath ? (0, file_utils_1.expandPath)(imagePath) : null; // Dev test mode: never touch the desktop on Linux. Running gsettings during
if (!img_path && url) { // development would reset the dev workstation monitors on every test cycle.
const result = await download_wallpaper_image(url, 'wallpaper_primary'); // Return what would have run so the Svelte side can show a debug popup.
if (!result.success || !result.path) const would_run = [];
return { success: false, error: result.error }; const cache_dir = wallpaper_cache_dir;
img_path = result.path; if (!imagePath && !url && !url_external) {
}
if (!img_path)
return { success: false, error: 'No image source provided' }; return { success: false, error: 'No image source provided' };
if (!fs.existsSync(img_path)) }
return { success: false, error: 'Image file not found' }; if (imagePath) {
return await runExec(`gsettings set org.gnome.desktop.background picture-uri "file://${img_path}"`); const clean = (0, file_utils_1.expandPath)(imagePath);
if (!fs.existsSync(clean))
return { success: false, error: 'Image file not found' };
}
if (url)
would_run.push(`download: ${url}\n${path.join(cache_dir, 'wallpaper_primary.jpg')}`);
if (url_external)
would_run.push(`download: ${url_external}\n${path.join(cache_dir, 'wallpaper_external.jpg')}`);
if (imagePath) {
would_run.push(`gsettings set org.gnome.desktop.background picture-uri "file://${(0, file_utils_1.expandPath)(imagePath)}"`);
}
else if (url) {
would_run.push(`gsettings set org.gnome.desktop.background picture-uri "file://${path.join(cache_dir, 'wallpaper_primary.jpg')}"`);
}
if (url_external) {
would_run.push(`(external display: gsettings has no per-display wallpaper support)`);
}
return {
success: true,
linux_test_mode: true,
platform: 'linux',
display,
url: url ?? null,
url_external: url_external ?? null,
would_run
};
} }
return { success: false, error: 'Platform not supported' }; return { success: false, error: 'Platform not supported' };
}); });

File diff suppressed because one or more lines are too long

View File

@@ -23,7 +23,7 @@ const runExec = (cmd: string): Promise<{ success: boolean; stdout?: string; stde
let recordingProcess: any = null; let recordingProcess: any = null;
export function registerSystemHandlers() { export function registerSystemHandlers() {
// 1. Window Control // 1. Window Control
ipcMain.handle('native:window-control', async (event, { action, value }) => { ipcMain.handle('native:window-control', async (event, { action, value }) => {
const win = BrowserWindow.fromWebContents(event.sender); const win = BrowserWindow.fromWebContents(event.sender);
@@ -35,7 +35,7 @@ export function registerSystemHandlers() {
case 'minimize': win.minimize(); break; case 'minimize': win.minimize(); break;
case 'restore': win.restore(); break; case 'restore': win.restore(); break;
case 'close': win.close(); break; case 'close': win.close(); break;
case 'devtools': case 'devtools':
if (value) win.webContents.openDevTools(); if (value) win.webContents.openDevTools();
else win.webContents.closeDevTools(); else win.webContents.closeDevTools();
break; break;
@@ -177,18 +177,42 @@ export function registerSystemHandlers() {
} }
if (os.platform() === 'linux') { if (os.platform() === 'linux') {
let img_path: string | null = imagePath ? expandPath(imagePath) : null; // Dev test mode: never touch the desktop on Linux. Running gsettings during
// development would reset the dev workstation monitors on every test cycle.
// Return what would have run so the Svelte side can show a debug popup.
const would_run: string[] = [];
const cache_dir = wallpaper_cache_dir;
if (!img_path && url) { if (!imagePath && !url && !url_external) {
const result = await download_wallpaper_image(url, 'wallpaper_primary'); return { success: false, error: 'No image source provided' };
if (!result.success || !result.path) return { success: false, error: result.error };
img_path = result.path;
} }
if (!img_path) return { success: false, error: 'No image source provided' }; if (imagePath) {
if (!fs.existsSync(img_path)) return { success: false, error: 'Image file not found' }; const clean = expandPath(imagePath);
if (!fs.existsSync(clean)) return { success: false, error: 'Image file not found' };
}
return await runExec(`gsettings set org.gnome.desktop.background picture-uri "file://${img_path}"`); if (url) would_run.push(`download: ${url}\n → ${path.join(cache_dir, 'wallpaper_primary.jpg')}`);
if (url_external) would_run.push(`download: ${url_external}\n → ${path.join(cache_dir, 'wallpaper_external.jpg')}`);
if (imagePath) {
would_run.push(`gsettings set org.gnome.desktop.background picture-uri "file://${expandPath(imagePath)}"`);
} else if (url) {
would_run.push(`gsettings set org.gnome.desktop.background picture-uri "file://${path.join(cache_dir, 'wallpaper_primary.jpg')}"`);
}
if (url_external) {
would_run.push(`(external display: gsettings has no per-display wallpaper support)`);
}
return {
success: true,
linux_test_mode: true,
platform: 'linux',
display,
url: url ?? null,
url_external: url_external ?? null,
would_run
};
} }
return { success: false, error: 'Platform not supported' }; return { success: false, error: 'Platform not supported' };
@@ -212,8 +236,8 @@ export function registerSystemHandlers() {
} }
if (!cmd) return { success: false, error: 'Action not supported' }; if (!cmd) return { success: false, error: 'Action not supported' };
// NOTE: These commands often require root. // NOTE: These commands often require root.
// For a kiosk, you might configure sudoers to allow this specific command without password. // For a kiosk, you might configure sudoers to allow this specific command without password.
return await runExec(cmd); return await runExec(cmd);
}); });
@@ -233,7 +257,7 @@ export function registerSystemHandlers() {
return await runExec(`firefox "${url}"`); return await runExec(`firefox "${url}"`);
} }
} }
// Default system handler // Default system handler
await shell.openExternal(url); await shell.openExternal(url);
return { success: true }; return { success: true };
@@ -242,30 +266,30 @@ export function registerSystemHandlers() {
// 5. Manage Recording (Aperture Wrapper) // 5. Manage Recording (Aperture Wrapper)
ipcMain.handle('native:manage-recording', async (event, { action, options }) => { ipcMain.handle('native:manage-recording', async (event, { action, options }) => {
if (os.platform() !== 'darwin') return { success: false, error: 'Recording only supported on macOS' }; if (os.platform() !== 'darwin') return { success: false, error: 'Recording only supported on macOS' };
// Path to bundled aperture binary // Path to bundled aperture binary
// In dev: ./resources/bin/aperture // In dev: ./resources/bin/aperture
// In prod: process.resourcesPath/bin/aperture // In prod: process.resourcesPath/bin/aperture
const binPath = app.isPackaged const binPath = app.isPackaged
? path.join(process.resourcesPath, 'bin', 'aperture') ? path.join(process.resourcesPath, 'bin', 'aperture')
: path.join(__dirname, '../../resources/bin/aperture'); // Adjust based on structure : path.join(__dirname, '../../resources/bin/aperture'); // Adjust based on structure
if (action === 'start') { if (action === 'start') {
if (recordingProcess) return { success: false, error: 'Recording already in progress' }; if (recordingProcess) return { success: false, error: 'Recording already in progress' };
const { fps = 30, audioDeviceId, output } = options || {}; const { fps = 30, audioDeviceId, output } = options || {};
const cleanOutput = expandPath(output || '~/tmp/recording.mp4'); const cleanOutput = expandPath(output || '~/tmp/recording.mp4');
const args = ['run', '--fps', fps, '--output', cleanOutput]; const args = ['run', '--fps', fps, '--output', cleanOutput];
if (audioDeviceId) args.push('--audio-device-id', audioDeviceId); if (audioDeviceId) args.push('--audio-device-id', audioDeviceId);
// Spawn process // Spawn process
// Note: aperture is a CLI tool. We might need 'aperture' node package or the binary. // Note: aperture is a CLI tool. We might need 'aperture' node package or the binary.
// Assuming binary usage here. // Assuming binary usage here.
try { try {
console.log(`Starting recording: ${binPath} ${args.join(' ')}`); console.log(`Starting recording: ${binPath} ${args.join(' ')}`);
recordingProcess = spawn(binPath, args); recordingProcess = spawn(binPath, args);
recordingProcess.on('error', (err: any) => { recordingProcess.on('error', (err: any) => {
console.error('Recording error:', err); console.error('Recording error:', err);
recordingProcess = null; recordingProcess = null;
@@ -283,7 +307,7 @@ export function registerSystemHandlers() {
} else if (action === 'stop') { } else if (action === 'stop') {
if (!recordingProcess) return { success: false, error: 'No recording in progress' }; if (!recordingProcess) return { success: false, error: 'No recording in progress' };
recordingProcess.kill('SIGINT'); // Send interrupt to stop cleanly recordingProcess.kill('SIGINT'); // Send interrupt to stop cleanly
recordingProcess = null; recordingProcess = null;
return { success: true }; return { success: true };
@@ -297,13 +321,13 @@ export function registerSystemHandlers() {
// 6. Set Display Layout (Displayplacer) // 6. Set Display Layout (Displayplacer)
ipcMain.handle('native:set-display-layout', async (event, { mode, configStr }) => { ipcMain.handle('native:set-display-layout', async (event, { mode, configStr }) => {
if (os.platform() !== 'darwin') return { success: false, error: 'Display control only supported on macOS' }; if (os.platform() !== 'darwin') return { success: false, error: 'Display control only supported on macOS' };
const binPath = app.isPackaged const binPath = app.isPackaged
? path.join(process.resourcesPath, 'bin', 'displayplacer') ? path.join(process.resourcesPath, 'bin', 'displayplacer')
: path.join(__dirname, '../../resources/bin/displayplacer'); : path.join(__dirname, '../../resources/bin/displayplacer');
let cmd = ''; let cmd = '';
if (mode === 'mirror') { if (mode === 'mirror') {
// This usually requires querying current IDs, which is complex. // This usually requires querying current IDs, which is complex.
// If configStr is provided (output of 'displayplacer list'), use it. // If configStr is provided (output of 'displayplacer list'), use it.
@@ -321,7 +345,7 @@ export function registerSystemHandlers() {
if (cmd) { if (cmd) {
return await runExec(cmd); return await runExec(cmd);
} }
return { success: false, error: 'Invalid mode or missing config' }; return { success: false, error: 'Invalid mode or missing config' };
}); });
@@ -341,10 +365,10 @@ export function registerSystemHandlers() {
url: url, url: url,
responseType: 'stream' responseType: 'stream'
}); });
const writer = fs.createWriteStream(destPath); const writer = fs.createWriteStream(destPath);
response.data.pipe(writer); response.data.pipe(writer);
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
writer.on('finish', () => resolve(true)); writer.on('finish', () => resolve(true));
writer.on('error', reject); writer.on('error', reject);
@@ -368,9 +392,9 @@ export function registerSystemHandlers() {
// Real implementation depends on OS and packaging format. // Real implementation depends on OS and packaging format.
// macOS: Mount DMG, copy .app to /Applications? Or Unzip .app? // macOS: Mount DMG, copy .app to /Applications? Or Unzip .app?
// Linux: chmod +x AppImage and move? // Linux: chmod +x AppImage and move?
console.log(`Ready to install update from: ${updateFile}`); console.log(`Ready to install update from: ${updateFile}`);
// For now, just return success so the UI knows we "downloaded" it. // For now, just return success so the UI knows we "downloaded" it.
return { success: true, message: 'Update downloaded/located. Installation logic requires packaging specifics.', downloadedPath: updateFile }; return { success: true, message: 'Update downloaded/located. Installation logic requires packaging specifics.', downloadedPath: updateFile };
}); });