From 46eb0e4b1c0229e18986053301f3cd162afa768c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 30 Sep 2024 22:43:29 +0800 Subject: [PATCH] Display (Linux): merge features of `Monitor` module --- .../displayserver/linux/displayserver_linux.c | 39 ---------- .../displayserver/linux/displayserver_linux.h | 2 - src/detection/displayserver/linux/drm.c | 77 +++++++++++++------ .../linux/wayland/global-output.c | 15 +++- .../displayserver/linux/wayland/kde-output.c | 16 +++- .../displayserver/linux/wayland/wayland.c | 43 ++++++++++- .../displayserver/linux/wayland/wayland.h | 5 ++ .../displayserver/linux/wayland/zwlr-output.c | 15 +++- src/detection/displayserver/linux/xcb.c | 61 +++++++-------- src/detection/displayserver/linux/xlib.c | 32 +++++--- 10 files changed, 191 insertions(+), 114 deletions(-) diff --git a/src/detection/displayserver/linux/displayserver_linux.c b/src/detection/displayserver/linux/displayserver_linux.c index de006c56b..a84177650 100644 --- a/src/detection/displayserver/linux/displayserver_linux.c +++ b/src/detection/displayserver/linux/displayserver_linux.c @@ -1,6 +1,5 @@ #include "displayserver_linux.h" #include "common/io/io.h" -#include "util/edidHelper.h" #include "util/stringUtils.h" #ifdef __FreeBSD__ @@ -104,44 +103,6 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds) } } -bool ffdsMatchDrmConnector(const char* connName, FFstrbuf* edidName) -{ - // https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_output-event-name - // The doc says that "do not assume that the name is a reflection of an underlying DRM connector, X11 connection, etc." - // However I can't find a better method to get the edid data - const char* drmDirPath = "/sys/class/drm/"; - - FF_AUTO_CLOSE_DIR DIR* dirp = opendir(drmDirPath); - if(dirp == NULL) - return false; - - struct dirent* entry; - while((entry = readdir(dirp)) != NULL) - { - const char* plainName = entry->d_name; - if (ffStrStartsWith(plainName, "card")) - { - const char* tmp = strchr(plainName + strlen("card"), '-'); - if (tmp) plainName = tmp + 1; - } - if (ffStrEquals(plainName, connName)) - { - ffStrbufAppendF(edidName, "%s%s/edid", drmDirPath, entry->d_name); - - uint8_t edidData[128]; - if(ffReadFileData(edidName->chars, sizeof(edidData), edidData) == sizeof(edidData)) - { - ffStrbufClear(edidName); - ffEdidGetName(edidData, edidName); - return true; - } - break; - } - } - ffStrbufClear(edidName); - return false; -} - FFDisplayType ffdsGetDisplayType(const char* name) { if(ffStrStartsWith(name, "eDP-") || ffStrStartsWith(name, "LVDS-")) diff --git a/src/detection/displayserver/linux/displayserver_linux.h b/src/detection/displayserver/linux/displayserver_linux.h index 99cad927f..b52b35b45 100644 --- a/src/detection/displayserver/linux/displayserver_linux.h +++ b/src/detection/displayserver/linux/displayserver_linux.h @@ -5,8 +5,6 @@ #include "detection/displayserver/displayserver.h" -bool ffdsMatchDrmConnector(const char* connName, FFstrbuf* edidName); - const char* ffdsConnectWayland(FFDisplayServerResult* result); const char* ffdsConnectXcbRandr(FFDisplayServerResult* result); diff --git a/src/detection/displayserver/linux/drm.c b/src/detection/displayserver/linux/drm.c index 48949266d..9ccaa3f7e 100644 --- a/src/detection/displayserver/linux/drm.c +++ b/src/detection/displayserver/linux/drm.c @@ -50,15 +50,18 @@ static const char* drmParseSysfs(FFDisplayServerResult* result) ffStrbufSubstrBefore(&drmDir, drmDirWithDnameLength); ffStrbufAppendS(&drmDir, "/edid"); - uint8_t edidData[128]; - if(ffReadFileData(drmDir.chars, sizeof(edidData), edidData) == sizeof(edidData)) + const char* plainName = entry->d_name; + if (ffStrStartsWith(plainName, "card")) { - ffEdidGetName(edidData, &name); - ffEdidGetPreferredResolutionAndRefreshRate(edidData, &width, &height, &refreshRate); - ffEdidGetPhysicalSize(edidData, &physicalWidth, &physicalHeight); + const char* tmp = strchr(plainName + strlen("card"), '-'); + if (tmp) plainName = tmp + 1; } - else + + uint8_t edidData[512]; + ssize_t edidLength = ffReadFileData(drmDir.chars, sizeof(edidData), edidData); + if(edidLength <= 0 || edidLength % 128 != 0) { + edidLength = 0; ffStrbufSubstrBefore(&drmDir, drmDirWithDnameLength); ffStrbufAppendS(&drmDir, "/modes"); @@ -66,29 +69,34 @@ static const char* drmParseSysfs(FFDisplayServerResult* result) if (ffReadFileData(drmDir.chars, sizeof(modes), modes) >= 3) { sscanf(modes, "%ux%u", &width, &height); - const char* plainName = entry->d_name; - if (ffStrStartsWith(plainName, "card")) - { - const char* tmp = strchr(plainName + strlen("card"), '-'); - if (tmp) plainName = tmp + 1; - } ffStrbufAppendS(&name, plainName); } } + else + { + ffEdidGetName(edidData, &name); + ffEdidGetPreferredResolutionAndRefreshRate(edidData, &width, &height, &refreshRate); + ffEdidGetPhysicalSize(edidData, &physicalWidth, &physicalHeight); + } - ffdsAppendDisplay( + FFDisplayResult* item = ffdsAppendDisplay( result, width, height, refreshRate, 0, 0, 0, &name, - FF_DISPLAY_TYPE_UNKNOWN, + ffdsGetDisplayType(plainName), false, 0, physicalWidth, physicalHeight ); + if (item && edidLength) + { + item->hdrStatus = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED; + ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek); + } ffStrbufSubstrBefore(&drmDir, drmDirLength); } @@ -160,7 +168,7 @@ static inline const char* drmType2Name(uint32_t connector_type) } } -static const char* drmGetNameByConnId(uint32_t connId, FFstrbuf* name) +static const char* drmGetEdidByConnId(uint32_t connId, uint8_t* edidData, ssize_t* edidLength) { const char* drmDirPath = "/sys/class/drm/"; @@ -182,24 +190,22 @@ static const char* drmGetNameByConnId(uint32_t connId, FFstrbuf* name) ffStrbufAppendS(&drmDir, entry->d_name); uint32_t drmDirWithDnameLength = drmDir.length; + char connectorId[16] = {}; + ffStrbufAppendS(&drmDir, "/connector_id"); - ffReadFileBuffer(drmDir.chars, name); - if (ffStrbufToUInt(name, 0) != connId) + ffReadFileData(drmDir.chars, sizeof(connectorId), connectorId); + if (strtoul(connectorId, NULL, 10) != connId) { ffStrbufSubstrBefore(&drmDir, drmDirLength); continue; } ffStrbufSubstrBefore(&drmDir, drmDirWithDnameLength); - ffStrbufClear(name); ffStrbufAppendS(&drmDir, "/edid"); - uint8_t edidData[128]; - if(ffReadFileData(drmDir.chars, sizeof(edidData), edidData) == sizeof(edidData)) - ffEdidGetName(edidData, name); + *edidLength = ffReadFileData(drmDir.chars, (uint32_t) *edidLength, edidData); return NULL; } - ffStrbufClear(name); return "Failed to match connector ID"; } @@ -309,6 +315,9 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result) ffStrbufClear(&name); + uint16_t myear = 0, mweak = 0; + uint32_t serial = 0; + FFDisplayHdrStatus hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN; for (int iProp = 0; iProp < conn->count_props; ++iProp) { @@ -329,7 +338,11 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result) if (blob) { if (blob->length >= 128) + { ffEdidGetName(blob->data, &name); + hdrStatus = ffEdidGetHdrCompatible(blob->data, blob->length) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED; + ffEdidGetSerialAndManufactureDate(blob->data, &serial, &myear, &mweak); + } ffdrmModeFreePropertyBlob(blob); } break; @@ -339,7 +352,15 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result) if (name.length == 0) { - drmGetNameByConnId(conn->connector_id, &name); + uint8_t edidData[512]; + ssize_t edidLength = 0; + drmGetEdidByConnId(conn->connector_id, edidData, &edidLength); + if (edidLength > 0 && edidLength % 128 == 0) + { + ffEdidGetName(edidData, &name); + hdrStatus = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED; + ffEdidGetSerialAndManufactureDate(edidData, &serial, &myear, &mweak); + } } if (name.length == 0) @@ -350,7 +371,7 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result) ffStrbufSetF(&name, "%s-%d", connectorTypeName, iConn + 1); } - ffdsAppendDisplay(result, + FFDisplayResult* item = ffdsAppendDisplay(result, width, height, refreshRate, @@ -367,6 +388,14 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result) conn->mmWidth, conn->mmHeight ); + + if (item) + { + item->hdrStatus = hdrStatus; + item->serial = serial; + item->manufactureYear = myear; + item->manufactureWeek = mweak; + } } ffdrmModeFreeConnector(conn); diff --git a/src/detection/displayserver/linux/wayland/global-output.c b/src/detection/displayserver/linux/wayland/global-output.c index a8299d16d..20227be36 100644 --- a/src/detection/displayserver/linux/wayland/global-output.c +++ b/src/detection/displayserver/linux/wayland/global-output.c @@ -112,7 +112,7 @@ void ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* regist uint32_t rotation = ffWaylandHandleRotation(&display); - ffdsAppendDisplay(wldata->result, + FFDisplayResult* item = ffdsAppendDisplay(wldata->result, (uint32_t) display.width, (uint32_t) display.height, display.refreshRate / 1000.0, @@ -131,6 +131,19 @@ void ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* regist (uint32_t) display.physicalWidth, (uint32_t) display.physicalHeight ); + if (item) + { + if (display.hdrSupported) + item->hdrStatus = FF_DISPLAY_HDR_STATUS_SUPPORTED; + else if (display.hdrInfoAvailable) + item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNSUPPORTED; + else + item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN; + + item->manufactureYear = display.myear; + item->manufactureWeek = display.mweek; + item->serial = display.serial; + } ffStrbufDestroy(&display.description); ffStrbufDestroy(&display.name); diff --git a/src/detection/displayserver/linux/wayland/kde-output.c b/src/detection/displayserver/linux/wayland/kde-output.c index fd0d4809b..0993f72a5 100644 --- a/src/detection/displayserver/linux/wayland/kde-output.c +++ b/src/detection/displayserver/linux/wayland/kde-output.c @@ -80,6 +80,9 @@ static void waylandKdeEdidListener(void* data, FF_MAYBE_UNUSED struct kde_output FF_STRBUF_AUTO_DESTROY edid = ffBase64DecodeStrbuf(&b64); if (edid.length < 128) return; ffEdidGetName((const uint8_t*) edid.chars, &wldata->edidName); + wldata->hdrSupported = ffEdidGetHdrCompatible((const uint8_t*) edid.chars, edid.length); + ffEdidGetSerialAndManufactureDate((const uint8_t*) edid.chars, &wldata->serial, &wldata->myear, &wldata->mweek); + wldata->hdrInfoAvailable = true; } static void waylandKdeEnabledListener(void* data, FF_MAYBE_UNUSED struct kde_output_device_v2* _, int32_t enabled) @@ -195,7 +198,18 @@ void ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, ); if (item) { - item->hdrEnabled = display.hdrEnabled; + if (display.hdrEnabled) + item->hdrStatus = FF_DISPLAY_HDR_STATUS_ENABLED; + else if (display.hdrSupported) + item->hdrStatus = FF_DISPLAY_HDR_STATUS_SUPPORTED; + else if (display.hdrInfoAvailable) + item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNSUPPORTED; + else + item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN; + + item->manufactureYear = display.myear; + item->manufactureWeek = display.mweek; + item->serial = display.serial; } ffStrbufDestroy(&display.description); diff --git a/src/detection/displayserver/linux/wayland/wayland.c b/src/detection/displayserver/linux/wayland/wayland.c index a0472ae74..5a67f7887 100644 --- a/src/detection/displayserver/linux/wayland/wayland.c +++ b/src/detection/displayserver/linux/wayland/wayland.c @@ -1,5 +1,6 @@ #include "../displayserver_linux.h" #include "common/io/io.h" +#include "util/edidHelper.h" #include "util/stringUtils.h" #include @@ -82,6 +83,46 @@ static void waylandGlobalAddListener(void* data, struct wl_registry* registry, u } } +static bool matchDrmConnector(const char* connName, WaylandDisplay* wldata) +{ + // https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_output-event-name + // The doc says that "do not assume that the name is a reflection of an underlying DRM connector, X11 connection, etc." + // However I can't find a better method to get the edid data + const char* drmDirPath = "/sys/class/drm/"; + + FF_AUTO_CLOSE_DIR DIR* dirp = opendir(drmDirPath); + if(dirp == NULL) + return false; + + struct dirent* entry; + while((entry = readdir(dirp)) != NULL) + { + const char* plainName = entry->d_name; + if (ffStrStartsWith(plainName, "card")) + { + const char* tmp = strchr(plainName + strlen("card"), '-'); + if (tmp) plainName = tmp + 1; + } + if (ffStrEquals(plainName, connName)) + { + FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateF("%s%s/edid", drmDirPath, entry->d_name); + + uint8_t edidData[512]; + ssize_t edidLength = ffReadFileData(path.chars, sizeof(edidData), edidData); + if (edidLength <= 0 || edidLength % 128 != 0) + { + ffEdidGetName(edidData, &wldata->edidName); + ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength); + ffEdidGetSerialAndManufactureDate(edidData, &wldata->serial, &wldata->myear, &wldata->mweek); + wldata->hdrInfoAvailable = true; + return true; + } + break; + } + } + return false; +} + void ffWaylandOutputNameListener(void* data, FF_MAYBE_UNUSED void* output, const char *name) { WaylandDisplay* display = data; @@ -89,7 +130,7 @@ void ffWaylandOutputNameListener(void* data, FF_MAYBE_UNUSED void* output, const display->type = ffdsGetDisplayType(name); if (!display->edidName.length) - ffdsMatchDrmConnector(name, &display->edidName); + matchDrmConnector(name, display); display->id = ffWaylandGenerateIdFromName(name); ffStrbufAppendS(&display->name, name); } diff --git a/src/detection/displayserver/linux/wayland/wayland.h b/src/detection/displayserver/linux/wayland/wayland.h index df7056a7b..3c3b64a94 100644 --- a/src/detection/displayserver/linux/wayland/wayland.h +++ b/src/detection/displayserver/linux/wayland/wayland.h @@ -46,7 +46,12 @@ typedef struct WaylandDisplay FFstrbuf description; FFstrbuf edidName; uint64_t id; + bool hdrInfoAvailable; + bool hdrSupported; bool hdrEnabled; + uint16_t myear; + uint16_t mweek; + uint32_t serial; void* internal; } WaylandDisplay; diff --git a/src/detection/displayserver/linux/wayland/zwlr-output.c b/src/detection/displayserver/linux/wayland/zwlr-output.c index dd31b91b0..7e23d593e 100644 --- a/src/detection/displayserver/linux/wayland/zwlr-output.c +++ b/src/detection/displayserver/linux/wayland/zwlr-output.c @@ -122,7 +122,7 @@ static void waylandHandleZwlrHead(void *data, FF_MAYBE_UNUSED struct zwlr_output uint32_t rotation = ffWaylandHandleRotation(&display); - ffdsAppendDisplay(wldata->result, + FFDisplayResult* item = ffdsAppendDisplay(wldata->result, (uint32_t) display.width, (uint32_t) display.height, display.refreshRate / 1000.0, @@ -140,6 +140,19 @@ static void waylandHandleZwlrHead(void *data, FF_MAYBE_UNUSED struct zwlr_output (uint32_t) display.physicalWidth, (uint32_t) display.physicalHeight ); + if (item) + { + if (display.hdrSupported) + item->hdrStatus = FF_DISPLAY_HDR_STATUS_SUPPORTED; + else if (display.hdrInfoAvailable) + item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNSUPPORTED; + else + item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN; + + item->manufactureYear = display.myear; + item->manufactureWeek = display.mweek; + item->serial = display.serial; + } ffStrbufDestroy(&display.description); ffStrbufDestroy(&display.name); diff --git a/src/detection/displayserver/linux/xcb.c b/src/detection/displayserver/linux/xcb.c index 6bf82e14b..d40386eb0 100644 --- a/src/detection/displayserver/linux/xcb.c +++ b/src/detection/displayserver/linux/xcb.c @@ -180,47 +180,29 @@ typedef struct XcbRandrData xcb_randr_get_screen_resources_current_reply_t* screenResources; } XcbRandrData; -static bool xcbRandrHandleModeInfo(XcbRandrData* data, xcb_randr_mode_info_t* modeInfo, FFstrbuf* name, uint32_t rotation, bool primary, xcb_randr_get_output_info_reply_t* output, FFDisplayType displayType) -{ - double refreshRate = (double) modeInfo->dot_clock / (double) (modeInfo->htotal * modeInfo->vtotal); - - return ffdsAppendDisplay( - data->result, - (uint32_t) modeInfo->width, - (uint32_t) modeInfo->height, - refreshRate, - (uint32_t) modeInfo->width, - (uint32_t) modeInfo->height, - rotation, - name, - displayType, - primary, - 0, - (uint32_t) output->mm_width, - (uint32_t) output->mm_height - ); -} - -static bool xcbRandrHandleMode(XcbRandrData* data, xcb_randr_mode_t mode, FFstrbuf* name, uint32_t rotation, bool primary, xcb_randr_get_output_info_reply_t* output, FFDisplayType displayType) +static double xcbRandrHandleMode(XcbRandrData* data, xcb_randr_mode_t mode) { //We do the check here, because we want the best fallback display if this call failed if(data->screenResources == NULL) - return false; + return 0; xcb_randr_mode_info_iterator_t modesIterator = data->ffxcb_randr_get_screen_resources_current_modes_iterator(data->screenResources); while(modesIterator.rem > 0) { if(modesIterator.data->id == mode) - return xcbRandrHandleModeInfo(data, modesIterator.data, name, rotation, primary, output, displayType); + { + xcb_randr_mode_info_t* modeInfo = modesIterator.data; + return (double) modeInfo->dot_clock / (double) (modeInfo->htotal * modeInfo->vtotal); + } data->ffxcb_randr_mode_info_next(&modesIterator); } - return false; + return 0; } -static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc, FFstrbuf* name, bool primary, xcb_randr_get_output_info_reply_t* output, FFDisplayType displayType) +static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc, FFstrbuf* name, bool primary, xcb_randr_get_output_info_reply_t* output, FFDisplayType displayType, uint8_t* edidData, uint32_t edidLength) { xcb_randr_get_crtc_info_cookie_t crtcInfoCookie = data->ffxcb_randr_get_crtc_info(data->connection, crtc, XCB_CURRENT_TIME); FF_AUTO_FREE xcb_randr_get_crtc_info_reply_t* crtcInfoReply = data->ffxcb_randr_get_crtc_info_reply(data->connection, crtcInfoCookie, NULL); @@ -243,12 +225,12 @@ static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc, FFstrb rotation = 0; break; } - bool res = xcbRandrHandleMode(data, crtcInfoReply->mode, name, rotation, primary, output, displayType); - res = res ? true : !!ffdsAppendDisplay( + + FFDisplayResult* item = ffdsAppendDisplay( data->result, (uint32_t) crtcInfoReply->width, (uint32_t) crtcInfoReply->height, - 0, + xcbRandrHandleMode(data, crtcInfoReply->mode), (uint32_t) crtcInfoReply->width, (uint32_t) crtcInfoReply->height, rotation, @@ -259,8 +241,13 @@ static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc, FFstrb (uint32_t) output->mm_width, (uint32_t) output->mm_height ); + if (item && edidLength) + { + item->hdrStatus = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED; + ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek); + } - return res; + return !!item; } static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output, FFstrbuf* name, bool primary, FFDisplayType displayType) @@ -272,21 +259,27 @@ static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output, xcb_intern_atom_cookie_t requestAtomCookie = data->ffxcb_intern_atom(data->connection, true, (uint16_t) strlen("EDID"), "EDID"); FF_AUTO_FREE xcb_intern_atom_reply_t* requestAtomReply = data->ffxcb_intern_atom_reply(data->connection, requestAtomCookie, NULL); + FF_AUTO_FREE xcb_randr_get_output_property_reply_t* outputPropertyReply = NULL; + uint8_t* edidData = NULL; + uint32_t edidLength = 0; if(requestAtomReply) { xcb_randr_get_output_property_cookie_t outputPropertyCookie = data->ffxcb_randr_get_output_property(data->connection, output, requestAtomReply->atom, XCB_GET_PROPERTY_TYPE_ANY, 0, 100, false, false); - FF_AUTO_FREE xcb_randr_get_output_property_reply_t* outputPropertyReply = data->ffxcb_randr_get_output_property_reply(data->connection, outputPropertyCookie, NULL); + outputPropertyReply = data->ffxcb_randr_get_output_property_reply(data->connection, outputPropertyCookie, NULL); if(outputPropertyReply) { - if(data->ffxcb_randr_get_output_property_data_length(outputPropertyReply) >= 128) + int len = data->ffxcb_randr_get_output_property_data_length(outputPropertyReply); + if(len >= 128) { ffStrbufClear(name); - ffEdidGetName(data->ffxcb_randr_get_output_property_data(outputPropertyReply), name); + edidData = data->ffxcb_randr_get_output_property_data(outputPropertyReply); + ffEdidGetName(edidData, name); + edidLength = (uint32_t) len; } } } - bool res = xcbRandrHandleCrtc(data, outputInfoReply->crtc, name, primary, outputInfoReply, displayType); + bool res = xcbRandrHandleCrtc(data, outputInfoReply->crtc, name, primary, outputInfoReply, displayType, edidData, edidLength); return res; } diff --git a/src/detection/displayserver/linux/xlib.c b/src/detection/displayserver/linux/xlib.c index 4a6a37080..e83b0e1ed 100644 --- a/src/detection/displayserver/linux/xlib.c +++ b/src/detection/displayserver/linux/xlib.c @@ -153,13 +153,13 @@ static double xrandrHandleMode(XrandrData* data, RRMode mode) return 0; } -static bool xrandrHandleCrtc(XrandrData* data, RRCrtc crtc, FFstrbuf* name, bool primary, XRROutputInfo* output, FFDisplayType displayType) +static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf* name, bool primary, FFDisplayType displayType, uint8_t* edidData, uint32_t edidLength) { //We do the check here, because we want the best fallback display if this call failed if(data->screenResources == NULL) return false; - XRRCrtcInfo* crtcInfo = data->ffXRRGetCrtcInfo(data->display, data->screenResources, crtc); + XRRCrtcInfo* crtcInfo = data->ffXRRGetCrtcInfo(data->display, data->screenResources, output->crtc); if(crtcInfo == NULL) return false; @@ -180,7 +180,7 @@ static bool xrandrHandleCrtc(XrandrData* data, RRCrtc crtc, FFstrbuf* name, bool break; } - bool res = ffdsAppendDisplay( + FFDisplayResult* item = ffdsAppendDisplay( data->result, (uint32_t) crtcInfo->width, (uint32_t) crtcInfo->height, @@ -196,8 +196,14 @@ static bool xrandrHandleCrtc(XrandrData* data, RRCrtc crtc, FFstrbuf* name, bool (uint32_t) output->mm_height ); + if (edidLength) + { + item->hdrStatus = ffEdidGetHdrCompatible(edidData, edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED; + ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek); + } + data->ffXRRFreeCrtcInfo(crtcInfo); - return res; + return !!item; } static bool xrandrHandleOutput(XrandrData* data, RROutput output, FFstrbuf* name, bool primary, FFDisplayType displayType) @@ -206,26 +212,30 @@ static bool xrandrHandleOutput(XrandrData* data, RROutput output, FFstrbuf* name if(outputInfo == NULL) return false; + uint8_t* edidData = NULL; + unsigned long edidLength = 0; Atom atomEdid = data->ffXInternAtom(data->display, "EDID", true); if (atomEdid != None) { int actual_format = 0; - unsigned long nitems = 0, bytes_after = 0; + unsigned long 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 (data->ffXRRGetOutputProperty(data->display, output, atomEdid, 0, 100, false, false, AnyPropertyType, &actual_type, &actual_format, &edidLength, &bytes_after, &edidData) == Success) { - if (nitems >= 128) + if (edidLength >= 128) { ffStrbufClear(name); ffEdidGetName(edidData, name); } + else + edidLength = 0; } - if (edidData) - data->ffXFree(edidData); } - bool res = xrandrHandleCrtc(data, outputInfo->crtc, name, primary, outputInfo, displayType); + bool res = xrandrHandleCrtc(data, outputInfo, name, primary, displayType, edidData, (uint32_t) edidLength); + + if (edidData) + data->ffXFree(edidData); data->ffXRRFreeOutputInfo(outputInfo); return res;