Fix launchcommands on Linux (#1352)

* feat: expose IPC listener to electron world

* feat: add listener + rouing to old function + remove old functions

* feat: register vrcx prefix + route launch arguments to electron
This commit is contained in:
kubectl
2025-08-27 02:52:17 +02:00
committed by GitHub
parent d0eca482fa
commit 21dcc51e83
4 changed files with 56 additions and 19 deletions

View File

@@ -14,8 +14,19 @@ const { spawn, spawnSync } = require('child_process');
const fs = require('fs'); const fs = require('fs');
const https = require('https'); const https = require('https');
const VRCX_URI_PREFIX = "vrcx"
//app.disableHardwareAcceleration(); //app.disableHardwareAcceleration();
if (process.defaultApp) {
if (process.argv.length >= 2) {
app.setAsDefaultProtocolClient(VRCX_URI_PREFIX, process.execPath, [path.resolve(process.argv[1])])
} else {
app.setAsDefaultProtocolClient(VRCX_URI_PREFIX)
}
}
if (process.platform === 'linux') { if (process.platform === 'linux') {
// Include bundled .NET runtime // Include bundled .NET runtime
const bundledDotNetPath = path.join( const bundledDotNetPath = path.join(
@@ -105,6 +116,7 @@ ipcMain.handle('callDotNetMethod', (event, className, methodName, args) => {
return interopApi.callMethod(className, methodName, args); return interopApi.callMethod(className, methodName, args);
}); });
/** @type {BrowserWindow} */
let mainWindow = undefined; let mainWindow = undefined;
const VRCXStorage = interopApi.getDotNetObject('VRCXStorage'); const VRCXStorage = interopApi.getDotNetObject('VRCXStorage');
@@ -112,6 +124,26 @@ const hasAskedToMoveAppImage =
VRCXStorage.Get('VRCX_HasAskedToMoveAppImage') === 'true'; VRCXStorage.Get('VRCX_HasAskedToMoveAppImage') === 'true';
let isCloseToTray = VRCXStorage.Get('VRCX_CloseToTray') === 'true'; let isCloseToTray = VRCXStorage.Get('VRCX_CloseToTray') === 'true';
const gotTheLock = app.requestSingleInstanceLock()
const strip_vrcx_prefix_regex = new RegExp("^" + VRCX_URI_PREFIX + ":\/\/")
if (!gotTheLock) {
app.quit()
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
if (mainWindow && commandLine.length >= 2) {
mainWindow.webContents.send('launch-command', commandLine.pop().trim().replace(strip_vrcx_prefix_regex, ""))
}
})
app.on('open-url', (event, url) => {
if (mainWindow && url) {
mainWindow.webContents.send('launch-command', url.replace(strip_vrcx_prefix_regex, ""))
}
})
}
ipcMain.handle('applyWindowSettings', (event, position, size, state) => { ipcMain.handle('applyWindowSettings', (event, position, size, state) => {
if (position) { if (position) {
mainWindow.setPosition(parseInt(position.x), parseInt(position.y)); mainWindow.setPosition(parseInt(position.x), parseInt(position.y));
@@ -270,7 +302,7 @@ function createWindow() {
icon: path.join(rootDir, 'VRCX.png'), icon: path.join(rootDir, 'VRCX.png'),
autoHideMenuBar: true, autoHideMenuBar: true,
webPreferences: { webPreferences: {
preload: path.join(__dirname, 'preload.js') preload: path.join(__dirname, 'preload.js'),
} }
}); });
applyWindowState(); applyWindowState();

View File

@@ -19,6 +19,10 @@ contextBridge.exposeInMainWorld('interopApi', {
} }
}); });
const validChannels = ['launch-command']
contextBridge.exposeInMainWorld('electron', { contextBridge.exposeInMainWorld('electron', {
openFileDialog: () => ipcRenderer.invoke('dialog:openFile'), openFileDialog: () => ipcRenderer.invoke('dialog:openFile'),
openDirectoryDialog: () => ipcRenderer.invoke('dialog:openDirectory'), openDirectoryDialog: () => ipcRenderer.invoke('dialog:openDirectory'),
@@ -33,6 +37,15 @@ contextBridge.exposeInMainWorld('electron', {
restartApp: () => ipcRenderer.invoke('app:restart'), restartApp: () => ipcRenderer.invoke('app:restart'),
getWristOverlayWindow: () => ipcRenderer.invoke('app:getWristOverlayWindow'), getWristOverlayWindow: () => ipcRenderer.invoke('app:getWristOverlayWindow'),
getHmdOverlayWindow: () => ipcRenderer.invoke('app:getHmdOverlayWindow'), getHmdOverlayWindow: () => ipcRenderer.invoke('app:getHmdOverlayWindow'),
updateVr: (active, hmdOverlay, wristOverlay, menuButton, overlayHand) => updateVr: (active, hmdOverlay, wristOverlay, menuButton, overlayHand) =>
ipcRenderer.invoke('app:updateVr', active, hmdOverlay, wristOverlay, menuButton, overlayHand) ipcRenderer.invoke('app:updateVr', active, hmdOverlay, wristOverlay, menuButton, overlayHand),
ipcRenderer: {
on(channel, func) {
if (validChannels.includes(channel)) {
console.log("contextBridge", channel, func)
ipcRenderer.on(channel, (event, ...args) => func(...args));
}
},
}
}); });

View File

@@ -516,12 +516,6 @@ export const useVrcxStore = defineStore('Vrcx', () => {
case 'MsgPing': case 'MsgPing':
state.externalNotifierVersion = data.version; state.externalNotifierVersion = data.version;
break; break;
case 'LaunchCommand':
eventLaunchCommand(data.command);
break;
case 'VRCXLaunch':
console.log('VRCXLaunch:', data);
break;
default: default:
console.log('IPC:', data); console.log('IPC:', data);
} }
@@ -538,22 +532,17 @@ export const useVrcxStore = defineStore('Vrcx', () => {
watch( watch(
() => watchState.isLoggedIn, () => watchState.isLoggedIn,
(isLoggedIn) => { (_isLoggedIn) => {
state.isRegistryBackupDialogVisible = false; state.isRegistryBackupDialogVisible = false;
if (isLoggedIn) {
startupLaunchCommand();
}
}, },
{ flush: 'sync' } { flush: 'sync' }
); );
async function startupLaunchCommand() { window.electron.ipcRenderer.on('launch-command', (command) => {
const command = await AppApi.GetLaunchCommand();
if (command) { if (command) {
eventLaunchCommand(command); eventLaunchCommand(command)
} }
} })
function eventLaunchCommand(input) { function eventLaunchCommand(input) {
if (!watchState.isLoggedIn) { if (!watchState.isLoggedIn) {
return; return;
@@ -766,8 +755,8 @@ export const useVrcxStore = defineStore('Vrcx', () => {
maxTableSize, maxTableSize,
showConsole, showConsole,
clearVRCXCache, clearVRCXCache,
startupLaunchCommand,
eventVrcxMessage, eventVrcxMessage,
eventLaunchCommand,
showRegistryBackupDialog, showRegistryBackupDialog,
checkAutoBackupRestoreVrcRegistry, checkAutoBackupRestoreVrcRegistry,
tryAutoBackupVrcRegistry, tryAutoBackupVrcRegistry,

View File

@@ -62,6 +62,9 @@ declare global {
menuButton: bool, menuButton: bool,
overlayHand: int overlayHand: int
) => Promise<void>; ) => Promise<void>;
ipcRenderer: {
on(channel: String, func: (...args: unknown[]) => void)
};
}; };
__APP_GLOBALS__: AppGlobals; __APP_GLOBALS__: AppGlobals;
} }