Add displayinfo_linux.cpp — Linux display enumeration using xrandr subprocess
This commit is contained in:
parent
7f5cc0d390
commit
af22df1997
1 changed files with 122 additions and 0 deletions
122
src/wg/displayinfo_linux.cpp
Normal file
122
src/wg/displayinfo_linux.cpp
Normal 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__)
|
||||||
Loading…
Reference in a new issue