summaryrefslogtreecommitdiffstats
path: root/extensions
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 15:59:36 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 15:59:36 +0000
commitec52555862913a23417735f9f7f5402f5230da13 (patch)
tree5e43a30d289a3daa69dddfbb060216ff6332f197 /extensions
parentInitial commit. (diff)
downloadnautilus-upstream.tar.xz
nautilus-upstream.zip
Adding upstream version 3.38.2.upstream/3.38.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'extensions')
-rw-r--r--extensions/audio-video-properties/bacon-video-widget-properties.c283
-rw-r--r--extensions/audio-video-properties/bacon-video-widget-properties.h62
-rw-r--r--extensions/audio-video-properties/meson.build53
-rw-r--r--extensions/audio-video-properties/resources/nautilus-audio-video-properties.gresource.xml6
-rw-r--r--extensions/audio-video-properties/resources/ui/properties.ui692
-rw-r--r--extensions/audio-video-properties/test-properties-page.c81
-rw-r--r--extensions/audio-video-properties/totem-gst-helpers.c58
-rw-r--r--extensions/audio-video-properties/totem-gst-helpers.h25
-rw-r--r--extensions/audio-video-properties/totem-mime-types.h282
-rw-r--r--extensions/audio-video-properties/totem-properties-main.c154
-rw-r--r--extensions/audio-video-properties/totem-properties-view.c389
-rw-r--r--extensions/audio-video-properties/totem-properties-view.h49
-rw-r--r--extensions/image-properties/meson.build15
-rw-r--r--extensions/image-properties/nautilus-image-properties-module.c54
-rw-r--r--extensions/image-properties/nautilus-image-properties-page-provider.c136
-rw-r--r--extensions/image-properties/nautilus-image-properties-page-provider.h30
-rw-r--r--extensions/image-properties/nautilus-image-properties-page.c515
-rw-r--r--extensions/image-properties/nautilus-image-properties-page.h35
-rw-r--r--extensions/meson.build3
-rw-r--r--extensions/sendto/meson.build13
-rw-r--r--extensions/sendto/nautilus-nste.c159
-rw-r--r--extensions/sendto/nautilus-nste.h35
-rw-r--r--extensions/sendto/nautilus-sendto-module.c53
23 files changed, 3182 insertions, 0 deletions
diff --git a/extensions/audio-video-properties/bacon-video-widget-properties.c b/extensions/audio-video-properties/bacon-video-widget-properties.c
new file mode 100644
index 0000000..b2b2aaf
--- /dev/null
+++ b/extensions/audio-video-properties/bacon-video-widget-properties.c
@@ -0,0 +1,283 @@
+/* bacon-video-widget-properties.c
+
+ Copyright (C) 2002 Bastien Nocera
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Library 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 Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA.
+
+ Author: Bastien Nocera <hadess@hadess.net>
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include <glib/gi18n-lib.h>
+#include <string.h>
+#include <math.h>
+
+#include "bacon-video-widget-properties.h"
+
+static void bacon_video_widget_properties_dispose (GObject *object);
+
+struct BaconVideoWidgetPropertiesPrivate {
+ GtkBuilder *xml;
+ int time;
+};
+
+#define BACON_VIDEO_WIDGET_PROPERTIES_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), BACON_TYPE_VIDEO_WIDGET_PROPERTIES, BaconVideoWidgetPropertiesPrivate))
+
+G_DEFINE_TYPE (BaconVideoWidgetProperties, bacon_video_widget_properties, GTK_TYPE_BOX)
+
+static void
+bacon_video_widget_properties_class_init (BaconVideoWidgetPropertiesClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BaconVideoWidgetPropertiesPrivate));
+
+ object_class->dispose = bacon_video_widget_properties_dispose;
+}
+
+static void
+bacon_video_widget_properties_init (BaconVideoWidgetProperties *props)
+{
+ props->priv = G_TYPE_INSTANCE_GET_PRIVATE (props, BACON_TYPE_VIDEO_WIDGET_PROPERTIES, BaconVideoWidgetPropertiesPrivate);
+
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (props), GTK_ORIENTATION_VERTICAL);
+}
+
+static void
+bacon_video_widget_properties_dispose (GObject *object)
+{
+ BaconVideoWidgetPropertiesPrivate *priv = BACON_VIDEO_WIDGET_PROPERTIES_GET_PRIVATE (object);
+
+ if (priv->xml != NULL)
+ g_object_unref (priv->xml);
+ priv->xml = NULL;
+
+ G_OBJECT_CLASS (bacon_video_widget_properties_parent_class)->dispose (object);
+}
+
+void
+bacon_video_widget_properties_set_label (BaconVideoWidgetProperties *props,
+ const char *name,
+ const char *text)
+{
+ GtkLabel *item;
+
+ g_return_if_fail (props != NULL);
+ g_return_if_fail (BACON_IS_VIDEO_WIDGET_PROPERTIES (props));
+ g_return_if_fail (name != NULL);
+
+ item = GTK_LABEL (gtk_builder_get_object (props->priv->xml, name));
+ g_return_if_fail (item != NULL);
+ gtk_label_set_text (item, text);
+}
+
+void
+bacon_video_widget_properties_reset (BaconVideoWidgetProperties *props)
+{
+ GtkWidget *item;
+
+ g_return_if_fail (props != NULL);
+ g_return_if_fail (BACON_IS_VIDEO_WIDGET_PROPERTIES (props));
+
+ item = GTK_WIDGET (gtk_builder_get_object (props->priv->xml, "video_vbox"));
+ gtk_widget_show (item);
+ item = GTK_WIDGET (gtk_builder_get_object (props->priv->xml, "video"));
+ gtk_widget_set_sensitive (item, FALSE);
+ item = GTK_WIDGET (gtk_builder_get_object (props->priv->xml, "audio"));
+ gtk_widget_set_sensitive (item, FALSE);
+
+ /* Title */
+ bacon_video_widget_properties_set_label (props, "title", C_("Title", "Unknown"));
+ /* Artist */
+ bacon_video_widget_properties_set_label (props, "artist", C_("Artist", "Unknown"));
+ /* Album */
+ bacon_video_widget_properties_set_label (props, "album", C_("Album", "Unknown"));
+ /* Year */
+ bacon_video_widget_properties_set_label (props, "year", C_("Year", "Unknown"));
+ /* Duration */
+ bacon_video_widget_properties_set_duration (props, 0);
+ /* Comment */
+ bacon_video_widget_properties_set_label (props, "comment", "");
+ /* Container */
+ bacon_video_widget_properties_set_label (props, "container", C_("Media container", "Unknown"));
+
+ /* Dimensions */
+ bacon_video_widget_properties_set_label (props, "dimensions", C_("Dimensions", "N/A"));
+ /* Video Codec */
+ bacon_video_widget_properties_set_label (props, "vcodec", C_("Video codec", "N/A"));
+ /* Video Bitrate */
+ bacon_video_widget_properties_set_label (props, "video_bitrate",
+ C_("Video bit rate", "N/A"));
+ /* Framerate */
+ bacon_video_widget_properties_set_label (props, "framerate",
+ C_("Frame rate", "N/A"));
+
+ /* Audio Bitrate */
+ bacon_video_widget_properties_set_label (props, "audio_bitrate",
+ C_("Audio bit rate", "N/A"));
+ /* Audio Codec */
+ bacon_video_widget_properties_set_label (props, "acodec", C_("Audio codec", "N/A"));
+ /* Sample rate */
+ bacon_video_widget_properties_set_label (props, "samplerate", _("0 Hz"));
+ /* Channels */
+ bacon_video_widget_properties_set_label (props, "channels", _("0 Channels"));
+}
+
+static char *
+time_to_string_text (gint64 msecs)
+{
+ char *secs, *mins, *hours, *string;
+ int sec, min, hour, _time;
+
+ _time = (int) (msecs / 1000);
+ sec = _time % 60;
+ _time = _time - sec;
+ min = (_time % (60*60)) / 60;
+ _time = _time - (min * 60);
+ hour = _time / (60*60);
+
+ hours = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%d hour", "%d hours", hour), hour);
+
+ mins = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%d minute",
+ "%d minutes", min), min);
+
+ secs = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%d second",
+ "%d seconds", sec), sec);
+
+ if (hour > 0)
+ {
+ /* 5 hours 2 minutes 12 seconds */
+ string = g_strdup_printf (C_("time", "%s %s %s"), hours, mins, secs);
+ } else if (min > 0) {
+ /* 2 minutes 12 seconds */
+ string = g_strdup_printf (C_("time", "%s %s"), mins, secs);
+ } else if (sec > 0) {
+ /* 10 seconds */
+ string = g_strdup (secs);
+ } else {
+ /* 0 seconds */
+ string = g_strdup (_("0 seconds"));
+ }
+
+ g_free (hours);
+ g_free (mins);
+ g_free (secs);
+
+ return string;
+}
+
+void
+bacon_video_widget_properties_set_duration (BaconVideoWidgetProperties *props,
+ int _time)
+{
+ char *string;
+
+ g_return_if_fail (props != NULL);
+ g_return_if_fail (BACON_IS_VIDEO_WIDGET_PROPERTIES (props));
+
+ if (_time == props->priv->time)
+ return;
+
+ string = time_to_string_text (_time);
+ bacon_video_widget_properties_set_label (props, "duration", string);
+ g_free (string);
+
+ props->priv->time = _time;
+}
+
+void
+bacon_video_widget_properties_set_has_type (BaconVideoWidgetProperties *props,
+ gboolean has_video,
+ gboolean has_audio)
+{
+ GtkWidget *item;
+
+ g_return_if_fail (props != NULL);
+ g_return_if_fail (BACON_IS_VIDEO_WIDGET_PROPERTIES (props));
+
+ /* Video */
+ item = GTK_WIDGET (gtk_builder_get_object (props->priv->xml, "video"));
+ gtk_widget_set_sensitive (item, has_video);
+ item = GTK_WIDGET (gtk_builder_get_object (props->priv->xml, "video_vbox"));
+ gtk_widget_set_visible (item, has_video);
+
+ /* Audio */
+ item = GTK_WIDGET (gtk_builder_get_object (props->priv->xml, "audio"));
+ gtk_widget_set_sensitive (item, has_audio);
+}
+
+void
+bacon_video_widget_properties_set_framerate (BaconVideoWidgetProperties *props,
+ float framerate)
+{
+ gchar *temp;
+
+ g_return_if_fail (props != NULL);
+ g_return_if_fail (BACON_IS_VIDEO_WIDGET_PROPERTIES (props));
+
+ if (framerate > 1.0) {
+ temp = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%0.2f frame per second", "%0.2f frames per second", (int) (ceilf (framerate))), framerate);
+ } else {
+ temp = g_strdup (C_("Frame rate", "N/A"));
+ }
+ bacon_video_widget_properties_set_label (props, "framerate", temp);
+ g_free (temp);
+}
+
+GtkWidget*
+bacon_video_widget_properties_new (void)
+{
+ BaconVideoWidgetProperties *props;
+ GtkBuilder *xml;
+ GtkWidget *vbox;
+ GtkSizeGroup *group;
+ const char *labels[] = { "title_label", "artist_label", "album_label",
+ "year_label", "duration_label", "comment_label", "container_label",
+ "dimensions_label", "vcodec_label", "framerate_label",
+ "vbitrate_label", "abitrate_label", "acodec_label",
+ "samplerate_label", "channels_label" };
+ guint i;
+
+ xml = gtk_builder_new ();
+ gtk_builder_set_translation_domain (xml, GETTEXT_PACKAGE);
+ if (gtk_builder_add_from_resource (xml, "/org/gnome/nautilus/audio-video-properties/ui/properties.ui", NULL) == 0) {
+ g_object_unref (xml);
+ return NULL;
+ }
+
+ props = BACON_VIDEO_WIDGET_PROPERTIES (g_object_new
+ (BACON_TYPE_VIDEO_WIDGET_PROPERTIES, NULL));
+
+ props->priv->xml = xml;
+ vbox = GTK_WIDGET (gtk_builder_get_object (props->priv->xml, "vbox1"));
+ gtk_box_pack_start (GTK_BOX (props), vbox, FALSE, FALSE, 0);
+
+ bacon_video_widget_properties_reset (props);
+
+ group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+ for (i = 0; i < G_N_ELEMENTS (labels); i++)
+ gtk_size_group_add_widget (group, GTK_WIDGET (gtk_builder_get_object (xml, labels[i])));
+
+ g_object_unref (group);
+
+ gtk_widget_show_all (GTK_WIDGET (props));
+
+ return GTK_WIDGET (props);
+}
+
diff --git a/extensions/audio-video-properties/bacon-video-widget-properties.h b/extensions/audio-video-properties/bacon-video-widget-properties.h
new file mode 100644
index 0000000..32ec5e0
--- /dev/null
+++ b/extensions/audio-video-properties/bacon-video-widget-properties.h
@@ -0,0 +1,62 @@
+/* bacon-video-widget-properties.h: Properties dialog for BaconVideoWidget
+
+ Copyright (C) 2002 Bastien Nocera <hadess@hadess.net>
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Library 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 Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA.
+
+ Author: Bastien Nocera <hadess@hadess.net>
+ */
+
+#ifndef BACON_VIDEO_WIDGET_PROPERTIES_H
+#define BACON_VIDEO_WIDGET_PROPERTIES_H
+
+#include <gtk/gtk.h>
+
+#define BACON_TYPE_VIDEO_WIDGET_PROPERTIES (bacon_video_widget_properties_get_type ())
+#define BACON_VIDEO_WIDGET_PROPERTIES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BACON_TYPE_VIDEO_WIDGET_PROPERTIES, BaconVideoWidgetProperties))
+#define BACON_VIDEO_WIDGET_PROPERTIES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BACON_TYPE_VIDEO_WIDGET_PROPERTIES, BaconVideoWidgetPropertiesClass))
+#define BACON_IS_VIDEO_WIDGET_PROPERTIES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BACON_TYPE_VIDEO_WIDGET_PROPERTIES))
+#define BACON_IS_VIDEO_WIDGET_PROPERTIES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BACON_TYPE_VIDEO_WIDGET_PROPERTIES))
+
+typedef struct BaconVideoWidgetProperties BaconVideoWidgetProperties;
+typedef struct BaconVideoWidgetPropertiesClass BaconVideoWidgetPropertiesClass;
+typedef struct BaconVideoWidgetPropertiesPrivate BaconVideoWidgetPropertiesPrivate;
+
+struct BaconVideoWidgetProperties {
+ GtkBox parent;
+ BaconVideoWidgetPropertiesPrivate *priv;
+};
+
+struct BaconVideoWidgetPropertiesClass {
+ GtkBoxClass parent_class;
+};
+
+GType bacon_video_widget_properties_get_type (void);
+GtkWidget *bacon_video_widget_properties_new (void);
+
+void bacon_video_widget_properties_reset (BaconVideoWidgetProperties *props);
+void bacon_video_widget_properties_set_label (BaconVideoWidgetProperties *props,
+ const char *name,
+ const char *text);
+void bacon_video_widget_properties_set_duration (BaconVideoWidgetProperties *props,
+ int duration);
+void bacon_video_widget_properties_set_has_type (BaconVideoWidgetProperties *props,
+ gboolean has_video,
+ gboolean has_audio);
+void bacon_video_widget_properties_set_framerate (BaconVideoWidgetProperties *props,
+ float framerate);
+
+#endif /* BACON_VIDEO_WIDGET_PROPERTIES_H */
diff --git a/extensions/audio-video-properties/meson.build b/extensions/audio-video-properties/meson.build
new file mode 100644
index 0000000..b67de9d
--- /dev/null
+++ b/extensions/audio-video-properties/meson.build
@@ -0,0 +1,53 @@
+resources = gnome.compile_resources(
+ 'nautilus-audio-video-properties-resources',
+ join_paths(
+ 'resources', 'nautilus-audio-video-properties.gresource.xml'
+ ),
+ source_dir: 'resources',
+ c_name: 'nautilus_audio_video_properties',
+)
+
+libm = cc.find_library('m')
+
+libtotem_properties_page_sources = files(
+ 'totem-properties-main.c',
+ 'totem-properties-view.c',
+ 'bacon-video-widget-properties.c',
+ 'totem-gst-helpers.c',
+) + resources
+
+libtotem_properties_page_deps = [
+ libm,
+ gst_tag_dep,
+ gst_pbutils_dep,
+]
+
+libtotem_properties_page = shared_module(
+ 'totem-properties-page',
+ sources: libtotem_properties_page_sources,
+ dependencies: libtotem_properties_page_deps + [
+ nautilus_extension
+ ],
+ c_args: [
+ '-DG_LOG_DOMAIN="TotemPropertiesPage"'
+ ],
+ install: true,
+ install_dir: extensiondir
+)
+
+test_properties_page_sources = files(
+ 'totem-properties-main.c',
+ 'totem-properties-view.c',
+ 'bacon-video-widget-properties.c',
+ 'totem-gst-helpers.c',
+ 'test-properties-page.c'
+) + resources
+
+executable(
+ 'test-properties-page',
+ test_properties_page_sources,
+ dependencies: libtotem_properties_page_deps + [
+ nautilus_extension
+ ],
+)
+
diff --git a/extensions/audio-video-properties/resources/nautilus-audio-video-properties.gresource.xml b/extensions/audio-video-properties/resources/nautilus-audio-video-properties.gresource.xml
new file mode 100644
index 0000000..d7f727d
--- /dev/null
+++ b/extensions/audio-video-properties/resources/nautilus-audio-video-properties.gresource.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/gnome/nautilus/audio-video-properties">
+ <file compressed="true">ui/properties.ui</file>
+ </gresource>
+</gresources>
diff --git a/extensions/audio-video-properties/resources/ui/properties.ui b/extensions/audio-video-properties/resources/ui/properties.ui
new file mode 100644
index 0000000..e7bbf88
--- /dev/null
+++ b/extensions/audio-video-properties/resources/ui/properties.ui
@@ -0,0 +1,692 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface>
+ <requires lib="gtk+" version="3.11"/>
+ <object class="GtkBox" id="vbox1">
+ <property name="width_request">375</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_bottom">12</property>
+ <property name="border_width">6</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkBox" id="general_vbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="bvwp_general_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">General</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="general">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="title_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">12</property>
+ <property name="label" translatable="yes">Title:</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ <accessibility>
+ <relation type="label-for" target="title"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="artist_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">12</property>
+ <property name="label" translatable="yes">Artist:</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ <accessibility>
+ <relation type="label-for" target="artist"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="duration_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">12</property>
+ <property name="label" translatable="yes">Duration:</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ <accessibility>
+ <relation type="label-for" target="duration"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="year_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">12</property>
+ <property name="label" translatable="yes">Year:</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ <accessibility>
+ <relation type="label-for" target="year"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="album_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">12</property>
+ <property name="label" translatable="yes">Album:</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ <accessibility>
+ <relation type="label-for" target="album"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="title">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">Unknown</property>
+ <property name="wrap">True</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="title_label"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="artist">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">Unknown</property>
+ <property name="wrap">True</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="artist_label"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="album">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">Unknown</property>
+ <property name="wrap">True</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="album_label"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="year">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">Unknown</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="year_label"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="duration">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">0 seconds</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="duration_label"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="comment_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">12</property>
+ <property name="label" translatable="yes">Comment:</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ <accessibility>
+ <relation type="label-for" target="comment"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="comment">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">Unknown</property>
+ <property name="wrap">True</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="comment_label"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="container_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">12</property>
+ <property name="label" translatable="yes">Container:</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label">Unknown</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">6</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="video_vbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="bvwp_video_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Video</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="video">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="dimensions_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">12</property>
+ <property name="label" translatable="yes">Dimensions:</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ <accessibility>
+ <relation type="label-for" target="dimensions"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="vcodec_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">12</property>
+ <property name="label" translatable="yes">Codec:</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ <accessibility>
+ <relation type="label-for" target="vcodec"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="framerate_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">12</property>
+ <property name="label" translatable="yes">Frame rate:</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ <accessibility>
+ <relation type="label-for" target="framerate"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="vbitrate_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">12</property>
+ <property name="label" translatable="yes">Bit rate:</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ <accessibility>
+ <relation type="label-for" target="video_bitrate"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="dimensions">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">0 x 0</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="dimensions_label"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="vcodec">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">N/A</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="vcodec_label"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="framerate">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">0 frames per second</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="framerate_label"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="video_bitrate">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">0 kbps</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="vbitrate_label"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="audio_vbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="bvwp_audio_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Audio</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="audio">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="samplerate_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">12</property>
+ <property name="label" translatable="yes">Sample rate:</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ <accessibility>
+ <relation type="label-for" target="samplerate"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="samplerate">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">0 Hz</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="samplerate_label"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="abitrate_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">12</property>
+ <property name="label" translatable="yes">Bit rate:</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ <accessibility>
+ <relation type="label-for" target="audio_bitrate"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="audio_bitrate">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">0 kbps</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="abitrate_label"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="acodec_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">12</property>
+ <property name="label" translatable="yes">Codec:</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ <accessibility>
+ <relation type="label-for" target="acodec"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="acodec">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">N/A</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="acodec_label"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="channels_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">12</property>
+ <property name="label" translatable="yes">Channels:</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ <accessibility>
+ <relation type="label-for" target="channels"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="channels">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">0 Channels</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="channels_label"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/extensions/audio-video-properties/test-properties-page.c b/extensions/audio-video-properties/test-properties-page.c
new file mode 100644
index 0000000..21be43a
--- /dev/null
+++ b/extensions/audio-video-properties/test-properties-page.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2005 Bastien Nocera <hadess@hadess.net>
+ *
+ * This library 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 library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <config.h>
+#include <string.h>
+#define GST_USE_UNSTABLE_API 1
+#include <gst/gst.h>
+#include <glib/gi18n-lib.h>
+#include "totem-gst-helpers.h"
+#include "totem-properties-view.h"
+
+static GtkWidget *window, *props, *label;
+
+static void
+create_props (const char *url)
+{
+ label = gtk_label_new ("Audio/Video");
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ g_signal_connect (G_OBJECT (window), "destroy",
+ G_CALLBACK (gtk_main_quit), NULL);
+ gtk_window_set_default_size (GTK_WINDOW (window), 450, 550);
+ props = totem_properties_view_new (url, label);
+ gtk_container_add (GTK_CONTAINER (window), props);
+
+ gtk_widget_show_all (window);
+}
+
+static void
+destroy_props (void)
+{
+ gtk_widget_destroy (label);
+}
+
+int main (int argc, char **argv)
+{
+ GFile *file;
+ char *url;
+
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ totem_gst_disable_display_decoders ();
+ gst_init (&argc, &argv);
+ gtk_init (&argc, &argv);
+
+ if (argc != 2) {
+ g_print ("Usage: %s [URI]\n", argv[0]);
+ return 1;
+ }
+
+ file = g_file_new_for_commandline_arg (argv[1]);
+ url = g_file_get_uri (file);
+ g_object_unref (file);
+
+ create_props (url);
+ g_free (url);
+
+ gtk_main ();
+
+ destroy_props ();
+
+ return 0;
+}
+
diff --git a/extensions/audio-video-properties/totem-gst-helpers.c b/extensions/audio-video-properties/totem-gst-helpers.c
new file mode 100644
index 0000000..e01996d
--- /dev/null
+++ b/extensions/audio-video-properties/totem-gst-helpers.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2003-2007 the GStreamer project
+ * Julien Moutte <julien@moutte.net>
+ * Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * Copyright (C) 2005-2008 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ * Copyright © 2009 Christian Persch
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include "totem-gst-helpers.h"
+#include <gst/gstprotection.h>
+
+/* Disable decoders that require a display environment to work,
+ * and that might cause crashes */
+void
+totem_gst_disable_display_decoders (void)
+{
+ GstRegistry *registry;
+ const char *blacklisted_plugins[] = {
+ "bmcdec",
+ "vaapi",
+ "video4linux2"
+ };
+ guint i;
+
+ /* Disable the vaapi plugin as it will not work with the
+ * fakesink we use:
+ * See: https://bugzilla.gnome.org/show_bug.cgi?id=700186 and
+ * https://bugzilla.gnome.org/show_bug.cgi?id=749605 */
+ registry = gst_registry_get ();
+
+ for (i = 0; i < G_N_ELEMENTS (blacklisted_plugins); i++) {
+ GstPlugin *plugin =
+ gst_registry_find_plugin (registry,
+ blacklisted_plugins[i]);
+ if (plugin)
+ gst_registry_remove_plugin (registry, plugin);
+ }
+}
+
+/*
+ * vim: sw=2 ts=8 cindent noai bs=2
+ */
diff --git a/extensions/audio-video-properties/totem-gst-helpers.h b/extensions/audio-video-properties/totem-gst-helpers.h
new file mode 100644
index 0000000..9ec559c
--- /dev/null
+++ b/extensions/audio-video-properties/totem-gst-helpers.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2001,2002,2003,2004,2005 Bastien Nocera <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 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.
+ *
+ */
+
+#ifndef HAVE_TOTEM_GST_HELPERS_H
+#define HAVE_TOTEM_GST_HELPERS_H
+
+void totem_gst_disable_display_decoders (void);
+
+#endif /* HAVE_TOTEM_GST_HELPERS_H */
diff --git a/extensions/audio-video-properties/totem-mime-types.h b/extensions/audio-video-properties/totem-mime-types.h
new file mode 100644
index 0000000..6551f31
--- /dev/null
+++ b/extensions/audio-video-properties/totem-mime-types.h
@@ -0,0 +1,282 @@
+/* generated with mime-types-include.sh, don't edit */
+G_GNUC_UNUSED static const gchar *mime_types[] = {
+"application/mxf",
+"application/ogg",
+"application/ram",
+"application/sdp",
+"application/smil",
+"application/smil+xml",
+"application/vnd.apple.mpegurl",
+"application/vnd.ms-asf",
+"application/vnd.ms-wpl",
+"application/vnd.rn-realmedia",
+"application/vnd.rn-realmedia-vbr",
+"application/x-extension-m4a",
+"application/x-extension-mp4",
+"application/x-flac",
+"application/x-flash-video",
+"application/x-matroska",
+"application/x-netshow-channel",
+"application/x-ogg",
+"application/x-quicktime-media-link",
+"application/x-quicktimeplayer",
+"application/x-shorten",
+"application/x-smil",
+"application/xspf+xml",
+"audio/3gpp",
+"audio/3gpp2",
+"audio/aac",
+"audio/ac3",
+"audio/AMR",
+"audio/AMR-WB",
+"audio/basic",
+"audio/dv",
+"audio/eac3",
+"audio/flac",
+"audio/m4a",
+"audio/midi",
+"audio/mp1",
+"audio/mp2",
+"audio/mp3",
+"audio/mp4",
+"audio/mpeg",
+"audio/mpegurl",
+"audio/mpg",
+"audio/ogg",
+"audio/opus",
+"audio/prs.sid",
+"audio/scpls",
+"audio/vnd.rn-realaudio",
+"audio/wav",
+"audio/webm",
+"audio/x-aac",
+"audio/x-aiff",
+"audio/x-ape",
+"audio/x-flac",
+"audio/x-gsm",
+"audio/x-it",
+"audio/x-m4a",
+"audio/x-m4b",
+"audio/x-matroska",
+"audio/x-mod",
+"audio/x-mp1",
+"audio/x-mp2",
+"audio/x-mp3",
+"audio/x-mpg",
+"audio/x-mpeg",
+"audio/x-mpegurl",
+"audio/x-ms-asf",
+"audio/x-ms-asx",
+"audio/x-ms-wax",
+"audio/x-ms-wma",
+"audio/x-musepack",
+"audio/x-opus+ogg",
+"audio/x-pn-aiff",
+"audio/x-pn-au",
+"audio/x-pn-realaudio",
+"audio/x-pn-realaudio-plugin",
+"audio/x-pn-wav",
+"audio/x-pn-windows-acm",
+"audio/x-realaudio",
+"audio/x-real-audio",
+"audio/x-s3m",
+"audio/x-sbc",
+"audio/x-scpls",
+"audio/x-shorten",
+"audio/x-speex",
+"audio/x-stm",
+"audio/x-tta",
+"audio/x-wav",
+"audio/x-wavpack",
+"audio/x-vorbis",
+"audio/x-vorbis+ogg",
+"audio/x-xm",
+"image/vnd.rn-realpix",
+"image/x-pict",
+"misc/ultravox",
+"text/google-video-pointer",
+"text/x-google-video-pointer",
+"video/3gp",
+"video/3gpp",
+"video/3gpp2",
+"video/dv",
+"video/divx",
+"video/fli",
+"video/flv",
+"video/mp2t",
+"video/mp4",
+"video/mp4v-es",
+"video/mpeg",
+"video/mpeg-system",
+"video/msvideo",
+"video/ogg",
+"video/quicktime",
+"video/vivo",
+"video/vnd.divx",
+"video/vnd.mpegurl",
+"video/vnd.rn-realvideo",
+"video/vnd.vivo",
+"video/webm",
+"video/x-anim",
+"video/x-avi",
+"video/x-flc",
+"video/x-fli",
+"video/x-flic",
+"video/x-flv",
+"video/x-m4v",
+"video/x-matroska",
+"video/x-mjpeg",
+"video/x-mpeg",
+"video/x-mpeg2",
+"video/x-ms-asf",
+"video/x-ms-asf-plugin",
+"video/x-ms-asx",
+"video/x-msvideo",
+"video/x-ms-wm",
+"video/x-ms-wmv",
+"video/x-ms-wmx",
+"video/x-ms-wvx",
+"video/x-nsv",
+"video/x-ogm+ogg",
+"video/x-theora",
+"video/x-theora+ogg",
+"video/x-totem-stream",
+NULL
+};
+G_GNUC_UNUSED static const gchar *audio_mime_types[] = {
+"audio/3gpp",
+"audio/3gpp2",
+"audio/aac",
+"audio/ac3",
+"audio/AMR",
+"audio/AMR-WB",
+"audio/basic",
+"audio/dv",
+"audio/eac3",
+"audio/flac",
+"audio/m4a",
+"audio/midi",
+"audio/mp1",
+"audio/mp2",
+"audio/mp3",
+"audio/mp4",
+"audio/mpeg",
+"audio/mpg",
+"audio/ogg",
+"audio/opus",
+"audio/prs.sid",
+"audio/scpls",
+"audio/vnd.rn-realaudio",
+"audio/wav",
+"audio/webm",
+"audio/x-aac",
+"audio/x-aiff",
+"audio/x-ape",
+"audio/x-flac",
+"audio/x-gsm",
+"audio/x-it",
+"audio/x-m4a",
+"audio/x-m4b",
+"audio/x-matroska",
+"audio/x-mod",
+"audio/x-mp1",
+"audio/x-mp2",
+"audio/x-mp3",
+"audio/x-mpg",
+"audio/x-mpeg",
+"audio/x-ms-asf",
+"audio/x-ms-asx",
+"audio/x-ms-wax",
+"audio/x-ms-wma",
+"audio/x-musepack",
+"audio/x-opus+ogg",
+"audio/x-pn-aiff",
+"audio/x-pn-au",
+"audio/x-pn-wav",
+"audio/x-pn-windows-acm",
+"audio/x-realaudio",
+"audio/x-real-audio",
+"audio/x-s3m",
+"audio/x-sbc",
+"audio/x-shorten",
+"audio/x-speex",
+"audio/x-stm",
+"audio/x-tta",
+"audio/x-wav",
+"audio/x-wavpack",
+"audio/x-vorbis",
+"audio/x-vorbis+ogg",
+"audio/x-xm",
+"application/x-flac",
+NULL
+};
+G_GNUC_UNUSED static const gchar *video_mime_types[] = {
+"application/mxf",
+"application/ogg",
+"application/ram",
+"application/sdp",
+"application/vnd.apple.mpegurl",
+"application/vnd.ms-asf",
+"application/vnd.ms-wpl",
+"application/vnd.rn-realmedia",
+"application/vnd.rn-realmedia-vbr",
+"application/x-extension-m4a",
+"application/x-extension-mp4",
+"application/x-flash-video",
+"application/x-matroska",
+"application/x-netshow-channel",
+"application/x-ogg",
+"application/x-quicktimeplayer",
+"application/x-shorten",
+"image/vnd.rn-realpix",
+"image/x-pict",
+"misc/ultravox",
+"text/x-google-video-pointer",
+"video/3gp",
+"video/3gpp",
+"video/3gpp2",
+"video/dv",
+"video/divx",
+"video/fli",
+"video/flv",
+"video/mp2t",
+"video/mp4",
+"video/mp4v-es",
+"video/mpeg",
+"video/mpeg-system",
+"video/msvideo",
+"video/ogg",
+"video/quicktime",
+"video/vivo",
+"video/vnd.divx",
+"video/vnd.mpegurl",
+"video/vnd.rn-realvideo",
+"video/vnd.vivo",
+"video/webm",
+"video/x-anim",
+"video/x-avi",
+"video/x-flc",
+"video/x-fli",
+"video/x-flic",
+"video/x-flv",
+"video/x-m4v",
+"video/x-matroska",
+"video/x-mjpeg",
+"video/x-mpeg",
+"video/x-mpeg2",
+"video/x-ms-asf",
+"video/x-ms-asf-plugin",
+"video/x-ms-asx",
+"video/x-msvideo",
+"video/x-ms-wm",
+"video/x-ms-wmv",
+"video/x-ms-wmx",
+"video/x-ms-wvx",
+"video/x-nsv",
+"video/x-ogm+ogg",
+"video/x-theora",
+"video/x-theora+ogg",
+"video/x-totem-stream",
+"audio/x-pn-realaudio",
+NULL
+};
diff --git a/extensions/audio-video-properties/totem-properties-main.c b/extensions/audio-video-properties/totem-properties-main.c
new file mode 100644
index 0000000..2bbd520
--- /dev/null
+++ b/extensions/audio-video-properties/totem-properties-main.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2000, 2001 Eazel Inc.
+ * Copyright (C) 2003 Andrew Sobala <aes@gnome.org>
+ * Copyright (C) 2005 Bastien Nocera <hadess@hadess.net>
+ *
+ * This library 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 library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <config.h>
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#define GST_USE_UNSTABLE_API 1
+#include <gst/gst.h>
+
+#include "totem-properties-view.h"
+#include "totem-gst-helpers.h"
+#include <nautilus-extension.h>
+
+#define WANT_MIME_TYPES 1
+#include "totem-mime-types.h"
+
+static GType tpp_type = 0;
+static void property_page_provider_iface_init
+ (NautilusPropertyPageProviderIface *iface);
+static GList *totem_properties_get_pages
+ (NautilusPropertyPageProvider *provider, GList *files);
+
+static void
+totem_properties_plugin_register_type (GTypeModule *module)
+{
+ const GTypeInfo info = {
+ sizeof (GObjectClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) NULL,
+ NULL,
+ NULL,
+ sizeof (GObject),
+ 0,
+ (GInstanceInitFunc) NULL
+ };
+ const GInterfaceInfo property_page_provider_iface_info = {
+ (GInterfaceInitFunc)property_page_provider_iface_init,
+ NULL,
+ NULL
+ };
+
+ tpp_type = g_type_module_register_type (module, G_TYPE_OBJECT,
+ "TotemPropertiesPlugin",
+ &info, 0);
+ g_type_module_add_interface (module,
+ tpp_type,
+ NAUTILUS_TYPE_PROPERTY_PAGE_PROVIDER,
+ &property_page_provider_iface_info);
+}
+
+static void
+property_page_provider_iface_init (NautilusPropertyPageProviderIface *iface)
+{
+ iface->get_pages = totem_properties_get_pages;
+}
+
+static gpointer
+init_backend (gpointer data)
+{
+ gst_init (NULL, NULL);
+ totem_gst_disable_display_decoders ();
+ return NULL;
+}
+
+static GList *
+totem_properties_get_pages (NautilusPropertyPageProvider *provider,
+ GList *files)
+{
+ static GOnce backend_inited = G_ONCE_INIT;
+ NautilusFileInfo *file;
+ char *uri;
+ GtkWidget *page, *label;
+ NautilusPropertyPage *property_page;
+ guint i;
+ gboolean found;
+
+ /* only add properties page if a single file is selected */
+ if (files == NULL || files->next != NULL)
+ return NULL;
+ file = files->data;
+
+ /* only add the properties page to these mime types */
+ found = FALSE;
+ for (i = 0; mime_types[i] != NULL; i++) {
+ if (nautilus_file_info_is_mime_type (file, mime_types[i])) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found == FALSE)
+ return NULL;
+
+ /* okay, make the page, init'ing the backend first if necessary */
+ g_once (&backend_inited, init_backend, NULL);
+
+ uri = nautilus_file_info_get_uri (file);
+ label = gtk_label_new (_("Audio/Video"));
+ page = totem_properties_view_new (uri, label);
+ g_free (uri);
+
+ gtk_container_set_border_width (GTK_CONTAINER (page), 6);
+ property_page = nautilus_property_page_new ("video-properties",
+ label, page);
+
+ return g_list_prepend (NULL, property_page);
+}
+
+/* --- extension interface --- */
+void
+nautilus_module_initialize (GTypeModule *module)
+{
+ /* set up translation catalog */
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+ totem_properties_plugin_register_type (module);
+ totem_properties_view_register_type (module);
+}
+
+void
+nautilus_module_shutdown (void)
+{
+}
+
+void
+nautilus_module_list_types (const GType **types,
+ int *num_types)
+{
+ static GType type_list[1];
+
+ type_list[0] = tpp_type;
+ *types = type_list;
+ *num_types = G_N_ELEMENTS (type_list);
+}
+
diff --git a/extensions/audio-video-properties/totem-properties-view.c b/extensions/audio-video-properties/totem-properties-view.c
new file mode 100644
index 0000000..f280fa2
--- /dev/null
+++ b/extensions/audio-video-properties/totem-properties-view.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2003 Andrew Sobala <aes@gnome.org>
+ * Copyright (C) 2004 Bastien Nocera <hadess@hadess.net>
+ *
+ * This library 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 library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <config.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n-lib.h>
+
+#define GST_USE_UNSTABLE_API 1
+#include <gst/tag/tag.h>
+#include <gst/pbutils/pbutils.h>
+
+#include "totem-properties-view.h"
+#include "bacon-video-widget-properties.h"
+
+struct TotemPropertiesViewPriv {
+ GtkWidget *label;
+ GtkWidget *vbox;
+ BaconVideoWidgetProperties *props;
+ GstDiscoverer *disco;
+};
+
+static GObjectClass *parent_class = NULL;
+static void totem_properties_view_finalize (GObject *object);
+
+G_DEFINE_TYPE (TotemPropertiesView, totem_properties_view, GTK_TYPE_GRID)
+
+void
+totem_properties_view_register_type (GTypeModule *module)
+{
+ totem_properties_view_get_type ();
+}
+
+static void
+totem_properties_view_class_init (TotemPropertiesViewClass *class)
+{
+ parent_class = g_type_class_peek_parent (class);
+ G_OBJECT_CLASS (class)->finalize = totem_properties_view_finalize;
+}
+
+static void
+update_general (TotemPropertiesView *props,
+ const GstTagList *list)
+{
+ struct {
+ const char *tag_name;
+ const char *widget;
+ } items[] = {
+ { GST_TAG_TITLE, "title" },
+ { GST_TAG_ARTIST, "artist" },
+ { GST_TAG_ALBUM, "album" },
+ };
+ guint i;
+ GDate *date;
+ GstDateTime *datetime;
+ gchar *comment;
+
+ for (i = 0; i < G_N_ELEMENTS(items); i++) {
+ char *string;
+
+ if (gst_tag_list_get_string_index (list, items[i].tag_name, 0, &string) != FALSE) {
+ bacon_video_widget_properties_set_label (props->priv->props,
+ items[i].widget,
+ string);
+ g_free (string);
+ }
+ }
+
+ /* Comment else use Description defined by:
+ * http://xiph.org/vorbis/doc/v-comment.html */
+ if (gst_tag_list_get_string (list, GST_TAG_COMMENT, &comment) ||
+ gst_tag_list_get_string (list, GST_TAG_DESCRIPTION, &comment)) {
+
+ bacon_video_widget_properties_set_label (props->priv->props,
+ "comment",
+ comment);
+ g_free (comment);
+ }
+
+ /* Date */
+ if (gst_tag_list_get_date (list, GST_TAG_DATE, &date)) {
+ char *string;
+
+ string = g_strdup_printf ("%d", g_date_get_year (date));
+ g_date_free (date);
+ bacon_video_widget_properties_set_label (props->priv->props,
+ "year",
+ string);
+ g_free (string);
+ } else if (gst_tag_list_get_date_time (list, GST_TAG_DATE_TIME, &datetime)) {
+ char *string;
+
+ string = g_strdup_printf ("%d", gst_date_time_get_year (datetime));
+ gst_date_time_unref (datetime);
+ bacon_video_widget_properties_set_label (props->priv->props,
+ "year",
+ string);
+ g_free (string);
+ }
+}
+
+static void
+set_codec (TotemPropertiesView *props,
+ GstDiscovererStreamInfo *info,
+ const char *widget)
+{
+ GstCaps *caps;
+ const char *nick;
+
+ nick = gst_discoverer_stream_info_get_stream_type_nick (info);
+ if (g_str_equal (nick, "audio") == FALSE &&
+ g_str_equal (nick, "video") == FALSE &&
+ g_str_equal (nick, "container") == FALSE) {
+ bacon_video_widget_properties_set_label (props->priv->props,
+ widget,
+ _("N/A"));
+ return;
+ }
+
+ caps = gst_discoverer_stream_info_get_caps (info);
+ if (caps) {
+ if (gst_caps_is_fixed (caps)) {
+ char *string;
+
+ string = gst_pb_utils_get_codec_description (caps);
+ bacon_video_widget_properties_set_label (props->priv->props,
+ widget,
+ string);
+ g_free (string);
+ }
+ gst_caps_unref (caps);
+ }
+}
+
+static void
+set_bitrate (TotemPropertiesView *props,
+ guint bitrate,
+ const char *widget)
+{
+ char *string;
+
+ if (!bitrate) {
+ bacon_video_widget_properties_set_label (props->priv->props,
+ widget,
+ C_("Stream bit rate", "N/A"));
+ return;
+ }
+ string = g_strdup_printf (_("%d kbps"), bitrate / 1000);
+ bacon_video_widget_properties_set_label (props->priv->props,
+ widget,
+ string);
+ g_free (string);
+}
+
+static void
+update_video (TotemPropertiesView *props,
+ GstDiscovererVideoInfo *info)
+{
+ guint width, height;
+ guint fps_n, fps_d;
+ char *string;
+
+ width = gst_discoverer_video_info_get_width (info);
+ height = gst_discoverer_video_info_get_height (info);
+ string = g_strdup_printf (N_("%d × %d"), width, height);
+ bacon_video_widget_properties_set_label (props->priv->props,
+ "dimensions",
+ string);
+ g_free (string);
+
+ set_codec (props, (GstDiscovererStreamInfo *) info, "vcodec");
+ set_bitrate (props, gst_discoverer_video_info_get_bitrate (info), "video_bitrate");
+
+ /* Round up/down to the nearest integer framerate */
+ fps_n = gst_discoverer_video_info_get_framerate_num (info);
+ fps_d = gst_discoverer_video_info_get_framerate_denom (info);
+ if (fps_d > 0.0)
+ bacon_video_widget_properties_set_framerate (props->priv->props,
+ (float) fps_n / (float) fps_d);
+ else
+ bacon_video_widget_properties_set_framerate (props->priv->props, 0.0);
+}
+
+static void
+update_audio (TotemPropertiesView *props,
+ GstDiscovererAudioInfo *info)
+{
+ guint samplerate, channels;
+
+ set_codec (props, (GstDiscovererStreamInfo *) info, "acodec");
+
+ set_bitrate (props, gst_discoverer_audio_info_get_bitrate (info), "audio_bitrate");
+
+ samplerate = gst_discoverer_audio_info_get_sample_rate (info);
+ if (samplerate) {
+ char *string;
+ string = g_strdup_printf (_("%d Hz"), samplerate);
+ bacon_video_widget_properties_set_label (props->priv->props,
+ "samplerate",
+ string);
+ g_free (string);
+ } else {
+ bacon_video_widget_properties_set_label (props->priv->props,
+ "samplerate",
+ C_("Sample rate", "N/A"));
+ }
+
+ channels = gst_discoverer_audio_info_get_channels (info);
+ if (channels) {
+ char *string;
+
+ if (channels > 2) {
+ string = g_strdup_printf ("%s %d.1", _("Surround"), channels - 1);
+ } else if (channels == 1) {
+ string = g_strdup (_("Mono"));
+ } else if (channels == 2) {
+ string = g_strdup (_("Stereo"));
+ } else {
+ string = g_strdup (""); //Should not happen
+ }
+ bacon_video_widget_properties_set_label (props->priv->props,
+ "channels",
+ string);
+ g_free (string);
+ } else {
+ bacon_video_widget_properties_set_label (props->priv->props,
+ "channels",
+ C_("Number of audio channels", "N/A"));
+ }
+}
+
+static void
+discovered_cb (GstDiscoverer *discoverer,
+ GstDiscovererInfo *info,
+ GError *error,
+ TotemPropertiesView *props)
+{
+ GList *video_streams, *audio_streams;
+ const GstTagList *taglist;
+ gboolean has_audio, has_video;
+ const char *label;
+ GstClockTime duration;
+ GstDiscovererStreamInfo *sinfo;
+
+ if (error) {
+ g_warning ("Couldn't get information about '%s': %s",
+ gst_discoverer_info_get_uri (info),
+ error->message);
+ return;
+ }
+
+ video_streams = gst_discoverer_info_get_video_streams (info);
+ has_video = (video_streams != NULL);
+ audio_streams = gst_discoverer_info_get_audio_streams (info);
+ has_audio = (audio_streams != NULL);
+
+ if (has_audio == has_video)
+ label = N_("Audio/Video");
+ else if (has_audio)
+ label = N_("Audio");
+ else
+ label = N_("Video");
+
+ gtk_label_set_text (GTK_LABEL (props->priv->label), _(label));
+
+ /* Widgets */
+ bacon_video_widget_properties_set_has_type (props->priv->props,
+ has_video,
+ has_audio);
+
+ /* General */
+ duration = gst_discoverer_info_get_duration (info);
+ bacon_video_widget_properties_set_duration (props->priv->props, duration / GST_SECOND * 1000);
+
+ sinfo = gst_discoverer_info_get_stream_info (info);
+ if (sinfo) {
+ set_codec (props, sinfo, "container");
+ gst_discoverer_stream_info_unref (sinfo);
+ }
+
+ taglist = gst_discoverer_info_get_tags (info);
+ update_general (props, taglist);
+
+ /* Video and Audio */
+ if (video_streams)
+ update_video (props, video_streams->data);
+ if (audio_streams)
+ update_audio (props, audio_streams->data);
+
+ gst_discoverer_stream_info_list_free (video_streams);
+ gst_discoverer_stream_info_list_free (audio_streams);
+}
+
+static void
+totem_properties_view_init (TotemPropertiesView *props)
+{
+ GError *err = NULL;
+
+ props->priv = g_new0 (TotemPropertiesViewPriv, 1);
+
+ props->priv->vbox = bacon_video_widget_properties_new ();
+ gtk_grid_attach (GTK_GRID (props), props->priv->vbox, 0, 0, 1, 1);
+ gtk_widget_show (GTK_WIDGET (props));
+
+ props->priv->props = BACON_VIDEO_WIDGET_PROPERTIES (props->priv->vbox);
+
+ props->priv->disco = gst_discoverer_new (GST_SECOND * 60, &err);
+ if (props->priv->disco == NULL) {
+ g_warning ("Could not create discoverer object: %s", err->message);
+ g_error_free (err);
+ return;
+ }
+ g_signal_connect (props->priv->disco, "discovered",
+ G_CALLBACK (discovered_cb), props);
+}
+
+static void
+totem_properties_view_finalize (GObject *object)
+{
+ TotemPropertiesView *props;
+
+ props = TOTEM_PROPERTIES_VIEW (object);
+
+ if (props->priv != NULL) {
+ if (props->priv->disco) {
+ g_signal_handlers_disconnect_by_func (props->priv->disco,
+ discovered_cb,
+ props);
+ gst_discoverer_stop (props->priv->disco);
+ g_clear_object (&props->priv->disco);
+ }
+ g_clear_object (&props->priv->label);
+ g_free (props->priv);
+ }
+ props->priv = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+totem_properties_view_set_location (TotemPropertiesView *props,
+ const char *location)
+{
+ g_assert (TOTEM_IS_PROPERTIES_VIEW (props));
+
+ if (props->priv->disco)
+ gst_discoverer_stop (props->priv->disco);
+
+ bacon_video_widget_properties_reset (props->priv->props);
+
+ if (location != NULL && props->priv->disco != NULL) {
+ gst_discoverer_start (props->priv->disco);
+
+ if (gst_discoverer_discover_uri_async (props->priv->disco, location) == FALSE) {
+ g_warning ("Couldn't add %s to list", location);
+ return;
+ }
+ }
+}
+
+GtkWidget *
+totem_properties_view_new (const char *location, GtkWidget *label)
+{
+ TotemPropertiesView *self;
+
+ self = g_object_new (TOTEM_TYPE_PROPERTIES_VIEW, NULL);
+ g_object_ref (label);
+ self->priv->label = label;
+ totem_properties_view_set_location (self, location);
+
+ return GTK_WIDGET (self);
+}
diff --git a/extensions/audio-video-properties/totem-properties-view.h b/extensions/audio-video-properties/totem-properties-view.h
new file mode 100644
index 0000000..0dc7292
--- /dev/null
+++ b/extensions/audio-video-properties/totem-properties-view.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2003 Andrew Sobala <aes@gnome.org>
+ * Copyright (C) 2005 Bastien Nocera <hadess@hadess.net>
+ *
+ * This library 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 library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef TOTEM_PROPERTIES_VIEW_H
+#define TOTEM_PROPERTIES_VIEW_H
+
+#include <gtk/gtk.h>
+
+#define TOTEM_TYPE_PROPERTIES_VIEW (totem_properties_view_get_type ())
+#define TOTEM_PROPERTIES_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TOTEM_TYPE_PROPERTIES_VIEW, TotemPropertiesView))
+#define TOTEM_PROPERTIES_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TOTEM_TYPE_PROPERTIES_VIEW, TotemPropertiesViewClass))
+#define TOTEM_IS_PROPERTIES_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TOTEM_TYPE_PROPERTIES_VIEW))
+#define TOTEM_IS_PROPERTIES_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TOTEM_TYPE_PROPERTIES_VIEW))
+
+typedef struct TotemPropertiesViewPriv TotemPropertiesViewPriv;
+
+typedef struct {
+ GtkGrid parent;
+ TotemPropertiesViewPriv *priv;
+} TotemPropertiesView;
+
+typedef struct {
+ GtkGridClass parent;
+} TotemPropertiesViewClass;
+
+GType totem_properties_view_get_type (void);
+void totem_properties_view_register_type (GTypeModule *module);
+
+GtkWidget *totem_properties_view_new (const char *location,
+ GtkWidget *label);
+
+#endif /* TOTEM_PROPERTIES_VIEW_H */
diff --git a/extensions/image-properties/meson.build b/extensions/image-properties/meson.build
new file mode 100644
index 0000000..b292a19
--- /dev/null
+++ b/extensions/image-properties/meson.build
@@ -0,0 +1,15 @@
+shared_module (
+ 'nautilus-image-properties', [
+ 'nautilus-image-properties-module.c',
+ 'nautilus-image-properties-page.c',
+ 'nautilus-image-properties-page.h',
+ 'nautilus-image-properties-page-provider.c',
+ 'nautilus-image-properties-page-provider.h'
+ ],
+ dependencies: [
+ gexiv,
+ nautilus_extension
+ ],
+ install: true,
+ install_dir: extensiondir
+)
diff --git a/extensions/image-properties/nautilus-image-properties-module.c b/extensions/image-properties/nautilus-image-properties-module.c
new file mode 100644
index 0000000..0ce02e9
--- /dev/null
+++ b/extensions/image-properties/nautilus-image-properties-module.c
@@ -0,0 +1,54 @@
+/* Copyright (C) 2018 Ernestas Kulik <ernestask@gnome.org>
+ *
+ * This file is part of Nautilus.
+ *
+ * Nautilus 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.
+ *
+ * Nautilus 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 Nautilus. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include "nautilus-image-properties-page-provider.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <nautilus-extension.h>
+
+void
+nautilus_module_initialize (GTypeModule *module)
+{
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+ nautilus_image_properties_page_provider_load (module);
+}
+
+void
+nautilus_module_shutdown (void)
+{
+}
+
+void
+nautilus_module_list_types (const GType **types,
+ int *num_types)
+{
+ static GType type_list[1] = { 0 };
+
+ g_assert (types != NULL);
+ g_assert (num_types != NULL);
+
+ type_list[0] = NAUTILUS_TYPE_IMAGE_PROPERTIES_PAGE_PROVIDER;
+
+ *types = type_list;
+ *num_types = G_N_ELEMENTS (type_list);
+}
diff --git a/extensions/image-properties/nautilus-image-properties-page-provider.c b/extensions/image-properties/nautilus-image-properties-page-provider.c
new file mode 100644
index 0000000..b270ea9
--- /dev/null
+++ b/extensions/image-properties/nautilus-image-properties-page-provider.c
@@ -0,0 +1,136 @@
+/* Copyright (C) 2004 Red Hat, Inc
+ * Copyright (c) 2007 Novell, Inc.
+ * Copyright (c) 2017 Thomas Bechtold <thomasbechtold@jpberlin.de>
+ * Copyright (c) 2018 Ernestas Kulik <ernestask@gnome.org>
+ *
+ * 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/>.
+ *
+ * Author: Alexander Larsson <alexl@redhat.com>
+ * XMP support by Hubert Figuiere <hfiguiere@novell.com>
+ */
+
+#include "nautilus-image-properties-page-provider.h"
+
+#include "nautilus-image-properties-page.h"
+
+#include <glib/gi18n.h>
+
+#include <nautilus-extension.h>
+
+#define NAUTILUS_IMAGE_PROPERTIES_PAGE_NAME "NautilusImagePropertiesPage::property_page"
+
+struct _NautilusImagesPropertiesPageProvider
+{
+ GObject parent_instance;
+};
+
+static void property_page_provider_iface_init (NautilusPropertyPageProviderInterface *iface);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (NautilusImagesPropertiesPageProvider,
+ nautilus_image_properties_page_provider,
+ G_TYPE_OBJECT,
+ 0,
+ G_IMPLEMENT_INTERFACE_DYNAMIC (NAUTILUS_TYPE_PROPERTY_PAGE_PROVIDER,
+ property_page_provider_iface_init))
+
+static gboolean
+is_mime_type_supported (const char *mime_type)
+{
+ g_autoptr (GSList) formats = NULL;
+
+ if (mime_type == NULL)
+ {
+ return FALSE;
+ }
+
+ formats = gdk_pixbuf_get_formats ();
+
+ for (GSList *l = formats; l != NULL; l = l->next)
+ {
+ g_auto (GStrv) mime_types = NULL;
+
+ mime_types = gdk_pixbuf_format_get_mime_types (l->data);
+ if (mime_types == NULL)
+ {
+ continue;
+ }
+
+ if (g_strv_contains ((const char * const *) mime_types, mime_type))
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static GList *
+get_pages (NautilusPropertyPageProvider *provider,
+ GList *files)
+{
+ NautilusFileInfo *file_info;
+ g_autofree char *mime_type = NULL;
+ NautilusImagesPropertiesPage *image_properties_page;
+ NautilusPropertyPage *property_page;
+
+ if (files == NULL || files->next != NULL)
+ {
+ return NULL;
+ }
+
+ file_info = NAUTILUS_FILE_INFO (files->data);
+ mime_type = nautilus_file_info_get_mime_type (file_info);
+ if (!is_mime_type_supported (mime_type))
+ {
+ return NULL;
+ }
+ image_properties_page = nautilus_image_properties_page_new ();
+ property_page = nautilus_property_page_new (NAUTILUS_IMAGE_PROPERTIES_PAGE_NAME,
+ gtk_label_new (_("Image")),
+ GTK_WIDGET (image_properties_page));
+
+ nautilus_image_properties_page_load_from_file_info (image_properties_page, file_info);
+
+ return g_list_prepend (NULL, property_page);
+}
+
+static void
+property_page_provider_iface_init (NautilusPropertyPageProviderInterface *iface)
+{
+ iface->get_pages = get_pages;
+}
+
+static void
+nautilus_image_properties_page_provider_init (NautilusImagesPropertiesPageProvider *self)
+{
+ (void) self;
+}
+
+static void
+nautilus_image_properties_page_provider_class_init (NautilusImagesPropertiesPageProviderClass *klass)
+{
+ (void) klass;
+}
+
+static void
+nautilus_image_properties_page_provider_class_finalize (NautilusImagesPropertiesPageProviderClass *klass)
+{
+ (void) klass;
+}
+
+void
+nautilus_image_properties_page_provider_load (GTypeModule *module)
+{
+ nautilus_image_properties_page_provider_register_type (module);
+}
diff --git a/extensions/image-properties/nautilus-image-properties-page-provider.h b/extensions/image-properties/nautilus-image-properties-page-provider.h
new file mode 100644
index 0000000..59fd6f9
--- /dev/null
+++ b/extensions/image-properties/nautilus-image-properties-page-provider.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2018 Ernestas Kulik <ernestask@gnome.org>
+ *
+ * This file is part of Nautilus.
+ *
+ * Nautilus 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.
+ *
+ * Nautilus 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 Nautilus. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+#define NAUTILUS_TYPE_IMAGE_PROPERTIES_PAGE_PROVIDER (nautilus_image_properties_page_provider_get_type ())
+
+G_DECLARE_FINAL_TYPE (NautilusImagesPropertiesPageProvider,
+ nautilus_image_properties_page_provider,
+ NAUTILUS, IMAGE_PROPERTIES_PAGE_PROVIDER,
+ GObject)
+
+void nautilus_image_properties_page_provider_load (GTypeModule *module); \ No newline at end of file
diff --git a/extensions/image-properties/nautilus-image-properties-page.c b/extensions/image-properties/nautilus-image-properties-page.c
new file mode 100644
index 0000000..bca0b56
--- /dev/null
+++ b/extensions/image-properties/nautilus-image-properties-page.c
@@ -0,0 +1,515 @@
+/* Copyright (C) 2004 Red Hat, Inc
+ * Copyright (c) 2007 Novell, Inc.
+ * Copyright (c) 2017 Thomas Bechtold <thomasbechtold@jpberlin.de>
+ *
+ * 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/>.
+ *
+ * Author: Alexander Larsson <alexl@redhat.com>
+ * XMP support by Hubert Figuiere <hfiguiere@novell.com>
+ */
+
+#include "nautilus-image-properties-page.h"
+
+#include <gexiv2/gexiv2.h>
+#include <glib/gi18n.h>
+
+#define LOAD_BUFFER_SIZE 8192
+
+struct _NautilusImagesPropertiesPage
+{
+ GtkGrid parent;
+
+ GCancellable *cancellable;
+ GtkWidget *grid;
+ GdkPixbufLoader *loader;
+ gboolean got_size;
+ gboolean pixbuf_still_loading;
+ unsigned char buffer[LOAD_BUFFER_SIZE];
+ int width;
+ int height;
+
+ GExiv2Metadata *md;
+ gboolean md_ready;
+};
+
+G_DEFINE_TYPE (NautilusImagesPropertiesPage,
+ nautilus_image_properties_page,
+ GTK_TYPE_GRID);
+
+static void
+finalize (GObject *object)
+{
+ NautilusImagesPropertiesPage *page;
+
+ page = NAUTILUS_IMAGE_PROPERTIES_PAGE (object);
+
+ if (page->cancellable != NULL)
+ {
+ g_cancellable_cancel (page->cancellable);
+ g_clear_object (&page->cancellable);
+ }
+
+ G_OBJECT_CLASS (nautilus_image_properties_page_parent_class)->finalize (object);
+}
+
+static void
+nautilus_image_properties_page_class_init (NautilusImagesPropertiesPageClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = finalize;
+}
+
+static void
+append_item (NautilusImagesPropertiesPage *page,
+ const char *name,
+ const char *value)
+{
+ GtkWidget *name_label;
+ PangoAttrList *attrs;
+
+ name_label = gtk_label_new (name);
+ attrs = pango_attr_list_new ();
+
+ pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
+ gtk_label_set_attributes (GTK_LABEL (name_label), attrs);
+ pango_attr_list_unref (attrs);
+ gtk_container_add (GTK_CONTAINER (page->grid), name_label);
+ gtk_widget_set_halign (name_label, GTK_ALIGN_START);
+ gtk_widget_show (name_label);
+
+ if (value != NULL)
+ {
+ GtkWidget *value_label;
+
+ value_label = gtk_label_new (value);
+
+ gtk_label_set_line_wrap (GTK_LABEL (value_label), TRUE);
+ gtk_grid_attach_next_to (GTK_GRID (page->grid), value_label,
+ name_label, GTK_POS_RIGHT,
+ 1, 1);
+ gtk_widget_set_halign (value_label, GTK_ALIGN_START);
+ gtk_widget_set_hexpand (value_label, TRUE);
+ gtk_widget_show (value_label);
+ }
+}
+
+static void
+nautilus_image_properties_page_init (NautilusImagesPropertiesPage *self)
+{
+ GtkWidget *scrolled_window;
+
+ scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+
+ gtk_widget_set_vexpand (GTK_WIDGET (scrolled_window), TRUE);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
+
+ gtk_container_add (GTK_CONTAINER (self), scrolled_window);
+
+ self->grid = gtk_grid_new ();
+
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (self->grid), GTK_ORIENTATION_VERTICAL);
+ gtk_grid_set_row_spacing (GTK_GRID (self->grid), 6);
+ gtk_grid_set_column_spacing (GTK_GRID (self->grid), 18);
+ append_item (self, _("Loading…"), NULL);
+ gtk_container_add (GTK_CONTAINER (scrolled_window), self->grid);
+
+ gtk_widget_show_all (GTK_WIDGET (self));
+}
+
+static void
+append_basic_info (NautilusImagesPropertiesPage *page)
+{
+ GdkPixbufFormat *format;
+ g_autofree char *name = NULL;
+ g_autofree char *desc = NULL;
+ g_autofree char *value = NULL;
+
+ format = gdk_pixbuf_loader_get_format (page->loader);
+ name = gdk_pixbuf_format_get_name (format);
+ desc = gdk_pixbuf_format_get_description (format);
+ value = g_strdup_printf ("%s (%s)", name, desc);
+
+ append_item (page, _("Image Type"), value);
+
+ g_free (value);
+ value = g_strdup_printf (ngettext ("%d pixel",
+ "%d pixels",
+ page->width),
+ page->width);
+
+ append_item (page, _("Width"), value);
+
+ g_free (value);
+ value = g_strdup_printf (ngettext ("%d pixel",
+ "%d pixels",
+ page->height),
+ page->height);
+
+ append_item (page, _("Height"), value);
+}
+
+static void
+append_gexiv2_tag (NautilusImagesPropertiesPage *page,
+ const char **tag_names,
+ const char *description)
+{
+ g_assert (tag_names != NULL);
+
+ for (const char **i = tag_names; *i != NULL; i++)
+ {
+ if (gexiv2_metadata_has_tag (page->md, *i))
+ {
+ g_autofree char *tag_value = NULL;
+
+ tag_value = gexiv2_metadata_get_tag_interpreted_string (page->md, *i);
+
+ if (description == NULL)
+ {
+ description = gexiv2_metadata_get_tag_description (*i);
+ }
+
+ /* don't add empty tags - try next one */
+ if (strlen (tag_value) > 0)
+ {
+ append_item (page, description, tag_value);
+ break;
+ }
+ }
+ }
+}
+
+static void
+append_gexiv2_info (NautilusImagesPropertiesPage *page)
+{
+ double longitude;
+ double latitude;
+ double altitude;
+
+ /* define tags and its alternatives */
+ const char *title[] = { "Xmp.dc.title", NULL };
+ const char *camera_brand[] = { "Exif.Image.Make", NULL };
+ const char *camera_model[] = { "Exif.Image.Model", "Exif.Image.UniqueCameraModel", NULL };
+ const char *created_on[] = { "Exif.Photo.DateTimeOriginal", "Xmp.xmp.CreateDate", "Exif.Image.DateTime", NULL };
+ const char *exposure_time[] = { "Exif.Photo.ExposureTime", NULL };
+ const char *aperture_value[] = { "Exif.Photo.ApertureValue", NULL };
+ const char *iso_speed_ratings[] = { "Exif.Photo.ISOSpeedRatings", "Xmp.exifEX.ISOSpeed", NULL };
+ const char *flash[] = { "Exif.Photo.Flash", NULL };
+ const char *metering_mode[] = { "Exif.Photo.MeteringMode", NULL };
+ const char *exposure_mode[] = { "Exif.Photo.ExposureMode", NULL };
+ const char *focal_length[] = { "Exif.Photo.FocalLength", NULL };
+ const char *software[] = { "Exif.Image.Software", NULL };
+ const char *description[] = { "Xmp.dc.description", "Exif.Photo.UserComment", NULL };
+ const char *subject[] = { "Xmp.dc.subject", NULL };
+ const char *creator[] = { "Xmp.dc.creator", "Exif.Image.Artist", NULL };
+ const char *rights[] = { "Xmp.dc.rights", NULL };
+ const char *rating[] = { "Xmp.xmp.Rating", NULL };
+
+ if (!page->md_ready)
+ {
+ return;
+ }
+
+ append_gexiv2_tag (page, camera_brand, _("Camera Brand"));
+ append_gexiv2_tag (page, camera_model, _("Camera Model"));
+ append_gexiv2_tag (page, exposure_time, _("Exposure Time"));
+ append_gexiv2_tag (page, exposure_mode, _("Exposure Program"));
+ append_gexiv2_tag (page, aperture_value, _("Aperture Value"));
+ append_gexiv2_tag (page, iso_speed_ratings, _("ISO Speed Rating"));
+ append_gexiv2_tag (page, flash, _("Flash Fired"));
+ append_gexiv2_tag (page, metering_mode, _("Metering Mode"));
+ append_gexiv2_tag (page, focal_length, _("Focal Length"));
+ append_gexiv2_tag (page, software, _("Software"));
+ append_gexiv2_tag (page, title, _("Title"));
+ append_gexiv2_tag (page, description, _("Description"));
+ append_gexiv2_tag (page, subject, _("Keywords"));
+ append_gexiv2_tag (page, creator, _("Creator"));
+ append_gexiv2_tag (page, created_on, _("Created On"));
+ append_gexiv2_tag (page, rights, _("Copyright"));
+ append_gexiv2_tag (page, rating, _("Rating"));
+
+ if (gexiv2_metadata_get_gps_info (page->md, &longitude, &latitude, &altitude))
+ {
+ g_autofree char *gps_coords = NULL;
+
+ /* Translators: These are the coordinates of a position where a picture was taken. */
+ gps_coords = g_strdup_printf (_("%f N / %f W (%.0f m)"), latitude, longitude, altitude);
+
+ append_item (page, _("Coordinates"), gps_coords);
+ }
+}
+
+static void
+load_finished (NautilusImagesPropertiesPage *page)
+{
+ GtkWidget *label;
+
+ label = gtk_grid_get_child_at (GTK_GRID (page->grid), 0, 0);
+ gtk_container_remove (GTK_CONTAINER (page->grid), label);
+
+ if (page->loader != NULL)
+ {
+ gdk_pixbuf_loader_close (page->loader, NULL);
+ }
+
+ if (page->got_size)
+ {
+ append_basic_info (page);
+ append_gexiv2_info (page);
+ }
+ else
+ {
+ append_item (page, _("Failed to load image information"), NULL);
+ }
+
+ if (page->loader != NULL)
+ {
+ g_object_unref (page->loader);
+ page->loader = NULL;
+ }
+ page->md_ready = FALSE;
+ g_clear_object (&page->md);
+}
+
+static void
+file_close_callback (GObject *object,
+ GAsyncResult *res,
+ gpointer data)
+{
+ NautilusImagesPropertiesPage *page;
+ GInputStream *stream;
+
+ page = data;
+ stream = G_INPUT_STREAM (object);
+
+ g_input_stream_close_finish (stream, res, NULL);
+
+ g_clear_object (&page->cancellable);
+}
+
+static void
+file_read_callback (GObject *object,
+ GAsyncResult *res,
+ gpointer data)
+{
+ NautilusImagesPropertiesPage *page;
+ GInputStream *stream;
+ g_autoptr (GError) error = NULL;
+ gssize count_read;
+ gboolean done_reading;
+
+ page = data;
+ stream = G_INPUT_STREAM (object);
+ count_read = g_input_stream_read_finish (stream, res, &error);
+ done_reading = FALSE;
+
+ if (count_read > 0)
+ {
+ g_assert (count_read <= sizeof (page->buffer));
+
+ if (page->pixbuf_still_loading)
+ {
+ if (!gdk_pixbuf_loader_write (page->loader,
+ page->buffer,
+ count_read,
+ NULL))
+ {
+ page->pixbuf_still_loading = FALSE;
+ }
+ }
+
+ if (page->pixbuf_still_loading)
+ {
+ g_input_stream_read_async (G_INPUT_STREAM (stream),
+ page->buffer,
+ sizeof (page->buffer),
+ G_PRIORITY_DEFAULT,
+ page->cancellable,
+ file_read_callback,
+ page);
+ }
+ else
+ {
+ done_reading = TRUE;
+ }
+ }
+ else
+ {
+ /* either EOF, cancelled or an error occurred */
+ done_reading = TRUE;
+ }
+
+ if (error != NULL)
+ {
+ g_autofree char *uri = NULL;
+
+ uri = g_file_get_uri (G_FILE (object));
+
+ g_warning ("Error reading %s: %s", uri, error->message);
+ }
+
+ if (done_reading)
+ {
+ load_finished (page);
+ g_input_stream_close_async (stream,
+ G_PRIORITY_DEFAULT,
+ page->cancellable,
+ file_close_callback,
+ page);
+ }
+}
+
+static void
+size_prepared_callback (GdkPixbufLoader *loader,
+ int width,
+ int height,
+ gpointer callback_data)
+{
+ NautilusImagesPropertiesPage *page;
+
+ page = callback_data;
+
+ page->height = height;
+ page->width = width;
+ page->got_size = TRUE;
+ page->pixbuf_still_loading = FALSE;
+}
+
+typedef struct
+{
+ NautilusImagesPropertiesPage *page;
+ NautilusFileInfo *file_info;
+} FileOpenData;
+
+static void
+file_open_callback (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ g_autofree FileOpenData *data = NULL;
+ NautilusImagesPropertiesPage *page;
+ GFile *file;
+ g_autofree char *uri = NULL;
+ g_autoptr (GError) error = NULL;
+ g_autoptr (GFileInputStream) stream = NULL;
+
+ data = user_data;
+ page = data->page;
+ file = G_FILE (object);
+ uri = g_file_get_uri (file);
+ stream = g_file_read_finish (file, res, &error);
+ if (stream != NULL)
+ {
+ g_autofree char *mime_type = NULL;
+
+ mime_type = nautilus_file_info_get_mime_type (data->file_info);
+
+ page->loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, &error);
+ if (error != NULL)
+ {
+ g_warning ("Error creating loader for %s: %s", uri, error->message);
+ }
+ page->pixbuf_still_loading = TRUE;
+ page->width = 0;
+ page->height = 0;
+
+ g_signal_connect (page->loader,
+ "size-prepared",
+ G_CALLBACK (size_prepared_callback),
+ page);
+
+ g_input_stream_read_async (G_INPUT_STREAM (stream),
+ page->buffer,
+ sizeof (page->buffer),
+ G_PRIORITY_DEFAULT,
+ page->cancellable,
+ file_read_callback,
+ page);
+ }
+ else
+ {
+ g_warning ("Error reading %s: %s", uri, error->message);
+ load_finished (page);
+ }
+}
+
+void
+nautilus_image_properties_page_load_from_file_info (NautilusImagesPropertiesPage *self,
+ NautilusFileInfo *file_info)
+{
+ g_autofree char *uri = NULL;
+ g_autoptr (GFile) file = NULL;
+ g_autofree char *path = NULL;
+ FileOpenData *data;
+
+ g_return_if_fail (NAUTILUS_IS_IMAGE_PROPERTIES_PAGE (self));
+ g_return_if_fail (file_info != NULL);
+
+ self->cancellable = g_cancellable_new ();
+
+ uri = nautilus_file_info_get_uri (file_info);
+ file = g_file_new_for_uri (uri);
+ path = g_file_get_path (file);
+
+ /* gexiv2 metadata init */
+ self->md_ready = gexiv2_initialize ();
+ if (!self->md_ready)
+ {
+ g_warning ("Unable to initialize gexiv2");
+ }
+ else
+ {
+ self->md = gexiv2_metadata_new ();
+ if (path != NULL)
+ {
+ g_autoptr (GError) error = NULL;
+
+ if (!gexiv2_metadata_open_path (self->md, path, &error))
+ {
+ g_warning ("gexiv2 metadata not supported for '%s': %s", path, error->message);
+ self->md_ready = FALSE;
+ }
+ }
+ else
+ {
+ self->md_ready = FALSE;
+ }
+ }
+
+ data = g_new0 (FileOpenData, 1);
+
+ data->page = self;
+ data->file_info = file_info;
+
+ g_file_read_async (file,
+ G_PRIORITY_DEFAULT,
+ self->cancellable,
+ file_open_callback,
+ data);
+}
+
+NautilusImagesPropertiesPage *
+nautilus_image_properties_page_new (void)
+{
+ return g_object_new (NAUTILUS_TYPE_IMAGE_PROPERTIES_PAGE,
+ "margin-bottom", 6,
+ "margin-end", 12,
+ "margin-start", 12,
+ "margin-top", 6,
+ NULL);
+}
diff --git a/extensions/image-properties/nautilus-image-properties-page.h b/extensions/image-properties/nautilus-image-properties-page.h
new file mode 100644
index 0000000..5a2c358
--- /dev/null
+++ b/extensions/image-properties/nautilus-image-properties-page.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2004 Red Hat, Inc
+ *
+ * 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/>.
+ *
+ * Author: Alexander Larsson <alexl@redhat.com>
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+#include <nautilus-extension.h>
+
+#define NAUTILUS_TYPE_IMAGE_PROPERTIES_PAGE (nautilus_image_properties_page_get_type ())
+
+G_DECLARE_FINAL_TYPE (NautilusImagesPropertiesPage,
+ nautilus_image_properties_page,
+ NAUTILUS, IMAGE_PROPERTIES_PAGE,
+ GtkGrid)
+
+void nautilus_image_properties_page_load_from_file_info (NautilusImagesPropertiesPage *page,
+ NautilusFileInfo *file_info);
+
+NautilusImagesPropertiesPage *nautilus_image_properties_page_new (void); \ No newline at end of file
diff --git a/extensions/meson.build b/extensions/meson.build
new file mode 100644
index 0000000..5c6f64c
--- /dev/null
+++ b/extensions/meson.build
@@ -0,0 +1,3 @@
+subdir('image-properties')
+subdir('audio-video-properties')
+subdir('sendto')
diff --git a/extensions/sendto/meson.build b/extensions/sendto/meson.build
new file mode 100644
index 0000000..3b73bcd
--- /dev/null
+++ b/extensions/sendto/meson.build
@@ -0,0 +1,13 @@
+libnautilus_sendto_sources = [
+ 'nautilus-nste.c',
+ 'nautilus-nste.h',
+ 'nautilus-sendto-module.c'
+]
+
+libnautilus_sendto = shared_module(
+ 'nautilus-sendto',
+ libnautilus_sendto_sources,
+ dependencies: nautilus_extension,
+ install: true,
+ install_dir: extensiondir
+)
diff --git a/extensions/sendto/nautilus-nste.c b/extensions/sendto/nautilus-nste.c
new file mode 100644
index 0000000..1e92800
--- /dev/null
+++ b/extensions/sendto/nautilus-nste.c
@@ -0,0 +1,159 @@
+/*
+ * Nautilus-sendto
+ *
+ * Copyright (C) 2004 Free Software Foundation, Inc.
+ *
+ * This library 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 library 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 library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Roberto Majadas <roberto.majadas@openshine.com>
+ *
+ */
+
+#include <config.h>
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <nautilus-extension.h>
+#include "nautilus-nste.h"
+
+struct _NautilusNste
+{
+ GObject parent_instance;
+
+ gboolean nst_present;
+};
+
+static void menu_provider_iface_init (NautilusMenuProviderInterface *iface);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (NautilusNste, nautilus_nste, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE_DYNAMIC (NAUTILUS_TYPE_MENU_PROVIDER,
+ menu_provider_iface_init))
+
+static void
+sendto_callback (NautilusMenuItem *item,
+ gpointer user_data)
+{
+ GList *files;
+ g_autoptr (GString) command = NULL;
+
+ files = g_object_get_data (G_OBJECT (item), "files");
+ command = g_string_new ("nautilus-sendto");
+
+ for (GList *l = files; l != NULL; l = l->next)
+ {
+ g_autofree char *uri = NULL;
+
+ uri = nautilus_file_info_get_uri (l->data);
+
+ g_string_append_printf (command, " \"%s\"", uri);
+ }
+
+ g_spawn_command_line_async (command->str, NULL);
+}
+
+static gboolean
+check_available_mailer (void)
+{
+ g_autoptr (GAppInfo) app_info = NULL;
+
+ app_info = g_app_info_get_default_for_uri_scheme ("mailto");
+
+ return app_info != NULL;
+}
+
+static GList *
+get_file_items (NautilusMenuProvider *provider,
+ GtkWidget *window,
+ GList *files)
+{
+ GList *items = NULL;
+ gboolean one_item;
+ NautilusMenuItem *item;
+ NautilusNste *nste;
+
+ nste = NAUTILUS_NSTE (provider);
+ if (!nste->nst_present)
+ {
+ return NULL;
+ }
+
+ if (files == NULL)
+ {
+ return NULL;
+ }
+
+ if (!check_available_mailer ())
+ {
+ return NULL;
+ }
+
+ one_item = (files != NULL) && (files->next == NULL);
+ if (one_item &&
+ !nautilus_file_info_is_directory ((NautilusFileInfo *) files->data))
+ {
+ item = nautilus_menu_item_new ("NautilusNste::sendto",
+ _("Send to…"),
+ _("Send file by mail…"),
+ "document-send");
+ }
+ else
+ {
+ item = nautilus_menu_item_new ("NautilusNste::sendto",
+ _("Send to…"),
+ _("Send files by mail…"),
+ "document-send");
+ }
+ g_signal_connect (item,
+ "activate",
+ G_CALLBACK (sendto_callback),
+ provider);
+ g_object_set_data_full (G_OBJECT (item),
+ "files",
+ nautilus_file_info_list_copy (files),
+ (GDestroyNotify) nautilus_file_info_list_free);
+
+ items = g_list_append (items, item);
+
+ return items;
+}
+
+static void
+menu_provider_iface_init (NautilusMenuProviderInterface *iface)
+{
+ iface->get_file_items = get_file_items;
+}
+
+static void
+nautilus_nste_init (NautilusNste *nste)
+{
+ g_autofree char *path = NULL;
+
+ path = g_find_program_in_path ("nautilus-sendto");
+ nste->nst_present = (path != NULL);
+}
+
+static void
+nautilus_nste_class_init (NautilusNsteClass *klass)
+{
+}
+
+static void
+nautilus_nste_class_finalize (NautilusNsteClass *klass)
+{
+}
+
+void
+nautilus_nste_load (GTypeModule *module)
+{
+ nautilus_nste_register_type (module);
+}
diff --git a/extensions/sendto/nautilus-nste.h b/extensions/sendto/nautilus-nste.h
new file mode 100644
index 0000000..46f7104
--- /dev/null
+++ b/extensions/sendto/nautilus-nste.h
@@ -0,0 +1,35 @@
+/*
+ * Nautilus SendTo extension
+ *
+ * Copyright (C) 2005 Roberto Majadas
+ *
+ * This library 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 library 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 library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Roberto Majadas <roberto.majadas@openshine.com>
+ *
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_NSTE (nautilus_nste_get_type ())
+
+G_DECLARE_FINAL_TYPE (NautilusNste, nautilus_nste, NAUTILUS, NSTE, GObject)
+
+void nautilus_nste_load (GTypeModule *module);
+
+G_END_DECLS \ No newline at end of file
diff --git a/extensions/sendto/nautilus-sendto-module.c b/extensions/sendto/nautilus-sendto-module.c
new file mode 100644
index 0000000..524a34b
--- /dev/null
+++ b/extensions/sendto/nautilus-sendto-module.c
@@ -0,0 +1,53 @@
+/*
+ * Nautilus SendTo
+ *
+ * Copyright (C) 2005 Roberto Majadas
+ *
+ * This library 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 library 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 library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Roberto Majadas <roberto.majadas@openshine.com>
+ *
+ */
+
+#include <config.h>
+#include <nautilus-extension.h>
+#include <glib/gi18n-lib.h>
+#include "nautilus-nste.h"
+
+
+void
+nautilus_module_initialize (GTypeModule *module)
+{
+ nautilus_nste_load (module);
+
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+}
+
+void
+nautilus_module_shutdown (void)
+{
+}
+
+void
+nautilus_module_list_types (const GType **types,
+ int *num_types)
+{
+ static GType type_list[1];
+
+ type_list[0] = NAUTILUS_TYPE_NSTE;
+ *types = type_list;
+
+ *num_types = 1;
+}