diff --git a/src/detection/displayserver/linux/xcb.c b/src/detection/displayserver/linux/xcb.c index 7d24448b5..ce19f02c1 100644 --- a/src/detection/displayserver/linux/xcb.c +++ b/src/detection/displayserver/linux/xcb.c @@ -78,6 +78,19 @@ static void* xcbGetProperty(XcbRandrData* data, xcb_window_t window, const char* return replyValue; } +static xcb_randr_get_output_property_reply_t* xcbRandrGetProperty(XcbRandrData* data, xcb_randr_output_t output, const char* name) +{ + xcb_intern_atom_cookie_t requestAtomCookie = data->ffxcb_intern_atom(data->connection, true, (uint16_t) strlen(name), name); + FF_AUTO_FREE xcb_intern_atom_reply_t* requestAtomReply = data->ffxcb_intern_atom_reply(data->connection, requestAtomCookie, NULL); + + 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); + return data->ffxcb_randr_get_output_property_reply(data->connection, outputPropertyCookie, NULL); + } + return NULL; +} + static void xcbDetectWMfromEWMH(XcbRandrData* data, xcb_window_t rootWindow, FFDisplayServerResult* result) { if(result->wmProcessName.length > 0 || ffStrbufCompS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND) == 0) @@ -121,28 +134,34 @@ static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output, if(outputInfoReply == NULL) return false; - 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; + FF_AUTO_FREE xcb_randr_get_output_property_reply_t* edidReply = xcbRandrGetProperty(data, output, "EDID"); uint8_t* edidData = NULL; uint32_t edidLength = 0; - if(requestAtomReply) + if(edidReply) { - 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); - outputPropertyReply = data->ffxcb_randr_get_output_property_reply(data->connection, outputPropertyCookie, NULL); - if(outputPropertyReply) + int len = data->ffxcb_randr_get_output_property_data_length(edidReply); + if(len >= 128) { - int len = data->ffxcb_randr_get_output_property_data_length(outputPropertyReply); - if(len >= 128) - { - ffStrbufClear(name); - edidData = data->ffxcb_randr_get_output_property_data(outputPropertyReply); - ffEdidGetName(edidData, name); - edidLength = (uint32_t) len; - } + edidData = data->ffxcb_randr_get_output_property_data(edidReply); + edidLength = (uint32_t) len; } } + if(edidData) + { + ffStrbufClear(name); + ffEdidGetName(edidData, name); + } + + uint8_t randrEmulation = 0; + FF_AUTO_FREE xcb_randr_get_output_property_reply_t* randrEmulationReply = xcbRandrGetProperty(data, output, "RANDR Emulation"); + if(randrEmulationReply) + { + int len = data->ffxcb_randr_get_output_property_data_length(randrEmulationReply); + if(len >= 1) + randrEmulation = data->ffxcb_randr_get_output_property_data(randrEmulationReply)[0]; + } + xcb_randr_get_crtc_info_cookie_t crtcInfoCookie = data->ffxcb_randr_get_crtc_info(data->connection, outputInfoReply->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); if(crtcInfoReply == NULL) @@ -204,9 +223,12 @@ static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output, 0, (uint32_t) outputInfoReply->mm_width, (uint32_t) outputInfoReply->mm_height, - currentMode ? "xcb-randr-mode" : "xcb-randr-crtc" + randrEmulation + ? (currentMode ? "xcb-randr-emu-mode" : "xcb-randr-emu-crtc") + : (currentMode ? "xcb-randr-mode" : "xcb-randr-crtc") + ); - if (item && edidLength) + if (item && edidData && edidLength >= 128) { 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); diff --git a/src/detection/displayserver/linux/xlib.c b/src/detection/displayserver/linux/xlib.c index 8820ad935..eb407f7b5 100644 --- a/src/detection/displayserver/linux/xlib.c +++ b/src/detection/displayserver/linux/xlib.c @@ -48,6 +48,32 @@ static unsigned char* x11GetProperty(XrandrData* data, Display* display, Window return result; } +static uint8_t* xrandrGetProperty(XrandrData* data, RROutput output, const char* name, uint32_t* bufSize) +{ + unsigned long size = 0; + uint8_t* result = NULL; + Atom atomEdid = data->ffXInternAtom(data->display, name, true); + if (atomEdid != None) + { + int actual_format = 0; + unsigned long bytes_after = 0; + Atom actual_type = None; + if (data->ffXRRGetOutputProperty(data->display, output, atomEdid, 0, 100, false, false, AnyPropertyType, &actual_type, &actual_format, &size, &bytes_after, &result) == Success) + { + if (size == 0) + data->ffXFree(result); + else + { + if (bufSize) + *bufSize = (uint32_t) size; + return result; + } + } + } + + return NULL; +} + static void x11DetectWMFromEWMH(XrandrData* data, FFDisplayServerResult* result) { if(result->wmProcessName.length > 0 || ffStrbufCompS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND) == 0) @@ -75,7 +101,7 @@ static void x11FetchServerVendor(XrandrData* data, FFDisplayServerResult* result ffStrbufSetS(&result->wmProtocolName, serverVendor); } -static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf* name, bool primary, FFDisplayType displayType, uint8_t* edidData, uint32_t edidLength, XRRScreenResources* screenResources, uint8_t bitDepth, double scaleFactor) +static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf* name, bool primary, FFDisplayType displayType, uint8_t* edidData, uint32_t edidLength, XRRScreenResources* screenResources, uint8_t bitDepth, double scaleFactor, bool randrEmulation) { //We do the check here, because we want the best fallback display if this call failed if(screenResources == NULL) @@ -131,7 +157,9 @@ static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf* 0, (uint32_t) output->mm_width, (uint32_t) output->mm_height, - currentMode ? "xlib-randr-mode" : "xlib-randr-crtc" + randrEmulation + ? (currentMode ? "xlib-randr-emu-mode" : "xlib-randr-emu-crtc") + : (currentMode ? "xlib-randr-mode" : "xlib-randr-crtc") ); if (item) @@ -154,30 +182,25 @@ 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 bytes_after = 0; - Atom actual_type = None; - if (data->ffXRRGetOutputProperty(data->display, output, atomEdid, 0, 100, false, false, AnyPropertyType, &actual_type, &actual_format, &edidLength, &bytes_after, &edidData) == Success) - { - if (edidLength >= 128) - { - ffStrbufClear(name); - ffEdidGetName(edidData, name); - } - else - edidLength = 0; - } - } + uint32_t edidLength = 0; + uint8_t* edidData = xrandrGetProperty(data, output, RR_PROPERTY_RANDR_EDID, &edidLength); - bool res = xrandrHandleCrtc(data, outputInfo, name, primary, displayType, edidData, (uint32_t) edidLength, screenResources, bitDepth, scaleFactor); + if (edidLength >= 128) + { + ffStrbufClear(name); + ffEdidGetName(edidData, name); + } + else + edidLength = 0; + + uint8_t* randrEmulation = xrandrGetProperty(data, output, "RANDR Emulation", NULL); + + bool res = xrandrHandleCrtc(data, outputInfo, name, primary, displayType, edidData, edidLength, screenResources, bitDepth, scaleFactor, randrEmulation ? !!randrEmulation[0] : false); if (edidData) data->ffXFree(edidData); + if (randrEmulation) + data->ffXFree(randrEmulation); data->ffXRRFreeOutputInfo(outputInfo); return res;