[cheese] Add videos and picture sharing support, bug 522210



commit b7079b4b55dac0fc5b8a4c0a5b0c420736e22677
Author: Patricia Santana Cruz <patriciasantanacruz gmail com>
Date:   Thu Dec 22 16:56:26 2011 +0000

    Add videos and picture sharing support, bug 522210
    
    Integrated nautilus-sendto with Cheese in order to add support for sharing
    videos and images with different technologies.

 Makefile.am                     |    4 +-
 README                          |    4 +
 TODO                            |    1 -
 data/cheese-actions.ui          |   12 ++++
 src/cheese-shareable-media.vala |  124 +++++++++++++++++++++++++++++++++++++++
 src/cheese-window.vala          |   49 +++++++++++++++-
 6 files changed, 191 insertions(+), 3 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 11a9d1d..9862b5d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -65,7 +65,8 @@ VALAFLAGS = \
 	--pkg libcanberra \
 	--pkg eogthumbnav \
 	--pkg cheese-thumbview \
-	--pkg cheese-common
+	--pkg cheese-common \
+	--pkg gdk-x11-3.0
 
 lib_LTLIBRARIES = libcheese.la libcheese-gtk.la
 
@@ -190,6 +191,7 @@ cheese_SOURCES = \
 	src/cheese-preferences.vala \
 	src/cheese-window.vala \
 	src/cheese-main.vala \
+	src/cheese-shareable-media.vala \
 	src/thumbview/cheese-thumb-view.c \
 	src/thumbview/cheese-thumbnail.c \
 	src/thumbview/eog-thumb-nav.c
diff --git a/README b/README
index a27e561..d6a71df 100644
--- a/README
+++ b/README
@@ -10,3 +10,7 @@ How to get your camera working:
 To get your camera working with cheese, you will have to ensure that it works
 with the Gstreamer Framework and Video4Linux2 (V4L2) or Video4Linux (V4L). To
 test this, you can use the 'gstreamer-properties' tool.
+
+Sharing images and videos:
+In order to be able to share images and videos from Cheese, you will need to
+install the 'nautilus-sendto' package first.
diff --git a/TODO b/TODO
index 96234f6..610bd5d 100644
--- a/TODO
+++ b/TODO
@@ -5,7 +5,6 @@ TODO
 * Drop MX table layout
   * Add a 1px white border around previews
 * Improve video recording, see bug #564957
-* Add nautilus-sendto as a sharing possibility to the context menu of each item
 * Upload videos to Youtube, bug #522210
 * Use a GStreamer pipeline to encode images, bug #628226
   * Save EXIF data to photos, bug #583650
diff --git a/data/cheese-actions.ui b/data/cheese-actions.ui
index 0ee570a..3f7f2cd 100644
--- a/data/cheese-actions.ui
+++ b/data/cheese-actions.ui
@@ -64,6 +64,14 @@
           <accelerator key="O" modifiers="GDK_CONTROL_MASK"/>
         </child>
         <child>
+          <object class="GtkAction" id="share">
+            <property name="name">Share</property>
+            <property name="label" translatable="yes">Shareâ</property>
+            <signal name="activate" handler="cheese_main_window_on_share_files"/>
+          </object>
+          <accelerator key="H" modifiers="GDK_CONTROL_MASK"/>
+        </child>
+        <child>
           <object class="GtkAction" id="save_as">
             <property name="name">SaveAs</property>
             <property name="label" translatable="yes">Save _Asâ</property>
@@ -240,6 +248,8 @@
           <menuitem action="effects_page_next"/>
           <menuitem action="effects_page_prev"/>
           <separator/>
+          <menuitem action="share"/>
+          <separator/>
           <menuitem action="move_to_trash"/>
           <menuitem action="move_all_to_trash"/>
           <separator/>
@@ -253,6 +263,8 @@
       <popup name="thumbnail_popup" id="thumbnail_popup">
         <menuitem action="open"/>
         <separator/>
+        <menuitem action="share"/>
+        <separator/>
         <menuitem action="save_as"/>
         <separator/>
         <menuitem action="move_to_trash"/>
