Add app config to set virtual display as primary

This commit is contained in:
Yukino Song
2024-08-19 08:29:10 +08:00
parent 25eb5c8714
commit e0924e3a21
7 changed files with 75 additions and 15 deletions
+19 -1
View File
@@ -36,6 +36,24 @@ LONG changeDisplaySettings(const wchar_t* deviceName, int width, int height, int
return 0; return 0;
} }
std::wstring getPrimaryDisplay() {
DISPLAY_DEVICEW displayDevice;
displayDevice.cb = sizeof(DISPLAY_DEVICE);
std::wstring primaryDeviceName;
int deviceIndex = 0;
while (EnumDisplayDevicesW(NULL, deviceIndex, &displayDevice, 0)) {
if (displayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
primaryDeviceName = displayDevice.DeviceName;
break;
}
deviceIndex++;
}
return primaryDeviceName;
}
bool setPrimaryDisplay(const wchar_t* primaryDeviceName) { bool setPrimaryDisplay(const wchar_t* primaryDeviceName) {
DEVMODEW primaryDevMode{}; DEVMODEW primaryDevMode{};
if (!getDeviceSettings(primaryDeviceName, primaryDevMode)) { if (!getDeviceSettings(primaryDeviceName, primaryDevMode)) {
@@ -178,7 +196,7 @@ std::wstring createVirtualDisplay(
retryInterval *= 2; retryInterval *= 2;
} }
wprintf(L"[SUDOVDA] Virtual display added successfully: %ws\n", deviceName); wprintf(L"[SUDOVDA] Virtual display added successfully: %ls\n", deviceName);
printf("[SUDOVDA] Configuration: W: %d, H: %d, FPS: %d\n", width, height, fps); printf("[SUDOVDA] Configuration: W: %d, H: %d, FPS: %d\n", width, height, fps);
return std::wstring(deviceName); return std::wstring(deviceName);
+1
View File
@@ -13,6 +13,7 @@ namespace VDISPLAY {
LONG getDeviceSettings(const wchar_t* deviceName, DEVMODEW& devMode); LONG getDeviceSettings(const wchar_t* deviceName, DEVMODEW& devMode);
LONG changeDisplaySettings(const wchar_t* deviceName, int width, int height, int refresh_rate); LONG changeDisplaySettings(const wchar_t* deviceName, int width, int height, int refresh_rate);
std::wstring getPrimaryDisplay();
bool setPrimaryDisplay(const wchar_t* primaryDeviceName); bool setPrimaryDisplay(const wchar_t* primaryDeviceName);
bool startPingThread(); bool startPingThread();
+34 -8
View File
@@ -208,15 +208,15 @@ namespace proc {
#ifdef _WIN32 #ifdef _WIN32
if (launch_session->virtual_display || _app.virtual_display) { if (launch_session->virtual_display || _app.virtual_display) {
// Mark as no vdisplay by default
launch_session->virtual_display = false;
if (!vdisplayDriverInitialized) { if (!vdisplayDriverInitialized) {
// Try init driver again // Try init driver again
vdisplayDriverInitialized = VDISPLAY::openVDisplayDevice(); vdisplayDriverInitialized = VDISPLAY::openVDisplayDevice();
} }
if (vdisplayDriverInitialized) { if (vdisplayDriverInitialized) {
std::wstring vdisplay_name = VDISPLAY::createVirtualDisplay( std::wstring prevPrimaryDisplayName = VDISPLAY::getPrimaryDisplay();
std::wstring vdisplayName = VDISPLAY::createVirtualDisplay(
launch_session->unique_id.c_str(), launch_session->unique_id.c_str(),
launch_session->device_name.c_str(), launch_session->device_name.c_str(),
_app.name.c_str(), _app.name.c_str(),
@@ -225,11 +225,33 @@ namespace proc {
launch_session->fps, launch_session->fps,
launch_session->display_guid launch_session->display_guid
); );
// Set virtual_display to true when everything went fine
launch_session->virtual_display = true;
VDISPLAY::changeDisplaySettings(vdisplay_name.c_str(), launch_session->width, launch_session->height, launch_session->fps); std::wstring currentPrimaryDisplayName = VDISPLAY::getPrimaryDisplay();
VDISPLAY::setPrimaryDisplay(vdisplay_name.c_str());
// Apply display settings
VDISPLAY::changeDisplaySettings(vdisplayName.c_str(), launch_session->width, launch_session->height, launch_session->fps);
// Determine if we need to set the virtual display as primary
bool shouldSetPrimary = false;
if (launch_session->virtual_display || _app.virtual_display_primary) {
shouldSetPrimary = (currentPrimaryDisplayName != vdisplayName);
} else {
shouldSetPrimary = (currentPrimaryDisplayName != prevPrimaryDisplayName);
}
// Set primary display if needed
if (shouldSetPrimary) {
VDISPLAY::setPrimaryDisplay(
(launch_session->virtual_display || _app.virtual_display_primary)
? vdisplayName.c_str()
: prevPrimaryDisplayName.c_str()
);
}
// Set virtual_display to true when everything went fine
this->virtual_display = true;
this->display_name = platf::to_utf8(vdisplayName);
} }
} }
#endif #endif
@@ -369,7 +391,7 @@ namespace proc {
_pipe.reset(); _pipe.reset();
#ifdef _WIN32 #ifdef _WIN32
if (vdisplayDriverInitialized && _launch_session && _launch_session->virtual_display) { if (vdisplayDriverInitialized && _launch_session && this->virtual_display) {
VDISPLAY::removeVirtualDisplay(_launch_session->display_guid); VDISPLAY::removeVirtualDisplay(_launch_session->display_guid);
} }
#endif #endif
@@ -387,6 +409,7 @@ namespace proc {
_app_id = -1; _app_id = -1;
display_name.clear(); display_name.clear();
_launch_session.reset(); _launch_session.reset();
virtual_display = false;
} }
const std::vector<ctx_t> & const std::vector<ctx_t> &
@@ -640,6 +663,7 @@ namespace proc {
ctx.name = "Virtual Display"; ctx.name = "Virtual Display";
ctx.image_path = parse_env_val(this_env, "virtual_desktop.png"); ctx.image_path = parse_env_val(this_env, "virtual_desktop.png");
ctx.virtual_display = true; ctx.virtual_display = true;
ctx.virtual_display_primary = true;
ctx.elevated = false; ctx.elevated = false;
ctx.auto_detach = true; ctx.auto_detach = true;
@@ -676,6 +700,7 @@ namespace proc {
auto wait_all = app_node.get_optional<bool>("wait-all"s); auto wait_all = app_node.get_optional<bool>("wait-all"s);
auto exit_timeout = app_node.get_optional<int>("exit-timeout"s); auto exit_timeout = app_node.get_optional<int>("exit-timeout"s);
auto virtual_display = app_node.get_optional<bool>("virtual-display"); auto virtual_display = app_node.get_optional<bool>("virtual-display");
auto virtual_display_primary = app_node.get_optional<bool>("virtual-display-primary");
std::vector<proc::cmd_t> prep_cmds; std::vector<proc::cmd_t> prep_cmds;
if (!exclude_global_prep.value_or(false)) { if (!exclude_global_prep.value_or(false)) {
@@ -744,6 +769,7 @@ namespace proc {
ctx.wait_all = wait_all.value_or(true); ctx.wait_all = wait_all.value_or(true);
ctx.exit_timeout = std::chrono::seconds { exit_timeout.value_or(5) }; ctx.exit_timeout = std::chrono::seconds { exit_timeout.value_or(5) };
ctx.virtual_display = virtual_display.value_or(false); ctx.virtual_display = virtual_display.value_or(false);
ctx.virtual_display_primary = virtual_display_primary.value_or(true);
auto possible_ids = calculate_app_id(name, ctx.image_path, i++); auto possible_ids = calculate_app_id(name, ctx.image_path, i++);
if (ids.count(std::get<0>(possible_ids)) == 0) { if (ids.count(std::get<0>(possible_ids)) == 0) {
+2
View File
@@ -65,6 +65,7 @@ namespace proc {
bool auto_detach; bool auto_detach;
bool wait_all; bool wait_all;
bool virtual_display; bool virtual_display;
bool virtual_display_primary;
std::chrono::seconds exit_timeout; std::chrono::seconds exit_timeout;
}; };
@@ -73,6 +74,7 @@ namespace proc {
KITTY_DEFAULT_CONSTR_MOVE_THROW(proc_t) KITTY_DEFAULT_CONSTR_MOVE_THROW(proc_t)
std::string display_name; std::string display_name;
bool virtual_display;
proc_t( proc_t(
boost::process::environment &&env, boost::process::environment &&env,
-2
View File
@@ -249,8 +249,6 @@ namespace system_tray {
return; return;
} }
printf("Tray playing: %s\n", app_name.c_str());
tray.notification_title = NULL; tray.notification_title = NULL;
tray.notification_text = NULL; tray.notification_text = NULL;
tray.notification_cb = NULL; tray.notification_cb = NULL;
+16 -3
View File
@@ -229,12 +229,19 @@
<div class="form-text">{{ $t('apps.wait_all_desc') }}</div> <div class="form-text">{{ $t('apps.wait_all_desc') }}</div>
</div> </div>
<!-- use virtual display --> <!-- use virtual display -->
<div class="mb-3 form-check"> <div class="mb-3 form-check" v-if="platform === 'windows'">
<label for="virtualDisplay" class="form-check-label">{{ $t('apps.virtual_display') }}</label> <label for="virtualDisplay" class="form-check-label">{{ $t('apps.virtual_display') }}</label>
<input type="checkbox" class="form-check-input" id="virtualDisplay" v-model="editForm['virtual-display']" <input type="checkbox" class="form-check-input" id="virtualDisplay" v-model="editForm['virtual-display']"
true-value="true" false-value="false" /> true-value="true" false-value="false" />
<div class="form-text">{{ $t('apps.virtual_display_desc') }}</div> <div class="form-text">{{ $t('apps.virtual_display_desc') }}</div>
</div> </div>
<!-- set virtual display to primary -->
<div class="mb-3 form-check" v-if="platform === 'windows' && editForm['virtual-display'] == 'true'">
<label for="virtualDisplayPrimary" class="form-check-label">{{ $t('apps.virtual_display_primary') }}</label>
<input type="checkbox" class="form-check-input" id="virtualDisplayPrimary" v-model="editForm['virtual-display-primary']"
true-value="true" false-value="false" />
<div class="form-text">{{ $t('apps.virtual_display_primary_desc') }}</div>
</div>
<!-- exit timeout --> <!-- exit timeout -->
<div class="mb-3"> <div class="mb-3">
<label for="exitTimeout" class="form-label">{{ $t('apps.exit_timeout') }}</label> <label for="exitTimeout" class="form-label">{{ $t('apps.exit_timeout') }}</label>
@@ -373,11 +380,13 @@
import { createApp } from 'vue' import { createApp } from 'vue'
import { initApp } from './init' import { initApp } from './init'
import Navbar from './Navbar.vue' import Navbar from './Navbar.vue'
import PlatformLayout from './PlatformLayout.vue'
import { Dropdown } from 'bootstrap/dist/js/bootstrap' import { Dropdown } from 'bootstrap/dist/js/bootstrap'
const app = createApp({ const app = createApp({
components: { components: {
Navbar Navbar,
PlatformLayout
}, },
data() { data() {
return { return {
@@ -417,7 +426,8 @@
"exit-timeout": 5, "exit-timeout": 5,
"prep-cmd": [], "prep-cmd": [],
detached: [], detached: [],
"image-path": "" "image-path": "",
"virtual-display-primary": true
}; };
this.editForm.index = -1; this.editForm.index = -1;
this.showEditForm = true; this.showEditForm = true;
@@ -443,6 +453,9 @@
if (this.editForm["exit-timeout"] === undefined) { if (this.editForm["exit-timeout"] === undefined) {
this.editForm["exit-timeout"] = 5; this.editForm["exit-timeout"] = 5;
} }
if (typeof this.editForm["virtual-display-primary"] === "undefined") {
this.editForm["virtual-display-primary"] = true;
}
this.showEditForm = true; this.showEditForm = true;
}, },
showDeleteForm(id) { showDeleteForm(id) {
@@ -81,7 +81,9 @@
"working_dir": "Working Directory", "working_dir": "Working Directory",
"working_dir_desc": "The working directory that should be passed to the process. For example, some applications use the working directory to search for configuration files. If not set, Apollo will default to the parent directory of the command", "working_dir_desc": "The working directory that should be passed to the process. For example, some applications use the working directory to search for configuration files. If not set, Apollo will default to the parent directory of the command",
"virtual_display": "Use Virtual Display", "virtual_display": "Use Virtual Display",
"virtual_display_desc": "Always use Virtual Display on this app, overriding client request." "virtual_display_desc": "Always use Virtual Display on this app, overriding client request. Please make sure the SudoVDA driver is installed and enabled.",
"virtual_display_primary": "Set Virtual Display as Primary Display",
"virtual_display_primary_desc": "Automatically set the Virtual Display as Primary Display when the app starts. (Recommended to keep on)"
}, },
"config": { "config": {
"adapter_name": "Adapter Name", "adapter_name": "Adapter Name",