From 810ded8fd608c09a62b57ac3cc4daafd16b5aea1 Mon Sep 17 00:00:00 2001 From: Joan Torres Lopez Date: Mon, 15 Dec 2025 16:53:49 +0100 Subject: [PATCH] Add gnome-qr library Resolves: https://redhat.atlassian.net/browse/RHEL-172426 --- 0001-Introduce-gnome-qr-library.patch | 2128 +++++++++++++++++++++++++ gnome-desktop3.spec | 11 +- 2 files changed, 2138 insertions(+), 1 deletion(-) create mode 100644 0001-Introduce-gnome-qr-library.patch diff --git a/0001-Introduce-gnome-qr-library.patch b/0001-Introduce-gnome-qr-library.patch new file mode 100644 index 0000000..9bc3fff --- /dev/null +++ b/0001-Introduce-gnome-qr-library.patch @@ -0,0 +1,2128 @@ +From 2b4aa5f90767d0f08519744f17783252fc537802 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Thu, 27 Nov 2025 18:03:16 +0100 +Subject: [PATCH 01/26] meson: Add QR-Code-generator as a subproject + +Will be used by next commit to generate QR codes + +Part-of: +--- + .gitignore | 1 + + meson.build | 3 +++ + subprojects/packagefiles/qrcodegen/meson.build | 10 ++++++++++ + subprojects/qrcodegen.wrap | 5 +++++ + 4 files changed, 19 insertions(+) + create mode 100644 .gitignore + create mode 100644 subprojects/packagefiles/qrcodegen/meson.build + create mode 100644 subprojects/qrcodegen.wrap + +diff --git a/.gitignore b/.gitignore +new file mode 100644 +index 0000000..97b1a62 +--- /dev/null ++++ b/.gitignore +@@ -0,0 +1 @@ ++subprojects/qrcodegen +diff --git a/meson.build b/meson.build +index 5a44db2..d5f19c3 100644 +--- a/meson.build ++++ b/meson.build +@@ -130,6 +130,9 @@ version_xml = configure_file( + ) + install_data(version_xml, install_dir: versiondir) + ++qrcodegen = subproject('qrcodegen') ++qrcodegen_dep = qrcodegen.get_variable('qrcodegen_dep') ++ + subdir('libgnome-desktop') + subdir('po') + subdir('tests') +diff --git a/subprojects/packagefiles/qrcodegen/meson.build b/subprojects/packagefiles/qrcodegen/meson.build +new file mode 100644 +index 0000000..0a66ccb +--- /dev/null ++++ b/subprojects/packagefiles/qrcodegen/meson.build +@@ -0,0 +1,10 @@ ++project('qrcodegen', 'c') ++ ++libqrcodegen = static_library('qrcodegen', ++ 'c/qrcodegen.c', ++ include_directories: include_directories('c') ++) ++qrcodegen_dep = declare_dependency( ++ link_with: libqrcodegen, ++ include_directories: include_directories('c') ++) +diff --git a/subprojects/qrcodegen.wrap b/subprojects/qrcodegen.wrap +new file mode 100644 +index 0000000..9080ca4 +--- /dev/null ++++ b/subprojects/qrcodegen.wrap +@@ -0,0 +1,5 @@ ++[wrap-git] ++url = https://github.com/nayuki/QR-Code-generator.git ++revision = head ++depth = 1 ++patch_directory = qrcodegen +From a4b42db6fc674a16ef2b4395afbf6ee9eea3b8fb Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Thu, 20 Nov 2025 19:54:34 +0100 +Subject: [PATCH 02/26] Introduce gnome-qr library + +g-c-c and now gnome-shell need to generate QR codes. + +Originaly g-c-c needed to create QR codes and used a copy of the qrcodegen +library implementation to avoid dependencies. + +Now gnome-shell needs to generate QR codes too, so it makes sense to +port the g-c-c QR code generation to libgnome-desktop. + +Part-of: +--- + .../gnome-desktop3-sections.txt | 14 + + libgnome-desktop/gnome-qr-gtk/meson.build | 67 ++++ + libgnome-desktop/gnome-qr/gnome-qr.c | 306 ++++++++++++++++++ + libgnome-desktop/gnome-qr/gnome-qr.h | 125 +++++++ + libgnome-desktop/gnome-qr/meson.build | 41 +++ + libgnome-desktop/meson.build | 1 + + meson.build | 4 + + 7 files changed, 558 insertions(+) + create mode 100644 libgnome-desktop/gnome-qr-gtk/meson.build + create mode 100644 libgnome-desktop/gnome-qr/gnome-qr.c + create mode 100644 libgnome-desktop/gnome-qr/gnome-qr.h + create mode 100644 libgnome-desktop/gnome-qr/meson.build + +diff --git a/docs/reference/gnome-desktop3/gnome-desktop3-sections.txt b/docs/reference/gnome-desktop3/gnome-desktop3-sections.txt +index 4f189fc..0b6b6ec 100644 +--- a/docs/reference/gnome-desktop3/gnome-desktop3-sections.txt ++++ b/docs/reference/gnome-desktop3/gnome-desktop3-sections.txt +@@ -359,3 +359,17 @@ GNOME_TYPE_PNP_IDS + GnomePnpIdsPrivate + gnome_pnp_ids_get_type + ++ ++
++gnome-qr ++QR Code Generation ++GnomeQrEccLevel ++GnomeQrPixelFormat ++GnomeQrColor ++GNOME_QR_BYTES_PER_FORMAT ++GNOME_QR_COLOR_WHITE ++GNOME_QR_COLOR_BLACK ++gnome_qr_generate_qr_code_sync ++gnome_qr_generate_qr_code_async ++gnome_qr_generate_qr_code_finish ++
+diff --git a/libgnome-desktop/gnome-qr/gnome-qr.c b/libgnome-desktop/gnome-qr/gnome-qr.c +new file mode 100644 +index 0000000..e22bb1f +--- /dev/null ++++ b/libgnome-desktop/gnome-qr/gnome-qr.c +@@ -0,0 +1,306 @@ ++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ ++/* ++ * Copyright 2024-2025 Red Hat, Inc ++ * Copyright 2024-2025 Canonical Ltd ++ * ++ * SPDX-License-Identifier: LGPL-2.1-or-later ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General ++ * Public License along with this library; if not, see . ++ * ++ * Author: Ray Strode ++ * Marco Trevisan ++ * Joan Torres Lopez ++ */ ++ ++#include "config.h" ++ ++#include "gnome-qr.h" ++ ++#include ++ ++typedef struct ++{ ++ char *text; ++ size_t size; ++ size_t out_size; ++ GnomeQrColor *bg_color; ++ GnomeQrColor *fg_color; ++ GnomeQrPixelFormat format; ++ GnomeQrEccLevel ecc; ++} GnomeQrCodeData; ++ ++static void ++gnome_qr_code_data_free (GnomeQrCodeData *data) ++{ ++ g_clear_pointer (&data->text, g_free); ++ g_clear_pointer (&data->bg_color, g_free); ++ g_clear_pointer (&data->fg_color, g_free); ++ g_free (data); ++} ++ ++static enum qrcodegen_Ecc ++gnome_qr_ecc_level_to_qrcodegen_ecc (GnomeQrEccLevel ecc) ++{ ++ switch (ecc) { ++ case GNOME_QR_ECC_LEVEL_LOW: ++ return qrcodegen_Ecc_LOW; ++ case GNOME_QR_ECC_LEVEL_MEDIUM: ++ return qrcodegen_Ecc_MEDIUM; ++ case GNOME_QR_ECC_LEVEL_QUARTILE: ++ return qrcodegen_Ecc_QUARTILE; ++ case GNOME_QR_ECC_LEVEL_HIGH: ++ return qrcodegen_Ecc_HIGH; ++ } ++ g_assert_not_reached (); ++} ++ ++static void ++fill_pixel (GByteArray *array, ++ const GnomeQrColor *color, ++ GnomeQrPixelFormat format, ++ int pixel_size) ++{ ++ guint i; ++ ++ for (i = 0; i < pixel_size; i++) { ++ g_byte_array_append (array, &color->red, 1); ++ g_byte_array_append (array, &color->green, 1); ++ g_byte_array_append (array, &color->blue, 1); ++ ++ if (format == GNOME_QR_PIXEL_FORMAT_RGBA_8888) ++ g_byte_array_append (array, &color->alpha, 1); ++ } ++} ++ ++/** ++ * gnome_qr_generate_qr_code_sync: ++ * @text: the text of which generate the qr code ++ * @size: The requested size in pixels (width and height) for the square QR code ++ * @bg_color: (nullable): The background color of the code ++ * or %NULL to use default (white) ++ * @fg_color: (nullable): The foreground color of the code ++ * or %NULL to use default (black) ++ * @format: The pixel format for the output image data ++ * @ecc: The error correction level ++ * @out_size: (out) (nullable): location to store the actual output size in pixels (width and height) of the square QR code, or %NULL ++ * @cancellable: (nullable): A #GCancellable to cancel the operation ++ * @error: #GError for error reporting ++ * ++ * Generates the QrCode synchronously. ++ * ++ * Returns: (transfer full): The pixel data or %NULL on error ++ */ ++GBytes * ++gnome_qr_generate_qr_code_sync (const char *text, ++ size_t size, ++ const GnomeQrColor *bg_color, ++ const GnomeQrColor *fg_color, ++ GnomeQrPixelFormat format, ++ GnomeQrEccLevel ecc, ++ size_t *out_size, ++ GCancellable *cancellable, ++ GError **error) ++{ ++ g_autoptr (GByteArray) qr_matrix = NULL; ++ uint8_t qr_code[qrcodegen_BUFFER_LEN_FOR_VERSION (qrcodegen_VERSION_MAX)]; ++ uint8_t temp_buf[qrcodegen_BUFFER_LEN_FOR_VERSION (qrcodegen_VERSION_MAX)]; ++ gint pixel_size, qr_size, total_size; ++ gint column, row, i; ++ ++ g_return_val_if_fail (text != NULL, NULL); ++ g_return_val_if_fail (size > 0, NULL); ++ ++ if (format == GNOME_QR_PIXEL_FORMAT_RGB_888) { ++ g_return_val_if_fail (!bg_color || bg_color->alpha == 255, NULL); ++ g_return_val_if_fail (!fg_color || fg_color->alpha == 255, NULL); ++ } ++ ++ if (g_cancellable_set_error_if_cancelled (cancellable, error)) ++ return NULL; ++ ++ if (!qrcodegen_encodeText (text, ++ temp_buf, ++ qr_code, ++ gnome_qr_ecc_level_to_qrcodegen_ecc (ecc), ++ qrcodegen_VERSION_MIN, ++ qrcodegen_VERSION_MAX, ++ qrcodegen_Mask_AUTO, ++ FALSE)) { ++ g_set_error (error, ++ G_IO_ERROR, ++ G_IO_ERROR_FAILED, ++ "QRCode generation failed for content %s", ++ text); ++ return NULL; ++ } ++ ++ if (g_cancellable_set_error_if_cancelled (cancellable, error)) ++ return NULL; ++ ++ if (!bg_color) ++ bg_color = &GNOME_QR_COLOR_WHITE; ++ ++ if (!fg_color) ++ fg_color = &GNOME_QR_COLOR_BLACK; ++ ++ qr_size = qrcodegen_getSize (qr_code); ++ pixel_size = MAX (1, size / qr_size); ++ total_size = qr_size * pixel_size; ++ ++ qr_matrix = g_byte_array_sized_new (total_size * total_size * pixel_size * ++ GNOME_QR_BYTES_PER_FORMAT (format)); ++ ++ for (column = 0; column < total_size; ++column) { ++ for (i = 0; i < pixel_size; ++i) { ++ for (row = 0; row < qr_size; ++row) { ++ if (qrcodegen_getModule (qr_code, column, row)) ++ fill_pixel (qr_matrix, fg_color, format, pixel_size); ++ else ++ fill_pixel (qr_matrix, bg_color, format, pixel_size); ++ } ++ } ++ ++ if (g_cancellable_set_error_if_cancelled (cancellable, error)) ++ return NULL; ++ } ++ ++ if (out_size) ++ *out_size = total_size; ++ ++ return g_byte_array_free_to_bytes (g_steal_pointer (&qr_matrix)); ++} ++ ++ ++static void ++generate_qr_code_in_thread (GTask *task, ++ gpointer source, ++ gpointer task_data, ++ GCancellable *cancellable) ++{ ++ GnomeQrCodeData *data = task_data; ++ g_autoptr (GError) error = NULL; ++ g_autoptr (GBytes) icon = NULL; ++ ++ icon = gnome_qr_generate_qr_code_sync (data->text, ++ data->size, ++ data->bg_color, ++ data->fg_color, ++ data->format, ++ data->ecc, ++ &data->out_size, ++ cancellable, ++ &error); ++ if (!icon) { ++ g_task_return_error (task, g_steal_pointer (&error)); ++ return; ++ } ++ ++ g_task_return_pointer (task, g_steal_pointer (&icon), (GDestroyNotify) g_bytes_unref); ++} ++ ++/** ++ * gnome_qr_generate_qr_code_async: ++ * @text: the text of which generate the qr code ++ * @size: The requested size in pixels (width and height) for the square QR code ++ * @bg_color: (nullable): The background color of the code ++ * or %NULL to use default (white) ++ * @fg_color: (nullable): The foreground color of the code ++ * or %NULL to use default (black) ++ * @format: The pixel format for the output image data ++ * @ecc: The error correction level ++ * @cancellable: (nullable): A #GCancellable to cancel the operation ++ * @callback: (scope async): function to call returning success or failure ++ * of the async grabbing ++ * @user_data: the data to pass to callback function ++ * ++ * Generates the QrCode asynchronously. ++ * ++ * Use gnome_qr_generate_qr_code_finish() to complete it. ++ */ ++void ++gnome_qr_generate_qr_code_async (const char *text, ++ size_t size, ++ const GnomeQrColor *bg_color, ++ const GnomeQrColor *fg_color, ++ GnomeQrPixelFormat format, ++ GnomeQrEccLevel ecc, ++ GCancellable *cancellable, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ g_autoptr (GTask) task = NULL; ++ GnomeQrCodeData *data; ++ ++ if (!text || *text == '\0') { ++ if (callback) ++ g_task_report_new_error (NULL, ++ callback, ++ user_data, ++ gnome_qr_generate_qr_code_async, ++ G_IO_ERROR, ++ G_IO_ERROR_INVALID_DATA, ++ "No valid QR code text is provided"); ++ return; ++ } ++ ++ data = g_new0 (GnomeQrCodeData, 1); ++ data->text = g_strdup (text); ++ data->size = size; ++ data->bg_color = g_memdup2 (bg_color, sizeof (GnomeQrColor)); ++ data->fg_color = g_memdup2 (fg_color, sizeof (GnomeQrColor)); ++ data->format = format; ++ data->ecc = ecc; ++ ++ task = g_task_new (NULL, cancellable, callback, user_data); ++ g_task_set_source_tag (task, gnome_qr_generate_qr_code_async); ++ g_task_set_task_data (task, data, ++ (GDestroyNotify) gnome_qr_code_data_free); ++ g_task_set_return_on_cancel (task, TRUE); ++ g_task_run_in_thread (task, generate_qr_code_in_thread); ++} ++ ++/** ++ * gnome_qr_generate_qr_code_finish: ++ * @result: the #GAsyncResult that was provided to the callback ++ * @out_size: (out) (nullable): location to store the actual output size in pixels (width and height) of the square QR code, or %NULL ++ * @error: #GError for error reporting ++ * ++ * Finish the asynchronous operation started by ++ * gnome_qr_generate_qr_code_async() and obtain its result. ++ * ++ * Returns: (transfer full): The pixel data or %NULL on error ++ */ ++GBytes * ++gnome_qr_generate_qr_code_finish (GAsyncResult *result, ++ size_t *out_size, ++ GError **error) ++{ ++ GnomeQrCodeData *data; ++ g_autoptr (GBytes) pixel_data = NULL; ++ ++ g_return_val_if_fail (G_IS_TASK (result), FALSE); ++ g_return_val_if_fail (g_async_result_is_tagged (result, ++ gnome_qr_generate_qr_code_async), ++ NULL); ++ ++ pixel_data = g_task_propagate_pointer (G_TASK (result), error); ++ if (!pixel_data) ++ return NULL; ++ ++ data = g_task_get_task_data (G_TASK (result)); ++ if (out_size) ++ *out_size = data->out_size; ++ ++ return g_steal_pointer (&pixel_data); ++} +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.h b/libgnome-desktop/gnome-qr/gnome-qr.h +new file mode 100644 +index 0000000..4d89c59 +--- /dev/null ++++ b/libgnome-desktop/gnome-qr/gnome-qr.h +@@ -0,0 +1,125 @@ ++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ ++/* ++ * Copyright 2024-2025 Red Hat, Inc ++ * Copyright 2024-2025 Canonical Ltd ++ * ++ * SPDX-License-Identifier: LGPL-2.1-or-later ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General ++ * Public License along with this library; if not, see . ++ * ++ * Author: Ray Strode ++ * Marco Trevisan ++ * Joan Torres Lopez ++ */ ++ ++#pragma once ++ ++#include ++#include ++#include ++ ++/** ++ * GNOME_QR_BYTES_PER_FORMAT: ++ * @format: a #GnomeQrPixelFormat ++ * ++ * Calculates the number of bytes per pixel for a given pixel format. ++ * ++ * Returns: the number of bytes ++ */ ++#define GNOME_QR_BYTES_PER_FORMAT(format) \ ++ ((format) == GNOME_QR_PIXEL_FORMAT_RGB_888 ? 3 : 4) ++ ++/** ++ * GNOME_QR_COLOR_WHITE: ++ * ++ * Predefined white color (255, 255, 255, 255). ++ */ ++#define GNOME_QR_COLOR_WHITE ((GnomeQrColor) { 255, 255, 255, 255 }) ++ ++/** ++ * GNOME_QR_COLOR_BLACK: ++ * ++ * Predefined black color (0, 0, 0, 255). ++ */ ++#define GNOME_QR_COLOR_BLACK ((GnomeQrColor) { 0, 0, 0, 255 }) ++ ++/** ++ * GnomeQrEccLevel: ++ * @GNOME_QR_ECC_LEVEL_LOW: Low error correction (~7% recovery capability) ++ * @GNOME_QR_ECC_LEVEL_MEDIUM: Medium error correction (~15% recovery capability) ++ * @GNOME_QR_ECC_LEVEL_QUARTILE: Quartile error correction (~25% recovery capability) ++ * @GNOME_QR_ECC_LEVEL_HIGH: High error correction (~30% recovery capability) ++ * ++ * Error correction levels for QR codes. Higher levels provide better error ++ * recovery at the cost of requiring bigger dimensions. ++ */ ++typedef enum { ++ GNOME_QR_ECC_LEVEL_LOW, ++ GNOME_QR_ECC_LEVEL_MEDIUM, ++ GNOME_QR_ECC_LEVEL_QUARTILE, ++ GNOME_QR_ECC_LEVEL_HIGH, ++} GnomeQrEccLevel; ++ ++/** ++ * GnomeQrPixelFormat: ++ * @GNOME_QR_PIXEL_FORMAT_RGB_888: 24-bit RGB format (3 bytes per pixel) ++ * @GNOME_QR_PIXEL_FORMAT_RGBA_8888: 32-bit RGBA format (4 bytes per pixel) ++ * ++ * Pixel formats for the generated QR code image data. ++ */ ++typedef enum { ++ GNOME_QR_PIXEL_FORMAT_RGB_888, ++ GNOME_QR_PIXEL_FORMAT_RGBA_8888, ++} GnomeQrPixelFormat; ++ ++/** ++ * GnomeQrColor: ++ * @red: Red component (0-255) ++ * @green: Green component (0-255) ++ * @blue: Blue component (0-255) ++ * @alpha: Alpha component (0-255, where 255 is fully opaque). ++ * Must be 255 when using %GNOME_QR_PIXEL_FORMAT_RGB_888. ++ * ++ * Represents an RGBA color for QR code generation. ++ */ ++typedef struct { ++ guint8 red; ++ guint8 green; ++ guint8 blue; ++ guint8 alpha; ++} GnomeQrColor; ++ ++GBytes * gnome_qr_generate_qr_code_sync (const char *text, ++ size_t size, ++ const GnomeQrColor *bg_color, ++ const GnomeQrColor *fg_color, ++ GnomeQrPixelFormat format, ++ GnomeQrEccLevel ecc, ++ size_t *out_size, ++ GCancellable *cancellable, ++ GError **error); ++ ++void gnome_qr_generate_qr_code_async (const char *text, ++ size_t size, ++ const GnomeQrColor *bg_color, ++ const GnomeQrColor *fg_color, ++ GnomeQrPixelFormat format, ++ GnomeQrEccLevel ecc, ++ GCancellable *cancellable, ++ GAsyncReadyCallback callback, ++ gpointer user_data); ++ ++GBytes * gnome_qr_generate_qr_code_finish (GAsyncResult *result, ++ size_t *out_size, ++ GError **error); +diff --git a/libgnome-desktop/gnome-qr/meson.build b/libgnome-desktop/gnome-qr/meson.build +new file mode 100644 +index 0000000..18739ca +--- /dev/null ++++ b/libgnome-desktop/gnome-qr/meson.build +@@ -0,0 +1,42 @@ ++libgnome_qr_deps = [ ++ config_h, ++ glib_dep, ++ gio_dep, ++ qrcodegen_dep, ++] ++ ++libgnome_qr_sources = files([ ++ 'gnome-qr.c', ++ 'gnome-qr.h', ++]) ++ ++libgnome_qr_headers = files([ ++ 'gnome-qr.h', ++]) ++ ++install_headers(libgnome_qr_headers, ++ subdir: 'gnome-desktop-4.0/gnome-qr' ++) ++ ++libgnome_qr = library('gnome-qr', ++ sources: libgnome_qr_sources, ++ dependencies: libgnome_qr_deps, ++ soversion: qr_soversion, ++ version: qr_libversion, ++ c_args: libargs, ++ install: true, ++ include_directories: [ ++ include_directories('.'), ++ include_directories('..'), ++ ], ++) ++ ++pkg.generate( ++ libgnome_qr, ++ requires: ['gio-2.0'], ++ version: meson.project_version(), ++ name: 'gnome-qr', ++ filebase: 'gnome-qr', ++ description: 'QR code utility library for GNOME desktop components', ++ subdirs: 'gnome-desktop', ++) +diff --git a/libgnome-desktop/meson.build b/libgnome-desktop/meson.build +index 483f1ff..a3b3b47 100644 +--- a/libgnome-desktop/meson.build ++++ b/libgnome-desktop/meson.build +@@ -129,6 +129,8 @@ desktop_pc = pkg.generate( + subdirs: 'gnome-desktop-3.0' + ) + ++subdir('gnome-qr') ++ + test_programs = [ + 'gnome-rr-debug', + 'test-xkb-info', +diff --git a/meson.build b/meson.build +index d5f19c3..78cc141 100644 +--- a/meson.build ++++ b/meson.build +@@ -17,6 +17,10 @@ project('gnome-desktop', 'c', + libversion = '19.1.5' + soversion = libversion.split('.')[0] + ++# Compatibilty versions for libgnome-qr ++qr_libversion = '0.0.1' ++qr_soversion = qr_libversion.split('.')[0] ++ + gdk_pixbuf_req = '>= 2.36.5' + gtk_req = '>= 3.3.6' + glib_req = '>= 2.53.0' +From bf0fe48a9e27b82748c2ad4bbfc977017adcd4a7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Sun, 8 Feb 2026 19:16:23 +0100 +Subject: [PATCH 03/26] gnome-qr: Use a symbol map file to export symbols + +Part-of: +--- + libgnome-desktop/gnome-qr/gnome-qr-symbols.map | 6 ++++++ + libgnome-desktop/gnome-qr/meson.build | 10 ++++++++++ + 2 files changed, 16 insertions(+) + create mode 100644 libgnome-desktop/gnome-qr/gnome-qr-symbols.map + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr-symbols.map b/libgnome-desktop/gnome-qr/gnome-qr-symbols.map +new file mode 100644 +index 00000000..b32e579d +--- /dev/null ++++ b/libgnome-desktop/gnome-qr/gnome-qr-symbols.map +@@ -0,0 +1,6 @@ ++{ ++global: ++ gnome_qr_*; ++local: ++ *; ++}; +diff --git a/libgnome-desktop/gnome-qr/meson.build b/libgnome-desktop/gnome-qr/meson.build +index 0c59079d..ec065699 100644 +--- a/libgnome-desktop/gnome-qr/meson.build ++++ b/libgnome-desktop/gnome-qr/meson.build +@@ -17,12 +17,22 @@ install_headers(libgnome_qr_headers, + subdir: 'gnome-desktop-4.0/gnome-qr' + ) + ++gnome_qr_ld_flags = [] ++gnome_qr_symbol_map = 'gnome-qr-symbols.map' ++gnome_qr_symbol_map_arg = '-Wl,--version-script=@0@'.format( ++ meson.current_source_dir() / gnome_qr_symbol_map) ++if cc.has_link_argument(gnome_qr_symbol_map_arg) ++ gnome_qr_ld_flags += gnome_qr_symbol_map_arg ++endif ++ + libgnome_qr = library('gnome-qr', + sources: libgnome_qr_sources, + dependencies: libgnome_qr_deps, + soversion: qr_soversion, + version: qr_libversion, + c_args: libargs, ++ link_args: gnome_qr_ld_flags, ++ link_depends: files(gnome_qr_symbol_map), + install: true, + include_directories: [ + include_directories('.'), +-- +2.53.0 + + +From a8ad9c83f37a266af4b2c699bbd96cab81e8d972 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 4 Dec 2025 22:07:57 +0100 +Subject: [PATCH 04/26] subprojects/qrcodegen: Pin the library version + +We cannot just allow any revision to be picked by meson without some +human review, so let's just lock the version to the latest that we +checked rather than just accept any new version + +Part-of: +--- + subprojects/qrcodegen.wrap | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/subprojects/qrcodegen.wrap b/subprojects/qrcodegen.wrap +index 9080ca48..9421ab21 100644 +--- a/subprojects/qrcodegen.wrap ++++ b/subprojects/qrcodegen.wrap +@@ -1,5 +1,5 @@ + [wrap-git] + url = https://github.com/nayuki/QR-Code-generator.git +-revision = head ++revision = 8329a7108fc22be3e1eec0a9f9318978579e3621 + depth = 1 + patch_directory = qrcodegen +-- +2.53.0 + + +From 7b7520c77bbcfd8b2831761d9151df9cf2553467 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 4 Dec 2025 22:27:52 +0100 +Subject: [PATCH 05/26] subprojects/qrcodegen: Move meson overlays to the + proper folders + +So we don't have to repeat it + +Part-of: +--- + subprojects/packagefiles/qrcodegen/c/meson.build | 8 ++++++++ + subprojects/packagefiles/qrcodegen/meson.build | 9 +-------- + 2 files changed, 9 insertions(+), 8 deletions(-) + create mode 100644 subprojects/packagefiles/qrcodegen/c/meson.build + +diff --git a/subprojects/packagefiles/qrcodegen/c/meson.build b/subprojects/packagefiles/qrcodegen/c/meson.build +new file mode 100644 +index 00000000..1f819005 +--- /dev/null ++++ b/subprojects/packagefiles/qrcodegen/c/meson.build +@@ -0,0 +1,8 @@ ++libqrcodegen = static_library('qrcodegen', ++ 'qrcodegen.c', ++) ++ ++qrcodegen_dep = declare_dependency( ++ link_with: libqrcodegen, ++ include_directories: include_directories('.') ++) +diff --git a/subprojects/packagefiles/qrcodegen/meson.build b/subprojects/packagefiles/qrcodegen/meson.build +index 0a66ccb5..e2ba7785 100644 +--- a/subprojects/packagefiles/qrcodegen/meson.build ++++ b/subprojects/packagefiles/qrcodegen/meson.build +@@ -1,10 +1,3 @@ + project('qrcodegen', 'c') + +-libqrcodegen = static_library('qrcodegen', +- 'c/qrcodegen.c', +- include_directories: include_directories('c') +-) +-qrcodegen_dep = declare_dependency( +- link_with: libqrcodegen, +- include_directories: include_directories('c') +-) ++subdir('c') +-- +2.53.0 + + +From 202bb7850872fceddccdd671df848c792e712a59 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 4 Dec 2025 22:40:00 +0100 +Subject: [PATCH 06/26] subprojects/qrcodegen: Run upstream tests + +Part-of: +--- + subprojects/packagefiles/qrcodegen/c/meson.build | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/subprojects/packagefiles/qrcodegen/c/meson.build b/subprojects/packagefiles/qrcodegen/c/meson.build +index 1f819005..ca221bca 100644 +--- a/subprojects/packagefiles/qrcodegen/c/meson.build ++++ b/subprojects/packagefiles/qrcodegen/c/meson.build +@@ -6,3 +6,13 @@ qrcodegen_dep = declare_dependency( + link_with: libqrcodegen, + include_directories: include_directories('.') + ) ++ ++test('qrcodegen', ++ executable('qrcodegen-test', ++ sources: [ ++ 'qrcodegen.c', ++ 'qrcodegen-test.c', ++ ], ++ c_args: ['-DQRCODEGEN_TEST'], ++ ), ++) +-- +2.53.0 + + +From 8974fa283bfe25a430f7bf4af069eb8df89dc310 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 4 Dec 2025 22:46:10 +0100 +Subject: [PATCH 07/26] gnome-qr: Always use spaces for indentation + +Part-of: +--- + libgnome-desktop/gnome-qr/gnome-qr.c | 6 +++--- + libgnome-desktop/gnome-qr/gnome-qr.h | 8 ++++---- + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.c b/libgnome-desktop/gnome-qr/gnome-qr.c +index e22bb1f4..59fd42e3 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.c ++++ b/libgnome-desktop/gnome-qr/gnome-qr.c +@@ -282,9 +282,9 @@ gnome_qr_generate_qr_code_async (const char *text, + * Returns: (transfer full): The pixel data or %NULL on error + */ + GBytes * +-gnome_qr_generate_qr_code_finish (GAsyncResult *result, +- size_t *out_size, +- GError **error) ++gnome_qr_generate_qr_code_finish (GAsyncResult *result, ++ size_t *pixel_size_out, ++ GError **error) + { + GnomeQrCodeData *data; + g_autoptr (GBytes) pixel_data = NULL; +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.h b/libgnome-desktop/gnome-qr/gnome-qr.h +index 4d89c59d..b95480c3 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.h ++++ b/libgnome-desktop/gnome-qr/gnome-qr.h +@@ -65,10 +65,10 @@ + * recovery at the cost of requiring bigger dimensions. + */ + typedef enum { +- GNOME_QR_ECC_LEVEL_LOW, +- GNOME_QR_ECC_LEVEL_MEDIUM, +- GNOME_QR_ECC_LEVEL_QUARTILE, +- GNOME_QR_ECC_LEVEL_HIGH, ++ GNOME_QR_ECC_LEVEL_LOW, ++ GNOME_QR_ECC_LEVEL_MEDIUM, ++ GNOME_QR_ECC_LEVEL_QUARTILE, ++ GNOME_QR_ECC_LEVEL_HIGH, + } GnomeQrEccLevel; + + /** +-- +2.53.0 + + +From 5545bb1fe7b77e2374a2d6bc63d0a46ce52f6bbf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 4 Dec 2025 23:14:07 +0100 +Subject: [PATCH 08/26] gnome-qr: Mark the out_size as optional + +It's not nullable actually, but optional being an out value + +Part-of: +--- + libgnome-desktop/gnome-qr/gnome-qr.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.c b/libgnome-desktop/gnome-qr/gnome-qr.c +index 59fd42e3..5977842f 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.c ++++ b/libgnome-desktop/gnome-qr/gnome-qr.c +@@ -93,7 +93,8 @@ fill_pixel (GByteArray *array, + * or %NULL to use default (black) + * @format: The pixel format for the output image data + * @ecc: The error correction level +- * @out_size: (out) (nullable): location to store the actual output size in pixels (width and height) of the square QR code, or %NULL ++ * @out_size: (out) (optional): location to store the actual output size ++ * in pixels (width and height) of the square QR code, or %NULL + * @cancellable: (nullable): A #GCancellable to cancel the operation + * @error: #GError for error reporting + * +@@ -273,7 +274,8 @@ gnome_qr_generate_qr_code_async (const char *text, + /** + * gnome_qr_generate_qr_code_finish: + * @result: the #GAsyncResult that was provided to the callback +- * @out_size: (out) (nullable): location to store the actual output size in pixels (width and height) of the square QR code, or %NULL ++ * @out_size: (out) (optional): location to store the actual output size ++ * in pixels (width and height) of the square QR code, or %NULL + * @error: #GError for error reporting + * + * Finish the asynchronous operation started by +-- +2.53.0 + + +From defdaa6be4695b64ba81d1b0f0a0759cb2bb2cec Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 5 Dec 2025 00:59:47 +0100 +Subject: [PATCH 09/26] gnome-qr: Clarify the input and output size values + +Part-of: +--- + libgnome-desktop/gnome-qr/gnome-qr.c | 63 +++++++++++++++------------- + libgnome-desktop/gnome-qr/gnome-qr.h | 8 ++-- + 2 files changed, 38 insertions(+), 33 deletions(-) + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.c b/libgnome-desktop/gnome-qr/gnome-qr.c +index 5977842f..f2e7b152 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.c ++++ b/libgnome-desktop/gnome-qr/gnome-qr.c +@@ -32,8 +32,8 @@ + typedef struct + { + char *text; +- size_t size; +- size_t out_size; ++ size_t requested_size; ++ size_t pixel_size; + GnomeQrColor *bg_color; + GnomeQrColor *fg_color; + GnomeQrPixelFormat format; +@@ -66,14 +66,14 @@ gnome_qr_ecc_level_to_qrcodegen_ecc (GnomeQrEccLevel ecc) + } + + static void +-fill_pixel (GByteArray *array, ++fill_block (GByteArray *array, + const GnomeQrColor *color, + GnomeQrPixelFormat format, +- int pixel_size) ++ int block_size) + { + guint i; + +- for (i = 0; i < pixel_size; i++) { ++ for (i = 0; i < block_size; i++) { + g_byte_array_append (array, &color->red, 1); + g_byte_array_append (array, &color->green, 1); + g_byte_array_append (array, &color->blue, 1); +@@ -86,15 +86,17 @@ fill_pixel (GByteArray *array, + /** + * gnome_qr_generate_qr_code_sync: + * @text: the text of which generate the qr code +- * @size: The requested size in pixels (width and height) for the square QR code ++ * @requested_size: The requested size (width and height) in pixels of the QR code. ++ * Only square QR codes are supported. + * @bg_color: (nullable): The background color of the code + * or %NULL to use default (white) + * @fg_color: (nullable): The foreground color of the code + * or %NULL to use default (black) + * @format: The pixel format for the output image data + * @ecc: The error correction level +- * @out_size: (out) (optional): location to store the actual output size +- * in pixels (width and height) of the square QR code, or %NULL ++ * @pixel_size_out: (out) (optional): The square QR code size ++ * (width and height) in pixels, or %NULL. ++ * Note that it may not match @requested_size. + * @cancellable: (nullable): A #GCancellable to cancel the operation + * @error: #GError for error reporting + * +@@ -104,23 +106,23 @@ fill_pixel (GByteArray *array, + */ + GBytes * + gnome_qr_generate_qr_code_sync (const char *text, +- size_t size, ++ size_t requested_size, + const GnomeQrColor *bg_color, + const GnomeQrColor *fg_color, + GnomeQrPixelFormat format, + GnomeQrEccLevel ecc, +- size_t *out_size, ++ size_t *pixel_size_out, + GCancellable *cancellable, + GError **error) + { + g_autoptr (GByteArray) qr_matrix = NULL; + uint8_t qr_code[qrcodegen_BUFFER_LEN_FOR_VERSION (qrcodegen_VERSION_MAX)]; + uint8_t temp_buf[qrcodegen_BUFFER_LEN_FOR_VERSION (qrcodegen_VERSION_MAX)]; +- gint pixel_size, qr_size, total_size; ++ gint qr_size, block_size, total_size; + gint column, row, i; + + g_return_val_if_fail (text != NULL, NULL); +- g_return_val_if_fail (size > 0, NULL); ++ g_return_val_if_fail (requested_size > 0, NULL); + + if (format == GNOME_QR_PIXEL_FORMAT_RGB_888) { + g_return_val_if_fail (!bg_color || bg_color->alpha == 255, NULL); +@@ -156,19 +158,19 @@ gnome_qr_generate_qr_code_sync (const char *text, + fg_color = &GNOME_QR_COLOR_BLACK; + + qr_size = qrcodegen_getSize (qr_code); +- pixel_size = MAX (1, size / qr_size); +- total_size = qr_size * pixel_size; ++ block_size = MAX (1, requested_size / qr_size); ++ total_size = qr_size * block_size; + +- qr_matrix = g_byte_array_sized_new (total_size * total_size * pixel_size * ++ qr_matrix = g_byte_array_sized_new (total_size * total_size * block_size * + GNOME_QR_BYTES_PER_FORMAT (format)); + + for (column = 0; column < total_size; ++column) { +- for (i = 0; i < pixel_size; ++i) { ++ for (i = 0; i < block_size; ++i) { + for (row = 0; row < qr_size; ++row) { + if (qrcodegen_getModule (qr_code, column, row)) +- fill_pixel (qr_matrix, fg_color, format, pixel_size); ++ fill_block (qr_matrix, fg_color, format, block_size); + else +- fill_pixel (qr_matrix, bg_color, format, pixel_size); ++ fill_block (qr_matrix, bg_color, format, block_size); + } + } + +@@ -176,8 +178,8 @@ gnome_qr_generate_qr_code_sync (const char *text, + return NULL; + } + +- if (out_size) +- *out_size = total_size; ++ if (pixel_size_out) ++ *pixel_size_out = total_size; + + return g_byte_array_free_to_bytes (g_steal_pointer (&qr_matrix)); + } +@@ -194,12 +196,12 @@ generate_qr_code_in_thread (GTask *task, + g_autoptr (GBytes) icon = NULL; + + icon = gnome_qr_generate_qr_code_sync (data->text, +- data->size, ++ data->requested_size, + data->bg_color, + data->fg_color, + data->format, + data->ecc, +- &data->out_size, ++ &data->pixel_size, + cancellable, + &error); + if (!icon) { +@@ -213,7 +215,8 @@ generate_qr_code_in_thread (GTask *task, + /** + * gnome_qr_generate_qr_code_async: + * @text: the text of which generate the qr code +- * @size: The requested size in pixels (width and height) for the square QR code ++ * @requested_size: The requested size (width and height) in pixels of the QR code. ++ * Only square QR codes are supported. + * @bg_color: (nullable): The background color of the code + * or %NULL to use default (white) + * @fg_color: (nullable): The foreground color of the code +@@ -231,7 +234,7 @@ generate_qr_code_in_thread (GTask *task, + */ + void + gnome_qr_generate_qr_code_async (const char *text, +- size_t size, ++ size_t requested_size, + const GnomeQrColor *bg_color, + const GnomeQrColor *fg_color, + GnomeQrPixelFormat format, +@@ -257,7 +260,7 @@ gnome_qr_generate_qr_code_async (const char *text, + + data = g_new0 (GnomeQrCodeData, 1); + data->text = g_strdup (text); +- data->size = size; ++ data->requested_size = requested_size; + data->bg_color = g_memdup2 (bg_color, sizeof (GnomeQrColor)); + data->fg_color = g_memdup2 (fg_color, sizeof (GnomeQrColor)); + data->format = format; +@@ -274,8 +277,10 @@ gnome_qr_generate_qr_code_async (const char *text, + /** + * gnome_qr_generate_qr_code_finish: + * @result: the #GAsyncResult that was provided to the callback +- * @out_size: (out) (optional): location to store the actual output size +- * in pixels (width and height) of the square QR code, or %NULL ++ * @pixel_size_out: (out) (optional): The square QR code size ++ * (width and height) in pixels, or %NULL. ++ * Note that it may not match the @requested_size in ++ * gnome_qr_generate_qr_code_async(). + * @error: #GError for error reporting + * + * Finish the asynchronous operation started by +@@ -301,8 +306,8 @@ gnome_qr_generate_qr_code_finish (GAsyncResult *result, + return NULL; + + data = g_task_get_task_data (G_TASK (result)); +- if (out_size) +- *out_size = data->out_size; ++ if (pixel_size_out) ++ *pixel_size_out = data->pixel_size; + + return g_steal_pointer (&pixel_data); + } +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.h b/libgnome-desktop/gnome-qr/gnome-qr.h +index b95480c3..d7dbf52a 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.h ++++ b/libgnome-desktop/gnome-qr/gnome-qr.h +@@ -101,17 +101,17 @@ typedef struct { + } GnomeQrColor; + + GBytes * gnome_qr_generate_qr_code_sync (const char *text, +- size_t size, ++ size_t requested_size, + const GnomeQrColor *bg_color, + const GnomeQrColor *fg_color, + GnomeQrPixelFormat format, + GnomeQrEccLevel ecc, +- size_t *out_size, ++ size_t *pixel_size_out, + GCancellable *cancellable, + GError **error); + + void gnome_qr_generate_qr_code_async (const char *text, +- size_t size, ++ size_t requested_size, + const GnomeQrColor *bg_color, + const GnomeQrColor *fg_color, + GnomeQrPixelFormat format, +@@ -121,5 +121,5 @@ void gnome_qr_generate_qr_code_async (const char *text, + gpointer user_data); + + GBytes * gnome_qr_generate_qr_code_finish (GAsyncResult *result, +- size_t *out_size, ++ size_t *pixel_size_out, + GError **error); +-- +2.53.0 + + +From c3681687172e079afa66311097f15144d9aebeea Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 5 Dec 2025 01:10:00 +0100 +Subject: [PATCH 10/26] gnome-qr: Docs cleanups + +Part-of: +--- + libgnome-desktop/gnome-qr/gnome-qr.c | 4 ++-- + libgnome-desktop/gnome-qr/meson.build | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.c b/libgnome-desktop/gnome-qr/gnome-qr.c +index f2e7b15..ce9fd40 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.c ++++ b/libgnome-desktop/gnome-qr/gnome-qr.c +@@ -85,7 +85,7 @@ fill_block (GByteArray *array, + + /** + * gnome_qr_generate_qr_code_sync: +- * @text: the text of which generate the qr code ++ * @text: the text of which generate the QR code + * @requested_size: The requested size (width and height) in pixels of the QR code. + * Only square QR codes are supported. + * @bg_color: (nullable): The background color of the code +@@ -214,7 +214,7 @@ generate_qr_code_in_thread (GTask *task, + + /** + * gnome_qr_generate_qr_code_async: +- * @text: the text of which generate the qr code ++ * @text: The text of which generate the QR code + * @requested_size: The requested size (width and height) in pixels of the QR code. + * Only square QR codes are supported. + * @bg_color: (nullable): The background color of the code +From 88cf4aa274e896844f4420f58b493b89d0e796b3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 5 Dec 2025 01:11:57 +0100 +Subject: [PATCH 11/26] gnome-qr: Use the same pre-conditions in the sync and + async versions + +We have exactly the same requirements, however we were not checking the +async case until the thread was actually spinned, and this might be too +late to figure out what's wrong. + +So let's just replicate the same logic in both versions, rather than +returning errors that are not real errors (but rather programmer +errors). + +Part-of: +--- + libgnome-desktop/gnome-qr/gnome-qr.c | 20 +++++++++----------- + 1 file changed, 9 insertions(+), 11 deletions(-) + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.c b/libgnome-desktop/gnome-qr/gnome-qr.c +index ce9fd406..50860bee 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.c ++++ b/libgnome-desktop/gnome-qr/gnome-qr.c +@@ -122,6 +122,7 @@ gnome_qr_generate_qr_code_sync (const char *text, + gint column, row, i; + + g_return_val_if_fail (text != NULL, NULL); ++ g_return_val_if_fail (*text != '\0', NULL); + g_return_val_if_fail (requested_size > 0, NULL); + + if (format == GNOME_QR_PIXEL_FORMAT_RGB_888) { +@@ -143,7 +144,7 @@ gnome_qr_generate_qr_code_sync (const char *text, + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, +- "QRCode generation failed for content %s", ++ "QRCode generation failed for content '%s'", + text); + return NULL; + } +@@ -246,16 +247,13 @@ gnome_qr_generate_qr_code_async (const char *text, + g_autoptr (GTask) task = NULL; + GnomeQrCodeData *data; + +- if (!text || *text == '\0') { +- if (callback) +- g_task_report_new_error (NULL, +- callback, +- user_data, +- gnome_qr_generate_qr_code_async, +- G_IO_ERROR, +- G_IO_ERROR_INVALID_DATA, +- "No valid QR code text is provided"); +- return; ++ g_return_if_fail (text != NULL); ++ g_return_if_fail (*text != '\0'); ++ g_return_if_fail (requested_size > 0); ++ ++ if (format == GNOME_QR_PIXEL_FORMAT_RGB_888) { ++ g_return_if_fail (!bg_color || bg_color->alpha == 255); ++ g_return_if_fail (!fg_color || fg_color->alpha == 255); + } + + data = g_new0 (GnomeQrCodeData, 1); +-- +2.53.0 + + +From 264ebc9120f5ddc41c22c976626f9bbb0214faff Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 5 Dec 2025 03:08:20 +0100 +Subject: [PATCH 12/26] gnome-qr: Do not create unnecessarily big array + +We were multiplying the total pixel size twice + +Also re-order the for logic to be clearer + +Part-of: +--- + libgnome-desktop/gnome-qr/gnome-qr.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.c b/libgnome-desktop/gnome-qr/gnome-qr.c +index 50860bee..0c597e6a 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.c ++++ b/libgnome-desktop/gnome-qr/gnome-qr.c +@@ -159,15 +159,17 @@ gnome_qr_generate_qr_code_sync (const char *text, + fg_color = &GNOME_QR_COLOR_BLACK; + + qr_size = qrcodegen_getSize (qr_code); ++ g_assert (qr_size > 0); ++ + block_size = MAX (1, requested_size / qr_size); + total_size = qr_size * block_size; + +- qr_matrix = g_byte_array_sized_new (total_size * total_size * block_size * ++ qr_matrix = g_byte_array_sized_new (total_size * total_size * + GNOME_QR_BYTES_PER_FORMAT (format)); + +- for (column = 0; column < total_size; ++column) { ++ for (row = 0; row < qr_size; ++row) { + for (i = 0; i < block_size; ++i) { +- for (row = 0; row < qr_size; ++row) { ++ for (column = 0; column < qr_size; ++column) { + if (qrcodegen_getModule (qr_code, column, row)) + fill_block (qr_matrix, fg_color, format, block_size); + else +-- +2.53.0 + + +From 3ffc65be6bce927d56e6b843fc92074f54e7fdd2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 5 Dec 2025 03:09:19 +0100 +Subject: [PATCH 13/26] gnome-qr: Do not access to potentially temporary data + +The colors needs to be statically saved or we may read from temporary +values + +Part-of: +--- + libgnome-desktop/gnome-qr/gnome-qr.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.c b/libgnome-desktop/gnome-qr/gnome-qr.c +index 0c597e6a..3fbea659 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.c ++++ b/libgnome-desktop/gnome-qr/gnome-qr.c +@@ -118,6 +118,8 @@ gnome_qr_generate_qr_code_sync (const char *text, + g_autoptr (GByteArray) qr_matrix = NULL; + uint8_t qr_code[qrcodegen_BUFFER_LEN_FOR_VERSION (qrcodegen_VERSION_MAX)]; + uint8_t temp_buf[qrcodegen_BUFFER_LEN_FOR_VERSION (qrcodegen_VERSION_MAX)]; ++ static const GnomeQrColor default_bg_color = GNOME_QR_COLOR_WHITE; ++ static const GnomeQrColor default_fg_color = GNOME_QR_COLOR_BLACK; + gint qr_size, block_size, total_size; + gint column, row, i; + +@@ -153,10 +155,10 @@ gnome_qr_generate_qr_code_sync (const char *text, + return NULL; + + if (!bg_color) +- bg_color = &GNOME_QR_COLOR_WHITE; ++ bg_color = &default_bg_color; + + if (!fg_color) +- fg_color = &GNOME_QR_COLOR_BLACK; ++ fg_color = &default_fg_color; + + qr_size = qrcodegen_getSize (qr_code); + g_assert (qr_size > 0); +-- +2.53.0 + + +From 681ee34eff01f88657fd911067183e6b163d7937 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 5 Dec 2025 03:10:02 +0100 +Subject: [PATCH 14/26] gnome-qr: Accept a 0-sized qr-code + +It will be just the minimal size that is required for this. + +UIs can then just stretch it using more optimized rendering, without +wasting memory + +Part-of: +--- + libgnome-desktop/gnome-qr/gnome-qr.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.c b/libgnome-desktop/gnome-qr/gnome-qr.c +index 3fbea659..936b43a7 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.c ++++ b/libgnome-desktop/gnome-qr/gnome-qr.c +@@ -125,7 +125,6 @@ gnome_qr_generate_qr_code_sync (const char *text, + + g_return_val_if_fail (text != NULL, NULL); + g_return_val_if_fail (*text != '\0', NULL); +- g_return_val_if_fail (requested_size > 0, NULL); + + if (format == GNOME_QR_PIXEL_FORMAT_RGB_888) { + g_return_val_if_fail (!bg_color || bg_color->alpha == 255, NULL); +@@ -253,7 +252,6 @@ gnome_qr_generate_qr_code_async (const char *text, + + g_return_if_fail (text != NULL); + g_return_if_fail (*text != '\0'); +- g_return_if_fail (requested_size > 0); + + if (format == GNOME_QR_PIXEL_FORMAT_RGB_888) { + g_return_if_fail (!bg_color || bg_color->alpha == 255); +-- +2.53.0 + + +From b5898036676e4bcd8258f9709c0fe466ad2422fd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 5 Dec 2025 03:11:49 +0100 +Subject: [PATCH 15/26] tests: Add basic qr-code tests + +Part-of: +--- + libgnome-desktop/gnome-qr/meson.build | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/libgnome-desktop/gnome-qr/meson.build b/libgnome-desktop/gnome-qr/meson.build +index addd22a..54fa746 100644 +--- a/libgnome-desktop/gnome-qr/meson.build ++++ b/libgnome-desktop/gnome-qr/meson.build +@@ -50,3 +50,11 @@ pkg.generate( + description: 'QR code utility library for GNOME desktop components', + subdirs: 'gnome-desktop', + ) ++ ++gnome_qr_dep = declare_dependency( ++ dependencies: libgnome_qr_deps, ++ include_directories: [ ++ include_directories('..'), ++ ], ++ link_with: libgnome_qr, ++) +From 833ab80efbc678e7b7b085bca045ad380ca09b2a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 5 Dec 2025 06:11:42 +0100 +Subject: [PATCH 16/26] gnome-qr: Ensure that the final size is at least the + requested one + +Each block can be wider if the space needed does not fit the requested +space + +Part-of: +--- + libgnome-desktop/gnome-qr/gnome-qr.c | 3 ++- + libgnome-desktop/gnome-qr/meson.build | 1 + + meson.build | 2 +- + 3 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.c b/libgnome-desktop/gnome-qr/gnome-qr.c +index 936b43a..e18c04a 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.c ++++ b/libgnome-desktop/gnome-qr/gnome-qr.c +@@ -27,6 +27,7 @@ + + #include "gnome-qr.h" + ++#include + #include + + typedef struct +@@ -162,7 +163,7 @@ gnome_qr_generate_qr_code_sync (const char *text, + qr_size = qrcodegen_getSize (qr_code); + g_assert (qr_size > 0); + +- block_size = MAX (1, requested_size / qr_size); ++ block_size = MAX (1, ceil ((double) requested_size / qr_size)); + total_size = qr_size * block_size; + + qr_matrix = g_byte_array_sized_new (total_size * total_size * +diff --git a/libgnome-desktop/gnome-qr/meson.build b/libgnome-desktop/gnome-qr/meson.build +index 31091b3..c9a72dd 100644 +--- a/libgnome-desktop/gnome-qr/meson.build ++++ b/libgnome-desktop/gnome-qr/meson.build +@@ -2,6 +2,7 @@ libgnome_qr_deps = [ + glib_dep, + gio_dep, + qrcodegen_dep, ++ m_dep, + ] + + libgnome_qr_sources = files([ +diff --git a/meson.build b/meson.build +index 78cc141..9873937 100644 +--- a/meson.build ++++ b/meson.build +@@ -76,7 +76,7 @@ iso_codes_prefix = iso_codes_dep.get_pkgconfig_variable('prefix') + + cc = meson.get_compiler('c') + +-m_dep = cc.find_library('m', required: false) ++m_dep = cc.find_library('m', required: true) + rt_dep = cc.find_library('rt', required: false) + + if not cc.has_function('clock_gettime', dependencies: rt_dep) +-- +2.53.0 + +From 6f146b96df08f3e0809fe257846bc290cfb6f8eb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 5 Dec 2025 06:41:02 +0100 +Subject: [PATCH 17/26] gnome-qr: Add introspection support + +We definitely need introspection to be able to use this in the shell and +anywhere else + +Part-of: +--- + libgnome-desktop/gnome-qr/meson.build | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/libgnome-desktop/gnome-qr/meson.build b/libgnome-desktop/gnome-qr/meson.build +index 998eaaa..1ba1922 100644 +--- a/libgnome-desktop/gnome-qr/meson.build ++++ b/libgnome-desktop/gnome-qr/meson.build +@@ -42,6 +42,20 @@ libgnome_qr = library('gnome-qr', + ], + ) + ++libgnome_qr_gir = [] ++libgnome_qr_gir += gnome.generate_gir(libgnome_qr, ++ sources: [libgnome_qr_headers, libgnome_qr_sources], ++ export_packages: 'gnome-qr', ++ namespace: 'GnomeQR', ++ nsversion: '0.0', ++ identifier_prefix: 'GnomeQr', ++ symbol_prefix: 'gnome_qr', ++ includes: ['Gio-2.0', 'GLib-2.0'], ++ extra_args: ['--quiet', '--warn-all'], ++ fatal_warnings: true, ++ install: true, ++) ++ + pkg.generate( + libgnome_qr, + requires: ['gio-2.0'], +@@ -54,6 +68,9 @@ pkg.generate( + + gnome_qr_dep = declare_dependency( + dependencies: libgnome_qr_deps, ++ sources: [ ++ libgnome_qr_gir, ++ ], + include_directories: [ + include_directories('..'), + ], +From 91374a180ebe444658daa38945e61640982a3d0a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 5 Dec 2025 08:03:39 +0100 +Subject: [PATCH 18/26] gnome-qr: Update license to GPL-3+ + +Part of this code was already licensed as GPL3+, so let's just use this +version and adjust the copyright holders + +Part-of: +--- + libgnome-desktop/gnome-qr/gnome-qr.c | 24 +++++++++++++----------- + libgnome-desktop/gnome-qr/gnome-qr.h | 24 +++++++++++++----------- + 2 files changed, 26 insertions(+), 22 deletions(-) + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.c b/libgnome-desktop/gnome-qr/gnome-qr.c +index e18c04a9..b2a34b13 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.c ++++ b/libgnome-desktop/gnome-qr/gnome-qr.c +@@ -1,24 +1,26 @@ + /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + /* ++ * Copyright 2019 Purism SPC + * Copyright 2024-2025 Red Hat, Inc + * Copyright 2024-2025 Canonical Ltd + * +- * SPDX-License-Identifier: LGPL-2.1-or-later ++ * SPDX-License-Identifier: GPL-3.0-or-later + * +- * This library is free software; you can redistribute it and/or +- * modify it under the terms of the GNU Lesser General Public +- * License as published by the Free Software Foundation; either +- * version 2.1 of the License, or (at your option) any later version. ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. + * +- * This library is distributed in the hope that it will be useful, ++ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- * Lesser General Public License for more details. ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. + * +- * You should have received a copy of the GNU Lesser General +- * Public License along with this library; if not, see . ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . + * +- * Author: Ray Strode ++ * Author: Mohammed Sadiq ++ * Ray Strode + * Marco Trevisan + * Joan Torres Lopez + */ +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.h b/libgnome-desktop/gnome-qr/gnome-qr.h +index d7dbf52a..955ebf3b 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.h ++++ b/libgnome-desktop/gnome-qr/gnome-qr.h +@@ -1,24 +1,26 @@ + /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + /* ++ * Copyright 2019 Purism SPC + * Copyright 2024-2025 Red Hat, Inc + * Copyright 2024-2025 Canonical Ltd + * +- * SPDX-License-Identifier: LGPL-2.1-or-later ++ * SPDX-License-Identifier: GPL-3.0-or-later + * +- * This library is free software; you can redistribute it and/or +- * modify it under the terms of the GNU Lesser General Public +- * License as published by the Free Software Foundation; either +- * version 2.1 of the License, or (at your option) any later version. ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. + * +- * This library is distributed in the hope that it will be useful, ++ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- * Lesser General Public License for more details. ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. + * +- * You should have received a copy of the GNU Lesser General +- * Public License along with this library; if not, see . ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . + * +- * Author: Ray Strode ++ * Author: Mohammed Sadiq ++ * Ray Strode + * Marco Trevisan + * Joan Torres Lopez + */ +-- +2.53.0 + + +From b4e332d62905109b763261a7d74d8b31b44c5f12 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Tue, 9 Dec 2025 18:19:38 +0100 +Subject: [PATCH 19/26] gnome-qr: Make pixel_out_size mandatory + +The caller must rely on the actual generated size instead of the requested one. + +It's already documented that the returned size may not match the requested +one. + +It's responsibility of the caller to check the returned size and act +accordingly. + +Part-of: +--- + libgnome-desktop/gnome-qr/gnome-qr.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.c b/libgnome-desktop/gnome-qr/gnome-qr.c +index b2a34b13..51f718e9 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.c ++++ b/libgnome-desktop/gnome-qr/gnome-qr.c +@@ -90,16 +90,17 @@ fill_block (GByteArray *array, + * gnome_qr_generate_qr_code_sync: + * @text: the text of which generate the QR code + * @requested_size: The requested size (width and height) in pixels of the QR code. +- * Only square QR codes are supported. ++ * Only square QR codes are supported. If the requested size is smaller than ++ * the minimum required size for the QR code, it will be generated with 1 pixel ++ * per block. + * @bg_color: (nullable): The background color of the code + * or %NULL to use default (white) + * @fg_color: (nullable): The foreground color of the code + * or %NULL to use default (black) + * @format: The pixel format for the output image data + * @ecc: The error correction level +- * @pixel_size_out: (out) (optional): The square QR code size +- * (width and height) in pixels, or %NULL. +- * Note that it may not match @requested_size. ++ * @pixel_size_out: (out): The actual square QR code size (width and height) ++ * in pixels. Note that it may not match @requested_size. + * @cancellable: (nullable): A #GCancellable to cancel the operation + * @error: #GError for error reporting + * +@@ -128,6 +129,7 @@ gnome_qr_generate_qr_code_sync (const char *text, + + g_return_val_if_fail (text != NULL, NULL); + g_return_val_if_fail (*text != '\0', NULL); ++ g_return_val_if_fail (pixel_size_out != NULL, NULL); + + if (format == GNOME_QR_PIXEL_FORMAT_RGB_888) { + g_return_val_if_fail (!bg_color || bg_color->alpha == 255, NULL); +@@ -185,8 +187,7 @@ gnome_qr_generate_qr_code_sync (const char *text, + return NULL; + } + +- if (pixel_size_out) +- *pixel_size_out = total_size; ++ *pixel_size_out = total_size; + + return g_byte_array_free_to_bytes (g_steal_pointer (&qr_matrix)); + } +@@ -280,9 +281,8 @@ gnome_qr_generate_qr_code_async (const char *text, + /** + * gnome_qr_generate_qr_code_finish: + * @result: the #GAsyncResult that was provided to the callback +- * @pixel_size_out: (out) (optional): The square QR code size +- * (width and height) in pixels, or %NULL. +- * Note that it may not match the @requested_size in ++ * @pixel_size_out: (out): The actual square QR code size (width and height) ++ * in pixels. Note that it may not match the @requested_size in + * gnome_qr_generate_qr_code_async(). + * @error: #GError for error reporting + * +@@ -303,14 +303,14 @@ gnome_qr_generate_qr_code_finish (GAsyncResult *result, + g_return_val_if_fail (g_async_result_is_tagged (result, + gnome_qr_generate_qr_code_async), + NULL); ++ g_return_val_if_fail (pixel_size_out != NULL, NULL); + + pixel_data = g_task_propagate_pointer (G_TASK (result), error); + if (!pixel_data) + return NULL; + + data = g_task_get_task_data (G_TASK (result)); +- if (pixel_size_out) +- *pixel_size_out = data->pixel_size; ++ *pixel_size_out = data->pixel_size; + + return g_steal_pointer (&pixel_data); + } +-- +2.53.0 + + +From 25f3e91eadd74273210941943336c8f073cf1267 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 5 Feb 2026 16:16:08 +0100 +Subject: [PATCH 20/26] gnome-qr: Register enums as gtype enumeration values + +It's better for bindings and to use these values as properties + +Part-of: +--- + libgnome-desktop/gnome-qr/gnome-qr.c | 10 ++++++++++ + libgnome-desktop/gnome-qr/gnome-qr.h | 4 ++++ + 2 files changed, 14 insertions(+) + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.c b/libgnome-desktop/gnome-qr/gnome-qr.c +index 51f718e9..d14ea51f 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.c ++++ b/libgnome-desktop/gnome-qr/gnome-qr.c +@@ -32,6 +32,16 @@ + #include + #include + ++G_DEFINE_ENUM_TYPE (GnomeQrEccLevel, gnome_qr_ecc_level, ++ G_DEFINE_ENUM_VALUE (GNOME_QR_ECC_LEVEL_LOW, "low"), ++ G_DEFINE_ENUM_VALUE (GNOME_QR_ECC_LEVEL_MEDIUM, "medium"), ++ G_DEFINE_ENUM_VALUE (GNOME_QR_ECC_LEVEL_QUARTILE, "quartile"), ++ G_DEFINE_ENUM_VALUE (GNOME_QR_ECC_LEVEL_HIGH, "high")) ++ ++G_DEFINE_ENUM_TYPE (GnomeQrPixelFormat, gnome_qr_pixel_format, ++ G_DEFINE_ENUM_VALUE (GNOME_QR_PIXEL_FORMAT_RGB_888, "rgb-888"), ++ G_DEFINE_ENUM_VALUE (GNOME_QR_PIXEL_FORMAT_RGBA_8888, "rgba-8888")) ++ + typedef struct + { + char *text; +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.h b/libgnome-desktop/gnome-qr/gnome-qr.h +index 955ebf3b..337ad457 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.h ++++ b/libgnome-desktop/gnome-qr/gnome-qr.h +@@ -102,6 +102,10 @@ typedef struct { + guint8 alpha; + } GnomeQrColor; + ++GType gnome_qr_ecc_level_get_type (void); ++ ++GType gnome_qr_pixel_format_get_type (void); ++ + GBytes * gnome_qr_generate_qr_code_sync (const char *text, + size_t requested_size, + const GnomeQrColor *bg_color, +-- +2.53.0 + + +From 56d7eeeef30f9cc3ca4a7882753376bb9e8aac50 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 5 Feb 2026 16:17:48 +0100 +Subject: [PATCH 21/26] gnome-qr: Uniform description for requested size + +We use the same for both sync and async case + +Part-of: +--- + libgnome-desktop/gnome-qr/gnome-qr.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.c b/libgnome-desktop/gnome-qr/gnome-qr.c +index d14ea51f..874b1f87 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.c ++++ b/libgnome-desktop/gnome-qr/gnome-qr.c +@@ -234,7 +234,9 @@ generate_qr_code_in_thread (GTask *task, + * gnome_qr_generate_qr_code_async: + * @text: The text of which generate the QR code + * @requested_size: The requested size (width and height) in pixels of the QR code. +- * Only square QR codes are supported. ++ * Only square QR codes are supported. If the requested size is smaller than ++ * the minimum required size for the QR code, it will be generated with 1 pixel ++ * per block. + * @bg_color: (nullable): The background color of the code + * or %NULL to use default (white) + * @fg_color: (nullable): The foreground color of the code +-- +2.53.0 + + +From b03f7c22b903e3877edcfe4b2edd18f6f283833e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 5 Feb 2026 21:10:19 +0100 +Subject: [PATCH 22/26] gnome-qr: Simplify the color for pixel format check + +So we can just use a simpler check and replicate in both functions + +Part-of: +--- + libgnome-desktop/gnome-qr/gnome-qr.c | 28 ++++++++++++++++++---------- + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.c b/libgnome-desktop/gnome-qr/gnome-qr.c +index 874b1f87..6c57ad91 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.c ++++ b/libgnome-desktop/gnome-qr/gnome-qr.c +@@ -96,6 +96,20 @@ fill_block (GByteArray *array, + } + } + ++G_ALWAYS_INLINE static inline gboolean ++check_color_validity (const GnomeQrColor *color, ++ GnomeQrPixelFormat format) ++{ ++ if (!color) ++ return TRUE; ++ ++ if (format == GNOME_QR_PIXEL_FORMAT_RGB_888) { ++ g_return_val_if_fail (color->alpha == 255, FALSE); ++ } ++ ++ return TRUE; ++} ++ + /** + * gnome_qr_generate_qr_code_sync: + * @text: the text of which generate the QR code +@@ -140,11 +154,8 @@ gnome_qr_generate_qr_code_sync (const char *text, + g_return_val_if_fail (text != NULL, NULL); + g_return_val_if_fail (*text != '\0', NULL); + g_return_val_if_fail (pixel_size_out != NULL, NULL); +- +- if (format == GNOME_QR_PIXEL_FORMAT_RGB_888) { +- g_return_val_if_fail (!bg_color || bg_color->alpha == 255, NULL); +- g_return_val_if_fail (!fg_color || fg_color->alpha == 255, NULL); +- } ++ g_return_val_if_fail (check_color_validity (bg_color, format), NULL); ++ g_return_val_if_fail (check_color_validity (fg_color, format), NULL); + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return NULL; +@@ -268,11 +279,8 @@ gnome_qr_generate_qr_code_async (const char *text, + + g_return_if_fail (text != NULL); + g_return_if_fail (*text != '\0'); +- +- if (format == GNOME_QR_PIXEL_FORMAT_RGB_888) { +- g_return_if_fail (!bg_color || bg_color->alpha == 255); +- g_return_if_fail (!fg_color || fg_color->alpha == 255); +- } ++ g_return_if_fail (check_color_validity (bg_color, format)); ++ g_return_if_fail (check_color_validity (fg_color, format)); + + data = g_new0 (GnomeQrCodeData, 1); + data->text = g_strdup (text); +-- +2.53.0 + + +From 92669e12578e622ced490603923838906c23488a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 5 Feb 2026 21:30:43 +0100 +Subject: [PATCH 23/26] gnome-qr: Add definition for transparent color + +Part-of: +--- + docs/reference/gnome-desktop3/gnome-desktop3-sections.txt | 1 + + libgnome-desktop/gnome-qr/gnome-qr.h | 7 +++++++ + 2 files changed, 8 insertions(+) + +diff --git a/docs/reference/gnome-desktop3/gnome-desktop3-sections.txt b/docs/reference/gnome-desktop3/gnome-desktop3-sections.txt +index 8098e0d6..2fe96b6c 100644 +--- a/docs/reference/gnome-desktop3/gnome-desktop3-sections.txt ++++ b/docs/reference/gnome-desktop3/gnome-desktop3-sections.txt +@@ -223,6 +223,7 @@ GnomeQrColor + GNOME_QR_BYTES_PER_FORMAT + GNOME_QR_COLOR_WHITE + GNOME_QR_COLOR_BLACK ++GNOME_QR_COLOR_TRANSPARENT + gnome_qr_generate_qr_code_sync + gnome_qr_generate_qr_code_async + gnome_qr_generate_qr_code_finish +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.h b/libgnome-desktop/gnome-qr/gnome-qr.h +index 337ad457..61ec738c 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.h ++++ b/libgnome-desktop/gnome-qr/gnome-qr.h +@@ -42,6 +42,13 @@ + #define GNOME_QR_BYTES_PER_FORMAT(format) \ + ((format) == GNOME_QR_PIXEL_FORMAT_RGB_888 ? 3 : 4) + ++/** ++ * GNOME_QR_COLOR_TRANSPARENT: ++ * ++ * Predefined transparent color (0, 0, 0, 0). ++ */ ++#define GNOME_QR_COLOR_TRANSPARENT ((GnomeQrColor) { 0, 0, 0, 0 }) ++ + /** + * GNOME_QR_COLOR_WHITE: + * +-- +2.53.0 + + +From 0aade54cf21d7c6bfc7101d681ee4864893006f3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 5 Feb 2026 21:53:02 +0100 +Subject: [PATCH 24/26] gnome-qr: Add simpler pixel formats such as A8 and G8 + +They can be useful to keep optimize the texture to the maximum + +Part-of: +--- + libgnome-desktop/gnome-qr/gnome-qr.c | 49 ++++- + libgnome-desktop/gnome-qr/gnome-qr.h | 6 +- + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.c b/libgnome-desktop/gnome-qr/gnome-qr.c +index 6c57ad91..1ea2e1b3 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.c ++++ b/libgnome-desktop/gnome-qr/gnome-qr.c +@@ -39,6 +39,8 @@ G_DEFINE_ENUM_TYPE (GnomeQrEccLevel, gnome_qr_ecc_level, + G_DEFINE_ENUM_VALUE (GNOME_QR_ECC_LEVEL_HIGH, "high")) + + G_DEFINE_ENUM_TYPE (GnomeQrPixelFormat, gnome_qr_pixel_format, ++ G_DEFINE_ENUM_VALUE (GNOME_QR_PIXEL_FORMAT_A_8, "a-8"), ++ G_DEFINE_ENUM_VALUE (GNOME_QR_PIXEL_FORMAT_G_8, "g-8"), + G_DEFINE_ENUM_VALUE (GNOME_QR_PIXEL_FORMAT_RGB_888, "rgb-888"), + G_DEFINE_ENUM_VALUE (GNOME_QR_PIXEL_FORMAT_RGBA_8888, "rgba-8888")) + +@@ -87,12 +89,29 @@ fill_block (GByteArray *array, + guint i; + + for (i = 0; i < block_size; i++) { +- g_byte_array_append (array, &color->red, 1); +- g_byte_array_append (array, &color->green, 1); +- g_byte_array_append (array, &color->blue, 1); +- +- if (format == GNOME_QR_PIXEL_FORMAT_RGBA_8888) ++ switch (format) { ++ case GNOME_QR_PIXEL_FORMAT_A_8: + g_byte_array_append (array, &color->alpha, 1); ++ break; ++ ++ case GNOME_QR_PIXEL_FORMAT_G_8: ++ /* Use the red channel, as we assert that all the ++ * values must be equal */ ++ g_byte_array_append (array, &color->red, 1); ++ break; ++ ++ case GNOME_QR_PIXEL_FORMAT_RGB_888: ++ case GNOME_QR_PIXEL_FORMAT_RGBA_8888: ++ g_byte_array_append (array, &color->red, 1); ++ g_byte_array_append (array, &color->green, 1); ++ g_byte_array_append (array, &color->blue, 1); ++ ++ if (format == GNOME_QR_PIXEL_FORMAT_RGBA_8888) ++ g_byte_array_append (array, &color->alpha, 1); ++ break; ++ default: ++ g_assert_not_reached (); ++ } + } + } + +@@ -103,8 +122,21 @@ check_color_validity (const GnomeQrColor *color, + if (!color) + return TRUE; + +- if (format == GNOME_QR_PIXEL_FORMAT_RGB_888) { ++ switch (format) { ++ case GNOME_QR_PIXEL_FORMAT_A_8: ++ case GNOME_QR_PIXEL_FORMAT_RGBA_8888: ++ break; ++ ++ case GNOME_QR_PIXEL_FORMAT_G_8: ++ g_return_val_if_fail (color->red == color->green && ++ color->red == color->blue, FALSE); ++ /* fallthrough */ ++ case GNOME_QR_PIXEL_FORMAT_RGB_888: + g_return_val_if_fail (color->alpha == 255, FALSE); ++ break; ++ ++ default: ++ g_assert_not_reached (); + } + + return TRUE; +@@ -148,6 +180,7 @@ gnome_qr_generate_qr_code_sync (const char *text, + uint8_t temp_buf[qrcodegen_BUFFER_LEN_FOR_VERSION (qrcodegen_VERSION_MAX)]; + static const GnomeQrColor default_bg_color = GNOME_QR_COLOR_WHITE; + static const GnomeQrColor default_fg_color = GNOME_QR_COLOR_BLACK; ++ static const GnomeQrColor transparent = GNOME_QR_COLOR_TRANSPARENT; + gint qr_size, block_size, total_size; + gint column, row, i; + +@@ -179,6 +212,10 @@ gnome_qr_generate_qr_code_sync (const char *text, + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return NULL; + ++ if (format == GNOME_QR_PIXEL_FORMAT_A_8 && !bg_color) { ++ bg_color = &transparent; ++ } ++ + if (!bg_color) + bg_color = &default_bg_color; + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.h b/libgnome-desktop/gnome-qr/gnome-qr.h +index 61ec738c..cb26ffb8 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.h ++++ b/libgnome-desktop/gnome-qr/gnome-qr.h +@@ -40,7 +40,9 @@ + * Returns: the number of bytes + */ + #define GNOME_QR_BYTES_PER_FORMAT(format) \ +- ((format) == GNOME_QR_PIXEL_FORMAT_RGB_888 ? 3 : 4) ++ ((format) == GNOME_QR_PIXEL_FORMAT_A_8 ? 1 : \ ++ ((format) == GNOME_QR_PIXEL_FORMAT_G_8 ? 1 : \ ++ (format) == GNOME_QR_PIXEL_FORMAT_RGB_888 ? 3 : 4)) + + /** + * GNOME_QR_COLOR_TRANSPARENT: +@@ -88,6 +90,8 @@ typedef enum { + * Pixel formats for the generated QR code image data. + */ + typedef enum { ++ GNOME_QR_PIXEL_FORMAT_A_8, ++ GNOME_QR_PIXEL_FORMAT_G_8, + GNOME_QR_PIXEL_FORMAT_RGB_888, + GNOME_QR_PIXEL_FORMAT_RGBA_8888, + } GnomeQrPixelFormat; +-- +2.53.0 + + +From e0e4144f098eb0fb5f8a655c563ed6f659b6be7f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 6 Feb 2026 00:23:15 +0100 +Subject: [PATCH 25/26] subprojects/qrcodegen: Only distribute C files + +Part-of: +--- + subprojects/packagefiles/qrcodegen/meson.build | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/subprojects/packagefiles/qrcodegen/meson.build b/subprojects/packagefiles/qrcodegen/meson.build +index e2ba7785..9a271366 100644 +--- a/subprojects/packagefiles/qrcodegen/meson.build ++++ b/subprojects/packagefiles/qrcodegen/meson.build +@@ -1,3 +1,14 @@ + project('qrcodegen', 'c') + + subdir('c') ++ ++# This library contains multiple implementations in different languages, ++# but only the C implementation is what we care. ++# So filter them out from the dist tarball. ++meson.add_dist_script('sh', '-xeu', '-c', ++ 'find "${MESON_PROJECT_DIST_ROOT}"/* -maxdepth 1 -type d ' + ++ '-not -name c -print -exec rm -rf {} +') ++ ++# Do not include git files in the dist tarball. ++meson.add_dist_script('sh', '-xeu', '-c', ++ 'rm -rfv "${MESON_PROJECT_DIST_ROOT}/.git"') +-- +2.53.0 + +From 6247a6a400ac236e893b261c4ef96f9de10229c5 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Thu, 30 Apr 2026 18:35:47 +0200 +Subject: [PATCH 26/26] gnome-qr: Adapt changes to older glib2 versions + +Some macros don't exist in this old glib version +--- + libgnome-desktop/gnome-qr/gnome-qr.c | 52 +++++++++++++++++++++------- + 1 file changed, 40 insertions(+), 12 deletions(-) + +diff --git a/libgnome-desktop/gnome-qr/gnome-qr.c b/libgnome-desktop/gnome-qr/gnome-qr.c +index 1ea2e1b..4c8a99a 100644 +--- a/libgnome-desktop/gnome-qr/gnome-qr.c ++++ b/libgnome-desktop/gnome-qr/gnome-qr.c +@@ -32,17 +32,45 @@ + #include + #include + +-G_DEFINE_ENUM_TYPE (GnomeQrEccLevel, gnome_qr_ecc_level, +- G_DEFINE_ENUM_VALUE (GNOME_QR_ECC_LEVEL_LOW, "low"), +- G_DEFINE_ENUM_VALUE (GNOME_QR_ECC_LEVEL_MEDIUM, "medium"), +- G_DEFINE_ENUM_VALUE (GNOME_QR_ECC_LEVEL_QUARTILE, "quartile"), +- G_DEFINE_ENUM_VALUE (GNOME_QR_ECC_LEVEL_HIGH, "high")) +- +-G_DEFINE_ENUM_TYPE (GnomeQrPixelFormat, gnome_qr_pixel_format, +- G_DEFINE_ENUM_VALUE (GNOME_QR_PIXEL_FORMAT_A_8, "a-8"), +- G_DEFINE_ENUM_VALUE (GNOME_QR_PIXEL_FORMAT_G_8, "g-8"), +- G_DEFINE_ENUM_VALUE (GNOME_QR_PIXEL_FORMAT_RGB_888, "rgb-888"), +- G_DEFINE_ENUM_VALUE (GNOME_QR_PIXEL_FORMAT_RGBA_8888, "rgba-8888")) ++GType ++gnome_qr_ecc_level_get_type (void) ++{ ++ static gsize g_type_id = 0; ++ ++ if (g_once_init_enter (&g_type_id)) { ++ static const GEnumValue values[] = { ++ { GNOME_QR_ECC_LEVEL_LOW, "GNOME_QR_ECC_LEVEL_LOW", "low" }, ++ { GNOME_QR_ECC_LEVEL_MEDIUM, "GNOME_QR_ECC_LEVEL_MEDIUM", "medium" }, ++ { GNOME_QR_ECC_LEVEL_QUARTILE, "GNOME_QR_ECC_LEVEL_QUARTILE", "quartile" }, ++ { GNOME_QR_ECC_LEVEL_HIGH, "GNOME_QR_ECC_LEVEL_HIGH", "high" }, ++ { 0, NULL, NULL } ++ }; ++ GType type_id = g_enum_register_static ("GnomeQrEccLevel", values); ++ g_once_init_leave (&g_type_id, type_id); ++ } ++ ++ return g_type_id; ++} ++ ++GType ++gnome_qr_pixel_format_get_type (void) ++{ ++ static gsize g_type_id = 0; ++ ++ if (g_once_init_enter (&g_type_id)) { ++ static const GEnumValue values[] = { ++ { GNOME_QR_PIXEL_FORMAT_A_8, "GNOME_QR_PIXEL_FORMAT_A_8", "a-8" }, ++ { GNOME_QR_PIXEL_FORMAT_G_8, "GNOME_QR_PIXEL_FORMAT_G_8", "g-8" }, ++ { GNOME_QR_PIXEL_FORMAT_RGB_888, "GNOME_QR_PIXEL_FORMAT_RGB_888", "rgb-888" }, ++ { GNOME_QR_PIXEL_FORMAT_RGBA_8888, "GNOME_QR_PIXEL_FORMAT_RGBA_8888", "rgba-8888" }, ++ { 0, NULL, NULL } ++ }; ++ GType type_id = g_enum_register_static ("GnomeQrPixelFormat", values); ++ g_once_init_leave (&g_type_id, type_id); ++ } ++ ++ return g_type_id; ++} + + typedef struct + { +@@ -115,7 +143,7 @@ fill_block (GByteArray *array, + } + } + +-G_ALWAYS_INLINE static inline gboolean ++static inline gboolean + check_color_validity (const GnomeQrColor *color, + GnomeQrPixelFormat format) + { +-- +2.53.0 + diff --git a/gnome-desktop3.spec b/gnome-desktop3.spec index 0d429a4..e8149db 100644 --- a/gnome-desktop3.spec +++ b/gnome-desktop3.spec @@ -8,7 +8,7 @@ Name: gnome-desktop3 Version: 40.4 -Release: 1%{?dist} +Release: 2%{?dist} Summary: Library with common API for various GNOME modules License: GPLv2+ and LGPLv2+ @@ -30,6 +30,8 @@ Source4: eog-defaults.list Source5: evince-defaults.list Source6: qrcodegen.tar.gz +Patch1: 0001-Introduce-gnome-qr-library.patch + BuildRequires: gcc BuildRequires: gettext BuildRequires: gtk-doc @@ -118,7 +120,9 @@ cat %SOURCE5 >> $RPM_BUILD_ROOT/%{_datadir}/applications/gnome-mimeapps.list %{_datadir}/applications/gnome-mimeapps.list # LGPL %{_libdir}/libgnome-desktop-3.so.19{,.*} +%{_libdir}/libgnome-qr.so.0{,.*} %{_libdir}/girepository-1.0/GnomeDesktop-3.0.typelib +%{_libdir}/girepository-1.0/GnomeQR-0.0.typelib %{_libexecdir}/gnome-desktop-debug/ %files devel @@ -126,6 +130,7 @@ cat %SOURCE5 >> $RPM_BUILD_ROOT/%{_datadir}/applications/gnome-mimeapps.list %{_libdir}/pkgconfig/* %{_includedir}/* %{_datadir}/gir-1.0/GnomeDesktop-3.0.gir +%{_datadir}/gir-1.0/GnomeQR-0.0.gir %dir %{_datadir}/gtk-doc/ %dir %{_datadir}/gtk-doc/html/ %doc %{_datadir}/gtk-doc/html/gnome-desktop3/ @@ -135,6 +140,10 @@ cat %SOURCE5 >> $RPM_BUILD_ROOT/%{_datadir}/applications/gnome-mimeapps.list %{_datadir}/installed-tests %changelog +* Thu Apr 30 2026 Joan Torres Lopez - 40.4-2 +- Add libgnome-qr + Resolves: RHEL-172426 + * Thu Aug 19 2021 Kalev Lember - 40.4-1 - Update to 40.4