[libdazzle/suggestion-secondary-icon] suggestion: Add secondary icon support



commit fad5ff25649e53fe8cf50c3d83ad9dba0dd0ddc0
Author: Jan-Michael Brummer <jan brummer tabos org>
Date:   Thu Jan 2 23:45:24 2020 +0100

    suggestion: Add secondary icon support
    
    Fixes: https://gitlab.gnome.org/GNOME/libdazzle/issues/50

 src/dzl-version-macros.h              |   7 ++
 src/suggestions/dzl-suggestion-row.c  |  36 +++++++++++
 src/suggestions/dzl-suggestion-row.ui |  14 ++++
 src/suggestions/dzl-suggestion.c      | 117 ++++++++++++++++++++++++++++++++++
 src/suggestions/dzl-suggestion.h      |  17 ++++-
 5 files changed, 188 insertions(+), 3 deletions(-)
---
diff --git a/src/dzl-version-macros.h b/src/dzl-version-macros.h
index 2eea9a8..166036c 100644
--- a/src/dzl-version-macros.h
+++ b/src/dzl-version-macros.h
@@ -45,6 +45,7 @@
 #define DZL_VERSION_3_30 (G_ENCODE_VERSION (3, 30))
 #define DZL_VERSION_3_32 (G_ENCODE_VERSION (3, 32))
 #define DZL_VERSION_3_34 (G_ENCODE_VERSION (3, 34))
+#define DZL_VERSION_3_36 (G_ENCODE_VERSION (3, 36))
 
 #if (DZL_MINOR_VERSION == 99)
 # define DZL_VERSION_CUR_STABLE (G_ENCODE_VERSION (DZL_MAJOR_VERSION + 1, 0))
@@ -173,4 +174,10 @@
 # define DZL_AVAILABLE_IN_3_34                 _DZL_EXTERN
 #endif
 
+#if DZL_VERSION_MAX_ALLOWED < DZL_VERSION_3_36
+# define DZL_AVAILABLE_IN_3_36                 DZL_UNAVAILABLE(3, 36)
+#else
+# define DZL_AVAILABLE_IN_3_36                 _DZL_EXTERN
+#endif
+
 #endif /* DZL_VERSION_MACROS_H */
diff --git a/src/suggestions/dzl-suggestion-row.c b/src/suggestions/dzl-suggestion-row.c
index 4d643cf..b073002 100644
--- a/src/suggestions/dzl-suggestion-row.c
+++ b/src/suggestions/dzl-suggestion-row.c
@@ -30,8 +30,10 @@ typedef struct
   GtkOrientation orientation;
 
   gulong         notify_icon_handler;
+  gulong         notify_secondary_icon_handler;
 
   GtkImage      *image;
+  GtkImage      *secondary_image;
   GtkLabel      *title;
   GtkLabel      *separator;
   GtkLabel      *subtitle;
@@ -63,8 +65,10 @@ dzl_suggestion_row_disconnect (DzlSuggestionRow *self)
     return;
 
   dzl_clear_signal_handler (priv->suggestion, &priv->notify_icon_handler);
+  dzl_clear_signal_handler (priv->suggestion, &priv->notify_secondary_icon_handler);
 
   g_object_set (priv->image, "icon-name", NULL, NULL);
+  g_object_set (priv->secondary_image, "icon-name", NULL, NULL);
   gtk_label_set_label (priv->title, NULL);
   gtk_label_set_label (priv->subtitle, NULL);
 }
@@ -92,6 +96,29 @@ on_notify_icon_cb (DzlSuggestionRow *self,
     }
 }
 
+static void
+on_notify_secondary_icon_cb (DzlSuggestionRow *self,
+                             GParamSpec       *pspec,
+                             DzlSuggestion    *suggestion)
+{
+  DzlSuggestionRowPrivate *priv = dzl_suggestion_row_get_instance_private (self);
+  cairo_surface_t *surface;
+
+  g_assert (DZL_IS_SUGGESTION_ROW (self));
+  g_assert (DZL_IS_SUGGESTION (suggestion));
+
+  if ((surface = dzl_suggestion_get_secondary_icon_surface (suggestion, GTK_WIDGET (priv->secondary_image))))
+    {
+      gtk_image_set_from_surface (priv->secondary_image, surface);
+      cairo_surface_destroy (surface);
+    }
+  else
+    {
+      g_autoptr(GIcon) icon = dzl_suggestion_get_secondary_icon (suggestion);
+      gtk_image_set_from_gicon (priv->secondary_image, icon, GTK_ICON_SIZE_MENU);
+    }
+}
+
 static void
 dzl_suggestion_set_orientation (DzlSuggestionRowPrivate *priv)
 {
@@ -148,7 +175,15 @@ dzl_suggestion_row_connect (DzlSuggestionRow *self)
                              self,
                              G_CONNECT_SWAPPED);
 
+  priv->notify_secondary_icon_handler =
+    g_signal_connect_object (priv->suggestion,
+                             "notify::secondary-icon",
+                             G_CALLBACK (on_notify_secondary_icon_cb),
+                             self,
+                             G_CONNECT_SWAPPED);
+
   on_notify_icon_cb (self, NULL, priv->suggestion);
