From e9ecff6c51b4e84fc350ccfe972439ed8dbe7215 Mon Sep 17 00:00:00 2001 From: Wolfgang Ulbrich Date: Mon, 11 Jan 2016 15:04:04 +0100 Subject: GTK3 icon-canvas-item: use gtk_render_* methods instead of direct cairo Instead of hardcoding colors and using direct cairo calls to draw the canvas items frame/background/labels, use gtk_render_* methods directly. This has the advantage of making them more friendly with GTK+ themes (by adding a caja-canvas-item style class to the canvas context when drawing) and removes a ton of convolut taken from: https://git.gnome.org/browse/nautilus/commit/?id=95910c9 --- libcaja-private/caja-icon-canvas-item.c | 385 ++++++++++++++++++++------------ 1 file changed, 243 insertions(+), 142 deletions(-) diff --git a/libcaja-private/caja-icon-canvas-item.c b/libcaja-private/caja-icon-canvas-item.c index 858a7393..d62f2c66 100644 --- a/libcaja-private/caja-icon-canvas-item.c +++ b/libcaja-private/caja-icon-canvas-item.c @@ -224,21 +224,15 @@ static void draw_pixbuf (GdkPixbuf static PangoLayout *get_label_layout (PangoLayout **layout, CajaIconCanvasItem *item, const char *text); +#if !GTK_CHECK_VERSION(3,0,0) static void draw_label_layout (CajaIconCanvasItem *item, -#if GTK_CHECK_VERSION(3,0,0) - cairo_t *cr, -#else GdkDrawable *drawable, -#endif PangoLayout *layout, gboolean highlight, -#if GTK_CHECK_VERSION(3,0,0) - GdkRGBA *label_color, -#else GdkColor *label_color, -#endif int x, int y); +#endif static gboolean hit_test_stretch_handle (CajaIconCanvasItem *item, EelIRect canvas_rect, GtkCornerType *corner); @@ -546,12 +540,19 @@ caja_icon_canvas_item_get_image (CajaIconCanvasItem *item, double item_x, item_y; gboolean is_rtl; cairo_t *cr; +#if GTK_CHECK_VERSION(3,0,0) + GtkStyleContext *context; +#endif g_return_val_if_fail (CAJA_IS_ICON_CANVAS_ITEM (item), NULL); canvas = EEL_CANVAS_ITEM (item)->canvas; #if GTK_CHECK_VERSION(3,0,0) screen = gtk_widget_get_screen (GTK_WIDGET (canvas)); + context = gtk_widget_get_style_context (GTK_WIDGET (canvas)); + + gtk_style_context_save (context); + gtk_style_context_add_class (context, "caja-canvas-item"); #else screen = gdk_colormap_get_screen (colormap); #endif @@ -577,12 +578,9 @@ caja_icon_canvas_item_get_image (CajaIconCanvasItem *item, width, height); cr = cairo_create (surface); - gdk_cairo_set_source_pixbuf (cr, item->details->pixbuf, + + gtk_render_icon (context, cr, item->details->pixbuf, item_offset_x, item_offset_y); - cairo_rectangle (cr, item_offset_x, item_offset_y, - gdk_pixbuf_get_width (item->details->pixbuf), - gdk_pixbuf_get_height (item->details->pixbuf)); - cairo_fill (cr); #else pixmap = gdk_pixmap_new (gdk_screen_get_root_window (screen), width, height, @@ -626,6 +624,8 @@ caja_icon_canvas_item_get_image (CajaIconCanvasItem *item, draw_label_text (item, cr, FALSE, icon_rect); cairo_destroy (cr); + gtk_style_context_restore (context); + return surface; #else while (emblem_layout_next (&emblem_layout, &emblem_pixbuf, &emblem_rect, is_rtl)) @@ -997,7 +997,7 @@ in_single_click_mode (void) return click_policy_auto_value == CAJA_CLICK_POLICY_SINGLE; } - +#if !GTK_CHECK_VERSION(3,0,0) /* Utility routine to create a rectangle with rounded corners. * This could possibly move to Eel as a general purpose routine. */ @@ -1041,24 +1041,15 @@ make_round_rect (cairo_t *cr, static void draw_frame (CajaIconCanvasItem *item, -#if GTK_CHECK_VERSION(3,0,0) - cairo_t *cr, - GdkRGBA *color, -#else GdkDrawable *drawable, guint color, -#endif gboolean create_mask, int x, int y, int width, int height) { -#if GTK_CHECK_VERSION(3,0,0) - cairo_save (cr); -#else cairo_t *cr = gdk_cairo_create (drawable); -#endif /* Set the rounded rect clip region. Magic rounding value taken * from old code. @@ -1073,26 +1064,18 @@ draw_frame (CajaIconCanvasItem *item, */ } -#if GTK_CHECK_VERSION(3,0,0) - gdk_cairo_set_source_rgba (cr, color); -#else cairo_set_source_rgba (cr, EEL_RGBA_COLOR_GET_R (color) / 255.0, EEL_RGBA_COLOR_GET_G (color) / 255.0, EEL_RGBA_COLOR_GET_B (color) / 255.0, EEL_RGBA_COLOR_GET_A (color) / 255.0); -#endif /* Paint into drawable now that we have set up the color and opacity */ cairo_fill (cr); -#if GTK_CHECK_VERSION(3,0,0) - cairo_restore (cr); -#else cairo_destroy (cr); -#endif } - +#endif /* Keep these for a bit while we work on performance of draw_or_measure_label_text. */ /* #define PERFORMANCE_TEST_DRAW_DISABLE @@ -1393,9 +1376,190 @@ static void draw_label_text (CajaIconCanvasItem *item, #if GTK_CHECK_VERSION(3,0,0) cairo_t *cr, + gboolean create_mask, + EelIRect icon_rect) +{ + CajaIconCanvasItemDetails *details; + CajaIconContainer *container; + PangoLayout *editable_layout; + PangoLayout *additional_layout; + GtkStyleContext *context; + GtkStateFlags state; + gboolean have_editable, have_additional; + gboolean needs_highlight, prelight_label, is_rtl_label_beside; + EelIRect text_rect; + int x; + int max_text_width; + gdouble frame_w, frame_h, frame_x, frame_y; + gboolean draw_frame = TRUE; + +#ifdef PERFORMANCE_TEST_DRAW_DISABLE + return; +#endif + + details = item->details; + + measure_label_text (item); + if (details->text_height == 0 || + details->text_width == 0) + { + return; + } + + container = CAJA_ICON_CONTAINER (EEL_CANVAS_ITEM (item)->canvas); + context = gtk_widget_get_style_context (GTK_WIDGET (container)); + + text_rect = compute_text_rectangle (item, icon_rect, TRUE, BOUNDS_USAGE_FOR_DISPLAY); + + needs_highlight = details->is_highlighted_for_selection || details->is_highlighted_for_drop; + is_rtl_label_beside = caja_icon_container_is_layout_rtl (container) && + container->details->label_position == CAJA_ICON_LABEL_POSITION_BESIDE; + + editable_layout = NULL; + additional_layout = NULL; + + have_editable = details->editable_text != NULL && details->editable_text[0] != '\0'; + have_additional = details->additional_text != NULL && details->additional_text[0] != '\0'; + g_assert (have_editable || have_additional); + + max_text_width = floor (caja_icon_canvas_item_get_max_text_width (item)); + + state = GTK_STATE_FLAG_NORMAL; + gtk_widget_style_get (GTK_WIDGET (container), + "activate_prelight_icon_label", &prelight_label, + NULL); + + /* if the icon is highlighted, do some set-up */ + if (needs_highlight && + !details->is_renaming) { + if (gtk_widget_has_focus (GTK_WIDGET (container))) { + state |= GTK_STATE_FLAG_SELECTED; + } else { + state |= GTK_STATE_FLAG_ACTIVE; + } + + frame_x = is_rtl_label_beside ? text_rect.x0 + item->details->text_dx : text_rect.x0; + frame_y = text_rect.y0; + frame_w = is_rtl_label_beside ? text_rect.x1 - text_rect.x0 - item->details->text_dx : text_rect.x1 - text_rect.x0; + frame_h = text_rect.y1 - text_rect.y0; + } else if (!needs_highlight && have_editable && + details->text_width > 0 && details->text_height > 0 && + prelight_label && item->details->is_prelit) { + state |= GTK_STATE_FLAG_PRELIGHT; + + frame_x = text_rect.x0; + frame_y = text_rect.y0; + frame_w = text_rect.x1 - text_rect.x0; + frame_h = text_rect.y1 - text_rect.y0; + } else { + draw_frame = FALSE; + } + + if (draw_frame) { + gtk_style_context_save (context); + gtk_style_context_set_state (context, state); + + gtk_render_frame (context, cr, + frame_x, frame_y, + frame_w, frame_h); + gtk_render_background (context, cr, + frame_x, frame_y, + frame_w, frame_h); + + gtk_style_context_restore (context); + } + + if (container->details->label_position == CAJA_ICON_LABEL_POSITION_BESIDE) + { + x = text_rect.x0 + 2; + } + else + { + x = text_rect.x0 + ((text_rect.x1 - text_rect.x0) - max_text_width) / 2; + } + + if (have_editable) + { + state = GTK_STATE_FLAG_NORMAL; + + if (prelight_label && item->details->is_prelit) { + state |= GTK_STATE_FLAG_PRELIGHT; + } + + if (needs_highlight && gtk_widget_has_focus (GTK_WIDGET (container))) { + state |= GTK_STATE_FLAG_SELECTED; + } else if (needs_highlight) { + state |= GTK_STATE_FLAG_ACTIVE; + } + + editable_layout = get_label_layout (&item->details->editable_text_layout, item, item->details->editable_text); + prepare_pango_layout_for_draw (item, editable_layout); + + gtk_style_context_save (context); + gtk_style_context_set_state (context, state); + + gtk_render_layout (context, cr, + x, text_rect.y0 + TEXT_BACK_PADDING_Y, + editable_layout); + + gtk_style_context_restore (context); + } + + if (have_additional) + { + state = GTK_STATE_FLAG_NORMAL; + + if (needs_highlight && gtk_widget_has_focus (GTK_WIDGET (container))) { + state |= GTK_STATE_FLAG_SELECTED; + } else if (needs_highlight) { + state |= GTK_STATE_FLAG_ACTIVE; + } + + additional_layout = get_label_layout (&item->details->additional_text_layout, item, item->details->additional_text); + prepare_pango_layout_for_draw (item, additional_layout); + + gtk_style_context_save (context); + gtk_style_context_set_state (context, state); + gtk_style_context_add_class (context, "dim-label"); + + gtk_render_layout (context, cr, + x, text_rect.y0 + details->editable_text_height + LABEL_LINE_SPACING + TEXT_BACK_PADDING_Y, + additional_layout); + } + + if (!create_mask && item->details->is_highlighted_as_keyboard_focus) + { + if (needs_highlight) { + state = GTK_STATE_FLAG_SELECTED; + } else { + state = GTK_STATE_FLAG_ACTIVE; + } + + gtk_style_context_save (context); + gtk_style_context_set_state (context, state); + + gtk_render_focus (context, + cr, + text_rect.x0, + text_rect.y0, + text_rect.x1 - text_rect.x0, + text_rect.y1 - text_rect.y0); + + gtk_style_context_restore (context); + } + + if (editable_layout != NULL) + { + g_object_unref (editable_layout); + } + + if (additional_layout != NULL) + { + g_object_unref (additional_layout); + } +} #else GdkDrawable *drawable, -#endif gboolean create_mask, EelIRect icon_rect) { @@ -1404,17 +1568,9 @@ draw_label_text (CajaIconCanvasItem *item, CajaIconContainer *container; PangoLayout *editable_layout; PangoLayout *additional_layout; -#if GTK_CHECK_VERSION(3,0,0) - GdkRGBA label_color; -#else GdkColor *label_color; -#endif gboolean have_editable, have_additional; -#if GTK_CHECK_VERSION(3,0,0) - gboolean needs_highlight, prelight_label, is_rtl_label_beside; -#else gboolean needs_frame, needs_highlight, prelight_label, is_rtl_label_beside; -#endif EelIRect text_rect; int x; int max_text_width; @@ -1423,7 +1579,6 @@ draw_label_text (CajaIconCanvasItem *item, return; #endif - canvas_item = EEL_CANVAS_ITEM (item); details = item->details; measure_label_text (item); @@ -1434,6 +1589,7 @@ draw_label_text (CajaIconCanvasItem *item, } container = CAJA_ICON_CONTAINER (EEL_CANVAS_ITEM (item)->canvas); + canvas_item = EEL_CANVAS_ITEM (item); text_rect = compute_text_rectangle (item, icon_rect, TRUE, BOUNDS_USAGE_FOR_DISPLAY); @@ -1450,23 +1606,16 @@ draw_label_text (CajaIconCanvasItem *item, max_text_width = floor (caja_icon_canvas_item_get_max_text_width (item)); - /* if the icon is highlighted, do some set-up */ if (needs_highlight && !details->is_renaming) { draw_frame (item, -#if GTK_CHECK_VERSION(3,0,0) - cr, - gtk_widget_has_focus (GTK_WIDGET (container)) ? &container->details->highlight_color_rgba : &container->details->active_color_rgba, -#else drawable, gtk_widget_has_focus (GTK_WIDGET (container)) ? container->details->highlight_color_rgba : container->details->active_color_rgba, -#endif create_mask, is_rtl_label_beside ? text_rect.x0 + item->details->text_dx : text_rect.x0, text_rect.y0, is_rtl_label_beside ? text_rect.x1 - text_rect.x0 - item->details->text_dx : text_rect.x1 - text_rect.x0, text_rect.y1 - text_rect.y0); -#if !GTK_CHECK_VERSION(3,0,0) } else if (!needs_highlight && !details->is_renaming && (details->is_prelit || @@ -1478,7 +1627,6 @@ draw_label_text (CajaIconCanvasItem *item, text_rect.y0, text_rect.x1 - text_rect.x0, text_rect.y1 - text_rect.y0); -#endif } if (container->details->label_position == CAJA_ICON_LABEL_POSITION_BESIDE) @@ -1496,19 +1644,9 @@ draw_label_text (CajaIconCanvasItem *item, prepare_pango_layout_for_draw (item, editable_layout); gtk_widget_style_get (GTK_WIDGET (container), -#if !GTK_CHECK_VERSION(3,0,0) "frame_text", &needs_frame, -#endif "activate_prelight_icon_label", &prelight_label, NULL); -#if GTK_CHECK_VERSION(3,0,0) - if (!needs_highlight && details->text_width > 0 && details->text_height > 0) - { - if (prelight_label && item->details->is_prelit) { - draw_frame (item, - cr, - &container->details->prelight_color_rgba, -#else if (needs_frame && !needs_highlight && details->text_width > 0 && details->text_height > 0) { if (!(prelight_label && item->details->is_prelit)) @@ -1527,7 +1665,6 @@ draw_label_text (CajaIconCanvasItem *item, draw_frame (item, drawable, container->details->prelight_color_rgba, -#endif create_mask, text_rect.x0, text_rect.y0, @@ -1542,15 +1679,9 @@ draw_label_text (CajaIconCanvasItem *item, prelight_label & item->details->is_prelit); draw_label_layout (item, -#if GTK_CHECK_VERSION(3,0,0) - cr, - editable_layout, needs_highlight, - &label_color, -#else drawable, editable_layout, needs_highlight, label_color, -#endif x, text_rect.y0 + TEXT_BACK_PADDING_Y); } @@ -1566,50 +1697,25 @@ draw_label_text (CajaIconCanvasItem *item, FALSE); draw_label_layout (item, -#if GTK_CHECK_VERSION(3,0,0) - cr, - additional_layout, needs_highlight, - &label_color, -#else drawable, additional_layout, needs_highlight, label_color, -#endif x, text_rect.y0 + details->editable_text_height + LABEL_LINE_SPACING + TEXT_BACK_PADDING_Y); } if (!create_mask && item->details->is_highlighted_as_keyboard_focus) { -#if GTK_CHECK_VERSION(3,0,0) - GtkStyleContext *style; - - style = gtk_widget_get_style_context (GTK_WIDGET (EEL_CANVAS_ITEM (item)->canvas)); - - gtk_style_context_save (style); - gtk_style_context_add_class (style, "icon-container"); - gtk_style_context_set_state (style, - needs_highlight ? - GTK_STATE_FLAG_SELECTED : GTK_STATE_FLAG_ACTIVE); - - gtk_render_focus (style, - cr, -#else gtk_paint_focus (gtk_widget_get_style (GTK_WIDGET (EEL_CANVAS_ITEM (item)->canvas)), drawable, needs_highlight ? GTK_STATE_SELECTED : GTK_STATE_NORMAL, NULL, GTK_WIDGET (EEL_CANVAS_ITEM (item)->canvas), "icon-container", -#endif text_rect.x0, text_rect.y0, text_rect.x1 - text_rect.x0, text_rect.y1 - text_rect.y0); -#if GTK_CHECK_VERSION(3,0,0) - - gtk_style_context_restore (style); -#endif } if (editable_layout != NULL) @@ -1622,6 +1728,7 @@ draw_label_text (CajaIconCanvasItem *item, g_object_unref (additional_layout); } } +#endif void caja_icon_canvas_item_set_is_visible (CajaIconCanvasItem *item, @@ -1942,7 +2049,10 @@ real_map_pixbuf (CajaIconCanvasItem *icon_item) CajaIconContainer *container; GdkPixbuf *temp_pixbuf, *old_pixbuf, *audio_pixbuf; int emblem_size; -#if !GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3,0,0) + GtkStyleContext *style; + GdkRGBA color; +#else guint render_mode, saturation, brightness, lighten; #endif @@ -2029,15 +2139,16 @@ real_map_pixbuf (CajaIconCanvasItem *icon_item) || icon_item->details->is_highlighted_for_drop) { #if GTK_CHECK_VERSION(3,0,0) - GdkRGBA *color; - - old_pixbuf = temp_pixbuf; + style = gtk_widget_get_style_context (GTK_WIDGET (canvas)); - color = gtk_widget_has_focus (GTK_WIDGET (canvas)) ? - &CAJA_ICON_CONTAINER (canvas)->details->highlight_color_rgba : - &CAJA_ICON_CONTAINER (canvas)->details->active_color_rgba; + if (gtk_widget_has_focus (GTK_WIDGET (canvas))) { + gtk_style_context_get_background_color (style, GTK_STATE_FLAG_SELECTED, &color); + } else { + gtk_style_context_get_background_color (style, GTK_STATE_FLAG_ACTIVE, &color); + } - temp_pixbuf = eel_create_colorized_pixbuf (temp_pixbuf, color); + old_pixbuf = temp_pixbuf; + temp_pixbuf = eel_create_colorized_pixbuf (temp_pixbuf, &color); #else guint color; @@ -2186,19 +2297,28 @@ static void caja_icon_canvas_item_draw (EelCanvasItem *item, cairo_t *cr, cairo_region_t *region) +{ + CajaIconContainer *container; #else caja_icon_canvas_item_draw (EelCanvasItem *item, GdkDrawable *drawable, GdkEventExpose *expose) -#endif { +#endif CajaIconCanvasItem *icon_item; CajaIconCanvasItemDetails *details; EelIRect icon_rect, emblem_rect; EmblemLayout emblem_layout; GdkPixbuf *emblem_pixbuf, *temp_pixbuf; +#if GTK_CHECK_VERSION(3,0,0) + GtkStyleContext *context; + + container = CAJA_ICON_CONTAINER (item->canvas); + gboolean is_rtl; +#else GdkRectangle pixbuf_rect; gboolean is_rtl; +#endif icon_item = CAJA_ICON_CANVAS_ITEM (item); details = icon_item->details; @@ -2208,8 +2328,23 @@ caja_icon_canvas_item_draw (EelCanvasItem *item, GdkDrawable *drawable, return; } +#if GTK_CHECK_VERSION(3,0,0) + context = gtk_widget_get_style_context (GTK_WIDGET (container)); + gtk_style_context_save (context); + gtk_style_context_add_class (context, "caja-canvas-item"); + +#endif icon_rect = icon_item->details->canvas_rect; +#if GTK_CHECK_VERSION(3,0,0) + temp_pixbuf = map_pixbuf (icon_item); + gtk_render_icon (context, cr, + temp_pixbuf, + icon_rect.x0, icon_rect.y0); + g_object_unref (temp_pixbuf); + + draw_embedded_text (icon_item, cr, icon_rect.x0, icon_rect.y0); +#else /* if the pre-lit or selection flag is set, make a pre-lit or darkened pixbuf and draw that instead */ /* and colorize normal pixbuf if rc wants that */ temp_pixbuf = map_pixbuf (icon_item); @@ -2218,26 +2353,15 @@ caja_icon_canvas_item_draw (EelCanvasItem *item, GdkDrawable *drawable, pixbuf_rect.width = gdk_pixbuf_get_width (temp_pixbuf); pixbuf_rect.height = gdk_pixbuf_get_height (temp_pixbuf); -#if GTK_CHECK_VERSION(3,0,0) - cairo_save (cr); -#else cairo_t *cr = gdk_cairo_create (drawable); gdk_cairo_rectangle (cr, &expose->area); cairo_clip (cr); -#endif gdk_cairo_set_source_pixbuf (cr, temp_pixbuf, pixbuf_rect.x, pixbuf_rect.y); gdk_cairo_rectangle (cr, &pixbuf_rect); cairo_fill (cr); -#if GTK_CHECK_VERSION(3,0,0) - cairo_restore (cr); -#else cairo_destroy (cr); -#endif g_object_unref (temp_pixbuf); -#if GTK_CHECK_VERSION(3,0,0) - draw_embedded_text (icon_item, cr, icon_rect.x0, icon_rect.y0); -#else draw_embedded_text (icon_item, drawable, icon_rect.x0, icon_rect.y0); #endif @@ -2249,18 +2373,19 @@ caja_icon_canvas_item_draw (EelCanvasItem *item, GdkDrawable *drawable, { #if GTK_CHECK_VERSION(3,0,0) draw_pixbuf (emblem_pixbuf, cr, emblem_rect.x0, emblem_rect.y0); -#else - draw_pixbuf (emblem_pixbuf, drawable, emblem_rect.x0, emblem_rect.y0); -#endif } -#if GTK_CHECK_VERSION(3,0,0) /* Draw stretching handles (if necessary). */ draw_stretch_handles (icon_item, cr, &icon_rect); /* Draw the label text. */ draw_label_text (icon_item, cr, FALSE, icon_rect); + + gtk_style_context_restore (context); #else + draw_pixbuf (emblem_pixbuf, drawable, emblem_rect.x0, emblem_rect.y0); + } + draw_stretch_handles (icon_item, drawable, &icon_rect); draw_label_text (icon_item, drawable, FALSE, icon_rect); #endif @@ -2379,18 +2504,9 @@ get_label_layout (PangoLayout **layout_cache, return layout; } +#if !GTK_CHECK_VERSION(3,0,0) static void draw_label_layout (CajaIconCanvasItem *item, -#if GTK_CHECK_VERSION(3,0,0) - cairo_t *cr, - PangoLayout *layout, - gboolean highlight, - GdkRGBA *label_color, - int x, - int y) -{ - GdkRGBA black = { 0, 0, 0, 1 }; -#else GdkDrawable *drawable, PangoLayout *layout, gboolean highlight, @@ -2399,7 +2515,6 @@ draw_label_layout (CajaIconCanvasItem *item, int y) { g_return_if_fail (drawable != NULL); -#endif if (item->details->is_renaming) { @@ -2409,36 +2524,22 @@ draw_label_layout (CajaIconCanvasItem *item, if (!highlight && (CAJA_ICON_CONTAINER (EEL_CANVAS_ITEM (item)->canvas)->details->use_drop_shadows)) { /* draw a drop shadow */ -#if GTK_CHECK_VERSION(3,0,0) - eel_cairo_draw_layout_with_drop_shadow (cr, - label_color, - &black, -#else eel_gdk_draw_layout_with_drop_shadow (drawable, label_color, >k_widget_get_style (GTK_WIDGET (EEL_CANVAS_ITEM (item)->canvas))->black, -#endif x, y, layout); } else { -#if GTK_CHECK_VERSION(3,0,0) - cairo_save (cr); - gdk_cairo_set_source_rgba (cr, label_color); -#else cairo_t *cr = gdk_cairo_create (drawable); gdk_cairo_set_source_color (cr, label_color); -#endif cairo_move_to (cr, x, y); pango_cairo_show_layout (cr, layout); -#if GTK_CHECK_VERSION(3,0,0) - cairo_restore (cr); -#else cairo_destroy (cr); -#endif } } +#endif /* handle events */ -- cgit v1.2.1