[gnome-flashback] desktop: make icons selectable



commit a9bf9ce60eaadcb6bb77f90844362a921e7c5ab2
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Sun Nov 10 22:35:37 2019 +0200

    desktop: make icons selectable

 gnome-flashback/libdesktop/Makefile.am    |   1 +
 gnome-flashback/libdesktop/gf-icon-view.c | 127 ++++++++++++++++++++++++------
 gnome-flashback/libdesktop/gf-icon.c      |  98 ++++++++++++++++++++++-
 gnome-flashback/libdesktop/gf-icon.h      |  19 +++--
 4 files changed, 216 insertions(+), 29 deletions(-)
---
diff --git a/gnome-flashback/libdesktop/Makefile.am b/gnome-flashback/libdesktop/Makefile.am
index 50da485..827ce32 100644
--- a/gnome-flashback/libdesktop/Makefile.am
+++ b/gnome-flashback/libdesktop/Makefile.am
@@ -45,6 +45,7 @@ libdesktop_la_LIBADD = \
 
 ENUM_TYPES = \
        $(srcdir)/gf-desktop-enums.h \
+       $(srcdir)/gf-icon.h \
        $(NULL)
 
 gf-desktop-enum-types.c: gf-desktop-enum-types.c.in gf-desktop-enum-types.h $(ENUM_TYPES)
diff --git a/gnome-flashback/libdesktop/gf-icon-view.c b/gnome-flashback/libdesktop/gf-icon-view.c
index 71407d5..f95884e 100644
--- a/gnome-flashback/libdesktop/gf-icon-view.c
+++ b/gnome-flashback/libdesktop/gf-icon-view.c
@@ -34,6 +34,8 @@ struct _GfIconView
 {
   GtkEventBox   parent;
 
+  GtkGesture   *multi_press;
+
   GFile        *desktop;
   GFileMonitor *monitor;
 
@@ -46,6 +48,8 @@ struct _GfIconView
   GList        *icons;
 
   guint         add_icons_id;
+
+  GList        *selected_icons;
 };
 
 G_DEFINE_TYPE (GfIconView, gf_icon_view, GTK_TYPE_EVENT_BOX)
@@ -186,6 +190,8 @@ file_deleted (GfIconView *self,
           gf_monitor_view_remove_icon (GF_MONITOR_VIEW (info->view),
                                        info->icon);
 
+          self->selected_icons = g_list_remove (self->selected_icons, l->data);
+
           self->icons = g_list_remove_link (self->icons, l);
           g_list_free_full (l, gf_icon_info_free);
 
@@ -194,6 +200,60 @@ file_deleted (GfIconView *self,
     }
 }
 