+  on_notify_secondary_icon_cb (self, NULL, priv->suggestion);
 
   gtk_label_set_label (priv->title, dzl_suggestion_get_title (priv->suggestion));
 
@@ -254,6 +289,7 @@ dzl_suggestion_row_class_init (DzlSuggestionRowClass *klass)
 
   gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/dazzle/ui/dzl-suggestion-row.ui");
   gtk_widget_class_bind_template_child_private (widget_class, DzlSuggestionRow, image);
+  gtk_widget_class_bind_template_child_private (widget_class, DzlSuggestionRow, secondary_image);
   gtk_widget_class_bind_template_child_private (widget_class, DzlSuggestionRow, title);
   gtk_widget_class_bind_template_child_private (widget_class, DzlSuggestionRow, subtitle);
   gtk_widget_class_bind_template_child_private (widget_class, DzlSuggestionRow, separator);
diff --git a/src/suggestions/dzl-suggestion-row.ui b/src/suggestions/dzl-suggestion-row.ui
index 57e24f1..8780d88 100644
--- a/src/suggestions/dzl-suggestion-row.ui
+++ b/src/suggestions/dzl-suggestion-row.ui
@@ -72,6 +72,20 @@
             <property name="top_attach">0</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkImage" id="secondary_image">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="valign">center</property>
+            <property name="hexpand">False</property>
+            <property name="pixel_size">16</property>
+            <property name="margin-start">6</property>
+          </object>
+          <packing>
+            <property name="left_attach">4</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
       </object>
     </child>
   </template>
diff --git a/src/suggestions/dzl-suggestion.c b/src/suggestions/dzl-suggestion.c
index 684ff1e..c8357ed 100644
--- a/src/suggestions/dzl-suggestion.c
+++ b/src/suggestions/dzl-suggestion.c
@@ -31,14 +31,18 @@ typedef struct
 
   /* interned string */
   const gchar *icon_name;
+  const gchar *secondary_icon_name;
 
   GIcon *icon;
+  GIcon *secondary_icon;
 } DzlSuggestionPrivate;
 
 enum {
   PROP_0,
   PROP_ICON_NAME,
   PROP_ICON,
+  PROP_SECONDARY_ICON_NAME,
+  PROP_SECONDARY_ICON,
   PROP_ID,
   PROP_SUBTITLE,
   PROP_TITLE,
@@ -69,6 +73,19 @@ dzl_suggestion_real_get_icon (DzlSuggestion *self)
   return NULL;
 }
 
