static void gtk_color_swatch_measure (GtkCssGadget *gadget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline, gpointer unused) { GtkWidget *widget; GtkColorSwatch *swatch; gint w, h, min; widget = gtk_css_gadget_get_owner (gadget); swatch = GTK_COLOR_SWATCH (widget); gtk_css_gadget_get_preferred_size (swatch->priv->overlay_gadget, orientation, -1, minimum, natural, NULL, NULL); gtk_widget_get_size_request (widget, &w, &h); if (orientation == GTK_ORIENTATION_HORIZONTAL) min = w < 0 ? 48 : w; else min = h < 0 ? 32 : h; *minimum = MAX (*minimum, min); *natural = MAX (*natural, min); }
static void gtk_button_measure (GtkCssGadget *gadget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline, gpointer data) { GtkWidget *widget; GtkWidget *child; widget = gtk_css_gadget_get_owner (gadget); child = gtk_bin_get_child (GTK_BIN (widget)); if (child && gtk_widget_get_visible (child)) { gtk_widget_measure (child, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline); } else { *minimum = 0; *natural = 0; if (minimum_baseline) *minimum_baseline = 0; if (natural_baseline) *natural_baseline = 0; } }
static void gtk_color_swatch_allocate (GtkCssGadget *gadget, const GtkAllocation *allocation, int baseline, GtkAllocation *out_clip, gpointer unused) { GtkColorSwatch *swatch; GtkAllocation overlay_alloc; gint overlay_width, overlay_height; swatch = GTK_COLOR_SWATCH (gtk_css_gadget_get_owner (gadget)); gtk_css_gadget_get_preferred_size (swatch->priv->overlay_gadget, GTK_ORIENTATION_HORIZONTAL, -1, &overlay_width, NULL, NULL, NULL); gtk_css_gadget_get_preferred_size (swatch->priv->overlay_gadget, GTK_ORIENTATION_VERTICAL, -1, &overlay_height, NULL, NULL, NULL); overlay_alloc.x = allocation->x + (allocation->width - overlay_width) / 2; overlay_alloc.y = allocation->y + (allocation->height - overlay_height) / 2; overlay_alloc.width = overlay_width; overlay_alloc.height = overlay_height; gtk_css_gadget_allocate (swatch->priv->overlay_gadget, &overlay_alloc, baseline, out_clip); }
static void gtk_button_allocate (GtkCssGadget *gadget, const GtkAllocation *allocation, int baseline, GtkAllocation *out_clip, gpointer unused) { GtkWidget *widget; GtkWidget *child; widget = gtk_css_gadget_get_owner (gadget); child = gtk_bin_get_child (GTK_BIN (widget)); if (child && gtk_widget_get_visible (child)) gtk_widget_size_allocate_with_baseline (child, (GtkAllocation *)allocation, baseline); if (gtk_widget_get_realized (widget)) { GtkAllocation border_allocation; gtk_css_gadget_get_border_allocation (gadget, &border_allocation, NULL); gdk_window_move_resize (GTK_BUTTON (widget)->priv->event_window, border_allocation.x, border_allocation.y, border_allocation.width, border_allocation.height); } gtk_container_get_children_clip (GTK_CONTAINER (widget), out_clip); }
static void gtk_switch_allocate_contents (GtkCssGadget *gadget, const GtkAllocation *allocation, int baseline, GtkAllocation *out_clip, gpointer unused) { GtkSwitch *self = GTK_SWITCH (gtk_css_gadget_get_owner (gadget)); GtkSwitchPrivate *priv = self->priv; GtkAllocation slider_alloc; slider_alloc.x = allocation->x + round (priv->handle_pos * (allocation->width - allocation->width / 2)); slider_alloc.y = allocation->y; slider_alloc.width = allocation->width / 2; slider_alloc.height = allocation->height; gtk_css_gadget_allocate (priv->slider_gadget, &slider_alloc, baseline, out_clip); if (gtk_widget_get_realized (GTK_WIDGET (self))) { GtkAllocation border_allocation; gtk_css_gadget_get_border_allocation (gadget, &border_allocation, NULL); gdk_window_move_resize (priv->event_window, border_allocation.x, border_allocation.y, border_allocation.width, border_allocation.height); } }
static gboolean gtk_switch_snapshot_trough (GtkCssGadget *gadget, GtkSnapshot *snapshot, int x, int y, int width, int height, gpointer data) { GtkWidget *widget = gtk_css_gadget_get_owner (gadget); GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv; GtkStyleContext *context = gtk_widget_get_style_context (widget); PangoRectangle rect; gint label_x, label_y; pango_layout_get_pixel_extents (priv->on_layout, NULL, &rect); label_x = x + ((width / 2) - rect.width) / 2; label_y = y + (height - rect.height) / 2; gtk_snapshot_render_layout (snapshot, context, label_x, label_y, priv->on_layout); pango_layout_get_pixel_extents (priv->off_layout, NULL, &rect); label_x = x + (width / 2) + ((width / 2) - rect.width) / 2; label_y = y + (height - rect.height) / 2; gtk_snapshot_render_layout (snapshot, context, label_x, label_y, priv->off_layout); gtk_css_gadget_snapshot (priv->slider_gadget, snapshot); return FALSE; }
static gboolean gtk_switch_snapshot_slider (GtkCssGadget *gadget, GtkSnapshot *snapshot, int x, int y, int width, int height, gpointer data) { return gtk_widget_has_visible_focus (gtk_css_gadget_get_owner (gadget)); }
static void gtk_icon_helper_ensure_surface (GtkIconHelper *self) { int scale; if (self->priv->rendered_surface) return; scale = gtk_widget_get_scale_factor (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))); self->priv->rendered_surface = gtk_icon_helper_load_surface (self, scale); }
static void gtk_icon_helper_invalidate (GtkIconHelper *self) { if (self->priv->rendered_surface != NULL) { cairo_surface_destroy (self->priv->rendered_surface); self->priv->rendered_surface = NULL; self->priv->rendered_surface_is_symbolic = FALSE; } if (!GTK_IS_CSS_TRANSIENT_NODE (gtk_css_gadget_get_node (GTK_CSS_GADGET (self)))) gtk_widget_queue_resize (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))); }
static void gtk_icon_helper_constructed (GObject *object) { GtkIconHelper *self = GTK_ICON_HELPER (object); GtkWidget *widget; widget = gtk_css_gadget_get_owner (GTK_CSS_GADGET (self)); g_signal_connect_swapped (widget, "direction-changed", G_CALLBACK (gtk_icon_helper_invalidate), self); g_signal_connect_swapped (widget, "notify::scale-factor", G_CALLBACK (gtk_icon_helper_invalidate), self); G_OBJECT_CLASS (gtk_icon_helper_parent_class)->constructed (object); }
static void gtk_icon_helper_finalize (GObject *object) { GtkIconHelper *self = GTK_ICON_HELPER (object); GtkWidget *widget; widget = gtk_css_gadget_get_owner (GTK_CSS_GADGET (self)); g_signal_handlers_disconnect_by_func (widget, G_CALLBACK (gtk_icon_helper_invalidate), self); _gtk_icon_helper_clear (self); gtk_image_definition_unref (self->priv->def); G_OBJECT_CLASS (gtk_icon_helper_parent_class)->finalize (object); }
static void gtk_level_bar_allocate_trough (GtkCssGadget *gadget, const GtkAllocation *allocation, int baseline, GtkAllocation *out_clip, gpointer data) { GtkWidget *widget = gtk_css_gadget_get_owner (gadget); GtkLevelBar *self = GTK_LEVEL_BAR (widget); if (self->priv->bar_mode == GTK_LEVEL_BAR_MODE_CONTINUOUS) gtk_level_bar_allocate_trough_continuous (self, allocation, baseline, out_clip); else gtk_level_bar_allocate_trough_discrete (self, allocation, baseline, out_clip); }
static gboolean gtk_button_render (GtkCssGadget *gadget, GtkSnapshot *snapshot, int x, int y, int width, int height, gpointer data) { GtkWidget *widget; widget = gtk_css_gadget_get_owner (gadget); GTK_WIDGET_CLASS (gtk_button_parent_class)->snapshot (widget, snapshot); return gtk_widget_has_visible_focus (widget); }
static gboolean gtk_level_bar_render_trough (GtkCssGadget *gadget, cairo_t *cr, int x, int y, int width, int height, gpointer data) { GtkWidget *widget = gtk_css_gadget_get_owner (gadget); GtkLevelBar *self = GTK_LEVEL_BAR (widget); if (self->priv->bar_mode == GTK_LEVEL_BAR_MODE_CONTINUOUS) gtk_level_bar_draw_fill_continuous (self, cr); else gtk_level_bar_draw_fill_discrete (self, cr); return FALSE; }
static void gtk_switch_get_content_size (GtkCssGadget *gadget, GtkOrientation orientation, gint for_size, gint *minimum, gint *natural, gint *minimum_baseline, gint *natural_baseline, gpointer unused) { GtkWidget *widget; GtkSwitch *self; GtkSwitchPrivate *priv; gint slider_minimum, slider_natural; PangoRectangle on_rect, off_rect; widget = gtk_css_gadget_get_owner (gadget); self = GTK_SWITCH (widget); priv = self->priv; gtk_css_gadget_get_preferred_size (priv->slider_gadget, orientation, -1, &slider_minimum, &slider_natural, NULL, NULL); pango_layout_get_pixel_extents (priv->on_layout, NULL, &on_rect); pango_layout_get_pixel_extents (priv->off_layout, NULL, &off_rect); if (orientation == GTK_ORIENTATION_HORIZONTAL) { int text_width = MAX (on_rect.width, off_rect.width); *minimum = 2 * MAX (slider_minimum, text_width); *natural = 2 * MAX (slider_natural, text_width); } else { int text_height = MAX (on_rect.height, off_rect.height); *minimum = MAX (slider_minimum, text_height); *natural = MAX (slider_natural, text_height); } }
static cairo_surface_t * ensure_surface_for_icon_set (GtkIconHelper *self, GtkCssStyle *style, GtkTextDirection direction, gint scale, GtkIconSet *icon_set) { cairo_surface_t *surface; GdkPixbuf *pixbuf; pixbuf = gtk_icon_set_render_icon_pixbuf_for_scale (icon_set, style, direction, self->priv->icon_size, scale); surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, gtk_widget_get_window (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self)))); g_object_unref (pixbuf); return surface; }
static void gtk_level_bar_measure_trough (GtkCssGadget *gadget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline, gpointer data) { GtkWidget *widget = gtk_css_gadget_get_owner (gadget); GtkLevelBar *self = GTK_LEVEL_BAR (widget); gint num_blocks, size; gint block_width, block_height; num_blocks = gtk_level_bar_get_num_blocks (self); gtk_level_bar_get_min_block_size (self, &block_width, &block_height); if (orientation == GTK_ORIENTATION_HORIZONTAL) { if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) size = num_blocks * block_width; else size = block_width; } else { if (self->priv->orientation == GTK_ORIENTATION_VERTICAL) size = num_blocks * block_height; else size = block_height; } *minimum = size; *natural = size; }
void _gtk_icon_helper_get_size (GtkIconHelper *self, gint *width_out, gint *height_out) { gint width, height, scale; width = height = 0; /* Certain kinds of images are easy to calculate the size for, these we do immediately to avoid having to potentially load the image data for something that may not yet be visible */ switch (gtk_image_definition_get_storage_type (self->priv->def)) { case GTK_IMAGE_SURFACE: get_surface_size (self, gtk_image_definition_get_surface (self->priv->def), &width, &height); break; case GTK_IMAGE_PIXBUF: get_pixbuf_size (self, gtk_widget_get_scale_factor (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))), gtk_image_definition_get_pixbuf (self->priv->def), gtk_image_definition_get_scale (self->priv->def), &width, &height, &scale); width = (width + scale - 1) / scale; height = (height + scale - 1) / scale; break; case GTK_IMAGE_ANIMATION: { GdkPixbufAnimation *animation = gtk_image_definition_get_animation (self->priv->def); width = gdk_pixbuf_animation_get_width (animation); height = gdk_pixbuf_animation_get_height (animation); break; } case GTK_IMAGE_ICON_NAME: case GTK_IMAGE_GICON: if (self->priv->pixel_size != -1 || self->priv->force_scale_pixbuf) ensure_icon_size (self, &width, &height); break; case GTK_IMAGE_STOCK: case GTK_IMAGE_ICON_SET: case GTK_IMAGE_EMPTY: default: break; } /* Otherwise we load the surface to guarantee we get a size */ if (width == 0) { gtk_icon_helper_ensure_surface (self); if (self->priv->rendered_surface != NULL) { get_surface_size (self, self->priv->rendered_surface, &width, &height); } else if (self->priv->icon_size != GTK_ICON_SIZE_INVALID) { ensure_icon_size (self, &width, &height); } } if (width_out) *width_out = width; if (height_out) *height_out = height; }
static cairo_surface_t * ensure_surface_from_pixbuf (GtkIconHelper *self, GtkCssStyle *style, gint scale, GdkPixbuf *orig_pixbuf, gint orig_scale) { gint width, height; cairo_surface_t *surface; GdkPixbuf *pixbuf; GtkCssIconEffect icon_effect; if (get_pixbuf_size (self, scale, orig_pixbuf, orig_scale, &width, &height, &scale)) pixbuf = gdk_pixbuf_scale_simple (orig_pixbuf, width, height, GDK_INTERP_BILINEAR); else pixbuf = g_object_ref (orig_pixbuf); surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, gtk_widget_get_window (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self)))); icon_effect = _gtk_css_icon_effect_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_EFFECT)); gtk_css_icon_effect_apply (icon_effect, surface); g_object_unref (pixbuf); return surface; }
static cairo_surface_t * ensure_surface_for_gicon (GtkIconHelper *self, GtkCssStyle *style, GtkTextDirection dir, gint scale, GIcon *gicon) { GtkIconHelperPrivate *priv = self->priv; GtkIconTheme *icon_theme; gint width, height; GtkIconInfo *info; GtkIconLookupFlags flags; cairo_surface_t *surface; GdkPixbuf *destination; gboolean symbolic; icon_theme = gtk_css_icon_theme_value_get_icon_theme (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_THEME)); flags = get_icon_lookup_flags (self, style, dir); ensure_icon_size (self, &width, &height); info = gtk_icon_theme_lookup_by_gicon_for_scale (icon_theme, gicon, MIN (width, height), scale, flags); if (info) { symbolic = gtk_icon_info_is_symbolic (info); if (symbolic) { GdkRGBA fg, success_color, warning_color, error_color; gtk_icon_theme_lookup_symbolic_colors (style, &fg, &success_color, &warning_color, &error_color); destination = gtk_icon_info_load_symbolic (info, &fg, &success_color, &warning_color, &error_color, NULL, NULL); } else { destination = gtk_icon_info_load_icon (info, NULL); } g_object_unref (info); } else { destination = NULL; } if (destination == NULL) { destination = gtk_icon_theme_load_icon (icon_theme, "image-missing", width, flags | GTK_ICON_LOOKUP_USE_BUILTIN | GTK_ICON_LOOKUP_GENERIC_FALLBACK, NULL); /* We include this image as resource, so we always have it available or * the icontheme code is broken */ g_assert (destination); symbolic = FALSE; } surface = gdk_cairo_surface_create_from_pixbuf (destination, scale, gtk_widget_get_window (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self)))); if (!symbolic) { GtkCssIconEffect icon_effect; icon_effect = _gtk_css_icon_effect_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_EFFECT)); gtk_css_icon_effect_apply (icon_effect, surface); } else { priv->rendered_surface_is_symbolic = TRUE; } g_object_unref (destination); return surface; }
cairo_surface_t * gtk_icon_helper_load_surface (GtkIconHelper *self, int scale) { cairo_surface_t *surface; GtkIconSet *icon_set; GIcon *gicon; switch (gtk_image_definition_get_storage_type (self->priv->def)) { case GTK_IMAGE_SURFACE: surface = ensure_surface_from_surface (self, gtk_image_definition_get_surface (self->priv->def)); break; case GTK_IMAGE_PIXBUF: surface = ensure_surface_from_pixbuf (self, gtk_css_node_get_style (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))), scale, gtk_image_definition_get_pixbuf (self->priv->def), gtk_image_definition_get_scale (self->priv->def)); break; case GTK_IMAGE_STOCK: G_GNUC_BEGIN_IGNORE_DEPRECATIONS; icon_set = gtk_icon_factory_lookup_default (gtk_image_definition_get_stock (self->priv->def)); G_GNUC_END_IGNORE_DEPRECATIONS; if (icon_set != NULL) surface = ensure_surface_for_icon_set (self, gtk_css_node_get_style (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))), gtk_widget_get_direction (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))), scale, icon_set); else surface = NULL; break; case GTK_IMAGE_ICON_SET: icon_set = gtk_image_definition_get_icon_set (self->priv->def); surface = ensure_surface_for_icon_set (self, gtk_css_node_get_style (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))), gtk_widget_get_direction (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))), scale, icon_set); break; case GTK_IMAGE_ICON_NAME: if (self->priv->use_fallback) gicon = g_themed_icon_new_with_default_fallbacks (gtk_image_definition_get_icon_name (self->priv->def)); else gicon = g_themed_icon_new (gtk_image_definition_get_icon_name (self->priv->def)); surface = ensure_surface_for_gicon (self, gtk_css_node_get_style (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))), gtk_widget_get_direction (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))), scale, gicon); g_object_unref (gicon); break; case GTK_IMAGE_GICON: surface = ensure_surface_for_gicon (self, gtk_css_node_get_style (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))), gtk_widget_get_direction (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))), scale, gtk_image_definition_get_gicon (self->priv->def)); break; case GTK_IMAGE_ANIMATION: case GTK_IMAGE_EMPTY: default: surface = NULL; break; } return surface; }
static gboolean gtk_color_swatch_render_overlay (GtkCssGadget *gadget, cairo_t *cr, int x, int y, int width, int height, gpointer data) { GtkWidget *widget; GtkColorSwatch *swatch; GtkStyleContext *context; GtkStateFlags state; GtkIconTheme *theme; GtkIconInfo *icon_info = NULL; gint scale; widget = gtk_css_gadget_get_owner (gadget); swatch = GTK_COLOR_SWATCH (widget); theme = gtk_icon_theme_get_default (); context = gtk_widget_get_style_context (widget); state = gtk_style_context_get_state (context); scale = gtk_widget_get_scale_factor (widget); if (swatch->priv->icon) { icon_info = gtk_icon_theme_lookup_icon_for_scale (theme, swatch->priv->icon, PIXBUF_SIZE, scale, GTK_ICON_LOOKUP_GENERIC_FALLBACK | GTK_ICON_LOOKUP_USE_BUILTIN); } else if ((state & GTK_STATE_FLAG_SELECTED) != 0) { GIcon *gicon; 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_for_scale (theme, gicon, PIXBUF_SIZE, scale, GTK_ICON_LOOKUP_USE_BUILTIN); g_object_unref (gicon); } /* now draw the overlay image */ if (icon_info != NULL) { GdkPixbuf *pixbuf; pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info, context, NULL, NULL); if (pixbuf != NULL) { cairo_surface_t *surface; surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, gtk_widget_get_window (widget)); gtk_render_icon_surface (context, cr, surface, x, y); cairo_surface_destroy (surface); g_object_unref (pixbuf); } g_object_unref (icon_info); } return FALSE; }
static gboolean gtk_color_swatch_render (GtkCssGadget *gadget, cairo_t *cr, int x, int y, int width, int height, gpointer data) { GtkWidget *widget; GtkColorSwatch *swatch; GtkStyleContext *context; widget = gtk_css_gadget_get_owner (gadget); swatch = GTK_COLOR_SWATCH (widget); context = gtk_widget_get_style_context (widget); if (swatch->priv->has_color) { cairo_pattern_t *pattern; cairo_matrix_t matrix; gtk_render_content_path (context, cr, x, y, width, height); if (swatch->priv->use_alpha) { cairo_save (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); gdk_cairo_set_source_rgba (cr, &swatch->priv->color); } else { cairo_set_source_rgb (cr, swatch->priv->color.red, swatch->priv->color.green, swatch->priv->color.blue); } cairo_fill (cr); } gtk_render_frame (context, cr, x, y, width, height); gtk_css_gadget_draw (swatch->priv->overlay_gadget, cr); return gtk_widget_has_visible_focus (widget); }