summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2007-04-03 23:27:33 +0000
committerBastien Nocera <hadess@src.gnome.org>2007-04-03 23:27:33 +0000
commitc6872d0c8dd03a5cca345586c647225e5157a155 (patch)
treef18a9b3dc4d3eb3ad1f1df52f777bd72601181c1
parentca2cd82a9aef40c5c315b5d29351b9cf23cdc08a (diff)
downloadtotem-c6872d0c8dd03a5cca345586c647225e5157a155.tar.gz
Turn Totem into a TotemObject, remove calling the screensaver directly,
2007-04-04 Bastien Nocera <hadess@hadess.net> * Makefile.am: * configure.in: * data/Makefile.am: * data/plugins.glade: * data/totem-ui.xml: * data/totem.schemas.in: * src/Makefile.am: * src/plugins/*: * src/totem-menu.c: (totem_plugins_window_delete_cb), (totem_plugins_response_cb), (plugins_action_callback): * src/totem-object.c: (totem_object_class_init), (totem_object_init), (totem_object_finalize), (totem_object_set_property), (totem_object_get_property): * src/totem-private.h: * src/totem.c: (play_pause_set_label), (totem_action_play), (totem_action_seek), (totem_action_stop), (totem_action_play_pause), (totem_action_pause), (window_state_event_cb), (totem_action_seek_relative), (commit_hide_skip_to), (totem_is_playing), (on_eos_event), (video_widget_create), (main): * src/totem.h: Turn Totem into a TotemObject, remove calling the screensaver directly, and emit property notifies when switching to fullscreen, or playing/stopping playing, Add a plugin system, Move the screensaver handling to a builtin plugin. * src/totem-scrsaver.c: * src/totem-scrsaver.h: Move to... * lib/*: ...here * src/backend/bacon-video-widget-xine.c: (bacon_video_widget_class_init): Some cleanups * src/totem-interface.c: (totem_interface_boldify_label): * src/totem-interface.h: Add totem_interface_boldify_label() * src/totem-uri.c: (totem_dot_dir): * src/totem-uri.h: Add the totem_dot_dir svn path=/trunk/; revision=4190
-rw-r--r--ChangeLog42
-rw-r--r--Makefile.am2
-rw-r--r--configure.in11
-rw-r--r--data/Makefile.am1
-rw-r--r--data/plugins.glade498
-rw-r--r--data/totem-ui.xml1
-rw-r--r--data/totem.schemas.in12
-rw-r--r--lib/Makefile.am30
-rw-r--r--lib/totem-scrsaver.c (renamed from src/totem-scrsaver.c)0
-rw-r--r--lib/totem-scrsaver.h (renamed from src/totem-scrsaver.h)0
-rw-r--r--po/ChangeLog4
-rw-r--r--po/POTFILES.in10
-rw-r--r--src/Makefile.am11
-rw-r--r--src/backend/bacon-video-widget-xine.c5
-rw-r--r--src/plugins/Makefile.am41
-rw-r--r--src/plugins/screensaver/Makefile.am41
-rw-r--r--src/plugins/screensaver/screensaver.totem-plugin.desktop.in9
-rw-r--r--src/plugins/screensaver/totem-screensaver.c140
-rw-r--r--src/plugins/totem-module.c175
-rw-r--r--src/plugins/totem-module.h56
-rw-r--r--src/plugins/totem-plugin-manager.c544
-rw-r--r--src/plugins/totem-plugin-manager.h78
-rw-r--r--src/plugins/totem-plugin.c263
-rw-r--r--src/plugins/totem-plugin.h208
-rw-r--r--src/plugins/totem-plugins-engine.c742
-rw-r--r--src/plugins/totem-plugins-engine.h65
-rw-r--r--src/totem-interface.c34
-rw-r--r--src/totem-interface.h2
-rw-r--r--src/totem-menu.c56
-rw-r--r--src/totem-object.c124
-rw-r--r--src/totem-private.h14
-rw-r--r--src/totem-uri.c14
-rw-r--r--src/totem-uri.h1
-rw-r--r--src/totem.c59
-rw-r--r--src/totem.h25
35 files changed, 3261 insertions, 57 deletions
diff --git a/ChangeLog b/ChangeLog
index f8f5649f1..02498324c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,45 @@
+2007-04-04 Bastien Nocera <hadess@hadess.net>
+
+ * Makefile.am:
+ * configure.in:
+ * data/Makefile.am:
+ * data/plugins.glade:
+ * data/totem-ui.xml:
+ * data/totem.schemas.in:
+ * src/Makefile.am:
+ * src/plugins/*:
+ * src/totem-menu.c: (totem_plugins_window_delete_cb),
+ (totem_plugins_response_cb), (plugins_action_callback):
+ * src/totem-object.c: (totem_object_class_init),
+ (totem_object_init), (totem_object_finalize),
+ (totem_object_set_property), (totem_object_get_property):
+ * src/totem-private.h:
+ * src/totem.c: (play_pause_set_label), (totem_action_play),
+ (totem_action_seek), (totem_action_stop),
+ (totem_action_play_pause), (totem_action_pause),
+ (window_state_event_cb), (totem_action_seek_relative),
+ (commit_hide_skip_to), (totem_is_playing), (on_eos_event),
+ (video_widget_create), (main):
+ * src/totem.h: Turn Totem into a TotemObject, remove calling
+ the screensaver directly, and emit property notifies when
+ switching to fullscreen, or playing/stopping playing,
+ Add a plugin system, Move the screensaver handling to a
+ builtin plugin.
+
+ * src/totem-scrsaver.c:
+ * src/totem-scrsaver.h: Move to...
+
+ * lib/*: ...here
+
+ * src/backend/bacon-video-widget-xine.c:
+ (bacon_video_widget_class_init): Some cleanups
+
+ * src/totem-interface.c: (totem_interface_boldify_label):
+ * src/totem-interface.h: Add totem_interface_boldify_label()
+
+ * src/totem-uri.c: (totem_dot_dir):
+ * src/totem-uri.h: Add the totem_dot_dir
+
2007-04-03 Tim-Philipp Müller <tim at centricular dot net>
* src/backend/bacon-video-widget-gst-0.10.c:
diff --git a/Makefile.am b/Makefile.am
index ba1bef77b..3109418c4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = po data src help
+SUBDIRS = po data lib src help
if ENABLE_BROWSER_PLUGINS
SUBDIRS += browser-plugin
diff --git a/configure.in b/configure.in
index cf64ee186..c5213b00e 100644
--- a/configure.in
+++ b/configure.in
@@ -23,6 +23,7 @@ IT_PROG_INTLTOOL([0.35.0])
GNOME_DOC_INIT
AC_PROG_CXX
+AM_PROG_CC_C_O
AC_PROG_LIBTOOL()
PKG_PROG_PKG_CONFIG
@@ -61,6 +62,9 @@ AC_SUBST(TOTEM_PL_PARSER_VERSION_MAJOR)
AC_SUBST(TOTEM_PL_PARSER_VERSION_MINOR)
AC_SUBST(TOTEM_PL_PARSER_VERSION_MICRO)
+PLUGINDIR='${libdir}/totem/plugins'
+AC_SUBST(PLUGINDIR)
+
AC_ARG_ENABLE(nvtv, AC_HELP_STRING([--enable-nvtv],[Enable support for TV-output with nvtv]), enable_nvtv="$enableval", enable_nvtv=yes)
if test x$enable_nvtv = xyes; then
@@ -782,7 +786,7 @@ fi
dnl run in source tree
AC_ARG_ENABLE(run-in-source-tree,
- AC_HELP_STRING([--disable-run-in-source-tree],[disable search for UI file in local directory ]),
+ AC_HELP_STRING([--disable-run-in-source-tree],[disable search for UI files and plugins in local directory ]),
[case "${enableval}" in
yes) ENABLE_RUN_IN_SOURCE_TREE=yes ;;
no) ENABLE_RUN_IN_SOURCE_TREE=no ;;
@@ -790,7 +794,7 @@ AC_ARG_ENABLE(run-in-source-tree,
esac],
[ENABLE_RUN_IN_SOURCE_TREE=yes]) dnl Default value
if test x$ENABLE_RUN_IN_SOURCE_TREE = xyes; then
- AC_DEFINE(TOTEM_RUN_IN_SOURCE_TREE, 1, [enable search for UI file in local directory])
+ AC_DEFINE(TOTEM_RUN_IN_SOURCE_TREE, 1, [enable search for UI files and plugins in local directory])
fi
if test "$GCC" = "yes" ; then
@@ -813,7 +817,10 @@ Makefile
totem.spec
totem-plparser.pc
totem-plparser-uninstalled.pc
+lib/Makefile
src/Makefile
+src/plugins/Makefile
+src/plugins/screensaver/Makefile
src/backend/Makefile
src/plparse/Makefile
src/plparse/totem-pl-parser-features.h
diff --git a/data/Makefile.am b/data/Makefile.am
index 63a7decbc..df5662baa 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -11,6 +11,7 @@ stuff_DATA = \
totem.glade \
playlist.glade \
playlist-ui.xml \
+ plugins.glade \
mozilla-viewer.glade \
properties.glade \
skip_to.glade \
diff --git a/data/plugins.glade b/data/plugins.glade
new file mode 100644
index 000000000..5ac628ffe
--- /dev/null
+++ b/data/plugins.glade
@@ -0,0 +1,498 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="edit_plugins">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Rhythmbox Plugins</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="plugins_vbox">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox3">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="plugins_list_window">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="header_hbox">
+ <property name="height_request">64</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="plugin_title">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkImage" id="plugin_icon">
+ <property name="visible">True</property>
+ <property name="stock">gtk-about</property>
+ <property name="icon_size">6</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="description_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Description:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="description_text">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox5">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="authors_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Author:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="authors_text">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox6">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="copyright_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Copyright:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="copyright_text">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox7">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="site_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Site:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="site_text">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <placeholder/>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkButton" id="configure_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-preferences</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">C_onfigure...</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/data/totem-ui.xml b/data/totem-ui.xml
index 70f334b94..a8bf331f2 100644
--- a/data/totem-ui.xml
+++ b/data/totem-ui.xml
@@ -23,6 +23,7 @@
<separator/>
<menuitem name="clear-playlist" action="clear-playlist"/>
<menuitem name="preferences" action="preferences"/>
+ <menuitem name="plugins" action="plugins"/>
</menu>
<menu name="view" action="view-menu">
<menuitem name="fullscreen" action="fullscreen"/>
diff --git a/data/totem.schemas.in b/data/totem.schemas.in
index b65c4d1ee..a01702049 100644
--- a/data/totem.schemas.in
+++ b/data/totem.schemas.in
@@ -236,5 +236,17 @@
</locale>
</schema>
+ <schema>
+ <key>/schemas/apps/disable_user_plugins</key>
+ <applyto>/apps/totem/disable_user_plugins</applyto>
+ <owner>totem</owner>
+ <type>boolean</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Whether to disable the plugins in the user's home directory</short>
+ <long>Whether to disable the plugins in the user's home directory</long>
+ </locale>
+ </schema>
+
</schemalist>
</gconfschemafile>
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 000000000..c67d8c470
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,30 @@
+noinst_LTLIBRARIES = \
+ libtotemscrsaver.la
+
+common_defines = \
+ -D_REENTRANT \
+ -DDBUS_API_SUBJECT_TO_CHANGE \
+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
+ -DGCONF_PREFIX=\""/apps/totem"\" \
+ -DDATADIR=\""$(datadir)"\" \
+ -DLIBEXECDIR=\""$(libexecdir)"\" \
+ -DBINDIR=\""$(bindir)"\" \
+ -DLOGO_PATH=DATADIR\"\"G_DIR_SEPARATOR_S\"totem\"G_DIR_SEPARATOR_S\"totem_logo.png\" \
+ $(DISABLE_DEPRECATED)
+
+libtotemscrsaver_la_SOURCES = \
+ totem-scrsaver.c \
+ totem-scrsaver.h
+libtotemscrsaver_la_CFLAGS = \
+ $(common_defines) \
+ $(EXTRA_GNOME_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(DBUS_CFLAGS) \
+ $(AM_CFLAGS)
+
+libtotemscrsaver_la_LDFLAGS = \
+ $(AM_LDFLAGS)
+libtotemscrsaver_la_LIBADD = \
+ $(DBUS_LIBS) \
+ $(XTEST_LIBS)
+
diff --git a/src/totem-scrsaver.c b/lib/totem-scrsaver.c
index 06d145a1b..06d145a1b 100644
--- a/src/totem-scrsaver.c
+++ b/lib/totem-scrsaver.c
diff --git a/src/totem-scrsaver.h b/lib/totem-scrsaver.h
index 93d469f44..93d469f44 100644
--- a/src/totem-scrsaver.h
+++ b/lib/totem-scrsaver.h
diff --git a/po/ChangeLog b/po/ChangeLog
index bd801fb8e..2f79636bd 100644
--- a/po/ChangeLog
+++ b/po/ChangeLog
@@ -1,3 +1,7 @@
+2007-04-04 Bastien Nocera <hadess@hadess.net>
+
+ * POTFILES.in: update files to translate
+
2007-04-02 Josep Puigdemont i Casamajó <josep.puigdemont@gmail.com>
* ca.po: Updated Catalan translation.
diff --git a/po/POTFILES.in b/po/POTFILES.in
index fd2fbf740..7ff701e4f 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -2,6 +2,7 @@
# Please keep this file sorted alphabetically.
[encoding: UTF-8]
data/playlist.glade
+data/plugins.glade
data/properties.glade
data/screenshot.glade
data/skip_to.glade
@@ -9,9 +10,7 @@ data/totem.desktop.in.in.in
data/totem.glade
data/totem.schemas.in
data/uri.glade
-data/vanity.desktop.in.in
-data/vanity.glade
-src/bacon-v4l-selection.c
+lib/totem-scrsaver.c
src/bacon-video-widget-properties.c
src/bacon-volume.c
src/totem-interface.c
@@ -22,7 +21,6 @@ src/totem-preferences.c
src/totem-properties-main.c
src/totem-properties-view.c
src/totem-screenshot.c
-src/totem-scrsaver.c
src/totem-sidebar.c
src/totem-skipto.c
src/totem-statusbar.c
@@ -30,7 +28,6 @@ src/totem-subtitle-encoding.c
src/totem-time-label.c
src/totem-uri.c
src/totem.c
-src/vanity.c
src/backend/bacon-video-widget-gst-0.10.c
src/backend/bacon-video-widget-xine.c
src/backend/video-utils.c
@@ -39,4 +36,7 @@ src/plparse/totem-pl-parser.c
src/plparse/totem-pl-parser-lines.c
src/plparse/totem-pl-parser-pls.c
src/plparse/totem-pl-parser-xspf.c
+src/plugins/totem-plugin-manager.c
+src/plugins/totem-plugins-engine.c
+src/plugins/screensaver/screensaver.totem-plugin.desktop.in
browser-plugin/totem-plugin-viewer.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 5dba3e6f8..eac740ce0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = backend plparse
+SUBDIRS = plugins backend plparse
bin_PROGRAMS = totem totem-video-thumbnailer totem-video-indexer
libexec_PROGRAMS =
@@ -15,7 +15,7 @@ common_defines = \
-DGCONF_PREFIX=\""/apps/totem"\" \
-DDATADIR=\""$(datadir)"\" \
-DLIBEXECDIR=\""$(libexecdir)"\" \
- -DBINDIR=\""$(bindir)"\" \
+ -DBINDIR=\""$(bindir)"\" \
-DLOGO_PATH=DATADIR\"\"G_DIR_SEPARATOR_S\"totem\"G_DIR_SEPARATOR_S\"totem_logo.png\" \
$(DISABLE_DEPRECATED)
@@ -99,11 +99,10 @@ libtotem_player_la_LDFLAGS = \
totem_SOURCES = \
totem.c totem.h \
+ totem-object.c \
+ totem-private.h \
totem-remote.c totem-remote.h \
totem-preferences.c totem-preferences.h \
- totem-private.h \
- totem-scrsaver.c \
- totem-scrsaver.h \
totem-options.c totem-options.h \
totem-playlist.c totem-playlist.h \
totem-screenshot.c \
@@ -124,6 +123,7 @@ totem_SOURCES = \
totem_CPPFLAGS = \
-I$(srcdir)/plparse \
-I$(srcdir)/backend \
+ -I$(srcdir)/plugins \
-I$(top_builddir)/data \
-I$(top_builddir)/src/plparse \
$(common_defines) \
@@ -144,6 +144,7 @@ totem_LDFLAGS = \
totem_LDADD = \
plparse/libtotem-plparser.la \
backend/libbaconvideowidget.la \
+ plugins/libtotemmodule.la \
libbaconpropertiespage.la \
libbaconmessageconnection.la \
libtotem_player.la \
diff --git a/src/backend/bacon-video-widget-xine.c b/src/backend/bacon-video-widget-xine.c
index 2d09e00e5..10f4ebfcf 100644
--- a/src/backend/bacon-video-widget-xine.c
+++ b/src/backend/bacon-video-widget-xine.c
@@ -272,7 +272,7 @@ static void bacon_video_widget_reconfigure_tick (BaconVideoWidget *bvw, gboolean
static void bacon_video_widget_set_visuals_quality_size (BaconVideoWidget *bvw,
int h, int w, int fps);
-static GtkWidgetClass *parent_class = NULL;
+static GObjectClass *parent_class = NULL;
static void xine_event (void *user_data, const xine_event_t *event);
static gboolean bacon_video_widget_idle_signal (BaconVideoWidget *bvw);
@@ -285,14 +285,13 @@ G_DEFINE_TYPE(BaconVideoWidget, bacon_video_widget, GTK_TYPE_BOX)
static void
bacon_video_widget_class_init (BaconVideoWidgetClass *klass)
{
-
GObjectClass *object_class;
GtkWidgetClass *widget_class;
object_class = (GObjectClass *) klass;
widget_class = (GtkWidgetClass *) klass;
- parent_class = gtk_type_class (gtk_box_get_type ());
+ parent_class = g_type_class_peek_parent (klass);
/* GtkWidget */
widget_class->realize = bacon_video_widget_realize;
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
new file mode 100644
index 000000000..7c8ee5dcc
--- /dev/null
+++ b/src/plugins/Makefile.am
@@ -0,0 +1,41 @@
+SUBDIRS = screensaver
+
+noinst_LTLIBRARIES = libtotemmodule.la
+
+common_defines = \
+ -D_REENTRANT \
+ -DDBUS_API_SUBJECT_TO_CHANGE \
+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
+ -DGCONF_PREFIX=\""/apps/totem"\" \
+ -DDATADIR=\""$(datadir)"\" \
+ -DLIBEXECDIR=\""$(libexecdir)"\" \
+ -DBINDIR=\""$(bindir)"\" \
+ -DTOTEM_PLUGIN_DIR=\""$(libdir)/totem/plugins"\"\
+ $(DISABLE_DEPRECATED)
+
+modules_flags = -export_dynamic -avoid-version -module
+
+libtotemmodule_la_SOURCES = \
+ totem-module.c \
+ totem-module.h \
+ totem-plugin.c \
+ totem-plugin.h \
+ totem-plugins-engine.c \
+ totem-plugins-engine.h \
+ totem-plugin-manager.c \
+ totem-plugin-manager.h
+
+libtotemmodule_la_CPPFLAGS = \
+ $(common_defines) \
+ $(AM_CPPFLAGS)
+
+libtotemmodule_la_CFLAGS = \
+ $(EXTRA_GNOME_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(DBUS_CFLAGS) \
+ $(AM_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libtotemmodule_la_LDFLAGS = \
+ $(AM_LDFLAGS)
+
diff --git a/src/plugins/screensaver/Makefile.am b/src/plugins/screensaver/Makefile.am
new file mode 100644
index 000000000..580d376c4
--- /dev/null
+++ b/src/plugins/screensaver/Makefile.am
@@ -0,0 +1,41 @@
+modules_flags = -export_dynamic -avoid-version -module
+
+plugindir = $(PLUGINDIR)/screensaver
+plugin_LTLIBRARIES = libscreensaver.la
+
+plugin_in_files = screensaver.totem-plugin.desktop.in
+
+%.totem-plugin: %.totem-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache
+
+plugin_DATA = $(plugin_in_files:.totem-plugin.desktop.in=.totem-plugin)
+
+common_defines = \
+ -D_REENTRANT \
+ -DDBUS_API_SUBJECT_TO_CHANGE \
+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
+ -DGCONF_PREFIX=\""/apps/totem"\" \
+ -DDATADIR=\""$(datadir)"\" \
+ -DLIBEXECDIR=\""$(libexecdir)"\" \
+ -DBINDIR=\""$(bindir)"\" \
+ -DTOTEM_PLUGIN_DIR=\""$(libdir)/totem/plugins"\"\
+ $(DISABLE_DEPRECATED)
+
+libscreensaver_la_SOURCES = totem-screensaver.c
+libscreensaver_la_LDFLAGS = $(modules_flags)
+libscreensaver_la_LIBADD = $(top_builddir)/lib/libtotemscrsaver.la
+libscreensaver_la_CPPFLAGS = $(common_defines)
+
+libscreensaver_la_CFLAGS = \
+ $(EXTRA_GNOME_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(DBUS_CFLAGS) \
+ $(AM_CFLAGS) \
+ -I$(top_srcdir)/lib \
+ -I$(top_srcdir)/src \
+ -I$(top_srcdir)/src/plugins
+
+EXTRA_DIST = $(plugin_in_files)
+
+CLEANFILES = $(plugin_DATA) $(BUILT_SOURCES)
+DISTCLEANFILES = $(plugin_DATA)
+
diff --git a/src/plugins/screensaver/screensaver.totem-plugin.desktop.in b/src/plugins/screensaver/screensaver.totem-plugin.desktop.in
new file mode 100644
index 000000000..9a17db565
--- /dev/null
+++ b/src/plugins/screensaver/screensaver.totem-plugin.desktop.in
@@ -0,0 +1,9 @@
+[Totem Plugin]
+Module=screensaver
+IAge=1
+Builtin=true
+_Name=Screensaver
+_Description=Deactivates the screensaver when a movie is playing
+Authors=Bastien Nocera
+Copyright=Copyright © 2007 Bastien Nocera
+Website=http://www.gnome.org/projects/totem/
diff --git a/src/plugins/screensaver/totem-screensaver.c b/src/plugins/screensaver/totem-screensaver.c
new file mode 100644
index 000000000..0d179c8bd
--- /dev/null
+++ b/src/plugins/screensaver/totem-screensaver.c
@@ -0,0 +1,140 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Totem project hereby grant permission for non-gpl compatible GStreamer
+ * plugins to be used and distributed together with GStreamer and Totem. This
+ * permission are above and beyond the permissions granted by the GPL license
+ * Totem is covered by.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add excemption clause.
+ * See license_change file for details.
+ *
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+#include <string.h>
+
+#include "totem-plugin.h"
+#include "totem.h"
+#include "totem-scrsaver.h"
+
+#define TOTEM_TYPE_SCREENSAVER_PLUGIN (totem_screensaver_plugin_get_type ())
+#define TOTEM_SCREENSAVER_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TOTEM_TYPE_SCREENSAVER_PLUGIN, TotemScreensaverPlugin))
+#define TOTEM_SCREENSAVER_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TOTEM_TYPE_SCREENSAVER_PLUGIN, TotemScreensaverPluginClass))
+#define TOTEM_IS_SCREENSAVER_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TOTEM_TYPE_SCREENSAVER_PLUGIN))
+#define TOTEM_IS_SCREENSAVER_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TOTEM_TYPE_SCREENSAVER_PLUGIN))
+#define TOTEM_SCREENSAVER_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TOTEM_TYPE_SCREENSAVER_PLUGIN, TotemScreensaverPluginClass))
+
+typedef struct
+{
+ TotemPlugin parent;
+
+ TotemObject *totem;
+ TotemScrsaver *scr;
+ guint handler_id;
+} TotemScreensaverPlugin;
+
+typedef struct
+{
+ TotemPluginClass parent_class;
+} TotemScreensaverPluginClass;
+
+
+G_MODULE_EXPORT GType register_totem_plugin (GTypeModule *module);
+GType totem_screensaver_plugin_get_type (void) G_GNUC_CONST;
+
+static void totem_screensaver_plugin_init (TotemScreensaverPlugin *plugin);
+static void totem_screensaver_plugin_finalize (GObject *object);
+static void impl_activate (TotemPlugin *plugin, TotemObject *totem);
+static void impl_deactivate (TotemPlugin *plugin, TotemObject *totem);
+
+TOTEM_PLUGIN_REGISTER(TotemScreensaverPlugin, totem_screensaver_plugin)
+
+static void
+totem_screensaver_plugin_class_init (TotemScreensaverPluginClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ TotemPluginClass *plugin_class = TOTEM_PLUGIN_CLASS (klass);
+
+ object_class->finalize = totem_screensaver_plugin_finalize;
+
+ plugin_class->activate = impl_activate;
+ plugin_class->deactivate = impl_deactivate;
+}
+
+static void
+totem_screensaver_plugin_init (TotemScreensaverPlugin *plugin)
+{
+ plugin->scr = totem_scrsaver_new ();
+}
+
+static void
+totem_screensaver_plugin_finalize (GObject *object)
+{
+ TotemScreensaverPlugin *plugin = TOTEM_SCREENSAVER_PLUGIN (object);
+
+ g_object_unref (plugin->scr);
+
+ G_OBJECT_CLASS (totem_screensaver_plugin_parent_class)->finalize (object);
+}
+
+static void
+property_notify_cb (TotemObject *totem,
+ GParamSpec *spec,
+ TotemScreensaverPlugin *pi)
+{
+ if (strcmp ("fullscreen", spec->name) != 0
+ && strcmp ("playing", spec->name) != 0) {
+ return;
+ }
+
+ if (totem_is_playing (totem) != FALSE
+ && totem_is_fullscreen (totem) != FALSE) {
+ totem_scrsaver_disable (pi->scr);
+ } else {
+ totem_scrsaver_enable (pi->scr);
+ }
+}
+
+static void
+impl_activate (TotemPlugin *plugin,
+ TotemObject *totem)
+{
+ TotemScreensaverPlugin *pi = TOTEM_SCREENSAVER_PLUGIN (plugin);
+
+ pi->handler_id = g_signal_connect (G_OBJECT (totem),
+ "notify",
+ G_CALLBACK (property_notify_cb),
+ pi);
+}
+
+static void
+impl_deactivate (TotemPlugin *plugin,
+ TotemObject *totem)
+{
+ TotemScreensaverPlugin *pi = TOTEM_SCREENSAVER_PLUGIN (plugin);
+
+ g_signal_handler_disconnect (G_OBJECT (totem), pi->handler_id);
+ totem_scrsaver_enable (pi->scr);
+}
+
diff --git a/src/plugins/totem-module.c b/src/plugins/totem-module.c
new file mode 100644
index 000000000..0fd000b5d
--- /dev/null
+++ b/src/plugins/totem-module.c
@@ -0,0 +1,175 @@
+/*
+ * This is a based on rb-module.c from Rhythmbox, which is based on
+ * gedit-module.h from gedit, which is based on Epiphany source code.
+ *
+ * Copyright (C) 2003 Marco Pesenti Gritti
+ * Copyright (C) 2003, 2004 Christian Persch
+ * Copyright (C) 2005 - Paolo Maggi
+ * Copyright (C) 2007 - 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add excemption clause.
+ * See license_change file for details.
+ *
+ */
+
+#include "config.h"
+
+#include "totem-module.h"
+
+#include <gmodule.h>
+
+typedef struct _TotemModuleClass TotemModuleClass;
+
+struct _TotemModuleClass
+{
+ GTypeModuleClass parent_class;
+};
+
+struct _TotemModule
+{
+ GTypeModule parent_instance;
+
+ GModule *library;
+
+ gchar *path;
+ gchar *name;
+ GType type;
+};
+
+typedef GType (*TotemModuleRegisterFunc) (GTypeModule *);
+
+static void totem_module_init (TotemModule *action);
+static void totem_module_class_init (TotemModuleClass *class);
+
+static GObjectClass *parent_class = NULL;
+
+G_DEFINE_TYPE (TotemModule, totem_module, G_TYPE_TYPE_MODULE)
+
+static gboolean
+totem_module_load (GTypeModule *gmodule)
+{
+ TotemModule *module = TOTEM_MODULE (gmodule);
+ TotemModuleRegisterFunc register_func;
+
+ module->library = g_module_open (module->path, 0);
+
+ if (module->library == NULL) {
+ g_warning (g_module_error());
+
+ return FALSE;
+ }
+
+ /* extract symbols from the lib */
+ if (!g_module_symbol (module->library, "register_totem_plugin", (void *)&register_func)) {
+ g_warning (g_module_error ());
+ g_module_close (module->library);
+ return FALSE;
+ }
+
+ g_assert (register_func);
+
+ module->type = register_func (gmodule);
+ if (module->type == 0) {
+ g_warning ("Invalid totem plugin contained by module %s", module->path);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+totem_module_unload (GTypeModule *gmodule)
+{
+ TotemModule *module = TOTEM_MODULE (gmodule);
+
+ g_module_close (module->library);
+
+ module->library = NULL;
+ module->type = 0;
+}
+
+const gchar *
+totem_module_get_path (TotemModule *module)
+{
+ g_return_val_if_fail (TOTEM_IS_MODULE (module), NULL);
+
+ return module->path;
+}
+
+GObject *
+totem_module_new_object (TotemModule *module)
+{
+ GObject *obj;
+
+ if (module->type == 0) {
+ return NULL;
+ }
+
+ obj = g_object_new (module->type,
+ "name", module->name,
+ NULL);
+ return obj;
+}
+
+static void
+totem_module_init (TotemModule *module)
+{
+
+}
+
+static void
+totem_module_finalize (GObject *object)
+{
+ TotemModule *module = TOTEM_MODULE (object);
+
+ g_free (module->path);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+totem_module_class_init (TotemModuleClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
+
+ parent_class = (GObjectClass *) g_type_class_peek_parent (class);
+
+ object_class->finalize = totem_module_finalize;
+
+ module_class->load = totem_module_load;
+ module_class->unload = totem_module_unload;
+}
+
+TotemModule *
+totem_module_new (const gchar *path, const char *module)
+{
+ TotemModule *result;
+
+ if (path == NULL || path[0] == '\0') {
+ return NULL;
+ }
+
+ result = g_object_new (TOTEM_TYPE_MODULE, NULL);
+
+ g_type_module_set_name (G_TYPE_MODULE (result), path);
+ result->path = g_strdup (path);
+ result->name = g_strdup (module);
+
+ return result;
+}
diff --git a/src/plugins/totem-module.h b/src/plugins/totem-module.h
new file mode 100644
index 000000000..f6f47ed46
--- /dev/null
+++ b/src/plugins/totem-module.h
@@ -0,0 +1,56 @@
+/*
+ * This is a based on rb-module.h from Rhythmbox, which is based on
+ * gedit-module.h from gedit, which is based on Epiphany source code.
+ *
+ * Copyright (C) 2003 Marco Pesenti Gritti
+ * Copyright (C) 2003, 2004 Christian Persch
+ * Copyright (C) 2005 - Paolo Maggi
+ * Copyright (C) 2007 - 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add excemption clause.
+ * See license_change file for details.
+ *
+ */
+
+#ifndef TOTEM_MODULE_H
+#define TOTEM_MODULE_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define TOTEM_TYPE_MODULE (totem_module_get_type ())
+#define TOTEM_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TOTEM_TYPE_MODULE, TotemModule))
+#define TOTEM_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TOTEM_TYPE_MODULE, TotemModuleClass))
+#define TOTEM_IS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TOTEM_TYPE_MODULE))
+#define TOTEM_IS_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), TOTEM_TYPE_MODULE))
+#define TOTEM_MODULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TOTEM_TYPE_MODULE, TotemModuleClass))
+
+typedef struct _TotemModule TotemModule;
+
+GType totem_module_get_type (void) G_GNUC_CONST;;
+
+TotemModule *totem_module_new (const gchar *path, const char *module);
+
+const gchar *totem_module_get_path (TotemModule *module);
+
+GObject *totem_module_new_object (TotemModule *module);
+
+G_END_DECLS
+
+#endif
diff --git a/src/plugins/totem-plugin-manager.c b/src/plugins/totem-plugin-manager.c
new file mode 100644
index 000000000..435ab630a
--- /dev/null
+++ b/src/plugins/totem-plugin-manager.c
@@ -0,0 +1,544 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * heavily based on code from Rhythmbox and Gedit
+ *
+ * Copyright (C) 2002 Paolo Maggi and James Willcox
+ * Copyright (C) 2003-2005 Paolo Maggi
+ * Copyright (C) 2007 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add excemption clause.
+ * See license_change file for details.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <glade/glade-xml.h>
+
+#include "totem-interface.h"
+#include "totem-plugin-manager.h"
+#include "totem-plugins-engine.h"
+#include "totem-plugin.h"
+
+enum
+{
+ ACTIVE_COLUMN,
+ VISIBLE_COLUMN,
+ INFO_COLUMN,
+ N_COLUMNS
+};
+
+#define PLUGIN_MANAGER_NAME_TITLE _("Plugin")
+#define PLUGIN_MANAGER_ACTIVE_TITLE _("Enabled")
+
+#define TOTEM_PLUGIN_MANAGER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), TOTEM_TYPE_PLUGIN_MANAGER, TotemPluginManagerPrivate))
+
+struct _TotemPluginManagerPrivate
+{
+ GList *plugins;
+ GtkWidget *tree;
+ GtkTreeModel *plugin_model;
+
+ GtkWidget *configure_button;
+ GtkWidget *site_label;
+ GtkWidget *copyright_label;
+ GtkWidget *authors_label;
+ GtkWidget *description_label;
+ GtkWidget *header_hbox;
+ GtkWidget *plugin_icon;
+ GtkWidget *site_text;
+ GtkWidget *copyright_text;
+ GtkWidget *authors_text;
+ GtkWidget *description_text;
+ GtkWidget *plugin_title;
+};
+
+G_DEFINE_TYPE(TotemPluginManager, totem_plugin_manager, GTK_TYPE_VBOX)
+
+static void totem_plugin_manager_finalize (GObject *o);
+static TotemPluginInfo *plugin_manager_get_selected_plugin (TotemPluginManager *pm);
+static void plugin_manager_toggle_active (GtkTreeIter *iter, GtkTreeModel *model, TotemPluginManager *pm);
+static void plugin_manager_toggle_all (TotemPluginManager *pm);
+
+static void
+totem_plugin_manager_class_init (TotemPluginManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = totem_plugin_manager_finalize;
+
+ g_type_class_add_private (object_class, sizeof (TotemPluginManagerPrivate));
+}
+
+static void
+configure_button_cb (GtkWidget *button,
+ TotemPluginManager *pm)
+{
+ TotemPluginInfo *info;
+ GtkWindow *toplevel;
+
+ info = plugin_manager_get_selected_plugin (pm);
+
+ g_return_if_fail (info != NULL);
+
+ toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (pm)));
+
+ totem_plugins_engine_configure_plugin (info, toplevel);
+}
+
+static void
+plugin_manager_view_cell_cb (GtkTreeViewColumn *tree_column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ TotemPluginInfo *info;
+
+ g_return_if_fail (tree_model != NULL);
+ g_return_if_fail (tree_column != NULL);
+
+ gtk_tree_model_get (tree_model, iter, INFO_COLUMN, &info, -1);
+
+ if (info == NULL)
+ return;
+
+ g_return_if_fail (totem_plugins_engine_get_plugin_name (info) != NULL);
+
+ g_object_set (G_OBJECT (cell),
+ "text",
+ totem_plugins_engine_get_plugin_name (info),
+ NULL);
+}
+
+static void
+active_toggled_cb (GtkCellRendererToggle *cell,
+ gchar *path_str,
+ TotemPluginManager *pm)
+{
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ GtkTreeModel *model;
+
+ path = gtk_tree_path_new_from_string (path_str);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
+ g_return_if_fail (model != NULL);
+
+ if (gtk_tree_model_get_iter (model, &iter, path))
+ plugin_manager_toggle_active (&iter, model, pm);
+
+ gtk_tree_path_free (path);
+}
+
+static void
+cursor_changed_cb (GtkTreeSelection *selection,
+ gpointer data)
+{
+ TotemPluginManager *pm = data;
+ GtkTreeView *view;
+ TotemPluginInfo *info;
+ char *string;
+ GdkPixbuf *icon;
+
+ view = gtk_tree_selection_get_tree_view (selection);
+ info = plugin_manager_get_selected_plugin (pm);
+
+ /* update info widgets */
+ string = g_strdup_printf ("<span size=\"x-large\">%s</span>",
+ totem_plugins_engine_get_plugin_name (info));
+ gtk_label_set_markup (GTK_LABEL (pm->priv->plugin_title), string);
+ g_free (string);
+ gtk_label_set_text (GTK_LABEL (pm->priv->description_text),
+ totem_plugins_engine_get_plugin_description (info));
+ gtk_label_set_text (GTK_LABEL (pm->priv->copyright_text),
+ totem_plugins_engine_get_plugin_copyright (info));
+ gtk_label_set_text (GTK_LABEL (pm->priv->site_text),
+ totem_plugins_engine_get_plugin_website (info));
+
+ string = g_strjoinv ("\n", (gchar**)totem_plugins_engine_get_plugin_authors (info));
+ gtk_label_set_text (GTK_LABEL (pm->priv->authors_text), string);
+ g_free (string);
+
+ icon = totem_plugins_engine_get_plugin_icon (info);
+ if (icon != NULL) {
+ /* rescale icon to fit header if needed */
+ GdkPixbuf *icon_scaled;
+ gint width, height, header_height;
+
+ width = gdk_pixbuf_get_width (icon);
+ height = gdk_pixbuf_get_height (icon);
+ header_height = pm->priv->header_hbox->allocation.height;
+ if (height > header_height) {
+ icon_scaled = gdk_pixbuf_scale_simple (icon,
+ (gfloat)width/height*header_height, header_height,
+ GDK_INTERP_BILINEAR);
+ gtk_image_set_from_pixbuf (GTK_IMAGE (pm->priv->plugin_icon), icon_scaled);
+ g_object_unref (G_OBJECT (icon_scaled));
+ } else {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (pm->priv->plugin_icon), icon);
+ }
+ } else {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (pm->priv->plugin_icon), NULL);
+ }
+
+ gtk_widget_set_sensitive (GTK_WIDGET (pm->priv->configure_button),
+ (info != NULL) &&
+ totem_plugins_engine_plugin_is_configurable (info));
+}
+
+static void
+row_activated_cb (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ gpointer data)
+{
+ TotemPluginManager *pm = data;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ gboolean found;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
+ g_return_if_fail (model != NULL);
+
+ found = gtk_tree_model_get_iter (model, &iter, path);
+ g_return_if_fail (found);
+
+ plugin_manager_toggle_active (&iter, model, pm);
+}
+
+static void
+column_clicked_cb (GtkTreeViewColumn *tree_column,
+ gpointer data)
+{
+ TotemPluginManager *pm = TOTEM_PLUGIN_MANAGER (data);
+
+ plugin_manager_toggle_all (pm);
+}
+
+static void
+plugin_manager_populate_lists (TotemPluginManager *pm)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GList *p;
+
+ for (p = pm->priv->plugins; p != NULL; p = g_list_next (p)) {
+ TotemPluginInfo *info;
+ info = (TotemPluginInfo *)p->data;
+
+ gtk_list_store_append (GTK_LIST_STORE (pm->priv->plugin_model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (pm->priv->plugin_model), &iter,
+ ACTIVE_COLUMN, totem_plugins_engine_plugin_is_active (info),
+ VISIBLE_COLUMN, totem_plugins_engine_plugin_is_visible (info),
+ INFO_COLUMN, info,
+ -1);
+ }
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter)) {
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
+ g_return_if_fail (selection != NULL);
+
+ gtk_tree_selection_select_iter (selection, &iter);
+ }
+}
+
+static void
+plugin_manager_set_active (GtkTreeIter *iter,
+ GtkTreeModel *model,
+ gboolean active,
+ TotemPluginManager *pm)
+{
+ TotemPluginInfo *info;
+ GtkTreeIter child_iter;
+
+ gtk_tree_model_get (model, iter, INFO_COLUMN, &info, -1);
+
+ g_return_if_fail (info != NULL);
+
+ if (active) {
+ /* activate the plugin */
+ if (!totem_plugins_engine_activate_plugin (info)) {
+ active ^= 1;
+ }
+ } else {
+ /* deactivate the plugin */
+ if (!totem_plugins_engine_deactivate_plugin (info)) {
+ active ^= 1;
+ }
+ }
+
+ /* set new value */
+ gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model),
+ &child_iter, iter);
+ gtk_list_store_set (GTK_LIST_STORE (pm->priv->plugin_model),
+ &child_iter,
+ ACTIVE_COLUMN,
+ totem_plugins_engine_plugin_is_active (info),
+ -1);
+
+ /* cause the configure button sensitivity to be updated */
+ cursor_changed_cb (gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree)), pm);
+}
+
+static void
+plugin_manager_toggle_active (GtkTreeIter *iter,
+ GtkTreeModel *model,
+ TotemPluginManager *pm)
+{
+ gboolean active, visible;
+
+ gtk_tree_model_get (model, iter,
+ ACTIVE_COLUMN, &active,
+ VISIBLE_COLUMN, &visible,
+ -1);
+
+ if (visible) {
+ active ^= 1;
+ plugin_manager_set_active (iter, model, active, pm);
+ }
+}
+
+static TotemPluginInfo *
+plugin_manager_get_selected_plugin (TotemPluginManager *pm)
+{
+ TotemPluginInfo *info = NULL;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
+ g_return_val_if_fail (model != NULL, NULL);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
+ g_return_val_if_fail (selection != NULL, NULL);
+
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
+ gtk_tree_model_get (model, &iter, INFO_COLUMN, &info, -1);
+ }
+
+ return info;
+}
+
+static void
+plugin_manager_toggle_all (TotemPluginManager *pm)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ static gboolean active;
+
+ active ^= 1;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
+
+ g_return_if_fail (model != NULL);
+
+ if (gtk_tree_model_get_iter_first (model, &iter)) {
+ do {
+ plugin_manager_set_active (&iter, model, active, pm);
+ } while (gtk_tree_model_iter_next (model, &iter));
+ }
+}
+
+/* Callback used as the interactive search comparison function */
+static gboolean
+name_search_cb (GtkTreeModel *model,
+ gint column,
+ const gchar *key,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ TotemPluginInfo *info;
+ gchar *normalized_string;
+ gchar *normalized_key;
+ gchar *case_normalized_string;
+ gchar *case_normalized_key;
+ gint key_len;
+ gboolean retval;
+
+ gtk_tree_model_get (model, iter, INFO_COLUMN, &info, -1);
+ if (!info)
+ return FALSE;
+
+ normalized_string = g_utf8_normalize (totem_plugins_engine_get_plugin_name (info), -1, G_NORMALIZE_ALL);
+ normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
+ case_normalized_string = g_utf8_casefold (normalized_string, -1);
+ case_normalized_key = g_utf8_casefold (normalized_key, -1);
+
+ key_len = strlen (case_normalized_key);
+
+ /* Oddly enough, this callback must return whether to stop the search
+ * because we found a match, not whether we actually matched.
+ */
+ retval = (strncmp (case_normalized_key, case_normalized_string, key_len) != 0);
+
+ g_free (normalized_key);
+ g_free (normalized_string);
+ g_free (case_normalized_key);
+ g_free (case_normalized_string);
+
+ return retval;
+}
+
+static void
+plugin_manager_construct_tree (TotemPluginManager *pm)
+{
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *cell;
+ GtkTreeModel *filter;
+
+ pm->priv->plugin_model = GTK_TREE_MODEL (gtk_list_store_new (N_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_POINTER));
+ filter = gtk_tree_model_filter_new (pm->priv->plugin_model, NULL);
+ gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter), VISIBLE_COLUMN);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (pm->priv->tree), filter);
+ g_object_unref (filter);
+
+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (pm->priv->tree), TRUE);
+ gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW (pm->priv->tree), TRUE);
+
+ /* first column */
+ cell = gtk_cell_renderer_toggle_new ();
+ g_signal_connect (cell,
+ "toggled",
+ G_CALLBACK (active_toggled_cb),
+ pm);
+ column = gtk_tree_view_column_new_with_attributes (PLUGIN_MANAGER_ACTIVE_TITLE,
+ cell,
+ "active",
+ ACTIVE_COLUMN,
+ NULL);
+ gtk_tree_view_column_set_clickable (column, TRUE);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ g_signal_connect (column, "clicked", G_CALLBACK (column_clicked_cb), pm);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (pm->priv->tree), column);
+
+ /* second column */
+ cell = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (PLUGIN_MANAGER_NAME_TITLE, cell, NULL);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_cell_data_func (column, cell, plugin_manager_view_cell_cb,
+ pm, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (pm->priv->tree), column);
+
+ /* Enable search for our non-string column */
+ gtk_tree_view_set_search_column (GTK_TREE_VIEW (pm->priv->tree), INFO_COLUMN);
+ gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (pm->priv->tree),
+ name_search_cb,
+ NULL,
+ NULL);
+
+ g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree)),
+ "changed",
+ G_CALLBACK (cursor_changed_cb),
+ pm);
+ g_signal_connect (pm->priv->tree,
+ "row_activated",
+ G_CALLBACK (row_activated_cb),
+ pm);
+
+ gtk_widget_show (pm->priv->tree);
+}
+
+static int
+plugin_name_cmp (gconstpointer a, gconstpointer b)
+{
+ TotemPluginInfo *lhs = (TotemPluginInfo*)a;
+ TotemPluginInfo *rhs = (TotemPluginInfo*)b;
+ return strcmp (totem_plugins_engine_get_plugin_name (lhs),
+ totem_plugins_engine_get_plugin_name (rhs));
+}
+
+static void
+totem_plugin_manager_init (TotemPluginManager *pm)
+{
+ GladeXML *xml;
+ GtkWidget *plugins_window;
+
+ pm->priv = TOTEM_PLUGIN_MANAGER_GET_PRIVATE (pm);
+
+ xml = totem_interface_load_with_root ("plugins.glade",
+ "plugins_vbox",
+ _("Plugins Manager"),
+ TRUE,
+ NULL);
+
+ gtk_container_add (GTK_CONTAINER (pm), glade_xml_get_widget (xml, "plugins_vbox"));
+
+ gtk_box_set_spacing (GTK_BOX (pm), 6);
+
+ pm->priv->tree = gtk_tree_view_new ();
+ plugins_window = glade_xml_get_widget (xml, "plugins_list_window");
+ gtk_container_add (GTK_CONTAINER (plugins_window), pm->priv->tree);
+
+ pm->priv->configure_button = glade_xml_get_widget (xml, "configure_button");
+ g_signal_connect (pm->priv->configure_button,
+ "clicked",
+ G_CALLBACK (configure_button_cb),
+ pm);
+
+ pm->priv->header_hbox = glade_xml_get_widget (xml, "header_hbox");
+
+ pm->priv->plugin_title = glade_xml_get_widget (xml, "plugin_title");
+
+ pm->priv->site_label = glade_xml_get_widget (xml, "site_label");
+ totem_interface_boldify_label (xml, "site_label");
+ pm->priv->copyright_label = glade_xml_get_widget (xml, "copyright_label");
+ totem_interface_boldify_label (xml, "copyright_label");
+ pm->priv->authors_label = glade_xml_get_widget (xml, "authors_label");
+ totem_interface_boldify_label (xml, "authors_label");
+ pm->priv->description_label = glade_xml_get_widget (xml, "description_label");
+ totem_interface_boldify_label (xml, "description_label");
+
+ pm->priv->plugin_icon = glade_xml_get_widget (xml, "plugin_icon");
+ pm->priv->site_text = glade_xml_get_widget (xml, "site_text");
+ pm->priv->copyright_text = glade_xml_get_widget (xml, "copyright_text");
+ pm->priv->authors_text = glade_xml_get_widget (xml, "authors_text");
+ pm->priv->description_text = glade_xml_get_widget (xml, "description_text");
+
+ plugin_manager_construct_tree (pm);
+
+ /* get the list of available plugins (or installed) */
+ pm->priv->plugins = totem_plugins_engine_get_plugins_list ();
+ pm->priv->plugins = g_list_sort (pm->priv->plugins, plugin_name_cmp);
+ plugin_manager_populate_lists (pm);
+ g_object_unref (xml);
+}
+
+GtkWidget *
+totem_plugin_manager_new (void)
+{
+ return g_object_new (TOTEM_TYPE_PLUGIN_MANAGER, 0);
+}
+
+static void
+totem_plugin_manager_finalize (GObject *o)
+{
+ TotemPluginManager *pm = TOTEM_PLUGIN_MANAGER (o);
+
+ g_list_free (pm->priv->plugins);
+
+ G_OBJECT_CLASS(totem_plugin_manager_parent_class)->finalize (o);
+}
diff --git a/src/plugins/totem-plugin-manager.h b/src/plugins/totem-plugin-manager.h
new file mode 100644
index 000000000..42463fb45
--- /dev/null
+++ b/src/plugins/totem-plugin-manager.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * heavily based on code from Rhythmbox and Gedit
+ *
+ * Copyright (C) 2002 Paolo Maggi and James Willcox
+ * Copyright (C) 2003-2005 Paolo Maggi
+ * Copyright (C) 2007 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add excemption clause.
+ * See license_change file for details.
+ *
+ */
+
+#ifndef __TOTEM_PLUGIN_MANAGER_H__
+#define __TOTEM_PLUGIN_MANAGER_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+/*
+ * Type checking and casting macros
+ */
+#define TOTEM_TYPE_PLUGIN_MANAGER (totem_plugin_manager_get_type())
+#define TOTEM_PLUGIN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TOTEM_TYPE_PLUGIN_MANAGER, TotemPluginManager))
+#define TOTEM_PLUGIN_MANAGER_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TOTEM_TYPE_PLUGIN_MANAGER, TotemPluginManager const))
+#define TOTEM_PLUGIN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TOTEM_TYPE_PLUGIN_MANAGER, TotemPluginManagerClass))
+#define TOTEM_IS_PLUGIN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TOTEM_TYPE_PLUGIN_MANAGER))
+#define TOTEM_IS_PLUGIN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TOTEM_TYPE_PLUGIN_MANAGER))
+#define TOTEM_PLUGIN_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TOTEM_TYPE_PLUGIN_MANAGER, TotemPluginManagerClass))
+
+/* Private structure type */
+typedef struct _TotemPluginManagerPrivate TotemPluginManagerPrivate;
+
+/*
+ * Main object structure
+ */
+typedef struct
+{
+ GtkVBox vbox;
+
+ /*< private > */
+ TotemPluginManagerPrivate *priv;
+} TotemPluginManager;
+
+/*
+ * Class definition
+ */
+typedef struct
+{
+ GtkVBoxClass parent_class;
+} TotemPluginManagerClass;
+
+/*
+ * Public methods
+ */
+GType totem_plugin_manager_get_type (void) G_GNUC_CONST;
+
+GtkWidget *totem_plugin_manager_new (void);
+
+G_END_DECLS
+
+#endif /* __TOTEM_PLUGIN_MANAGER_H__ */
diff --git a/src/plugins/totem-plugin.c b/src/plugins/totem-plugin.c
new file mode 100644
index 000000000..63644c3b8
--- /dev/null
+++ b/src/plugins/totem-plugin.c
@@ -0,0 +1,263 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * heavily based on code from Rhythmbox and Gedit
+ *
+ * Copyright (C) 2002-2005 Paolo Maggi
+ * Copyright (C) 2007 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add excemption clause.
+ * See license_change file for details.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <gconf/gconf-client.h>
+
+#include "totem-plugin.h"
+#include "totem-uri.h"
+#include "totem-interface.h"
+
+G_DEFINE_TYPE (TotemPlugin, totem_plugin, G_TYPE_OBJECT)
+
+#define TOTEM_PLUGIN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TOTEM_TYPE_PLUGIN, TotemPluginPrivate))
+
+static void totem_plugin_finalise (GObject *o);
+static void totem_plugin_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void totem_plugin_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+typedef struct {
+ char *name;
+} TotemPluginPrivate;
+
+enum
+{
+ PROP_0,
+ PROP_NAME,
+};
+
+static gboolean
+is_configurable (TotemPlugin *plugin)
+{
+ return (TOTEM_PLUGIN_GET_CLASS (plugin)->create_configure_dialog != NULL);
+}
+
+static void
+totem_plugin_class_init (TotemPluginClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = totem_plugin_finalise;
+ object_class->get_property = totem_plugin_get_property;
+ object_class->set_property = totem_plugin_set_property;
+
+ klass->activate = NULL;
+ klass->deactivate = NULL;
+ klass->create_configure_dialog = NULL;
+ klass->is_configurable = is_configurable;
+
+ /* this should be a construction property, but due to the python plugin hack can't be */
+ g_object_class_install_property (object_class,
+ PROP_NAME,
+ g_param_spec_string ("name",
+ "name",
+ "name",
+ NULL,
+ G_PARAM_READWRITE /*| G_PARAM_CONSTRUCT_ONLY*/));
+
+ g_type_class_add_private (klass, sizeof (TotemPluginPrivate));
+}
+
+static void
+totem_plugin_init (TotemPlugin *plugin)
+{
+ /* Empty */
+}
+
+static void
+totem_plugin_finalise (GObject *object)
+{
+ TotemPluginPrivate *priv = TOTEM_PLUGIN_GET_PRIVATE (object);
+
+ g_free (priv->name);
+
+ G_OBJECT_CLASS (totem_plugin_parent_class)->finalize (object);
+}
+
+static void
+totem_plugin_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TotemPluginPrivate *priv = TOTEM_PLUGIN_GET_PRIVATE (object);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ g_free (priv->name);
+ priv->name = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+totem_plugin_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TotemPluginPrivate *priv = TOTEM_PLUGIN_GET_PRIVATE (object);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ g_value_set_string (value, priv->name);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+void
+totem_plugin_activate (TotemPlugin *plugin,
+ TotemObject *totem)
+{
+ g_return_if_fail (TOTEM_IS_PLUGIN (plugin));
+ g_return_if_fail (TOTEM_IS_OBJECT (totem));
+
+ if (TOTEM_PLUGIN_GET_CLASS (plugin)->activate)
+ TOTEM_PLUGIN_GET_CLASS (plugin)->activate (plugin, totem);
+}
+
+void
+totem_plugin_deactivate (TotemPlugin *plugin,
+ TotemObject *totem)
+{
+ g_return_if_fail (TOTEM_IS_PLUGIN (plugin));
+ g_return_if_fail (TOTEM_IS_OBJECT (totem));
+
+ if (TOTEM_PLUGIN_GET_CLASS (plugin)->deactivate)
+ TOTEM_PLUGIN_GET_CLASS (plugin)->deactivate (plugin, totem);
+}
+
+gboolean
+totem_plugin_is_configurable (TotemPlugin *plugin)
+{
+ g_return_val_if_fail (TOTEM_IS_PLUGIN (plugin), FALSE);
+
+ return TOTEM_PLUGIN_GET_CLASS (plugin)->is_configurable (plugin);
+}
+
+GtkWidget *
+totem_plugin_create_configure_dialog (TotemPlugin *plugin)
+{
+ g_return_val_if_fail (TOTEM_IS_PLUGIN (plugin), NULL);
+
+ if (TOTEM_PLUGIN_GET_CLASS (plugin)->create_configure_dialog)
+ return TOTEM_PLUGIN_GET_CLASS (plugin)->create_configure_dialog (plugin);
+ else
+ return NULL;
+}
+
+#define UNINSTALLED_PLUGINS_LOCATION "plugins"
+
+GList *
+totem_get_plugin_paths (void)
+{
+ GList *paths;
+ char *path;
+ GConfClient *client;
+
+ paths = NULL;
+
+ client = gconf_client_get_default ();
+ if (gconf_client_get_bool (client, GCONF_PREFIX"/disable_user_plugins", NULL) != FALSE) {
+ path = g_build_filename (totem_dot_dir (), "plugins", NULL);
+ paths = g_list_prepend (paths, path);
+ }
+
+#ifdef TOTEM_RUN_IN_SOURCE_TREE
+ path = g_build_filename (UNINSTALLED_PLUGINS_LOCATION, NULL);
+ paths = g_list_prepend (paths, path);
+#endif
+
+ path = g_strdup (TOTEM_PLUGIN_DIR);
+ paths = g_list_prepend (paths, path);
+
+ paths = g_list_reverse (paths);
+
+ return paths;
+}
+
+
+char *
+totem_plugin_find_file (TotemPlugin *plugin,
+ const char *file)
+{
+ TotemPluginPrivate *priv = TOTEM_PLUGIN_GET_PRIVATE (plugin);
+ GList *paths;
+ GList *l;
+ char *ret = NULL;
+
+ paths = totem_get_plugin_paths ();
+
+ for (l = paths; l != NULL; l = l->next) {
+ if (ret == NULL && priv->name) {
+ char *tmp;
+
+ tmp = g_build_filename (l->data, priv->name, file, NULL);
+
+ if (g_file_test (tmp, G_FILE_TEST_EXISTS)) {
+ ret = tmp;
+ break;
+ }
+ g_free (tmp);
+ }
+ }
+
+ g_list_foreach (paths, (GFunc)g_free, NULL);
+ g_list_free (paths);
+
+ /* global data files */
+ if (ret == NULL)
+ ret = totem_interface_get_full_path (file);
+
+ /* ensure it's an absolute path, so doesn't confuse rb_glade_new et al */
+ if (ret && ret[0] != '/') {
+ char *pwd = g_get_current_dir ();
+ char *path = g_strconcat (pwd, G_DIR_SEPARATOR_S, ret, NULL);
+ g_free (ret);
+ g_free (pwd);
+ ret = path;
+ }
+ return ret;
+}
diff --git a/src/plugins/totem-plugin.h b/src/plugins/totem-plugin.h
new file mode 100644
index 000000000..23414c161
--- /dev/null
+++ b/src/plugins/totem-plugin.h
@@ -0,0 +1,208 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * heavily based on code from Rhythmbox and Gedit
+ *
+ * Copyright (C) 2002-2005 Paolo Maggi
+ * Copyright (C) 2007 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add excemption clause.
+ * See license_change file for details.
+ *
+ */
+
+#ifndef __TOTEM_PLUGIN_H__
+#define __TOTEM_PLUGIN_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "totem.h"
+
+G_BEGIN_DECLS
+
+/*
+ * Type checking and casting macros
+ */
+#define TOTEM_TYPE_PLUGIN (totem_plugin_get_type())
+#define TOTEM_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TOTEM_TYPE_PLUGIN, TotemPlugin))
+#define TOTEM_PLUGIN_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TOTEM_TYPE_PLUGIN, TotemPlugin const))
+#define TOTEM_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TOTEM_TYPE_PLUGIN, TotemPluginClass))
+#define TOTEM_IS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TOTEM_TYPE_PLUGIN))
+#define TOTEM_IS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TOTEM_TYPE_PLUGIN))
+#define TOTEM_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TOTEM_TYPE_PLUGIN, TotemPluginClass))
+
+/*
+ * Main object structure
+ */
+typedef struct
+{
+ GObject parent;
+} TotemPlugin;
+
+typedef void (*TotemPluginActivationFunc) (TotemPlugin *plugin, TotemObject *totem);
+typedef GtkWidget * (*TotemPluginWidgetFunc) (TotemPlugin *plugin);
+typedef gboolean (*TotemPluginBooleanFunc) (TotemPlugin *plugin);
+
+/*
+ * Class definition
+ */
+typedef struct
+{
+ GObjectClass parent_class;
+
+ /* Virtual public methods */
+
+ TotemPluginActivationFunc activate;
+ TotemPluginActivationFunc deactivate;
+ TotemPluginWidgetFunc create_configure_dialog;
+
+ /* Plugins should not override this, it's handled automatically by
+ the TotemPluginClass */
+ TotemPluginBooleanFunc is_configurable;
+} TotemPluginClass;
+
+/*
+ * Public methods
+ */
+GType totem_plugin_get_type (void) G_GNUC_CONST;
+
+void totem_plugin_activate (TotemPlugin *plugin,
+ TotemObject *shell);
+void totem_plugin_deactivate (TotemPlugin *plugin,
+ TotemObject *totem);
+
+gboolean totem_plugin_is_configurable (TotemPlugin *plugin);
+GtkWidget *totem_plugin_create_configure_dialog
+ (TotemPlugin *plugin);
+
+char * totem_plugin_find_file (TotemPlugin *plugin,
+ const char *file);
+
+GList * totem_get_plugin_paths (void);
+
+/*
+ * Utility macro used to register plugins
+ *
+ * use: TOTEM_PLUGIN_REGISTER(TOTEMSamplePlugin, totem_sample_plugin)
+ */
+
+#define TOTEM_PLUGIN_REGISTER(PluginName, plugin_name) \
+ \
+static GType plugin_name##_type = 0; \
+static GTypeModule *plugin_module_type = 0; \
+ \
+GType \
+plugin_name##_get_type (void) \
+{ \
+ return plugin_name##_type; \
+} \
+ \
+static void plugin_name##_init (PluginName *self); \
+static void plugin_name##_class_init (PluginName##Class *klass); \
+static gpointer plugin_name##_parent_class = NULL; \
+static void plugin_name##_class_intern_init (gpointer klass) \
+{ \
+ plugin_name##_parent_class = g_type_class_peek_parent (klass); \
+ plugin_name##_class_init ((PluginName##Class *) klass); \
+} \
+ \
+G_MODULE_EXPORT GType \
+register_totem_plugin (GTypeModule *module) \
+{ \
+ static const GTypeInfo our_info = \
+ { \
+ sizeof (PluginName##Class), \
+ NULL, /* base_init */ \
+ NULL, /* base_finalize */ \
+ (GClassInitFunc) plugin_name##_class_intern_init, \
+ NULL, \
+ NULL, /* class_data */ \
+ sizeof (PluginName), \
+ 0, /* n_preallocs */ \
+ (GInstanceInitFunc) plugin_name##_init \
+ }; \
+ \
+ /* Initialise the i18n stuff */ \
+ bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); \
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); \
+ \
+ plugin_module_type = module; \
+ plugin_name##_type = g_type_module_register_type (module, \
+ TOTEM_TYPE_PLUGIN, \
+ #PluginName, \
+ &our_info, \
+ 0); \
+ return plugin_name##_type; \
+}
+
+#define TOTEM_PLUGIN_REGISTER_TYPE(type_name) \
+ type_name##_register_type (plugin_module_type)
+
+#define TOTEM_PLUGIN_DEFINE_TYPE(TypeName, type_name, TYPE_PARENT) \
+static void type_name##_init (TypeName *self); \
+static void type_name##_class_init (TypeName##Class *klass); \
+static gpointer type_name##_parent_class = ((void *)0); \
+static GType type_name##_type_id = 0; \
+ \
+static void \
+type_name##_class_intern_init (gpointer klass) \
+{ \
+ type_name##_parent_class = g_type_class_peek_parent (klass); \
+ type_name##_class_init ((TypeName##Class*) klass); \
+} \
+ \
+ \
+GType \
+type_name##_get_type (void) \
+{ \
+ g_assert (type_name##_type_id != 0); \
+ \
+ return type_name##_type_id; \
+} \
+ \
+GType \
+type_name##_register_type (GTypeModule *module) \
+{ \
+ \
+ if ((type_name##_type_id == 0)) { \
+ static const GTypeInfo g_define_type_info = { \
+ sizeof (TypeName##Class), \
+ (GBaseInitFunc) ((void *)0), \
+ (GBaseFinalizeFunc) ((void *)0), \
+ (GClassInitFunc) type_name##_class_intern_init, \
+ (GClassFinalizeFunc) ((void *)0), \
+ ((void *)0), \
+ sizeof (TypeName), \
+ 0, \
+ (GInstanceInitFunc) type_name##_init, \
+ ((void *)0) \
+ }; \
+ type_name##_type_id = \
+ g_type_module_register_type (module, \
+ TYPE_PARENT, \
+ #TypeName, \
+ &g_define_type_info, \
+ (GTypeFlags) 0); \
+ } \
+ \
+ return type_name##_type_id; \
+}
+
+G_END_DECLS
+
+#endif /* __TOTEM_PLUGIN_H__ */
diff --git a/src/plugins/totem-plugins-engine.c b/src/plugins/totem-plugins-engine.c
new file mode 100644
index 000000000..b6ad4315d
--- /dev/null
+++ b/src/plugins/totem-plugins-engine.c
@@ -0,0 +1,742 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Plugin engine for Totem, heavily based on the code from Rhythmbox,
+ * which is based heavily on the code from gedit.
+ *
+ * Copyright (C) 2002-2005 Paolo Maggi
+ * 2006 James Livingston <jrl@ids.org.au>
+ * 2007 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add excemption clause.
+ * See license_change file for details.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <glib/gkeyfile.h>
+#include <gconf/gconf-client.h>
+
+#include "totem-plugin.h"
+
+#include "totem-module.h"
+#include "totem-interface.h"
+
+#ifdef ENABLE_PYTHON
+#include "rb-python-module.h"
+#endif
+
+#include "totem-plugins-engine.h"
+
+#define PLUGIN_EXT ".totem-plugin"
+#define GCONF_PREFIX_PLUGINS GCONF_PREFIX"/plugins"
+#define GCONF_PREFIX_PLUGIN GCONF_PREFIX"/plugins/%s"
+#define GCONF_PLUGIN_ACTIVE GCONF_PREFIX_PLUGINS"/%s/active"
+#define GCONF_PLUGIN_HIDDEN GCONF_PREFIX_PLUGINS"/%s/hidden"
+
+typedef enum
+{
+ TOTEM_PLUGIN_LOADER_C,
+ TOTEM_PLUGIN_LOADER_PY,
+} TotemPluginLang;
+
+struct _TotemPluginInfo
+{
+ gchar *file;
+
+ gchar *location;
+ TotemPluginLang lang;
+ GTypeModule *module;
+
+ gchar *name;
+ gchar *desc;
+ gchar **authors;
+ gchar *copyright;
+ gchar *website;
+
+ gchar *icon_name;
+ GdkPixbuf *icon_pixbuf;
+
+ TotemPlugin *plugin;
+
+ gboolean builtin;
+ gboolean active;
+ gboolean visible;
+ guint active_notification_id;
+ guint visible_notification_id;
+};
+
+static void totem_plugin_info_free (TotemPluginInfo *info);
+static void totem_plugins_engine_plugin_active_cb (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ TotemPluginInfo *info);
+static void totem_plugins_engine_plugin_visible_cb (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ TotemPluginInfo *info);
+static gboolean totem_plugins_engine_activate_plugin_real (TotemPluginInfo *info,
+ TotemObject *totem);
+static void totem_plugins_engine_deactivate_plugin_real (TotemPluginInfo *info,
+ TotemObject *totem);
+
+static GHashTable *totem_plugins = NULL;
+guint garbage_collect_id = 0;
+TotemObject *totem_plugins_object = NULL;
+static GConfClient *client = NULL;
+
+static TotemPluginInfo *
+totem_plugins_engine_load (const gchar *file)
+{
+ TotemPluginInfo *info;
+ GKeyFile *plugin_file = NULL;
+ GError *err = NULL;
+ gchar *str;
+
+ g_return_val_if_fail (file != NULL, NULL);
+
+ info = g_new0 (TotemPluginInfo, 1);
+ info->file = g_strdup (file);
+
+ plugin_file = g_key_file_new ();
+ if (!g_key_file_load_from_file (plugin_file, file, G_KEY_FILE_NONE, NULL)) {
+ g_warning ("Bad plugin file: %s", file);
+ goto error;
+ }
+
+ if (!g_key_file_has_key (plugin_file,
+ "Totem Plugin",
+ "IAge",
+ NULL)) {
+ goto error;
+ }
+
+ /* Check IAge=1 */
+ if (g_key_file_get_integer (plugin_file,
+ "Totem Plugin",
+ "IAge",
+ NULL) != 1) {
+ goto error;
+ }
+
+ /* Get Location */
+ str = g_key_file_get_string (plugin_file,
+ "Totem Plugin",
+ "Module",
+ NULL);
+ if (str) {
+ info->location = str;
+ } else {
+ g_warning ("Could not find 'Module' in %s", file);
+ goto error;
+ }
+
+ /* Get the loader for this plugin */
+ str = g_key_file_get_string (plugin_file,
+ "Totem Plugin",
+ "Loader",
+ NULL);
+ if (str && strcmp(str, "python") == 0) {
+ info->lang = TOTEM_PLUGIN_LOADER_PY;
+#if 0
+#ifndef ENABLE_PYTHON
+ rb_debug ("Cannot load python extension '%s', Rhythmbox was not "
+ "compiled with python support", file);
+ goto error;
+#endif
+#endif
+ } else {
+ info->lang = TOTEM_PLUGIN_LOADER_C;
+ }
+ g_free (str);
+
+ /* Get Name */
+ str = g_key_file_get_locale_string (plugin_file,
+ "Totem Plugin",
+ "Name",
+ NULL, NULL);
+ if (str) {
+ info->name = str;
+ } else {
+ g_warning ("Could not find 'Name' in %s", file);
+ goto error;
+ }
+
+ /* Get Description */
+ str = g_key_file_get_locale_string (plugin_file,
+ "Totem Plugin",
+ "Description",
+ NULL, NULL);
+ if (str) {
+ info->desc = str;
+ } else {
+ info->desc = g_strdup ("");
+ }
+
+ /* Get icon name */
+ str = g_key_file_get_string (plugin_file,
+ "Totem Plugin",
+ "Icon",
+ NULL);
+ if (str) {
+ info->icon_name = str;
+ } else {
+ info->icon_name = g_strdup ("");
+ }
+
+ /* Get Authors */
+ info->authors = g_key_file_get_string_list (plugin_file,
+ "Totem Plugin",
+ "Authors",
+ NULL, NULL);
+
+ /* Get Copyright */
+ str = g_key_file_get_string (plugin_file,
+ "Totem Plugin",
+ "Copyright",
+ NULL);
+ if (str) {
+ info->copyright = str;
+ } else {
+ info->copyright = g_strdup ("");
+ }
+
+ /* Get Copyright */
+ str = g_key_file_get_string (plugin_file,
+ "Totem Plugin",
+ "Website",
+ NULL);
+ if (str) {
+ info->website = str;
+ } else {
+ info->website = g_strdup ("");
+
+ }
+
+ /* Get Builtin */
+ info->builtin = g_key_file_get_boolean (plugin_file,
+ "Totem Plugin",
+ "Builtin",
+ &err);
+ if (err != NULL) {
+ info->builtin = FALSE;
+ g_error_free (err);
+ }
+
+ g_key_file_free (plugin_file);
+
+ return info;
+
+error:
+ g_free (info->file);
+ g_free (info->location);
+ g_free (info->name);
+ g_free (info);
+ g_key_file_free (plugin_file);
+
+ return NULL;
+}
+
+static void
+totem_plugins_engine_load_file (const char *plugin_file)
+{
+ TotemPluginInfo *info;
+ char *key_name;
+ gboolean activate;
+
+ if (g_str_has_suffix (plugin_file, PLUGIN_EXT) == FALSE)
+ return;
+
+ info = totem_plugins_engine_load (plugin_file);
+ if (info == NULL)
+ return;
+
+ if (g_hash_table_lookup (totem_plugins, info->location)) {
+ totem_plugin_info_free (info);
+ return;
+ }
+
+ g_hash_table_insert (totem_plugins, info->location, info);
+
+ if (info->builtin != FALSE) {
+ info->visible = FALSE;
+ totem_plugins_engine_activate_plugin (info);
+ return;
+ }
+
+ key_name = g_strdup_printf (GCONF_PREFIX_PLUGIN, info->location);
+ gconf_client_add_dir (client, key_name, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+
+ key_name = g_strdup_printf (GCONF_PLUGIN_ACTIVE, info->location);
+ info->active_notification_id = gconf_client_notify_add (client,
+ key_name,
+ (GConfClientNotifyFunc)totem_plugins_engine_plugin_active_cb,
+ info,
+ NULL,
+ NULL);
+ activate = gconf_client_get_bool (client, key_name, NULL);
+ g_free (key_name);
+
+ key_name = g_strdup_printf (GCONF_PLUGIN_HIDDEN, info->location);
+ info->visible_notification_id = gconf_client_notify_add (client,
+ key_name,
+ (GConfClientNotifyFunc)totem_plugins_engine_plugin_visible_cb,
+ info,
+ NULL,
+ NULL);
+ info->visible = !gconf_client_get_bool (client, key_name, NULL);
+ g_free (key_name);
+
+ if (activate)
+ totem_plugins_engine_activate_plugin (info);
+}
+
+static void
+totem_plugins_engine_load_dir (const gchar *path)
+{
+ GDir *dir;
+ const char *name;
+
+ dir = g_dir_open (path, 0, NULL);
+ if (dir == NULL)
+ return;
+
+ while ((name = g_dir_read_name (dir)) != NULL) {
+ char *filename;
+
+ filename = g_build_filename (path, name, NULL);
+ if (g_file_test (filename, G_FILE_TEST_IS_DIR) != FALSE) {
+ totem_plugins_engine_load_dir (filename);
+ } else {
+ totem_plugins_engine_load_file (filename);
+ }
+ g_free (filename);
+ }
+ g_dir_close (dir);
+}
+
+static void
+totem_plugins_engine_load_all (void)
+{
+ GList *paths;
+
+ paths = totem_get_plugin_paths ();
+ while (paths != NULL) {
+ totem_plugins_engine_load_dir (paths->data);
+ g_free (paths->data);
+ paths = g_list_delete_link (paths, paths);
+ }
+}
+
+static gboolean
+garbage_collect_cb (gpointer data)
+{
+ totem_plugins_engine_garbage_collect ();
+ return TRUE;
+}
+
+gboolean
+totem_plugins_engine_init (TotemObject *totem)
+{
+ g_return_val_if_fail (totem_plugins == NULL, FALSE);
+
+ if (!g_module_supported ())
+ {
+ g_warning ("rb is not able to initialize the plugins engine.");
+ return FALSE;
+ }
+ totem_plugins = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)totem_plugin_info_free);
+
+ totem_plugins_object = totem;
+ g_object_ref (G_OBJECT (totem_plugins_object));
+
+ client = gconf_client_get_default ();
+
+ totem_plugins_engine_load_all ();
+
+ garbage_collect_id = g_timeout_add_full (G_PRIORITY_LOW, 20000, garbage_collect_cb, NULL, NULL);
+
+ return TRUE;
+}
+
+void
+totem_plugins_engine_garbage_collect (void)
+{
+#ifdef ENABLE_PYTHON
+ rb_python_garbage_collect ();
+#endif
+}
+
+static void
+totem_plugin_info_free (TotemPluginInfo *info)
+{
+ if (info->active)
+ totem_plugins_engine_deactivate_plugin_real (info, totem_plugins_object);
+
+ if (info->plugin != NULL) {
+ g_object_unref (info->plugin);
+
+ /* info->module must not be unref since it is not possible to finalize
+ * a type module */
+ }
+
+ if (info->active_notification_id > 0)
+ gconf_client_notify_remove (client, info->active_notification_id);
+ if (info->visible_notification_id > 0)
+ gconf_client_notify_remove (client, info->visible_notification_id);
+
+ g_free (info->file);
+ g_free (info->location);
+ g_free (info->name);
+ g_free (info->desc);
+ g_free (info->website);
+ g_free (info->copyright);
+ g_free (info->icon_name);
+
+ if (info->icon_pixbuf)
+ g_object_unref (info->icon_pixbuf);
+ g_strfreev (info->authors);
+
+ g_free (info);
+}
+
+void
+totem_plugins_engine_shutdown (void)
+{
+ g_hash_table_destroy (totem_plugins);
+ totem_plugins = NULL;
+
+ g_object_unref (totem_plugins_object);
+ totem_plugins_object = NULL;
+
+ g_source_remove (garbage_collect_id);
+ totem_plugins_engine_garbage_collect ();
+
+ g_object_unref (client);
+ client = NULL;
+
+#ifdef ENABLE_PYTHON
+ rb_python_shutdown ();
+#endif
+}
+
+static void
+collate_values_cb (gpointer key, gpointer value, GList **list)
+{
+ *list = g_list_prepend (*list, value);
+}
+
+GList *
+totem_plugins_engine_get_plugins_list (void)
+{
+ GList *list = NULL;
+
+ if (totem_plugins == NULL)
+ return NULL;
+
+ g_hash_table_foreach (totem_plugins, (GHFunc)collate_values_cb, &list);
+ list = g_list_reverse (list);
+
+ return list;
+}
+
+static gboolean
+load_plugin_module (TotemPluginInfo *info)
+{
+ gchar *path;
+ gchar *dirname;
+
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (info->file != NULL, FALSE);
+ g_return_val_if_fail (info->location != NULL, FALSE);
+ g_return_val_if_fail (info->plugin == NULL, FALSE);
+
+ switch (info->lang) {
+ case TOTEM_PLUGIN_LOADER_C:
+ dirname = g_path_get_dirname (info->file);
+ g_return_val_if_fail (dirname != NULL, FALSE);
+
+ path = g_module_build_path (dirname, info->location);
+#ifdef TOTEM_RUN_IN_SOURCE_TREE
+ if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
+ char *temp;
+
+ g_free (path);
+ temp = g_build_filename (dirname, ".libs", NULL);
+
+ path = g_module_build_path (temp, info->location);
+ g_free (temp);
+ }
+#endif
+
+ g_free (dirname);
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ info->module = G_TYPE_MODULE (totem_module_new (path, info->location));
+ g_free (path);
+ break;
+ case TOTEM_PLUGIN_LOADER_PY:
+#if 0
+#ifdef ENABLE_PYTHON
+ info->module = G_TYPE_MODULE (rb_python_module_new (info->file, info->location));
+#else
+ rb_debug ("cannot load plugin %s, python plugin support is disabled", info->location);
+#endif
+#endif
+ break;
+ }
+
+ if (g_type_module_use (info->module) == FALSE) {
+ g_warning ("Could not load plugin %s\n", info->location);
+
+ g_object_unref (G_OBJECT (info->module));
+ info->module = NULL;
+
+ return FALSE;
+ }
+
+ switch (info->lang) {
+ case TOTEM_PLUGIN_LOADER_C:
+ info->plugin = TOTEM_PLUGIN (totem_module_new_object (TOTEM_MODULE (info->module)));
+ break;
+ case TOTEM_PLUGIN_LOADER_PY:
+#ifdef ENABLE_PYTHON
+ info->plugin = TOTEM_PLUGIN (rb_python_module_new_object (TOTEM_PYTHON_MODULE (info->module)));
+#endif
+ break;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+totem_plugins_engine_activate_plugin_real (TotemPluginInfo *info, TotemObject *totem)
+{
+ gboolean res = TRUE;
+
+ if (info->plugin == NULL)
+ res = load_plugin_module (info);
+
+ if (res)
+ totem_plugin_activate (info->plugin, totem);
+ else
+ g_warning ("Error, impossible to activate plugin '%s'", info->name);
+
+ return res;
+}
+
+gboolean
+totem_plugins_engine_activate_plugin (TotemPluginInfo *info)
+{
+ char *msg;
+
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ if (info->active)
+ return TRUE;
+
+ if (totem_plugins_engine_activate_plugin_real (info, totem_plugins_object)) {
+ char *key_name;
+
+ key_name = g_strdup_printf (GCONF_PLUGIN_ACTIVE, info->location);
+ gconf_client_set_bool (client, key_name, TRUE, NULL);
+ g_free (key_name);
+
+ info->active = TRUE;
+
+ return TRUE;
+ }
+
+ msg = g_strdup_printf (_("Unable to activate plugin %s"), info->name);
+ totem_interface_error (_("Plugin Error"), msg, NULL);
+ g_free (msg);
+
+ return FALSE;
+}
+
+static void
+totem_plugins_engine_deactivate_plugin_real (TotemPluginInfo *info, TotemObject *totem)
+{
+ totem_plugin_deactivate (info->plugin, totem_plugins_object);
+}
+
+gboolean
+totem_plugins_engine_deactivate_plugin (TotemPluginInfo *info)
+{
+ char *key_name;
+
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ if (!info->active)
+ return TRUE;
+
+ totem_plugins_engine_deactivate_plugin_real (info, totem_plugins_object);
+
+ /* Update plugin state */
+ info->active = FALSE;
+
+ key_name = g_strdup_printf (GCONF_PLUGIN_ACTIVE, info->location);
+ gconf_client_set_bool (client, key_name, FALSE, NULL);
+ g_free (key_name);
+
+ return TRUE;
+}
+
+gboolean
+totem_plugins_engine_plugin_is_active (TotemPluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ return info->active;
+}
+
+gboolean
+totem_plugins_engine_plugin_is_visible (TotemPluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ return info->visible;
+}
+
+gboolean
+totem_plugins_engine_plugin_is_configurable (TotemPluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ if ((info->plugin == NULL) || !info->active)
+ return FALSE;
+
+ return totem_plugin_is_configurable (info->plugin);
+}
+
+void
+totem_plugins_engine_configure_plugin (TotemPluginInfo *info,
+ GtkWindow *parent)
+{
+ GtkWidget *conf_dlg;
+
+ GtkWindowGroup *wg;
+
+ g_return_if_fail (info != NULL);
+
+ conf_dlg = totem_plugin_create_configure_dialog (info->plugin);
+ g_return_if_fail (conf_dlg != NULL);
+ gtk_window_set_transient_for (GTK_WINDOW (conf_dlg),
+ parent);
+
+ wg = parent->group;
+ if (wg == NULL)
+ {
+ wg = gtk_window_group_new ();
+ gtk_window_group_add_window (wg, parent);
+ }
+
+ gtk_window_group_add_window (wg,
+ GTK_WINDOW (conf_dlg));
+
+ gtk_window_set_modal (GTK_WINDOW (conf_dlg), TRUE);
+ gtk_widget_show (conf_dlg);
+}
+
+static void
+totem_plugins_engine_plugin_active_cb (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ TotemPluginInfo *info)
+{
+ if (gconf_value_get_bool (entry->value)) {
+ totem_plugins_engine_activate_plugin (info);
+ } else {
+ totem_plugins_engine_deactivate_plugin (info);
+ }
+}
+
+static void
+totem_plugins_engine_plugin_visible_cb (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ TotemPluginInfo *info)
+{
+ info->visible = !gconf_value_get_bool (entry->value);
+}
+
+const gchar *
+totem_plugins_engine_get_plugin_name (TotemPluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->name;
+}
+
+const gchar *
+totem_plugins_engine_get_plugin_description (TotemPluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->desc;
+}
+
+const gchar **
+totem_plugins_engine_get_plugin_authors (TotemPluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, (const gchar **)NULL);
+
+ return (const gchar **)info->authors;
+}
+
+const gchar *
+totem_plugins_engine_get_plugin_website (TotemPluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->website;
+}
+
+const gchar *
+totem_plugins_engine_get_plugin_copyright (TotemPluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->copyright;
+}
+
+GdkPixbuf *
+totem_plugins_engine_get_plugin_icon (TotemPluginInfo *info)
+{
+ if (info->icon_name == NULL)
+ return NULL;
+
+ if (info->icon_pixbuf == NULL) {
+ char *filename = NULL;
+ char *dirname;
+
+ dirname = g_path_get_dirname (info->file);
+ filename = g_build_filename (dirname, info->icon_name, NULL);
+ g_free (dirname);
+
+ info->icon_pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
+ g_free (filename);
+ }
+
+ return info->icon_pixbuf;
+}
diff --git a/src/plugins/totem-plugins-engine.h b/src/plugins/totem-plugins-engine.h
new file mode 100644
index 000000000..af18cf0c1
--- /dev/null
+++ b/src/plugins/totem-plugins-engine.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Plugin engine for Totem, heavily based on the code from Rhythmbox,
+ * which is based heavily on the code from gedit.
+ *
+ * Copyright (C) 2002-2005 Paolo Maggi
+ * 2006 James Livingston <jrl@ids.org.au>
+ * 2007 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add excemption clause.
+ * See license_change file for details.
+ *
+ */
+
+#ifndef __TOTEM_PLUGINS_ENGINE_H__
+#define __TOTEM_PLUGINS_ENGINE_H__
+
+#include <glib.h>
+#include <totem.h>
+
+typedef struct _TotemPluginInfo TotemPluginInfo;
+
+gboolean totem_plugins_engine_init (TotemObject *totem);
+void totem_plugins_engine_shutdown (void);
+
+void totem_plugins_engine_garbage_collect (void);
+
+GList* totem_plugins_engine_get_plugins_list (void);
+
+gboolean totem_plugins_engine_activate_plugin (TotemPluginInfo *info);
+gboolean totem_plugins_engine_deactivate_plugin (TotemPluginInfo *info);
+gboolean totem_plugins_engine_plugin_is_active (TotemPluginInfo *info);
+gboolean totem_plugins_engine_plugin_is_visible (TotemPluginInfo *info);
+
+gboolean totem_plugins_engine_plugin_is_configurable
+ (TotemPluginInfo *info);
+void totem_plugins_engine_configure_plugin (TotemPluginInfo *info,
+ GtkWindow *parent);
+
+const gchar* totem_plugins_engine_get_plugin_name (TotemPluginInfo *info);
+const gchar* totem_plugins_engine_get_plugin_description
+ (TotemPluginInfo *info);
+
+const gchar** totem_plugins_engine_get_plugin_authors (TotemPluginInfo *info);
+const gchar* totem_plugins_engine_get_plugin_website (TotemPluginInfo *info);
+const gchar* totem_plugins_engine_get_plugin_copyright
+ (TotemPluginInfo *info);
+GdkPixbuf * totem_plugins_engine_get_plugin_icon (TotemPluginInfo *info);
+
+#endif /* __TOTEM_PLUGINS_ENGINE_H__ */
diff --git a/src/totem-interface.c b/src/totem-interface.c
index b7feb6d39..d05b2da07 100644
--- a/src/totem-interface.c
+++ b/src/totem-interface.c
@@ -255,3 +255,37 @@ totem_interface_get_license (void)
NULL);
}
+void
+totem_interface_boldify_label (GladeXML *xml, const char *name)
+{
+ GtkWidget *widget;
+
+ widget = glade_xml_get_widget (xml, name);
+
+ if (widget == NULL) {
+ g_warning ("widget '%s' not found", name);
+ return;
+ }
+
+ /* this way is probably better, but for some reason doesn't work with
+ * labels with mnemonics.
+
+ static PangoAttrList *pattrlist = NULL;
+
+ if (pattrlist == NULL) {
+ PangoAttribute *attr;
+
+ pattrlist = pango_attr_list_new ();
+ attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
+ attr->start_index = 0;
+ attr->end_index = G_MAXINT;
+ pango_attr_list_insert (pattrlist, attr);
+ }
+ gtk_label_set_attributes (GTK_LABEL (widget), pattrlist);*/
+
+ gchar *str_final;
+ str_final = g_strdup_printf ("<b>%s</b>", gtk_label_get_label (GTK_LABEL (widget)));
+ gtk_label_set_markup_with_mnemonic (GTK_LABEL (widget), str_final);
+ g_free (str_final);
+}
+
diff --git a/src/totem-interface.h b/src/totem-interface.h
index 55ca77c88..485d52aaa 100644
--- a/src/totem-interface.h
+++ b/src/totem-interface.h
@@ -48,6 +48,8 @@ void totem_interface_error_blocking (const char *title,
void totem_interface_set_transient_for (GtkWindow *window,
GtkWindow *parent);
char * totem_interface_get_license (void);
+void totem_interface_boldify_label (GladeXML *xml,
+ const char *label);
G_END_DECLS
diff --git a/src/totem-menu.c b/src/totem-menu.c
index f30186d75..dfad0c124 100644
--- a/src/totem-menu.c
+++ b/src/totem-menu.c
@@ -32,6 +32,7 @@
#include "totem-interface.h"
#include "totem-private.h"
#include "totem-sidebar.h"
+#include "totem-plugin-manager.h"
#include "bacon-video-widget.h"
#include "debug.h"
@@ -1122,6 +1123,60 @@ about_action_callback (GtkAction *action, Totem *totem)
g_free (license);
}
+static gboolean
+totem_plugins_window_delete_cb (GtkWidget *window,
+ GdkEventAny *event,
+ gpointer data)
+{
+ gtk_widget_hide (window);
+
+ return TRUE;
+}
+
+static void
+totem_plugins_response_cb (GtkDialog *dialog,
+ int response_id,
+ gpointer data)
+{
+ if (response_id == GTK_RESPONSE_CLOSE)
+ gtk_widget_hide (GTK_WIDGET (dialog));
+}
+
+
+static void
+plugins_action_callback (GtkAction *action, Totem *totem)
+{
+ if (totem->plugins == NULL) {
+ GtkWidget *manager;
+
+ totem->plugins = gtk_dialog_new_with_buttons (_("Configure Plugins"),
+ GTK_WINDOW (totem->win),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CLOSE,
+ GTK_RESPONSE_CLOSE,
+ NULL);
+ gtk_container_set_border_width (GTK_CONTAINER (totem->plugins), 5);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (totem->plugins)->vbox), 2);
+ gtk_dialog_set_has_separator (GTK_DIALOG (totem->plugins), FALSE);
+
+ g_signal_connect_object (G_OBJECT (totem->plugins),
+ "delete_event",
+ G_CALLBACK (totem_plugins_window_delete_cb),
+ NULL, 0);
+ g_signal_connect_object (G_OBJECT (totem->plugins),
+ "response",
+ G_CALLBACK (totem_plugins_response_cb),
+ NULL, 0);
+
+ manager = totem_plugin_manager_new ();
+ gtk_widget_show_all (GTK_WIDGET (manager));
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (totem->plugins)->vbox),
+ manager);
+ }
+
+ gtk_window_present (GTK_WINDOW (totem->plugins));
+}
+
static void
repeat_mode_action_callback (GtkToggleAction *action, Totem *totem)
{
@@ -1208,6 +1263,7 @@ static const GtkActionEntry entries[] = {
{ "take-screenshot", "camera-photo", N_("Take _Screenshot..."), "<control>S", N_("Take a screenshot"), G_CALLBACK (take_screenshot_action_callback) },
{ "clear-playlist", NULL, N_("_Clear Playlist"), NULL, N_("Clear playlist"), G_CALLBACK (clear_playlist_action_callback) },
{ "preferences", GTK_STOCK_PREFERENCES, N_("Prefere_nces"), NULL, NULL, G_CALLBACK (preferences_action_callback) },
+ { "plugins", NULL, N_("Plugins..."), NULL, NULL, G_CALLBACK (plugins_action_callback) },
{ "view-menu", NULL, N_("_View") },
{ "fullscreen", "view-fullscreen", N_("_Fullscreen"), "F", N_("Switch to fullscreen"), G_CALLBACK (fullscreen_action_callback) },
diff --git a/src/totem-object.c b/src/totem-object.c
new file mode 100644
index 000000000..f7dee0a35
--- /dev/null
+++ b/src/totem-object.c
@@ -0,0 +1,124 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Totem project hereby grant permission for non-gpl compatible GStreamer
+ * plugins to be used and distributed together with GStreamer and Totem. This
+ * permission are above and beyond the permissions granted by the GPL license
+ * Totem is covered by.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add excemption clause.
+ * See license_change file for details.
+ *
+ */
+
+#include "config.h"
+
+#include <glib-object.h>
+
+#include "totem.h"
+#include "totem-private.h"
+#include "totem-plugins-engine.h"
+
+enum {
+ PROP_0,
+ PROP_FULLSCREEN,
+ PROP_PLAYING
+};
+
+static void totem_object_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void totem_object_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void totem_object_finalize (GObject *totem);
+
+G_DEFINE_TYPE(TotemObject, totem_object, G_TYPE_OBJECT)
+
+static GObjectClass *parent_class = NULL;
+
+static void
+totem_object_class_init (TotemObjectClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = (GObjectClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->set_property = totem_object_set_property;
+ object_class->get_property = totem_object_get_property;
+ object_class->finalize = totem_object_finalize;
+
+ g_object_class_install_property (object_class, PROP_FULLSCREEN,
+ g_param_spec_boolean ("fullscreen", NULL, NULL,
+ FALSE, G_PARAM_READABLE));
+ g_object_class_install_property (object_class, PROP_PLAYING,
+ g_param_spec_boolean ("playing", NULL, NULL,
+ FALSE, G_PARAM_READABLE));
+ //FIXME properties and signals
+}
+
+static void
+totem_object_init (TotemObject *totem)
+{
+ //FIXME nothing yet
+
+ totem_plugins_engine_init (totem);
+}
+
+static void
+totem_object_finalize (GObject *totem)
+{
+ totem_plugins_engine_shutdown ();
+}
+
+static void
+totem_object_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+totem_object_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TotemObject *totem;
+
+ totem = TOTEM_OBJECT (object);
+
+ switch (property_id)
+ {
+ case PROP_FULLSCREEN:
+ g_value_set_boolean (value, totem_is_fullscreen (totem));
+ break;
+ case PROP_PLAYING:
+ g_value_set_boolean (value, totem_is_playing (totem));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
diff --git a/src/totem-private.h b/src/totem-private.h
index b3b8404a6..1d8d493d0 100644
--- a/src/totem-private.h
+++ b/src/totem-private.h
@@ -34,7 +34,6 @@
#include <libgnomevfs/gnome-vfs.h>
#include "totem-remote.h"
-#include "totem-scrsaver.h"
#include "totem-playlist.h"
#include "bacon-message-connection.h"
#include "bacon-video-widget.h"
@@ -70,7 +69,9 @@ typedef enum {
STATE_STOPPED
} TotemStates;
-struct Totem {
+struct TotemObject {
+ GObject parent;
+
/* Control window */
GladeXML *xml;
GtkWidget *win;
@@ -92,6 +93,9 @@ struct Totem {
GtkActionGroup *subtitles_action_group;
guint subtitles_ui_id;
+ /* Plugins */
+ GtkWidget *plugins;
+
/* Sidebar */
GtkWidget *sidebar;
gboolean sidebar_shown;
@@ -146,8 +150,6 @@ struct Totem {
gboolean popup_in_progress;
GdkRectangle fullscreen_rect;
- TotemScrsaver *scr;
-
/* recent file stuff */
GtkRecentManager *recent_manager;
GtkActionGroup *recent_action_group;
@@ -200,8 +202,4 @@ void totem_action_show_properties (Totem *totem);
void show_controls (Totem *totem, gboolean was_fullscreen);
-gboolean totem_is_fullscreen (Totem *totem);
-
-
-
#endif /* __TOTEM_PRIVATE_H__ */
diff --git a/src/totem-uri.c b/src/totem-uri.c
index 6d84e2522..569c8ea4a 100644
--- a/src/totem-uri.c
+++ b/src/totem-uri.c
@@ -49,6 +49,20 @@ totem_playing_dvd (const char *uri)
return g_str_has_prefix (uri, "dvd:/");
}
+const char *
+totem_dot_dir (void)
+{
+ static char *totem_dir = NULL;
+ if (totem_dir != NULL)
+ return totem_dir;
+
+ totem_dir = g_build_filename (g_get_home_dir (),
+ ".gnome2",
+ "Totem",
+ NULL);
+ return (const char *)totem_dir;
+}
+
gboolean
totem_is_media (const char *uri)
{
diff --git a/src/totem-uri.h b/src/totem-uri.h
index 4a9ca8b7a..aea38cf62 100644
--- a/src/totem-uri.h
+++ b/src/totem-uri.h
@@ -28,6 +28,7 @@
G_BEGIN_DECLS
+const char * totem_dot_dir (void);
char* totem_create_full_path (const char *path);
gboolean totem_is_media (const char *uri);
gboolean totem_is_special_mrl (const char *uri);
diff --git a/src/totem.c b/src/totem.c
index da4eba905..d386efb84 100644
--- a/src/totem.c
+++ b/src/totem.c
@@ -297,6 +297,7 @@ play_pause_set_label (Totem *totem, TotemStates state)
tip = N_("Play");
break;
default:
+ g_assert_not_reached ();
return;
}
@@ -312,6 +313,8 @@ play_pause_set_label (Totem *totem, TotemStates state)
}
totem->state = state;
+
+ g_object_notify (G_OBJECT (totem), "playing");
}
void
@@ -353,6 +356,7 @@ totem_action_play (Totem *totem)
{
GError *err = NULL;
int retval;
+ char *msg, *disp;
if (totem->mrl == NULL)
return;
@@ -362,23 +366,20 @@ totem_action_play (Totem *totem)
retval = bacon_video_widget_play (totem->bvw, &err);
play_pause_set_label (totem, retval ? STATE_PLAYING : STATE_STOPPED);
- if (totem_is_fullscreen (totem) != FALSE)
- totem_scrsaver_set_state (totem->scr, !retval);
- if (retval == FALSE)
- {
- char *msg, *disp;
+ if (retval != FALSE) {
+ play_pause_set_label (totem, STATE_PLAYING);
+ return;
+ }
- disp = totem_uri_escape_for_display (totem->mrl);
- msg = g_strdup_printf(_("Totem could not play '%s'."), disp);
- g_free (disp);
+ disp = totem_uri_escape_for_display (totem->mrl);
+ msg = g_strdup_printf(_("Totem could not play '%s'."), disp);
+ g_free (disp);
- totem_playlist_set_playing (totem->playlist, FALSE);
- totem_action_error (msg, err->message, totem);
- totem_action_stop (totem);
- g_free (msg);
- g_error_free (err);
- }
+ totem_action_error (msg, err->message, totem);
+ totem_action_stop (totem);
+ g_free (msg);
+ g_error_free (err);
}
static void
@@ -402,7 +403,6 @@ totem_action_seek (Totem *totem, double pos)
msg = g_strdup_printf(_("Totem could not play '%s'."), disp);
g_free (disp);
- totem_playlist_set_playing (totem->playlist, FALSE);
totem_action_error (msg, err->message, totem);
totem_action_stop (totem);
g_free (msg);
@@ -554,7 +554,8 @@ void
totem_action_stop (Totem *totem)
{
bacon_video_widget_stop (totem->bvw);
- totem_scrsaver_enable (totem->scr);
+ totem_playlist_set_playing (totem->playlist, FALSE);
+ play_pause_set_label (totem, STATE_STOPPED);
}
void
@@ -581,12 +582,9 @@ totem_action_play_pause (Totem *totem)
{
bacon_video_widget_play (totem->bvw, NULL);
play_pause_set_label (totem, STATE_PLAYING);
- if (totem_is_fullscreen (totem) != FALSE)
- totem_scrsaver_disable (totem->scr);
} else {
bacon_video_widget_pause (totem->bvw);
play_pause_set_label (totem, STATE_PAUSED);
- totem_scrsaver_enable (totem->scr);
}
}
@@ -597,7 +595,6 @@ totem_action_pause (Totem *totem)
{
bacon_video_widget_pause (totem->bvw);
play_pause_set_label (totem, STATE_PAUSED);
- totem_scrsaver_enable (totem->scr);
}
}
@@ -628,9 +625,6 @@ window_state_event_cb (GtkWidget *window, GdkEventWindowState *event,
bacon_video_widget_set_fullscreen (totem->bvw, TRUE);
totem_action_set_cursor (totem, FALSE);
- if (bacon_video_widget_is_playing (totem->bvw) != FALSE)
- totem_scrsaver_disable (totem->scr);
-
totem->controls_visibility = TOTEM_CONTROLS_FULLSCREEN;
show_controls (totem, FALSE);
totem_action_set_sensitivity ("fullscreen", FALSE);
@@ -641,8 +635,6 @@ window_state_event_cb (GtkWidget *window, GdkEventWindowState *event,
bacon_video_widget_set_fullscreen (totem->bvw, FALSE);
totem_action_set_cursor (totem, TRUE);
- totem_scrsaver_enable (totem->scr);
-
action = gtk_action_group_get_action (totem->main_action_group,
"show-controls");
@@ -655,6 +647,8 @@ window_state_event_cb (GtkWidget *window, GdkEventWindowState *event,
totem_action_set_sensitivity ("fullscreen", TRUE);
}
+ g_object_notify (G_OBJECT (totem), "fullscreen");
+
return FALSE;
}
@@ -1178,7 +1172,6 @@ totem_action_seek_relative (Totem *totem, int off_sec)
msg = g_strdup_printf(_("Totem could not play '%s'."), totem->mrl);
g_free (disp);
- totem_playlist_set_playing (totem->playlist, FALSE);
totem_action_stop (totem);
totem_action_error (msg, err->message, totem);
g_free (msg);
@@ -1894,7 +1887,6 @@ commit_hide_skip_to (GtkDialog *dialog, gint response, Totem *totem)
msg = g_strdup_printf(_("Totem could not seek in '%s'."), disp);
g_free (disp);
totem_action_stop (totem);
- totem_playlist_set_playing (totem->playlist, FALSE);
totem_action_error (msg, err->message, totem);
g_free (msg);
g_error_free (err);
@@ -2317,6 +2309,12 @@ totem_is_fullscreen (Totem *totem)
return (totem->controls_visibility == TOTEM_CONTROLS_FULLSCREEN);
}
+gboolean
+totem_is_playing (Totem *totem)
+{
+ return bacon_video_widget_is_playing (totem->bvw) != FALSE;
+}
+
static void
move_popups (Totem *totem)
{
@@ -2495,11 +2493,10 @@ on_eos_event (GtkWidget *widget, Totem *totem)
char *mrl;
/* Set play button status */
- play_pause_set_label (totem, STATE_PAUSED);
totem_playlist_set_at_start (totem->playlist);
update_buttons (totem);
- mrl = totem_playlist_get_current_mrl (totem->playlist);
totem_action_stop (totem);
+ mrl = totem_playlist_get_current_mrl (totem->playlist);
totem_action_set_mrl_with_warning (totem, mrl, FALSE);
bacon_video_widget_pause (totem->bvw);
g_free (mrl);
@@ -3277,8 +3274,6 @@ video_widget_create (Totem *totem)
{ "text/uri-list", 0, 0 },
};
- totem->scr = totem_scrsaver_new ();
-
totem->bvw = BACON_VIDEO_WIDGET
(bacon_video_widget_new (-1, -1, BVW_USE_TYPE_VIDEO, &err));
@@ -3478,7 +3473,7 @@ main (int argc, char **argv)
gnome_authentication_manager_init ();
#endif /* !HAVE_GTK_ONLY */
- totem = g_new0 (Totem, 1);
+ totem = g_object_new (TOTEM_TYPE_OBJECT, NULL);
/* IPC stuff */
totem->conn = bacon_message_connection_new (GETTEXT_PACKAGE);
diff --git a/src/totem.h b/src/totem.h
index ace1fb723..03db47931 100644
--- a/src/totem.h
+++ b/src/totem.h
@@ -28,11 +28,31 @@
#ifndef __TOTEM_H__
#define __TOTEM_H__
+#include <glib-object.h>
+
#include "plparse/totem-disc.h"
#define TOTEM_GCONF_PREFIX "/apps/totem"
-typedef struct Totem Totem;
+G_BEGIN_DECLS
+
+#define TOTEM_TYPE_OBJECT (totem_object_get_type ())
+#define TOTEM_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), totem_object_get_type (), TotemObject))
+#define TOTEM_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), totem_object_get_type (), TotemObjectClass))
+#define TOTEM_IS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, totem_object_get_type ()))
+#define TOTEM_IS_OBJECT_CLASS(klass) (G_CHECK_INSTANCE_GET_CLASS ((klass), totem_object_get_type ()))
+
+typedef struct TotemObject Totem;
+typedef struct TotemObject TotemObject;
+
+typedef struct {
+ GObjectClass parent_class;
+
+ void (*file_opened) (Totem *totem, const char *mrl);
+ void (*file_closed) (Totem *totem, const char *mrl);
+} TotemObjectClass;
+
+GType totem_object_get_type (void);
void totem_action_exit (Totem *totem);
void totem_action_play (Totem *totem);
@@ -70,4 +90,7 @@ void totem_action_error (const char *title,
void totem_action_play_media_device (Totem *totem,
const char *device);
+gboolean totem_is_fullscreen (Totem *totem);
+gboolean totem_is_playing (Totem *totem);
+
#endif /* __TOTEM_H__ */