[gtk/overlay-cleanup: 1/3] gtk-demo: Move the blur demo code here



commit b70cd64d6dea4c02cf53489e41f6ff6567cf1b6a
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Feb 21 19:27:41 2019 -0500

    gtk-demo: Move the blur demo code here
    
    We want to remove this from the GtkOverlay code.

 demos/gtk-demo/bluroverlay.c      | 482 ++++++++++++++++++++++++++++++++++++++
 demos/gtk-demo/bluroverlay.h      |  65 +++++
 demos/gtk-demo/demo.gresource.xml |   1 +
 demos/gtk-demo/meson.build        |   2 +-
 demos/gtk-demo/transparent.c      |   9 +-
 5 files changed, 553 insertions(+), 6 deletions(-)
---
diff --git a/demos/gtk-demo/bluroverlay.c b/demos/gtk-demo/bluroverlay.c
new file mode 100644
index 0000000000..f6e268c6e6
--- /dev/null
+++ b/demos/gtk-demo/bluroverlay.c
@@ -0,0 +1,482 @@
+/*
+ * bluroverlay.c
+ * This file is part of gtk
+ *
+ * Copyright (C) 2011 - Ignacio Casal Quinteiro, Mike Krüger
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bluroverlay.h"
+
+/*
+ * This is a cut-down copy of gtkoverlay.c with a custom snapshot
+ * function that support a limited form of blur-under.
+ */
+typedef struct _BlurOverlayChild BlurOverlayChild;
+
+struct _BlurOverlayChild
+{
+  double blur;
+};
+
+enum {
+  GET_CHILD_POSITION,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+static GQuark child_data_quark = 0;
+
+G_DEFINE_TYPE (BlurOverlay, blur_overlay, GTK_TYPE_BIN)
+
+static void
+blur_overlay_set_overlay_child (GtkWidget       *widget,
+                               BlurOverlayChild *child_data)
+{
+  g_object_set_qdata_full (G_OBJECT (widget), child_data_quark, child_data, g_free);
+}
+
+static BlurOverlayChild *
+blur_overlay_get_overlay_child (GtkWidget *widget)
+{
+  return (BlurOverlayChild *) g_object_get_qdata (G_OBJECT (widget), child_data_quark);
+}
+
+static void
+blur_overlay_measure (GtkWidget      *widget,
+                     GtkOrientation  orientation,
+                     int             for_size,
+                     int            *minimum,
+                     int            *natural,
+                     int            *minimum_baseline,
+                     int            *natural_baseline)
+{
+  GtkWidget *child;
+
+  for (child = gtk_widget_get_first_child (widget);
+       child != NULL;
+       child = gtk_widget_get_next_sibling (child))
+    {
+      int child_min, child_nat, child_min_baseline, child_nat_baseline;
+
+      gtk_widget_measure (child,
+                          orientation,
+                          for_size,
+                          &child_min, &child_nat,
+                          &child_min_baseline, &child_nat_baseline);
+
+      *minimum = MAX (*minimum, child_min);
+      *natural = MAX (*natural, child_nat);
+      if (child_min_baseline > -1)
+        *minimum_baseline = MAX (*minimum_baseline, child_min_baseline);
+      if (child_nat_baseline > -1)
+        *natural_baseline = MAX (*natural_baseline, child_nat_baseline);
+    }
+}
+
+static void
+blur_overlay_compute_child_allocation (BlurOverlay      *overlay,
+                                      GtkWidget       *widget,
+                                      BlurOverlayChild *child,
+                                      GtkAllocation   *widget_allocation)
+{
+  GtkAllocation allocation;
+  gboolean result;
+
+  g_signal_emit (overlay, signals[GET_CHILD_POSITION],
+                 0, widget, &allocation, &result);
+
+  widget_allocation->x = allocation.x;
+  widget_allocation->y = allocation.y;
+  widget_allocation->width = allocation.width;
+  widget_allocation->height = allocation.height;
+}
+
+static GtkAlign
+effective_align (GtkAlign         align,
+                 GtkTextDirection direction)
+{
+  switch (align)
+    {
+    case GTK_ALIGN_START:
+      return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_END : GTK_ALIGN_START;
+    case GTK_ALIGN_END:
+      return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END;
+    case GTK_ALIGN_FILL:
+    case GTK_ALIGN_CENTER:
+    case GTK_ALIGN_BASELINE:
+    default:
+      return align;
+    }
+}
+
+static void
+blur_overlay_child_update_style_classes (BlurOverlay *overlay,
+                                         GtkWidget *child,
+                                         GtkAllocation *child_allocation)
+{
+  int width, height;
+  GtkAlign valign, halign;
+  gboolean is_left, is_right, is_top, is_bottom;
+  gboolean has_left, has_right, has_top, has_bottom;
+  GtkStyleContext *context;
+
+  context = gtk_widget_get_style_context (child);
+  has_left = gtk_style_context_has_class (context, GTK_STYLE_CLASS_LEFT);
+  has_right = gtk_style_context_has_class (context, GTK_STYLE_CLASS_RIGHT);
+  has_top = gtk_style_context_has_class (context, GTK_STYLE_CLASS_TOP);
+  has_bottom = gtk_style_context_has_class (context, GTK_STYLE_CLASS_BOTTOM);
+
+  is_left = is_right = is_top = is_bottom = FALSE;
+
+  width = gtk_widget_get_width (GTK_WIDGET (overlay));
+  height = gtk_widget_get_height (GTK_WIDGET (overlay));
+
+  halign = effective_align (gtk_widget_get_halign (child),
+                            gtk_widget_get_direction (child));
+
+  if (halign == GTK_ALIGN_START)
+    is_left = (child_allocation->x == 0);
+  else if (halign == GTK_ALIGN_END)
+    is_right = (child_allocation->x + child_allocation->width == width);
+
+  valign = gtk_widget_get_valign (child);
+
+  if (valign == GTK_ALIGN_START)
+    is_top = (child_allocation->y == 0);
+  else if (valign == GTK_ALIGN_END)
+    is_bottom = (child_allocation->y + child_allocation->height == height);
+
+  if (has_left && !is_left)
+    gtk_style_context_remove_class (context, GTK_STYLE_CLASS_LEFT);
+  else if (!has_left && is_left)
+    gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT);
+
+  if (has_right && !is_right)
+    gtk_style_context_remove_class (context, GTK_STYLE_CLASS_RIGHT);
+  else if (!has_right && is_right)
+    gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT);
+
+  if (has_top && !is_top)
+    gtk_style_context_remove_class (context, GTK_STYLE_CLASS_TOP);
+  else if (!has_top && is_top)
+    gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOP);
+
+  if (has_bottom && !is_bottom)
+    gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BOTTOM);
+  else if (!has_bottom && is_bottom)
+    gtk_style_context_add_class (context, GTK_STYLE_CLASS_BOTTOM);
+}
+
+static void
+blur_overlay_child_allocate (BlurOverlay      *overlay,
+                            GtkWidget       *widget,
+                            BlurOverlayChild *child)
+{
+  GtkAllocation child_allocation;
+
+  if (!gtk_widget_get_visible (widget))
+    return;
+
+  blur_overlay_compute_child_allocation (overlay, widget, child, &child_allocation);
+
+  blur_overlay_child_update_style_classes (overlay, widget, &child_allocation);
+  gtk_widget_size_allocate (widget, &child_allocation, -1);
+}
+
+static void
+blur_overlay_size_allocate (GtkWidget *widget,
+                           int        width,
+                           int        height,
+                           int        baseline)
+{
+  BlurOverlay *overlay = BLUR_OVERLAY (widget);
+  GtkWidget *child;
+  GtkWidget *main_widget;
+
+  main_widget = gtk_bin_get_child (GTK_BIN (overlay));
+  if (main_widget && gtk_widget_get_visible (main_widget))
+    gtk_widget_size_allocate (main_widget,
+                              &(GtkAllocation) {
+                                0, 0,
+                                width, height
+                              }, -1);
+
+  for (child = gtk_widget_get_first_child (widget);
+       child != NULL;
+       child = gtk_widget_get_next_sibling (child))
+    {
+      if (child != main_widget)
+        {
+          BlurOverlayChild *child_data = blur_overlay_get_overlay_child (child);
+          blur_overlay_child_allocate (overlay, child, child_data);
+        }
+    }
+}
+
+static gboolean
+blur_overlay_get_child_position (BlurOverlay    *overlay,
+                                 GtkWidget      *widget,
+                                 GtkAllocation  *alloc)
+{
+  GtkRequisition min, req;
+  GtkAlign halign;
+  GtkTextDirection direction;
+  int width, height;
+
+  gtk_widget_get_preferred_size (widget, &min, &req);
+  width = gtk_widget_get_width (GTK_WIDGET (overlay));
+  height = gtk_widget_get_height (GTK_WIDGET (overlay));
+
+  alloc->x = 0;
+  alloc->width = MAX (min.width, MIN (width, req.width));
+
+  direction = gtk_widget_get_direction (widget);
+
+  halign = gtk_widget_get_halign (widget);
+  switch (effective_align (halign, direction))
+    {
+    case GTK_ALIGN_START:
+      /* nothing to do */
+      break;
+    case GTK_ALIGN_FILL:
+      alloc->width = MAX (alloc->width, width);
+      break;
+    case GTK_ALIGN_CENTER:
+      alloc->x += width / 2 - alloc->width / 2;
+      break;
+    case GTK_ALIGN_END:
+      alloc->x += width - alloc->width;
+      break;
+    case GTK_ALIGN_BASELINE:
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+
+  alloc->y = 0;
+  alloc->height = MAX  (min.height, MIN (height, req.height));
+
+  switch (gtk_widget_get_valign (widget))
+    {
+    case GTK_ALIGN_START:
+      /* nothing to do */
+      break;
+    case GTK_ALIGN_FILL:
+      alloc->height = MAX (alloc->height, height);
+      break;
+    case GTK_ALIGN_CENTER:
+      alloc->y += height / 2 - alloc->height / 2;
+      break;
+    case GTK_ALIGN_END:
+      alloc->y += height - alloc->height;
+      break;
+    case GTK_ALIGN_BASELINE:
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+
+  return TRUE;
+}
+
+static void
+blur_overlay_add (GtkContainer *container,
+                  GtkWidget    *widget)
+{
+  BlurOverlay *overlay = BLUR_OVERLAY (container);
+  gtk_widget_insert_after (widget, GTK_WIDGET (container), NULL);
+  overlay->main_widget = widget;  
+}
+
+static void
+blur_overlay_remove (GtkContainer *container,
+                     GtkWidget    *widget)
+{
+  BlurOverlay *overlay = BLUR_OVERLAY (container);
+  gtk_widget_unparent (widget);
+  if (overlay->main_widget == widget)
+    overlay->main_widget = NULL;
+}
+
+static void
+blur_overlay_forall (GtkContainer *overlay,
+                    GtkCallback   callback,
+                    gpointer      callback_data)
+{
+  GtkWidget *child;
+
+  child = gtk_widget_get_first_child (GTK_WIDGET (overlay));
+  while (child != NULL)
+    {
+      GtkWidget *next = gtk_widget_get_next_sibling (child);
+
+      (* callback) (child, callback_data);
+
+      child = next;
+    }
+}
+
+static void
+blur_overlay_snapshot (GtkWidget   *widget,
+                      GtkSnapshot *snapshot)
+{
+  GtkWidget *main_widget;
+  GskRenderNode *main_widget_node = NULL;
+  GtkWidget *child;
+  GtkAllocation main_alloc;
+  cairo_region_t *clip = NULL;
+  int i;
+
+  main_widget = BLUR_OVERLAY (widget)->main_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))
+    {
+      BlurOverlayChild *child_info = blur_overlay_get_overlay_child (child);
+      double blur = 0;
+      if (child_info)
+        blur = child_info->blur;
+
+      if (blur > 0)
+        {
+          GtkAllocation alloc;
+          graphene_rect_t bounds;
+
+          if (main_widget_node == NULL)
+            {
+              GtkSnapshot *child_snapshot;
+
+              child_snapshot = gtk_snapshot_new ();
+              gtk_widget_snapshot_child (widget, main_widget, child_snapshot);
+              main_widget_node = gtk_snapshot_free_to_node (child_snapshot);
+            }
+
+          gtk_widget_get_allocation (child, &alloc);
+          graphene_rect_init (&bounds, alloc.x, alloc.y, alloc.width, alloc.height);
+          gtk_snapshot_push_blur (snapshot, blur);
+          gtk_snapshot_push_clip (snapshot, &bounds);
+          gtk_snapshot_append_node (snapshot, main_widget_node);
+          gtk_snapshot_pop (snapshot);
+          gtk_snapshot_pop (snapshot);
+
+          if (clip == NULL)
+            {
+              cairo_rectangle_int_t rect;
+              rect.x = rect.y = 0;
+              rect.width = main_alloc.width;
+              rect.height = main_alloc.height;
+              clip = cairo_region_create_rectangle (&rect);
+            }
+          cairo_region_subtract_rectangle (clip, (cairo_rectangle_int_t *)&alloc);
+        }
+    }
+
+  if (clip == NULL)
+    {
+      for (child = gtk_widget_get_first_child (widget);
+           child != NULL;
+           child = gtk_widget_get_next_sibling (child))
+        {
+          gtk_widget_snapshot_child (widget, child, 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);
+      gtk_snapshot_append_node (snapshot, main_widget_node);
+      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);
+    }
+
+  gsk_render_node_unref (main_widget_node);
+}
+
+static void
+blur_overlay_class_init (BlurOverlayClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+  widget_class->measure = blur_overlay_measure;
+  widget_class->size_allocate = blur_overlay_size_allocate;
+  widget_class->snapshot = blur_overlay_snapshot;
+
+  container_class->add = blur_overlay_add;
+  container_class->remove = blur_overlay_remove;
+  container_class->forall = blur_overlay_forall;
+
+  klass->get_child_position = blur_overlay_get_child_position;
+
+  signals[GET_CHILD_POSITION] =
+    g_signal_new ("get-child-position",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (BlurOverlayClass, get_child_position),
+                  g_signal_accumulator_true_handled, NULL,
+                  NULL,
+                  G_TYPE_BOOLEAN, 2,
+                  GTK_TYPE_WIDGET,
+                  GDK_TYPE_RECTANGLE | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+  child_data_quark = g_quark_from_static_string ("gtk-overlay-child-data");
+
+  gtk_widget_class_set_css_name (widget_class, "overlay");
+}
+
+static void
+blur_overlay_init (BlurOverlay *overlay)
+{
+  gtk_widget_set_has_surface (GTK_WIDGET (overlay), FALSE);
+}
+
+GtkWidget *
+blur_overlay_new (void)
+{
+  return g_object_new (BLUR_TYPE_OVERLAY, NULL);
+}
+
+void
+blur_overlay_add_overlay (BlurOverlay *overlay,
+                          GtkWidget   *widget,
+                          double       blur)
+{
+  BlurOverlayChild *child = g_new0 (BlurOverlayChild, 1);
+
+  gtk_widget_insert_before (widget, GTK_WIDGET (overlay), NULL);
+
+  child->blur = blur;
+
+  blur_overlay_set_overlay_child (widget, child);
+}
diff --git a/demos/gtk-demo/bluroverlay.h b/demos/gtk-demo/bluroverlay.h
new file mode 100644
index 0000000000..e3fc27c7a8
--- /dev/null
+++ b/demos/gtk-demo/bluroverlay.h
@@ -0,0 +1,65 @@
+/*
+ * bluroverlay.h
+ * This file is part of gtk
+ *
+ * Copyright (C) 2011 - Ignacio Casal Quinteiro, Mike Krüger
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BLUR_OVERLAY_H__
+#define __BLUR_OVERLAY_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define BLUR_TYPE_OVERLAY             (blur_overlay_get_type ())
+#define BLUR_OVERLAY(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), BLUR_TYPE_OVERLAY, BlurOverlay))
+#define BLUR_OVERLAY_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), BLUR_TYPE_OVERLAY, 
BlurOverlayClass))
+#define BLUR_IS_OVERLAY(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BLUR_TYPE_OVERLAY))
+#define BLUR_IS_OVERLAY_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), BLUR_TYPE_OVERLAY))
+#define BLUR_OVERLAY_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), BLUR_TYPE_OVERLAY, 
BlurOverlayClass))
+
+typedef struct _BlurOverlay         BlurOverlay;
+typedef struct _BlurOverlayClass    BlurOverlayClass;
+
+struct _BlurOverlay
+{
+  GtkBin parent_instance;
+
+  GtkWidget *main_widget;
+};
+
+struct _BlurOverlayClass
+{
+  GtkBinClass parent_class;
+
+  gboolean (*get_child_position) (BlurOverlay   *overlay,
+                                  GtkWidget     *widget,
+                                  GtkAllocation *allocation);
+};
+
+GDK_AVAILABLE_IN_ALL
+GType      blur_overlay_get_type    (void) G_GNUC_CONST;
+GDK_AVAILABLE_IN_ALL
+GtkWidget *blur_overlay_new         (void);
+GDK_AVAILABLE_IN_ALL
+void       blur_overlay_add_overlay (BlurOverlay *overlay,
+                                     GtkWidget   *widget,
+                                     double       blur);
+
+G_END_DECLS
+
+#endif /* __BLUR_OVERLAY_H__ */
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index 1294f73f41..0a49548a48 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -247,6 +247,7 @@
   </gresource>
   <gresource prefix="/transparent">
     <file>portland-rose.jpg</file>
+    <file>bluroverlay.c</file>
   </gresource>
   <gresource prefix="/markup">
     <file>markup.txt</file>
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index 7116a411e2..83d0176250 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -75,7 +75,7 @@ demos = files([
 
 gtkdemo_deps = [ libgtk_dep, ]
 
-extra_demo_sources = files(['main.c', 'gtkfishbowl.c', 'fontplane.c', 'gtkgears.c', 'puzzlepiece.c'])
+extra_demo_sources = files(['main.c', 'gtkfishbowl.c', 'fontplane.c', 'gtkgears.c', 'puzzlepiece.c', 
'bluroverlay.c'])
 
 if harfbuzz_dep.found() and pangoft_dep.found()
   demos += files('font_features.c')
diff --git a/demos/gtk-demo/transparent.c b/demos/gtk-demo/transparent.c
index 6d5e80750b..9f1e989856 100644
--- a/demos/gtk-demo/transparent.c
+++ b/demos/gtk-demo/transparent.c
@@ -4,6 +4,7 @@
  */
 
 #include <gtk/gtk.h>
+#include "bluroverlay.h"
 
 GtkWidget *
 do_transparent (GtkWidget *do_widget)
@@ -27,7 +28,7 @@ do_transparent (GtkWidget *do_widget)
 
       gtk_window_set_title (GTK_WINDOW (window), "Transparency");
 
-      overlay = gtk_overlay_new ();
+      overlay = blur_overlay_new ();
       gtk_container_add (GTK_CONTAINER (window), overlay);
 
       button = gtk_button_new_with_label ("Don't click this button!");
@@ -38,8 +39,7 @@ do_transparent (GtkWidget *do_widget)
       gtk_widget_set_halign (button, GTK_ALIGN_FILL);
       gtk_widget_set_valign (button, GTK_ALIGN_START);
 
-      gtk_overlay_add_overlay (GTK_OVERLAY (overlay), button);
-      gtk_container_child_set (GTK_CONTAINER (overlay), button, "blur", 5.0, NULL);
+      blur_overlay_add_overlay (BLUR_OVERLAY (overlay), button, 5.0);
 
       button = gtk_button_new_with_label ("Maybe this one?");
       label = gtk_bin_get_child (GTK_BIN (button));
@@ -49,8 +49,7 @@ do_transparent (GtkWidget *do_widget)
       gtk_widget_set_halign (button, GTK_ALIGN_FILL);
       gtk_widget_set_valign (button, GTK_ALIGN_END);
 
-      gtk_overlay_add_overlay (GTK_OVERLAY (overlay), button);
-      gtk_container_child_set (GTK_CONTAINER (overlay), button, "blur", 5.0, NULL);
+      blur_overlay_add_overlay (BLUR_OVERLAY (overlay), button, 5.0);
 
       picture = gtk_picture_new_for_resource ("/transparent/portland-rose.jpg");
       gtk_container_add (GTK_CONTAINER (overlay), picture);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]