fix: resolve Arch/Wayland tray issues by enabling Ozone Wayland and hardening icon resolution paths

This commit is contained in:
2026-02-21 15:23:57 +01:00
parent 3f4b1abc4b
commit 4c77cb0a56

View File

@@ -16,6 +16,12 @@ const isDev = !app.isPackaged;
app.name = "Ultimate Ban Tracker";
// Force Wayland/Ozone support if on Linux
if (process.platform === 'linux') {
app.commandLine.appendSwitch('enable-features', 'UseOzonePlatform');
app.commandLine.appendSwitch('ozone-platform', 'wayland');
}
// Load environment variables
dotenv.config({ path: path.join(app.getAppPath(), '..', '.env') });
@@ -89,35 +95,64 @@ const initBackend = () => {
// --- System Tray ---
const createTray = () => {
console.log('[Tray] Initializing...');
const possiblePaths = [
'/usr/share/pixmaps/ultimate-ban-tracker.png',
path.join(process.resourcesPath, 'assets-build', 'icon.png'),
path.join(app.getAppPath(), 'assets-build', 'icon.png'),
path.join(__dirname, '..', 'assets-build', 'icon.png')
'/usr/share/pixmaps/ultimate-ban-tracker.png', // Priority 1: System installed
path.join(process.resourcesPath, 'assets-build', 'icon.png'), // Priority 2: Unpacked resources
path.join(app.getAppPath(), 'assets-build', 'icon.png'), // Priority 3: Internal ASAR (Fallback)
path.join(__dirname, '..', 'assets-build', 'icon.png') // Priority 4: Dev
];
let iconPath = '';
for (const p of possiblePaths) { if (p && fs.existsSync(p)) { iconPath = p; break; } }
for (const p of possiblePaths) {
console.log(`[Tray] Checking path: ${p}`);
if (p && fs.existsSync(p)) {
iconPath = p;
console.log(`[Tray] Found icon at: ${p}`);
break;
}
}
if (!iconPath) { try { tray = new Tray(nativeImage.createEmpty()); } catch (e) {} return; }
if (!iconPath) {
console.warn('[Tray] FAILED: No icon file found on disk. Using empty fallback.');
try { tray = new Tray(nativeImage.createEmpty()); } catch (e) {}
} else {
try {
const icon = nativeImage.createFromPath(iconPath).resize({ width: 16, height: 16 });
tray = new Tray(icon);
console.log('[Tray] Tray object created successfully');
} catch (e: any) {
console.error(`[Tray] Failed to create Tray object: ${e.message}`);
return;
}
}
try {
const icon = nativeImage.createFromPath(iconPath).resize({ width: 16, height: 16 });
tray = new Tray(icon);
if (tray) {
tray.setToolTip('Ultimate Ban Tracker');
if (process.platform === 'linux') tray.setIgnoreMouseEvents(false);
tray.on('click', () => { if (mainWindow) { mainWindow.show(); mainWindow.focus(); } });
// Initial menu build
updateTrayMenu();
const config = store.get('serverConfig');
if (config?.theme) setAppIcon(config.theme);
} catch (e: any) { console.error(`[Tray] Error: ${e.message}`); }
}
};
const updateTrayMenu = () => {
if (!tray) return;
if (!tray) {
console.warn('[Tray] Cannot update menu: Tray is null');
return;
}
const accounts = store.get('accounts') as Account[];
const config = store.get('serverConfig');
const contextMenu = Menu.buildFromTemplate([
console.log(`[Tray] Building menu with ${accounts.length} accounts...`);
const menuTemplate: any[] = [
{ label: `Ultimate Ban Tracker v${app.getVersion()}`, enabled: false },
{ type: 'separator' },
{
@@ -125,34 +160,83 @@ const updateTrayMenu = () => {
submenu: accounts.length > 0 ? accounts.map(acc => ({
label: `${acc.personaName} ${acc.loginName ? `(${acc.loginName})` : ''}`,
enabled: !!acc.loginName,
click: () => handleSwitchAccount(acc.loginName)
})) : [{ label: 'No accounts found', enabled: false }]
click: () => {
console.log(`[Tray] Switching to account: ${acc.loginName}`);
handleSwitchAccount(acc.loginName);
}
})) : [{ label: 'No accounts tracked', enabled: false }]
},
{
label: 'Sync Now',
enabled: !!config?.enabled,
click: () => {
console.log('[Tray] Manual sync requested');
syncAccounts(true);
}
},
{ label: 'Sync Now', enabled: !!config?.enabled, click: () => syncAccounts(true) },
{ type: 'separator' },
{ label: 'Show Dashboard', click: () => { if (mainWindow) { mainWindow.show(); mainWindow.focus(); } } },
{ label: 'Quit', click: () => {
(app as any).isQuitting = true;
if (tray) tray.destroy();
app.quit();
} }
]);
tray.setContextMenu(contextMenu);
{
label: 'Show Dashboard',
click: () => {
console.log('[Tray] Showing dashboard');
if (mainWindow) {
mainWindow.show();
mainWindow.focus();
}
}
},
{
label: 'Quit',
click: () => {
console.log('[Tray] Quitting application via menu');
(app as any).isQuitting = true;
if (tray) tray.destroy();
app.quit();
}
}
];
try {
const contextMenu = Menu.buildFromTemplate(menuTemplate);
tray.setContextMenu(contextMenu);
console.log('[Tray] Menu updated and attached');
} catch (e: any) {
console.error(`[Tray] Failed to build or set context menu: ${e.message}`);
}
};
const setAppIcon = (themeName: string = 'steam') => {
console.log(`[AppIcon] Setting icon for theme: ${themeName}`);
const possiblePaths = [
path.join(__dirname, '..', 'assets-build', 'icons', `${themeName}.svg`),
path.join(app.getAppPath(), 'assets-build', 'icons', `${themeName}.svg`),
path.join(__dirname, '..', 'assets-build', 'icons', `${themeName}.svg`),
path.join(process.resourcesPath, 'assets-build', 'icons', `${themeName}.svg`),
'/usr/share/pixmaps/ultimate-ban-tracker.png'
];
let iconPath = '';
for (const p of possiblePaths) { if (fs.existsSync(p)) { iconPath = p; break; } }
if (!iconPath) return;
const icon = nativeImage.createFromPath(iconPath);
if (tray) tray.setImage(icon.resize({ width: 16, height: 16 }));
if (mainWindow) mainWindow.setIcon(icon);
updateTrayMenu();
for (const p of possiblePaths) { if (p && fs.existsSync(p)) { iconPath = p; break; } }
if (!iconPath) {
console.warn(`[AppIcon] No themed icon found for ${themeName}`);
return;
}
try {
const icon = nativeImage.createFromPath(iconPath);
if (tray) {
tray.setImage(icon.resize({ width: 16, height: 16 }));
console.log('[AppIcon] Tray icon updated');
}
if (mainWindow) {
mainWindow.setIcon(icon);
console.log('[AppIcon] Window icon updated');
}
// Re-build menu to ensure everything is consistent
updateTrayMenu();
} catch (e: any) {
console.error(`[AppIcon] Failed to apply themed icon: ${e.message}`);
}
};
// --- Steam Logic ---