summaryrefslogtreecommitdiffstats
path: root/src/detection/displayserver/displayserver_windows.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/detection/displayserver/displayserver_windows.c')
-rw-r--r--src/detection/displayserver/displayserver_windows.c219
1 files changed, 219 insertions, 0 deletions
diff --git a/src/detection/displayserver/displayserver_windows.c b/src/detection/displayserver/displayserver_windows.c
new file mode 100644
index 0000000..f92c144
--- /dev/null
+++ b/src/detection/displayserver/displayserver_windows.c
@@ -0,0 +1,219 @@
+#include "displayserver.h"
+#include "common/edidHelper.h"
+#include "common/windows/registry.h"
+#include "common/windows/unicode.h"
+
+#include <windows.h>
+#include <shellscalingapi.h>
+
+static inline void freeArgBuffer(FFArgBuffer* buffer) {
+ if (buffer->data) {
+ free(buffer->data);
+ }
+ buffer->data = NULL;
+ buffer->length = 0;
+}
+#define FF_AUTO_FREE_ARG_BUFFER FF_A_CLEANUP(freeArgBuffer)
+
+// http://undoc.airesoft.co.uk/user32.dll/IsThreadDesktopComposited.php
+BOOL WINAPI IsThreadDesktopComposited();
+BOOL WINAPI GetDpiForMonitorInternal(HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT* dpiX, UINT* dpiY);
+
+static void detectDisplays(FFDisplayServerResult* ds) {
+ DISPLAYCONFIG_PATH_INFO paths[128];
+ uint32_t pathCount = ARRAY_SIZE(paths);
+ DISPLAYCONFIG_MODE_INFO modes[256];
+ uint32_t modeCount = ARRAY_SIZE(modes);
+
+ if (QueryDisplayConfig(
+ QDC_ONLY_ACTIVE_PATHS,
+ &pathCount,
+ paths,
+ &modeCount,
+ modes,
+ NULL) == ERROR_SUCCESS) {
+ for (uint32_t i = 0; i < pathCount; ++i) {
+ const DISPLAYCONFIG_PATH_INFO* path = &paths[i];
+ const DISPLAYCONFIG_SOURCE_MODE* sourceMode = &modes[path->sourceInfo.modeInfoIdx].sourceMode;
+
+ FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate();
+ uint32_t physicalWidth = 0, physicalHeight = 0;
+
+ DISPLAYCONFIG_TARGET_DEVICE_NAME targetName = {
+ .header = {
+ .type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME,
+ .size = sizeof(targetName),
+ .adapterId = path->targetInfo.adapterId,
+ .id = path->targetInfo.id,
+ },
+ };
+ FF_AUTO_FREE_ARG_BUFFER FFArgBuffer edid = {};
+ if (DisplayConfigGetDeviceInfo(&targetName.header) == ERROR_SUCCESS) {
+ wchar_t regPath[256] = L"SYSTEM\\CurrentControlSet\\Enum";
+ wchar_t* pRegPath = regPath + strlen("SYSTEM\\CurrentControlSet\\Enum");
+ wchar_t* pDevPath = targetName.monitorDevicePath + strlen("\\\\?");
+ while (*pDevPath && *pDevPath != L'{') {
+ if (*pDevPath == L'#') {
+ *pRegPath = L'\\';
+ } else {
+ *pRegPath = *pDevPath;
+ }
+ ++pRegPath;
+ ++pDevPath;
+ assert(pRegPath < regPath + ARRAY_SIZE(regPath) + strlen("Device Parameters"));
+ }
+ wcscpy(pRegPath, L"Device Parameters");
+
+ FF_AUTO_CLOSE_FD HANDLE hKey = NULL;
+ if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regPath, &hKey, NULL) &&
+ ffRegReadData(hKey, L"EDID", &edid, NULL) &&
+ ffEdidIsValid(edid.data, edid.length)) {
+ ffEdidGetName(edid.data, &name);
+ ffEdidGetPhysicalSize(edid.data, &physicalWidth, &physicalHeight);
+ } else {
+ edid.length = 0;
+ if (targetName.flags.friendlyNameFromEdid) {
+ ffStrbufSetWS(&name, targetName.monitorFriendlyDeviceName);
+ } else {
+ ffStrbufSetWS(&name, targetName.monitorDevicePath);
+ ffStrbufSubstrAfterFirstC(&name, '#');
+ ffStrbufSubstrBeforeFirstC(&name, '#');
+ }
+ }
+ }
+
+ uint32_t width = sourceMode->width;
+ uint32_t height = sourceMode->height;
+ uint32_t rotation;
+ switch (path->targetInfo.rotation) {
+ case DISPLAYCONFIG_ROTATION_ROTATE90:
+ rotation = 90;
+ break;
+ case DISPLAYCONFIG_ROTATION_ROTATE180:
+ rotation = 180;
+ break;
+ case DISPLAYCONFIG_ROTATION_ROTATE270:
+ rotation = 270;
+ break;
+ default:
+ rotation = 0;
+ break;
+ }
+
+ DISPLAYCONFIG_TARGET_PREFERRED_MODE preferredMode = {
+ .header = {
+ .type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE,
+ .size = sizeof(preferredMode),
+ .adapterId = path->targetInfo.adapterId,
+ .id = path->targetInfo.id,
+ }
+ };
+ double preferredRefreshRate = 0;
+ if (DisplayConfigGetDeviceInfo(&preferredMode.header) == ERROR_SUCCESS) {
+ DISPLAYCONFIG_RATIONAL freq = preferredMode.targetMode.targetVideoSignalInfo.vSyncFreq;
+ preferredRefreshRate = freq.Numerator / (double) freq.Denominator;
+ }
+
+ uint32_t systemDpi = 0;
+ HMONITOR hMonitor = MonitorFromPoint(*(POINT*) &sourceMode->position, MONITOR_DEFAULTTONULL);
+ if (hMonitor) {
+ UINT ignored;
+ GetDpiForMonitorInternal(hMonitor, MDT_EFFECTIVE_DPI, &systemDpi, &ignored);
+ }
+
+ if (systemDpi == 0) {
+ HDC hdc = GetDC(NULL);
+ systemDpi = (uint32_t) GetDeviceCaps(hdc, LOGPIXELSX);
+ if (systemDpi == 0) {
+ systemDpi = 96;
+ }
+ ReleaseDC(NULL, hdc);
+ }
+
+ if (path->targetInfo.rotation == DISPLAYCONFIG_ROTATION_ROTATE90 ||
+ path->targetInfo.rotation == DISPLAYCONFIG_ROTATION_ROTATE270) {
+ uint32_t temp = width;
+ width = height;
+ height = temp;
+ }
+
+ FFDisplayResult* display = ffdsAppendDisplay(ds,
+ width,
+ height,
+ path->targetInfo.refreshRate.Numerator / (double) path->targetInfo.refreshRate.Denominator,
+ systemDpi,
+ preferredMode.width,
+ preferredMode.height,
+ preferredRefreshRate,
+ rotation,
+ &name,
+ path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER ? FF_DISPLAY_TYPE_UNKNOWN : path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL || path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED || path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED ? FF_DISPLAY_TYPE_BUILTIN
+ : FF_DISPLAY_TYPE_EXTERNAL,
+ sourceMode->position.x == 0 && sourceMode->position.y == 0,
+ (uintptr_t) hMonitor,
+ physicalWidth,
+ physicalHeight,
+ "GDI");
+
+ if (display) {
+ DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 advColorInfo2 = {
+ .header = {
+ .type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2,
+ .size = sizeof(advColorInfo2),
+ .adapterId = path->targetInfo.adapterId,
+ .id = path->targetInfo.id,
+ }
+ };
+ if (DisplayConfigGetDeviceInfo(&advColorInfo2.header) == ERROR_SUCCESS) {
+ if (advColorInfo2.highDynamicRangeUserEnabled) {
+ display->hdrStatus = FF_DISPLAY_HDR_STATUS_ENABLED;
+ } else if (advColorInfo2.highDynamicRangeSupported) {
+ display->hdrStatus = FF_DISPLAY_HDR_STATUS_SUPPORTED;
+ } else {
+ display->hdrStatus = FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
+ }
+ display->bitDepth = (uint8_t) advColorInfo2.bitsPerColorChannel;
+ } else {
+ DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO advColorInfo = {
+ .header = {
+ .type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO,
+ .size = sizeof(advColorInfo),
+ .adapterId = path->targetInfo.adapterId,
+ .id = path->targetInfo.id,
+ }
+ };
+ if (DisplayConfigGetDeviceInfo(&advColorInfo.header) == ERROR_SUCCESS) {
+ if (advColorInfo.advancedColorEnabled) {
+ display->hdrStatus = FF_DISPLAY_HDR_STATUS_ENABLED;
+ } else if (advColorInfo.advancedColorSupported) {
+ display->hdrStatus = FF_DISPLAY_HDR_STATUS_SUPPORTED;
+ } else {
+ display->hdrStatus = FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
+ }
+ display->bitDepth = (uint8_t) advColorInfo.bitsPerColorChannel;
+ } else {
+ display->hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN;
+ }
+ }
+ if (edid.length > 0) {
+ ffEdidGetSerialAndManufactureDate(edid.data, &display->serial, &display->manufactureYear, &display->manufactureWeek);
+ }
+ display->drrStatus = path->flags & DISPLAYCONFIG_PATH_BOOST_REFRESH_RATE ? FF_DISPLAY_DRR_STATUS_ENABLED : FF_DISPLAY_DRR_STATUS_DISABLED;
+ }
+ }
+ }
+}
+
+void ffConnectDisplayServerImpl(FFDisplayServerResult* ds) {
+ if (IsThreadDesktopComposited()) {
+ ffStrbufSetStatic(&ds->wmProcessName, "dwm.exe");
+ ffStrbufSetStatic(&ds->wmPrettyName, "Desktop Window Manager");
+ } else {
+ // `explorer.exe` only provides a subset of WM functions, as well as the taskbar and desktop icons.
+ // While a window itself is drawn by kernel (GDI). Killing `explorer.exe` won't affect how windows are displayed generally.
+ ffStrbufSetStatic(&ds->wmProcessName, "explorer.exe");
+ ffStrbufSetStatic(&ds->wmPrettyName, "Internal");
+ }
+
+ detectDisplays(ds);
+}