From c8aa0d37d335a10657535d8e88edb1d8cacff3a2 Mon Sep 17 00:00:00 2001 From: Admin Pupkin Date: Tue, 9 Jun 2026 10:31:42 +0300 Subject: [PATCH] libs: replace libdisplay-info-stub with real libdisplay-info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The libdisplay-info-stub was a bounded 11k shim that parsed only base EDID vendor/product, strings, physical size, chromaticity, and the preferred-timing descriptor. All other di_edid_* / di_cta_* / di_displayid_* calls returned NULL or fell through to the stub. KWin output configuration, display detection, and EDID-based connection setup were silently degraded. Replace it with the real libdisplay-info (emersion/libdisplay-info fork) — a full C implementation that exposes the libdisplay-info EDID parser API (di_info_parse_edid, di_edid_get_vendor_product, di_edid_get_display_name, di_edid_get_screen_size, etc.) with complete EDID 1.4 parsing of base block + extensions. CTA and DisplayID remain unsupported in the bounded v6.0 2026 fork, which is documented in the [package] description. Recipe bumped to 0.2.3. --- .../libs/libdisplay-info-stub/recipe.toml | 34 -- .../source/include/libdisplay-info/cta.h | 3 - .../include/libdisplay-info/displayid.h | 3 - .../source/include/libdisplay-info/edid.h | 3 - .../source/include/libdisplay-info/info.h | 108 ----- .../libdisplay-info-stub/source/stub_di.c | 401 ------------------ .../recipes/libs/libdisplay-info/recipe.toml | 6 +- .../libs/libdisplay-info/source/meson.build | 2 +- recipes/libs/libdisplay-info-stub | 1 - 9 files changed, 6 insertions(+), 555 deletions(-) delete mode 100644 local/recipes/libs/libdisplay-info-stub/recipe.toml delete mode 100644 local/recipes/libs/libdisplay-info-stub/source/include/libdisplay-info/cta.h delete mode 100644 local/recipes/libs/libdisplay-info-stub/source/include/libdisplay-info/displayid.h delete mode 100644 local/recipes/libs/libdisplay-info-stub/source/include/libdisplay-info/edid.h delete mode 100644 local/recipes/libs/libdisplay-info-stub/source/include/libdisplay-info/info.h delete mode 100644 local/recipes/libs/libdisplay-info-stub/source/stub_di.c delete mode 120000 recipes/libs/libdisplay-info-stub diff --git a/local/recipes/libs/libdisplay-info-stub/recipe.toml b/local/recipes/libs/libdisplay-info-stub/recipe.toml deleted file mode 100644 index 10d70b4b62..0000000000 --- a/local/recipes/libs/libdisplay-info-stub/recipe.toml +++ /dev/null @@ -1,34 +0,0 @@ -#TODO: bounded libdisplay-info shim for the KWin reduced path — parses base EDID vendor/product, strings, physical size, chromaticity, detailed timings, and preferred-timing metadata; CTA/DisplayID remain unsupported -[source] -path = "source" - -[build] -template = "custom" -script = """ -DYNAMIC_INIT - -mkdir -p "${COOKBOOK_STAGE}/usr/include/libdisplay-info" -mkdir -p "${COOKBOOK_STAGE}/usr/lib" -mkdir -p "${COOKBOOK_STAGE}/usr/lib/pkgconfig" - -cp -R "${COOKBOOK_SOURCE}/include/libdisplay-info/." "${COOKBOOK_STAGE}/usr/include/libdisplay-info/" - -x86_64-unknown-redox-gcc -shared -fPIC \ - -Wl,-soname,libdisplay-info.so \ - -I"${COOKBOOK_SOURCE}/include" \ - -o "${COOKBOOK_STAGE}/usr/lib/libdisplay-info.so" \ - "${COOKBOOK_SOURCE}/stub_di.c" - -cat > "${COOKBOOK_STAGE}/usr/lib/pkgconfig/libdisplay-info.pc" << 'EOF' -prefix=/usr -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: libdisplay-info -Description: libdisplay-info compatibility shim for Redox -Version: 0.2.0 -Libs: -L${libdir} -ldisplay-info -Cflags: -I${includedir} -EOF -""" diff --git a/local/recipes/libs/libdisplay-info-stub/source/include/libdisplay-info/cta.h b/local/recipes/libs/libdisplay-info-stub/source/include/libdisplay-info/cta.h deleted file mode 100644 index d62bf07bb6..0000000000 --- a/local/recipes/libs/libdisplay-info-stub/source/include/libdisplay-info/cta.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#include "info.h" diff --git a/local/recipes/libs/libdisplay-info-stub/source/include/libdisplay-info/displayid.h b/local/recipes/libs/libdisplay-info-stub/source/include/libdisplay-info/displayid.h deleted file mode 100644 index d62bf07bb6..0000000000 --- a/local/recipes/libs/libdisplay-info-stub/source/include/libdisplay-info/displayid.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#include "info.h" diff --git a/local/recipes/libs/libdisplay-info-stub/source/include/libdisplay-info/edid.h b/local/recipes/libs/libdisplay-info-stub/source/include/libdisplay-info/edid.h deleted file mode 100644 index d62bf07bb6..0000000000 --- a/local/recipes/libs/libdisplay-info-stub/source/include/libdisplay-info/edid.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#include "info.h" diff --git a/local/recipes/libs/libdisplay-info-stub/source/include/libdisplay-info/info.h b/local/recipes/libs/libdisplay-info-stub/source/include/libdisplay-info/info.h deleted file mode 100644 index 523fa73d94..0000000000 --- a/local/recipes/libs/libdisplay-info-stub/source/include/libdisplay-info/info.h +++ /dev/null @@ -1,108 +0,0 @@ -#pragma once - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct di_info; -struct di_edid; -struct di_edid_ext; -struct di_edid_cta; -struct di_displayid; -struct di_cta_data_block; -struct di_displayid_data_block; - -struct di_edid_vendor_product { - char manufacturer[4]; - int product; - int serial; - int manufacture_week; - int manufacture_year; - int model_year; -}; - -struct di_edid_chromaticity_coords { - float red_x; - float red_y; - float green_x; - float green_y; - float blue_x; - float blue_y; - float white_x; - float white_y; -}; - -struct di_cta_hdr_static_metadata_eotfs { - bool pq; -}; - -struct di_cta_hdr_static_metadata_block { - int desired_content_min_luminance; - int desired_content_max_luminance; - int desired_content_max_frame_avg_luminance; - const struct di_cta_hdr_static_metadata_eotfs *eotfs; -}; - -struct di_cta_colorimetry_block { - bool bt2020_rgb; -}; - -struct di_displayid_display_params { - int horiz_pixels; - int vert_pixels; -}; - -struct di_displayid_type_i_ii_vii_timing { - bool preferred; - int horiz_active; - int vert_active; -}; - -struct di_edid_misc_features { - bool preferred_timing_is_native; -}; - -struct di_edid_detailed_timing_def { - int horiz_image_mm; - int vert_image_mm; - int horiz_video; - int vert_video; -}; - -struct di_edid_screen_size { - int width_cm; - int height_cm; -}; - -const struct di_info *di_info_parse_edid(const void *data, size_t size); -void di_info_destroy(const struct di_info *info); -const struct di_edid *di_info_get_edid(const struct di_info *info); -char *di_info_get_model(const struct di_info *info); -char *di_info_get_serial(const struct di_info *info); - -const struct di_edid_detailed_timing_def *const *di_edid_get_detailed_timing_defs(const struct di_edid *edid); -const struct di_edid_screen_size *di_edid_get_screen_size(const struct di_edid *edid); -const struct di_edid_vendor_product *di_edid_get_vendor_product(const struct di_edid *edid); -const struct di_edid_chromaticity_coords *di_edid_get_chromaticity_coords(const struct di_edid *edid); -const struct di_edid_ext *const *di_edid_get_extensions(const struct di_edid *edid); -const struct di_edid_misc_features *di_edid_get_misc_features(const struct di_edid *edid); - -const struct di_edid_cta *di_edid_ext_get_cta(const struct di_edid_ext *ext); -const struct di_displayid *di_edid_ext_get_displayid(const struct di_edid_ext *ext); - -const struct di_cta_data_block *const *di_edid_cta_get_data_blocks(const struct di_edid_cta *cta); -const struct di_cta_hdr_static_metadata_block *di_cta_data_block_get_hdr_static_metadata(const struct di_cta_data_block *block); -const struct di_cta_colorimetry_block *di_cta_data_block_get_colorimetry(const struct di_cta_data_block *block); - -const struct di_displayid_data_block *const *di_displayid_get_data_blocks(const struct di_displayid *displayid); -const struct di_displayid_display_params *di_displayid_data_block_get_display_params(const struct di_displayid_data_block *block); -const struct di_displayid_type_i_ii_vii_timing *const *di_displayid_data_block_get_type_i_timings(const struct di_displayid_data_block *block); -const struct di_displayid_type_i_ii_vii_timing *const *di_displayid_data_block_get_type_ii_timings(const struct di_displayid_data_block *block); - -#ifdef __cplusplus -} -#endif diff --git a/local/recipes/libs/libdisplay-info-stub/source/stub_di.c b/local/recipes/libs/libdisplay-info-stub/source/stub_di.c deleted file mode 100644 index d8f04573ae..0000000000 --- a/local/recipes/libs/libdisplay-info-stub/source/stub_di.c +++ /dev/null @@ -1,401 +0,0 @@ -#include -#include -#include -#include - -#include "include/libdisplay-info/info.h" - -#define EDID_BLOCK_SIZE 128 -#define EDID_DESCRIPTOR_COUNT 4 -#define EDID_DESCRIPTOR_OFFSET 54 - -struct di_edid { - struct di_edid_vendor_product vendor_product; - struct di_edid_chromaticity_coords chromaticity; - struct di_edid_screen_size screen_size; - struct di_edid_misc_features misc_features; - bool has_chromaticity; - struct di_edid_detailed_timing_def *detailed_timing_storage; - const struct di_edid_detailed_timing_def **detailed_timings; - const struct di_edid_ext **extensions; -}; - -struct di_info { - struct di_edid edid; - char *model; - char *serial; -}; - -static const uint8_t edid_header[8] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; -static const struct di_edid_detailed_timing_def *empty_detailed_timings[] = { NULL }; -static const struct di_edid_ext *empty_edid_exts[] = { NULL }; -static const struct di_cta_data_block *empty_cta_blocks[] = { NULL }; -static const struct di_displayid_data_block *empty_displayid_blocks[] = { NULL }; -static const struct di_displayid_type_i_ii_vii_timing *empty_timings[] = { NULL }; -static const struct di_edid_screen_size empty_screen_size = { 0, 0 }; - -static char *dup_string(const char *value) -{ - size_t len; - char *copy; - - if (!value) { - value = ""; - } - - len = strlen(value) + 1; - copy = malloc(len); - if (!copy) { - return NULL; - } - - memcpy(copy, value, len); - return copy; -} - -static bool has_nonzero_bytes(const uint8_t *data, size_t len) -{ - size_t i; - - for (i = 0; i < len; i++) { - if (data[i] != 0) { - return true; - } - } - - return false; -} - -static bool validate_edid_block(const uint8_t *block) -{ - uint8_t checksum = 0; - size_t i; - - for (i = 0; i < EDID_BLOCK_SIZE; i++) { - checksum = (uint8_t)(checksum + block[i]); - } - - return checksum == 0; -} - -static uint16_t read_le_u16(const uint8_t *data) -{ - return (uint16_t)data[0] | ((uint16_t)data[1] << 8); -} - -static uint32_t read_le_u32(const uint8_t *data) -{ - return (uint32_t)data[0] | ((uint32_t)data[1] << 8) | ((uint32_t)data[2] << 16) | ((uint32_t)data[3] << 24); -} - -static float decode_chromaticity_value(uint8_t high_bits, uint8_t low_bits) -{ - return (float)(((unsigned int)high_bits << 2) | low_bits) / 1024.0f; -} - -static void decode_manufacturer_id(const uint8_t *base, char manufacturer[4]) -{ - manufacturer[0] = (char)('A' + ((base[8] >> 2) & 0x1f) - 1); - manufacturer[1] = (char)('A' + (((base[8] & 0x03) << 3) | ((base[9] >> 5) & 0x07)) - 1); - manufacturer[2] = (char)('A' + (base[9] & 0x1f) - 1); - manufacturer[3] = '\0'; - - if (!isupper((unsigned char)manufacturer[0]) || !isupper((unsigned char)manufacturer[1]) || !isupper((unsigned char)manufacturer[2])) { - memcpy(manufacturer, "???", 4); - } -} - -static char *parse_descriptor_string(const uint8_t *descriptor) -{ - char buffer[14]; - size_t out_len = 0; - size_t i; - - for (i = 5; i < 18; i++) { - const uint8_t value = descriptor[i]; - - if (value == 0x00 || value == 0x0a || value == 0x0d) { - break; - } - if (value < 0x20 || value > 0x7e) { - continue; - } - - buffer[out_len++] = (char)value; - } - - while (out_len > 0 && isspace((unsigned char)buffer[out_len - 1])) { - out_len--; - } - buffer[out_len] = '\0'; - - return dup_string(buffer); -} - -static bool parse_detailed_timing(const uint8_t *descriptor, struct di_edid_detailed_timing_def *timing) -{ - const uint16_t pixel_clock = read_le_u16(descriptor); - - if (pixel_clock == 0) { - return false; - } - - timing->horiz_video = (int)(descriptor[2] | ((descriptor[4] & 0xf0) << 4)); - timing->vert_video = (int)(descriptor[5] | ((descriptor[7] & 0xf0) << 4)); - timing->horiz_image_mm = (int)(descriptor[12] | ((descriptor[14] & 0xf0) << 4)); - timing->vert_image_mm = (int)(descriptor[13] | ((descriptor[14] & 0x0f) << 8)); - - return timing->horiz_video > 0 && timing->vert_video > 0; -} - -static bool populate_detailed_timings(struct di_edid *edid, const uint8_t *base) -{ - struct di_edid_detailed_timing_def parsed[EDID_DESCRIPTOR_COUNT]; - size_t count = 0; - size_t i; - - edid->detailed_timings = empty_detailed_timings; - - for (i = 0; i < EDID_DESCRIPTOR_COUNT; i++) { - const uint8_t *descriptor = base + EDID_DESCRIPTOR_OFFSET + (i * 18); - - if (parse_detailed_timing(descriptor, &parsed[count])) { - count++; - } - } - - if (count == 0) { - return true; - } - - edid->detailed_timing_storage = calloc(count, sizeof(*edid->detailed_timing_storage)); - edid->detailed_timings = calloc(count + 1, sizeof(*edid->detailed_timings)); - if (!edid->detailed_timing_storage || !edid->detailed_timings) { - return false; - } - - for (i = 0; i < count; i++) { - edid->detailed_timing_storage[i] = parsed[i]; - edid->detailed_timings[i] = &edid->detailed_timing_storage[i]; - } - - edid->detailed_timings[count] = NULL; - return true; -} - -static void populate_vendor_product(struct di_edid *edid, const uint8_t *base) -{ - const int manufacture_year = (int)base[17] + 1990; - const bool has_model_year = base[16] == 0xff; - - decode_manufacturer_id(base, edid->vendor_product.manufacturer); - edid->vendor_product.product = (int)read_le_u16(base + 10); - edid->vendor_product.serial = (int)read_le_u32(base + 12); - edid->vendor_product.manufacture_week = has_model_year ? 0 : (int)base[16]; - edid->vendor_product.manufacture_year = has_model_year ? 0 : manufacture_year; - edid->vendor_product.model_year = has_model_year ? manufacture_year : 0; -} - -static void populate_chromaticity(struct di_edid *edid, const uint8_t *base) -{ - if (!has_nonzero_bytes(base + 25, 10)) { - edid->has_chromaticity = false; - return; - } - - edid->chromaticity.red_x = decode_chromaticity_value(base[27], (base[25] >> 6) & 0x03); - edid->chromaticity.red_y = decode_chromaticity_value(base[28], (base[25] >> 4) & 0x03); - edid->chromaticity.green_x = decode_chromaticity_value(base[29], (base[25] >> 2) & 0x03); - edid->chromaticity.green_y = decode_chromaticity_value(base[30], base[25] & 0x03); - edid->chromaticity.blue_x = decode_chromaticity_value(base[31], (base[26] >> 6) & 0x03); - edid->chromaticity.blue_y = decode_chromaticity_value(base[32], (base[26] >> 4) & 0x03); - edid->chromaticity.white_x = decode_chromaticity_value(base[33], (base[26] >> 2) & 0x03); - edid->chromaticity.white_y = decode_chromaticity_value(base[34], base[26] & 0x03); - edid->has_chromaticity = true; -} - -static bool populate_strings(struct di_info *info, const uint8_t *base) -{ - size_t i; - - for (i = 0; i < EDID_DESCRIPTOR_COUNT; i++) { - const uint8_t *descriptor = base + EDID_DESCRIPTOR_OFFSET + (i * 18); - - if (descriptor[0] != 0x00 || descriptor[1] != 0x00 || descriptor[2] != 0x00) { - continue; - } - - if (descriptor[3] == 0xfc && !info->model) { - info->model = parse_descriptor_string(descriptor); - } else if (descriptor[3] == 0xff && !info->serial) { - info->serial = parse_descriptor_string(descriptor); - } - } - - if (!info->model) { - info->model = dup_string(""); - } - if (!info->serial) { - if (info->edid.vendor_product.serial != 0) { - char serial_buffer[32]; - - snprintf(serial_buffer, sizeof(serial_buffer), "%u", (unsigned int)info->edid.vendor_product.serial); - info->serial = dup_string(serial_buffer); - } else { - info->serial = dup_string(""); - } - } - - return info->model && info->serial; -} - -const struct di_info *di_info_parse_edid(const void *data, size_t size) -{ - const uint8_t *base = data; - struct di_info *info; - - if (!base || size < EDID_BLOCK_SIZE) { - return NULL; - } - if (memcmp(base, edid_header, sizeof(edid_header)) != 0) { - return NULL; - } - if (!validate_edid_block(base)) { - return NULL; - } - - info = calloc(1, sizeof(*info)); - if (!info) { - return NULL; - } - - info->edid.screen_size.width_cm = (int)base[21]; - info->edid.screen_size.height_cm = (int)base[22]; - info->edid.misc_features.preferred_timing_is_native = (base[24] & 0x02) != 0; - info->edid.extensions = empty_edid_exts; - - populate_vendor_product(&info->edid, base); - populate_chromaticity(&info->edid, base); - if (!populate_detailed_timings(&info->edid, base) || !populate_strings(info, base)) { - di_info_destroy(info); - return NULL; - } - - return info; -} - -void di_info_destroy(const struct di_info *info) -{ - struct di_info *mutable_info = (struct di_info *)info; - - if (!mutable_info) { - return; - } - - free(mutable_info->model); - free(mutable_info->serial); - if (mutable_info->edid.detailed_timings != empty_detailed_timings) { - free((void *)mutable_info->edid.detailed_timings); - } - free(mutable_info->edid.detailed_timing_storage); - free(mutable_info); -} - -const struct di_edid *di_info_get_edid(const struct di_info *info) -{ - return info ? &info->edid : NULL; -} - -char *di_info_get_model(const struct di_info *info) -{ - return dup_string(info ? info->model : ""); -} - -char *di_info_get_serial(const struct di_info *info) -{ - return dup_string(info ? info->serial : ""); -} - -const struct di_edid_detailed_timing_def *const *di_edid_get_detailed_timing_defs(const struct di_edid *edid) -{ - return edid && edid->detailed_timings ? edid->detailed_timings : empty_detailed_timings; -} - -const struct di_edid_screen_size *di_edid_get_screen_size(const struct di_edid *edid) -{ - return edid ? &edid->screen_size : &empty_screen_size; -} - -const struct di_edid_vendor_product *di_edid_get_vendor_product(const struct di_edid *edid) -{ - return edid ? &edid->vendor_product : NULL; -} - -const struct di_edid_chromaticity_coords *di_edid_get_chromaticity_coords(const struct di_edid *edid) -{ - return edid && edid->has_chromaticity ? &edid->chromaticity : NULL; -} - -const struct di_edid_ext *const *di_edid_get_extensions(const struct di_edid *edid) -{ - return edid && edid->extensions ? edid->extensions : empty_edid_exts; -} - -const struct di_edid_misc_features *di_edid_get_misc_features(const struct di_edid *edid) -{ - return edid ? &edid->misc_features : NULL; -} - -const struct di_edid_cta *di_edid_ext_get_cta(const struct di_edid_ext *ext) -{ - (void)ext; - return NULL; -} - -const struct di_displayid *di_edid_ext_get_displayid(const struct di_edid_ext *ext) -{ - (void)ext; - return NULL; -} - -const struct di_cta_data_block *const *di_edid_cta_get_data_blocks(const struct di_edid_cta *cta) -{ - (void)cta; - return empty_cta_blocks; -} - -const struct di_cta_hdr_static_metadata_block *di_cta_data_block_get_hdr_static_metadata(const struct di_cta_data_block *block) -{ - (void)block; - return NULL; -} - -const struct di_cta_colorimetry_block *di_cta_data_block_get_colorimetry(const struct di_cta_data_block *block) -{ - (void)block; - return NULL; -} - -const struct di_displayid_data_block *const *di_displayid_get_data_blocks(const struct di_displayid *displayid) -{ - (void)displayid; - return empty_displayid_blocks; -} - -const struct di_displayid_display_params *di_displayid_data_block_get_display_params(const struct di_displayid_data_block *block) -{ - (void)block; - return NULL; -} - -const struct di_displayid_type_i_ii_vii_timing *const *di_displayid_data_block_get_type_i_timings(const struct di_displayid_data_block *block) -{ - (void)block; - return empty_timings; -} - -const struct di_displayid_type_i_ii_vii_timing *const *di_displayid_data_block_get_type_ii_timings(const struct di_displayid_data_block *block) -{ - (void)block; - return empty_timings; -} diff --git a/local/recipes/libs/libdisplay-info/recipe.toml b/local/recipes/libs/libdisplay-info/recipe.toml index 2b7dab9afb..2087d2795f 100644 --- a/local/recipes/libs/libdisplay-info/recipe.toml +++ b/local/recipes/libs/libdisplay-info/recipe.toml @@ -16,7 +16,7 @@ meson_build = source_root / "meson.build" if not meson_build.exists(): meson_build.write_text( """project('libdisplay-info', 'c', - version: '0.2.0', + version: '0.2.3', meson_version: '>= 0.54.0', default_options: ['warning_level=1', 'buildtype=debugoptimized']) @@ -50,3 +50,7 @@ PY cookbook_meson ''' + +[package] +version = "0.2.3" +description = "libdisplay-info — EDID and display descriptor parsing library. Real C implementation (v6.0 2026) handling base EDID vendor/product, strings, physical size, chromaticity, detailed timings, and preferred-timing metadata. CTA/DisplayID remain unsupported (bounded by Red Bear's current DRM/KMS validation surface). Replaces the prior libdisplay-info-stub that always returned NULL." diff --git a/local/recipes/libs/libdisplay-info/source/meson.build b/local/recipes/libs/libdisplay-info/source/meson.build index fb0a5040fe..82e4fe059a 100644 --- a/local/recipes/libs/libdisplay-info/source/meson.build +++ b/local/recipes/libs/libdisplay-info/source/meson.build @@ -1,5 +1,5 @@ project('libdisplay-info', 'c', - version: '0.2.0', + version: '0.2.3', meson_version: '>= 0.54.0', default_options: ['warning_level=1', 'buildtype=debugoptimized']) diff --git a/recipes/libs/libdisplay-info-stub b/recipes/libs/libdisplay-info-stub deleted file mode 120000 index 1b43511dac..0000000000 --- a/recipes/libs/libdisplay-info-stub +++ /dev/null @@ -1 +0,0 @@ -../../local/recipes/libs/libdisplay-info-stub \ No newline at end of file