[gtk/clipboard-demo-fixes: 2/2] gtk-demo: Polish the clipboard demo



commit f8f391ceb9a5178f0ffe55f059721a7747567020
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Apr 25 21:16:02 2020 -0400

    gtk-demo: Polish the clipboard demo
    
    The DND part of this demo was broken by recent
    icon theme changes. Make it work again.
    
    And make the demo nicer by breaking out a
    DemoImage widget.

 demos/gtk-demo/clipboard.c        | 206 +-----------------------------
 demos/gtk-demo/demo.gresource.xml |   4 +
 demos/gtk-demo/demoimage.c        | 259 ++++++++++++++++++++++++++++++++++++++
 demos/gtk-demo/demoimage.h        |  13 ++
 demos/gtk-demo/meson.build        |   1 +
 5 files changed, 283 insertions(+), 200 deletions(-)
---
diff --git a/demos/gtk-demo/clipboard.c b/demos/gtk-demo/clipboard.c
index 8fc6bb7cf54..ca8ca076700 100644
--- a/demos/gtk-demo/clipboard.c
+++ b/demos/gtk-demo/clipboard.c
@@ -12,6 +12,7 @@
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 #include <string.h>
+#include "demoimage.h"
 
 static GtkWidget *window = NULL;
 
@@ -93,147 +94,6 @@ paste_button_clicked (GtkWidget *button,
   gdk_clipboard_read_text_async (clipboard, NULL, paste_received, entry);
 }
 
-static GdkPaintable *
-get_image_paintable (GtkImage *image)
-{
-  const gchar *icon_name;
-  GtkIconTheme *icon_theme;
-  GtkIconPaintable *icon;
-
-  switch (gtk_image_get_storage_type (image))
-    {
-    case GTK_IMAGE_PAINTABLE:
-      return g_object_ref (gtk_image_get_paintable (image));
-    case GTK_IMAGE_ICON_NAME:
-      icon_name = gtk_image_get_icon_name (image);
-      icon_theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (image)));
-      icon = gtk_icon_theme_lookup_icon (icon_theme,
-                                         icon_name,
-                                         NULL,
-                                         48, 1,
-                                         gtk_widget_get_direction (GTK_WIDGET (image)),
-                                         0);
-      if (icon == NULL)
-        return NULL;
-      return GDK_PAINTABLE (icon);
-
-    case GTK_IMAGE_EMPTY:
-    case GTK_IMAGE_GICON:
-    default:
-      g_warning ("Image storage type %d not handled",
-                 gtk_image_get_storage_type (image));
-      return NULL;
-    }
-}
-
-static void
-drag_begin (GtkDragSource *source,
-            GdkDrag       *drag,
-            GtkWidget     *widget)
-{
-  GdkPaintable *paintable;
-
-  paintable = get_image_paintable (GTK_IMAGE (widget));
-  if (paintable)
-    {
-      gtk_drag_source_set_icon (source, paintable, -2, -2);
-      g_object_unref (paintable);
-    }
-}
-
-static GdkContentProvider *
-prepare_drag (GtkDragSource *source,
-              double         x,
-              double         y,
-              GtkWidget     *image)
-{
-  GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (image));
-
-  if (!GDK_IS_TEXTURE (paintable))
-    return NULL;
-
-  return gdk_content_provider_new_typed (GDK_TYPE_TEXTURE, paintable);
-}
-
-static gboolean
-drag_drop (GtkDropTarget *dest,
-           const GValue  *value,
-           double         x,
-           double         y,
-           GtkImage      *image)
-{
-  GdkTexture *texture = g_value_get_object (value);
-  gtk_image_set_from_paintable (GTK_IMAGE (image), GDK_PAINTABLE (texture));
-
-  return TRUE;
-}
-
-static void
-copy_image (GSimpleAction *action,
-            GVariant      *value,
-            gpointer       data)
-{
-  GdkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (data));
-  GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (data));
-
-  if (GDK_IS_TEXTURE (paintable))
-    gdk_clipboard_set_texture (clipboard, GDK_TEXTURE (paintable));
-
-  if (paintable)
-    g_object_unref (paintable);
-}
-
-static void
-paste_image_received (GObject      *source,
-                      GAsyncResult *result,
-                      gpointer      data)
-{
-  GdkTexture *texture;
-
-  texture = gdk_clipboard_read_texture_finish (GDK_CLIPBOARD (source), result, NULL);
-  if (texture == NULL)
-    return;
-    
-  gtk_image_set_from_paintable (GTK_IMAGE (data), GDK_PAINTABLE (texture));
-  g_object_unref (texture);
-}
-
-static void
-paste_image (GSimpleAction *action,
-             GVariant      *value,
-             gpointer       data)
-{
-  GdkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (data));
-  gdk_clipboard_read_texture_async (clipboard, NULL, paste_image_received, data);
-}
-
-static void
-pressed_cb (GtkGesture *gesture,
-            int         n_press,
-            double      x,
-            double      y,
-            GtkWidget  *image)
-{
-  GtkWidget *popover;
-  GMenu *menu;
-  GMenuItem *item;
-
-  menu = g_menu_new (); 
-  item = g_menu_item_new (_("_Copy"), "clipboard.copy");
-  g_menu_append_item (menu, item);
-
-  item = g_menu_item_new (_("_Paste"), "clipboard.paste");
-  g_menu_append_item (menu, item);
-
-  popover = gtk_popover_menu_new_from_model (G_MENU_MODEL (menu));
-  gtk_widget_set_parent (popover, image);
-
-  gtk_popover_set_pointing_to (GTK_POPOVER (popover), &(GdkRectangle) { x, y, 1, 1});
-  gtk_popover_popup (GTK_POPOVER (popover));
-
-  g_object_unref (menu);
-}
-
 GtkWidget *
 do_clipboard (GtkWidget *do_widget)
 {
@@ -243,14 +103,6 @@ do_clipboard (GtkWidget *do_widget)
       GtkWidget *label;
       GtkWidget *entry, *button;
       GtkWidget *image;
-      GtkGesture *gesture;
-      GActionEntry entries[] = {
-        { "copy", copy_image, NULL, NULL, NULL },
-        { "paste", paste_image, NULL, NULL, NULL },
-      };
-      GActionGroup *actions;
-      GtkDragSource *source;
-      GtkDropTarget *dest;
 
       window = gtk_window_new ();
       gtk_window_set_display (GTK_WINDOW (window),
@@ -320,62 +172,16 @@ do_clipboard (GtkWidget *do_widget)
       gtk_container_add (GTK_CONTAINER (vbox), hbox);
 
       /* Create the first image */
-      image = gtk_image_new_from_icon_name ("dialog-warning");
-      gtk_image_set_pixel_size (GTK_IMAGE (image), 48);
+      image = demo_image_new ("dialog-warning");
       gtk_container_add (GTK_CONTAINER (hbox), image);
 
-      /* make image a drag source */
-      source = gtk_drag_source_new ();
-      g_signal_connect (source, "prepare", G_CALLBACK (prepare_drag), NULL);
-      g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), image);
-      gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
-
-      /* accept drops on image */
-      dest = gtk_drop_target_new (GDK_TYPE_TEXTURE, GDK_ACTION_COPY);
-      g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), image);
-      gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (dest));
-
-      /* context menu on image */
-      gesture = gtk_gesture_click_new ();
-      gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
-      g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), image);
-      gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (gesture));
-
-      actions = G_ACTION_GROUP (g_simple_action_group_new ());
-      g_action_map_add_action_entries (G_ACTION_MAP (actions), entries, G_N_ELEMENTS (entries), image);
-
-      gtk_widget_insert_action_group (image, "clipboard", actions);
-
-      g_object_unref (actions);
-
       /* Create the second image */
