diff options
author | Bastien Nocera <hadess@hadess.net> | 2007-04-03 23:27:33 +0000 |
---|---|---|
committer | Bastien Nocera <hadess@src.gnome.org> | 2007-04-03 23:27:33 +0000 |
commit | c6872d0c8dd03a5cca345586c647225e5157a155 (patch) | |
tree | f18a9b3dc4d3eb3ad1f1df52f777bd72601181c1 | |
parent | ca2cd82a9aef40c5c315b5d29351b9cf23cdc08a (diff) | |
download | totem-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
35 files changed, 3261 insertions, 57 deletions
@@ -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 *)®ister_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__ */ |