From 5b85f27a19e96c6e39d24cf815e05d94c3de1133 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 29 Nov 2023 17:02:16 +0100 Subject: [PATCH 01/10] all: Drop usage of g_source_set_static_name() --- gdk/gdk.c | 2 +- gdk/gdkframeclockidle.c | 5 ----- gdk/wayland/gdkdevice-wayland.c | 3 --- gtk/deprecated/gtkentrycompletion.c | 1 - gtk/gtktextlinedisplaycache.c | 1 - gtk/print/gtkprintoperation.c | 15 +++++---------- gtk/print/gtkprintunixdialog.c | 2 -- modules/printbackends/gtkprintbackendcups.c | 1 - testsuite/css/data.c | 2 +- testsuite/gdk/clipboard.c | 6 +++--- testsuite/gdk/glcontext.c | 6 +++--- testsuite/gtk/meson.build | 1 - 12 files changed, 13 insertions(+), 32 deletions(-) diff --git a/gdk/gdk.c b/gdk/gdk.c index 19cf1aa6b0..bfd9a96c34 100644 --- a/gdk/gdk.c +++ b/gdk/gdk.c @@ -425,5 +425,5 @@ gdk_source_set_static_name_by_id (guint tag, if (source == NULL) return; - g_source_set_static_name (source, name); + /* No-op */ } diff --git a/gdk/gdkframeclockidle.c b/gdk/gdkframeclockidle.c index 3deade7b05..70b4a4e3d5 100644 --- a/gdk/gdkframeclockidle.c +++ b/gdk/gdkframeclockidle.c @@ -123,7 +123,6 @@ get_sleep_serial (void) { sleep_source = g_source_new (&sleep_source_funcs, sizeof (GSource)); - g_source_set_static_name (sleep_source, "[gtk] sleep serial"); g_source_set_priority (sleep_source, G_PRIORITY_HIGH); g_source_attach (sleep_source, NULL); g_source_unref (sleep_source); @@ -330,15 +329,11 @@ maybe_start_idle (GdkFrameClockIdle *self, if (priv->flush_idle_id == 0 && should_run_flush_idle (self)) { - GSource *source; - priv->flush_idle_id = g_timeout_add_full (GDK_PRIORITY_EVENTS + 1, min_interval, gdk_frame_clock_flush_idle, g_object_ref (self), (GDestroyNotify) g_object_unref); - source = g_main_context_find_source_by_id (NULL, priv->flush_idle_id); - g_source_set_static_name (source, "[gtk] gdk_frame_clock_flush_idle"); } if (!priv->in_paint_idle && diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c index 9cb3cfbfda..20438bc452 100644 --- a/gdk/wayland/gdkdevice-wayland.c +++ b/gdk/wayland/gdkdevice-wayland.c @@ -333,7 +333,6 @@ gdk_wayland_device_update_surface_cursor (GdkDevice *device) pointer->cursor_timeout_id == 0) { guint id; - GSource *source; gdk_wayland_seat_stop_cursor_animation (seat, pointer); @@ -341,8 +340,6 @@ gdk_wayland_device_update_surface_cursor (GdkDevice *device) id = g_timeout_add (next_image_delay, (GSourceFunc) gdk_wayland_device_update_surface_cursor, device); - source = g_main_context_find_source_by_id (NULL, id); - g_source_set_static_name (source, "[gtk] gdk_wayland_device_update_surface_cursor"); pointer->cursor_timeout_id = id; } else diff --git a/gtk/deprecated/gtkentrycompletion.c b/gtk/deprecated/gtkentrycompletion.c index f3319e26af..d83651d28a 100644 --- a/gtk/deprecated/gtkentrycompletion.c +++ b/gtk/deprecated/gtkentrycompletion.c @@ -2088,7 +2088,6 @@ completion_inserted_text_callback (GtkEntryBuffer *buffer, g_cclosure_new_object (G_CALLBACK (check_completion_callback), G_OBJECT (completion))); g_source_attach (completion->check_completion_idle, NULL); - g_source_set_static_name (completion->check_completion_idle, "[gtk] check_completion_callback"); } } diff --git a/gtk/gtktextlinedisplaycache.c b/gtk/gtktextlinedisplaycache.c index c99ef06d01..28a6a91eb2 100644 --- a/gtk/gtktextlinedisplaycache.c +++ b/gtk/gtktextlinedisplaycache.c @@ -142,7 +142,6 @@ gtk_text_line_display_cache_delay_eviction (GtkTextLineDisplayCache *cache) gtk_text_line_display_cache_blow_cb, cache); cache->evict_source = g_main_context_find_source_by_id (NULL, tag); - g_source_set_static_name (cache->evict_source, "[gtk+] gtk_text_line_display_cache_blow_cb"); } } diff --git a/gtk/print/gtkprintoperation.c b/gtk/print/gtkprintoperation.c index 8aa8976a10..bb169b0ae1 100644 --- a/gtk/print/gtkprintoperation.c +++ b/gtk/print/gtkprintoperation.c @@ -620,17 +620,14 @@ preview_ready (GtkPrintOperationPreview *preview, GtkPrintContext *context, PreviewOp *pop) { - guint id; - pop->print_context = context; g_object_ref (preview); - - id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 10, - preview_print_idle, - pop, - preview_print_idle_done); - g_source_set_static_name (g_main_context_find_source_by_id (NULL, id), "[gtk] preview_print_idle"); + + g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 10, + preview_print_idle, + pop, + preview_print_idle_done); } @@ -2877,7 +2874,6 @@ G_GNUC_END_IGNORE_DEPRECATIONS g_timeout_add (SHOW_PROGRESS_TIME, (GSourceFunc) show_progress_timeout, data); - g_source_set_static_name (g_main_context_find_source_by_id (NULL, priv->show_progress_timeout_id), "[gtk] show_progress_timeout"); data->progress = progress; } @@ -2948,7 +2944,6 @@ G_GNUC_END_IGNORE_DEPRECATIONS print_pages_idle, data, print_pages_idle_done); - g_source_set_static_name (g_main_context_find_source_by_id (NULL, priv->print_pages_idle_id), "[gtk] print_pages_idle"); /* Recursive main loop to make sure we don't exit on sync operations */ if (priv->is_sync) diff --git a/gtk/print/gtkprintunixdialog.c b/gtk/print/gtkprintunixdialog.c index f39a361a1a..94b427e145 100644 --- a/gtk/print/gtkprintunixdialog.c +++ b/gtk/print/gtkprintunixdialog.c @@ -1799,8 +1799,6 @@ schedule_idle_mark_conflicts (GtkPrintUnixDialog *dialog) return; dialog->mark_conflicts_id = g_idle_add (mark_conflicts_callback, dialog); - g_source_set_static_name (g_main_context_find_source_by_id (NULL, dialog->mark_conflicts_id), - "[gtk] mark_conflicts_callback"); } static void diff --git a/modules/printbackends/gtkprintbackendcups.c b/modules/printbackends/gtkprintbackendcups.c index 0382c8983d..be6fbbcd2a 100644 --- a/modules/printbackends/gtkprintbackendcups.c +++ b/modules/printbackends/gtkprintbackendcups.c @@ -1673,7 +1673,6 @@ cups_request_execute (GtkPrintBackendCups *print_backend, dispatch = (GtkPrintCupsDispatchWatch *) g_source_new (&_cups_dispatch_watch_funcs, sizeof (GtkPrintCupsDispatchWatch)); - g_source_set_static_name (&dispatch->source, "GTK CUPS backend"); GTK_DEBUG (PRINTING, "CUPS Backend: %s - Executing cups request on server '%s' and resource '%s'", G_STRFUNC, dispatch, request->server, request->resource); diff --git a/testsuite/css/data.c b/testsuite/css/data.c index 8022bcd96f..82db8f3852 100644 --- a/testsuite/css/data.c +++ b/testsuite/css/data.c @@ -63,7 +63,7 @@ test_parse (gconstpointer data) iconv = g_iconv_open ("UTF-8", test->charset); if (iconv == (GIConv) -1) { - g_test_skip_printf ("Conversion from %s to UTF-8 not supported", test->charset); + g_test_skip ("Conversion to UTF-8 not supported"); return; } diff --git a/testsuite/gdk/clipboard.c b/testsuite/gdk/clipboard.c index 1a414c5b6a..eb2b58d238 100644 --- a/testsuite/gdk/clipboard.c +++ b/testsuite/gdk/clipboard.c @@ -135,9 +135,9 @@ compare_files (const char *file1, g_assert_no_error (error); if (l1 != l2) - g_test_fail_printf ("file length mismatch: %s %s\n", file1, file2); + g_test_fail (); else if (memcmp (m1, m2, l1) != 0) - g_test_fail_printf ("file mismatch: %s %s\n", file1, file2); + g_test_fail (); g_free (m1); g_free (m2); @@ -208,7 +208,7 @@ test_clipboard_roundtrip (const char *type, g_assert_cmpstr (stdout_buf, ==, result); else if (g_str_has_prefix (stdout_buf, "ERROR")) { - g_test_fail_printf ("dest error: %s", stdout_buf); + g_test_fail (); } else if (g_str_equal (type, "image")) { diff --git a/testsuite/gdk/glcontext.c b/testsuite/gdk/glcontext.c index 2fecec2f24..121d40f2ca 100644 --- a/testsuite/gdk/glcontext.c +++ b/testsuite/gdk/glcontext.c @@ -21,7 +21,7 @@ test_allowed_backends (gconstpointer data) display = gdk_display_get_default (); if (!gdk_display_prepare_gl (display, &error)) { - g_test_skip_printf ("no GL support: %s", error->message); + g_test_skip ("no GL support"); g_clear_error (&error); return; } @@ -79,7 +79,7 @@ test_use_es (void) display = gdk_display_get_default (); if (!gdk_display_prepare_gl (display, &error)) { - g_test_skip_printf ("no GL support: %s", error->message); + g_test_skip ("no GL support"); g_clear_error (&error); return; } @@ -127,7 +127,7 @@ test_version (void) display = gdk_display_get_default (); if (!gdk_display_prepare_gl (display, &error)) { - g_test_skip_printf ("no GL support: %s", error->message); + g_test_skip ("no GL support"); g_clear_error (&error); return; } diff --git a/testsuite/gtk/meson.build b/testsuite/gtk/meson.build index 12b025f317..e95fd95bfb 100644 --- a/testsuite/gtk/meson.build +++ b/testsuite/gtk/meson.build @@ -53,7 +53,6 @@ tests = [ { 'name': 'grid' }, { 'name': 'grid-layout' }, { 'name': 'icontheme' }, - { 'name': 'label' }, { 'name': 'listbox' }, { 'name': 'listlistmodel' }, { 'name': 'main' }, -- 2.43.0 From 6197d5dbfbc1a6cfbb66c423591a45b1e5f6402e Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 29 Nov 2023 17:02:57 +0100 Subject: [PATCH 02/10] gsk: Add internal GtkPangoGlyphVisAttr struct This struct has an is_color field. --- gsk/gl/gskglrenderjob.c | 3 ++- gsk/gskprivate.h | 8 ++++++++ gsk/gskrendernodeimpl.c | 5 +++-- gsk/gskrendernodeparser.c | 11 ++++++----- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c index 938f9f7fb1..1a3cea3e90 100644 --- a/gsk/gl/gskglrenderjob.c +++ b/gsk/gl/gskglrenderjob.c @@ -43,6 +43,7 @@ #include "gskglprogramprivate.h" #include "gskglrenderjobprivate.h" #include "gskglshadowlibraryprivate.h" +#include "gskprivate.h" #include "ninesliceprivate.h" #include "fp16private.h" @@ -3021,7 +3022,7 @@ gsk_gl_render_job_visit_text_node (GskGLRenderJob *job, /* If the glyph has color, we don't need to recolor anything. * We tell the shader by setting the color to vec4(-1). */ - if (!force_color && gi->attr.is_color) + if (!force_color && ((GtkPangoGlyphVisAttr*) &gi->attr)->is_color) c = nc; else c = cc; diff --git a/gsk/gskprivate.h b/gsk/gskprivate.h index 150b89eb78..9be7a8cffc 100644 --- a/gsk/gskprivate.h +++ b/gsk/gskprivate.h @@ -7,5 +7,13 @@ G_BEGIN_DECLS void gsk_ensure_resources (void); +typedef struct _GtkPangoGlyphVisAttr GtkPangoGlyphVisAttr; + +struct _GtkPangoGlyphVisAttr +{ + guint is_cluster_start : 1; + guint is_color : 1; +}; + G_END_DECLS diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index 3790fcb4c3..d0043b08e6 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -28,6 +28,7 @@ #include "gskrendererprivate.h" #include "gskroundedrectprivate.h" #include "gsktransformprivate.h" +#include "gskprivate.h" #include "gdk/gdktextureprivate.h" #include "gdk/gdkmemoryformatprivate.h" @@ -5105,7 +5106,7 @@ gsk_text_node_diff (GskRenderNode *node1, info1->geometry.x_offset == info2->geometry.x_offset && info1->geometry.y_offset == info2->geometry.y_offset && info1->attr.is_cluster_start == info2->attr.is_cluster_start && - info1->attr.is_color == info2->attr.is_color) + ((GtkPangoGlyphVisAttr*) &info1->attr)->is_color == ((GtkPangoGlyphVisAttr*) &info2->attr)->is_color) continue; gsk_render_node_diff_impossible (node1, node2, region); @@ -5184,7 +5185,7 @@ gsk_text_node_new (PangoFont *font, glyph_infos[n] = glyphs->glyphs[i]; - if (glyphs->glyphs[i].attr.is_color) + if (((GtkPangoGlyphVisAttr*) &glyphs->glyphs[i].attr)->is_color) self->has_color_glyphs = TRUE; n++; diff --git a/gsk/gskrendernodeparser.c b/gsk/gskrendernodeparser.c index 7f00437068..2c39447352 100644 --- a/gsk/gskrendernodeparser.c +++ b/gsk/gskrendernodeparser.c @@ -26,6 +26,7 @@ #include "gskroundedrectprivate.h" #include "gskrendernodeprivate.h" #include "gsktransformprivate.h" +#include "gskprivate.h" #include "gdk/gdkrgbaprivate.h" #include "gdk/gdktextureprivate.h" @@ -1013,9 +1014,9 @@ parse_glyphs (GtkCssParser *parser, gi.attr.is_cluster_start = 1; if (gtk_css_parser_try_ident (parser, "color")) - gi.attr.is_color = 1; + ((GtkPangoGlyphVisAttr*) &gi.attr)->is_color = 1; else - gi.attr.is_color = 0; + ((GtkPangoGlyphVisAttr*) &gi.attr)->is_color = 0; } pango_glyph_string_set_size (glyph_string, glyph_string->num_glyphs + 1); @@ -2979,7 +2980,7 @@ gsk_text_node_serialize_glyphs (GskRenderNode *node, glyphs[i].geometry.x_offset == 0 && glyphs[i].geometry.y_offset == 0 && glyphs[i].attr.is_cluster_start && - !glyphs[i].attr.is_color) + !((GtkPangoGlyphVisAttr*) &glyphs[i].attr)->is_color) { switch (j + MIN_ASCII_GLYPH) { @@ -3009,7 +3010,7 @@ gsk_text_node_serialize_glyphs (GskRenderNode *node, g_string_append_printf (p, "%u ", glyphs[i].glyph); string_append_double (p, (double) glyphs[i].geometry.width / PANGO_SCALE); if (!glyphs[i].attr.is_cluster_start || - glyphs[i].attr.is_color || + ((GtkPangoGlyphVisAttr*) &glyphs[i].attr)->is_color || glyphs[i].geometry.x_offset != 0 || glyphs[i].geometry.y_offset != 0) { @@ -3019,7 +3020,7 @@ gsk_text_node_serialize_glyphs (GskRenderNode *node, string_append_double (p, (double) glyphs[i].geometry.y_offset / PANGO_SCALE); if (!glyphs[i].attr.is_cluster_start) g_string_append (p, " same-cluster"); - if (glyphs[i].attr.is_color) + if (((GtkPangoGlyphVisAttr*) &glyphs[i].attr)->is_color) g_string_append (p, " color"); } -- 2.43.0 From c0e1849b0c5e06ca648e6ed2d4731c269d872e6e Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 29 Nov 2023 17:04:37 +0100 Subject: [PATCH 03/10] all: Avoid G_DEFINE_FINAL_TYPE --- gtk/gtkfilethumbnail.c | 2 +- testsuite/gtk/action.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gtk/gtkfilethumbnail.c b/gtk/gtkfilethumbnail.c index 84df7dcc07..850c6b306e 100644 --- a/gtk/gtkfilethumbnail.c +++ b/gtk/gtkfilethumbnail.c @@ -46,7 +46,7 @@ typedef struct GtkWidgetClass parent; } GtkFileThumbnailClass; -G_DEFINE_FINAL_TYPE (GtkFileThumbnail, _gtk_file_thumbnail, GTK_TYPE_WIDGET) +G_DEFINE_TYPE (GtkFileThumbnail, _gtk_file_thumbnail, GTK_TYPE_WIDGET) enum { PROP_0, diff --git a/testsuite/gtk/action.c b/testsuite/gtk/action.c index d99b16c33b..c1859644fc 100644 --- a/testsuite/gtk/action.c +++ b/testsuite/gtk/action.c @@ -725,7 +725,7 @@ struct _MyGtkActionable GtkButton parent_instance; }; -G_DEFINE_FINAL_TYPE (MyGtkActionable, my_gtk_actionable, GTK_TYPE_BUTTON); +G_DEFINE_TYPE (MyGtkActionable, my_gtk_actionable, GTK_TYPE_BUTTON); static void test_cb (GtkWidget *sender, -- 2.43.0 From c380212c74569ba6ff63e8b605a03d68ab26e69c Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 29 Nov 2023 17:05:12 +0100 Subject: [PATCH 04/10] gtk: Add internal GtkSignalGroup Copied from GSignalGroup at newer GLib --- gtk/deprecated/gtkentrycompletion.c | 12 +- gtk/gtkentryprivate.h | 3 +- gtk/gtksignalgroup.c | 732 ++++++++++++++++++++++++++++ gtk/gtksignalgroup.h | 72 +++ gtk/meson.build | 1 + 5 files changed, 813 insertions(+), 7 deletions(-) create mode 100644 gtk/gtksignalgroup.c create mode 100644 gtk/gtksignalgroup.h diff --git a/gtk/deprecated/gtkentrycompletion.c b/gtk/deprecated/gtkentrycompletion.c index d83651d28a..129472f4a4 100644 --- a/gtk/deprecated/gtkentrycompletion.c +++ b/gtk/deprecated/gtkentrycompletion.c @@ -1391,7 +1391,7 @@ gtk_entry_completion_insert_completion_text (GtkEntryCompletion *completion, g_signal_handler_block (text, completion->changed_id); if (completion->insert_text_signal_group != NULL) - g_signal_group_block (completion->insert_text_signal_group); + gtk_signal_group_block (completion->insert_text_signal_group); gtk_editable_set_text (GTK_EDITABLE (completion->entry), new_text); @@ -1402,7 +1402,7 @@ gtk_entry_completion_insert_completion_text (GtkEntryCompletion *completion, g_signal_handler_unblock (text, completion->changed_id); if (completion->insert_text_signal_group != NULL) - g_signal_group_unblock (completion->insert_text_signal_group); + gtk_signal_group_unblock (completion->insert_text_signal_group); } static gboolean @@ -1443,7 +1443,7 @@ gtk_entry_completion_insert_prefix (GtkEntryCompletion *completion) char *prefix; if (completion->insert_text_signal_group != NULL) - g_signal_group_block (completion->insert_text_signal_group); + gtk_signal_group_block (completion->insert_text_signal_group); prefix = gtk_entry_completion_compute_prefix (completion, gtk_editable_get_text (GTK_EDITABLE (completion->entry))); @@ -1456,7 +1456,7 @@ gtk_entry_completion_insert_prefix (GtkEntryCompletion *completion) } if (completion->insert_text_signal_group != NULL) - g_signal_group_unblock (completion->insert_text_signal_group); + gtk_signal_group_unblock (completion->insert_text_signal_group); } /** @@ -2110,8 +2110,8 @@ connect_completion_signals (GtkEntryCompletion *completion) completion->changed_id = g_signal_connect (text, "changed", G_CALLBACK (gtk_entry_completion_changed), completion); - completion->insert_text_signal_group = g_signal_group_new (GTK_TYPE_ENTRY_BUFFER); - g_signal_group_connect (completion->insert_text_signal_group, "inserted-text", G_CALLBACK (completion_inserted_text_callback), completion); + completion->insert_text_signal_group = gtk_signal_group_new (GTK_TYPE_ENTRY_BUFFER); + gtk_signal_group_connect (completion->insert_text_signal_group, "inserted-text", G_CALLBACK (completion_inserted_text_callback), completion); g_object_bind_property (text, "buffer", completion->insert_text_signal_group, "target", G_BINDING_SYNC_CREATE); g_signal_connect (text, "notify", G_CALLBACK (clear_completion_callback), completion); diff --git a/gtk/gtkentryprivate.h b/gtk/gtkentryprivate.h index e5c381021e..38165c6c47 100644 --- a/gtk/gtkentryprivate.h +++ b/gtk/gtkentryprivate.h @@ -26,6 +26,7 @@ #include "deprecated/gtktreeviewcolumn.h" #include "gtkeventcontrollerkey.h" #include "gtktextprivate.h" +#include "gtksignalgroup.h" G_BEGIN_DECLS @@ -61,7 +62,7 @@ struct _GtkEntryCompletion gulong completion_timeout; gulong changed_id; - GSignalGroup *insert_text_signal_group; + GtkSignalGroup *insert_text_signal_group; int current_selected; diff --git a/gtk/gtksignalgroup.c b/gtk/gtksignalgroup.c new file mode 100644 index 0000000000..38b39e8996 --- /dev/null +++ b/gtk/gtksignalgroup.c @@ -0,0 +1,732 @@ +/* GObject - GLib Type, Object, Parameter and Signal Library + * + * Copyright (C) 2015-2022 Christian Hergert + * Copyright (C) 2015 Garrett Regier + * + * 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 . + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include "config.h" + +#include + +#include "gtksignalgroup.h" + +struct _GtkSignalGroup +{ + GObject parent_instance; + + GWeakRef target_ref; + GRecMutex mutex; + GPtrArray *handlers; + GType target_type; + gssize block_count; + + guint has_bound_at_least_once : 1; +}; + +typedef struct _GtkSignalGroupClass +{ + GObjectClass parent_class; + + void (*bind) (GtkSignalGroup *self, + GObject *target); +} GtkSignalGroupClass; + +typedef struct +{ + GtkSignalGroup *group; + gulong handler_id; + GClosure *closure; + guint signal_id; + GQuark signal_detail; + guint connect_after : 1; +} SignalHandler; + +G_DEFINE_TYPE (GtkSignalGroup, gtk_signal_group, G_TYPE_OBJECT) + +typedef enum +{ + PROP_TARGET = 1, + PROP_TARGET_TYPE, + LAST_PROP +} GSignalGroupProperty; + +enum +{ + BIND, + UNBIND, + LAST_SIGNAL +}; + +static GParamSpec *properties[LAST_PROP]; +static guint signals[LAST_SIGNAL]; + +static void +g_signal_group_set_target_type (GtkSignalGroup *self, + GType target_type) +{ + g_assert (GTK_IS_SIGNAL_GROUP (self)); + g_assert (g_type_is_a (target_type, G_TYPE_OBJECT)); + + self->target_type = target_type; + + /* The class must be created at least once for the signals + * to be registered, otherwise g_signal_parse_name() will fail + */ + if (G_TYPE_IS_INTERFACE (target_type)) + { + if (g_type_default_interface_peek (target_type) == NULL) + g_type_default_interface_unref (g_type_default_interface_ref (target_type)); + } + else + { + if (g_type_class_peek (target_type) == NULL) + g_type_class_unref (g_type_class_ref (target_type)); + } +} + +static void +g_signal_group_gc_handlers (GtkSignalGroup *self) +{ + guint i; + + g_assert (GTK_IS_SIGNAL_GROUP (self)); + + /* + * Remove any handlers for which the closures have become invalid. We do + * this cleanup lazily to avoid situations where we could have disposal + * active on both the signal group and the peer object. + */ + + for (i = self->handlers->len; i > 0; i--) + { + const SignalHandler *handler = g_ptr_array_index (self->handlers, i - 1); + + g_assert (handler != NULL); + g_assert (handler->closure != NULL); + + if (handler->closure->is_invalid) + g_ptr_array_remove_index (self->handlers, i - 1); + } +} + +static void +g_signal_group__target_weak_notify (gpointer data, + GObject *where_object_was) +{ + GtkSignalGroup *self = data; + guint i; + + g_assert (GTK_IS_SIGNAL_GROUP (self)); + g_assert (where_object_was != NULL); + + g_rec_mutex_lock (&self->mutex); + + g_weak_ref_set (&self->target_ref, NULL); + + for (i = 0; i < self->handlers->len; i++) + { + SignalHandler *handler = g_ptr_array_index (self->handlers, i); + + handler->handler_id = 0; + } + + g_signal_emit (self, signals[UNBIND], 0); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TARGET]); + + g_rec_mutex_unlock (&self->mutex); +} + +static void +g_signal_group_bind_handler (GtkSignalGroup *self, + SignalHandler *handler, + GObject *target) +{ + gssize i; + + g_assert (self != NULL); + g_assert (G_IS_OBJECT (target)); + g_assert (handler != NULL); + g_assert (handler->signal_id != 0); + g_assert (handler->closure != NULL); + g_assert (handler->closure->is_invalid == 0); + g_assert (handler->handler_id == 0); + + handler->handler_id = g_signal_connect_closure_by_id (target, + handler->signal_id, + handler->signal_detail, + handler->closure, + handler->connect_after); + + g_assert (handler->handler_id != 0); + + for (i = 0; i < self->block_count; i++) + g_signal_handler_block (target, handler->handler_id); +} + +static void +g_signal_group_bind (GtkSignalGroup *self, + GObject *target) +{ + GObject *hold; + guint i; + + g_assert (GTK_IS_SIGNAL_GROUP (self)); + g_assert (!target || G_IS_OBJECT (target)); + + if (target == NULL) + return; + + self->has_bound_at_least_once = TRUE; + + hold = g_object_ref (target); + + g_weak_ref_set (&self->target_ref, hold); + g_object_weak_ref (hold, g_signal_group__target_weak_notify, self); + + g_signal_group_gc_handlers (self); + + for (i = 0; i < self->handlers->len; i++) + { + SignalHandler *handler = g_ptr_array_index (self->handlers, i); + + g_signal_group_bind_handler (self, handler, hold); + } + + g_signal_emit (self, signals [BIND], 0, hold); + + g_object_unref (hold); +} + +static void +g_signal_group_unbind (GtkSignalGroup *self) +{ + GObject *target; + guint i; + + g_return_if_fail (GTK_IS_SIGNAL_GROUP (self)); + + target = g_weak_ref_get (&self->target_ref); + + /* + * Target may be NULL by this point, as we got notified of its destruction. + * However, if we're early enough, we may get a full reference back and can + * cleanly disconnect our connections. + */ + + if (target != NULL) + { + g_weak_ref_set (&self->target_ref, NULL); + + /* + * Let go of our weak reference now that we have a full reference + * for the life of this function. + */ + g_object_weak_unref (target, + g_signal_group__target_weak_notify, + self); + } + + g_signal_group_gc_handlers (self); + + for (i = 0; i < self->handlers->len; i++) + { + SignalHandler *handler; + gulong handler_id; + + handler = g_ptr_array_index (self->handlers, i); + + g_assert (handler != NULL); + g_assert (handler->signal_id != 0); + g_assert (handler->closure != NULL); + + handler_id = handler->handler_id; + handler->handler_id = 0; + + /* + * If @target is NULL, we lost a race to cleanup the weak + * instance and the signal connections have already been + * finalized and therefore nothing to do. + */ + + if (target != NULL && handler_id != 0) + g_signal_handler_disconnect (target, handler_id); + } + + g_signal_emit (self, signals [UNBIND], 0); + + g_clear_object (&target); +} + +static gboolean +g_signal_group_check_target_type (GtkSignalGroup *self, + gpointer target) +{ + if ((target != NULL) && + !g_type_is_a (G_OBJECT_TYPE (target), self->target_type)) + { + g_critical ("Failed to set GtkSignalGroup of target type %s " + "using target %p of type %s", + g_type_name (self->target_type), + target, G_OBJECT_TYPE_NAME (target)); + return FALSE; + } + + return TRUE; +} + +void +gtk_signal_group_block (GtkSignalGroup *self) +{ + GObject *target; + guint i; + + g_return_if_fail (GTK_IS_SIGNAL_GROUP (self)); + g_return_if_fail (self->block_count >= 0); + + g_rec_mutex_lock (&self->mutex); + + self->block_count++; + + target = g_weak_ref_get (&self->target_ref); + + if (target == NULL) + goto unlock; + + for (i = 0; i < self->handlers->len; i++) + { + const SignalHandler *handler = g_ptr_array_index (self->handlers, i); + + g_assert (handler != NULL); + g_assert (handler->signal_id != 0); + g_assert (handler->closure != NULL); + g_assert (handler->handler_id != 0); + + g_signal_handler_block (target, handler->handler_id); + } + + g_object_unref (target); + +unlock: + g_rec_mutex_unlock (&self->mutex); +} + +void +gtk_signal_group_unblock (GtkSignalGroup *self) +{ + GObject *target; + guint i; + + g_return_if_fail (GTK_IS_SIGNAL_GROUP (self)); + g_return_if_fail (self->block_count > 0); + + g_rec_mutex_lock (&self->mutex); + + self->block_count--; + + target = g_weak_ref_get (&self->target_ref); + if (target == NULL) + goto unlock; + + for (i = 0; i < self->handlers->len; i++) + { + const SignalHandler *handler = g_ptr_array_index (self->handlers, i); + + g_assert (handler != NULL); + g_assert (handler->signal_id != 0); + g_assert (handler->closure != NULL); + g_assert (handler->handler_id != 0); + + g_signal_handler_unblock (target, handler->handler_id); + } + + g_object_unref (target); + +unlock: + g_rec_mutex_unlock (&self->mutex); +} + +gpointer +gtk_signal_group_dup_target (GtkSignalGroup *self) +{ + GObject *target; + + g_return_val_if_fail (GTK_IS_SIGNAL_GROUP (self), NULL); + + g_rec_mutex_lock (&self->mutex); + target = g_weak_ref_get (&self->target_ref); + g_rec_mutex_unlock (&self->mutex); + + return target; +} + +void +gtk_signal_group_set_target (GtkSignalGroup *self, + gpointer target) +{ + GObject *object; + + g_return_if_fail (GTK_IS_SIGNAL_GROUP (self)); + + g_rec_mutex_lock (&self->mutex); + + object = g_weak_ref_get (&self->target_ref); + + if (object == (GObject *)target) + goto cleanup; + + if (!g_signal_group_check_target_type (self, target)) + goto cleanup; + + /* Only emit unbind if we've ever called bind */ + if (self->has_bound_at_least_once) + g_signal_group_unbind (self); + + g_signal_group_bind (self, target); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TARGET]); + +cleanup: + g_clear_object (&object); + g_rec_mutex_unlock (&self->mutex); +} + +static void +signal_handler_free (gpointer data) +{ + SignalHandler *handler = data; + + if (handler->closure != NULL) + g_closure_invalidate (handler->closure); + + handler->handler_id = 0; + handler->signal_id = 0; + handler->signal_detail = 0; + g_clear_pointer (&handler->closure, g_closure_unref); + g_slice_free (SignalHandler, handler); +} + +static void +g_signal_group_constructed (GObject *object) +{ + GtkSignalGroup *self = (GtkSignalGroup *)object; + GObject *target; + + g_rec_mutex_lock (&self->mutex); + + target = g_weak_ref_get (&self->target_ref); + if (!g_signal_group_check_target_type (self, target)) + gtk_signal_group_set_target (self, NULL); + + G_OBJECT_CLASS (gtk_signal_group_parent_class)->constructed (object); + + g_clear_object (&target); + + g_rec_mutex_unlock (&self->mutex); +} + +static void +g_signal_group_dispose (GObject *object) +{ + GtkSignalGroup *self = (GtkSignalGroup *)object; + + g_rec_mutex_lock (&self->mutex); + + g_signal_group_gc_handlers (self); + + if (self->has_bound_at_least_once) + g_signal_group_unbind (self); + + g_clear_pointer (&self->handlers, g_ptr_array_unref); + + g_rec_mutex_unlock (&self->mutex); + + G_OBJECT_CLASS (gtk_signal_group_parent_class)->dispose (object); +} + +static void +g_signal_group_finalize (GObject *object) +{ + GtkSignalGroup *self = (GtkSignalGroup *)object; + + g_weak_ref_clear (&self->target_ref); + g_rec_mutex_clear (&self->mutex); + + G_OBJECT_CLASS (gtk_signal_group_parent_class)->finalize (object); +} + +static void +g_signal_group_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkSignalGroup *self = GTK_SIGNAL_GROUP (object); + + switch (prop_id) + { + case PROP_TARGET: + g_value_take_object (value, gtk_signal_group_dup_target (self)); + break; + + case PROP_TARGET_TYPE: + g_value_set_gtype (value, self->target_type); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +g_signal_group_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkSignalGroup *self = GTK_SIGNAL_GROUP (object); + + switch (prop_id) + { + case PROP_TARGET: + gtk_signal_group_set_target (self, g_value_get_object (value)); + break; + + case PROP_TARGET_TYPE: + g_signal_group_set_target_type (self, g_value_get_gtype (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gtk_signal_group_class_init (GtkSignalGroupClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = g_signal_group_constructed; + object_class->dispose = g_signal_group_dispose; + object_class->finalize = g_signal_group_finalize; + object_class->get_property = g_signal_group_get_property; + object_class->set_property = g_signal_group_set_property; + + properties[PROP_TARGET] = + g_param_spec_object ("target", + "Target", + "The target instance used when connecting signals.", + G_TYPE_OBJECT, + (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); + + properties[PROP_TARGET_TYPE] = + g_param_spec_gtype ("target-type", + "Target Type", + "The GType of the target property.", + G_TYPE_OBJECT, + (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (object_class, LAST_PROP, properties); + + signals[BIND] = + g_signal_new ("bind", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, + 1, + G_TYPE_OBJECT); + + signals[UNBIND] = + g_signal_new ("unbind", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, + 0); +} + +static void +gtk_signal_group_init (GtkSignalGroup *self) +{ + g_rec_mutex_init (&self->mutex); + self->handlers = g_ptr_array_new_with_free_func (signal_handler_free); + self->target_type = G_TYPE_OBJECT; +} + +GtkSignalGroup * +gtk_signal_group_new (GType target_type) +{ + g_return_val_if_fail (g_type_is_a (target_type, G_TYPE_OBJECT), NULL); + + return g_object_new (GTK_TYPE_SIGNAL_GROUP, + "target-type", target_type, + NULL); +} + +static gboolean +g_signal_group_connect_closure_ (GtkSignalGroup *self, + const gchar *detailed_signal, + GClosure *closure, + gboolean after) +{ + GObject *target; + SignalHandler *handler; + guint signal_id; + GQuark signal_detail; + + g_return_val_if_fail (GTK_IS_SIGNAL_GROUP (self), FALSE); + g_return_val_if_fail (detailed_signal != NULL, FALSE); + g_return_val_if_fail (g_signal_parse_name (detailed_signal, self->target_type, + &signal_id, &signal_detail, TRUE) != 0, FALSE); + g_return_val_if_fail (closure != NULL, FALSE); + + g_rec_mutex_lock (&self->mutex); + + if (self->has_bound_at_least_once) + { + g_critical ("Cannot add signals after setting target"); + g_rec_mutex_unlock (&self->mutex); + return FALSE; + } + + handler = g_slice_new0 (SignalHandler); + handler->group = self; + handler->signal_id = signal_id; + handler->signal_detail = signal_detail; + handler->closure = g_closure_ref (closure); + handler->connect_after = after; + + g_closure_sink (closure); + + g_ptr_array_add (self->handlers, handler); + + target = g_weak_ref_get (&self->target_ref); + + if (target != NULL) + { + g_signal_group_bind_handler (self, handler, target); + g_object_unref (target); + } + + /* Lazily remove any old handlers on connect */ + g_signal_group_gc_handlers (self); + + g_rec_mutex_unlock (&self->mutex); + return TRUE; +} + +void +gtk_signal_group_connect_closure (GtkSignalGroup *self, + const gchar *detailed_signal, + GClosure *closure, + gboolean after) +{ + g_signal_group_connect_closure_ (self, detailed_signal, closure, after); +} + +static void +gtk_signal_group_connect_full (GtkSignalGroup *self, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data, + GClosureNotify notify, + GConnectFlags flags, + gboolean is_object) +{ + GClosure *closure; + + g_return_if_fail (c_handler != NULL); + g_return_if_fail (!is_object || G_IS_OBJECT (data)); + + if ((flags & G_CONNECT_SWAPPED) != 0) + closure = g_cclosure_new_swap (c_handler, data, notify); + else + closure = g_cclosure_new (c_handler, data, notify); + + if (is_object) + { + /* Set closure->is_invalid when data is disposed. We only track this to avoid + * reconnecting in the future. However, we do a round of cleanup when ever we + * connect a new object or the target changes to GC the old handlers. + */ + g_object_watch_closure (data, closure); + } + + if (!g_signal_group_connect_closure_ (self, + detailed_signal, + closure, + (flags & G_CONNECT_AFTER) != 0)) + g_closure_unref (closure); +} + +void +gtk_signal_group_connect_object (GtkSignalGroup *self, + const gchar *detailed_signal, + GCallback c_handler, + gpointer object, + GConnectFlags flags) +{ + g_return_if_fail (G_IS_OBJECT (object)); + + gtk_signal_group_connect_full (self, detailed_signal, c_handler, object, NULL, + flags, TRUE); +} + +void +gtk_signal_group_connect_data (GtkSignalGroup *self, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data, + GClosureNotify notify, + GConnectFlags flags) +{ + gtk_signal_group_connect_full (self, detailed_signal, c_handler, data, notify, + flags, FALSE); +} + +void +gtk_signal_group_connect (GtkSignalGroup *self, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data) +{ + gtk_signal_group_connect_full (self, detailed_signal, c_handler, data, NULL, + 0, FALSE); +} + +void +gtk_signal_group_connect_after (GtkSignalGroup *self, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data) +{ + gtk_signal_group_connect_full (self, detailed_signal, c_handler, + data, NULL, G_CONNECT_AFTER, FALSE); +} + +void +gtk_signal_group_connect_swapped (GtkSignalGroup *self, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data) +{ + gtk_signal_group_connect_full (self, detailed_signal, c_handler, data, NULL, + G_CONNECT_SWAPPED, FALSE); +} diff --git a/gtk/gtksignalgroup.h b/gtk/gtksignalgroup.h new file mode 100644 index 0000000000..e72de0c838 --- /dev/null +++ b/gtk/gtksignalgroup.h @@ -0,0 +1,72 @@ +/* GObject - GLib Type, Object, Parameter and Signal Library + * + * Copyright (C) 2015-2022 Christian Hergert + * Copyright (C) 2015 Garrett Regier + * + * 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 . + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __GTK_SIGNAL_GROUP_H__ +#define __GTK_SIGNAL_GROUP_H__ + +#include + +G_BEGIN_DECLS + +#define GTK_SIGNAL_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SIGNAL_GROUP, GtkSignalGroup)) +#define GTK_IS_SIGNAL_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SIGNAL_GROUP)) +#define GTK_TYPE_SIGNAL_GROUP (gtk_signal_group_get_type()) + +typedef struct _GtkSignalGroup GtkSignalGroup; + +GType gtk_signal_group_get_type (void) G_GNUC_CONST; +GtkSignalGroup *gtk_signal_group_new (GType target_type); +void gtk_signal_group_set_target (GtkSignalGroup *self, + gpointer target); +gpointer gtk_signal_group_dup_target (GtkSignalGroup *self); +void gtk_signal_group_block (GtkSignalGroup *self); +void gtk_signal_group_unblock (GtkSignalGroup *self); +void gtk_signal_group_connect_closure (GtkSignalGroup *self, + const gchar *detailed_signal, + GClosure *closure, + gboolean after); +void gtk_signal_group_connect_object (GtkSignalGroup *self, + const gchar *detailed_signal, + GCallback c_handler, + gpointer object, + GConnectFlags flags); +void gtk_signal_group_connect_data (GtkSignalGroup *self, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data, + GClosureNotify notify, + GConnectFlags flags); +void gtk_signal_group_connect (GtkSignalGroup *self, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data); +void gtk_signal_group_connect_after (GtkSignalGroup *self, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data); +void gtk_signal_group_connect_swapped (GtkSignalGroup *self, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data); + +G_END_DECLS + +#endif /* __GTK_SIGNAL_GROUP_H__ */ diff --git a/gtk/meson.build b/gtk/meson.build index 1bc3ab14e6..20ac76844a 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -137,6 +137,7 @@ gtk_private_sources = files([ 'gtksearchengine.c', 'gtksearchenginemodel.c', 'gtksecurememory.c', + 'gtksignalgroup.c', 'gtksizerequestcache.c', 'gtksortkeys.c', 'gtkstyleanimation.c', -- 2.43.0 From 5db21b2df160d11cc89b65f0acf6e8e5d7328413 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 29 Nov 2023 17:12:20 +0100 Subject: [PATCH 05/10] testsuite: Avoid G_TEST_SUBPROCESS_DEFAULT --- testsuite/gdk/display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testsuite/gdk/display.c b/testsuite/gdk/display.c index 16be96db63..3e285aaa75 100644 --- a/testsuite/gdk/display.c +++ b/testsuite/gdk/display.c @@ -76,7 +76,7 @@ test_debug_help (void) return; } - g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_subprocess (NULL, 0, 0); g_test_trap_assert_passed (); g_test_trap_assert_stderr ("*Supported GDK_DEBUG values:*"); g_test_trap_assert_stderr ("*Multiple values can be given, separated by : or space.*"); -- 2.43.0 From b8bb55fa2946da52d2ec233ce4e512299b240fa3 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 29 Nov 2023 17:16:05 +0100 Subject: [PATCH 06/10] demos: Do not demo unsupported pango features --- demos/gtk-demo/fontify.c | 27 --------------------------- demos/gtk-demo/tabs.c | 2 -- 2 files changed, 29 deletions(-) diff --git a/demos/gtk-demo/fontify.c b/demos/gtk-demo/fontify.c index cdbdf654d3..7d2ec6766a 100644 --- a/demos/gtk-demo/fontify.c +++ b/demos/gtk-demo/fontify.c @@ -268,29 +268,6 @@ insert_tags_for_attributes (GtkTextBuffer *buffer, INT_ATTR (insert_hyphens); break; - case PANGO_ATTR_LINE_HEIGHT: - FLOAT_ATTR (line_height); - break; - - case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT: - break; - - case PANGO_ATTR_WORD: - VOID_ATTR (word); - break; - - case PANGO_ATTR_SENTENCE: - VOID_ATTR (sentence); - break; - - case PANGO_ATTR_BASELINE_SHIFT: - INT_ATTR (baseline_shift); - break; - - case PANGO_ATTR_FONT_SCALE: - INT_ATTR (font_scale); - break; - case PANGO_ATTR_SHAPE: case PANGO_ATTR_ABSOLUTE_SIZE: case PANGO_ATTR_GRAVITY: @@ -299,10 +276,6 @@ insert_tags_for_attributes (GtkTextBuffer *buffer, case PANGO_ATTR_BACKGROUND_ALPHA: break; - case PANGO_ATTR_TEXT_TRANSFORM: - INT_ATTR (text_transform); - break; - case PANGO_ATTR_INVALID: default: g_assert_not_reached (); diff --git a/demos/gtk-demo/tabs.c b/demos/gtk-demo/tabs.c index 96c2300ac8..afba8a53a6 100644 --- a/demos/gtk-demo/tabs.c +++ b/demos/gtk-demo/tabs.c @@ -40,9 +40,7 @@ do_tabs (GtkWidget *do_widget) tabs = pango_tab_array_new (3, TRUE); pango_tab_array_set_tab (tabs, 0, PANGO_TAB_LEFT, 0); - pango_tab_array_set_tab (tabs, 1, PANGO_TAB_DECIMAL, 150); pango_tab_array_set_decimal_point (tabs, 1, '.'); - pango_tab_array_set_tab (tabs, 2, PANGO_TAB_RIGHT, 290); gtk_text_view_set_tabs (GTK_TEXT_VIEW (view), tabs); pango_tab_array_free (tabs); -- 2.43.0 From 0eea3d49ffdd673ef6d09264c76478e27b121899 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 29 Nov 2023 17:49:55 +0100 Subject: [PATCH 07/10] gtk: Avoid g_set_str() --- gtk/gtkcolumnviewrow.c | 10 ++++++++-- gtk/gtkfiledialog.c | 38 +++++++++++++++++++++++++++++--------- gtk/gtklistitem.c | 10 ++++++++-- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/gtk/gtkcolumnviewrow.c b/gtk/gtkcolumnviewrow.c index 23aac2a701..8145fbefb7 100644 --- a/gtk/gtkcolumnviewrow.c +++ b/gtk/gtkcolumnviewrow.c @@ -565,9 +565,12 @@ gtk_column_view_row_set_accessible_description (GtkColumnViewRow *self, { g_return_if_fail (GTK_IS_COLUMN_VIEW_ROW (self)); - if (!g_set_str (&self->accessible_description, description)) + if (g_strcmp0 (description, self->accessible_description) == 0) return; + g_clear_pointer (&self->accessible_description, g_free); + self->accessible_description = g_strdup (description); + if (self->owner) gtk_accessible_update_property (GTK_ACCESSIBLE (self->owner), GTK_ACCESSIBLE_PROPERTY_DESCRIPTION, self->accessible_description, @@ -610,9 +613,12 @@ gtk_column_view_row_set_accessible_label (GtkColumnViewRow *self, { g_return_if_fail (GTK_IS_COLUMN_VIEW_ROW (self)); - if (!g_set_str (&self->accessible_label, label)) + if (g_strcmp0 (self->accessible_label, label) == 0) return; + g_clear_pointer (&self->accessible_label, g_free); + self->accessible_label = g_strdup (label); + if (self->owner) gtk_accessible_update_property (GTK_ACCESSIBLE (self->owner), GTK_ACCESSIBLE_PROPERTY_LABEL, self->accessible_label, diff --git a/gtk/gtkfiledialog.c b/gtk/gtkfiledialog.c index 2b25842d15..826d254a7b 100644 --- a/gtk/gtkfiledialog.c +++ b/gtk/gtkfiledialog.c @@ -632,9 +632,12 @@ gtk_file_dialog_set_initial_name (GtkFileDialog *self, { g_return_if_fail (GTK_IS_FILE_DIALOG (self)); - if (!g_set_str (&self->initial_name, name)) + if (g_strcmp0 (self->initial_name, name) == 0) return; + g_clear_pointer (&self->initial_name, g_free); + self->initial_name = g_strdup (name); + if (self->initial_name && self->initial_folder) { g_clear_object (&self->initial_file); @@ -709,8 +712,12 @@ gtk_file_dialog_set_initial_file (GtkFileDialog *self, info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME, 0, NULL, NULL); if (info && g_file_info_get_edit_name (info) != NULL) { - if (g_set_str (&self->initial_name, g_file_info_get_edit_name (info))) - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INITIAL_NAME]); + if (g_strcmp0 (self->initial_name, g_file_info_get_edit_name (info)) != 0) + { + g_clear_pointer (&self->initial_name, g_free); + self->initial_name = g_strdup (g_file_info_get_edit_name (info)); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INITIAL_NAME]); + } } else { @@ -718,8 +725,13 @@ gtk_file_dialog_set_initial_file (GtkFileDialog *self, relative = g_file_get_relative_path (folder, file); name = g_filename_display_name (relative); - if (g_set_str (&self->initial_name, name)) - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INITIAL_NAME]); + + if (g_strcmp0 (self->initial_name, name) != 0) + { + g_clear_pointer (&self->initial_name, g_free); + self->initial_name = g_strdup (name); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INITIAL_NAME]); + } g_free (name); g_free (relative); @@ -734,8 +746,12 @@ invalid_file: g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INITIAL_FILE]); if (g_set_object (&self->initial_folder, NULL)) g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INITIAL_FOLDER]); - if (g_set_str (&self->initial_name, NULL)) - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INITIAL_NAME]); + + if (self->initial_name) + { + g_clear_pointer (&self->initial_name, g_free); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INITIAL_NAME]); + } } g_object_thaw_notify (G_OBJECT (self)); @@ -1307,8 +1323,12 @@ gtk_file_dialog_set_accept_label (GtkFileDialog *self, { g_return_if_fail (GTK_IS_FILE_DIALOG (self)); - if (g_set_str (&self->accept_label, accept_label)) - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACCEPT_LABEL]); + if (g_strcmp0 (self->accept_label, accept_label) == 0) + return; + + g_clear_pointer (&self->accept_label, g_free); + self->accept_label = g_strdup (accept_label); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACCEPT_LABEL]); } /* }}} */ diff --git a/gtk/gtklistitem.c b/gtk/gtklistitem.c index bb07c1f832..3f4c8597a2 100644 --- a/gtk/gtklistitem.c +++ b/gtk/gtklistitem.c @@ -626,9 +626,12 @@ gtk_list_item_set_accessible_description (GtkListItem *self, { g_return_if_fail (GTK_IS_LIST_ITEM (self)); - if (!g_set_str (&self->accessible_description, description)) + if (g_strcmp0 (self->accessible_description, description) == 0) return; + g_clear_pointer (&self->accessible_description, g_free); + self->accessible_description = g_strdup (description); + if (self->owner) gtk_accessible_update_property (GTK_ACCESSIBLE (self->owner), GTK_ACCESSIBLE_PROPERTY_DESCRIPTION, self->accessible_description, @@ -671,9 +674,12 @@ gtk_list_item_set_accessible_label (GtkListItem *self, { g_return_if_fail (GTK_IS_LIST_ITEM (self)); - if (!g_set_str (&self->accessible_label, label)) + if (g_strcmp0 (self->accessible_label, label) == 0) return; + g_clear_pointer (&self->accessible_label, g_free); + self->accessible_label = g_strdup (label); + if (self->owner) gtk_accessible_update_property (GTK_ACCESSIBLE (self->owner), GTK_ACCESSIBLE_PROPERTY_LABEL, self->accessible_label, -- 2.43.0 From 3c4027a438437502f057684cccaf335800011876 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 29 Nov 2023 20:44:54 +0100 Subject: [PATCH 08/10] gtk: Port back to old pango API --- demos/gtk-demo/font_features.c | 8 - demos/gtk-demo/tabs.c | 1 - gdk/gdkpango.c | 4 +- gtk/a11y/gtkatspipango.c | 28 +- gtk/gtkbuilder.c | 3 +- gtk/gtkcssstyle.c | 32 +- gtk/gtkcssstyleprivate.h | 10 + gtk/gtkfontchooserwidget.c | 36 +- gtk/gtkinscription.c | 4 +- gtk/gtklabel.c | 4 +- gtk/gtkpango.c | 675 ++++++++++++++++++++++++++++++--- gtk/gtkpangoprivate.h | 3 + gtk/gtkrenderlayout.c | 2 +- gtk/gtktextbuffer.c | 27 -- gtk/gtktextlayout.c | 87 ++--- gtk/gtktexttag.c | 7 +- gtk/gtktextutil.c | 12 +- gtk/inspector/prop-editor.c | 5 +- 18 files changed, 727 insertions(+), 221 deletions(-) diff --git a/demos/gtk-demo/font_features.c b/demos/gtk-demo/font_features.c index c4a11b41bf..b348bbb52f 100644 --- a/demos/gtk-demo/font_features.c +++ b/demos/gtk-demo/font_features.c @@ -669,14 +669,6 @@ update_display (void) pango_attr_list_insert (attrs, attr); } - if (gtk_adjustment_get_value (demo->line_height_adjustment) != 1.) - { - attr = pango_attr_line_height_new (gtk_adjustment_get_value (demo->line_height_adjustment)); - attr->start_index = start; - attr->end_index = end; - pango_attr_list_insert (attrs, attr); - } - { GdkRGBA rgba; char *fg, *bg, *css; diff --git a/demos/gtk-demo/tabs.c b/demos/gtk-demo/tabs.c index afba8a53a6..8bb123d1ed 100644 --- a/demos/gtk-demo/tabs.c +++ b/demos/gtk-demo/tabs.c @@ -40,7 +40,6 @@ do_tabs (GtkWidget *do_widget) tabs = pango_tab_array_new (3, TRUE); pango_tab_array_set_tab (tabs, 0, PANGO_TAB_LEFT, 0); - pango_tab_array_set_decimal_point (tabs, 1, '.'); gtk_text_view_set_tabs (GTK_TEXT_VIEW (view), tabs); pango_tab_array_free (tabs); diff --git a/gdk/gdkpango.c b/gdk/gdkpango.c index 3bbeac1cc2..2b53c21409 100644 --- a/gdk/gdkpango.c +++ b/gdk/gdkpango.c @@ -59,8 +59,8 @@ layout_iter_get_line_clip_region (PangoLayoutIter *iter, /* Note that get_x_ranges returns layout coordinates */ - if (index_ranges[i*2+1] >= pango_layout_line_get_start_index (line) && - index_ranges[i*2] < pango_layout_line_get_start_index (line) + pango_layout_line_get_length (line)) + if (index_ranges[i*2+1] >= line->start_index && + index_ranges[i*2] < line->start_index + line->length) pango_layout_line_get_x_ranges (line, index_ranges[i*2], index_ranges[i*2+1], diff --git a/gtk/a11y/gtkatspipango.c b/gtk/a11y/gtkatspipango.c index 2ca7bd419b..aa8f920a19 100644 --- a/gtk/a11y/gtkatspipango.c +++ b/gtk/a11y/gtkatspipango.c @@ -567,8 +567,8 @@ pango_layout_get_line_before (PangoLayout *layout, do { line = pango_layout_iter_get_line (iter); - start_index = pango_layout_line_get_start_index (line); - length = pango_layout_line_get_length (line); + start_index = line->start_index; + length = line->length; end_index = start_index + length; if (index >= start_index && index <= end_index) @@ -644,8 +644,8 @@ pango_layout_get_line_at (PangoLayout *layout, do { line = pango_layout_iter_get_line (iter); - start_index = pango_layout_line_get_start_index (line); - length = pango_layout_line_get_length (line); + start_index = line->start_index; + length = line->length; end_index = start_index + length; if (index >= start_index && index <= end_index) @@ -655,11 +655,11 @@ pango_layout_get_line_at (PangoLayout *layout, { case ATSPI_TEXT_BOUNDARY_LINE_START: if (pango_layout_iter_next_line (iter)) - end_index = pango_layout_line_get_start_index (pango_layout_iter_get_line (iter)); + end_index = pango_layout_iter_get_line (iter)->start_index; break; case ATSPI_TEXT_BOUNDARY_LINE_END: if (prev_line) - start_index = pango_layout_line_get_start_index (prev_line) + pango_layout_line_get_length (prev_line); + start_index = prev_line->start_index + prev_line->length; break; case ATSPI_TEXT_BOUNDARY_CHAR: case ATSPI_TEXT_BOUNDARY_WORD_START: @@ -680,7 +680,7 @@ pango_layout_get_line_at (PangoLayout *layout, if (!found) { - start_index = pango_layout_line_get_start_index (prev_line) + pango_layout_line_get_length (prev_line); + start_index = prev_line->start_index + prev_line->length; end_index = start_index; } pango_layout_iter_free (iter); @@ -708,8 +708,8 @@ pango_layout_get_line_after (PangoLayout *layout, do { line = pango_layout_iter_get_line (iter); - start_index = pango_layout_line_get_start_index (line); - length = pango_layout_line_get_length (line); + start_index = line->start_index; + length = line->length; end_index = start_index + length; if (index >= start_index && index <= end_index) @@ -721,15 +721,15 @@ pango_layout_get_line_after (PangoLayout *layout, switch (boundary_type) { case ATSPI_TEXT_BOUNDARY_LINE_START: - start_index = pango_layout_line_get_start_index (line); + start_index = line->start_index; if (pango_layout_iter_next_line (iter)) - end_index = pango_layout_line_get_start_index (pango_layout_iter_get_line (iter)); + end_index = pango_layout_iter_get_line (iter)->start_index; else - end_index = start_index + pango_layout_line_get_length (line); + end_index = start_index + line->length;; break; case ATSPI_TEXT_BOUNDARY_LINE_END: start_index = end_index; - end_index = pango_layout_line_get_start_index (line) + pango_layout_line_get_length (line); + end_index = line->start_index + line->length; break; case ATSPI_TEXT_BOUNDARY_CHAR: case ATSPI_TEXT_BOUNDARY_WORD_START: @@ -753,7 +753,7 @@ pango_layout_get_line_after (PangoLayout *layout, if (!found) { - start_index = pango_layout_line_get_start_index (prev_line) + pango_layout_line_get_length (prev_line); + start_index = prev_line->start_index + prev_line->length; end_index = start_index; } pango_layout_iter_free (iter); diff --git a/gtk/gtkbuilder.c b/gtk/gtkbuilder.c index ebc19445bc..a4741963aa 100644 --- a/gtk/gtkbuilder.c +++ b/gtk/gtkbuilder.c @@ -325,6 +325,7 @@ #include "gtkdebug.h" #include "gtkexpression.h" #include "gtkmain.h" +#include "gtkpangoprivate.h" #include "gtkprivate.h" #include "gtkshortcutactionprivate.h" #include "gtkshortcuttrigger.h" @@ -2457,7 +2458,7 @@ gtk_builder_value_from_string_type (GtkBuilder *builder, { PangoAttrList *attrs; - attrs = pango_attr_list_from_string (string); + attrs = gtk_pango_attr_list_from_string (string); if (attrs) g_value_take_boxed (value, attrs); else diff --git a/gtk/gtkcssstyle.c b/gtk/gtkcssstyle.c index 0822e80a46..b9b6c30176 100644 --- a/gtk/gtkcssstyle.c +++ b/gtk/gtkcssstyle.c @@ -638,39 +638,17 @@ gtk_css_style_get_pango_attributes (GtkCssStyle *style) attrs = add_pango_attr (attrs, pango_attr_letter_spacing_new (letter_spacing * PANGO_SCALE)); } - /* line-height */ - { - double height = gtk_css_line_height_value_get (style->font->line_height); - if (height != 0.0) - { - if (gtk_css_number_value_get_dimension (style->font->line_height) == GTK_CSS_DIMENSION_LENGTH) - attrs = add_pango_attr (attrs, pango_attr_line_height_new_absolute (height * PANGO_SCALE)); - else - attrs = add_pango_attr (attrs, pango_attr_line_height_new (height)); - } - } - /* casing variants */ switch (_gtk_css_font_variant_caps_value_get (style->font_variant->font_variant_caps)) { case GTK_CSS_FONT_VARIANT_CAPS_SMALL_CAPS: - attrs = add_pango_attr (attrs, pango_attr_variant_new (PANGO_VARIANT_SMALL_CAPS)); - break; case GTK_CSS_FONT_VARIANT_CAPS_ALL_SMALL_CAPS: - attrs = add_pango_attr (attrs, pango_attr_variant_new (PANGO_VARIANT_ALL_SMALL_CAPS)); - break; case GTK_CSS_FONT_VARIANT_CAPS_PETITE_CAPS: - attrs = add_pango_attr (attrs, pango_attr_variant_new (PANGO_VARIANT_PETITE_CAPS)); - break; case GTK_CSS_FONT_VARIANT_CAPS_ALL_PETITE_CAPS: - attrs = add_pango_attr (attrs, pango_attr_variant_new (PANGO_VARIANT_ALL_PETITE_CAPS)); + attrs = add_pango_attr (attrs, pango_attr_variant_new (PANGO_VARIANT_SMALL_CAPS)); break; case GTK_CSS_FONT_VARIANT_CAPS_UNICASE: - attrs = add_pango_attr (attrs, pango_attr_variant_new (PANGO_VARIANT_UNICASE)); - break; case GTK_CSS_FONT_VARIANT_CAPS_TITLING_CAPS: - attrs = add_pango_attr (attrs, pango_attr_variant_new (PANGO_VARIANT_TITLE_CAPS)); - break; case GTK_CSS_FONT_VARIANT_CAPS_NORMAL: default: break; @@ -687,14 +665,6 @@ gtk_css_style_get_pango_attributes (GtkCssStyle *style) } } - /* text-transform */ - { - PangoTextTransform transform = gtk_css_style_get_pango_text_transform (style); - - if (transform != PANGO_TEXT_TRANSFORM_NONE) - attrs = add_pango_attr (attrs, pango_attr_text_transform_new (transform)); - } - return attrs; } diff --git a/gtk/gtkcssstyleprivate.h b/gtk/gtkcssstyleprivate.h index 82531a6ffe..94aa973741 100644 --- a/gtk/gtkcssstyleprivate.h +++ b/gtk/gtkcssstyleprivate.h @@ -59,6 +59,16 @@ typedef enum { GTK_CSS_OTHER_INITIAL_VALUES, } GtkCssValuesType; +#if !PANGO_VERSION_CHECK(1,50, 0) +typedef enum +{ + PANGO_TEXT_TRANSFORM_NONE, + PANGO_TEXT_TRANSFORM_LOWERCASE, + PANGO_TEXT_TRANSFORM_UPPERCASE, + PANGO_TEXT_TRANSFORM_CAPITALIZE, +} PangoTextTransform; +#endif + typedef struct _GtkCssValues GtkCssValues; typedef struct _GtkCssCoreValues GtkCssCoreValues; typedef struct _GtkCssBackgroundValues GtkCssBackgroundValues; diff --git a/gtk/gtkfontchooserwidget.c b/gtk/gtkfontchooserwidget.c index 598466d027..6a78260d8b 100644 --- a/gtk/gtkfontchooserwidget.c +++ b/gtk/gtkfontchooserwidget.c @@ -67,6 +67,10 @@ #include +#if defined(HAVE_PANGOFT) && defined(HAVE_HARFBUZZ) +#include +#endif + #include "language-names.h" #include "open-type-layout.h" @@ -377,7 +381,7 @@ user_filter_cb (gpointer item, PangoFontDescription *desc; PangoContext *context; PangoFont *font; - gboolean ret; + gboolean ret = TRUE; PangoLanguage **langs; desc = pango_font_face_describe (face); @@ -386,17 +390,21 @@ user_filter_cb (gpointer item, context = gtk_widget_get_pango_context (GTK_WIDGET (self)); font = pango_context_load_font (context, desc); - ret = FALSE; - - langs = pango_font_get_languages (font); - if (langs) + if (PANGO_IS_FC_FONT (font)) { - for (int i = 0; langs[i]; i++) + ret = FALSE; + + langs = pango_fc_font_get_languages (PANGO_FC_FONT (font)); + + if (langs) { - if (langs[i] == self->filter_language) + for (int i = 0; langs[i]; i++) { - ret = TRUE; - break; + if (langs[i] == self->filter_language) + { + ret = TRUE; + break; + } } } } @@ -552,7 +560,7 @@ maybe_update_preview_text (GtkFontChooserWidget *self, PangoContext *context; PangoFont *font; const char *sample; - PangoLanguage **languages; + PangoLanguage **languages = NULL; GHashTable *langs = NULL; PangoLanguage *default_lang; PangoLanguage *alt_default = NULL; @@ -599,7 +607,8 @@ maybe_update_preview_text (GtkFontChooserWidget *self, alt_default = pango_language_from_string (q); } - languages = pango_font_get_languages (font); + if (PANGO_IS_FC_FONT (font)) + languages = pango_fc_font_get_languages (PANGO_FC_FONT (font)); /* If the font supports the default language, just use it. */ if (languages) @@ -1047,7 +1056,7 @@ add_languages_from_font (GtkFontChooserWidget *self, PangoContext *context; GtkSelectionModel *model = gtk_list_view_get_model (GTK_LIST_VIEW (self->language_list)); PangoLanguage *default_lang = pango_language_get_default (); - PangoLanguage **langs; + PangoLanguage **langs = NULL; int i; if (PANGO_IS_FONT_FAMILY (item)) @@ -1064,7 +1073,8 @@ add_languages_from_font (GtkFontChooserWidget *self, context = gtk_widget_get_pango_context (GTK_WIDGET (self)); font = pango_context_load_font (context, desc); - langs = pango_font_get_languages (font); + if (PANGO_IS_FC_FONT (font)) + langs = pango_fc_font_get_languages (PANGO_FC_FONT (font)); if (langs) { for (i = 0; langs[i]; i++) diff --git a/gtk/gtkinscription.c b/gtk/gtkinscription.c index 25e41c3103..ea2110f2e2 100644 --- a/gtk/gtkinscription.c +++ b/gtk/gtkinscription.c @@ -480,12 +480,12 @@ gtk_inscription_allocate (GtkWidget *widget, pango_layout_iter_get_line_extents (iter, NULL, &rect); if (rect.y + rect.height > height * PANGO_SCALE) { - while (!pango_layout_line_is_paragraph_start (pango_layout_iter_get_line_readonly (iter))) + while (!pango_layout_iter_get_line_readonly (iter)->is_paragraph_start) { if (!pango_layout_iter_next_line (iter)) break; } - if (!pango_layout_line_is_paragraph_start (pango_layout_iter_get_line_readonly (iter))) + if (!pango_layout_iter_get_line_readonly (iter)->is_paragraph_start) { pango_layout_set_width (self->layout, -1); } diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c index 8d59efe0c1..2502d72adb 100644 --- a/gtk/gtklabel.c +++ b/gtk/gtklabel.c @@ -911,8 +911,8 @@ get_cursor_direction (GtkLabel *self) * definitely in this paragraph, which is good enough * to figure out the resolved direction. */ - if (pango_layout_line_get_start_index (line) + pango_layout_line_get_length (line) >= self->select_info->selection_end) - return pango_layout_line_get_resolved_direction (line); + if (line->start_index + line->length >= self->select_info->selection_end) + return line->resolved_dir; } return PANGO_DIRECTION_LTR; diff --git a/gtk/gtkpango.c b/gtk/gtkpango.c index 68a80e5c46..69d96b43a1 100644 --- a/gtk/gtkpango.c +++ b/gtk/gtkpango.c @@ -248,39 +248,6 @@ attribute_from_text (GtkBuilder *builder, color->blue * 65535); } break; - case PANGO_ATTR_LINE_HEIGHT: - if (gtk_builder_value_from_string_type (builder, G_TYPE_DOUBLE, value, &val, error)) - attribute = pango_attr_line_height_new (g_value_get_double (&val)); - break; - case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT: - if (gtk_builder_value_from_string_type (builder, G_TYPE_INT, value, &val, error)) - attribute = pango_attr_line_height_new_absolute (g_value_get_int (&val) * PANGO_SCALE); - break; - case PANGO_ATTR_TEXT_TRANSFORM: - if (gtk_builder_value_from_string_type (builder, PANGO_TYPE_TEXT_TRANSFORM, value, &val, error)) - attribute = pango_attr_text_transform_new (g_value_get_enum (&val)); - break; - case PANGO_ATTR_WORD: - attribute = pango_attr_word_new (); - break; - case PANGO_ATTR_SENTENCE: - attribute = pango_attr_sentence_new (); - break; - case PANGO_ATTR_BASELINE_SHIFT: - if (gtk_builder_value_from_string_type (builder, PANGO_TYPE_BASELINE_SHIFT, value, &val, NULL)) - attribute = pango_attr_baseline_shift_new (g_value_get_enum (&val)); - else if (gtk_builder_value_from_string_type (builder, G_TYPE_INT, value, &val, NULL)) - attribute = pango_attr_baseline_shift_new (g_value_get_enum (&val)); - else - g_set_error (error, - GTK_BUILDER_ERROR, - GTK_BUILDER_ERROR_INVALID_VALUE, - "Could not parse '%s' as baseline shift value", value); - break; - case PANGO_ATTR_FONT_SCALE: - if (gtk_builder_value_from_string_type (builder, PANGO_TYPE_FONT_SCALE, value, &val, error)) - attribute = pango_attr_font_scale_new (g_value_get_enum (&val)); - break; case PANGO_ATTR_INVALID: default: break; @@ -406,18 +373,8 @@ pango_variant_to_string (PangoVariant variant) return "normal"; case PANGO_VARIANT_SMALL_CAPS: return "small_caps"; - case PANGO_VARIANT_ALL_SMALL_CAPS: - return "all_small_caps"; - case PANGO_VARIANT_PETITE_CAPS: - return "petite_caps"; - case PANGO_VARIANT_ALL_PETITE_CAPS: - return "all_petite_caps"; - case PANGO_VARIANT_UNICASE: - return "unicase"; - case PANGO_VARIANT_TITLE_CAPS: - return "title_caps"; default: - g_assert_not_reached (); + return "unknown"; } } @@ -504,3 +461,633 @@ pango_align_to_string (PangoAlignment align) g_assert_not_reached (); } } + +static const char * +get_attr_type_nick (PangoAttrType attr_type) +{ + GEnumClass *enum_class; + GEnumValue *enum_value; + + enum_class = g_type_class_ref (pango_attr_type_get_type ()); + enum_value = g_enum_get_value (enum_class, attr_type); + g_type_class_unref (enum_class); + + return enum_value->value_nick; +} + +static GType +get_attr_value_type (PangoAttrType type) +{ + switch ((int)type) + { + case PANGO_ATTR_STYLE: return PANGO_TYPE_STYLE; + case PANGO_ATTR_WEIGHT: return PANGO_TYPE_WEIGHT; + case PANGO_ATTR_VARIANT: return PANGO_TYPE_VARIANT; + case PANGO_ATTR_STRETCH: return PANGO_TYPE_STRETCH; + case PANGO_ATTR_GRAVITY: return PANGO_TYPE_GRAVITY; + case PANGO_ATTR_GRAVITY_HINT: return PANGO_TYPE_GRAVITY_HINT; + case PANGO_ATTR_UNDERLINE: return PANGO_TYPE_UNDERLINE; + case PANGO_ATTR_OVERLINE: return PANGO_TYPE_OVERLINE; + default: return G_TYPE_INVALID; + } +} + +static void +append_enum_value (GString *str, + GType type, + int value) +{ + GEnumClass *enum_class; + GEnumValue *enum_value; + + enum_class = g_type_class_ref (type); + enum_value = g_enum_get_value (enum_class, value); + g_type_class_unref (enum_class); + + if (enum_value) + g_string_append_printf (str, " %s", enum_value->value_nick); + else + g_string_append_printf (str, " %d", value); +} + +static PangoAttrInt * +pango_attribute_as_int (PangoAttribute *attr) +{ + switch ((int)attr->klass->type) + { + case PANGO_ATTR_STYLE: + case PANGO_ATTR_WEIGHT: + case PANGO_ATTR_VARIANT: + case PANGO_ATTR_STRETCH: + case PANGO_ATTR_UNDERLINE: + case PANGO_ATTR_STRIKETHROUGH: + case PANGO_ATTR_RISE: + case PANGO_ATTR_FALLBACK: + case PANGO_ATTR_LETTER_SPACING: + case PANGO_ATTR_GRAVITY: + case PANGO_ATTR_GRAVITY_HINT: + case PANGO_ATTR_FOREGROUND_ALPHA: + case PANGO_ATTR_BACKGROUND_ALPHA: + case PANGO_ATTR_ALLOW_BREAKS: + case PANGO_ATTR_SHOW: + case PANGO_ATTR_INSERT_HYPHENS: + case PANGO_ATTR_OVERLINE: + return (PangoAttrInt *)attr; + + default: + return NULL; + } +} + +static PangoAttrFloat * +pango_attribute_as_float (PangoAttribute *attr) +{ + switch ((int)attr->klass->type) + { + case PANGO_ATTR_SCALE: + return (PangoAttrFloat *)attr; + + default: + return NULL; + } +} + +static PangoAttrString * +pango_attribute_as_string (PangoAttribute *attr) +{ + switch ((int)attr->klass->type) + { + case PANGO_ATTR_FAMILY: + return (PangoAttrString *)attr; + + default: + return NULL; + } +} + +static PangoAttrSize * +pango_attribute_as_size (PangoAttribute *attr) +{ + switch ((int)attr->klass->type) + { + case PANGO_ATTR_SIZE: + case PANGO_ATTR_ABSOLUTE_SIZE: + return (PangoAttrSize *)attr; + + default: + return NULL; + } +} + +static PangoAttrColor * +pango_attribute_as_color (PangoAttribute *attr) +{ + switch ((int)attr->klass->type) + { + case PANGO_ATTR_FOREGROUND: + case PANGO_ATTR_BACKGROUND: + case PANGO_ATTR_UNDERLINE_COLOR: + case PANGO_ATTR_STRIKETHROUGH_COLOR: + case PANGO_ATTR_OVERLINE_COLOR: + return (PangoAttrColor *)attr; + + default: + return NULL; + } +} + +static PangoAttrFontDesc * +pango_attribute_as_font_desc (PangoAttribute *attr) +{ + switch ((int)attr->klass->type) + { + case PANGO_ATTR_FONT_DESC: + return (PangoAttrFontDesc *)attr; + + default: + return NULL; + } +} + +static PangoAttrFontFeatures * +pango_attribute_as_font_features (PangoAttribute *attr) +{ + switch ((int)attr->klass->type) + { + case PANGO_ATTR_FONT_FEATURES: + return (PangoAttrFontFeatures *)attr; + + default: + return NULL; + } +} + +static PangoAttrLanguage * +pango_attribute_as_language (PangoAttribute *attr) +{ + switch ((int)attr->klass->type) + { + case PANGO_ATTR_LANGUAGE: + return (PangoAttrLanguage *)attr; + + default: + return NULL; + } +} + +static PangoAttrShape * +pango_attribute_as_shape (PangoAttribute *attr) +{ + switch ((int)attr->klass->type) + { + case PANGO_ATTR_SHAPE: + return (PangoAttrShape *)attr; + + default: + return NULL; + } +} + +static void +attr_print (GString *str, + PangoAttribute *attr) +{ + PangoAttrString *string; + PangoAttrLanguage *lang; + PangoAttrInt *integer; + PangoAttrFloat *flt; + PangoAttrFontDesc *font; + PangoAttrColor *color; + PangoAttrShape *shape; + PangoAttrSize *size; + PangoAttrFontFeatures *features; + + g_string_append_printf (str, "%u %u ", attr->start_index, attr->end_index); + + g_string_append (str, get_attr_type_nick (attr->klass->type)); + + if (attr->klass->type == PANGO_ATTR_WEIGHT || + attr->klass->type == PANGO_ATTR_STYLE || + attr->klass->type == PANGO_ATTR_STRETCH || + attr->klass->type == PANGO_ATTR_VARIANT || + attr->klass->type == PANGO_ATTR_GRAVITY || + attr->klass->type == PANGO_ATTR_GRAVITY_HINT || + attr->klass->type == PANGO_ATTR_UNDERLINE || + attr->klass->type == PANGO_ATTR_OVERLINE) + append_enum_value (str, get_attr_value_type (attr->klass->type), ((PangoAttrInt *)attr)->value); + else if (attr->klass->type == PANGO_ATTR_STRIKETHROUGH || + attr->klass->type == PANGO_ATTR_ALLOW_BREAKS || + attr->klass->type == PANGO_ATTR_INSERT_HYPHENS || + attr->klass->type == PANGO_ATTR_FALLBACK) + g_string_append (str, ((PangoAttrInt *)attr)->value ? " true" : " false"); + else if ((string = pango_attribute_as_string (attr)) != NULL) + { + char *s = g_strescape (string->value, NULL); + g_string_append_printf (str, " \"%s\"", s); + g_free (s); + } + else if ((lang = pango_attribute_as_language (attr)) != NULL) + g_string_append_printf (str, " %s", pango_language_to_string (lang->value)); + else if ((integer = pango_attribute_as_int (attr)) != NULL) + g_string_append_printf (str, " %d", integer->value); + else if ((flt = pango_attribute_as_float (attr)) != NULL) + { + char buf[20]; + g_ascii_formatd (buf, 20, "%f", flt->value); + g_string_append_printf (str, " %s", buf); + } + else if ((font = pango_attribute_as_font_desc (attr)) != NULL) + { + char *s = pango_font_description_to_string (font->desc); + char *s2 = g_strescape (s, NULL); + g_string_append_printf (str, " \"%s\"", s2); + g_free (s2); + g_free (s); + } + else if ((color = pango_attribute_as_color (attr)) != NULL) + { + char *s = pango_color_to_string (&color->color); + g_string_append_printf (str, " %s", s); + g_free (s); + } + else if ((shape = pango_attribute_as_shape (attr)) != NULL) + g_string_append (str, "shape"); /* FIXME */ + else if ((size = pango_attribute_as_size (attr)) != NULL) + g_string_append_printf (str, " %d", size->size); + else if ((features = pango_attribute_as_font_features (attr)) != NULL) + g_string_append_printf (str, " \"%s\"", features->features); + else + g_assert_not_reached (); +} + +char * +gtk_pango_attr_list_to_string (PangoAttrList *list) +{ + GSList *attrs; + GString *s; + + s = g_string_new (""); + + attrs = pango_attr_list_get_attributes (list); + + if (attrs) + { + for (GSList *l = attrs; l; l = l->next) + { + PangoAttribute *attr = l->data; + + if (l != attrs) + g_string_append (s, "\n"); + attr_print (s, attr); + } + + g_slist_free_full (attrs, (GDestroyNotify) pango_attribute_destroy); + } + + return g_string_free (s, FALSE); +} + +static PangoAttrType +get_attr_type_by_nick (const char *nick, + int len) +{ + GEnumClass *enum_class; + + enum_class = g_type_class_ref (pango_attr_type_get_type ()); + for (GEnumValue *ev = enum_class->values; ev->value_name; ev++) + { + if (ev->value_nick && strncmp (ev->value_nick, nick, len) == 0) + { + g_type_class_unref (enum_class); + return (PangoAttrType) ev->value; + } + } + + g_type_class_unref (enum_class); + return PANGO_ATTR_INVALID; +} + +static int +get_attr_value (PangoAttrType type, + const char *str, + int len) +{ + GEnumClass *enum_class; + char *endp; + int value; + + enum_class = g_type_class_ref (get_attr_value_type (type)); + for (GEnumValue *ev = enum_class->values; ev->value_name; ev++) + { + if (ev->value_nick && strncmp (ev->value_nick, str, len) == 0) + { + g_type_class_unref (enum_class); + return ev->value; + } + } + g_type_class_unref (enum_class); + + value = g_ascii_strtoll (str, &endp, 10); + if (endp - str == len) + return value; + + return -1; +} + +static gboolean +is_valid_end_char (char c) +{ + return c == ',' || c == '\n' || c == '\0'; +} + +PangoAttrList * +gtk_pango_attr_list_from_string (const char *text) +{ + PangoAttrList *list; + const char *p; + + g_return_val_if_fail (text != NULL, NULL); + + list = pango_attr_list_new (); + + if (*text == '\0') + return list; + + p = text + strspn (text, " \t\n"); + while (*p) + { + char *endp; + gint64 start_index; + gint64 end_index; + char *str; + PangoAttrType attr_type; + PangoAttribute *attr; + PangoLanguage *lang; + gint64 integer; + PangoFontDescription *desc; + PangoColor color; + double num; + int len; + + start_index = g_ascii_strtoll (p, &endp, 10); + if (*endp != ' ') + goto fail; + + p = endp + strspn (endp, " "); + if (!*p) + goto fail; + + end_index = g_ascii_strtoll (p, &endp, 10); + if (*endp != ' ') + goto fail; + + p = endp + strspn (endp, " "); + + endp = (char *)p + strcspn (p, " "); + attr_type = get_attr_type_by_nick (p, endp - p); + + p = endp + strspn (endp, " "); + if (*p == '\0') + goto fail; + +#define INT_ATTR(name,type) \ + integer = g_ascii_strtoll (p, &endp, 10); \ + if (!is_valid_end_char (*endp)) goto fail; \ + attr = pango_attr_##name##_new ((type)integer); + +#define BOOLEAN_ATTR(name,type) \ + if (strncmp (p, "true", strlen ("true")) == 0) \ + { \ + integer = 1; \ + endp = (char *)(p + strlen ("true")); \ + } \ + else if (strncmp (p, "false", strlen ("false")) == 0) \ + { \ + integer = 0; \ + endp = (char *)(p + strlen ("false")); \ + } \ + else \ + integer = g_ascii_strtoll (p, &endp, 10); \ + if (!is_valid_end_char (*endp)) goto fail; \ + attr = pango_attr_##name##_new ((type)integer); + +#define ENUM_ATTR(name, type, min, max) \ + endp = (char *)p + strcspn (p, ",\n"); \ + len = endp - p; \ + while (len > 0 && p[len - 1] == ' ') \ + len--; \ + integer = get_attr_value (attr_type, p, len); \ + attr = pango_attr_##name##_new ((type) CLAMP (integer, min, max)); + +#define FLOAT_ATTR(name) \ + num = g_ascii_strtod (p, &endp); \ + if (!is_valid_end_char (*endp)) goto fail; \ + attr = pango_attr_##name##_new ((float)num); + +#define COLOR_ATTR(name) \ + endp = (char *)p + strcspn (p, ",\n"); \ + if (!is_valid_end_char (*endp)) goto fail; \ + str = g_strndup (p, endp - p); \ + if (!pango_color_parse (&color, str)) \ + { \ + g_free (str); \ + goto fail; \ + } \ + attr = pango_attr_##name##_new (color.red, color.green, color.blue); \ + g_free (str); + + switch (attr_type) + { + case PANGO_ATTR_INVALID: + pango_attr_list_unref (list); + return NULL; + + case PANGO_ATTR_LANGUAGE: + endp = (char *)p + strcspn (p, ",\n"); + if (!is_valid_end_char (*endp)) goto fail; + str = g_strndup (p, endp - p); + lang = pango_language_from_string (str); + attr = pango_attr_language_new (lang); + g_free (str); + break; + + case PANGO_ATTR_FAMILY: + endp = (char *)p + strcspn (p, ",\n"); + if (!is_valid_end_char (*endp)) goto fail; + if (p[0] == '"') + { + char *str2; + + len = endp - p; + while (len > 0 && p[len - 1] == ' ') + len--; + + if (p[len - 1] != '"') goto fail; + + str2 = g_strndup (p + 1, len - 2); + str = g_strcompress (str2); + g_free (str2); + } + else + str = g_strndup (p, endp - p); + attr = pango_attr_family_new (str); + g_free (str); + break; + + case PANGO_ATTR_STYLE: + ENUM_ATTR(style, PangoStyle, PANGO_STYLE_NORMAL, PANGO_STYLE_ITALIC); + break; + + case PANGO_ATTR_WEIGHT: + ENUM_ATTR(weight, PangoWeight, PANGO_WEIGHT_THIN, PANGO_WEIGHT_ULTRAHEAVY); + break; + + case PANGO_ATTR_VARIANT: + ENUM_ATTR(variant, PangoVariant, PANGO_VARIANT_NORMAL, PANGO_VARIANT_SMALL_CAPS); + break; + + case PANGO_ATTR_STRETCH: + ENUM_ATTR(stretch, PangoStretch, PANGO_STRETCH_ULTRA_CONDENSED, PANGO_STRETCH_ULTRA_EXPANDED); + break; + + case PANGO_ATTR_SIZE: + INT_ATTR(size, int); + break; + + case PANGO_ATTR_FONT_DESC: + if (*p != '"') goto fail; + p++; + endp = strchr (p, '"'); + if (!endp) goto fail; + str = g_strndup (p, endp - p); + desc = pango_font_description_from_string (str); + attr = pango_attr_font_desc_new (desc); + pango_font_description_free (desc); + g_free (str); + endp++; + if (!is_valid_end_char (*endp)) goto fail; + break; + + case PANGO_ATTR_FOREGROUND: + COLOR_ATTR(foreground); + break; + + case PANGO_ATTR_BACKGROUND: + COLOR_ATTR(background); + break; + + case PANGO_ATTR_UNDERLINE: + ENUM_ATTR(underline, PangoUnderline, PANGO_UNDERLINE_NONE, PANGO_UNDERLINE_ERROR_LINE); + break; + + case PANGO_ATTR_STRIKETHROUGH: + BOOLEAN_ATTR(strikethrough, gboolean); + break; + + case PANGO_ATTR_RISE: + INT_ATTR(rise, int); + break; + + case PANGO_ATTR_SHAPE: + endp = (char *)p + strcspn (p, ",\n"); + continue; /* FIXME */ + + case PANGO_ATTR_SCALE: + FLOAT_ATTR(scale); + break; + + case PANGO_ATTR_FALLBACK: + BOOLEAN_ATTR(fallback, gboolean); + break; + + case PANGO_ATTR_LETTER_SPACING: + INT_ATTR(letter_spacing, int); + break; + + case PANGO_ATTR_UNDERLINE_COLOR: + COLOR_ATTR(underline_color); + break; + + case PANGO_ATTR_STRIKETHROUGH_COLOR: + COLOR_ATTR(strikethrough_color); + break; + + case PANGO_ATTR_ABSOLUTE_SIZE: + integer = g_ascii_strtoll (p, &endp, 10); + if (!is_valid_end_char (*endp)) goto fail; + attr = pango_attr_size_new_absolute (integer); + break; + + case PANGO_ATTR_GRAVITY: + ENUM_ATTR(gravity, PangoGravity, PANGO_GRAVITY_SOUTH, PANGO_GRAVITY_WEST); + break; + + case PANGO_ATTR_FONT_FEATURES: + p++; + endp = strchr (p, '"'); + if (!endp) goto fail; + str = g_strndup (p, endp - p); + attr = pango_attr_font_features_new (str); + g_free (str); + endp++; + if (!is_valid_end_char (*endp)) goto fail; + break; + + case PANGO_ATTR_GRAVITY_HINT: + ENUM_ATTR(gravity_hint, PangoGravityHint, PANGO_GRAVITY_HINT_NATURAL, PANGO_GRAVITY_HINT_LINE); + break; + + case PANGO_ATTR_FOREGROUND_ALPHA: + INT_ATTR(foreground_alpha, int); + break; + + case PANGO_ATTR_BACKGROUND_ALPHA: + INT_ATTR(background_alpha, int); + break; + + case PANGO_ATTR_ALLOW_BREAKS: + BOOLEAN_ATTR(allow_breaks, gboolean); + break; + + case PANGO_ATTR_SHOW: + INT_ATTR(show, PangoShowFlags); + break; + + case PANGO_ATTR_INSERT_HYPHENS: + BOOLEAN_ATTR(insert_hyphens, gboolean); + break; + + case PANGO_ATTR_OVERLINE: + ENUM_ATTR(overline, PangoOverline, PANGO_OVERLINE_NONE, PANGO_OVERLINE_SINGLE); + break; + + case PANGO_ATTR_OVERLINE_COLOR: + COLOR_ATTR(overline_color); + break; + + default: + g_assert_not_reached (); + } + + attr->start_index = (guint)start_index; + attr->end_index = (guint)end_index; + pango_attr_list_insert (list, attr); + + p = endp; + if (*p) + { + if (*p == ',') + p++; + p += strspn (p, " \n"); + } + } + + goto success; + +fail: + pango_attr_list_unref (list); + list = NULL; + +success: + return list; +} diff --git a/gtk/gtkpangoprivate.h b/gtk/gtkpangoprivate.h index b03e281582..a5528db823 100644 --- a/gtk/gtkpangoprivate.h +++ b/gtk/gtkpangoprivate.h @@ -60,5 +60,8 @@ const char *pango_style_to_string (PangoStyle style); const char *pango_variant_to_string (PangoVariant variant); const char *pango_align_to_string (PangoAlignment align); +PangoAttrList * gtk_pango_attr_list_from_string (const char *text); +char * gtk_pango_attr_list_to_string (PangoAttrList *list); + G_END_DECLS diff --git a/gtk/gtkrenderlayout.c b/gtk/gtkrenderlayout.c index 454ca2fc78..3484696774 100644 --- a/gtk/gtkrenderlayout.c +++ b/gtk/gtkrenderlayout.c @@ -258,7 +258,7 @@ gtk_css_style_snapshot_caret (GtkCssBoxes *boxes, keyboard_direction = gdk_device_get_direction (keyboard); } - pango_layout_get_caret_pos (layout, index, &strong_pos, &weak_pos); + pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos); direction2 = PANGO_DIRECTION_NEUTRAL; diff --git a/gtk/gtktextbuffer.c b/gtk/gtktextbuffer.c index 09bb01c7d5..430df12ae1 100644 --- a/gtk/gtktextbuffer.c +++ b/gtk/gtktextbuffer.c @@ -4695,13 +4695,6 @@ insert_tags_for_attributes (GtkTextBuffer *buffer, INT_ATTR (letter_spacing); break; - case PANGO_ATTR_LINE_HEIGHT: - FLOAT_ATTR (line_height); - break; - - case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT: - break; - case PANGO_ATTR_FONT_FEATURES: STRING_ATTR (font_features); break; @@ -4718,26 +4711,6 @@ insert_tags_for_attributes (GtkTextBuffer *buffer, INT_ATTR (insert_hyphens); break; - case PANGO_ATTR_TEXT_TRANSFORM: - INT_ATTR (text_transform); - break; - - case PANGO_ATTR_WORD: - VOID_ATTR (word); - break; - - case PANGO_ATTR_SENTENCE: - VOID_ATTR (sentence); - break; - - case PANGO_ATTR_BASELINE_SHIFT: - INT_ATTR (baseline_shift); - break; - - case PANGO_ATTR_FONT_SCALE: - INT_ATTR (font_scale); - break; - case PANGO_ATTR_SHAPE: case PANGO_ATTR_ABSOLUTE_SIZE: case PANGO_ATTR_GRAVITY: diff --git a/gtk/gtktextlayout.c b/gtk/gtktextlayout.c index 10e9562c48..b68e6b2e54 100644 --- a/gtk/gtktextlayout.c +++ b/gtk/gtktextlayout.c @@ -1629,18 +1629,6 @@ add_text_attrs (GtkTextLayout *layout, pango_attr_list_insert (attrs, attr); } - if (style->line_height != 0.0) - { - if (style->line_height_is_absolute) - attr = pango_attr_line_height_new_absolute (style->line_height * PANGO_SCALE); - else - attr = pango_attr_line_height_new (style->line_height); - attr->start_index = start; - attr->end_index = start + byte_count; - - pango_attr_list_insert (attrs, attr); - } - if (style->font_features) { attr = pango_attr_font_features_new (style->font_features); @@ -1674,33 +1662,6 @@ add_text_attrs (GtkTextLayout *layout, attr->start_index = start; attr->end_index = start + byte_count; - pango_attr_list_insert (attrs, attr); - } - - if (style->text_transform != PANGO_TEXT_TRANSFORM_NONE) - { - attr = pango_attr_text_transform_new (style->text_transform); - attr->start_index = start; - attr->end_index = start + byte_count; - - pango_attr_list_insert (attrs, attr); - } - - if (style->word) - { - attr = pango_attr_word_new (); - attr->start_index = start; - attr->end_index = start + byte_count; - - pango_attr_list_insert (attrs, attr); - } - - if (style->sentence) - { - attr = pango_attr_sentence_new (); - attr->start_index = start; - attr->end_index = start + byte_count; - pango_attr_list_insert (attrs, attr); } } @@ -3087,7 +3048,7 @@ find_display_line_below (GtkTextLayout *layout, int first_y, last_y; PangoLayoutLine *layout_line = pango_layout_iter_get_line_readonly (layout_iter); - found_byte = pango_layout_line_get_start_index (layout_line); + found_byte = layout_line->start_index; if (line_top >= y) { @@ -3159,7 +3120,7 @@ find_display_line_above (GtkTextLayout *layout, int first_y, last_y; PangoLayoutLine *layout_line = pango_layout_iter_get_line_readonly (layout_iter); - found_byte = pango_layout_line_get_start_index (layout_line); + found_byte = layout_line->start_index; pango_layout_iter_get_line_yrange (layout_iter, &first_y, &last_y); @@ -3292,10 +3253,10 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout, if (update_byte) { - line_byte = pango_layout_line_get_start_index (layout_line) + pango_layout_line_get_length (layout_line); + line_byte = layout_line->start_index + layout_line->length; } - if (line_byte < pango_layout_line_get_length (layout_line) || !tmp_list->next) /* first line of paragraph */ + if (line_byte < layout_line->length || !tmp_list->next) /* first line of paragraph */ { GtkTextLine *prev_line; @@ -3317,7 +3278,7 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout, layout_line = tmp_list->data; line_display_index_to_iter (layout, display, iter, - pango_layout_line_get_start_index (layout_line) + pango_layout_line_get_length (layout_line), 0); + layout_line->start_index + layout_line->length, 0); break; } @@ -3326,21 +3287,21 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout, } else { - int prev_offset = pango_layout_line_get_start_index (layout_line); + int prev_offset = layout_line->start_index; tmp_list = tmp_list->next; while (tmp_list) { layout_line = tmp_list->data; - if (line_byte < pango_layout_line_get_start_index (layout_line) + pango_layout_line_get_length (layout_line) || + if (line_byte < layout_line->start_index + layout_line->length || !tmp_list->next) { line_display_index_to_iter (layout, display, iter, prev_offset, 0); break; } - prev_offset = pango_layout_line_get_start_index (layout_line); + prev_offset = layout_line->start_index; tmp_list = tmp_list->next; } } @@ -3407,10 +3368,10 @@ gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout, if (found) { line_display_index_to_iter (layout, display, iter, - pango_layout_line_get_start_index (layout_line), 0); + layout_line->start_index, 0); found_after = TRUE; } - else if (line_byte < pango_layout_line_get_start_index (layout_line) + pango_layout_line_get_length (layout_line) || !tmp_list->next) + else if (line_byte < layout_line->start_index + layout_line->length || !tmp_list->next) found = TRUE; tmp_list = tmp_list->next; @@ -3464,17 +3425,17 @@ gtk_text_layout_move_iter_to_line_end (GtkTextLayout *layout, { PangoLayoutLine *layout_line = tmp_list->data; - if (line_byte < pango_layout_line_get_start_index (layout_line) + pango_layout_line_get_length (layout_line) || !tmp_list->next) + if (line_byte < layout_line->start_index + layout_line->length || !tmp_list->next) { line_display_index_to_iter (layout, display, iter, - direction < 0 ? pango_layout_line_get_start_index (layout_line) : pango_layout_line_get_start_index (layout_line) + pango_layout_line_get_length (layout_line), + direction < 0 ? layout_line->start_index : layout_line->start_index + layout_line->length, 0); /* FIXME: As a bad hack, we move back one position when we * are inside a paragraph to avoid going to next line on a * forced break not at whitespace. Real fix is to keep track * of whether marks are at leading or trailing edge? */ - if (direction > 0 && pango_layout_line_get_length (layout_line) > 0 && + if (direction > 0 && layout_line->length > 0 && !gtk_text_iter_ends_line (iter) && !_gtk_text_btree_char_is_invisible (iter)) gtk_text_iter_backward_char (iter); @@ -3520,7 +3481,7 @@ gtk_text_layout_iter_starts_line (GtkTextLayout *layout, { PangoLayoutLine *layout_line = tmp_list->data; - if (line_byte < pango_layout_line_get_start_index (layout_line) + pango_layout_line_get_length (layout_line) || + if (line_byte < layout_line->start_index + layout_line->length || !tmp_list->next) { /* We're located on this line or the para delimiters before @@ -3528,7 +3489,7 @@ gtk_text_layout_iter_starts_line (GtkTextLayout *layout, */ gtk_text_line_display_unref (display); - if (line_byte == pango_layout_line_get_start_index (layout_line)) + if (line_byte == layout_line->start_index) return TRUE; else return FALSE; @@ -3585,7 +3546,7 @@ gtk_text_layout_move_iter_to_x (GtkTextLayout *layout, { PangoLayoutLine *layout_line = pango_layout_iter_get_line_readonly (layout_iter); - if (line_byte < pango_layout_line_get_start_index (layout_line) + pango_layout_line_get_length (layout_line) || + if (line_byte < layout_line->start_index + layout_line->length || pango_layout_iter_at_last_line (layout_iter)) { PangoRectangle logical_rect; @@ -3910,7 +3871,7 @@ render_para (GskPangoRenderer *crenderer, * only do it if the selection is opaque. */ if (selection_start_index < byte_offset && - selection_end_index > pango_layout_line_get_length (line) + byte_offset && + selection_end_index > line->length + byte_offset && selection->alpha >= 1) { gtk_snapshot_append_color (crenderer->snapshot, @@ -3949,8 +3910,8 @@ render_para (GskPangoRenderer *crenderer, * that is after pango_layout_line_get_length (line) for the last line of the * paragraph counts as part of the line for this */ - if ((selection_start_index < byte_offset + pango_layout_line_get_length (line) || - (selection_start_index == byte_offset + pango_layout_line_get_length (line) && pango_layout_iter_at_last_line (iter))) && + if ((selection_start_index < byte_offset + line->length || + (selection_start_index == byte_offset + line->length && pango_layout_iter_at_last_line (iter))) && selection_end_index > byte_offset) { int *ranges = NULL; @@ -3998,7 +3959,7 @@ render_para (GskPangoRenderer *crenderer, /* Paint in the ends of the line */ if (line_rect.x > line_display->left_margin * PANGO_SCALE && ((line_display->direction == GTK_TEXT_DIR_LTR && selection_start_index < byte_offset) || - (line_display->direction == GTK_TEXT_DIR_RTL && selection_end_index > byte_offset + pango_layout_line_get_length (line)))) + (line_display->direction == GTK_TEXT_DIR_RTL && selection_end_index > byte_offset + line->length))) gtk_snapshot_append_color (crenderer->snapshot, selection, &GRAPHENE_RECT_INIT (line_display->left_margin, @@ -4008,7 +3969,7 @@ render_para (GskPangoRenderer *crenderer, if (line_rect.x + line_rect.width < (screen_width + line_display->left_margin) * PANGO_SCALE && - ((line_display->direction == GTK_TEXT_DIR_LTR && selection_end_index > byte_offset + pango_layout_line_get_length (line)) || + ((line_display->direction == GTK_TEXT_DIR_LTR && selection_end_index > byte_offset + line->length) || (line_display->direction == GTK_TEXT_DIR_RTL && selection_start_index < byte_offset))) { int nonlayout_width = line_display->left_margin @@ -4027,8 +3988,8 @@ render_para (GskPangoRenderer *crenderer, gtk_widget_has_focus (crenderer->widget) && cursor_alpha > 0 && byte_offset <= line_display->insert_index && - (line_display->insert_index < byte_offset + pango_layout_line_get_length (line) || - (at_last_line && line_display->insert_index == byte_offset + pango_layout_line_get_length (line)))) + (line_display->insert_index < byte_offset + line->length || + (at_last_line && line_display->insert_index == byte_offset + line->length))) { GtkCssStyle *style; GdkRGBA cursor_color; @@ -4063,7 +4024,7 @@ render_para (GskPangoRenderer *crenderer, } } - byte_offset += pango_layout_line_get_length (line); + byte_offset += line->length; } while (pango_layout_iter_next_line (iter)); diff --git a/gtk/gtktexttag.c b/gtk/gtktexttag.c index 9774623b89..c3ef142864 100644 --- a/gtk/gtktexttag.c +++ b/gtk/gtktexttag.c @@ -785,10 +785,9 @@ gtk_text_tag_class_init (GtkTextTagClass *klass) */ g_object_class_install_property (object_class, PROP_TEXT_TRANSFORM, - g_param_spec_enum ("text-transform", NULL, NULL, - PANGO_TYPE_TEXT_TRANSFORM, - PANGO_TEXT_TRANSFORM_NONE, - GTK_PARAM_READWRITE)); + g_param_spec_uint ("text-transform", NULL, NULL, + 0, G_MAXUINT, 0, + GTK_PARAM_READWRITE)); /** * GtkTextTag:word: diff --git a/gtk/gtktextutil.c b/gtk/gtktextutil.c index 5d3146b786..f63d853443 100644 --- a/gtk/gtktextutil.c +++ b/gtk/gtktextutil.c @@ -50,8 +50,8 @@ append_n_lines (GString *str, const char *text, GSList *lines, int n_lines) { line = lines->data; g_string_append_len (str, - &text[pango_layout_line_get_start_index (line)], - pango_layout_line_get_length (line)); + &text[line->start_index], + line->length); lines = lines->next; } } @@ -363,13 +363,13 @@ _gtk_text_util_get_block_cursor_location (PangoLayout *layout, text = pango_layout_get_text (layout); - if (index < pango_layout_line_get_start_index (layout_line) + pango_layout_line_get_length (layout_line)) + if (index < layout_line->start_index + layout_line->length) { /* this may be a zero-width character in the middle of the line, * or it could be a character where line is wrapped, we do want * block cursor in latter case */ if (g_utf8_next_char (text + index) - text != - pango_layout_line_get_start_index (layout_line) + pango_layout_line_get_length (layout_line)) + layout_line->start_index + layout_line->length) { /* zero-width character in the middle of the line, do not * bother with block cursor */ @@ -392,9 +392,9 @@ _gtk_text_util_get_block_cursor_location (PangoLayout *layout, /* In case when index points to the end of line, pos->x is always most right * pixel of the layout line, so we need to correct it for RTL text. */ - if (pango_layout_line_get_length (layout_line)) + if (layout_line->length) { - if (pango_layout_line_get_resolved_direction (layout_line) == PANGO_DIRECTION_RTL) + if (layout_line->resolved_dir == PANGO_DIRECTION_RTL) { PangoLayoutIter *iter; PangoRectangle line_rect; diff --git a/gtk/inspector/prop-editor.c b/gtk/inspector/prop-editor.c index 15de3d4d23..3184e8ca8a 100644 --- a/gtk/inspector/prop-editor.c +++ b/gtk/inspector/prop-editor.c @@ -33,6 +33,7 @@ #include "gtkcolordialogbutton.h" #include "gtkfontdialogbutton.h" #include "gtklabel.h" +#include "gtkpangoprivate.h" #include "gtkpopover.h" #include "gtkscrolledwindow.h" #include "gtkspinbutton.h" @@ -365,7 +366,7 @@ attr_list_modified (GtkEntry *entry, ObjectProperty *p) GValue val = G_VALUE_INIT; PangoAttrList *attrs; - attrs = pango_attr_list_from_string (gtk_editable_get_text (GTK_EDITABLE (entry))); + attrs = gtk_pango_attr_list_from_string (gtk_editable_get_text (GTK_EDITABLE (entry))); if (!attrs) return; @@ -414,7 +415,7 @@ attr_list_changed (GObject *object, GParamSpec *pspec, gpointer data) attrs = g_value_get_boxed (&val); if (attrs) - str = pango_attr_list_to_string (attrs); + str = gtk_pango_attr_list_to_string (attrs); if (str == NULL) str = g_strdup (""); text = gtk_editable_get_text (GTK_EDITABLE (entry)); -- 2.43.0 From 62228a63c461485688642acae46a57a38994aff2 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 29 Nov 2023 20:45:32 +0100 Subject: [PATCH 09/10] build: Decrease pango/glib version --- meson.build | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 998f4c08f2..a3ce04ce70 100644 --- a/meson.build +++ b/meson.build @@ -11,9 +11,9 @@ project('gtk', 'c', license: 'LGPL-2.1-or-later') # keep these numbers in sync with wrap files where there exist -glib_req = '>= 2.76.0' -introspection_req = '>= 1.76.0' # keep this in sync with glib -pango_req = '>= 1.50.0' # keep this in sync with .gitlab-ci/test-msys.sh +glib_req = '>= 2.68.0' +introspection_req = '>= 1.68.0' # keep this in sync with glib +pango_req = '>= 1.48.0' # keep this in sync with .gitlab-ci/test-msys.sh harfbuzz_req = '>= 2.6.0' fribidi_req = '>= 1.0.6' cairo_req = '>= 1.14.0' -- 2.43.0 From 64a07ed871fd99ea1f40204eedba6dff96ac7ad4 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 7 Dec 2023 17:50:56 +0100 Subject: [PATCH 10/10] Fixups --- gsk/gl/gskglrenderjob.c | 9 +-------- gsk/gskrendernodeimpl.c | 6 ++---- gsk/gskrendernodeparser.c | 11 +++-------- gtk/gtkpango.c | 2 ++ 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c index 1a3cea3e90..a75917968e 100644 --- a/gsk/gl/gskglrenderjob.c +++ b/gsk/gl/gskglrenderjob.c @@ -2980,7 +2980,6 @@ gsk_gl_render_job_visit_text_node (GskGLRenderJob *job, guint last_texture = 0; GskGLDrawVertex *vertices; guint used = 0; - guint16 nc[4] = { FP16_MINUS_ONE, FP16_MINUS_ONE, FP16_MINUS_ONE, FP16_MINUS_ONE }; guint16 cc[4]; const guint16 *c; const PangoGlyphInfo *gi; @@ -3019,13 +3018,7 @@ gsk_gl_render_job_visit_text_node (GskGLRenderJob *job, lookup.glyph = gi->glyph; - /* If the glyph has color, we don't need to recolor anything. - * We tell the shader by setting the color to vec4(-1). - */ - if (!force_color && ((GtkPangoGlyphVisAttr*) &gi->attr)->is_color) - c = nc; - else - c = cc; + c = cc; cx = (float)(x_position + gi->geometry.x_offset) / PANGO_SCALE; lookup.xshift = compute_phase_and_pos (x + cx, &cx); diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index d0043b08e6..90c9401194 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -5105,8 +5105,7 @@ gsk_text_node_diff (GskRenderNode *node1, info1->geometry.width == info2->geometry.width && info1->geometry.x_offset == info2->geometry.x_offset && info1->geometry.y_offset == info2->geometry.y_offset && - info1->attr.is_cluster_start == info2->attr.is_cluster_start && - ((GtkPangoGlyphVisAttr*) &info1->attr)->is_color == ((GtkPangoGlyphVisAttr*) &info2->attr)->is_color) + info1->attr.is_cluster_start == info2->attr.is_cluster_start) continue; gsk_render_node_diff_impossible (node1, node2, region); @@ -5185,8 +5184,7 @@ gsk_text_node_new (PangoFont *font, glyph_infos[n] = glyphs->glyphs[i]; - if (((GtkPangoGlyphVisAttr*) &glyphs->glyphs[i].attr)->is_color) - self->has_color_glyphs = TRUE; + self->has_color_glyphs = FALSE; n++; } diff --git a/gsk/gskrendernodeparser.c b/gsk/gskrendernodeparser.c index 2c39447352..41edc8bcff 100644 --- a/gsk/gskrendernodeparser.c +++ b/gsk/gskrendernodeparser.c @@ -1014,9 +1014,8 @@ parse_glyphs (GtkCssParser *parser, gi.attr.is_cluster_start = 1; if (gtk_css_parser_try_ident (parser, "color")) - ((GtkPangoGlyphVisAttr*) &gi.attr)->is_color = 1; - else - ((GtkPangoGlyphVisAttr*) &gi.attr)->is_color = 0; + { + } } pango_glyph_string_set_size (glyph_string, glyph_string->num_glyphs + 1); @@ -2979,8 +2978,7 @@ gsk_text_node_serialize_glyphs (GskRenderNode *node, glyphs[i].geometry.width == ascii->glyphs[j].geometry.width && glyphs[i].geometry.x_offset == 0 && glyphs[i].geometry.y_offset == 0 && - glyphs[i].attr.is_cluster_start && - !((GtkPangoGlyphVisAttr*) &glyphs[i].attr)->is_color) + glyphs[i].attr.is_cluster_start) { switch (j + MIN_ASCII_GLYPH) { @@ -3010,7 +3008,6 @@ gsk_text_node_serialize_glyphs (GskRenderNode *node, g_string_append_printf (p, "%u ", glyphs[i].glyph); string_append_double (p, (double) glyphs[i].geometry.width / PANGO_SCALE); if (!glyphs[i].attr.is_cluster_start || - ((GtkPangoGlyphVisAttr*) &glyphs[i].attr)->is_color || glyphs[i].geometry.x_offset != 0 || glyphs[i].geometry.y_offset != 0) { @@ -3020,8 +3017,6 @@ gsk_text_node_serialize_glyphs (GskRenderNode *node, string_append_double (p, (double) glyphs[i].geometry.y_offset / PANGO_SCALE); if (!glyphs[i].attr.is_cluster_start) g_string_append (p, " same-cluster"); - if (((GtkPangoGlyphVisAttr*) &glyphs[i].attr)->is_color) - g_string_append (p, " color"); } if (i + 1 < n_glyphs) diff --git a/gtk/gtkpango.c b/gtk/gtkpango.c index 69d96b43a1..e85d2efd26 100644 --- a/gtk/gtkpango.c +++ b/gtk/gtkpango.c @@ -510,6 +510,7 @@ append_enum_value (GString *str, g_string_append_printf (str, " %d", value); } +#if !PANGO_VERSION_CHECK(1, 50, 0) static PangoAttrInt * pango_attribute_as_int (PangoAttribute *attr) { @@ -647,6 +648,7 @@ pango_attribute_as_shape (PangoAttribute *attr) return NULL; } } +#endif static void attr_print (GString *str, -- 2.43.0