-      image = gtk_image_new_from_icon_name ("process-stop");
-      gtk_image_set_pixel_size (GTK_IMAGE (image), 48);
+      image = demo_image_new ("process-stop");
       gtk_container_add (GTK_CONTAINER (hbox), image);
 
-      /* make image a drag source */
-      source = gtk_drag_source_new ();
-      g_signal_connect (source, "prepare", G_CALLBACK (prepare_drag), NULL);
-      g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), image);
-      gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
-
-      /* accept drops on image */
-      dest = gtk_drop_target_new (GDK_TYPE_TEXTURE, GDK_ACTION_COPY);
-      g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), image);
-      gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (dest));
-
-      /* context menu on image */
-      gesture = gtk_gesture_click_new ();
-      gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
-      g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), image);
-      gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (gesture));
-
-      actions = G_ACTION_GROUP (g_simple_action_group_new ());
-      g_action_map_add_action_entries (G_ACTION_MAP (actions), entries, G_N_ELEMENTS (entries), image);
-
-      gtk_widget_insert_action_group (image, "clipboard", actions);
-
-      g_object_unref (actions);
+      /* Create the third image */
+      image = demo_image_new ("weather-clear");
+      gtk_container_add (GTK_CONTAINER (hbox), image);
     }
 
   if (!gtk_widget_get_visible (window))
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index 3afc75c7dbf..6df9f252a19 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -12,6 +12,10 @@
   <gresource prefix="/builder">
     <file>demo.ui</file>
   </gresource>
