diff --git a/src/detection/displayserver/linux/xlib.c b/src/detection/displayserver/linux/xlib.c index 69beb63af..ac06f499d 100644 --- a/src/detection/displayserver/linux/xlib.c +++ b/src/detection/displayserver/linux/xlib.c @@ -119,7 +119,6 @@ typedef struct XrandrData FF_LIBRARY_SYMBOL(XInternAtom) FF_LIBRARY_SYMBOL(XGetAtomName); FF_LIBRARY_SYMBOL(XFree); - FF_LIBRARY_SYMBOL(XRRConfigCurrentRate) FF_LIBRARY_SYMBOL(XRRGetMonitors) FF_LIBRARY_SYMBOL(XRRGetScreenResourcesCurrent) FF_LIBRARY_SYMBOL(XRRGetOutputInfo) @@ -321,7 +320,6 @@ void ffdsConnectXrandr(FFDisplayServerResult* result) FF_LIBRARY_LOAD_SYMBOL_VAR(xrandr, data, XInternAtom,); FF_LIBRARY_LOAD_SYMBOL_VAR(xrandr, data, XGetAtomName,); FF_LIBRARY_LOAD_SYMBOL_VAR(xrandr, data, XFree,); - FF_LIBRARY_LOAD_SYMBOL_VAR(xrandr, data, XRRConfigCurrentRate,); FF_LIBRARY_LOAD_SYMBOL_VAR(xrandr, data, XRRGetMonitors,); FF_LIBRARY_LOAD_SYMBOL_VAR(xrandr, data, XRRGetScreenResourcesCurrent,); FF_LIBRARY_LOAD_SYMBOL_VAR(xrandr, data, XRRGetOutputInfo,); diff --git a/src/detection/monitor/monitor_linux.c b/src/detection/monitor/monitor_linux.c index b6c7e361e..d5c0e4fe3 100644 --- a/src/detection/monitor/monitor_linux.c +++ b/src/detection/monitor/monitor_linux.c @@ -1,13 +1,178 @@ #include "monitor.h" #include "common/io/io.h" +#include "common/library.h" #include "util/edidHelper.h" #include "util/stringUtils.h" -#include -#include +#ifdef FF_HAVE_XRANDR -const char* ffDetectMonitor(FFlist* results) +#include +#include + +typedef struct XrandrData +{ + FF_LIBRARY_SYMBOL(XInternAtom) + FF_LIBRARY_SYMBOL(XGetAtomName); + FF_LIBRARY_SYMBOL(XFree); + FF_LIBRARY_SYMBOL(XRRGetMonitors) + FF_LIBRARY_SYMBOL(XRRGetOutputInfo) + FF_LIBRARY_SYMBOL(XRRGetOutputProperty) + FF_LIBRARY_SYMBOL(XRRFreeOutputInfo) + FF_LIBRARY_SYMBOL(XRRFreeMonitors) + + //Init once + Display* display; + + //Init per screen + XRRScreenResources* screenResources; +} XrandrData; + +static const char* xrandrHandleMonitors(XrandrData* data, Screen* screen, FFlist* results) +{ + int numberOfMonitors; + XRRMonitorInfo* monitorInfos = data->ffXRRGetMonitors(data->display, RootWindowOfScreen(screen), True, &numberOfMonitors); + if(monitorInfos == NULL) + return "XRRGetMonitors() failed"; + + for(int i = 0; i < numberOfMonitors; i++) + { + XRRMonitorInfo* monitorInfo = &monitorInfos[i]; + for(int i = 0; i < monitorInfo->noutput; i++) + { + RROutput output = monitorInfo->outputs[i]; + XRROutputInfo* outputInfo = data->ffXRRGetOutputInfo(data->display, data->screenResources, output); + if(outputInfo == NULL) + continue; + + FFMonitorResult* display = (FFMonitorResult*) ffListAdd(results); + ffStrbufInit(&display->name); + display->width = 0; + display->height = 0; + display->manufactureYear = 0; + display->manufactureWeek = 0; + display->serial = 0; + display->hdrCompatible = false; + display->refreshRate = 0; + + bool edidOk = false; + Atom atomEdid = data->ffXInternAtom(data->display, "EDID", true); + if (atomEdid != None) + { + int actual_format = 0; + unsigned long nitems = 0, bytes_after = 0; + Atom actual_type = None; + uint8_t* edidData = NULL; + if (data->ffXRRGetOutputProperty(data->display, output, atomEdid, 0, 100, false, false, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &edidData) == Success) + { + if (nitems > 0 && nitems % 128 == 0) + { + ffEdidGetName(edidData, &display->name); + ffEdidGetPhysicalResolution(edidData, &display->width, &display->height); + ffEdidGetPhysicalSize(edidData, &display->physicalWidth, &display->physicalHeight); + ffEdidGetSerialAndManufactureDate(edidData, &display->serial, &display->manufactureYear, &display->manufactureWeek); + display->hdrCompatible = ffEdidGetHdrCompatible(edidData, (uint32_t) nitems); + edidOk = true; + } + } + if (edidData) + data->ffXFree(edidData); + } + + if (!edidOk) + { + ffStrbufSetS(&display->name, data->ffXGetAtomName(data->display, monitorInfo->name)); + display->physicalWidth = (uint32_t) monitorInfo->mwidth; + display->physicalHeight = (uint32_t) monitorInfo->mheight; + display->width = (uint32_t) monitorInfo->width; + display->height = (uint32_t) monitorInfo->height; + } + + for(int i = 0; i < data->screenResources->nmode; i++) + { + bool found = false; + for (int j = 0; j < outputInfo->nmode; ++j) + { + if (data->screenResources->modes[i].id == outputInfo->modes[j]) + { + found = true; + break; + } + } + + if(found) + { + XRRModeInfo* modeInfo = &data->screenResources->modes[i]; + double refreshRate = (double) modeInfo->dotClock / (double) (modeInfo->hTotal * modeInfo->vTotal); + if (edidOk) + { + if (display->width != modeInfo->width || display->height != modeInfo->height) + continue; + } + else + { + if (display->width < modeInfo->width || display->height < modeInfo->height) + { + display->width = (uint32_t) modeInfo->width; + display->height = (uint32_t) modeInfo->height; + display->refreshRate = refreshRate; + continue; + } + else if (display->width != modeInfo->width || display->height != modeInfo->height) + continue; + } + if (display->refreshRate < refreshRate) + display->refreshRate = refreshRate; + } + } + data->ffXRRFreeOutputInfo(outputInfo); + } + } + + data->ffXRRFreeMonitors(monitorInfos); + return NULL; +} + +static const char* detectByXrandr(FFlist* results) +{ + FF_LIBRARY_LOAD(xrandr, &instance.config.library.libXrandr, "dlopen libXrandr" FF_LIBRARY_EXTENSION " failed", "libXrandr" FF_LIBRARY_EXTENSION, 3) + + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xrandr, XOpenDisplay) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xrandr, XCloseDisplay) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xrandr, XRRGetScreenResourcesCurrent); + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xrandr, XRRFreeScreenResources); + + XrandrData data; + + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xrandr, data, XInternAtom); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xrandr, data, XGetAtomName); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xrandr, data, XFree); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xrandr, data, XRRGetMonitors); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xrandr, data, XRRGetOutputInfo); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xrandr, data, XRRGetOutputProperty); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xrandr, data, XRRFreeOutputInfo); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(xrandr, data, XRRFreeMonitors); + + data.display = ffXOpenDisplay(NULL); + if(data.display == NULL) + return "XOpenDisplay() failed"; + + for(int i = 0; i < ScreenCount(data.display); i++) + { + Screen* screen = ScreenOfDisplay(data.display, i); + data.screenResources = ffXRRGetScreenResourcesCurrent(data.display, RootWindowOfScreen(screen)); + xrandrHandleMonitors(&data, screen, results); + ffXRRFreeScreenResources(data.screenResources); + } + + ffXCloseDisplay(data.display); + + return NULL; +} +#endif // FF_HAVE_XRANDR + +#ifdef __linux__ +FF_MAYBE_UNUSED static const char* detectByDrm(FFlist* results) { const char* drmDirPath = "/sys/class/drm/"; @@ -70,3 +235,20 @@ const char* ffDetectMonitor(FFlist* results) closedir(dirp); return NULL; } +#endif // __linux__ + +const char* ffDetectMonitor(FFlist* results) +{ + const char* error = "Fastfetch was compiled without xrandr support"; + + #ifdef FF_HAVE_XRANDR + error = detectByXrandr(results); + if (!error) return NULL; + #endif + + #if defined(__linux__) + error = detectByDrm(results); + #endif + + return error; +}