+static void
+unselect_cb (gpointer data,
+             gpointer user_data)
+{
+  gf_icon_set_selected (data, FALSE, GF_ICON_SELECTED_NONE);
+}
+
+static void
+unselect_icons (GfIconView *self)
+{
+  if (self->selected_icons == NULL)
+    return;
+
+  g_list_foreach (self->selected_icons, unselect_cb, NULL);
+  g_clear_pointer (&self->selected_icons, g_list_free);
+}
+
+static void
+icon_selected_cb (GfIcon              *icon,
+                  GfIconSelectedFlags  flags,
+                  GfIconView          *self)
+{
+  if ((flags & GF_ICON_SELECTED_CLEAR) == GF_ICON_SELECTED_CLEAR)
+    unselect_icons (self);
+
+  if ((flags & GF_ICON_SELECTED_ADD) == GF_ICON_SELECTED_ADD)
+    self->selected_icons = g_list_append (self->selected_icons, icon);
+
+  if ((flags & GF_ICON_SELECTED_REMOVE) == GF_ICON_SELECTED_REMOVE)
+    self->selected_icons = g_list_remove (self->selected_icons, icon);
+}
+
+static GfIconInfo *
+create_icon_info (GfIconView *self,
+                  GFile      *file,
+                  GFileInfo  *info)
+{
+  GtkWidget *icon;
+
+  icon = gf_icon_new (file, info);
+
+  g_signal_connect (icon, "selected", G_CALLBACK (icon_selected_cb), self);
+
+  g_settings_bind (self->settings, "icon-size",
+                   icon, "icon-size",
+                   G_SETTINGS_BIND_GET);
+
+  g_settings_bind (self->settings, "extra-text-width",
+                   icon, "extra-text-width",
+                   G_SETTINGS_BIND_GET);
+
+  return gf_icon_info_new (icon);
+}
+
 static void
 query_info_cb (GObject      *object,
                GAsyncResult *res,
@@ -203,7 +263,7 @@ query_info_cb (GObject      *object,
   GFileInfo *file_info;
   GError *error;
   GfIconView *self;
-  GtkWidget *icon;
+  GfIconInfo *icon_info;
 
   file = G_FILE (object);
 
@@ -221,18 +281,10 @@ query_info_cb (GObject      *object,
 
   self = GF_ICON_VIEW (user_data);
 
-  icon = gf_icon_new (file, file_info);
+  icon_info = create_icon_info (self, file, file_info);
   g_object_unref (file_info);
 
-  g_settings_bind (self->settings, "icon-size",
-                   icon, "icon-size",
-                   G_SETTINGS_BIND_GET);
-
-  g_settings_bind (self->settings, "extra-text-width",
-                   icon, "extra-text-width",
-                   G_SETTINGS_BIND_GET);
-
-  self->icons = g_list_append (self->icons, gf_icon_info_new (icon));
+  self->icons = g_list_append (self->icons, icon_info);
 
   add_icons (self);
 }
@@ -308,6 +360,34 @@ desktop_changed_cb (GFileMonitor      *monitor,
     }
 }
 
+static void
+multi_press_pressed_cb (GtkGestureMultiPress *gesture,
+                        gint                  n_press,
+                        gdouble               x,
+                        gdouble               y,
+                        GfIconView           *self)
+{
+  guint button;
+  GdkEventSequence *sequence;
+  const GdkEvent *event;
+
+  button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
+  sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
+  event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
+
+  if (event == NULL)
+    return;
+
+  unselect_icons (self);
+
+  if (button == GDK_BUTTON_PRIMARY)
+    {
+    }
+  else if (button == GDK_BUTTON_SECONDARY)
+    {
+    }
+}
+
 static void
 view_foreach_cb (GtkWidget *widget,
                  gpointer   user_data)
@@ -371,23 +451,15 @@ next_files_cb (GObject      *object,
     {
       GFileInfo *info;
       GFile *file;
-      GtkWidget *icon;
+      GfIconInfo *icon_info;
 
       info = l->data;
       file = g_file_enumerator_get_child (enumerator, info);
 
-      icon = gf_icon_new (file, info);
+      icon_info = create_icon_info (self, file, info);
       g_object_unref (file);
 
-      g_settings_bind (self->settings, "icon-size",
-                       icon, "icon-size",
-                       G_SETTINGS_BIND_GET);
-
-      g_settings_bind (self->settings, "extra-text-width",
-                       icon, "extra-text-width",
-                       G_SETTINGS_BIND_GET);
-
-      self->icons = g_list_prepend (self->icons, gf_icon_info_new (icon));
+      self->icons = g_list_prepend (self->icons, icon_info);
     }
 
   self->icons = g_list_reverse (self->icons);
@@ -572,6 +644,7 @@ gf_icon_view_dispose (GObject *object)
 
   self = GF_ICON_VIEW (object);
 
+  g_clear_object (&self->multi_press);
   g_clear_object (&self->desktop);
   g_clear_object (&self->monitor);
   g_clear_object (&self->settings);
@@ -585,6 +658,8 @@ gf_icon_view_dispose (GObject *object)
       self->icons = NULL;
     }
 
+  g_clear_pointer (&self->selected_icons, g_list_free);
+
   G_OBJECT_CLASS (gf_icon_view_parent_class)->dispose (object);
 }
 
@@ -624,6 +699,14 @@ gf_icon_view_init (GfIconView *self)
   int n_monitors;
   int i;
 
+  self->multi_press = gtk_gesture_multi_press_new (GTK_WIDGET (self));
+
+  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (self->multi_press), 0);
+
+  g_signal_connect (self->multi_press, "pressed",
+                    G_CALLBACK (multi_press_pressed_cb),
+                    self);
+
   desktop_dir = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP);
   self->desktop = g_file_new_for_path (desktop_dir);
 
diff --git a/gnome-flashback/libdesktop/gf-icon.c b/gnome-flashback/libdesktop/gf-icon.c
index b3f93ca..9eab1b9 100644
--- a/gnome-flashback/libdesktop/gf-icon.c
+++ b/gnome-flashback/libdesktop/gf-icon.c
@@ -25,6 +25,8 @@ struct _GfIcon
 {
   GtkButton   parent;
 
+  GtkGesture *multi_press;
+
   GFile      *file;
   GFileInfo  *info;
 
@@ -52,6 +54,15 @@ enum
 
 static GParamSpec *icon_properties[LAST_PROP] = { NULL };
 
+enum
+{
+  SELECTED,
+
+  LAST_SIGNAL
+};
+
+static guint icon_signals[LAST_SIGNAL] = { 0 };
+
 G_DEFINE_TYPE (GfIcon, gf_icon, GTK_TYPE_BUTTON)
 
 static void
@@ -68,6 +79,66 @@ update_state (GfIcon *self)
   gtk_widget_set_state_flags (GTK_WIDGET (self), state, TRUE);
 }
 
