From bc1405c9f54e19e74f973581130229ef1053ff9c Mon Sep 17 00:00:00 2001 From: Cosimo Cecchi Date: Fri, 2 Aug 2013 14:37:13 +0200 Subject: Support HiDpi icons Port the rendering of icons to cairo surfaces, so that we can apply the GDK scale factor when rendering icons. origin commit: https://gitlab.gnome.org/GNOME/nautilus/commit/0d4555d7 --- libcaja-private/caja-icon-canvas-item.c | 150 ++++++++++++++++++-------------- 1 file changed, 83 insertions(+), 67 deletions(-) (limited to 'libcaja-private/caja-icon-canvas-item.c') diff --git a/libcaja-private/caja-icon-canvas-item.c b/libcaja-private/caja-icon-canvas-item.c index 88908196..98551be4 100644 --- a/libcaja-private/caja-icon-canvas-item.c +++ b/libcaja-private/caja-icon-canvas-item.c @@ -83,7 +83,7 @@ struct CajaIconCanvasItemDetails /* The image, text, font. */ double x, y; GdkPixbuf *pixbuf; - GdkPixbuf *rendered_pixbuf; + cairo_surface_t *rendered_surface; GList *emblem_pixbufs; char *editable_text; /* Text that can be modified by a renaming function */ char *additional_text; /* Text that cannot be modifed, such as file size, etc. */ @@ -278,9 +278,9 @@ caja_icon_canvas_item_finalize (GObject *object) g_free (details->additional_text); g_free (details->attach_points); - if (details->rendered_pixbuf != NULL) + if (details->rendered_surface != NULL) { - g_object_unref (details->rendered_pixbuf); + g_object_unref (details->rendered_surface); } if (details->editable_text_layout != NULL) @@ -498,6 +498,27 @@ caja_icon_canvas_item_get_property (GObject *object, } } +static void +get_scaled_icon_size (CajaIconCanvasItem *item, + gint *width, + gint *height) +{ + EelCanvas *canvas; + GdkPixbuf *pixbuf = NULL; + gint scale; + + if (item != NULL) { + canvas = EEL_CANVAS_ITEM (item)->canvas; + scale = gtk_widget_get_scale_factor (GTK_WIDGET (canvas)); + pixbuf = item->details->pixbuf; + } + + if (width) + *width = (pixbuf == NULL) ? 0 : (gdk_pixbuf_get_width (pixbuf) / scale); + if (height) + *height = (pixbuf == NULL) ? 0 : (gdk_pixbuf_get_height (pixbuf) / scale); +} + cairo_surface_t * caja_icon_canvas_item_get_drag_surface (CajaIconCanvasItem *item) { @@ -506,6 +527,7 @@ caja_icon_canvas_item_get_drag_surface (CajaIconCanvasItem *item) EelCanvas *canvas; GdkScreen *screen; int width, height; + int pix_width, pix_height; int item_offset_x, item_offset_y; EelIRect icon_rect; EelIRect emblem_rect; @@ -554,11 +576,12 @@ caja_icon_canvas_item_get_drag_surface (CajaIconCanvasItem *item) item_offset_x, item_offset_y); cairo_surface_destroy (drag_surface); + get_scaled_icon_size (item, &pix_width, &pix_height); icon_rect.x0 = item_offset_x; icon_rect.y0 = item_offset_y; - icon_rect.x1 = item_offset_x + gdk_pixbuf_get_width (item->details->pixbuf); - icon_rect.y1 = item_offset_y + gdk_pixbuf_get_height (item->details->pixbuf); + icon_rect.x1 = item_offset_x + pix_width; + icon_rect.y1 = item_offset_y + pix_height; is_rtl = caja_icon_container_is_layout_rtl (CAJA_ICON_CONTAINER (canvas)); @@ -607,10 +630,10 @@ caja_icon_canvas_item_set_image (CajaIconCanvasItem *item, { g_object_unref (details->pixbuf); } - if (details->rendered_pixbuf != NULL) + if (details->rendered_surface != NULL) { - g_object_unref (details->rendered_pixbuf); - details->rendered_pixbuf = NULL; + cairo_surface_destroy (details->rendered_surface); + details->rendered_surface = NULL; } details->pixbuf = image; @@ -1671,8 +1694,8 @@ draw_pixbuf (GdkPixbuf *pixbuf, } /* shared code to highlight or dim the passed-in pixbuf */ -static GdkPixbuf * -real_map_pixbuf (CajaIconCanvasItem *icon_item) +static cairo_surface_t * +real_map_surface (CajaIconCanvasItem *icon_item) { EelCanvas *canvas; char *audio_filename; @@ -1681,6 +1704,7 @@ real_map_pixbuf (CajaIconCanvasItem *icon_item) int emblem_size; GtkStyleContext *style; GdkRGBA color; + cairo_surface_t *surface; temp_pixbuf = icon_item->details->pixbuf; canvas = EEL_CANVAS_ITEM(icon_item)->canvas; @@ -1758,13 +1782,18 @@ real_map_pixbuf (CajaIconCanvasItem *icon_item) g_object_unref (old_pixbuf); } - return temp_pixbuf; + surface = gdk_cairo_surface_create_from_pixbuf (temp_pixbuf, + gtk_widget_get_scale_factor (GTK_WIDGET (canvas)), + gtk_widget_get_window (GTK_WIDGET (canvas))); + g_object_unref (temp_pixbuf); + + return surface; } -static GdkPixbuf * -map_pixbuf (CajaIconCanvasItem *icon_item) +static cairo_surface_t * +map_surface (CajaIconCanvasItem *icon_item) { - if (!(icon_item->details->rendered_pixbuf != NULL + if (!(icon_item->details->rendered_surface != NULL && icon_item->details->rendered_is_active == icon_item->details->is_active && icon_item->details->rendered_is_prelit == icon_item->details->is_prelit && icon_item->details->rendered_is_highlighted_for_selection == icon_item->details->is_highlighted_for_selection @@ -1772,11 +1801,11 @@ map_pixbuf (CajaIconCanvasItem *icon_item) && icon_item->details->rendered_is_highlighted_for_clipboard == icon_item->details->is_highlighted_for_clipboard && (icon_item->details->is_highlighted_for_selection && icon_item->details->rendered_is_focused == gtk_widget_has_focus (GTK_WIDGET (EEL_CANVAS_ITEM (icon_item)->canvas))))) { - if (icon_item->details->rendered_pixbuf != NULL) + if (icon_item->details->rendered_surface != NULL) { - g_object_unref (icon_item->details->rendered_pixbuf); + cairo_surface_destroy (icon_item->details->rendered_surface); } - icon_item->details->rendered_pixbuf = real_map_pixbuf (icon_item); + icon_item->details->rendered_surface = real_map_surface (icon_item); icon_item->details->rendered_is_active = icon_item->details->is_active; icon_item->details->rendered_is_prelit = icon_item->details->is_prelit; icon_item->details->rendered_is_highlighted_for_selection = icon_item->details->is_highlighted_for_selection; @@ -1785,9 +1814,9 @@ map_pixbuf (CajaIconCanvasItem *icon_item) icon_item->details->rendered_is_focused = gtk_widget_has_focus (GTK_WIDGET (EEL_CANVAS_ITEM (icon_item)->canvas)); } - g_object_ref (icon_item->details->rendered_pixbuf); + cairo_surface_reference (icon_item->details->rendered_surface); - return icon_item->details->rendered_pixbuf; + return icon_item->details->rendered_surface; } static void @@ -1863,7 +1892,8 @@ caja_icon_canvas_item_draw (EelCanvasItem *item, CajaIconCanvasItemDetails *details; EelIRect icon_rect, emblem_rect; EmblemLayout emblem_layout; - GdkPixbuf *emblem_pixbuf, *temp_pixbuf; + GdkPixbuf *emblem_pixbuf; + cairo_surface_t *temp_surface; GtkStyleContext *context; container = CAJA_ICON_CONTAINER (item->canvas); @@ -1884,12 +1914,12 @@ caja_icon_canvas_item_draw (EelCanvasItem *item, icon_rect = icon_item->details->canvas_rect; - temp_pixbuf = map_pixbuf (icon_item); + temp_surface = map_surface (icon_item); - gtk_render_icon (context, cr, - temp_pixbuf, - icon_rect.x0, icon_rect.y0); - g_object_unref (temp_pixbuf); + gtk_render_icon_surface (context, cr, + temp_surface, + icon_rect.x0, icon_rect.y0); + cairo_surface_destroy (temp_surface); draw_embedded_text (icon_item, cr, icon_rect.x0, icon_rect.y0); @@ -2360,6 +2390,7 @@ caja_icon_canvas_item_ensure_bounds_up_to_date (CajaIconCanvasItem *icon_item) EelIRect total_rect, total_rect_for_layout, total_rect_for_entire_text; EelCanvasItem *item; double pixels_per_unit; + gint width, height; EmblemLayout emblem_layout; GdkPixbuf *emblem_pixbuf; gboolean is_rtl; @@ -2378,20 +2409,13 @@ caja_icon_canvas_item_ensure_bounds_up_to_date (CajaIconCanvasItem *icon_item) icon_rect.y0 = 0; icon_rect_raw.x0 = 0; icon_rect_raw.y0 = 0; - if (details->pixbuf == NULL) - { - icon_rect.x1 = icon_rect.x0; - icon_rect.y1 = icon_rect.y0; - icon_rect_raw.x1 = icon_rect_raw.x0; - icon_rect_raw.y1 = icon_rect_raw.y0; - } - else - { - icon_rect_raw.x1 = icon_rect_raw.x0 + gdk_pixbuf_get_width (details->pixbuf); - icon_rect_raw.y1 = icon_rect_raw.y0 + gdk_pixbuf_get_height (details->pixbuf); - icon_rect.x1 = icon_rect_raw.x1 / pixels_per_unit; - icon_rect.y1 = icon_rect_raw.y1 / pixels_per_unit; - } + + get_scaled_icon_size (icon_item, &width, &height); + + icon_rect_raw.x1 = icon_rect_raw.x0 + width; + icon_rect_raw.y1 = icon_rect_raw.y0 + height; + icon_rect.x1 = icon_rect_raw.x1 / pixels_per_unit; + icon_rect.y1 = icon_rect_raw.y1 / pixels_per_unit; /* Compute text rectangle. */ text_rect = compute_text_rectangle (icon_item, icon_rect, FALSE, BOUNDS_USAGE_FOR_DISPLAY); @@ -2430,18 +2454,17 @@ caja_icon_canvas_item_get_icon_rectangle (const CajaIconCanvasItem *item) { EelDRect rectangle; double pixels_per_unit; - GdkPixbuf *pixbuf; + gint width, height; g_return_val_if_fail (CAJA_IS_ICON_CANVAS_ITEM (item), eel_drect_empty); rectangle.x0 = item->details->x; rectangle.y0 = item->details->y; - pixbuf = item->details->pixbuf; - pixels_per_unit = EEL_CANVAS_ITEM (item)->canvas->pixels_per_unit; - rectangle.x1 = rectangle.x0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_width (pixbuf)) / pixels_per_unit; - rectangle.y1 = rectangle.y0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_height (pixbuf)) / pixels_per_unit; + get_scaled_icon_size (EEL_CANVAS_ITEM (item), &width, &height); + rectangle.x1 = rectangle.x0 + width / pixels_per_unit; + rectangle.y1 = rectangle.y0 + height / pixels_per_unit; eel_canvas_item_i2w (EEL_CANVAS_ITEM (item), &rectangle.x0, @@ -2462,18 +2485,17 @@ caja_icon_canvas_item_get_text_rectangle (CajaIconCanvasItem *item, EelIRect text_rectangle; EelDRect ret; double pixels_per_unit; - GdkPixbuf *pixbuf; + gint width, height; g_return_val_if_fail (CAJA_IS_ICON_CANVAS_ITEM (item), eel_drect_empty); icon_rectangle.x0 = item->details->x; icon_rectangle.y0 = item->details->y; - pixbuf = item->details->pixbuf; - pixels_per_unit = EEL_CANVAS_ITEM (item)->canvas->pixels_per_unit; - icon_rectangle.x1 = icon_rectangle.x0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_width (pixbuf)) / pixels_per_unit; - icon_rectangle.y1 = icon_rectangle.y0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_height (pixbuf)) / pixels_per_unit; + get_scaled_icon_size (item, &width, &height); + icon_rectangle.x1 = icon_rectangle.x0 + width / pixels_per_unit; + icon_rectangle.y1 = icon_rectangle.y0 + height / pixels_per_unit; measure_label_text (item); @@ -2495,27 +2517,27 @@ caja_icon_canvas_item_get_text_rectangle (CajaIconCanvasItem *item, return ret; } - /* Get the rectangle of the icon only, in canvas coordinates. */ static void get_icon_canvas_rectangle (CajaIconCanvasItem *item, EelIRect *rect) { - GdkPixbuf *pixbuf; + gint width, height; g_assert (CAJA_IS_ICON_CANVAS_ITEM (item)); g_assert (rect != NULL); + eel_canvas_w2c (EEL_CANVAS_ITEM (item)->canvas, item->details->x, item->details->y, &rect->x0, &rect->y0); - pixbuf = item->details->pixbuf; + get_scaled_icon_size (item, &width, &height); - rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_width (pixbuf)); - rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_height (pixbuf)); + rect->x1 = rect->x0 + width; + rect->y1 = rect->y0 + height; } void @@ -3114,15 +3136,7 @@ caja_icon_canvas_item_accessible_get_image_size item = CAJA_ICON_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (image))); - if (!item || !item->details->pixbuf) - { - *width = *height = 0; - } - else - { - *width = gdk_pixbuf_get_width (item->details->pixbuf); - *height = gdk_pixbuf_get_height (item->details->pixbuf); - } + get_scaled_icon_size (item, width, height); } static void @@ -3224,7 +3238,7 @@ caja_icon_canvas_item_accessible_get_offset_at_point (AtkText *text, char *icon_text; gboolean have_editable; gboolean have_additional; - gint text_offset; + gint text_offset, height; atk_component_get_extents (ATK_COMPONENT (text), &real_x, &real_y, &real_width, &real_height, coords); @@ -3236,7 +3250,8 @@ caja_icon_canvas_item_accessible_get_offset_at_point (AtkText *text, if (item->details->pixbuf) { - y -= gdk_pixbuf_get_height (item->details->pixbuf); + get_scaled_icon_size (item, NULL, &height); + y -= height; } have_editable = item->details->editable_text != NULL && item->details->editable_text[0] != '\0'; @@ -3353,14 +3368,15 @@ caja_icon_canvas_item_accessible_get_character_extents (AtkText *text, PangoRectangle rect; PangoRectangle rect0; gboolean have_editable; - gint text_offset; + gint text_offset, pix_height; atk_component_get_extents (ATK_COMPONENT (text), &pos_x, &pos_y, NULL, NULL, coords); item = CAJA_ICON_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text))); if (item->details->pixbuf) { - pos_y += gdk_pixbuf_get_height (item->details->pixbuf); + get_scaled_icon_size (item, NULL, &pix_height); + pos_y += pix_height; } have_editable = item->details->editable_text != NULL && -- cgit v1.2.1