Add displayinfo_linux.cpp — Linux display enumeration using xrandr subprocess

This commit is contained in:
Zac Gaetano 2026-05-06 19:49:40 -04:00
parent 7f5cc0d390
commit af22df1997

View file

@ -0,0 +1,122 @@
// src/wg/displayinfo_linux.cpp — Linux implementation of display enumeration.
//
// Uses xrandr subprocess to query connected displays.
// Parses lines matching: <output-name> connected [primary] <WxH>+<x>+<y>
#include "displayinfo.h"
#if defined(__linux__)
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
namespace wg {
std::vector<DisplayInfo> enumerateDisplays() {
std::vector<DisplayInfo> 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: <name> connected [primary] <resolution>
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__)