From 404996a84bd4e1229ab0948a12f535d0583294b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Fernandes?= Date: Mon, 28 Feb 2022 13:05:40 +0000 Subject: [PATCH 1/3] list-view: Draw thumbnail shadow in advance Cell renderers do not have their own style context, so style classes are applied to the tree view widget as a whole. In order to workaround this, the thumbnail shadows have been achieved using a css class on the whole tree view which is flipped on/off when getting the data for each row. This was assumedly a fragile hack, but it turns out to be worse than that: changing the view style repeatedly hurts the performance when loading directories with many thumbnailable files, even freezing the application. Let's render the shadow ourselves and immediately restore the style context to its original state, which fixes the performance bug and is also a more solid solution. Fixes https://gitlab.gnome.org/GNOME/nautilus/-/issues/2169 --- src/nautilus-list-view.c | 63 ++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/src/nautilus-list-view.c b/src/nautilus-list-view.c index 77278fab19..941d5f5f1f 100644 --- a/src/nautilus-list-view.c +++ b/src/nautilus-list-view.c @@ -1578,16 +1578,6 @@ starred_cell_data_func (GtkTreeViewColumn *column, g_autofree gchar *text = NULL; g_autofree gchar *uri = NULL; NautilusFile *file; - GtkStyleContext *context; - - /* The "thumbnail" style class is set before rendering each icon cell with - * a thumbnail. However, style classes are not applied to each cell, but - * alwyas to the whole GtkTreeView widget. So, before the star icon is - * rendered, we must ensure that the style is not set, otherwise the star - * icon is going to get the styles meant only for thumbnail icons. - */ - context = gtk_widget_get_style_context (GTK_WIDGET (view)); - gtk_style_context_remove_class (context, "thumbnail"); gtk_tree_model_get (model, iter, view->details->file_name_column_num, &text, @@ -1659,10 +1649,6 @@ icon_cell_data_func (GtkTreeViewColumn *column, &file, -1); - /* Hack: Set/unset the style class in advance of rendering. This makes a - * major assumption that's all but clearly stated in the documentation of - * GtkCellLayout: that the DataFunc is called before rendering each cell. - */ is_thumbnail = FALSE; if (zoom_level_is_enough_for_thumbnails (view) && file != NULL) { @@ -1678,11 +1664,52 @@ icon_cell_data_func (GtkTreeViewColumn *column, if (is_thumbnail) { + cairo_surface_t *new_surface; + cairo_t *cr; + int w, h; + + /* The shadow extends 1px up, 3px down, and 2px left and right. For that + * reason, the final surface must be 4px taller and 4px wider, with the + * original icon starting at (2, 1). + * + * ************************* -+ + * *#. #* -+ | + * *# \ #* | | + * *# \ #* | | + * *# (2, 1) #* | | + * *# #* | h | + * *# #* | | h + 4 + * *# #* | | + * *# #* | | + * *# #* -+ | + * *#######################* | + * *#######################* | + * ************************* -+ + * | | + * +-------------------+ :¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨: + * w : #### --> Solid shadow : + * | | : : + * +-----------------------+ : **** --> Blur shadow : + * w + 4 '.......................' + */ + w = cairo_image_surface_get_width (surface); + h = cairo_image_surface_get_height (surface); + + new_surface = cairo_surface_create_similar (surface, + CAIRO_CONTENT_COLOR_ALPHA, + w + 4, + h + 4); + cr = cairo_create (new_surface); + + gtk_style_context_save (context); gtk_style_context_add_class (context, "thumbnail"); - } - else - { - gtk_style_context_remove_class (context, "thumbnail"); + gtk_render_icon_surface (context, cr, surface, 2, 1); + gtk_style_context_restore (context); + + cairo_destroy (cr); + + cairo_surface_destroy (surface); + surface = new_surface; } g_object_set (renderer, -- GitLab From 77ba1d76f7de82bd867a5c149a370dc107c28a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Fernandes?= Date: Tue, 1 Mar 2022 21:37:23 +0000 Subject: [PATCH 2/3] css: Don't use -gtk-icon-shadow for thumbnails Gaussian blur has high performance impact. Also, thumbnails with transparent areas don't get a shadow around their bounding rectangle. Instead, use gtk_render_background() which is both cheaper and allows us to use the same CSS from the GTK 4 port. Furthermore, it allows us to set an opaque background for thumbnails with transparent parts. Fixes https://gitlab.gnome.org/GNOME/nautilus/-/issues/2161 --- src/nautilus-canvas-item.c | 16 ++++++++++++---- src/nautilus-list-view.c | 3 ++- src/resources/css/Adwaita.css | 25 +++++++++---------------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/nautilus-canvas-item.c b/src/nautilus-canvas-item.c index f51967d23f..436f813d73 100644 --- a/src/nautilus-canvas-item.c +++ b/src/nautilus-canvas-item.c @@ -1362,14 +1362,22 @@ nautilus_canvas_item_draw (EelCanvasItem *item, context = gtk_widget_get_style_context (GTK_WIDGET (container)); gtk_style_context_save (context); gtk_style_context_add_class (context, "nautilus-canvas-item"); - if (details->is_thumbnail) - { - gtk_style_context_add_class (context, "thumbnail"); - } icon_rect = canvas_item->details->icon_rect; temp_surface = map_surface (canvas_item); + if (details->is_thumbnail) + { + /* Draw box shadow before drawing the thumbnail. */ + gtk_style_context_save (context); + gtk_style_context_add_class (context, "thumbnail"); + gtk_render_background (context, cr, + icon_rect.x0, + icon_rect.y0, + icon_rect.x1 - icon_rect.x0, + icon_rect.y1 - icon_rect.y0); + gtk_style_context_restore (context); + } gtk_render_icon_surface (context, cr, temp_surface, icon_rect.x0, icon_rect.y0); diff --git a/src/nautilus-list-view.c b/src/nautilus-list-view.c index 941d5f5f1f..bb7fbe3ee6 100644 --- a/src/nautilus-list-view.c +++ b/src/nautilus-list-view.c @@ -1672,7 +1672,7 @@ icon_cell_data_func (GtkTreeViewColumn *column, * reason, the final surface must be 4px taller and 4px wider, with the * original icon starting at (2, 1). * - * ************************* -+ + * *#######################* -+ * *#. #* -+ | * *# \ #* | | * *# \ #* | | @@ -1703,6 +1703,7 @@ icon_cell_data_func (GtkTreeViewColumn *column, gtk_style_context_save (context); gtk_style_context_add_class (context, "thumbnail"); + gtk_render_background (context, cr, 2, 1, w, h); gtk_render_icon_surface (context, cr, surface, 2, 1); gtk_style_context_restore (context); diff --git a/src/resources/css/Adwaita.css b/src/resources/css/Adwaita.css index 4991979cf0..d259921ce8 100644 --- a/src/resources/css/Adwaita.css +++ b/src/resources/css/Adwaita.css @@ -12,11 +12,6 @@ border-radius: 5px; } -.nautilus-canvas-item.thumbnail { - -gtk-icon-shadow: 0px 1px 2px @borders, - 1px 0px 0px alpha(@borders, 0.25), - -1px 0px 0px alpha(@borders, 0.25), - 0px 2px 0px alpha(@borders, 0.5); } .nautilus-canvas-item.dim-label { @@ -194,13 +189,6 @@ entry.search > * { border-bottom: 1px solid @theme_bg_color; } -.nautilus-list-view.thumbnail { - -gtk-icon-shadow: 0px 1px 2px @borders, - 1px 0px 0px alpha(@borders, 0.25), - -1px 0px 0px alpha(@borders, 0.25), - 0px 2px 0px alpha(@borders, 0.5); -} - .search-information { background-color: @theme_selected_bg_color; color:white; @@ -239,10 +227,6 @@ flowboxchild:selected { flowboxchild .thumbnail { margin: 4px; - box-shadow: 0px 1px 2px 0px alpha(@borders, 0.5), - 0px 0px 0px 1px alpha(@borders, 0.5), - 0px 2px 0px 0px alpha(@borders, 0.5); - border-radius: 2px; } .icon-ui-labels-box { @@ -262,3 +246,12 @@ flowboxchild:selected image { */ -gtk-icon-shadow: 0px 0px @theme_selected_bg_color; } + +.thumbnail { + box-shadow: 0px 1px 2px 0px alpha(@borders, 0.5), + 0px 0px 0px 1px alpha(@borders, 0.5), + 0px 2px 0px 0px alpha(@borders, 0.5); + border-radius: 2px; + /* Opaque background for thumbnails with transparent areas. */ + background-color: #fafafa; +} -- GitLab From 7e22b73f01b187d809f2736de7026804d8ff7528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Fernandes?= Date: Tue, 1 Mar 2022 21:37:56 +0000 Subject: [PATCH 3/3] canvas-item: Fix black corner glitch in selected thumbnails The canvas item style includes a 5px border-radius for the rectangle around labels when the item is selected. However, this is also affecting the icon, causing black artifacts in the corners of selected thumbnails and custom icons. Previously, this wasn't visible for thumbnails because they used to have rounded frames. Explicitly set the 5px for the box label alone and ensure the icons (before applying the shadow) have sharp corners. --- src/nautilus-canvas-item.c | 1 + src/resources/css/Adwaita.css | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/nautilus-canvas-item.c b/src/nautilus-canvas-item.c index 436f813d73..d833b6d490 100644 --- a/src/nautilus-canvas-item.c +++ b/src/nautilus-canvas-item.c @@ -1384,6 +1384,7 @@ nautilus_canvas_item_draw (EelCanvasItem *item, cairo_surface_destroy (temp_surface); /* Draw the label text. */ + gtk_style_context_add_class (context, "label-text"); draw_label_text (canvas_item, cr, icon_rect); gtk_style_context_restore (context); diff --git a/src/resources/css/Adwaita.css b/src/resources/css/Adwaita.css index d259921ce8..f96cddc199 100644 --- a/src/resources/css/Adwaita.css +++ b/src/resources/css/Adwaita.css @@ -9,9 +9,11 @@ } .nautilus-canvas-item { - border-radius: 5px; + border-radius: 0px; } +.nautilus-canvas-item.label-text { + border-radius: 5px; } .nautilus-canvas-item.dim-label { -- GitLab