From c5abdfb72b2b9e7a4fdb6dac40b935657c518c13 Mon Sep 17 00:00:00 2001 From: Alice Mikhaylenko Date: Thu, 13 Jun 2024 23:36:38 +0400 Subject: [PATCH 1/7] label: Fix critical when updating styles Noticed when testing with libadwaita styles instead of GTK styles. --- gtk/gtklabel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c index 4b7089d004..94cdcb9b31 100644 --- a/gtk/gtklabel.c +++ b/gtk/gtklabel.c @@ -3440,7 +3440,7 @@ link_style_changed_cb (GtkCssNode *node, GTK_CSS_AFFECTS_CONTENT | GTK_CSS_AFFECTS_TEXT_ATTRS)) { - gtk_label_clear_layout (self); + gtk_label_ensure_layout (self); gtk_widget_queue_draw (GTK_WIDGET (self)); } } @@ -6300,3 +6300,4 @@ gtk_label_accessible_text_init (GtkAccessibleTextInterface *iface) /* }}} */ /* vim:set foldmethod=marker expandtab: */ + From 66c9132abe28a20e01a6b9c12232bc01a66fa05c Mon Sep 17 00:00:00 2001 From: Alice Mikhaylenko Date: Thu, 13 Jun 2024 23:53:30 +0400 Subject: [PATCH 2/7] label: Update selection on css changes too --- gtk/gtklabel.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c index 94cdcb9b31..414a8d444c 100644 --- a/gtk/gtklabel.c +++ b/gtk/gtklabel.c @@ -3445,6 +3445,15 @@ link_style_changed_cb (GtkCssNode *node, } } +static void +selection_style_changed_cb (GtkCssNode *node, + GtkCssStyleChange *change, + GtkLabel *self) +{ + if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_REDRAW)) + gtk_widget_queue_draw (GTK_WIDGET (self)); +} + static void start_element_handler (GMarkupParseContext *context, const char *element_name, @@ -5152,6 +5161,8 @@ gtk_label_select_region_index (GtkLabel *self, gtk_css_node_set_name (self->select_info->selection_node, g_quark_from_static_string ("selection")); gtk_css_node_set_parent (self->select_info->selection_node, widget_node); gtk_css_node_set_state (self->select_info->selection_node, gtk_css_node_get_state (widget_node)); + g_signal_connect (self->select_info->selection_node, "style-changed", + G_CALLBACK (selection_style_changed_cb), self); g_object_unref (self->select_info->selection_node); } } From 260898ecf65a5deb9848f3eec957c8b776705fd3 Mon Sep 17 00:00:00 2001 From: Alice Mikhaylenko Date: Fri, 14 Jun 2024 00:07:22 +0400 Subject: [PATCH 3/7] text: Redraw when selection style changes --- gtk/gtktext.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gtk/gtktext.c b/gtk/gtktext.c index 599ccbb99f..24874a0c62 100644 --- a/gtk/gtktext.c +++ b/gtk/gtktext.c @@ -3858,6 +3858,15 @@ get_better_cursor_x (GtkText *self, return (direction == priv->resolved_dir) ? strong_pos.x / PANGO_SCALE : weak_pos.x / PANGO_SCALE; } +static void +selection_style_changed_cb (GtkCssNode *node, + GtkCssStyleChange *change, + GtkText *self) +{ + if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_REDRAW)) + gtk_widget_queue_draw (GTK_WIDGET (self)); +} + static void gtk_text_move_cursor (GtkText *self, GtkMovementStep step, @@ -4510,6 +4519,8 @@ gtk_text_set_positions (GtkText *self, gtk_css_node_set_name (priv->selection_node, g_quark_from_static_string ("selection")); gtk_css_node_set_parent (priv->selection_node, widget_node); gtk_css_node_set_state (priv->selection_node, gtk_css_node_get_state (widget_node)); + g_signal_connect (priv->selection_node, "style-changed", + G_CALLBACK (selection_style_changed_cb), self); g_object_unref (priv->selection_node); } } From 9fcf55571eee5c6ad454d54a57a0473b10ad3b7c Mon Sep 17 00:00:00 2001 From: Alice Mikhaylenko Date: Fri, 14 Jun 2024 01:39:51 +0400 Subject: [PATCH 4/7] textlayout: Clamp colors before passing them to Pango --- gtk/gtktextlayout.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/gtk/gtktextlayout.c b/gtk/gtktextlayout.c index 10e9562c48..76b1b43616 100644 --- a/gtk/gtktextlayout.c +++ b/gtk/gtktextlayout.c @@ -1407,6 +1407,16 @@ gtk_text_attr_appearance_compare (const PangoAttribute *attr1, overline_equal (appearance1, appearance2); } +static inline GdkRGBA * +clamp_rgba (GdkRGBA *rgba) +{ + rgba->red = CLAMP (rgba->red, 0, 1); + rgba->green = CLAMP (rgba->green, 0, 1); + rgba->blue = CLAMP (rgba->blue, 0, 1); + rgba->alpha = CLAMP (rgba->alpha, 0, 1); + return rgba; +} + /* * gtk_text_attr_appearance_new: * @desc: @@ -1439,19 +1449,19 @@ gtk_text_attr_appearance_new (const GtkTextAppearance *appearance) result->appearance = *appearance; if (appearance->fg_rgba) - result->appearance.fg_rgba = gdk_rgba_copy (appearance->fg_rgba); + result->appearance.fg_rgba = clamp_rgba (gdk_rgba_copy (appearance->fg_rgba)); if (appearance->bg_rgba) - result->appearance.bg_rgba = gdk_rgba_copy (appearance->bg_rgba); + result->appearance.bg_rgba = clamp_rgba (gdk_rgba_copy (appearance->bg_rgba)); if (appearance->underline_rgba) - result->appearance.underline_rgba = gdk_rgba_copy (appearance->underline_rgba); + result->appearance.underline_rgba = clamp_rgba (gdk_rgba_copy (appearance->underline_rgba)); if (appearance->overline_rgba) - result->appearance.overline_rgba = gdk_rgba_copy (appearance->overline_rgba); + result->appearance.overline_rgba = clamp_rgba (gdk_rgba_copy (appearance->overline_rgba)); if (appearance->strikethrough_rgba) - result->appearance.strikethrough_rgba = gdk_rgba_copy (appearance->strikethrough_rgba); + result->appearance.strikethrough_rgba = clamp_rgba (gdk_rgba_copy (appearance->strikethrough_rgba)); return (PangoAttribute *)result; } From ef5e3fae64d923be81c3dbd68812a0fcf88094c1 Mon Sep 17 00:00:00 2001 From: Alice Mikhaylenko Date: Fri, 14 Jun 2024 00:56:29 +0400 Subject: [PATCH 5/7] aboutdialog: Update link colors on css changes --- gtk/gtkaboutdialog.c | 62 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/gtk/gtkaboutdialog.c b/gtk/gtkaboutdialog.c index 773713d2d7..93c5711620 100644 --- a/gtk/gtkaboutdialog.c +++ b/gtk/gtkaboutdialog.c @@ -201,6 +201,10 @@ struct _GtkAboutDialog guint hovering_over_link : 1; guint wrap_license : 1; guint in_child_changed : 1; + + GSList *link_tags; + + guint update_links_cb_id; }; struct _GtkAboutDialogClass @@ -706,6 +710,51 @@ update_credits_button_visibility (GtkAboutDialog *about) update_stack_switcher_visibility (about); } +static void +update_links_cb (GtkAboutDialog *about) +{ + GtkCssStyle *style; + GdkRGBA link_color, visited_link_color; + GSList *l; + + style = gtk_css_node_get_style (about->link_node); + link_color = *gtk_css_color_value_get_rgba (style->core->color); + + style = gtk_css_node_get_style (about->visited_link_node); + visited_link_color = *gtk_css_color_value_get_rgba (style->core->color); + + for (l = about->link_tags; l != NULL; l = l->next) + { + GtkTextTag *tag = l->data; + GdkRGBA color; + + if (g_ptr_array_find_with_equal_func (about->visited_links, link, (GCompareFunc)strcmp, NULL)) + color = visited_link_color; + else + color = link_color; + + g_object_set (G_OBJECT (tag), "foreground-rgba", &color, NULL); + } + + about->update_links_cb_id = 0; +} + +static void +link_style_changed_cb (GtkCssNode *node, + GtkCssStyleChange *change, + GtkAboutDialog *about) +{ + if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_REDRAW)) + { + /* If we access the node right here, we'll end up with infinite recursion */ + if (about->link_tags && !about->update_links_cb_id) + { + about->update_links_cb_id = + g_idle_add_once ((GSourceOnceFunc) update_links_cb, about); + } + } +} + static void gtk_about_dialog_init (GtkAboutDialog *about) { @@ -748,12 +797,16 @@ gtk_about_dialog_init (GtkAboutDialog *about) gtk_css_node_set_name (about->link_node, g_quark_from_static_string ("link")); gtk_css_node_set_parent (about->link_node, node); gtk_css_node_set_state (about->link_node, state | GTK_STATE_FLAG_LINK); + g_signal_connect (about->link_node, "style-changed", + G_CALLBACK (link_style_changed_cb), about); g_object_unref (about->link_node); about->visited_link_node = gtk_css_node_new (); gtk_css_node_set_name (about->visited_link_node, g_quark_from_static_string ("link")); gtk_css_node_set_parent (about->visited_link_node, node); - gtk_css_node_set_state (about->visited_link_node, state | GTK_STATE_FLAG_VISITED); + gtk_css_node_set_state (about->visited_link_node, state | GTK_STATE_FLAG_LINK); + g_signal_connect (about->visited_link_node, "style-changed", + G_CALLBACK (link_style_changed_cb), about); g_object_unref (about->visited_link_node); } @@ -788,6 +841,10 @@ gtk_about_dialog_finalize (GObject *object) g_slist_free_full (about->credit_sections, destroy_credit_section); g_ptr_array_unref (about->visited_links); + g_slist_free (about->link_tags); + + g_clear_handle_id (&about->update_links_cb_id, g_source_remove); + G_OBJECT_CLASS (gtk_about_dialog_parent_class)->finalize (object); } @@ -1910,6 +1967,9 @@ text_buffer_new (GtkAboutDialog *about, "foreground-rgba", &color, "underline", PANGO_UNDERLINE_SINGLE, NULL); + + about->link_tags = g_slist_prepend (about->link_tags, tag); + if (strcmp (link_type, "email") == 0) { char *escaped; From 4918a46172a70fa6931c9783101d692c0dbf8e04 Mon Sep 17 00:00:00 2001 From: Alice Mikhaylenko Date: Fri, 14 Jun 2024 02:14:24 +0400 Subject: [PATCH 6/7] textview: Redraw selection on style changes --- gtk/gtktextlayout.c | 7 +++++++ gtk/gtktextlayoutprivate.h | 1 + gtk/gtktextutil.c | 2 +- gtk/gtktextview.c | 20 ++++++++++++++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/gtk/gtktextlayout.c b/gtk/gtktextlayout.c index 76b1b43616..e032242a3b 100644 --- a/gtk/gtktextlayout.c +++ b/gtk/gtktextlayout.c @@ -4100,6 +4100,7 @@ gtk_text_layout_snapshot (GtkTextLayout *layout, GtkWidget *widget, GtkSnapshot *snapshot, const GdkRectangle *clip, + gboolean selection_style_changed, float cursor_alpha) { GtkTextLayoutPrivate *priv; @@ -4237,6 +4238,12 @@ gtk_text_layout_snapshot (GtkTextLayout *layout, { if (line_display->has_block_cursor && gtk_widget_has_focus (widget)) g_clear_pointer (&line_display->node, gsk_render_node_unref); + + if (selection_style_changed && + (selection_start_index != -1 || selection_end_index != -1)) + { + g_clear_pointer (&line_display->node, gsk_render_node_unref); + } } if (line_display->node == NULL && diff --git a/gtk/gtktextlayoutprivate.h b/gtk/gtktextlayoutprivate.h index 7f24a375fc..e48f5ca487 100644 --- a/gtk/gtktextlayoutprivate.h +++ b/gtk/gtktextlayoutprivate.h @@ -376,6 +376,7 @@ void gtk_text_layout_snapshot (GtkTextLayout *layout, GtkWidget *widget, GtkSnapshot *snapshot, const GdkRectangle *clip, + gboolean selection_style_changed, float cursor_alpha); void gtk_text_layout_set_mru_size (GtkTextLayout *layout, diff --git a/gtk/gtktextutil.c b/gtk/gtktextutil.c index 5d3146b786..7488476fb0 100644 --- a/gtk/gtktextutil.c +++ b/gtk/gtktextutil.c @@ -286,7 +286,7 @@ gtk_text_util_create_rich_drag_icon (GtkWidget *widget, gtk_css_style_snapshot_background (&boxes, snapshot); } - gtk_text_layout_snapshot (layout, widget, snapshot, &(GdkRectangle) { 0, 0, layout_width, layout_height }, 1.0); + gtk_text_layout_snapshot (layout, widget, snapshot, &(GdkRectangle) { 0, 0, layout_width, layout_height }, FALSE, 1.0); g_object_unref (layout); g_object_unref (new_buffer); diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index 82256dc67c..b81e8d6b22 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -303,6 +303,8 @@ struct _GtkTextViewPrivate guint vscroll_policy : 1; guint cursor_handle_dragged : 1; guint selection_handle_dragged : 1; + + guint selection_style_changed : 1; }; struct _GtkTextPendingScroll @@ -840,6 +842,19 @@ gtk_text_view_notify (GObject *object, G_OBJECT_CLASS (gtk_text_view_parent_class)->notify (object, pspec); } +static void +selection_style_changed_cb (GtkCssNode *node, + GtkCssStyleChange *change, + GtkTextView *self) +{ + if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_REDRAW)) + { + GtkTextViewPrivate *priv = self->priv; + priv->selection_style_changed = TRUE; + gtk_widget_queue_draw (GTK_WIDGET (self)); + } +} + static void gtk_text_view_class_init (GtkTextViewClass *klass) { @@ -2041,6 +2056,8 @@ gtk_text_view_init (GtkTextView *text_view) gtk_css_node_set_state (priv->selection_node, gtk_css_node_get_state (priv->text_window->css_node) & ~GTK_STATE_FLAG_DROP_ACTIVE); gtk_css_node_set_visible (priv->selection_node, FALSE); + g_signal_connect (priv->selection_node, "style-changed", + G_CALLBACK (selection_style_changed_cb), text_view); g_object_unref (priv->selection_node); gtk_widget_action_set_enabled (GTK_WIDGET (text_view), "text.can-redo", FALSE); @@ -5922,9 +5939,12 @@ gtk_text_view_paint (GtkWidget *widget, gtk_widget_get_width (widget), gtk_widget_get_height (widget) }, + priv->selection_style_changed, priv->cursor_alpha); gtk_snapshot_restore (snapshot); + + priv->selection_style_changed = FALSE; } static void From 701e0812e446c97bdebbf138901f96dd7f091c11 Mon Sep 17 00:00:00 2001 From: Alice Mikhaylenko Date: Fri, 14 Jun 2024 03:02:33 +0400 Subject: [PATCH 7/7] treeview: Clamp tree line and grid line colors --- gtk/deprecated/gtktreeview.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/gtk/deprecated/gtktreeview.c b/gtk/deprecated/gtktreeview.c index 0c65b7188a..9767e36100 100644 --- a/gtk/deprecated/gtktreeview.c +++ b/gtk/deprecated/gtktreeview.c @@ -4197,20 +4197,20 @@ gtk_tree_view_snapshot_grid_line (GtkTreeView *tree_view, surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 2, 1); data = cairo_image_surface_get_data (surface); /* just color the first pixel... */ - data[0] = round (grid_line_color->blue * 255); - data[1] = round (grid_line_color->green * 255); - data[2] = round (grid_line_color->red * 255); - data[3] = round (grid_line_color->alpha * 255); + data[0] = round (CLAMP (grid_line_color->blue, 0, 1) * 255); + data[1] = round (CLAMP (grid_line_color->green, 0, 1) * 255); + data[2] = round (CLAMP (grid_line_color->red, 0, 1) * 255); + data[3] = round (CLAMP (grid_line_color->alpha, 0, 1) * 255); priv->horizontal_grid_line_texture = gdk_texture_new_for_surface (surface); cairo_surface_destroy (surface); surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 2); data = cairo_image_surface_get_data (surface); - data[0] = round (grid_line_color->blue * 255); - data[1] = round (grid_line_color->green * 255); - data[2] = round (grid_line_color->red * 255); - data[3] = round (grid_line_color->alpha * 255); + data[0] = round (CLAMP (grid_line_color->blue, 0, 1) * 255); + data[1] = round (CLAMP (grid_line_color->green, 0, 1) * 255); + data[2] = round (CLAMP (grid_line_color->red, 0, 1) * 255); + data[3] = round (CLAMP (grid_line_color->alpha, 0, 1) * 255); priv->vertical_grid_line_texture = gdk_texture_new_for_surface (surface); cairo_surface_destroy (surface); @@ -4272,20 +4272,20 @@ gtk_tree_view_snapshot_tree_line (GtkTreeView *tree_view, surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 2, 1); data = cairo_image_surface_get_data (surface); /* just color the first pixel... */ - data[0] = round (tree_line_color->blue * 255); - data[1] = round (tree_line_color->green * 255); - data[2] = round (tree_line_color->red * 255); - data[3] = round (tree_line_color->alpha * 255); + data[0] = round (CLAMP (tree_line_color->blue, 0, 1) * 255); + data[1] = round (CLAMP (tree_line_color->green, 0, 1) * 255); + data[2] = round (CLAMP (tree_line_color->red, 0, 1) * 255); + data[3] = round (CLAMP (tree_line_color->alpha, 0, 1) * 255); priv->horizontal_tree_line_texture = gdk_texture_new_for_surface (surface); cairo_surface_destroy (surface); surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 2); data = cairo_image_surface_get_data (surface); - data[0] = round (tree_line_color->blue * 255); - data[1] = round (tree_line_color->green * 255); - data[2] = round (tree_line_color->red * 255); - data[3] = round (tree_line_color->alpha * 255); + data[0] = round (CLAMP (tree_line_color->blue, 0, 1) * 255); + data[1] = round (CLAMP (tree_line_color->green, 0, 1) * 255); + data[2] = round (CLAMP (tree_line_color->red, 0, 1) * 255); + data[3] = round (CLAMP (tree_line_color->alpha, 0, 1) * 255); priv->vertical_tree_line_texture = gdk_texture_new_for_surface (surface); cairo_surface_destroy (surface);