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