+static GIcon *
+dzl_suggestion_real_get_secondary_icon (DzlSuggestion *self)
+{
+  DzlSuggestionPrivate *priv = dzl_suggestion_get_instance_private (self);
+
+  g_assert (DZL_IS_SUGGESTION (self));
+
+  if (priv->secondary_icon_name != NULL)
+    return g_icon_new_for_string (priv->secondary_icon_name, NULL);
+
+  return NULL;
+}
+
 static void
 dzl_suggestion_finalize (GObject *object)
 {
@@ -106,6 +123,14 @@ dzl_suggestion_get_property (GObject    *object,
       g_value_take_object (value, dzl_suggestion_get_icon (self));
       break;
 
+    case PROP_SECONDARY_ICON_NAME:
+      g_value_set_static_string (value, dzl_suggestion_get_secondary_icon_name (self));
+      break;
+
+    case PROP_SECONDARY_ICON:
+      g_value_take_object (value, dzl_suggestion_get_secondary_icon (self));
+      break;
+
     case PROP_TITLE:
       g_value_set_string (value, dzl_suggestion_get_title (self));
       break;
@@ -133,6 +158,10 @@ dzl_suggestion_set_property (GObject      *object,
       dzl_suggestion_set_icon_name (self, g_value_get_string (value));
       break;
 
+    case PROP_SECONDARY_ICON_NAME:
+      dzl_suggestion_set_secondary_icon_name (self, g_value_get_string (value));
+      break;
+
     case PROP_ID:
       dzl_suggestion_set_id (self, g_value_get_string (value));
       break;
@@ -160,6 +189,7 @@ dzl_suggestion_class_init (DzlSuggestionClass *klass)
   object_class->set_property = dzl_suggestion_set_property;
 
   klass->get_icon = dzl_suggestion_real_get_icon;
+  klass->get_secondary_icon = dzl_suggestion_real_get_secondary_icon;
 
   properties [PROP_ID] =
     g_param_spec_string ("id",
@@ -182,6 +212,20 @@ dzl_suggestion_class_init (DzlSuggestionClass *klass)
                          NULL,
                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
 
+  properties [PROP_SECONDARY_ICON] =
+    g_param_spec_object ("secondary-icon",
+                         "Secondary Icon",
+                         "The secondary GIcon for the suggestion on the right",
+                         G_TYPE_ICON,
+                         (G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_SECONDARY_ICON_NAME] =
+    g_param_spec_string ("secondary-icon-name",
+                         "Secondary Icon Name",
+                         "The name of the secondary icon to display",
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
   properties [PROP_TITLE] =
     g_param_spec_string ("title",
                          "Title",
@@ -240,6 +284,16 @@ dzl_suggestion_get_icon_name (DzlSuggestion *self)
   return priv->icon_name;
 }
 
+const gchar *
+dzl_suggestion_get_secondary_icon_name (DzlSuggestion *self)
+{
+  DzlSuggestionPrivate *priv = dzl_suggestion_get_instance_private (self);
+
+  g_return_val_if_fail (DZL_IS_SUGGESTION (self), NULL);
+
+  return priv->secondary_icon_name;
+}
+
 const gchar *
 dzl_suggestion_get_title (DzlSuggestion *self)
 {
@@ -277,6 +331,23 @@ dzl_suggestion_set_icon_name (DzlSuggestion *self,
     }
 }
 
+void
+dzl_suggestion_set_secondary_icon_name (DzlSuggestion *self,
+                                        const gchar   *icon_name)
+{
+  DzlSuggestionPrivate *priv = dzl_suggestion_get_instance_private (self);
+
+  g_return_if_fail (DZL_IS_SUGGESTION (self));
+
+  icon_name = g_intern_string (icon_name);
+
+  if (priv->secondary_icon_name != icon_name)
+    {
+      priv->secondary_icon_name = icon_name;
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SECONDARY_ICON_NAME]);
+    }
+}
+
 void
 dzl_suggestion_set_id (DzlSuggestion *self,
                        const gchar   *id)
@@ -431,3 +502,49 @@ dzl_suggestion_get_icon_surface (DzlSuggestion *self,
 
   return NULL;
 }
+
+/**
+ * dzl_suggestion_get_secondary_icon:
+ * @self: a #DzlSuggestion
+ *
+ * Gets the secondary icon for the suggestion, if any.
+ *
+ * Returns: (transfer full) (nullable): a #GIcon or %NULL
+ *
+ * Since: 3.36
+ */
+GIcon *
+dzl_suggestion_get_secondary_icon (DzlSuggestion *self)
+{
+  g_return_val_if_fail (DZL_IS_SUGGESTION (self), NULL);
+
+  return DZL_SUGGESTION_GET_CLASS (self)->get_secondary_icon (self);
+}
+
+/**
+ * dzl_suggestion_get_secondary_icon_surface:
+ * @self: a #DzlSuggestion
+ * @widget: a widget that may contain the surface
+ *
+ * This function allows subclasses to dynamicly generate content for the
+ * suggestion such as may be required when integrating with favicons or
+ * similar.
+ *
+ * @widget is provided so that the implementation may determine scale or
+ * any other style-specific settings from the style context.
+ *
+ * Returns: (transfer full) (nullable): a #cairo_surface_t or %NULL
+ *
+ * Since: 3.36
+ */
+cairo_surface_t *
+dzl_suggestion_get_secondary_icon_surface (DzlSuggestion *self,
+                                           GtkWidget     *widget)
+{
+  g_return_val_if_fail (DZL_IS_SUGGESTION (self), NULL);
+
+  if (DZL_SUGGESTION_GET_CLASS (self)->get_secondary_icon_surface)
+    return DZL_SUGGESTION_GET_CLASS (self)->get_secondary_icon_surface (self, widget);
+
+  return NULL;
+}
diff --git a/src/suggestions/dzl-suggestion.h b/src/suggestions/dzl-suggestion.h
index 442dac5..19a32e5 100644
--- a/src/suggestions/dzl-suggestion.h
+++ b/src/suggestions/dzl-suggestion.h
@@ -42,9 +42,9 @@ struct _DzlSuggestionClass
   GIcon           *(*get_icon)           (DzlSuggestion *self);
   cairo_surface_t *(*get_icon_surface)   (DzlSuggestion *self,
                                           GtkWidget     *widget);
-
-  gpointer _reserved3;
-  gpointer _reserved4;
+  GIcon           *(*get_secondary_icon) (DzlSuggestion *self);
+  cairo_surface_t *(*get_secondary_icon_surface)   (DzlSuggestion *self,
+                                                    GtkWidget     *widget);
 };
 
 DZL_AVAILABLE_IN_ALL
@@ -80,6 +80,17 @@ GIcon           *dzl_suggestion_get_icon           (DzlSuggestion *self);
 DZL_AVAILABLE_IN_3_30
 cairo_surface_t *dzl_suggestion_get_icon_surface   (DzlSuggestion *self,
                                                     GtkWidget     *widget);
+DZL_AVAILABLE_IN_3_36
+const gchar     *dzl_suggestion_get_secondary_icon_name (DzlSuggestion *self);
+DZL_AVAILABLE_IN_3_36
+void             dzl_suggestion_set_secondary_icon_name (DzlSuggestion *self,
+                                                         const gchar   *icon_name);
+
+DZL_AVAILABLE_IN_3_36
+GIcon           *dzl_suggestion_get_secondary_icon (DzlSuggestion *self);
+DZL_AVAILABLE_IN_3_36
+cairo_surface_t *dzl_suggestion_get_secondary_icon_surface (DzlSuggestion *self,
+                                                            GtkWidget     *widget);
 
 G_END_DECLS
 


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