+static void
+multi_press_pressed_cb (GtkGestureMultiPress *gesture,
+                        gint                  n_press,
+                        gdouble               x,
+                        gdouble               y,
+                        GfIcon               *self)
+{
+  guint button;
+  GdkEventSequence *sequence;
+  const GdkEvent *event;
+  GfIconSelectedFlags flags;
+  GdkModifierType state;
+  gboolean control_pressed;
+  gboolean shift_pressed;
+
+  button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
+  sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
+  event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
+  flags = GF_ICON_SELECTED_NONE;
+
+  if (event == NULL)
+    return;
+
+  gdk_event_get_state (event, &state);
+
+  control_pressed = (state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK;
+  shift_pressed = (state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK;
+
+  if (button == GDK_BUTTON_PRIMARY)
+    {
+      gboolean selected;
+
+      if (!control_pressed && !shift_pressed)
+        flags |= GF_ICON_SELECTED_CLEAR;
+
+      if (control_pressed || shift_pressed)
+        {
+          selected = !self->selected;
+
+          if (self->selected)
+            flags |= GF_ICON_SELECTED_REMOVE;
+          else
+            flags |= GF_ICON_SELECTED_ADD;
+        }
+      else
+        {
+          selected = TRUE;
+          flags |= GF_ICON_SELECTED_ADD;
+        }
+
+      gf_icon_set_selected (self, selected, flags);
+    }
+  else if (button == GDK_BUTTON_SECONDARY)
+    {
+    }
+  else if (button == GDK_BUTTON_MIDDLE)
+    {
+    }
+}
+
 static void
 gf_icon_constructed (GObject *object)
 {
@@ -94,6 +165,8 @@ gf_icon_dispose (GObject *object)
 
   self = GF_ICON (object);
 
+  g_clear_object (&self->multi_press);
+
   g_clear_object (&self->file);
   g_clear_object (&self->info);
 
@@ -200,6 +273,15 @@ install_properties (GObjectClass *object_class)
   g_object_class_install_properties (object_class, LAST_PROP, icon_properties);
 }
 
+static void
+install_signals (void)
+{
+  icon_signals[SELECTED] =
+    g_signal_new ("selected", GF_TYPE_ICON, G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL, NULL, G_TYPE_NONE, 1,
+                  GF_TYPE_ICON_SELECTED_FLAGS);
+}
+
 static void
 gf_icon_class_init (GfIconClass *self_class)
 {
@@ -216,6 +298,7 @@ gf_icon_class_init (GfIconClass *self_class)
   widget_class->get_preferred_width = gf_icon_get_preferred_width;
 
   install_properties (object_class);
+  install_signals ();
 
   gtk_widget_class_set_css_name (widget_class, "gf-icon");
 }
@@ -229,6 +312,14 @@ gf_icon_init (GfIcon *self)
   PangoAttrList *attrs;
 #endif
 
+  self->multi_press = gtk_gesture_multi_press_new (GTK_WIDGET (self));
+
+  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (self->multi_press), 0);
+
+  g_signal_connect (self->multi_press, "pressed",
+                    G_CALLBACK (multi_press_pressed_cb),
+                    self);
+
   box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
   gtk_container_add (GTK_CONTAINER (self), box);
   gtk_widget_show (box);
@@ -270,14 +361,17 @@ gf_icon_new (GFile     *file,
 }
 
 void
-gf_icon_set_selected (GfIcon   *self,
-                      gboolean  selected)
+gf_icon_set_selected (GfIcon              *self,
+                      gboolean             selected,
+                      GfIconSelectedFlags  flags)
 {
   if (self->selected == selected)
     return;
 
   self->selected = selected;
   update_state (self);
+
+  g_signal_emit (self, icon_signals[SELECTED], 0, flags);
 }
 
 GFile *
diff --git a/gnome-flashback/libdesktop/gf-icon.h b/gnome-flashback/libdesktop/gf-icon.h
index 2903c8f..2ff4961 100644
--- a/gnome-flashback/libdesktop/gf-icon.h
+++ b/gnome-flashback/libdesktop/gf-icon.h
@@ -22,16 +22,25 @@
 
 G_BEGIN_DECLS
 
+typedef enum
+{
+  GF_ICON_SELECTED_NONE = 0,
+  GF_ICON_SELECTED_CLEAR = (1 << 0),
+  GF_ICON_SELECTED_ADD = (1 << 1),
+  GF_ICON_SELECTED_REMOVE = (1 << 2)
+} GfIconSelectedFlags;
+
 #define GF_TYPE_ICON (gf_icon_get_type ())
 G_DECLARE_FINAL_TYPE (GfIcon, gf_icon, GF, ICON, GtkButton)
 
-GtkWidget *gf_icon_new          (GFile     *file,
-                                 GFileInfo *info);
+GtkWidget *gf_icon_new          (GFile               *file,
+                                 GFileInfo           *info);
 
-void       gf_icon_set_selected (GfIcon    *self,
-                                 gboolean   selected);
+void       gf_icon_set_selected (GfIcon              *self,
+                                 gboolean             selected,
+                                 GfIconSelectedFlags  flags);
 
-GFile     *gf_icon_get_file     (GfIcon    *self);
+GFile     *gf_icon_get_file     (GfIcon              *self);
 
 G_END_DECLS
 


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