diff --git a/gtk/gtkoverlay.c b/gtk/gtkoverlay.c index 9c46f34130..97ee9ebe42 100644 --- a/gtk/gtkoverlay.c +++ b/gtk/gtkoverlay.c @@ -25,6 +25,7 @@ #include "gtkscrolledwindow.h" #include "gtkwidgetprivate.h" #include "gtkmarshalers.h" +#include "gtksnapshot.h" #include "gtkprivate.h" #include "gtkintl.h" @@ -65,6 +66,7 @@ struct _GtkOverlayChild { GtkWidget *widget; gboolean pass_through; + double blur; }; enum { @@ -76,6 +78,7 @@ enum { CHILD_PROP_0, CHILD_PROP_PASS_THROUGH, + CHILD_PROP_BLUR, CHILD_PROP_INDEX }; @@ -539,6 +542,17 @@ gtk_overlay_set_child_property (GtkContainer *container, } } break; + case CHILD_PROP_BLUR: + if (child_info) + { + if (g_value_get_double (value) != child_info->blur) + { + child_info->blur = g_value_get_double (value); + gtk_container_child_notify (container, child, "blur"); + gtk_widget_queue_draw (GTK_WIDGET (overlay)); + } + } + break; case CHILD_PROP_INDEX: if (child_info != NULL) gtk_overlay_reorder_overlay (GTK_OVERLAY (container), @@ -585,6 +599,12 @@ gtk_overlay_get_child_property (GtkContainer *container, else g_value_set_boolean (value, FALSE); break; + case CHILD_PROP_BLUR: + if (child_info) + g_value_set_double (value, child_info->blur); + else + g_value_set_double (value, 0); + break; case CHILD_PROP_INDEX: g_value_set_int (value, g_slist_index (priv->children, child_info)); break; @@ -594,6 +614,77 @@ gtk_overlay_get_child_property (GtkContainer *container, } } +static void +gtk_overlay_snapshot (GtkWidget *widget, + GtkSnapshot *snapshot) +{ + GtkWidget *main_widget; + GtkWidget *child; + GtkAllocation main_alloc; + cairo_region_t *clip = NULL; + int i; + + main_widget = gtk_bin_get_child (GTK_BIN (widget)); + gtk_widget_get_allocation (widget, &main_alloc); + + for (child = _gtk_widget_get_first_child (widget); + child != NULL; + child = _gtk_widget_get_next_sibling (child)) + { + double blur; + gtk_container_child_get (GTK_CONTAINER (widget), child, "blur", &blur, NULL); + if (blur > 0) + { + GtkAllocation alloc; + graphene_rect_t bounds; + + gtk_widget_get_allocation (child, &alloc); + graphene_rect_init (&bounds, alloc.x, alloc.y, alloc.width, alloc.height); + gtk_snapshot_push_clip (snapshot, &bounds, "Overlay Effect Clip"); + gtk_snapshot_push_blur (snapshot, blur, "Overlay Effect"); + gtk_widget_snapshot_child (widget, main_widget, snapshot); + gtk_snapshot_pop (snapshot); + gtk_snapshot_pop (snapshot); + + if (clip == NULL) + { + clip = cairo_region_create (); + main_alloc.x = main_alloc.y = 0; + cairo_region_union_rectangle (clip, (cairo_rectangle_int_t *)&main_alloc); + } + + cairo_region_subtract_rectangle (clip, (cairo_rectangle_int_t *)&alloc); + } + } + + if (clip == NULL) + { + GTK_WIDGET_CLASS (gtk_overlay_parent_class)->snapshot (widget, snapshot); + return; + } + + for (i = 0; i < cairo_region_num_rectangles (clip); i++) + { + cairo_rectangle_int_t rect; + graphene_rect_t bounds; + + cairo_region_get_rectangle (clip, i, &rect); + graphene_rect_init (&bounds, rect.x, rect.y, rect.width, rect.height); + gtk_snapshot_push_clip (snapshot, &bounds, "Overlay Non-Effect Clip"); + gtk_widget_snapshot_child (widget, main_widget, snapshot); + gtk_snapshot_pop (snapshot); + } + + cairo_region_destroy (clip); + + for (child = _gtk_widget_get_first_child (widget); + child != NULL; + child = _gtk_widget_get_next_sibling (child)) + { + if (child != main_widget) + gtk_widget_snapshot_child (widget, child, snapshot); + } +} static void gtk_overlay_class_init (GtkOverlayClass *klass) @@ -603,6 +694,7 @@ gtk_overlay_class_init (GtkOverlayClass *klass) GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); widget_class->size_allocate = gtk_overlay_size_allocate; + widget_class->snapshot = gtk_overlay_snapshot; container_class->add = gtk_overlay_add; container_class->remove = gtk_overlay_remove; @@ -624,6 +716,17 @@ gtk_overlay_class_init (GtkOverlayClass *klass) FALSE, GTK_PARAM_READWRITE)); + /** + * GtkOverlay:blur: + * + * Blur the content behind this child with a Gaussian blur of this radius. + * + * Since: 3.92 + */ + gtk_container_class_install_child_property (container_class, CHILD_PROP_BLUR, + g_param_spec_double ("blur", P_("Blur Radius"), P_("Apply a blur to the content behind this child"), + 0, 100, 0, + GTK_PARAM_READWRITE)); /** * GtkOverlay:index: *