diff --git a/src/cheese-shareable-media.vala b/src/cheese-shareable-media.vala
new file mode 100644
index 0000000..d75d0eb
--- /dev/null
+++ b/src/cheese-shareable-media.vala
@@ -0,0 +1,124 @@
+/*
+ * Copyright  2011 Patricia Santana Cruz <patriciasantanacruz gmail com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Class used for sharing images or videos with different technologies through
+ * nautilus-sendto.
+ */
+public class Cheese.ShareableMedia : GLib.Object {
+    private const string XID = "--xid=";
+    private uint num_children = 0;
+    Cheese.MainWindow window;
+
+    /**
+     * Create a new ShareableMedia instance.
+     *
+     * @param main_window the main window of the Cheese application
+     */
+    public ShareableMedia (Cheese.MainWindow main_window)
+    {
+        window = main_window;
+    }
+
+    /**
+     * Callback to be called when the child exits.
+     *
+     * Cleans up the child process spawned by { link ShareableMedia.share_files}
+     * and if that child is the last one, it will also set the cursor
+     * back to normal.
+     *
+     * @param pid the process id of the child process
+     * @param status the status information about the child process
+     *
+     * @see ShareableMedia.share_files
+     */
+    void child_finished (Pid pid, int status)
+    {
+        /* Method for checking WIFEXITED(status) value, which returns true if the
+         * child terminated normally, that is, by calling exit(3) or _exit(2), or
+         * by returning from main().
+         */
+        if (!Process.if_exited(status))
+            warning ("nautilus-sendto exited abnormally");
+
+        Process.close_pid(pid);
+
+        --num_children;
+        if (num_children == 0)
+        {
+            window.get_window ().set_cursor (
+                new Gdk.Cursor (Gdk.CursorType.LEFT_PTR));
+        }
+    }
+
+    /**
+     * Used for sharing one or more images and/or one or more videos through
+     * different technologies.
+     *
+     * It works asynchronously and will create a new child every time it is
+     * called. When the child exists, the { link ShareableMedia.child_finished}
+     * callback is called.
+     *
+     * It will also set the cursor to busy to indicate to the user that
+     * there is some task that is being done.
+     *
+     * @param files a list of the files (videos and/or images that are going to
+     * be shared.
+     *
+     * @see ShareableMedia.child_finished.
+     */
+    public void share_files (GLib.List<GLib.File> files)
+    {
+        string[] argv = {};
+        // Defined in cheese-window.vala.
+        argv += SENDTO_EXEC;
+        argv += XID + "%lu".printf (
+            Gdk.X11Window.get_xid (window.get_window ()));
+
+        files.foreach ((file) => argv += file.get_path ());
+
+        try
+        {
+            Pid child_pid;
+
+            if (Process.spawn_async ("/", argv, null,
+                SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD, null,
+                out child_pid))
+            {
+                ChildWatch.add (child_pid, child_finished);
+
+                ++num_children;
+                /* Show a busy cursor if there are any children. It just needs
+                 * to be done for the first child.
+                 */
+                if (num_children == 1)
+                {
+                    window.get_window ().set_cursor (new Gdk.Cursor
+                        (Gdk.CursorType.WATCH));
+                }
+            }
+        }
+        catch (SpawnError error)
+        {
+            window.get_window ().set_cursor (new Gdk.Cursor
+                (Gdk.CursorType.LEFT_PTR));
+            warning ("Unable to launch nautilus-sendto: %s\n", error.message);
+        }
+    }
+}
diff --git a/src/cheese-window.vala b/src/cheese-window.vala
index 97cb0ee..545e124 100644
--- a/src/cheese-window.vala
+++ b/src/cheese-window.vala
@@ -31,6 +31,7 @@ using CanberraGtk;
 
 const int FULLSCREEN_TIMEOUT_INTERVAL = 5 * 1000;
 const int EFFECTS_PER_PAGE            = 9;
