[totem] save-file: Add save file plugin
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [totem] save-file: Add save file plugin
- Date: Mon, 6 Dec 2010 19:42:55 +0000 (UTC)
commit cce123f328297fe7b6cadeba5525eae94df0f2bb
Author: Bastien Nocera <hadess hadess net>
Date: Mon Dec 6 13:30:41 2010 +0000
save-file: Add save file plugin
https://bugzilla.gnome.org/show_bug.cgi?id=350261
configure.in | 17 ++-
data/org.gnome.totem.gschema.xml.in.in | 2 +-
data/totem.ui | 5 +-
src/plugins/save-file/Makefile.am | 15 ++
src/plugins/save-file/save-file.plugin.in | 9 +
src/plugins/save-file/totem-save-file.c | 351 +++++++++++++++++++++++++++++
6 files changed, 395 insertions(+), 4 deletions(-)
---
diff --git a/configure.in b/configure.in
index 63a6f5a..1c28b6e 100644
--- a/configure.in
+++ b/configure.in
@@ -65,7 +65,7 @@ AC_SUBST(TOTEM_API_VERSION)
AC_DEFINE_UNQUOTED(TOTEM_API_VERSION, ["$TOTEM_API_VERSION"], [Define to the Totem plugin API version])
# The full list of plugins
-allowed_plugins="bemused brasero-disc-recorder chapters coherence_upnp dbus-service galago gromit iplayer jamendo lirc media-player-keys ontop opensubtitles properties publish pythonconsole sample-python screensaver screenshot sidebar-test skipto thumbnail tracker youtube"
+allowed_plugins="bemused brasero-disc-recorder chapters coherence_upnp dbus-service galago gromit iplayer jamendo lirc media-player-keys ontop opensubtitles properties publish pythonconsole save-file sample-python screensaver screenshot sidebar-test skipto thumbnail tracker youtube"
PLUGINDIR='${libdir}/totem/plugins'
AC_SUBST(PLUGINDIR)
@@ -442,7 +442,7 @@ for plugin in ${used_plugins}; do
tracker)
PKG_CHECK_MODULES(TRACKER, tracker-client-0.8 >= 0.8.1, [HAVE_TRACKER=yes], [HAVE_TRACKER=no])
if test "${HAVE_TRACKER}" != "yes" ; then
- PKG_CHECK_MODULES(TRACKER, tracker-client-0.9 >= 0.9.0, [HAVE_TRACKER=yes], [HAVE_TRACKER=no])
+ PKG_CHECK_MODULES(TRACKER, tracker-client-0.9 >= 0.9.0, [HAVE_TRACKER=yes], [HAVE_TRACKER=no])
fi
if test "${HAVE_TRACKER}" != "yes" ; then
@@ -467,6 +467,18 @@ for plugin in ${used_plugins}; do
add_plugin="0"
fi
;;
+ save-file)
+ dnl the nautilus check should be a run-time check
+ dnl but it might not always be running
+ PKG_CHECK_MODULES(SAVE_FILE_CHECK, gio-2.0 >= 2.26 libnautilus-extension >= 2.91.3,
+ [BUILD_SAVE_FILE=yes], [BUILD_SAVE_FILE=no])
+ if test "${BUILD_SAVE_FILE}" != "yes" ; then
+ plugin_error_or_ignore "you need gio-2.0 >=2.26 to use the save-file plugin"
+ add_plugin="0"
+ else
+ PKG_CHECK_MODULES(SAVE_FILE, gio-2.0 >= 2.26)
+ fi
+ ;;
youtube)
PKG_CHECK_MODULES(LIBGDATA, libgdata >= 0.4.0,
[HAVE_LIBGDATA=yes], [HAVE_LIBGDATA=no])
@@ -755,6 +767,7 @@ src/plugins/media-player-keys/Makefile
src/plugins/opensubtitles/Makefile
src/plugins/opensubtitles/org.gnome.totem.plugins.opensubtitles.gschema.xml.in
src/plugins/properties/Makefile
+src/plugins/save-file/Makefile
src/plugins/sidebar-test/Makefile
src/plugins/skipto/Makefile
src/plugins/sample-python/Makefile
diff --git a/data/org.gnome.totem.gschema.xml.in.in b/data/org.gnome.totem.gschema.xml.in.in
index f95a19a..4d45eb8 100644
--- a/data/org.gnome.totem.gschema.xml.in.in
+++ b/data/org.gnome.totem.gschema.xml.in.in
@@ -116,7 +116,7 @@
<_summary>Whether to remember the position of played audio/video files when pausing or closing them</_summary>
</key>
<key name="active-plugins" type="as">
- <default>['skipto','chapters','screenshot','media_player_keys','screensaver','movie-properties']</default>
+ <default>['skipto','chapters','screenshot','media_player_keys','screensaver','movie-properties','save-file']</default>
<_summary>Active plugins list</_summary>
<_description>A list of the names of the plugins which are currently active (loaded and running).</_description>
</key>
diff --git a/data/totem.ui b/data/totem.ui
index e5ed8ed..5951af6 100644
--- a/data/totem.ui
+++ b/data/totem.ui
@@ -421,7 +421,8 @@
<menubar name="tmw-menubar">
<menu name="movie" action="movie-menu">
<menuitem name="open" action="open"/>
- <menuitem name="open-location" action="open-location"/>
+ <menuitem name="open-location" action="open-location"/>
+ <placeholder name="save-placeholder"/>
<placeholder name="devices-placeholder"/>
<separator name="recent-separator"/>
<placeholder name="recent-placeholder"/>
@@ -509,6 +510,8 @@
<menuitem name="fullscreen" action="fullscreen"/>
<menuitem name="select-subtitle" action="select-subtitle"/>
<separator/>
+ <placeholder name="save-placeholder"/>
+ <separator/>
<menu name="popup-languages" action="languages-menu">
<placeholder name="placeholder"/>
</menu>
diff --git a/src/plugins/save-file/Makefile.am b/src/plugins/save-file/Makefile.am
new file mode 100644
index 0000000..39b6b64
--- /dev/null
+++ b/src/plugins/save-file/Makefile.am
@@ -0,0 +1,15 @@
+include $(top_srcdir)/src/plugins/Makefile.plugins
+
+plugindir = $(PLUGINDIR)/save-file
+plugin_LTLIBRARIES = libsave-file.la
+
+plugin_in_files = save-file.plugin.in
+
+libsave_file_la_SOURCES = totem-save-file.c
+libsave_file_la_LDFLAGS = $(plugin_ldflags)
+libsave_file_la_LIBADD = $(SAVE_FILE_LIBS)
+libsave_file_la_CFLAGS = \
+ $(plugin_cflags) \
+ $(SAVE_FILE_CFLAGS)
+
+-include $(top_srcdir)/git.mk
diff --git a/src/plugins/save-file/save-file.plugin.in b/src/plugins/save-file/save-file.plugin.in
new file mode 100644
index 0000000..b07355f
--- /dev/null
+++ b/src/plugins/save-file/save-file.plugin.in
@@ -0,0 +1,9 @@
+[Plugin]
+Module=save-file
+IAge=1
+Builtin=true
+_Name=Save copy
+_Description=Save a copy of the currently playing movie
+Authors=Bastien Nocera
+Copyright=Copyright © 2010 Bastien Nocera
+Website=http://projects.gnome.org/totem
diff --git a/src/plugins/save-file/totem-save-file.c b/src/plugins/save-file/totem-save-file.c
new file mode 100644
index 0000000..638d8c1
--- /dev/null
+++ b/src/plugins/save-file/totem-save-file.c
@@ -0,0 +1,351 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) Bastien Nocera 2010 <hadess hadess net>
+ *
+ * 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+#include <gdk/gdkx.h>
+#include <libpeas/peas-extension-base.h>
+#include <libpeas/peas-object-module.h>
+#include <libpeas/peas-activatable.h>
+
+#include "totem-plugin.h"
+#include "totem-interface.h"
+
+#define TOTEM_TYPE_SAVE_FILE_PLUGIN (totem_save_file_plugin_get_type ())
+#define TOTEM_SAVE_FILE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TOTEM_TYPE_SAVE_FILE_PLUGIN, TotemSaveFilePlugin))
+#define TOTEM_SAVE_FILE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TOTEM_TYPE_SAVE_FILE_PLUGIN, TotemSaveFilePluginClass))
+#define TOTEM_IS_SAVE_FILE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TOTEM_TYPE_SAVE_FILE_PLUGIN))
+#define TOTEM_IS_SAVE_FILE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TOTEM_TYPE_SAVE_FILE_PLUGIN))
+#define TOTEM_SAVE_FILE_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TOTEM_TYPE_SAVE_FILE_PLUGIN, TotemSaveFilePluginClass))
+
+typedef struct {
+ TotemObject *totem;
+ GtkWidget *bvw;
+
+ char *mrl;
+ char *name;
+ char *save_uri;
+ gboolean is_tmp;
+
+ GtkActionGroup *action_group;
+ guint ui_merge_id;
+} TotemSaveFilePluginPrivate;
+
+TOTEM_PLUGIN_REGISTER(TOTEM_TYPE_SAVE_FILE_PLUGIN, TotemSaveFilePlugin, totem_save_file_plugin)
+
+static void totem_save_file_plugin_copy (GtkAction *action,
+ TotemSaveFilePlugin *pi);
+
+static GtkActionEntry totem_save_file_plugin_actions [] = {
+ { "SaveFile", "save-as", N_("Save a Copy..."), NULL,
+ N_("Save a copy of the movie"),
+ G_CALLBACK (totem_save_file_plugin_copy) },
+};
+
+static void
+copy_uris_with_nautilus (const char *source,
+ const char *src_name,
+ const char *dest)
+{
+ GError *error = NULL;
+ GDBusProxyFlags flags;
+ GDBusProxy *proxy;
+ GFile *dest_file, *parent;
+ char *dest_name, *dest_dir;
+
+ g_return_if_fail (source != NULL);
+ g_return_if_fail (dest != NULL);
+ g_return_if_fail (src_name != NULL); /* Must be "" or something interesting, not NULL */
+
+ flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
+ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ flags,
+ NULL, /* GDBusInterfaceInfo */
+ "org.gnome.Nautilus",
+ "/org/gnome/Nautilus",
+ "org.gnome.Nautilus.FileOperations",
+ NULL, /* GCancellable */
+ &error);
+ if (proxy == NULL) {
+ g_warning ("Could not contact nautilus: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ dest_file = g_file_new_for_uri (dest);
+ dest_name = g_file_get_basename (dest_file);
+ parent = g_file_get_parent (dest_file);
+ g_object_unref (dest_file);
+ dest_dir = g_file_get_uri (parent);
+ g_object_unref (parent);
+
+ if (g_dbus_proxy_call_sync (proxy,
+ "CopyFile", g_variant_new ("(&s&s&s&s)", source, src_name, dest_dir, dest_name),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, &error) == FALSE) {
+ g_warning ("Could not get nautilus to copy file: %s", error->message);
+ g_error_free (error);
+ }
+
+ g_free (dest_dir);
+ g_free (dest_name);
+ g_object_unref (proxy);
+}
+
+static void
+totem_save_file_plugin_copy (GtkAction *action,
+ TotemSaveFilePlugin *pi)
+{
+ GtkWidget *fs;
+ char *filename;
+ int response;
+
+ g_assert (pi->priv->mrl != NULL);
+
+
+ fs = gtk_file_chooser_dialog_new (_("Save a Copy"),
+ totem_get_main_window (pi->priv->totem),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_dialog_set_default_response (GTK_DIALOG (fs), GTK_RESPONSE_ACCEPT);
+ gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (fs), FALSE);
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (fs), TRUE);
+
+ if (pi->priv->name != NULL) {
+ filename = g_strdup (pi->priv->name);
+ } else {
+ GFile *file;
+ char *basename;
+
+ /* Try to get a nice filename from the URI */
+ file = g_file_new_for_uri (pi->priv->mrl);
+ basename = g_file_get_basename (file);
+ g_object_unref (file);
+
+ if (g_utf8_validate (basename, -1, NULL) == FALSE) {
+ g_free (basename);
+ filename = NULL;
+ } else {
+ filename = basename;
+ }
+ }
+
+ if (filename == NULL) {
+ /* translators: Movie is the default saved movie filename,
+ * without the suffix */
+ filename = g_strdup (_("Movie"));
+ }
+
+ gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (fs), filename);
+ g_free (filename);
+
+ if (pi->priv->save_uri != NULL) {
+ gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (fs),
+ pi->priv->save_uri);
+ }
+
+ response = gtk_dialog_run (GTK_DIALOG (fs));
+ gtk_widget_hide (fs);
+
+ if (response == GTK_RESPONSE_ACCEPT) {
+ char *dest_uri;
+
+ dest_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (fs));
+ /* translators: "Movie stream" is what will show up in the
+ * nautilus copy dialogue as the source, when saving a streamed
+ * movie */
+ copy_uris_with_nautilus (pi->priv->mrl,
+ pi->priv->is_tmp ? _("Movie stream") : "",
+ dest_uri);
+
+ g_free (pi->priv->save_uri);
+ pi->priv->save_uri = g_path_get_dirname (dest_uri);
+ g_free (dest_uri);
+ }
+ gtk_widget_destroy (fs);
+}
+
+static void
+totem_save_file_file_closed (TotemObject *totem,
+ TotemSaveFilePlugin *pi)
+{
+ GtkAction *action;
+
+ g_free (pi->priv->mrl);
+ pi->priv->mrl = NULL;
+ g_free (pi->priv->name);
+ pi->priv->name = NULL;
+
+ action = gtk_action_group_get_action (pi->priv->action_group, "SaveFile");
+ gtk_action_set_sensitive (action, FALSE);
+}
+
+static void
+totem_save_file_file_opened (TotemObject *totem,
+ const char *mrl,
+ TotemSaveFilePlugin *pi)
+{
+ TotemSaveFilePluginPrivate *priv = pi->priv;
+ GtkAction *action;
+
+ g_assert (pi->priv->mrl == NULL);
+
+ if (mrl == NULL)
+ return;
+
+ if (g_str_has_prefix (mrl, "file:") || g_str_has_prefix (mrl, "smb:")) {
+ /* We can always copy files from file:/// URIs */
+ action = gtk_action_group_get_action (priv->action_group, "SaveFile");
+ gtk_action_set_sensitive (action, TRUE);
+ pi->priv->mrl = g_strdup (mrl);
+ pi->priv->name = totem_get_short_title (pi->priv->totem);
+ pi->priv->is_tmp = FALSE;
+ }
+}
+
+static void
+totem_save_file_download_filename (GObject *gobject,
+ GParamSpec *pspec,
+ TotemSaveFilePlugin *pi)
+{
+ GtkAction *action;
+ char *filename;
+
+ /* We're already ready to copy it */
+ if (pi->priv->mrl != NULL)
+ return;
+
+ filename = NULL;
+ g_object_get (G_OBJECT (pi->priv->bvw), "download-filename", &filename, NULL);
+ if (filename == NULL)
+ return;
+
+ pi->priv->mrl = g_filename_to_uri (filename, NULL, NULL);
+ g_free (filename);
+ pi->priv->name = totem_get_short_title (pi->priv->totem);
+ pi->priv->is_tmp = TRUE;
+
+ action = gtk_action_group_get_action (pi->priv->action_group, "SaveFile");
+ gtk_action_set_sensitive (action, TRUE);
+}
+
+static void
+impl_activate (PeasActivatable *plugin)
+{
+ TotemSaveFilePlugin *pi = TOTEM_SAVE_FILE_PLUGIN (plugin);
+ TotemSaveFilePluginPrivate *priv = pi->priv;
+ GtkUIManager *uimanager = NULL;
+ GtkAction *action;
+ char *path;
+ char *mrl;
+
+ /* make sure nautilus is in the path */
+ path = g_find_program_in_path ("nautilus");
+ if (!path)
+ return;
+ g_free (path);
+
+ priv->totem = g_object_get_data (G_OBJECT (plugin), "object");
+ priv->bvw = totem_get_video_widget (priv->totem);
+
+ g_signal_connect (priv->totem,
+ "file-opened",
+ G_CALLBACK (totem_save_file_file_opened),
+ plugin);
+ g_signal_connect (priv->totem,
+ "file-closed",
+ G_CALLBACK (totem_save_file_file_closed),
+ plugin);
+ g_signal_connect (priv->bvw,
+ "notify::download-filename",
+ G_CALLBACK (totem_save_file_download_filename),
+ plugin);
+
+ /* add UI */
+ priv->action_group = gtk_action_group_new ("SaveFileActions");
+ gtk_action_group_set_translation_domain (priv->action_group, GETTEXT_PACKAGE);
+ gtk_action_group_add_actions (priv->action_group,
+ totem_save_file_plugin_actions,
+ G_N_ELEMENTS (totem_save_file_plugin_actions),
+ pi);
+
+ uimanager = totem_get_ui_manager (priv->totem);
+ gtk_ui_manager_insert_action_group (uimanager, priv->action_group, -1);
+ g_object_unref (priv->action_group);
+
+ priv->ui_merge_id = gtk_ui_manager_new_merge_id (uimanager);
+
+ gtk_ui_manager_add_ui (uimanager,
+ priv->ui_merge_id,
+ "/ui/tmw-menubar/movie/save-placeholder",
+ "SaveFile",
+ "SaveFile",
+ GTK_UI_MANAGER_MENUITEM,
+ TRUE);
+ gtk_ui_manager_add_ui (uimanager,
+ priv->ui_merge_id,
+ "/ui/totem-main-popup/save-placeholder",
+ "SaveFile",
+ "SaveFile",
+ GTK_UI_MANAGER_MENUITEM,
+ TRUE);
+
+ action = gtk_action_group_get_action (priv->action_group, "SaveFile");
+ gtk_action_set_sensitive (action, FALSE);
+
+ mrl = totem_get_current_mrl (priv->totem);
+ totem_save_file_file_opened (priv->totem, mrl, pi);
+ totem_save_file_download_filename (NULL, NULL, pi);
+ g_free (mrl);
+}
+
+static void
+impl_deactivate (PeasActivatable *plugin)
+{
+ TotemSaveFilePlugin *pi = TOTEM_SAVE_FILE_PLUGIN (plugin);
+ TotemSaveFilePluginPrivate *priv = pi->priv;
+ GtkUIManager *uimanager = NULL;
+
+ g_signal_handlers_disconnect_by_func (priv->totem, totem_save_file_file_opened, plugin);
+ g_signal_handlers_disconnect_by_func (priv->totem, totem_save_file_file_closed, plugin);
+ g_signal_handlers_disconnect_by_func (priv->bvw, totem_save_file_download_filename, plugin);
+
+ uimanager = totem_get_ui_manager (priv->totem);
+ gtk_ui_manager_remove_ui (uimanager, priv->ui_merge_id);
+ gtk_ui_manager_remove_action_group (uimanager, priv->action_group);
+
+ priv->totem = NULL;
+ priv->bvw = NULL;
+
+ g_free (priv->mrl);
+ priv->mrl = NULL;
+ g_free (priv->name);
+ priv->mrl = NULL;
+ g_free (priv->save_uri);
+ priv->save_uri = NULL;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]