+  <gresource prefix="/clipboard">
+    <file>demoimage.c</file>
+    <file>demoimage.h</file>
+  </gresource>
   <gresource prefix="/css_accordion">
     <file>css_accordion.css</file>
     <file>reset.css</file>
diff --git a/demos/gtk-demo/demoimage.c b/demos/gtk-demo/demoimage.c
new file mode 100644
index 00000000000..37c0acd6846
--- /dev/null
+++ b/demos/gtk-demo/demoimage.c
@@ -0,0 +1,259 @@
+#include "demoimage.h"
+#include <glib/gi18n.h>
+
+struct _DemoImage {
+  GtkWidget parent_instance;
+ 
+  GtkWidget *image;
+  GtkWidget *popover;
+};
+
+enum {
+  PROP_ICON_NAME = 1
+};
+
+G_DEFINE_TYPE(DemoImage, demo_image, GTK_TYPE_WIDGET)
+
+static GdkPaintable *
+get_image_paintable (GtkImage *image)
+{
+  const gchar *icon_name;
+  GtkIconTheme *icon_theme;
+  GtkIconPaintable *icon;
+
+  switch (gtk_image_get_storage_type (image))
+    {
+    case GTK_IMAGE_PAINTABLE:
+      return g_object_ref (gtk_image_get_paintable (image));
+    case GTK_IMAGE_ICON_NAME:
+      icon_name = gtk_image_get_icon_name (image);
+      icon_theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (image)));
+      icon = gtk_icon_theme_lookup_icon (icon_theme,
+                                         icon_name,
+                                         NULL,
+                                         48, 1,
+                                         gtk_widget_get_direction (GTK_WIDGET (image)),
+                                         0);
+      if (icon == NULL)
+        return NULL;
+      return GDK_PAINTABLE (icon);
+
+    case GTK_IMAGE_EMPTY:
+    case GTK_IMAGE_GICON:
+    default:
+      g_warning ("Image storage type %d not handled",
+                 gtk_image_get_storage_type (image));
+      return NULL;
+    }
+}
+
+static void
+drag_begin (GtkDragSource *source,
+            GdkDrag       *drag,
+            gpointer       data)
+{
+  GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
+  DemoImage *demo = DEMO_IMAGE (widget);
+  GdkPaintable *paintable;
+
+  paintable = get_image_paintable (GTK_IMAGE (demo->image));
+  if (paintable)
+    {
+      gtk_drag_icon_set_from_paintable (drag, paintable, -2, -2);
+      g_object_unref (paintable);
+    }
+}
+
+static GdkContentProvider *
+prepare_drag (GtkDragSource *source,
+              double         x,
+              double         y,
+              gpointer       data)
+{
+  GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
+  DemoImage *demo = DEMO_IMAGE (widget);
+  GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (demo->image));
+
+  return gdk_content_provider_new_typed (GDK_TYPE_PAINTABLE, paintable);
+}
+
+static gboolean
+drag_drop (GtkDropTarget *dest,
+           const GValue  *value,
+           double         x,
+           double         y,
+           gpointer       data)
+{
+  GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
+  DemoImage *demo = DEMO_IMAGE (widget);
+  GdkPaintable *paintable = g_value_get_object (value);
+
+  gtk_image_set_from_paintable (GTK_IMAGE (demo->image), paintable);
+
+  return TRUE;
+}
+
+static void
+copy_image (GtkWidget *widget,
+            const char *action_name,
+            GVariant *parameter)
+{
+  GdkClipboard *clipboard = gtk_widget_get_clipboard (widget);
+  DemoImage *demo = DEMO_IMAGE (widget);
+  GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (demo->image));
+  GValue value = G_VALUE_INIT;
+
+  g_value_init (&value, GDK_TYPE_PAINTABLE);
+  g_value_set_object (&value, paintable);
+  gdk_clipboard_set_value (clipboard, &value);
+  g_value_unset (&value);
+
+  if (paintable)
+    g_object_unref (paintable);
+}
+
+static void
+paste_image (GtkWidget *widget,
+             const char *action_name,
+             GVariant *parameter)
+{
+  GdkClipboard *clipboard = gtk_widget_get_clipboard (widget);
+  DemoImage *demo = DEMO_IMAGE (widget);
+  GdkContentProvider *content = gdk_clipboard_get_content (clipboard);
+  GValue value = G_VALUE_INIT;
+  GdkPaintable *paintable;
+
+  g_value_init (&value, GDK_TYPE_PAINTABLE);
+  if (!gdk_content_provider_get_value (content, &value, NULL))
+    return;
+
+  paintable = GDK_PAINTABLE (g_value_get_object (&value));
+  gtk_image_set_from_paintable (GTK_IMAGE (demo->image), paintable);
+  g_value_unset (&value);
+}
+
+static void
+pressed_cb (GtkGesture *gesture,
+            int         n_press,
+            double      x,
+            double      y,
+            gpointer    data)
+{
+  DemoImage *demo = DEMO_IMAGE (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)));
+
+  gtk_popover_popup (GTK_POPOVER (demo->popover));
+}
+
+static void
+demo_image_init (DemoImage *demo)
+{
+  GMenu *menu;
+  GMenuItem *item;
+  GtkDragSource *source;
+  GtkDropTarget *dest;
+  GtkGesture *gesture;
+
+  demo->image = gtk_image_new ();
+  gtk_image_set_pixel_size (GTK_IMAGE (demo->image), 48);
+  gtk_widget_set_parent (demo->image, GTK_WIDGET (demo));
+
+  menu = g_menu_new (); 
+  item = g_menu_item_new (_("_Copy"), "clipboard.copy");
+  g_menu_append_item (menu, item);
+
+  item = g_menu_item_new (_("_Paste"), "clipboard.paste");
+  g_menu_append_item (menu, item);
+
+  demo->popover = gtk_popover_menu_new_from_model (G_MENU_MODEL (menu));
+  gtk_widget_set_parent (demo->popover, GTK_WIDGET (demo));
+
+  source = gtk_drag_source_new ();
+  g_signal_connect (source, "prepare", G_CALLBACK (prepare_drag), NULL);
+  g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), NULL);
+  gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (source));
+
+  dest = gtk_drop_target_new (GDK_TYPE_PAINTABLE, GDK_ACTION_COPY);
+  g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), NULL);
+  gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (dest));
+
+  gesture = gtk_gesture_click_new ();
+  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
+  g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), NULL);
+  gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (gesture));
+}
+
+static void
+demo_image_dispose (GObject *object)
+{
+  DemoImage *demo = DEMO_IMAGE (object);
+
+  g_clear_pointer (&demo->image, gtk_widget_unparent);
+  g_clear_pointer (&demo->popover, gtk_widget_unparent);
+
+  G_OBJECT_CLASS (demo_image_parent_class)->dispose (object);
+}
+
+static void
+demo_image_get_property (GObject    *object,
+                         guint       prop_id,
+                         GValue     *value,
+                         GParamSpec *pspec)
+{
+  DemoImage *demo = DEMO_IMAGE (object);
+
+  switch (prop_id)
+    {
+    case PROP_ICON_NAME:
+      g_value_set_string (value, gtk_image_get_icon_name (GTK_IMAGE (demo->image)));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+demo_image_set_property (GObject      *object,
+                         guint         prop_id,
+                         const GValue *value,
+                         GParamSpec   *pspec)
+{
+  DemoImage *demo = DEMO_IMAGE (object);
+
+  switch (prop_id)
+    {
+    case PROP_ICON_NAME:
+      gtk_image_set_from_icon_name (GTK_IMAGE (demo->image),
+                                    g_value_get_string (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+demo_image_class_init (DemoImageClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+  object_class->dispose = demo_image_dispose;
+  object_class->get_property = demo_image_get_property;
+  object_class->set_property = demo_image_set_property;
+
+  g_object_class_install_property (object_class, PROP_ICON_NAME,
+      g_param_spec_string ("icon-name", "Icon name", "Icon name",
+                           NULL, G_PARAM_READWRITE));
+                       
+  gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
+
+  gtk_widget_class_install_action (widget_class, "clipboard.copy", NULL, copy_image);
+  gtk_widget_class_install_action (widget_class, "clipboard.paste", NULL, paste_image);
+}
+
+GtkWidget *
+demo_image_new (const char *icon_name)
+{
+  return g_object_new (DEMO_TYPE_IMAGE, "icon-name", icon_name, NULL);
+}
diff --git a/demos/gtk-demo/demoimage.h b/demos/gtk-demo/demoimage.h
new file mode 100644
index 00000000000..bd8e160a731
--- /dev/null
+++ b/demos/gtk-demo/demoimage.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define DEMO_TYPE_IMAGE (demo_image_get_type ())
+
+G_DECLARE_FINAL_TYPE(DemoImage, demo_image, DEMO, IMAGE, GtkWidget)
+
+GtkWidget * demo_image_new (const char *icon_name);
+
+G_END_DECLS
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index 8a4ad34d6e9..a2750049b73 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -90,6 +90,7 @@ extra_demo_sources = files(['main.c',
                             'gtkgears.c',
                             'puzzlepiece.c',
                             'bluroverlay.c',
+                            'demoimage.c',
                             'demotaggedentry.c'])
 
 if harfbuzz_dep.found() and pangoft_dep.found()


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