static void _gtk_theming_background_init_context (GtkThemingBackground *bg, double width, double height, GtkJunctionSides junction) { GtkStateFlags flags = gtk_style_context_get_state (bg->context); GtkBorder border, padding; gtk_style_context_get_border (bg->context, flags, &border); gtk_style_context_get_padding (bg->context, flags, &padding); /* In the CSS box model, by default the background positioning area is * the padding-box, i.e. all the border-box minus the borders themselves, * which determines also its default size, see * http://dev.w3.org/csswg/css3-background/#background-origin * * In the future we might want to support different origins or clips, but * right now we just shrink to the default. */ _gtk_rounded_box_init_rect (&bg->boxes[GTK_CSS_AREA_BORDER_BOX], 0, 0, width, height); _gtk_rounded_box_apply_border_radius_for_context (&bg->boxes[GTK_CSS_AREA_BORDER_BOX], bg->context, junction); bg->boxes[GTK_CSS_AREA_PADDING_BOX] = bg->boxes[GTK_CSS_AREA_BORDER_BOX]; _gtk_rounded_box_shrink (&bg->boxes[GTK_CSS_AREA_PADDING_BOX], border.top, border.right, border.bottom, border.left); bg->boxes[GTK_CSS_AREA_CONTENT_BOX] = bg->boxes[GTK_CSS_AREA_PADDING_BOX]; _gtk_rounded_box_shrink (&bg->boxes[GTK_CSS_AREA_CONTENT_BOX], padding.top, padding.right, padding.bottom, padding.left); }
/* * gtk_render_content_path: * @context: style context to get style information from * @cr: cairo context to add path to * @x: x coordinate of CSS box * @y: y coordinate of CSS box * @width: width of CSS box * @height: height of CSS box * * Adds the path of the content box to @cr for a given border box. * This function respects rounded corners. * * This is useful if you are drawing content that is supposed to * fill the whole content area, like the color buttons in * #GtkColorChooserDialog. **/ void gtk_render_content_path (GtkStyleContext *context, cairo_t *cr, double x, double y, double width, double height) { GtkRoundedBox box; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); _gtk_rounded_box_init_rect (&box, x, y, width, height); _gtk_rounded_box_apply_border_radius_for_style (&box, gtk_style_context_lookup_style (context), 0); _gtk_rounded_box_shrink (&box, _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100) + _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_TOP), 100), _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100) + _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_RIGHT), 100), _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100) + _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_BOTTOM), 100), _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100) + _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_LEFT), 100)); _gtk_rounded_box_path (&box, cr); }
static void _gtk_theming_background_init_context (GtkThemingBackground *bg) { bg->flags = gtk_style_context_get_state (bg->context); gtk_style_context_get_border (bg->context, bg->flags, &bg->border); gtk_style_context_get_padding (bg->context, bg->flags, &bg->padding); gtk_style_context_get_background_color (bg->context, bg->flags, &bg->bg_color); /* In the CSS box model, by default the background positioning area is * the padding-box, i.e. all the border-box minus the borders themselves, * which determines also its default size, see * http://dev.w3.org/csswg/css3-background/#background-origin * * In the future we might want to support different origins or clips, but * right now we just shrink to the default. */ _gtk_rounded_box_init_rect (&bg->border_box, 0, 0, bg->paint_area.width, bg->paint_area.height); _gtk_rounded_box_apply_border_radius_for_context (&bg->border_box, bg->context, bg->junction); bg->padding_box = bg->border_box; _gtk_rounded_box_shrink (&bg->padding_box, bg->border.top, bg->border.right, bg->border.bottom, bg->border.left); }
static void _gtk_theming_background_apply_clip (GtkThemingBackground *bg, GtkRoundedBox *box, GtkCssArea clip) { if (clip == GTK_CSS_AREA_PADDING_BOX) { _gtk_rounded_box_shrink (box, bg->border.top, bg->border.right, bg->border.bottom, bg->border.left); } else if (clip == GTK_CSS_AREA_CONTENT_BOX) { _gtk_rounded_box_shrink (box, bg->border.top + bg->padding.top, bg->border.right + bg->padding.right, bg->border.bottom + bg->padding.bottom, bg->border.left + bg->padding.left); } }
void gtk_css_style_render_outline (GtkCssStyle *style, cairo_t *cr, gdouble x, gdouble y, gdouble width, gdouble height) { GtkBorderStyle border_style[4]; GtkRoundedBox border_box; double border_width[4]; GdkRGBA colors[4]; border_style[0] = _gtk_css_border_style_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_STYLE)); if (border_style[0] != GTK_BORDER_STYLE_NONE) { int offset; border_style[1] = border_style[2] = border_style[3] = border_style[0]; border_width[0] = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_WIDTH), 100); border_width[3] = border_width[2] = border_width[1] = border_width[0]; colors[0] = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_COLOR)); colors[3] = colors[2] = colors[1] = colors[0]; offset = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_OFFSET), 100); _gtk_rounded_box_init_rect (&border_box, x, y, width, height); _gtk_rounded_box_shrink (&border_box, - border_width[GTK_CSS_TOP] - offset, - border_width[GTK_CSS_RIGHT] - offset, - border_width[GTK_CSS_LEFT] - offset, - border_width[GTK_CSS_BOTTOM] - offset); _gtk_rounded_box_apply_outline_radius_for_style (&border_box, style, GTK_JUNCTION_NONE); render_border (cr, &border_box, border_width, 0, colors, border_style); } }
static void render_border (cairo_t *cr, GtkRoundedBox *border_box, const double border_width[4], guint hidden_side, GdkRGBA colors[4], GtkBorderStyle border_style[4]) { guint i, j; cairo_save (cr); cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); for (i = 0; i < 4; i++) { if (hidden_side & (1 << i)) continue; /* NB: code below divides by this value */ /* a border smaller than this will not noticably modify * pixels on screen, and since we don't compare with 0, * we'll use this value */ if (border_width[i] < 1.0 / 1024) continue; switch (border_style[i]) { case GTK_BORDER_STYLE_NONE: case GTK_BORDER_STYLE_HIDDEN: case GTK_BORDER_STYLE_SOLID: break; case GTK_BORDER_STYLE_INSET: if (i == 1 || i == 2) color_shade (&colors[i], 1.8, &colors[i]); break; case GTK_BORDER_STYLE_OUTSET: if (i == 0 || i == 3) color_shade (&colors[i], 1.8, &colors[i]); break; case GTK_BORDER_STYLE_DOTTED: case GTK_BORDER_STYLE_DASHED: { guint dont_draw = hidden_side; for (j = 0; j < 4; j++) { if (border_style[j] == border_style[i]) hidden_side |= (1 << j); else dont_draw |= (1 << j); } render_frame_stroke (cr, border_box, border_width, colors, dont_draw, border_style[i]); } break; case GTK_BORDER_STYLE_DOUBLE: { GtkRoundedBox other_box; double other_border[4]; guint dont_draw = hidden_side; for (j = 0; j < 4; j++) { if (border_style[j] == GTK_BORDER_STYLE_DOUBLE) hidden_side |= (1 << j); else dont_draw |= (1 << j); other_border[j] = border_width[j] / 3; } render_frame_fill (cr, border_box, other_border, colors, dont_draw); other_box = *border_box; _gtk_rounded_box_shrink (&other_box, 2 * other_border[GTK_CSS_TOP], 2 * other_border[GTK_CSS_RIGHT], 2 * other_border[GTK_CSS_BOTTOM], 2 * other_border[GTK_CSS_LEFT]); render_frame_fill (cr, &other_box, other_border, colors, dont_draw); } break; case GTK_BORDER_STYLE_GROOVE: case GTK_BORDER_STYLE_RIDGE: { GtkRoundedBox other_box; GdkRGBA other_colors[4]; guint dont_draw = hidden_side; double other_border[4]; for (j = 0; j < 4; j++) { other_colors[j] = colors[j]; if ((j == 0 || j == 3) ^ (border_style[j] == GTK_BORDER_STYLE_RIDGE)) color_shade (&other_colors[j], 1.8, &other_colors[j]); else color_shade (&colors[j], 1.8, &colors[j]); if (border_style[j] == GTK_BORDER_STYLE_GROOVE || border_style[j] == GTK_BORDER_STYLE_RIDGE) hidden_side |= (1 << j); else dont_draw |= (1 << j); other_border[j] = border_width[j] / 2; } render_frame_fill (cr, border_box, other_border, colors, dont_draw); other_box = *border_box; _gtk_rounded_box_shrink (&other_box, other_border[GTK_CSS_TOP], other_border[GTK_CSS_RIGHT], other_border[GTK_CSS_BOTTOM], other_border[GTK_CSS_LEFT]); render_frame_fill (cr, &other_box, other_border, other_colors, dont_draw); } break; default: g_assert_not_reached (); break; } } render_frame_fill (cr, border_box, border_width, colors, hidden_side); cairo_restore (cr); }
static void render_frame_stroke (cairo_t *cr, GtkRoundedBox *border_box, const double border_width[4], GdkRGBA colors[4], guint hidden_side, GtkBorderStyle stroke_style) { gboolean different_colors, different_borders; GtkRoundedBox stroke_box; guint i; different_colors = !gdk_rgba_equal (&colors[0], &colors[1]) || !gdk_rgba_equal (&colors[0], &colors[2]) || !gdk_rgba_equal (&colors[0], &colors[3]); different_borders = border_width[0] != border_width[1] || border_width[0] != border_width[2] || border_width[0] != border_width[3] ; stroke_box = *border_box; _gtk_rounded_box_shrink (&stroke_box, border_width[GTK_CSS_TOP] / 2.0, border_width[GTK_CSS_RIGHT] / 2.0, border_width[GTK_CSS_BOTTOM] / 2.0, border_width[GTK_CSS_LEFT] / 2.0); if (!different_colors && !different_borders && hidden_side == 0) { double length = 0; /* FAST PATH: * Mostly expected to trigger for focus rectangles */ for (i = 0; i < 4; i++) { length += _gtk_rounded_box_guess_length (&stroke_box, i); } _gtk_rounded_box_path (&stroke_box, cr); gdk_cairo_set_source_rgba (cr, &colors[0]); set_stroke_style (cr, border_width[0], stroke_style, length); cairo_stroke (cr); } else { GtkRoundedBox padding_box; padding_box = *border_box; _gtk_rounded_box_shrink (&padding_box, border_width[GTK_CSS_TOP], border_width[GTK_CSS_RIGHT], border_width[GTK_CSS_BOTTOM], border_width[GTK_CSS_LEFT]); for (i = 0; i < 4; i++) { if (hidden_side & (1 << i)) continue; if (border_width[i] == 0) continue; cairo_save (cr); if (i == 0) _gtk_rounded_box_path_top (border_box, &padding_box, cr); else if (i == 1) _gtk_rounded_box_path_right (border_box, &padding_box, cr); else if (i == 2) _gtk_rounded_box_path_bottom (border_box, &padding_box, cr); else if (i == 3) _gtk_rounded_box_path_left (border_box, &padding_box, cr); cairo_clip (cr); _gtk_rounded_box_path_side (&stroke_box, cr, i); gdk_cairo_set_source_rgba (cr, &colors[i]); set_stroke_style (cr, border_width[i], stroke_style, _gtk_rounded_box_guess_length (&stroke_box, i)); cairo_stroke (cr); cairo_restore (cr); } } }
static void render_frame_fill (cairo_t *cr, GtkRoundedBox *border_box, const double border_width[4], GdkRGBA colors[4], guint hidden_side) { GtkRoundedBox padding_box; guint i, j; padding_box = *border_box; _gtk_rounded_box_shrink (&padding_box, border_width[GTK_CSS_TOP], border_width[GTK_CSS_RIGHT], border_width[GTK_CSS_BOTTOM], border_width[GTK_CSS_LEFT]); if (hidden_side == 0 && gdk_rgba_equal (&colors[0], &colors[1]) && gdk_rgba_equal (&colors[0], &colors[2]) && gdk_rgba_equal (&colors[0], &colors[3])) { gdk_cairo_set_source_rgba (cr, &colors[0]); _gtk_rounded_box_path (border_box, cr); _gtk_rounded_box_path (&padding_box, cr); cairo_fill (cr); } else { for (i = 0; i < 4; i++) { if (hidden_side & (1 << i)) continue; for (j = 0; j < 4; j++) { if (hidden_side & (1 << j)) continue; if (i == j || (gdk_rgba_equal (&colors[i], &colors[j]))) { /* We were already painted when i == j */ if (i > j) break; if (j == 0) _gtk_rounded_box_path_top (border_box, &padding_box, cr); else if (j == 1) _gtk_rounded_box_path_right (border_box, &padding_box, cr); else if (j == 2) _gtk_rounded_box_path_bottom (border_box, &padding_box, cr); else if (j == 3) _gtk_rounded_box_path_left (border_box, &padding_box, cr); } } /* We were already painted when i == j */ if (i > j) continue; gdk_cairo_set_source_rgba (cr, &colors[i]); cairo_fill (cr); } } }
static gboolean swatch_draw (GtkWidget *widget, cairo_t *cr) { GtkColorSwatch *swatch = (GtkColorSwatch*)widget; GtkThemingBackground background; gdouble width, height; GtkStyleContext *context; GtkStateFlags state; GtkIconTheme *theme; GtkIconInfo *icon_info = NULL; theme = gtk_icon_theme_get_default (); context = gtk_widget_get_style_context (widget); state = gtk_widget_get_state_flags (widget); width = gtk_widget_get_allocated_width (widget); height = gtk_widget_get_allocated_height (widget); cairo_save (cr); gtk_style_context_save (context); gtk_style_context_set_state (context, state); _gtk_theming_background_init_from_context (&background, context, 0, 0, width, height, GTK_JUNCTION_NONE); if (swatch->priv->has_color) { cairo_pattern_t *pattern; cairo_matrix_t matrix; if (swatch->priv->use_alpha) { cairo_save (cr); _gtk_rounded_box_path (&background.padding_box, cr); cairo_clip_preserve (cr); cairo_set_source_rgb (cr, 0.33, 0.33, 0.33); cairo_fill_preserve (cr); pattern = _gtk_color_chooser_get_checkered_pattern (); cairo_matrix_init_scale (&matrix, 0.125, 0.125); cairo_pattern_set_matrix (pattern, &matrix); cairo_set_source_rgb (cr, 0.66, 0.66, 0.66); cairo_mask (cr, pattern); cairo_pattern_destroy (pattern); cairo_restore (cr); background.bg_color = swatch->priv->color; } else { background.bg_color = swatch->priv->color; background.bg_color.alpha = 1.0; } _gtk_theming_background_render (&background, cr); } else _gtk_theming_background_render (&background, cr); gtk_render_frame (context, cr, 0, 0, width, height); if (gtk_widget_has_visible_focus (widget)) { cairo_set_line_width (cr, 2); if (swatch->priv->has_color && INTENSITY (swatch->priv->color.red, swatch->priv->color.green, swatch->priv->color.blue) < 0.5) cairo_set_source_rgba (cr, 1., 1., 1., 0.4); else cairo_set_source_rgba (cr, 0., 0., 0., 0.4); _gtk_rounded_box_shrink (&background.padding_box, 3, 3, 3, 3); _gtk_rounded_box_path (&background.padding_box, cr); cairo_stroke (cr); } if (swatch->priv->icon) { icon_info = gtk_icon_theme_lookup_icon (theme, swatch->priv->icon, 16, GTK_ICON_LOOKUP_GENERIC_FALLBACK | GTK_ICON_LOOKUP_USE_BUILTIN); } else if ((state & GTK_STATE_FLAG_SELECTED) != 0) { GdkRGBA bg, border; GtkBorder border_width; GIcon *gicon; gtk_style_context_add_class (context, "color-active-badge"); _gtk_theming_background_init_from_context (&background, context, (width - 2 * ACTIVE_BADGE_RADIUS) / 2, (height - 2 * ACTIVE_BADGE_RADIUS) / 2, 2 * ACTIVE_BADGE_RADIUS, 2* ACTIVE_BADGE_RADIUS, GTK_JUNCTION_NONE); if (_gtk_theming_background_has_background_image (&background)) { _gtk_theming_background_render (&background, cr); } else { gtk_style_context_get_background_color (context, state, &bg); gtk_style_context_get_border_color (context, state, &border); gtk_style_context_get_border (context, state, &border_width); cairo_new_sub_path (cr); cairo_arc (cr, width / 2, height / 2, ACTIVE_BADGE_RADIUS, 0, 2 * G_PI); cairo_close_path (cr); gdk_cairo_set_source_rgba (cr, &bg); cairo_fill_preserve (cr); gdk_cairo_set_source_rgba (cr, &border); cairo_set_line_width (cr, border_width.left); cairo_stroke (cr); gicon = g_themed_icon_new ("object-select-symbolic"); /* fallback for themes that don't have object-select-symbolic */ g_themed_icon_append_name (G_THEMED_ICON (gicon), "gtk-apply"); icon_info = gtk_icon_theme_lookup_by_gicon (theme, gicon, 16, GTK_ICON_LOOKUP_GENERIC_FALLBACK | GTK_ICON_LOOKUP_USE_BUILTIN); g_object_unref (gicon); } } if (icon_info != NULL) { GdkPixbuf *pixbuf; pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info, context, NULL, NULL); if (pixbuf != NULL) { gtk_render_icon (context, cr, pixbuf, (width - gdk_pixbuf_get_width (pixbuf)) / 2, (height - gdk_pixbuf_get_height (pixbuf)) / 2); g_object_unref (pixbuf); } g_object_unref (icon_info); } cairo_restore (cr); gtk_style_context_restore (context); return FALSE; }