diff --git a/src/detection/monitor/monitor.h b/src/detection/monitor/monitor.h index 8314c4cf4..a6150e5d3 100644 --- a/src/detection/monitor/monitor.h +++ b/src/detection/monitor/monitor.h @@ -8,6 +8,9 @@ typedef struct FFMonitorResult uint32_t physicalWidth; // in mm uint32_t physicalHeight; // in mm bool hdrCompatible; + uint16_t manufactureYear; + uint16_t manufactureWeek; + uint32_t serial; } FFMonitorResult; const char* ffDetectMonitor(FFlist* results); diff --git a/src/detection/monitor/monitor_apple.m b/src/detection/monitor/monitor_apple.m index be3b51a46..348a1ad33 100644 --- a/src/detection/monitor/monitor_apple.m +++ b/src/detection/monitor/monitor_apple.m @@ -40,9 +40,13 @@ const char* ffDetectMonitor(FFlist* results) CFDictionaryRef FF_CFTYPE_AUTO_RELEASE displayInfo = CoreDisplay_DisplayCreateInfoDictionary((CGDirectDisplayID) display->id); if(!displayInfo) continue; + bool isVirtual = false; + if (ffCfDictGetBool(displayInfo, CFSTR("kCGDisplayIsVirtualDevice"), &isVirtual) == NULL && isVirtual) + continue; + uint8_t edidData[128] = {}; uint32_t edidLength = 0; - if (false || !ffCfDictGetData(displayInfo, CFSTR("IODisplayEDID"), 0, sizeof(edidData), edidData, &edidLength)) + if (ffCfDictGetData(displayInfo, CFSTR("IODisplayEDID"), 0, sizeof(edidData), edidData, &edidLength) == NULL) { uint32_t width, height; ffEdidGetPhysicalResolution(edidData, &width, &height); @@ -75,6 +79,14 @@ const char* ffDetectMonitor(FFlist* results) monitor->physicalHeight = (uint32_t) (size.height + 0.5); monitor->hdrCompatible = CFDictionaryContainsKey(displayInfo, CFSTR("ReferencePeakHDRLuminance")) || detectHdrSupportWithNSScreen(display); + + int64_t serial, year, week; + if (ffCfDictGetInt64(displayInfo, CFSTR("DisplaySerialNumber"), &serial) == NULL) + monitor->serial = (uint32_t) (uint64_t) serial; + if (ffCfDictGetInt64(displayInfo, CFSTR("DisplayYearManufacture"), &year) == NULL) + monitor->manufactureYear = (uint16_t) year; + if (ffCfDictGetInt64(displayInfo, CFSTR("DisplayWeekManufacture"), &week) == NULL) + monitor->manufactureWeek = (uint16_t) week; } return NULL; diff --git a/src/detection/monitor/monitor_linux.c b/src/detection/monitor/monitor_linux.c index 3b2ef1ea7..8d0f5ec11 100644 --- a/src/detection/monitor/monitor_linux.c +++ b/src/detection/monitor/monitor_linux.c @@ -59,6 +59,7 @@ const char* ffDetectMonitor(FFlist* results) ffStrbufInit(&display->name); ffEdidGetName(edidData, &display->name); ffEdidGetPhysicalSize(edidData, &display->physicalWidth, &display->physicalHeight); + ffEdidGetSerialAndManufactureDate(edidData, &display->serial, &display->manufactureYear, &display->manufactureWeek); display->hdrCompatible = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength); } diff --git a/src/detection/monitor/monitor_windows.c b/src/detection/monitor/monitor_windows.c index f56c5a188..b695cf67a 100644 --- a/src/detection/monitor/monitor_windows.c +++ b/src/detection/monitor/monitor_windows.c @@ -44,6 +44,7 @@ const char* ffDetectMonitor(FFlist* results) FFMonitorResult* display = (FFMonitorResult*) ffListAdd(results); display->width = width; display->height = height; + ffEdidGetSerialAndManufactureDate(edidData, &display->serial, &display->manufactureYear, &display->manufactureWeek); display->hdrCompatible = ffEdidGetHdrCompatible(edidData, edidLength); // Doesn't work. edidLength is always 128 ffStrbufInit(&display->name); ffEdidGetName(edidData, &display->name); diff --git a/src/modules/monitor/monitor.c b/src/modules/monitor/monitor.c index 35ad8a6c4..776d4fd18 100644 --- a/src/modules/monitor/monitor.c +++ b/src/modules/monitor/monitor.c @@ -59,6 +59,15 @@ void ffPrintMonitor(FFMonitorOptions* options) } else { + char buf[32]; + if (display->serial) + { + const uint8_t* nums = (uint8_t*) &display->serial; + snprintf(buf, sizeof(buf), "%2X-%2X-%2X-%2X", nums[0], nums[1], nums[2], nums[3]); + } + else + buf[0] = '\0'; + ffPrintFormatString(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, FF_MONITOR_NUM_FORMAT_ARGS, (FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &display->name}, {FF_FORMAT_ARG_TYPE_UINT, &display->width}, @@ -67,6 +76,9 @@ void ffPrintMonitor(FFMonitorOptions* options) {FF_FORMAT_ARG_TYPE_UINT, &display->physicalHeight}, {FF_FORMAT_ARG_TYPE_DOUBLE, &inch}, {FF_FORMAT_ARG_TYPE_DOUBLE, &ppi}, + {FF_FORMAT_ARG_TYPE_UINT16, &display->manufactureYear}, + {FF_FORMAT_ARG_TYPE_UINT16, &display->manufactureWeek}, + {FF_FORMAT_ARG_TYPE_STRING, buf}, }); } @@ -131,11 +143,31 @@ void ffGenerateMonitorJsonResult(FF_MAYBE_UNUSED FFMonitorOptions* options, yyjs { yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr); yyjson_mut_obj_add_bool(doc, obj, "hdrCompatible", item->hdrCompatible); - yyjson_mut_obj_add_uint(doc, obj, "width", item->width); - yyjson_mut_obj_add_uint(doc, obj, "height", item->height); yyjson_mut_obj_add_strbuf(doc, obj, "name", &item->name); - yyjson_mut_obj_add_uint(doc, obj, "physicalHeight", item->physicalHeight); - yyjson_mut_obj_add_uint(doc, obj, "physicalWidth", item->physicalWidth); + + yyjson_mut_val* resolution = yyjson_mut_obj_add_obj(doc, obj, "resolution"); + yyjson_mut_obj_add_uint(doc, resolution, "width", item->width); + yyjson_mut_obj_add_uint(doc, resolution, "height", item->height); + + yyjson_mut_val* physical = yyjson_mut_obj_add_obj(doc, obj, "physical"); + yyjson_mut_obj_add_uint(doc, physical, "height", item->physicalHeight); + yyjson_mut_obj_add_uint(doc, physical, "width", item->physicalWidth); + + if (item->manufactureYear) + { + yyjson_mut_val* manufactureDate = yyjson_mut_obj_add_obj(doc, obj, "manufactureDate"); + yyjson_mut_obj_add_uint(doc, manufactureDate, "year", item->manufactureYear); + yyjson_mut_obj_add_uint(doc, manufactureDate, "week", item->manufactureWeek); + } + else + { + yyjson_mut_obj_add_null(doc, obj, "manufactureDate"); + } + + if (item->serial) + yyjson_mut_obj_add_uint(doc, obj, "serial", item->serial); + else + yyjson_mut_obj_add_null(doc, obj, "serial"); } } @@ -154,7 +186,9 @@ void ffPrintMonitorHelpFormat(void) "Display physical width in millimeters", "Display physical height in millimeters", "Display physical diagonal length in inches", - "Display physical pixels per inch (PPI)" + "Year of manufacturing", + "Nth week of manufacturing in the year", + "Serial number", }); } diff --git a/src/util/edidHelper.c b/src/util/edidHelper.c index 5a375dfcf..5fa2c662b 100644 --- a/src/util/edidHelper.c +++ b/src/util/edidHelper.c @@ -50,6 +50,20 @@ void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* h *height = (((uint32_t) edid[68] & 0x0F) << 8) + edid[67]; } +void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial, uint16_t* year, uint16_t* week) +{ + if (edid[17] > 0 && edid[17] < 0xFF) + { + *year = edid[17] + 1990; + *week = edid[16]; + if (*week == 0xFF) *week = 0; + } + else + *year = *week = 0; + + *serial = *(uint32_t*) &edid[12]; +} + bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length) { if (length <= 128) return false; diff --git a/src/util/edidHelper.h b/src/util/edidHelper.h index 2fc8d591d..6e768ddf9 100644 --- a/src/util/edidHelper.h +++ b/src/util/edidHelper.h @@ -7,4 +7,5 @@ void ffEdidGetVendorAndModel(const uint8_t edid[128], FFstrbuf* result); bool ffEdidGetName(const uint8_t edid[128], FFstrbuf* name); void ffEdidGetPhysicalResolution(const uint8_t edid[128], uint32_t* width, uint32_t* height); void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* height); // in mm +void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial, uint16_t* year, uint16_t* week); bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length);