From af22df199750ea57813f1aaba6049358644568ba Mon Sep 17 00:00:00 2001 From: ZGaetano Date: Wed, 6 May 2026 19:49:40 -0400 Subject: [PATCH] =?UTF-8?q?Add=20displayinfo=5Flinux.cpp=20=E2=80=94=20Lin?= =?UTF-8?q?ux=20display=20enumeration=20using=20xrandr=20subprocess?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/wg/displayinfo_linux.cpp | 122 +++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 src/wg/displayinfo_linux.cpp diff --git a/src/wg/displayinfo_linux.cpp b/src/wg/displayinfo_linux.cpp new file mode 100644 index 0000000..696927c --- /dev/null +++ b/src/wg/displayinfo_linux.cpp @@ -0,0 +1,122 @@ +// src/wg/displayinfo_linux.cpp — Linux implementation of display enumeration. +// +// Uses xrandr subprocess to query connected displays. +// Parses lines matching: connected [primary] ++ + +#include "displayinfo.h" + +#if defined(__linux__) + +#include +#include +#include +#include + +namespace wg { + +std::vector enumerateDisplays() { + std::vector displays; + + FILE *fp = popen("xrandr --query 2>/dev/null", "r"); + if (!fp) { + // Fallback: return default display + DisplayInfo def; + def.name = "default"; + def.friendlyName = "default"; + def.width = 1920; + def.height = 1080; + def.isPrimary = true; + displays.push_back(def); + return displays; + } + + char line[512]; + while (fgets(line, sizeof(line), fp) != nullptr) { + // Remove trailing newline + size_t len = strlen(line); + if (len > 0 && line[len - 1] == '\n') { + line[len - 1] = '\0'; + } + + // Skip lines that don't look like output lines (no "connected") + if (strstr(line, "connected") == nullptr) { + continue; + } + + // Parse: connected [primary] + char name[128] = {}; + char resolution[64] = {}; + int isPrimary = 0; + + // Extract name (first token before space) + char *space = strchr(line, ' '); + if (!space) continue; + size_t nameLen = space - line; + if (nameLen >= sizeof(name)) nameLen = sizeof(name) - 1; + memcpy(name, line, nameLen); + name[nameLen] = '\0'; + + // Check if "primary" is in the line + if (strstr(line, "primary") != nullptr) { + isPrimary = 1; + } + + // Extract resolution: look for pattern like "1920x1080" + char *res = strstr(line, "1280x720"); + if (!res) res = strstr(line, "1920x1080"); + if (!res) res = strstr(line, "2560x1440"); + if (!res) res = strstr(line, "3840x2160"); + if (!res) { + // More general: look for digits followed by 'x' and more digits + res = line; + while (*res) { + if (isdigit(*res)) { + char *xpos = strchr(res, 'x'); + if (xpos && isdigit(xpos[1])) { + break; + } + } + res++; + } + if (!*res) continue; + } + + int w = 0, h = 0; + if (sscanf(res, "%dx%d", &w, &h) != 2) { + continue; + } + + // Only add if we have valid dimensions + if (w <= 0 || h <= 0) { + continue; + } + + DisplayInfo info; + info.name = std::string(name); + info.friendlyName = std::string(name); + info.width = w; + info.height = h; + info.isPrimary = isPrimary != 0; + + displays.push_back(info); + } + + pclose(fp); + + // If xrandr returned nothing, fallback to default + if (displays.empty()) { + DisplayInfo def; + def.name = "default"; + def.friendlyName = "default"; + def.width = 1920; + def.height = 1080; + def.isPrimary = true; + displays.push_back(def); + } + + return displays; +} + +} // namespace wg + +#endif // defined(__linux__)