diff --git a/Dotnet/AppApi/Common/AppApiCommon.cs b/Dotnet/AppApi/Common/AppApiCommon.cs
index 305bb9e2..14d9c4ab 100644
--- a/Dotnet/AppApi/Common/AppApiCommon.cs
+++ b/Dotnet/AppApi/Common/AppApiCommon.cs
@@ -149,10 +149,11 @@ namespace VRCX
return output;
}
- public void SetAppLauncherSettings(bool enabled, bool killOnExit)
+ public void SetAppLauncherSettings(bool enabled, bool killOnExit, bool runProcessOnce)
{
AutoAppLaunchManager.Instance.Enabled = enabled;
AutoAppLaunchManager.Instance.KillChildrenOnExit = killOnExit;
+ AutoAppLaunchManager.Instance.RunProcessOnce = runProcessOnce;
}
public string GetFileBase64(string path)
diff --git a/Dotnet/AutoAppLaunchManager.cs b/Dotnet/AutoAppLaunchManager.cs
index 595c9354..cf5054e1 100644
--- a/Dotnet/AutoAppLaunchManager.cs
+++ b/Dotnet/AutoAppLaunchManager.cs
@@ -21,6 +21,7 @@ namespace VRCX
public bool Enabled = false;
/// Whether or not to kill child processes when VRChat closes.
public bool KillChildrenOnExit = true;
+ public bool RunProcessOnce = true;
public readonly string AppShortcutDirectory;
private DateTime startTime = DateTime.Now;
@@ -110,11 +111,15 @@ namespace VRCX
UpdateChildProcesses();
var shortcutFiles = FindShortcutFiles(AppShortcutDirectory);
-
foreach (var file in shortcutFiles)
{
- if (!IsChildProcessRunning(file))
- StartChildProcess(file);
+ if (RunProcessOnce && IsProcessRunning(file))
+ continue;
+
+ if (IsChildProcessRunning(file))
+ continue;
+
+ StartChildProcess(file);
}
if (shortcutFiles.Length == 0)
@@ -273,6 +278,20 @@ namespace VRCX
{
return startedProcesses.ContainsKey(path);
}
+
+ private bool IsProcessRunning(string filePath)
+ {
+ try
+ {
+ var processName = Path.GetFileNameWithoutExtension(filePath);
+ return Process.GetProcessesByName(processName).Length != 0;
+ }
+ catch (Exception ex)
+ {
+ logger.Error(ex, "Error checking if process is running: {0}", filePath);
+ return false;
+ }
+ }
public void Init()
{
diff --git a/src/localization/en/en.json b/src/localization/en/en.json
index 40613289..15d454a4 100644
--- a/src/localization/en/en.json
+++ b/src/localization/en/en.json
@@ -631,7 +631,8 @@
"folder": "Auto-Launch Folder",
"folder_tooltip": "To auto-launch apps with VRChat, place shortcuts in this folder.",
"enable": "Enable",
- "auto_close": "Auto close apps"
+ "auto_close": "Auto close apps",
+ "run_process_once": "Open single instance of app"
},
"cache_debug": {
"header": "VRCX Instance Cache/Debug",
diff --git a/src/stores/settings/advanced.js b/src/stores/settings/advanced.js
index 1a9d4523..82b5a166 100644
--- a/src/stores/settings/advanced.js
+++ b/src/stores/settings/advanced.js
@@ -25,6 +25,7 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => {
avatarRemoteDatabase: true,
enableAppLauncher: true,
enableAppLauncherAutoClose: true,
+ enableAppLauncherRunProcessOnce: true,
screenshotHelper: true,
screenshotHelperModifyFilename: false,
screenshotHelperCopyToClipboard: false,
@@ -58,6 +59,7 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => {
avatarRemoteDatabase,
enableAppLauncher,
enableAppLauncherAutoClose,
+ enableAppLauncherRunProcessOnce,
screenshotHelper,
screenshotHelperModifyFilename,
screenshotHelperCopyToClipboard,
@@ -84,6 +86,10 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => {
configRepository.getBool('VRCX_avatarRemoteDatabase', true),
configRepository.getBool('VRCX_enableAppLauncher', true),
configRepository.getBool('VRCX_enableAppLauncherAutoClose', true),
+ configRepository.getBool(
+ 'VRCX_enableAppLauncherRunProcessOnce',
+ true
+ ),
configRepository.getBool('VRCX_screenshotHelper', true),
configRepository.getBool(
'VRCX_screenshotHelperModifyFilename',
@@ -120,6 +126,7 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => {
state.avatarRemoteDatabase = avatarRemoteDatabase;
state.enableAppLauncher = enableAppLauncher;
state.enableAppLauncherAutoClose = enableAppLauncherAutoClose;
+ state.enableAppLauncherRunProcessOnce = enableAppLauncherRunProcessOnce;
state.screenshotHelper = screenshotHelper;
state.screenshotHelperModifyFilename = screenshotHelperModifyFilename;
state.screenshotHelperCopyToClipboard = screenshotHelperCopyToClipboard;
@@ -167,6 +174,9 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => {
const enableAppLauncherAutoClose = computed(
() => state.enableAppLauncherAutoClose
);
+ const enableAppLauncherRunProcessOnce = computed(
+ () => state.enableAppLauncherRunProcessOnce
+ );
const screenshotHelper = computed(() => state.screenshotHelper);
``;
const screenshotHelperModifyFilename = computed(
@@ -280,6 +290,15 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => {
);
handleSetAppLauncherSettings();
}
+ async function setEnableAppLauncherRunProcessOnce() {
+ state.enableAppLauncherRunProcessOnce =
+ !state.enableAppLauncherRunProcessOnce;
+ await configRepository.setBool(
+ 'VRCX_enableAppLauncherRunProcessOnce',
+ state.enableAppLauncherRunProcessOnce
+ );
+ handleSetAppLauncherSettings();
+ }
async function setScreenshotHelper() {
state.screenshotHelper = !state.screenshotHelper;
await configRepository.setBool(
@@ -440,7 +459,8 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => {
function handleSetAppLauncherSettings() {
AppApi.SetAppLauncherSettings(
state.enableAppLauncher,
- state.enableAppLauncherAutoClose
+ state.enableAppLauncherAutoClose,
+ state.enableAppLauncherRunProcessOnce
);
}
@@ -678,6 +698,7 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => {
avatarRemoteDatabase,
enableAppLauncher,
enableAppLauncherAutoClose,
+ enableAppLauncherRunProcessOnce,
screenshotHelper,
screenshotHelperModifyFilename,
screenshotHelperCopyToClipboard,
@@ -707,6 +728,7 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => {
setAvatarRemoteDatabase,
setEnableAppLauncher,
setEnableAppLauncherAutoClose,
+ setEnableAppLauncherRunProcessOnce,
setScreenshotHelper,
setScreenshotHelperModifyFilename,
setScreenshotHelperCopyToClipboard,
diff --git a/src/types/globals.d.ts b/src/types/globals.d.ts
index 0b3245c7..f9ff0442 100644
--- a/src/types/globals.d.ts
+++ b/src/types/globals.d.ts
@@ -197,7 +197,8 @@ declare global {
GetColourBulk(userIds: string[]): Promise>;
SetAppLauncherSettings(
enabled: boolean,
- killOnExit: boolean
+ killOnExit: boolean,
+ runProcessOnce: boolean
): Promise;
GetFileBase64(path: string): Promise;
diff --git a/src/views/Settings/Settings.vue b/src/views/Settings/Settings.vue
index 1b84af90..6436af51 100644
--- a/src/views/Settings/Settings.vue
+++ b/src/views/Settings/Settings.vue
@@ -1521,6 +1521,11 @@
:value="enableAppLauncherAutoClose"
:long-label="true"
@change="setEnableAppLauncherAutoClose" />
+
@@ -2118,6 +2123,7 @@
avatarRemoteDatabase,
enableAppLauncher,
enableAppLauncherAutoClose,
+ enableAppLauncherRunProcessOnce,
screenshotHelper,
screenshotHelperModifyFilename,
screenshotHelperCopyToClipboard,
@@ -2143,6 +2149,7 @@
setAvatarRemoteDatabase,
setEnableAppLauncher,
setEnableAppLauncherAutoClose,
+ setEnableAppLauncherRunProcessOnce,
setScreenshotHelper,
setScreenshotHelperModifyFilename,
setScreenshotHelperCopyToClipboard,