[Xfce4-commits] <design:master> Work on DnD, entirely experimental though.

Jannis Pohlmann noreply at xfce.org
Sun Jun 5 01:40:01 CEST 2011


Updating branch refs/heads/master
         to 883cf7f2623c63c28e237d8f4c9011760a9708c0 (commit)
       from 6106a699ed82d7a1c8ab5de5ac1a42e711f3e5e2 (commit)

commit 883cf7f2623c63c28e237d8f4c9011760a9708c0
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Sun Jun 5 01:36:51 2011 +0200

    Work on DnD, entirely experimental though.

 .../demo-code/custom-view/drag-source.vala         |   27 +++
 .../demo-code/custom-view/mockup.vala              |   19 ++-
 .../demo-code/custom-view/shortcut-row.vala        |   11 +-
 .../demo-code/custom-view/shortcuts-view.vala      |  236 ++++++++++++++++++--
 4 files changed, 271 insertions(+), 22 deletions(-)

diff --git a/thunar/shortcuts-pane/demo-code/custom-view/drag-source.vala b/thunar/shortcuts-pane/demo-code/custom-view/drag-source.vala
index baaa0cf..1d8a763 100644
--- a/thunar/shortcuts-pane/demo-code/custom-view/drag-source.vala
+++ b/thunar/shortcuts-pane/demo-code/custom-view/drag-source.vala
@@ -24,11 +24,38 @@ using Gtk;
 
 class DragSource : EventBox {
 
+  public static enum DragInfo {
+    TEXT_URI_LIST
+  }
+
   public string location { get; set; }
 
   public DragSource (string location) {
     this.location = location;
 
+    TargetEntry targets[1] = {
+      TargetEntry () {
+        target = "text/uri-list",
+        flags = 0,
+        info = DragInfo.TEXT_URI_LIST
+      }
+    };
+
+    drag_source_set (this, Gdk.ModifierType.BUTTON1_MASK, targets, Gdk.DragAction.COPY);
+
+    drag_begin.connect ((context) => {
+      debug ("drag begin");
+    });
+
+    drag_data_get.connect ((context, selection_data, info, time) => {
+      debug ("drag data get");
+      selection_data.set_uris (new string[] { location });
+    });
+
+    drag_end.connect ((context) => {
+      debug ("drag end");
+    });
+
     var label = new Label (this.location);
     add (label);
     label.show ();
diff --git a/thunar/shortcuts-pane/demo-code/custom-view/mockup.vala b/thunar/shortcuts-pane/demo-code/custom-view/mockup.vala
index 77a7484..72adee5 100644
--- a/thunar/shortcuts-pane/demo-code/custom-view/mockup.vala
+++ b/thunar/shortcuts-pane/demo-code/custom-view/mockup.vala
@@ -55,12 +55,27 @@ int main (string[] args) {
   viewport.add (view);
   view.show ();
 
+  var drag_frame = new Frame (null);
+  drag_frame.set_label_align (0.5f, 0.5f);
+  box.pack_start (drag_frame, false, true, 0);
+  drag_frame.show ();
+
+  var drag_frame_label = new Label ("<b>Drag us</b>");
+  drag_frame_label.set_use_markup (true);
+  drag_frame.set_label_widget (drag_frame_label);
+  drag_frame_label.show ();
+
+  var drag_sources = new VBox (false, 6);
+  drag_sources.set_border_width (6);
+  drag_frame.add (drag_sources);
+  drag_sources.show ();
+
   var local_file = new DragSource ("file:///home/jannis/foo.txt");
-  box.pack_start (local_file, false, true, 0);
+  drag_sources.pack_start (local_file, false, true, 0);
   local_file.show ();
 
   var remote_uri = new DragSource ("sftp://xfce.org/home/jannis/bar.txt");
-  box.pack_start (remote_uri, false, true, 0);
+  drag_sources.pack_start (remote_uri, false, true, 0);
   remote_uri.show ();
 
   window.show ();
diff --git a/thunar/shortcuts-pane/demo-code/custom-view/shortcut-row.vala b/thunar/shortcuts-pane/demo-code/custom-view/shortcut-row.vala
index 0ef1b6f..b6bad1a 100644
--- a/thunar/shortcuts-pane/demo-code/custom-view/shortcut-row.vala
+++ b/thunar/shortcuts-pane/demo-code/custom-view/shortcut-row.vala
@@ -26,13 +26,14 @@ public class ShortcutRow : EventBox {
   public string title { get; set; }
   public string icon_name { get; set; }
   public bool connected { get; set; }
+  public bool is_drop_target { get; set; default = false; }
 
   private Image disconnect_icon { get; set; }
   private Image cancel_icon { get; set; }
   private Button button { get; set; }
   private Spinner spinner { get; set; }
 
-  public ShortcutRow (string title, string icon_name, bool connected) {
+  public ShortcutRow (string? title, string? icon_name, bool connected) {
     this.title = title;
     this.icon_name = icon_name;
     this.connected = connected;
@@ -49,6 +50,14 @@ public class ShortcutRow : EventBox {
     align.add (box);
     box.show ();
 
+    notify["is-drop-target"].connect (() => {
+      if (this.is_drop_target) {
+        drag_highlight (box);
+      } else {
+        drag_unhighlight (box);
+      }
+    });
+
     var icon = new Image.from_icon_name (icon_name, IconSize.MENU);
     box.pack_start (icon, false, true, 0);
     icon.show ();
diff --git a/thunar/shortcuts-pane/demo-code/custom-view/shortcuts-view.vala b/thunar/shortcuts-pane/demo-code/custom-view/shortcuts-view.vala
index c934a2a..c1fc5e3 100644
--- a/thunar/shortcuts-pane/demo-code/custom-view/shortcuts-view.vala
+++ b/thunar/shortcuts-pane/demo-code/custom-view/shortcuts-view.vala
@@ -24,9 +24,11 @@ using Gtk;
 
 public class Category : GLib.Object {
   public string name { get; set; }
+  public bool supports_bookmarks { get; set; default = false; }
 
-  public Category (string name) {
+  public Category (string name, bool supports_bookmarks) {
     this.name = name;
+    this.supports_bookmarks = supports_bookmarks;
   }
 }
 
@@ -46,10 +48,50 @@ public class Shortcut : GLib.Object {
 
 
 
+public class CategoryExpander : Expander {
+  public Category category { get; set; }
+  public Container container { get; private set; }
+  public ShortcutRow? drop_indicator { get; private set; default = null; }
+
+  public CategoryExpander (Category category) {
+    this.category = category;
+
+    var markup = "<span size='medium' weight='bold' color='#353535'>%s</span>";
+    set_label (GLib.Markup.printf_escaped (markup, category.name));
+
+    set_border_width (0);
+    set_use_markup (true);
+    set_expanded (true);
+    set_spacing (0);
+
+    container = new VBox (false, 0);
+    add (container);
+    container.show ();
+  }
+
+  public void add_drop_indicator () {
+    drop_indicator = new ShortcutRow (null, null, false);
+    drop_indicator.set_no_show_all (true);
+    drop_indicator.set_visible (false);
+    container.add (drop_indicator);
+  }
+}
+
+
+
 public class ShortcutsView : EventBox {
   private Alignment alignment { get; set; }
   private VBox box { get; set; }
-  private unowned List<Expander> expanders { get; set; }
+  private unowned List<CategoryExpander> expanders { get; set; }
+
+  private bool drop_data_ready { get; set; default = false; }
+  private bool drop_occured { get; set; default = false; }
+  private TargetList drop_targets { get; set; default = null; }
+  private string[]? drop_uris { get; set; default = null; }
+
+  public static enum DragInfo {
+    TEXT_URI_LIST
+  }
 
   public ShortcutsView () {
     alignment = new Alignment (0.0f, 0.0f, 1.0f, 1.0f);
@@ -63,12 +105,12 @@ public class ShortcutsView : EventBox {
 
     List<GLib.Object> shortcuts = new List<GLib.Object> ();
 
-    shortcuts.append (new Category ("DEVICES"));
+    shortcuts.append (new Category ("DEVICES", false));
     shortcuts.append (new Shortcut ("File System", "harddrive", false));
     shortcuts.append (new Shortcut ("iPod", "multimedia-player", true));
     shortcuts.append (new Shortcut ("Blank DVD+RW Disc", "media-optical-dvd", true));
 
-    shortcuts.append (new Category ("PLACES"));
+    shortcuts.append (new Category ("PLACES", true));
     shortcuts.append (new Shortcut ("jannis", "user-home", false));
     shortcuts.append (new Shortcut ("Desktop", "user-desktop", false));
     shortcuts.append (new Shortcut ("Trash", "user-trash", false));
@@ -76,39 +118,195 @@ public class ShortcutsView : EventBox {
     shortcuts.append (new Shortcut ("Downloads", "folder", false));
     shortcuts.append (new Shortcut ("Thesis", "folder", false));
 
-    shortcuts.append (new Category ("NETWORK"));
+    shortcuts.append (new Category ("NETWORK", true));
     shortcuts.append (new Shortcut ("sftp at xfce.org", "folder-remote", true));
     shortcuts.append (new Shortcut ("ftp at gezeiten.org", "folder-remote", false));
 
-    expanders = new List<Expander> ();
+    expanders = new List<CategoryExpander> ();
 
-    Container? container = null;
+    CategoryExpander? expander = null;
     foreach (var item in shortcuts) {
       if (item is Category) {
         Category category = (Category) item;
 
-        var markup = "<span size='medium' weight='bold' color='#353535'>%s</span>";
-
-        var expander = new Expander (GLib.Markup.printf_escaped (markup, category.name));
-        expander.set_border_width (0);
-        expander.set_use_markup (true);
-        expander.set_expanded (true);
-        expander.set_spacing (0);
+        expander = new CategoryExpander (category);
         box.pack_start (expander, false, true, 0);
-
-        container = new VBox (false, 0);
-        expander.add (container);
-        container.show ();
+        expander.show ();
 
         expanders.append (expander);
       } else {
         Shortcut shortcut = (Shortcut) item;
         var row = new ShortcutRow (shortcut.name, shortcut.icon_name, shortcut.connected);
-        container.add (row);
+        expander.container.add (row);
         row.show ();
       }
     }
 
+    foreach (var exp in expanders) {
+      if (exp.category.supports_bookmarks) {
+        exp.add_drop_indicator ();
+      }
+    }
+
     show_all ();
+
+    /* create list of supported drop targets */
+    TargetEntry target_entries[1] = {
+      TargetEntry () {
+        target = "text/uri-list",
+        flags = 0,
+        info = DragInfo.TEXT_URI_LIST
+      }
+    };
+
+    /* remember this list for use in DnD handlers */
+    drop_targets = new TargetList (target_entries);
+
+    /* set the view as a drag destination for these targets */
+    drag_dest_set (this, 0, target_entries, Gdk.DragAction.COPY);
+  }
+
+  public bool find_category_for_file (GLib.File file,
+                                      out CategoryExpander? expander)
+  {
+    foreach (var exp in expanders) {
+      if (exp.category.name == "PLACES" && file.has_uri_scheme ("file")) {
+        expander = exp;
+        return true;
+      } else if (exp.category.name == "NETWORK" && file.has_uri_scheme ("sftp")) {
+        expander = exp;
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  public override bool drag_motion (Gdk.DragContext context,
+                                    int x,
+                                    int y,
+                                    uint time) {
+    debug ("drag motion");
+
+    /* request drop data on demand */
+    if (!drop_data_ready) {
+      /* check if we can handle the drag data (only text/uri-list supported) */
+      var target = drag_dest_find_target (this, context, drop_targets);
+      if (target == Gdk.Atom.intern_static_string ("text/uri-list")) {
+        /* request drop data from the source */
+        drag_get_data (this, context, target, time);
+      }
+
+      /* we are not ready to drop yet */
+      Gdk.drag_status (context, 0, time);
+    } else {
+      /* create a file object for the URI */
+      var file = GLib.File.new_for_uri (drop_uris[0]);
+
+      /* find the correct category for it */
+      CategoryExpander? expander = null;
+      if (find_category_for_file (file, out expander)) {
+        if (expander.drop_indicator != null) {
+          expander.drop_indicator.is_drop_target = true;
+          expander.drop_indicator.set_visible (true);
+        }
+
+        /* we have drop data, now we can create the bookmark */
+        Gdk.drag_status (context, Gdk.DragAction.COPY, time);
+      } else {
+        /* we have an unsupported drop URI, cannot handle it */
+        Gdk.drag_status (context, 0, time);
+      }
+    }
+
+    return true;
+  }
+
+  public override void drag_leave (Gdk.DragContext context, uint time) {
+    debug ("drag leave, reset flags");
+
+    if (drop_data_ready) {
+      /* create a file object for the URI */
+      var file = GLib.File.new_for_uri (drop_uris[0]);
+
+      /* find the correct category for it */
+      CategoryExpander? expander = null;
+      if (find_category_for_file (file, out expander)) {
+        if (expander.drop_indicator != null) {
+          expander.drop_indicator.is_drop_target = false;
+          expander.drop_indicator.set_visible (false);
+        }
+      }
+    }
+
+    drop_data_ready = false;
+    drop_occured = false;
+    drop_uris = null;
+  }
+
+  public override bool drag_drop (Gdk.DragContext context,
+                                  int x,
+                                  int y,
+                                  uint time)
+  {
+    /* determine the DnD target and see if we can handle it */
+    var target = drag_dest_find_target (this, context, drop_targets);
+    if (target == Gdk.Atom.intern_static_string ("text/uri-list")) {
+      debug ("drag drop, supports target, perform drop");
+
+      /* set flag so that drag_data_received knows we are dropping for real */
+      drop_occured = true;
+
+      /* request data from drag source */
+      drag_get_data (this, context, target, time);
+
+      /* we will call drag_finish later */
+      return true;
+    } else {
+      debug ("drag drop, target unsupported, cancel drop");
+
+      /* cancel drop */
+      return false;
+    }
+  }
+
+  public override void drag_data_received (Gdk.DragContext context,
+                                           int x,
+                                           int y,
+                                           SelectionData selection_data,
+                                           uint info,
+                                           uint time)
+  {
+    debug ("drag data received");
+
+    string[] uris = selection_data.get_uris ();
+
+    if (!drop_data_ready) {
+      drop_uris = uris;
+      drop_data_ready = true;
+
+      if (uris != null) {
+        debug ("request from drag motion, have uris");
+      } else {
+        debug ("request from drag motion, don't have uris");
+      }
+    }
+
+    if (drop_occured) {
+      /* reset the drop state */
+      drop_occured = false;
+
+      if (drop_uris != null) {
+        debug ("have uris, create bookmark now");
+      } else {
+        debug ("don't have uris, abort drag-and-drop");
+      }
+
+      /* tell the drag source that we handled the drop */
+      drag_finish (context, drop_uris != null, false, time);
+
+      /* disable highlighting and release the drag data */
+      drag_leave (context, time);
+    }
   }
 }



More information about the Xfce4-commits mailing list