+const string SENDTO_EXEC = "nautilus-sendto";
 
 public class Cheese.MainWindow : Gtk.Window
 {
@@ -85,6 +86,8 @@ public class Cheese.MainWindow : Gtk.Window
   private Gtk.Action       countdown_action;
   private Gtk.Action       effects_page_prev_action;
   private Gtk.Action       effects_page_next_action;
+  private Gtk.Action       share_action;
+  private Gtk.ActionGroup  main_actions;
 
   private bool is_fullscreen;
   private bool is_wide_mode;
@@ -106,6 +109,8 @@ public class Cheese.MainWindow : Gtk.Window
 
   private Cheese.Effect selected_effect;
 
+  private Cheese.ShareableMedia shareable_media;
+
   /**
    * Destroy the main window, and shutdown the application, when quitting.
    *
@@ -158,7 +163,12 @@ public class Cheese.MainWindow : Gtk.Window
     {
       if (event.button == 3)
       {
-        thumbnail_popup.popup (null, thumb_view, null, event.button, event.time);
+	thumbnail_popup.popup (null, thumb_view, null, event.button, event.time);
+
+	// Check whether nautilus-sendto is installed or not. In case it is, set
+	// the "Share" action to sensitive, if it is not, set it to insensitive.
+	bool nautilus_sendto_installed = Environment.find_program_in_path(SENDTO_EXEC) != null;
+	share_action.set_sensitive (nautilus_sendto_installed);
       }
     }
     else
@@ -341,6 +351,20 @@ public class Cheese.MainWindow : Gtk.Window
   }
 
   /**
+   * Share the selected file(s) in the thumbview.
+   *
+   * A dialog is shown to the user, where the technology for sharing the
+   * image or video can be selected.
+   *
+   * @param action the action that emitted the signal
+   */
+  [CCode (instance_pos = -1)]
+  public void on_share_files (Gtk.Action action)
+  {
+    shareable_media.share_files (thumb_view.get_selected_images_list ());
+  }
+
+  /**
    * Save the selected file in the thumbview to an alternate storage location.
    *
    * A file chooser dialog is shown to the user, asking where the file should
@@ -1370,6 +1394,7 @@ public class Cheese.MainWindow : Gtk.Window
     buttons_area                      = gtk_builder.get_object ("buttons_area") as Gtk.Box;
     thumbnail_popup                   = gtk_builder.get_object ("thumbnail_popup") as Gtk.Menu;
 
+    main_actions             = gtk_builder.get_object ("main_actions") as Gtk.ActionGroup;
     take_photo_action        = gtk_builder.get_object ("take_photo") as Gtk.Action;
     take_video_action        = gtk_builder.get_object ("take_video") as Gtk.Action;
     take_burst_action        = gtk_builder.get_object ("take_burst") as Gtk.Action;
@@ -1382,6 +1407,10 @@ public class Cheese.MainWindow : Gtk.Window
     fullscreen_action        = gtk_builder.get_object ("fullscreen") as Gtk.ToggleAction;
     effects_page_next_action = gtk_builder.get_object ("effects_page_next") as Gtk.Action;
     effects_page_prev_action = gtk_builder.get_object ("effects_page_prev") as Gtk.Action;
+    share_action             = gtk_builder.get_object ("share") as Gtk.Action;
+
+    shareable_media = new Cheese.ShareableMedia (this);
+    main_actions.pre_activate.connect(on_action_pre_activated);
 
     /* Array contains all 'buttons', for easier manipulation
      * IMPORTANT: IF ANOTHER BUTTON IS ADDED UNDER THE VIEWPORT, ADD IT TO THIS ARRAY */
@@ -1457,6 +1486,24 @@ public class Cheese.MainWindow : Gtk.Window
   }
 
   /**
+   * Decide which actions will be sensitive or insensitive.
+   *
+   * @param action the action that emitted the signal.
+   */
+  public void on_action_pre_activated (Gtk.Action action)
+  {
+     if (strcmp (action.get_name(), "edit_action") == 0)
+     {
+        if (thumb_view.get_selected_images_list () != null)
+        {
+           bool nautilus_sendto_installed = Environment.find_program_in_path(SENDTO_EXEC) != null;
+           share_action.set_sensitive (nautilus_sendto_installed);
+        } else
+           share_action.set_sensitive (false);
+     }
+  }
+
+  /**
    * Setup the camera listed in GSettings.
    *
    * @param uri the uri of the device node to setup, or null



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