summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2020-08-18 15:19:41 +0200
committerSimon Rettberg2020-08-18 15:19:41 +0200
commit2128d62a24a1f2a13303296c50de72f4c86ef507 (patch)
tree234567d978d75e6b36f7b260b0ac9e3aa7aec88d
parent[run-virt] Only restart WM if a different one is requested (diff)
downloadmltk-2128d62a24a1f2a13303296c50de72f4c86ef507.tar.gz
mltk-2128d62a24a1f2a13303296c50de72f4c86ef507.tar.xz
mltk-2128d62a24a1f2a13303296c50de72f4c86ef507.zip
[run-virt] openslx.exe: Multi-screen support via WinAPI
Improved retry logic for multi-screen setup. openslx.ini hack for VirtualBox has now been removed.
-rwxr-xr-xcore/modules/run-virt/data/opt/openslx/vmchooser/data/openslx.exebin59904 -> 60416 bytes
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/run-virt.d/setup_virtual_floppy.inc13
-rw-r--r--core/modules/run-virt/winres/src/winres.c112
3 files changed, 104 insertions, 21 deletions
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/openslx.exe b/core/modules/run-virt/data/opt/openslx/vmchooser/data/openslx.exe
index ceaa3159..eb04d9e6 100755
--- a/core/modules/run-virt/data/opt/openslx/vmchooser/data/openslx.exe
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/openslx.exe
Binary files differ
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt.d/setup_virtual_floppy.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt.d/setup_virtual_floppy.inc
index 703d2cd0..54f60e16 100644
--- a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt.d/setup_virtual_floppy.inc
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt.d/setup_virtual_floppy.inc
@@ -105,20 +105,11 @@ setup_virtual_floppy() {
SHARE_NO_HOME_WARN=0
fi
- local resolution=
- # Ugly hack for multi-monitor support with virtualbox.
- # The guest additions properly set up the resolutions of multiple
- # monitor, thus we need to disable the resolution feature of
- # the openslx.exe as it would break what virtualbox did.
- if [ "$PLUGIN_ID" != "virtualbox" ] || [ "$DISPLAY_COUNT" -eq 1 ]; then
- resolution="${RESOLUTIONS}"
- fi
-
cat > "${FLOPPYDIR}/openslx.ini" <<-EOF
[openslx]
username=${UNAME}
- resolution=${resolution%% *}
- resolution2=${resolution}
+ resolution=${RESOLUTIONS%% *}
+ resolution2=${RESOLUTIONS}
createMissingRemap=${SHARE_CREATE_MISSING_REMAP}
remapMode=${SHARE_REMAP_MODE_INI}
homeDrive=${SHARE_HOME_DRIVE}
diff --git a/core/modules/run-virt/winres/src/winres.c b/core/modules/run-virt/winres/src/winres.c
index 2c843c3b..92bf0967 100644
--- a/core/modules/run-virt/winres/src/winres.c
+++ b/core/modules/run-virt/winres/src/winres.c
@@ -51,7 +51,7 @@ static const ssize_t KEYLEN = 16;
static BOOL _debug = FALSE;
-static HINSTANCE hKernel32, hShell32;
+static HINSTANCE hKernel32, hShell32, hUser32;
static OSVERSIONINFO winVer;
static BOOL shareFileOk = FALSE;
static netdrive_t drives[DRIVEMAX];
@@ -424,6 +424,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
if (hShell32 == NULL) {
alog("Cannot load shell32.dll");
}
+ hUser32 = LoadLibraryW(L"user32.dll");
+ if (hUser32 == NULL) {
+ alog("Cannot load user32.dll");
+ }
winVer.dwOSVersionInfoSize = sizeof(winVer);
BOOL retVer = GetVersionEx(&winVer);
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
@@ -499,6 +503,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
}
FreeLibrary(hKernel32);
FreeLibrary(hShell32);
+ FreeLibrary(hUser32);
return 0;
}
@@ -596,11 +601,20 @@ static void setPowerState()
}
}
+typedef LONG (WINAPI *CDSTYPE)(LPCWSTR, PDEVMODEW, HWND, DWORD, LPVOID);
+typedef BOOL (WINAPI *EDDTYPE)(LPCWSTR, DWORD, PDISPLAY_DEVICEW, DWORD);
+
+struct resolution {
+ long int w, h;
+};
+
+static BOOL setResWinMulti(struct resolution *res, int nres);
+static BOOL setResWinLegacy(struct resolution *res, int nres);
+
static int setResolution()
{
- int ret;
static int nres = 0;
- static struct { long int w, h; } res[16];
+ static struct resolution res[16];
if (nres == -1) // We've been here before and consider config invalid, or are done
return 0;
if (nres == 0) {
@@ -665,12 +679,85 @@ static int setResolution()
alog("VmwareRes: CreateProcess failed (%d)", (int)GetLastError());
} else if (ret == -2) {
alog("VmwareRes: GetExitCode failed (%d)", (int)GetLastError());
- } else {
+ } else if (ret == 0) {
return 0;
}
}
// Use WinAPI as fallback
- // TODO: Multi-Screen (once it really matters)
+ if (setResWinMulti(res, nres))
+ return 0;
+ // Legacy WinAPI (single screen only)
+ if (setResWinLegacy(res, nres))
+ return 0;
+ return 1;
+}
+
+/*
+ * This seems to be broken with VirtualBox, and I'm not sure whether
+ * I'm doing something wrong here. For a dualscreen setup, this
+ * returns two devices, but only the first one has a monitor, i.e.
+ * the inner loop never runs for the second device.
+ * I'm still leaving this here as a starting-point for future
+ * changes or new virtualizers.
+ */
+static BOOL setResWinMulti(struct resolution *res, int nres)
+{
+ if (hUser32 == NULL)
+ return FALSE;
+ CDSTYPE cdsEx = NULL;
+ EDDTYPE edd = NULL;
+ cdsEx = (CDSTYPE)GetProcAddress(hUser32, "ChangeDisplaySettingsExW");
+ edd = (EDDTYPE)GetProcAddress(hUser32, "EnumDisplayDevicesW");
+ if (cdsEx == NULL || edd == NULL)
+ return FALSE;
+ DISPLAY_DEVICEW ddev = { .cb = sizeof(ddev) };
+ DWORD devNum = 0;
+ int ires = 0;
+ int chret;
+ //alog("Trying multiscreen");
+ while (edd(NULL, devNum++, &ddev, 0)) {
+ //wlog(L"Have device %s (%s)", ddev.DeviceName, ddev.DeviceString);
+ DISPLAY_DEVICEW screen = { .cb = sizeof(screen) };
+ DWORD screenNum = 0;
+ long int sx = 0;
+ while (edd(ddev.DeviceName, screenNum++, &screen, 0)) {
+ DEVMODEW mode = { .dmSize = sizeof(mode) };
+ EnumDisplaySettingsW(screen.DeviceName, ENUM_CURRENT_SETTINGS, &mode);
+ //wlog(L"%s (%s) currently %dx%d+%d+%d", screen.DeviceName, screen.DeviceString, mode.dmPelsWidth, mode.dmPelsHeight, mode.dmPosition.x, mode.dmPosition.y);
+ if (ires < nres) {
+ // Enable
+ mode.dmPelsWidth = res[ires].w;
+ mode.dmPelsHeight = res[ires].h;
+ mode.dmPosition.x = sx;
+ mode.dmPosition.y = 0;
+ sx += mode.dmPelsWidth;
+ mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION;
+ } else {
+ // Disable
+ mode.dmPelsWidth = mode.dmPelsHeight = 0;
+ mode.dmFields = DM_POSITION;
+ }
+ //wlog(L"New: %dx%d+%d+%d", mode.dmPelsWidth, mode.dmPelsHeight, mode.dmPosition.x, mode.dmPosition.y);
+ chret = cdsEx(screen.DeviceName, &mode, 0, (CDS_UPDATEREGISTRY | CDS_NORESET), NULL);
+ if (chret != DISP_CHANGE_SUCCESSFUL) {
+ //alog("Returned %d", chret);
+ }
+ ires++;
+ screen = (DISPLAY_DEVICEW){ .cb = sizeof(DISPLAY_DEVICEW) };
+ }
+ ddev = (DISPLAY_DEVICEW){ .cb = sizeof(DISPLAY_DEVICEW) };
+ }
+ chret = cdsEx(NULL, NULL, NULL, 0, NULL);
+ if (chret != DISP_CHANGE_SUCCESSFUL) {
+ alog("Final multiscreen change display call: %d", chret);
+ return FALSE;
+ }
+ return ires >= nres; // Did we find enough (virtual) screens?
+}
+
+static BOOL setResWinLegacy(struct resolution *res, int nres)
+{
+ // Legacy single screen
DEVMODE mode = { .dmSize = sizeof(mode) };
// MSDN recommends to fill the struct first by querying....
int query = EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &mode);
@@ -678,7 +765,7 @@ static int setResolution()
mode.dmPelsWidth = res[0].w;
mode.dmPelsHeight = res[0].h;
mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
- ret = ChangeDisplaySettings(&mode, CDS_GLOBAL | CDS_UPDATEREGISTRY);
+ int ret = ChangeDisplaySettings(&mode, CDS_GLOBAL | CDS_UPDATEREGISTRY);
if (ret != DISP_CHANGE_SUCCESSFUL) {
ret = ChangeDisplaySettings(&mode, CDS_GLOBAL);
}
@@ -688,15 +775,20 @@ static int setResolution()
if (ret != DISP_CHANGE_SUCCESSFUL) {
ret = ChangeDisplaySettings(&mode, 0);
}
+ static int fails = 0;
if (ret != DISP_CHANGE_SUCCESSFUL) {
- static int fails = 0;
if (++fails == 5) {
- alog("Fehler beim Setzen der Auflösung: %d (soll: 0) / %d ( soll: !0) - Zielaufloesung: %ld * %ld",
+ alog("Fehler beim Setzen der Auflösung: %d (soll: 0) / %d ( soll: !0) - Zielauflösung: %ld * %ld",
ret, query, res[0].w, res[0].h);
}
- return 1;
+ return FALSE;
}
- return 0;
+ if (nres > 1) {
+ // Fake a failure since we want the other methods to be retried
+ // If we get called repeatedly, eventually return TRUE to make it stop.
+ return fails++ > 4;
+ }
+ return TRUE;
}
static int optimizeForRemote()