summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Persch <chpe@cvs.gnome.org>2006-11-15 17:21:16 +0000
committerChristian Persch <chpe@src.gnome.org>2006-11-15 17:21:16 +0000
commit08504d7f6857b23ea596e08b8afc8944fbf31850 (patch)
tree6180a5d8f5b21458e75fbab4b91eeffd8a1748e6
parent9a634aa3ae8af039131a0e816ae25419e49a23fe (diff)
downloadtotem-08504d7f6857b23ea596e08b8afc8944fbf31850.tar.gz
A browser-plugin/org_gnome_totem_PluginViewer.xml: A
2006-11-15 Christian Persch <chpe@cvs.gnome.org> * Makefile.am: * browser-plugin/Makefile.am: * browser-plugin/README: * browser-plugin/TODO: A browser-plugin/org_gnome_totem_PluginViewer.xml: A browser-plugin/totem-plugin-viewer-commands.h: A browser-plugin/totem-plugin-viewer-options.h: A browser-plugin/totem-plugin-viewer.c: * browser-plugin/totemBasicPlugin.cpp: * browser-plugin/totemBasicPlugin.h: * browser-plugin/totemComplexPlugin.cpp: * browser-plugin/totemComplexPlugin.h: * browser-plugin/totemGMPPlugin.cpp: * browser-plugin/totemGMPPlugin.h: * browser-plugin/totemMullYPlugin.cpp: * browser-plugin/totemMullYPlugin.h: * browser-plugin/totemNarrowSpacePlugin.cpp: * browser-plugin/totemNarrowSpacePlugin.h: * browser-plugin/totemPlugin.cpp: * browser-plugin/totemPlugin.h: * browser-plugin/totemPluginGlue.cpp: * configure.in: * data/mozilla-viewer.glade: * po/POTFILES.in: * src/Makefile.am: * src/backend/bvw-test.c: (on_redirect), (main): * src/plparse/totem-pl-parser.c: (totem_pl_parser_can_parse_from_data): R src/totem-mozilla-interface.xml: R src/totem-mozilla-options.h: R src/totem-mozilla-viewer.c: Make plugin / viewer interaction completely async. Bug #350297. Move plugin viewer from src/ to browser-plugin/.
-rw-r--r--ChangeLog37
-rw-r--r--Makefile.am9
-rw-r--r--browser-plugin/Makefile.am142
-rw-r--r--browser-plugin/README17
-rw-r--r--browser-plugin/TODO14
-rw-r--r--browser-plugin/org_gnome_totem_PluginViewer.xml42
-rw-r--r--browser-plugin/totem-plugin-viewer-commands.h28
-rw-r--r--browser-plugin/totem-plugin-viewer-options.h (renamed from src/totem-mozilla-options.h)28
-rw-r--r--browser-plugin/totem-plugin-viewer.c1566
-rw-r--r--browser-plugin/totemBasicPlugin.cpp6
-rw-r--r--browser-plugin/totemBasicPlugin.h2
-rw-r--r--browser-plugin/totemComplexPlugin.cpp6
-rw-r--r--browser-plugin/totemComplexPlugin.h2
-rw-r--r--browser-plugin/totemGMPPlugin.cpp6
-rw-r--r--browser-plugin/totemGMPPlugin.h2
-rw-r--r--browser-plugin/totemMullYPlugin.cpp6
-rw-r--r--browser-plugin/totemMullYPlugin.h2
-rw-r--r--browser-plugin/totemNarrowSpacePlugin.cpp6
-rw-r--r--browser-plugin/totemNarrowSpacePlugin.h2
-rw-r--r--browser-plugin/totemPlugin.cpp2348
-rw-r--r--browser-plugin/totemPlugin.h223
-rw-r--r--browser-plugin/totemPluginGlue.cpp91
-rw-r--r--configure.in131
-rw-r--r--data/mozilla-viewer.glade11
-rw-r--r--po/POTFILES.in3
-rw-r--r--src/Makefile.am38
-rw-r--r--src/backend/bvw-test.c6
-rw-r--r--src/plparse/totem-pl-parser.c6
-rw-r--r--src/totem-mozilla-interface.xml13
-rw-r--r--src/totem-mozilla-viewer.c1077
30 files changed, 3968 insertions, 1902 deletions
diff --git a/ChangeLog b/ChangeLog
index cabb35455..6ffdc8ddd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,40 @@
+2006-11-15 Christian Persch <chpe@cvs.gnome.org>
+
+ * Makefile.am:
+ * browser-plugin/Makefile.am:
+ * browser-plugin/README:
+ * browser-plugin/TODO:
+ A browser-plugin/org_gnome_totem_PluginViewer.xml:
+ A browser-plugin/totem-plugin-viewer-commands.h:
+ A browser-plugin/totem-plugin-viewer-options.h:
+ A browser-plugin/totem-plugin-viewer.c:
+ * browser-plugin/totemBasicPlugin.cpp:
+ * browser-plugin/totemBasicPlugin.h:
+ * browser-plugin/totemComplexPlugin.cpp:
+ * browser-plugin/totemComplexPlugin.h:
+ * browser-plugin/totemGMPPlugin.cpp:
+ * browser-plugin/totemGMPPlugin.h:
+ * browser-plugin/totemMullYPlugin.cpp:
+ * browser-plugin/totemMullYPlugin.h:
+ * browser-plugin/totemNarrowSpacePlugin.cpp:
+ * browser-plugin/totemNarrowSpacePlugin.h:
+ * browser-plugin/totemPlugin.cpp:
+ * browser-plugin/totemPlugin.h:
+ * browser-plugin/totemPluginGlue.cpp:
+ * configure.in:
+ * data/mozilla-viewer.glade:
+ * po/POTFILES.in:
+ * src/Makefile.am:
+ * src/backend/bvw-test.c: (on_redirect), (main):
+ * src/plparse/totem-pl-parser.c:
+ (totem_pl_parser_can_parse_from_data):
+ R src/totem-mozilla-interface.xml:
+ R src/totem-mozilla-options.h:
+ R src/totem-mozilla-viewer.c:
+
+ Make plugin / viewer interaction completely async. Bug #350297.
+ Move plugin viewer from src/ to browser-plugin/.
+
============ Version 2.17.3
2006-11-15 Bastien Nocera <hadess@hadess.net>
diff --git a/Makefile.am b/Makefile.am
index 331ab17b1..ba1bef77b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,8 @@
-SUBDIRS = po data src browser-plugin help
+SUBDIRS = po data src help
-install-data-local:
- @$(NORMAL_INSTALL)
+if ENABLE_BROWSER_PLUGINS
+SUBDIRS += browser-plugin
+endif
EXTRA_DIST = \
COPYING.LIB \
@@ -25,4 +26,4 @@ DISTCLEANFILES = intltool-extract intltool-merge intltool-update \
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = totem-plparser.pc
-DISTCHECK_CONFIGURE_FLAGS = --disable-scrollkeeper \ No newline at end of file
+DISTCHECK_CONFIGURE_FLAGS = --disable-scrollkeeper
diff --git a/browser-plugin/Makefile.am b/browser-plugin/Makefile.am
index 5b2fd578d..1dd0a5dc4 100644
--- a/browser-plugin/Makefile.am
+++ b/browser-plugin/Makefile.am
@@ -3,6 +3,8 @@ SUBDIRS = idl
plugindir = $(libdir)/mozilla/plugins
plugin_LTLIBRARIES =
+BUILT_SOURCES =
+
EXTRA_DIST = \
plugin.symbols \
TODO
@@ -11,7 +13,65 @@ gecko_include_subdirs = \
. \
docshell \
dom \
- necko
+ necko \
+ xpcom
+
+# Totem Plugin Viewer
+
+libexec_PROGRAMS = totem-plugin-viewer
+
+totem_plugin_viewer_SOURCES = \
+ totem-plugin-viewer.c \
+ totem-plugin-viewer-interface.h \
+ totem-plugin-viewer-commands.h \
+ totem-plugin-viewer-options.h
+
+totem_plugin_viewer_CPPFLAGS = \
+ -D_REENTRANT \
+ -DDBUS_API_SUBJECT_TO_CHANGE \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src \
+ -I$(top_srcdir)/src/plparse \
+ -I$(top_srcdir)/src/backend \
+ -I$(top_builddir)/src \
+ -I$(top_builddir)/src/plparse \
+ -I$(top_builddir)/src/backend \
+ -DGNOMELOCALEDIR="\"$(datadir)/locale\"" \
+ -DGCONF_PREFIX="\"/apps/totem\"" \
+ -DDATADIR="\"$(datadir)\"" \
+ -DLIBEXECDIR="\"$(libexecdir)\"" \
+ -DBINDIR="\"$(bindir)\"" \
+ -DSHAREDIR="\"$(pkgdatadir)\"" \
+ -DLOGO_NAME="\"totem_logo.png\"" \
+ $(AM_CPPFLAGS)
+
+totem_plugin_viewer_CFLAGS = \
+ $(EXTRA_GNOME_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(DBUS_CFLAGS) \
+ $(NVTV_CFLAGS) \
+ $(AM_CFLAGS)
+
+totem_plugin_viewer_LDADD = \
+ $(top_builddir)/src/backend/libbaconvideowidget.la \
+ $(top_builddir)/src/libbaconpropertiespage.la \
+ $(top_builddir)/src/libtotem_player.la \
+ $(top_builddir)/src/plparse/libtotem-plparser.la \
+ $(EXTRA_GNOME_LIBS) \
+ $(XVIDMODE_LIBS) \
+ $(DBUS_LIBS) \
+ $(NVTV_LIBS) \
+ $(XTEST_LIBS) \
+ $(X_LIBS)
+
+BUILT_SOURCES += \
+ totem-plugin-viewer-interface.h
+
+totem-plugin-viewer-interface.h: org_gnome_totem_PluginViewer.xml
+ $(DBUS_BIND) --prefix=totem_embedded --mode=glib-server $< > $@
+
+EXTRA_DIST += \
+ org_gnome_totem_PluginViewer.xml
# Totem Basic Plugin
@@ -25,7 +85,8 @@ libtotem_basic_plugin_la_SOURCES = \
totemPlugin.cpp \
totemPlugin.h \
totemBasicPlugin.cpp \
- totemBasicPlugin.h
+ totemBasicPlugin.h \
+ totem-plugin-viewer-commands.h
libtotem_basic_plugin_la_CPPFLAGS = \
-I$(top_srcdir)/src \
@@ -40,11 +101,11 @@ libtotem_basic_plugin_la_CPPFLAGS = \
-DTOTEM_PL_PARSER_MINI \
-D_REENTRANT \
-DDBUS_API_SUBJECT_TO_CHANGE \
- -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
- -DGCONF_PREFIX=\""/apps/totem"\" \
- -DDATADIR=\""$(pkgdatadir)"\" \
- -DLIBEXECDIR=\""$(libexecdir)"\" \
- -DBINDIR=\""$(bindir)"\" \
+ -DGNOMELOCALEDIR="\"$(datadir)/locale\"" \
+ -DGCONF_PREFIX="\"/apps/totem\"" \
+ -DDATADIR="\"$(pkgdatadir)\"" \
+ -DLIBEXECDIR="\"$(libexecdir)\"" \
+ -DBINDIR="\"$(bindir)\"" \
$(AM_CPPFLAGS)
libtotem_basic_plugin_la_CFLAGS = \
@@ -65,7 +126,8 @@ libtotem_basic_plugin_la_CXXFLAGS = \
libtotem_basic_plugin_la_LIBADD = \
$(top_builddir)/src/plparse/libtotem-plparser-mini.la \
$(DBUS_LIBS) \
- $(MOZILLA_LIBS)
+ $(MOZILLA_LIBS) \
+ $(LIBXPCOMGLUE_S)
libtotem_basic_plugin_la_LDFLAGS = \
-avoid-version \
@@ -87,7 +149,8 @@ libtotem_gmp_plugin_la_SOURCES = \
totemPlugin.cpp \
totemPlugin.h \
totemGMPPlugin.cpp \
- totemGMPPlugin.h
+ totemGMPPlugin.h \
+ totem-plugin-viewer-commands.h
libtotem_gmp_plugin_la_CPPFLAGS = \
-I$(top_srcdir)/src \
@@ -102,11 +165,11 @@ libtotem_gmp_plugin_la_CPPFLAGS = \
-DTOTEM_PL_PARSER_MINI \
-D_REENTRANT \
-DDBUS_API_SUBJECT_TO_CHANGE \
- -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
- -DGCONF_PREFIX=\""/apps/totem"\" \
- -DDATADIR=\""$(pkgdatadir)"\" \
- -DLIBEXECDIR=\""$(libexecdir)"\" \
- -DBINDIR=\""$(bindir)"\" \
+ -DGNOMELOCALEDIR="\"$(datadir)/locale\"" \
+ -DGCONF_PREFIX="\"/apps/totem\"" \
+ -DDATADIR="\"$(pkgdatadir)\"" \
+ -DLIBEXECDIR="\"$(libexecdir)\"" \
+ -DBINDIR="\"$(bindir)\"" \
$(AM_CPPFLAGS)
libtotem_gmp_plugin_la_CFLAGS = \
@@ -127,7 +190,8 @@ libtotem_gmp_plugin_la_CXXFLAGS = \
libtotem_gmp_plugin_la_LIBADD = \
$(top_builddir)/src/plparse/libtotem-plparser-mini.la \
$(DBUS_LIBS) \
- $(MOZILLA_LIBS)
+ $(MOZILLA_LIBS) \
+ $(LIBXPCOMGLUE_S)
libtotem_gmp_plugin_la_LDFLAGS = \
-avoid-version \
@@ -149,7 +213,8 @@ libtotem_complex_plugin_la_SOURCES = \
totemPlugin.cpp \
totemPlugin.h \
totemComplexPlugin.cpp \
- totemComplexPlugin.h
+ totemComplexPlugin.h \
+ totem-plugin-viewer-commands.h
libtotem_complex_plugin_la_CPPFLAGS = \
-I$(top_srcdir)/src \
@@ -164,11 +229,11 @@ libtotem_complex_plugin_la_CPPFLAGS = \
-DTOTEM_PL_PARSER_MINI \
-D_REENTRANT \
-DDBUS_API_SUBJECT_TO_CHANGE \
- -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
- -DGCONF_PREFIX=\""/apps/totem"\" \
- -DDATADIR=\""$(pkgdatadir)"\" \
- -DLIBEXECDIR=\""$(libexecdir)"\" \
- -DBINDIR=\""$(bindir)"\" \
+ -DGNOMELOCALEDIR="\"$(datadir)/locale\"" \
+ -DGCONF_PREFIX="\"/apps/totem\"" \
+ -DDATADIR="\"$(pkgdatadir)\"" \
+ -DLIBEXECDIR="\"$(libexecdir)\"" \
+ -DBINDIR="\"$(bindir)\"" \
$(AM_CPPFLAGS)
libtotem_complex_plugin_la_CFLAGS = \
@@ -189,7 +254,8 @@ libtotem_complex_plugin_la_CXXFLAGS = \
libtotem_complex_plugin_la_LIBADD = \
$(top_builddir)/src/plparse/libtotem-plparser-mini.la \
$(DBUS_LIBS) \
- $(MOZILLA_LIBS)
+ $(MOZILLA_LIBS) \
+ $(LIBXPCOMGLUE_S)
libtotem_complex_plugin_la_LDFLAGS = \
-avoid-version \
@@ -211,7 +277,8 @@ libtotem_narrowspace_plugin_la_SOURCES = \
totemPlugin.cpp \
totemPlugin.h \
totemNarrowSpacePlugin.cpp \
- totemNarrowSpacePlugin.h
+ totemNarrowSpacePlugin.h \
+ totem-plugin-viewer-commands.h
libtotem_narrowspace_plugin_la_CPPFLAGS = \
-I$(top_srcdir)/src \
@@ -226,11 +293,11 @@ libtotem_narrowspace_plugin_la_CPPFLAGS = \
-DTOTEM_PL_PARSER_MINI \
-D_REENTRANT \
-DDBUS_API_SUBJECT_TO_CHANGE \
- -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
- -DGCONF_PREFIX=\""/apps/totem"\" \
- -DDATADIR=\""$(pkgdatadir)"\" \
- -DLIBEXECDIR=\""$(libexecdir)"\" \
- -DBINDIR=\""$(bindir)"\" \
+ -DGNOMELOCALEDIR="\"$(datadir)/locale\"" \
+ -DGCONF_PREFIX="\"/apps/totem\"" \
+ -DDATADIR="\"$(pkgdatadir)\"" \
+ -DLIBEXECDIR="\"$(libexecdir)\"" \
+ -DBINDIR="\"$(bindir)\"" \
$(AM_CPPFLAGS)
libtotem_narrowspace_plugin_la_CFLAGS = \
@@ -251,7 +318,8 @@ libtotem_narrowspace_plugin_la_CXXFLAGS = \
libtotem_narrowspace_plugin_la_LIBADD = \
$(top_builddir)/src/plparse/libtotem-plparser-mini.la \
$(DBUS_LIBS) \
- $(MOZILLA_LIBS)
+ $(MOZILLA_LIBS) \
+ $(LIBXPCOMGLUE_S)
libtotem_narrowspace_plugin_la_LDFLAGS = \
-avoid-version \
@@ -273,7 +341,8 @@ libtotem_mully_plugin_la_SOURCES = \
totemPlugin.cpp \
totemPlugin.h \
totemMullYPlugin.cpp \
- totemMullYPlugin.h
+ totemMullYPlugin.h \
+ totem-plugin-viewer-commands.h
libtotem_mully_plugin_la_CPPFLAGS = \
-I$(top_srcdir)/src \
@@ -288,11 +357,11 @@ libtotem_mully_plugin_la_CPPFLAGS = \
-DTOTEM_PL_PARSER_MINI \
-D_REENTRANT \
-DDBUS_API_SUBJECT_TO_CHANGE \
- -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
- -DGCONF_PREFIX=\""/apps/totem"\" \
- -DDATADIR=\""$(pkgdatadir)"\" \
- -DLIBEXECDIR=\""$(libexecdir)"\" \
- -DBINDIR=\""$(bindir)"\" \
+ -DGNOMELOCALEDIR="\"$(datadir)/locale\"" \
+ -DGCONF_PREFIX="\"/apps/totem\"" \
+ -DDATADIR="\"$(pkgdatadir)\"" \
+ -DLIBEXECDIR="\"$(libexecdir)\"" \
+ -DBINDIR="\"$(bindir)\"" \
$(AM_CPPFLAGS)
libtotem_mully_plugin_la_CFLAGS = \
@@ -313,7 +382,8 @@ libtotem_mully_plugin_la_CXXFLAGS = \
libtotem_mully_plugin_la_LIBADD = \
$(top_builddir)/src/plparse/libtotem-plparser-mini.la \
$(DBUS_LIBS) \
- $(MOZILLA_LIBS)
+ $(MOZILLA_LIBS) \
+ $(LIBXPCOMGLUE_S)
libtotem_mully_plugin_la_LDFLAGS = \
-avoid-version \
diff --git a/browser-plugin/README b/browser-plugin/README
new file mode 100644
index 000000000..ba6394d46
--- /dev/null
+++ b/browser-plugin/README
@@ -0,0 +1,17 @@
+Notes on the plugin's internas
+==============================
+
+
+Special topics: Complex plugin
+==============================
+
+The complex plugin supports multiple plugins working together, see
+[http://service.real.com/help/library/guides/realone/ProductionGuide/HTML/realpgd.htm?page=htmfiles/embed.htm].
+
+To implement this, we maintain a list of totem complex plugins.
+The plugins are partitioned into classes by their 'console' name; and a
+random plugin (well, the first one instantiated) is chosen as representant.
+This one owns the plugin viewer and all viewer interaction of the linked plugins
+are done trough it. When this plugin is destroyed, we search for a new
+representant, transfer the viewer ownership to it and update the representant
+pointer in all of the classes' plugins.
diff --git a/browser-plugin/TODO b/browser-plugin/TODO
index b5a899a6f..b604cbbba 100644
--- a/browser-plugin/TODO
+++ b/browser-plugin/TODO
@@ -2,6 +2,18 @@ Plugin:
- get info about play state, URL etc back from viewer to the plugin
- support all <embed> and <object> attributes that the legacy plugins support
- there still seem to be some unnecessary symbols exported in the plugin .so's
+- use peer-2-peer DBUS instead of session bus
+- (maybe) use libdbus directly instead of dbus-glib
+- unify playlist handling into the viewer (is it possible to write a gstreamer element
+ that handles the playlist internally?)
+- make StreamAsFile use async calls; need to keep a link to the file around!!
+- put back narrowspace URL extension parsing
+- use nsCOMPtr<> once the linking has been figured out (libxpcomglue_s)
+- invert DBUS-OpenStream/NPN_GetURL order: this is necessary so we can push the real stream URI
+ to the viewer (for use as base uri for redirects)
+
+Viewer:
+- show totem logo image when waiting for click to start?
GMP plugin:
- write IDL files (where [_not_ MSDN !] to find documentation?)
@@ -9,6 +21,8 @@ GMP plugin:
Complex plugin:
- write IDL file (nsIHXPlayer.idl available, but incompatible with totem's
licence exception; is the exception needed for the *plugin* itself?)
+- implement the various 'controls' types in the viewer
+- in the viewer, cope with the 'main' window being removed? (maybe reparent to a hidden window)
NarrowSpace plugin:
- write IDL file (where to find documentation?)
diff --git a/browser-plugin/org_gnome_totem_PluginViewer.xml b/browser-plugin/org_gnome_totem_PluginViewer.xml
new file mode 100644
index 000000000..0bf4df057
--- /dev/null
+++ b/browser-plugin/org_gnome_totem_PluginViewer.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<node name="/org/gnome/totem/PluginViewer">
+ <interface name="org.gnome.totem.PluginViewer">
+ <method name="DoCommand">
+ <arg type="s" name="Command" direction="in" />
+ </method>
+ <method name="SetWindow">
+ <arg type="s" name="Controls" direction="in" />
+ <arg type="u" name="XID" direction="in" />
+ <arg type="i" name="Width" direction="in" />
+ <arg type="i" name="Height" direction="in" />
+ </method>
+ <method name="UnsetWindow">
+ <arg type="u" name="XID" direction="in" />
+ </method>
+ <method name="OpenStream">
+ <arg type="s" name="URI" direction="in" />
+ <arg type="s" name="BaseURI" direction="in" />
+ </method>
+ <method name="CloseStream" />
+ <method name="OpenURI">
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="totem_embedded_open_uri" />
+ <arg type="s" name="URI" direction="in" />
+ <arg type="s" name="BaseURI" direction="in" />
+ </method>
+ <method name="SetPlaylist">
+ <arg type="s" name="Path" direction="in" />
+ <arg type="s" name="URI" direction="in" />
+ <arg type="s" name="BaseURI" direction="in" />
+ </method>
+ <method name="SetLocalFile">
+ <arg type="s" name="Path" direction="in" />
+ <arg type="s" name="URI" direction="in" />
+ <arg type="s" name="BaseURI" direction="in" />
+ </method>
+
+ <signal name="ButtonPress" />
+ <signal name="StartStream" />
+ <signal name="StopStream" />
+ </interface>
+</node>
diff --git a/browser-plugin/totem-plugin-viewer-commands.h b/browser-plugin/totem-plugin-viewer-commands.h
new file mode 100644
index 000000000..631d500ef
--- /dev/null
+++ b/browser-plugin/totem-plugin-viewer-commands.h
@@ -0,0 +1,28 @@
+/* Totem Plugin Viewer commands
+ *
+ * Copyright © 2006 Christian Persch
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __TOTEM_PLUGIN_VIEWER_COMMANDS__
+#define __TOTEM_PLUGIN_VIEWER_COMMANDS__
+
+#define TOTEM_COMMAND_PLAY "Play"
+#define TOTEM_COMMAND_PAUSE "Pause"
+#define TOTEM_COMMAND_STOP "Stop"
+
+#endif /* !__TOTEM_PLUGIN_VIEWER_COMMANDS__ */
diff --git a/src/totem-mozilla-options.h b/browser-plugin/totem-plugin-viewer-options.h
index 6a2359000..0bd595513 100644
--- a/src/totem-mozilla-options.h
+++ b/browser-plugin/totem-plugin-viewer-options.h
@@ -1,6 +1,6 @@
-/* Totem Mozilla plugin
+/* Totem Plugin Viewer options
*
- * Copyright (C) <2005> Bastien Nocera <hadess@hadess.net>
+ * Copyright © 2005 Bastien Nocera <hadess@hadess.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -18,16 +18,22 @@
* Boston, MA 02111-1307, USA.
*/
-#define TOTEM_OPTION_XID "xid"
-#define TOTEM_OPTION_WIDTH "width"
-#define TOTEM_OPTION_HEIGHT "height"
-#define TOTEM_OPTION_URL "url"
-#define TOTEM_OPTION_CONTROLS_HIDDEN "nocontrols"
-#define TOTEM_OPTION_STATUSBAR "statusbar"
-#define TOTEM_OPTION_HREF "href"
-#define TOTEM_OPTION_TARGET "target"
+#ifndef __TOTEM_PLUGIN_VIEWER_OPTIONS_H__
+#define __TOTEM_PLUGIN_VIEWER_OPTIONS_H__
+
+#define TOTEM_PLUGIN_VIEWER_INTERFACE_NAME "org.gnome.totem.PluginViewer"
+#define TOTEM_PLUGIN_VIEWER_NAME_TEMPLATE "org.gnome.totem.PluginViewer_%d"
+#define TOTEM_PLUGIN_VIEWER_DBUS_PATH "/org/gnome/totem/PluginViewer"
+
+#define TOTEM_OPTION_BASE_URI "base-uri"
+#define TOTEM_OPTION_CONTROLS_HIDDEN "no-controls"
#define TOTEM_OPTION_HIDDEN "hidden"
#define TOTEM_OPTION_MIMETYPE "mimetype"
+#define TOTEM_OPTION_NOAUTOSTART "no-autostart"
#define TOTEM_OPTION_PLAYLIST "playlist"
+#define TOTEM_OPTION_PLUGIN_TYPE "plugin-type"
#define TOTEM_OPTION_REPEAT "repeat"
-#define TOTEM_OPTION_NOAUTOSTART "noautostart"
+#define TOTEM_OPTION_USER_AGENT "user-agent"
+#define TOTEM_OPTION_STATUSBAR "statusbar"
+
+#endif /* !__TOTEM_PLUGIN_VIEWER_OPTIONS_H__ */
diff --git a/browser-plugin/totem-plugin-viewer.c b/browser-plugin/totem-plugin-viewer.c
new file mode 100644
index 000000000..079da7713
--- /dev/null
+++ b/browser-plugin/totem-plugin-viewer.c
@@ -0,0 +1,1566 @@
+/* Totem Plugin Viewer
+ *
+ * Copyright © 2004-2006 Bastien Nocera <hadess@hadess.net>
+ * Copyright © 2002 David A. Schleef <ds@schleef.org>
+ * Copyright © 2006 Christian Persch
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <gconf/gconf-client.h>
+
+#include <totem-pl-parser.h>
+
+#include <dbus/dbus-glib.h>
+
+#include <libgnomevfs/gnome-vfs.h>
+#include <libgnomevfs/gnome-vfs-mime-handlers.h>
+
+#include "bacon-video-widget.h"
+#include "totem-interface.h"
+#include "totem-statusbar.h"
+#include "bacon-volume.h"
+#include "video-utils.h"
+
+#include "totem-plugin-viewer-commands.h"
+#include "totem-plugin-viewer-options.h"
+
+GtkWidget *totem_statusbar_create (void);
+GtkWidget *totem_volume_create (void);
+
+#define VOLUME_DOWN_OFFSET -8
+#define VOLUME_UP_OFFSET 8
+
+/* For newer D-Bus version */
+#ifndef DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT
+#define DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT 0
+#endif
+
+typedef enum {
+ STATE_PLAYING,
+ STATE_PAUSED,
+ STATE_STOPPED,
+ LAST_STATE
+} TotemStates;
+
+typedef enum {
+ TOTEM_PLUGIN_TYPE_BASIC,
+ TOTEM_PLUGIN_TYPE_GMP,
+ TOTEM_PLUGIN_TYPE_COMPLEX,
+ TOTEM_PLUGIN_TYPE_NARROWSPACE,
+ TOTEM_PLUGIN_TYPE_MULLY,
+ TOTEM_PLUGIN_TYPE_LAST
+} TotemPluginType;
+
+#define TOTEM_TYPE_EMBEDDED (totem_embedded_get_type ())
+#define TOTEM_EMBEDDED(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TOTEM_TYPE_EMBEDDED, TotemEmbedded))
+#define TOTEM_EMBEDDED_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TOTEM_TYPE_EMBEDDED, TotemEmbeddedClass))
+#define TOTEM_IS_EMBEDDED(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TOTEM_TYPE_EMBEDDED))
+#define TOTEM_IS_EMBEDDED_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TOTEM_TYPE_EMBEDDED))
+#define TOTEM_EMBEDDED_GET_CLASS(o)(G_TYPE_INSTANCE_GET_CLASS ((o), TOTEM_TYPE_EMBEDDED, TotemEmbeddedClass))
+
+typedef GObjectClass TotemEmbeddedClass;
+
+typedef struct _TotemEmbedded {
+ GObject parent;
+
+ GtkWidget *window;
+ GladeXML *menuxml, *xml;
+ GtkWidget *about;
+ TotemStatusbar *statusbar;
+ int width, height;
+ const char *mimetype;
+ char *base_uri;
+ char *current_uri;
+ char *href;
+ char *target;
+ char *stream_uri;
+ BaconVideoWidget *bvw;
+ TotemStates state;
+ GdkCursor *cursor;
+
+ /* Playlist */
+ GList *playlist, *current;
+ guint parser_id;
+ int num_items;
+
+ /* Open menu item */
+ GnomeVFSMimeApplication *app;
+ GtkWidget *menu_item;
+
+ /* Seek bits */
+ GtkAdjustment *seekadj;
+ GtkWidget *seek;
+
+ /* Error */
+
+ guint type : 3; /* TotemPluginType */
+
+ guint is_browser_stream : 1;
+ guint is_playlist : 1;
+ guint controller_hidden : 1;
+ guint show_statusbar : 1;
+ guint hidden : 1;
+ guint repeat : 1;
+ guint seeking : 1;
+ guint noautostart : 1;
+ guint autostart : 1;
+} TotemEmbedded;
+
+GType totem_embedded_get_type (void);
+
+#define TOTEM_EMBEDDED_ERROR_QUARK (g_quark_from_static_string ("TotemEmbeddedErrorQuark"))
+
+enum
+{
+ TOTEM_EMBEDDED_UNKNOWN_PLUGIN_TYPE,
+ TOTEM_EMBEDDED_SETWINDOW_UNSUPPORTED_CONTROLS,
+ TOTEM_EMBEDDED_SETWINDOW_HAVE_WINDOW,
+ TOTEM_EMBEDDED_SETWINDOW_INVALID_XID,
+ TOTEM_EMBEDDED_NO_URI,
+ TOTEM_EMBEDDED_OPEN_FAILED,
+ TOTEM_EMBEDDED_UNKNOWN_COMMAND
+};
+
+G_DEFINE_TYPE (TotemEmbedded, totem_embedded, G_TYPE_OBJECT);
+static void totem_embedded_init (TotemEmbedded *emb) { }
+
+static gboolean totem_embedded_do_command (TotemEmbedded *emb, const char *command, GError **err);
+static gboolean totem_embedded_push_parser (gpointer data);
+static gboolean totem_embedded_play (TotemEmbedded *embedded, GError **error);
+
+static void totem_embedded_clear_playlist (TotemEmbedded *embedded);
+
+static void totem_embedded_set_menu (TotemEmbedded *emb, gboolean enable_copy);
+static void on_open1_activate (GtkButton *button, TotemEmbedded *emb);
+
+enum {
+ BUTTON_PRESS,
+ START_STREAM,
+ STOP_STREAM,
+ LAST_SIGNAL
+};
+static int signals[LAST_SIGNAL] = { 0 };
+
+static void
+totem_embedded_finalize (GObject *object)
+{
+ TotemEmbedded *embedded = TOTEM_EMBEDDED (object);
+
+ if (embedded->window)
+ gtk_widget_destroy (embedded->window);
+
+ if (embedded->xml)
+ g_object_unref (embedded->xml);
+ if (embedded->menuxml)
+ g_object_unref (embedded->menuxml);
+
+ /* FIXME etc */
+
+ G_OBJECT_CLASS (totem_embedded_parent_class)->finalize (object);
+}
+
+static void totem_embedded_class_init (TotemEmbeddedClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = totem_embedded_finalize;
+
+ signals[BUTTON_PRESS] =
+ g_signal_newv ("button-press",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ NULL /* class closure */,
+ NULL /* accu */, NULL /* accu data */,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0, NULL);
+ signals[START_STREAM] =
+ g_signal_newv ("start-stream",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ NULL /* class closure */,
+ NULL /* accu */, NULL /* accu data */,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0, NULL);
+ signals[STOP_STREAM] =
+ g_signal_newv ("stop-stream",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ NULL /* class closure */,
+ NULL /* accu */, NULL /* accu data */,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0, NULL);
+}
+
+static void
+totem_embedded_exit (TotemEmbedded *emb)
+{
+ //FIXME what happens when embedded, and we can't go on?
+ exit (1);
+}
+
+static void
+totem_embedded_error_and_exit (char *title, char *reason, TotemEmbedded *emb)
+{
+ /* FIXME send a signal to the plugin with the error message instead! */
+ totem_interface_error_blocking (title, reason,
+ GTK_WINDOW (emb->window));
+ totem_embedded_exit (emb);
+}
+
+static void
+totem_embedded_set_error (TotemEmbedded *emb,
+ char *primary,
+ char *secondary)
+{
+ /* FIXME */
+}
+
+static void
+totem_embedded_set_state (TotemEmbedded *emb, TotemStates state)
+{
+ GtkWidget *image;
+ GdkCursor *cursor;
+ char id[32];
+ static const char *states[] = {
+ "PLAYING",
+ "PAUSED",
+ "STOPPED",
+ "INVALID"
+ };
+
+ if (state == emb->state)
+ return;
+
+ g_message ("Viewer state: %s", states[state]);
+
+ cursor = NULL;
+ image = glade_xml_get_widget (emb->xml, "emb_pp_button_image");
+
+ switch (state) {
+ case STATE_STOPPED:
+ if (emb->href != NULL)
+ cursor = emb->cursor;
+
+ g_snprintf (id, sizeof (id), "gtk-media-play-%s",
+ gtk_widget_get_direction (image) ? "ltr" : "rtl");
+ totem_statusbar_set_text (emb->statusbar, _("Stopped"));
+ totem_statusbar_set_time_and_length (emb->statusbar, 0, 0);
+ break;
+ case STATE_PAUSED:
+ g_snprintf (id, sizeof (id), "gtk-media-play-%s",
+ gtk_widget_get_direction (image) ? "ltr" : "rtl");
+ totem_statusbar_set_text (emb->statusbar, _("Paused"));
+ break;
+ case STATE_PLAYING:
+ g_snprintf (id, sizeof (id), "gtk-media-pause");
+ totem_statusbar_set_text (emb->statusbar, _("Playing"));
+ break;
+ default:
+ break;
+ }
+
+ gtk_image_set_from_icon_name (GTK_IMAGE (image), id, GTK_ICON_SIZE_MENU);
+
+ if (emb->hidden == FALSE && cursor != NULL)
+ gdk_window_set_cursor (GTK_WIDGET (emb->bvw)->window, cursor);
+
+ emb->state = state;
+}
+
+static void
+totem_embedded_set_pp_state (TotemEmbedded *emb, gboolean state)
+{
+ GtkWidget *item;
+
+ item = glade_xml_get_widget (emb->xml, "pp_button");
+ gtk_widget_set_sensitive (item, state);
+}
+
+static gboolean
+totem_embedded_open_internal (TotemEmbedded *emb,
+ GError **error)
+{
+ GError *err = NULL;
+ gboolean retval;
+ const char *uri;
+
+ /* FIXME: stop previous content, or is that automatic ? */
+
+ if (emb->is_browser_stream)
+ uri = "fd://0";
+ else
+ uri = emb->current_uri;
+
+ if (!uri) {
+ g_set_error (error,
+ TOTEM_EMBEDDED_ERROR_QUARK,
+ TOTEM_EMBEDDED_NO_URI,
+ _("No URI to play"));
+ //FIXME totem_embedded_set_error (emb, error); |error| may be null?
+
+ return FALSE;
+ }
+
+ g_message ("totem_embedded_open_internal '%s' is-browser-stream %d", uri, emb->is_browser_stream);
+
+ bacon_video_widget_set_logo_mode (emb->bvw, FALSE);
+
+ /* FIXME: remove |err| and rely on async on_error? */
+ g_message ("BEFORE _open");
+ retval = bacon_video_widget_open (emb->bvw, uri, &err);
+ g_message ("AFTER _open");
+ if (retval == FALSE)
+ {
+ GError *errint;
+ char *primary;
+
+ /* FIXME we haven't even started sending yet! */
+ //g_signal_emit (emb, signals[STOP_STREAM], 0);
+
+ totem_embedded_set_state (emb, STATE_STOPPED);
+ bacon_video_widget_set_logo_mode (emb->bvw, TRUE);
+
+ errint = g_error_new (TOTEM_EMBEDDED_ERROR_QUARK,
+ TOTEM_EMBEDDED_OPEN_FAILED,
+ _("Totem could not play '%s'"),
+ emb->current_uri);
+
+ //FIXME disp = gnome_vfs_unescape_string_for_display (totem->mrl); ?
+ primary = g_strdup_printf(_("Totem could not play '%s'"), emb->current_uri);
+ totem_embedded_set_error (emb, primary, err->message);;
+ g_free (primary);
+
+ g_propagate_error (error, err);
+
+ totem_embedded_set_pp_state (emb, FALSE);
+ } else {
+ /* FIXME this doesn't deal correctly with playlists */
+ //if (emb->autostart)
+ totem_embedded_play (emb, NULL);
+
+ //totem_embedded_set_state (emb, STATE_PAUSED);
+ totem_embedded_set_pp_state (emb, TRUE);
+ }
+
+ if (emb->is_browser_stream) {
+ totem_embedded_set_menu (emb, FALSE);
+ } else {
+ totem_embedded_set_menu (emb, TRUE);
+ }
+
+ return retval;
+}
+
+static gboolean
+totem_embedded_play (TotemEmbedded *emb,
+ GError **error)
+{
+ if (bacon_video_widget_play (emb->bvw, NULL))
+ totem_embedded_set_state (emb, STATE_PLAYING);
+
+ return TRUE;
+}
+
+static gboolean
+totem_embedded_pause (TotemEmbedded *emb,
+ GError **error)
+{
+ bacon_video_widget_pause (emb->bvw);
+ totem_embedded_set_state (emb, STATE_PAUSED);
+
+ return TRUE;
+}
+
+static gboolean
+totem_embedded_stop (TotemEmbedded *emb,
+ GError **error)
+{
+ bacon_video_widget_stop (emb->bvw);
+ totem_embedded_set_state (emb, STATE_STOPPED);
+
+ return TRUE;
+}
+
+static gboolean
+totem_embedded_do_command (TotemEmbedded *embedded,
+ const char *command,
+ GError **error)
+{
+ g_return_val_if_fail (command != NULL, FALSE);
+
+ if (strcmp (command, TOTEM_COMMAND_PLAY) == 0) {
+ return totem_embedded_play (embedded, error);
+ }
+ if (strcmp (command, TOTEM_COMMAND_PAUSE) == 0) {
+ return totem_embedded_pause (embedded, error);
+ }
+ if (strcmp (command, TOTEM_COMMAND_STOP) == 0) {
+ return totem_embedded_stop (embedded, error);
+ }
+
+ g_set_error (error,
+ TOTEM_EMBEDDED_ERROR_QUARK,
+ TOTEM_EMBEDDED_UNKNOWN_COMMAND,
+ "Unknown command '%s'", command);
+ return FALSE;
+}
+
+static void
+totem_embedded_set_uri (TotemEmbedded *emb,
+ const char *uri,
+ const char *base_uri,
+ gboolean is_browser_stream)
+{
+ char *old_uri, *old_base;
+
+ old_uri = emb->current_uri;
+ old_base = emb->base_uri;
+
+ emb->current_uri = g_strdup (uri);
+ emb->base_uri = g_strdup (base_uri);
+ emb->is_browser_stream = (is_browser_stream != FALSE);
+
+ g_free (old_uri);
+ g_free (old_base);
+}
+
+static gboolean
+totem_embedded_open_uri (TotemEmbedded *emb,
+ const char *uri,
+ const char *base_uri,
+ GError **error)
+{
+ totem_embedded_clear_playlist (emb);
+
+ bacon_video_widget_close (emb->bvw);
+
+ totem_embedded_set_uri (emb, uri, base_uri, FALSE);
+
+ return totem_embedded_open_internal (emb, error);
+}
+
+static gboolean
+totem_embedded_open_stream (TotemEmbedded *emb,
+ const char *uri,
+ const char *base_uri,
+ GError **error)
+{
+ totem_embedded_clear_playlist (emb);
+
+ bacon_video_widget_close (emb->bvw);
+
+ totem_embedded_set_uri (emb, uri, base_uri, TRUE);
+
+ /* FIXME: consume any remaining input from stdin */
+
+ return totem_embedded_open_internal (emb, error);
+}
+
+static gboolean
+totem_embedded_close_stream (TotemEmbedded *emb,
+ GError *error)
+{
+ if (!emb->is_browser_stream)
+ return TRUE;
+
+ /* FIXME this enough? */
+ bacon_video_widget_close (emb->bvw);
+
+ return TRUE;
+}
+
+static gboolean
+totem_embedded_open_playlist_item (TotemEmbedded *emb,
+ GList *item)
+{
+ gboolean eop;
+
+ if (!emb->playlist)
+ return FALSE;
+
+ eop = item == NULL;
+
+ /* Start at the head */
+ if (item == NULL)
+ item = emb->playlist;
+
+ /* FIXME: if (emb->current == item) { just start again, depending on repeat/autostart settings } */
+ emb->current = item;
+ g_assert (item != NULL);
+
+ totem_embedded_set_uri (emb,
+ (const char *) item->data,
+ emb->base_uri /* FIXME? */,
+ FALSE);
+
+ bacon_video_widget_close (emb->bvw);
+ if (totem_embedded_open_internal (emb, NULL /* FIXME */) &&
+ ((eop != FALSE && emb->repeat != FALSE)
+ || (eop == FALSE))) {
+ totem_embedded_play (emb, NULL);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+totem_embedded_set_local_file (TotemEmbedded *emb,
+ const char *path,
+ const char *uri,
+ const char *base_uri,
+ GError **error)
+{
+ char *file_uri;
+
+ g_message ("Setting the current path to %s", path);
+
+ totem_embedded_clear_playlist (emb);
+
+ file_uri = g_filename_to_uri (path, NULL, error);
+ if (!file_uri)
+ return FALSE;
+
+ /* FIXME what about |uri| param?!! */
+ totem_embedded_set_uri (emb, file_uri, base_uri, FALSE);
+ g_free (file_uri);
+
+ return totem_embedded_open_internal (emb, error);
+}
+
+static gboolean
+totem_embedded_set_playlist (TotemEmbedded *emb,
+ const char *path,
+ const char *uri,
+ const char *base_uri,
+ GError **error)
+{
+ char *file_uri;
+
+ g_message ("Setting the current playlist to %s", path);
+
+ totem_embedded_clear_playlist (emb);
+
+ file_uri = g_filename_to_uri (path, NULL, error);
+ if (!file_uri)
+ return FALSE;
+
+ totem_embedded_set_uri (emb, file_uri, base_uri, FALSE);
+ g_free (file_uri);
+
+ /* Schedule parsing on idle */
+ if (emb->parser_id == 0)
+ emb->parser_id = g_idle_add (totem_embedded_push_parser,
+ emb);
+
+ return TRUE;
+}
+
+static void
+totem_embedded_set_menu (TotemEmbedded *emb,
+ gboolean enable_copy)
+{
+ GtkWidget *menu, *item, *image;
+ GtkWidget *copy;
+ char *label;
+
+ copy = glade_xml_get_widget (emb->menuxml, "copy_location1");
+ gtk_widget_set_sensitive (copy, enable_copy);
+
+ if (emb->menu_item != NULL) {
+ gtk_widget_destroy (emb->menu_item);
+ emb->menu_item = NULL;
+ }
+ if (emb->app != NULL) {
+ gnome_vfs_mime_application_free (emb->app);
+ emb->app = NULL;
+ }
+
+ if (enable_copy == FALSE)
+ return;
+
+ if (emb->mimetype) {
+ emb->app = gnome_vfs_mime_get_default_application_for_uri
+ (emb->current_uri, emb->mimetype);
+ } else {
+ emb->app = gnome_vfs_mime_get_default_application_for_uri
+ (emb->current_uri,
+ gnome_vfs_get_mime_type_for_name (emb->current_uri));
+ }
+
+ if (emb->app == NULL)
+ return;
+
+ /* translators: this is:
+ * Open With ApplicationName
+ * as in nautilus' right-click menu */
+ label = g_strdup_printf ("_Open with \"%s\"", emb->app->name);
+ item = gtk_image_menu_item_new_with_mnemonic (label);
+ g_free (label);
+ image = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ g_signal_connect (G_OBJECT (item), "activate",
+ G_CALLBACK (on_open1_activate), emb);
+ gtk_widget_show (item);
+ emb->menu_item = item;
+
+ menu = glade_xml_get_widget (emb->menuxml, "menu");
+ gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
+}
+
+static void
+on_open1_activate (GtkButton *button, TotemEmbedded *emb)
+{
+ GList *l = NULL;
+
+ g_return_if_fail (emb->app != NULL);
+
+ /* FIXME */
+ if (emb->type == TOTEM_PLUGIN_TYPE_NARROWSPACE &&
+ emb->href != NULL) {
+ l = g_list_prepend (l, emb->href);
+ } else {
+ l = g_list_prepend (l, emb->current_uri);
+ }
+
+ /* FIXME: launch with startup ID and startup notification! */
+ if (gnome_vfs_mime_application_launch (emb->app, l) == GNOME_VFS_OK) {
+ totem_embedded_stop (emb, NULL);
+ }
+
+ g_list_free (l);
+}
+
+static void
+on_about1_activate (GtkButton *button, TotemEmbedded *emb)
+{
+ char *backend_version, *description;
+
+ const char *authors[] =
+ {
+ "Bastien Nocera <hadess@hadess.net>",
+ "Ronald Bultje <rbultje@ronald.bitfreak.net>",
+ "Christian Persch" " <" "chpe" "@" "gnome" "." "org" ">",
+ NULL
+ };
+
+ if (emb->about != NULL)
+ {
+ gtk_window_present (GTK_WINDOW (emb->about));
+ return;
+ }
+
+ backend_version = bacon_video_widget_get_backend_name (emb->bvw);
+ description = g_strdup_printf (_("Browser Plugin using %s"),
+ backend_version);
+
+ emb->about = g_object_new (GTK_TYPE_ABOUT_DIALOG,
+ "name", _("Totem Browser Plugin"),
+ "version", VERSION,
+ "copyright", _("Copyright \xc2\xa9 2002-2006 Bastien Nocera"),
+ "comments", description,
+ "authors", authors,
+ "translator-credits", _("translator-credits"),
+ "logo-icon-name", "totem",
+ NULL);
+
+ g_free (backend_version);
+ g_free (description);
+
+ totem_interface_set_transient_for (GTK_WINDOW (emb->about),
+ GTK_WINDOW (emb->window));
+
+ g_object_add_weak_pointer (G_OBJECT (emb->about),
+ (gpointer *)&emb->about);
+ g_signal_connect (G_OBJECT (emb->about), "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ gtk_widget_show (emb->about);
+}
+
+static void
+on_copy_location1_activate (GtkButton *button, TotemEmbedded *emb)
+{
+ GdkDisplay *display;
+ GtkClipboard *clip;
+ const char *uri;
+
+ if (emb->is_browser_stream) {
+ uri = emb->base_uri; /* FIXME! */
+ } else if (emb->href != NULL) {
+ uri = emb->href;
+ } else {
+ uri = emb->current_uri;
+ }
+
+ display = gtk_widget_get_display (GTK_WIDGET (emb->window));
+
+ /* Set both the middle-click and the super-paste buffers */
+ clip = gtk_clipboard_get_for_display (display,
+ GDK_SELECTION_CLIPBOARD);
+ gtk_clipboard_set_text (clip, uri, -1);
+
+ clip = gtk_clipboard_get_for_display (display,
+ GDK_SELECTION_PRIMARY);
+ gtk_clipboard_set_text (clip, uri, -1);
+}
+
+static void
+on_play_pause (GtkWidget *widget, TotemEmbedded *emb)
+{
+ if (emb->state == STATE_PLAYING) {
+ totem_embedded_pause (emb, NULL);
+ } else {
+ totem_embedded_play (emb, NULL);
+ }
+}
+
+static void
+on_got_redirect (GtkWidget *bvw, const char *mrl, TotemEmbedded *emb)
+{
+ char *new_uri = NULL;
+
+ g_message ("url: %s", emb->base_uri);
+ g_message ("redirect: %s", mrl);
+
+ bacon_video_widget_close (emb->bvw);
+
+ if (emb->current_uri)
+ new_uri = totem_resolve_relative_link (emb->current_uri, mrl);
+ /* FIXME: not sure that this is actually correct... */
+ else if (emb->base_uri)
+ new_uri = totem_resolve_relative_link (emb->base_uri, mrl);
+
+ if (!new_uri)
+ return;
+
+ g_message ("Redirecting to '%s'", new_uri);
+
+ /* FIXME: clear playlist? or replace current entry? or add a new entry? */
+ /* FIXME: use totem_embedded_open_uri? */
+
+ totem_embedded_set_uri (emb, new_uri, emb->base_uri /* FIXME? */, FALSE);
+
+ totem_embedded_set_state (emb, STATE_STOPPED);
+
+ if (totem_embedded_open_internal (emb, NULL /* FIXME? */) != FALSE)
+ totem_embedded_play (emb, NULL);
+}
+
+static gboolean
+on_video_button_press_event (BaconVideoWidget *bvw,
+ GdkEventButton *event,
+ TotemEmbedded *emb)
+{
+ guint state = event->state & gtk_accelerator_get_default_mod_mask ();
+ gboolean handled = FALSE;
+
+ //g_print ("button-press type %d button %d state %d play-state %d\n",
+ // event->type, event->button, state, emb->state);
+
+ if (event->type == GDK_BUTTON_PRESS &&
+ event->button == 1 &&
+ state == 0 &&
+ emb->state == STATE_STOPPED) {
+ g_signal_emit (emb, signals[BUTTON_PRESS], 0,
+ event->time,
+ event->button);
+ handled = TRUE;
+ }
+
+#if 0
+ if (emb->state == STATE_STOPPED) {
+ g_signal_emit (emb, signals[START_PLAY], 0);
+ }
+#ifdef TOTEM_RUN_IN_SOURCE_TREE
+ if (g_file_test ("./totem",
+ G_FILE_TEST_EXISTS) != FALSE) {
+ cmd = g_strdup_printf ("./totem %s",
+ emb->href);
+ } else
+#endif
+ {
+ cmd = g_strdup_printf (BINDIR"/totem %s",
+ emb->href);
+ }
+ /* FIXME Shouldn't this use gdk_spawn_on_screen? */
+ if (!g_spawn_command_line_async (cmd, &err)) {
+#ifdef NOTPORTED
+ /* FIXME this is unacceptable! */
+ totem_interface_error_blocking (
+ _("Failed to start stand-alone movie player"),
+ err->message,
+ GTK_WINDOW (emb->window));
+ g_error_free (err);
+#endif
+ }
+ g_free (cmd);
+#endif
+
+ else if (event->type == GDK_BUTTON_PRESS &&
+ event->button == 3 &&
+ state == 0) {
+ GtkMenu *menu;
+
+ menu = GTK_MENU (glade_xml_get_widget (emb->menuxml, "menu"));
+ gtk_menu_popup (menu, NULL, NULL, NULL, NULL,
+ event->button, event->time);
+
+ handled = TRUE;
+ }
+
+ return handled;
+}
+
+static void
+on_eos_event (GtkWidget *bvw, TotemEmbedded *emb)
+{
+ totem_embedded_set_state (emb, STATE_STOPPED);
+ gtk_adjustment_set_value (emb->seekadj, 0);
+
+ /* FIXME: the plugin needs to handle EOS itself, e.g. for QTNext */
+
+ /* No playlist if we have fd://0, right? */
+ if (emb->is_browser_stream) {
+ /* FIXME: totem_embedded_set_state missing? */
+ /* FIXME: should find a way to enable playback of the stream again without re-requesting it */
+ totem_embedded_set_pp_state (emb, FALSE);
+ /* FIXME? else if (emb->playing_nth_item == emb->playlist_num_items) ? */
+ } else if (emb->num_items == 1) {
+ if (g_str_has_prefix (emb->current_uri, "file://") != FALSE) {
+ if (bacon_video_widget_is_seekable (emb->bvw) != FALSE) {
+ bacon_video_widget_pause (emb->bvw);
+ bacon_video_widget_seek (emb->bvw, 0.0, NULL);
+ } else {
+ bacon_video_widget_close (emb->bvw);
+ totem_embedded_open_internal (emb, NULL /* FIXME? */);
+ }
+ } else {
+ bacon_video_widget_close (emb->bvw);
+ totem_embedded_open_internal (emb, NULL /* FIXME? */);
+ }
+ if (emb->repeat != FALSE && emb->autostart)
+ totem_embedded_play (emb, NULL);
+ } else if (emb->current) {
+ totem_embedded_open_playlist_item (emb, emb->current->next);
+ }
+}
+
+static void
+on_error_event (BaconVideoWidget *bvw,
+ char *message,
+ gboolean playback_stopped,
+ gboolean fatal,
+ TotemEmbedded *emb)
+{
+ if (playback_stopped) {
+ /* FIXME: necessary? */
+ if (emb->is_browser_stream)
+ g_signal_emit (emb, signals[STOP_STREAM], 0);
+
+ totem_embedded_set_state (emb, STATE_STOPPED);
+ }
+
+ if (fatal) {
+ /* FIXME: report error back to plugin */
+ exit (1);
+ }
+
+ totem_embedded_set_error (emb, _("An error occurred"), message);
+}
+
+static void
+cb_vol (GtkWidget *val, TotemEmbedded *emb)
+{
+ bacon_video_widget_set_volume (emb->bvw,
+ bacon_volume_button_get_value (BACON_VOLUME_BUTTON (val)));
+}
+
+static gboolean
+on_volume_scroll_event (GtkWidget *win, GdkEventScroll *event, TotemEmbedded *emb)
+{
+ GtkWidget *vbut;
+ int vol, offset;
+
+ switch (event->direction) {
+ case GDK_SCROLL_UP:
+ offset = VOLUME_UP_OFFSET;
+ break;
+ case GDK_SCROLL_DOWN:
+ offset = VOLUME_DOWN_OFFSET;
+ break;
+ default:
+ return FALSE;
+ }
+
+ vbut = glade_xml_get_widget (emb->xml, "volume_button");
+ vol = bacon_volume_button_get_value (BACON_VOLUME_BUTTON (vbut));
+ bacon_volume_button_set_value (BACON_VOLUME_BUTTON (vbut),
+ vol + offset);
+
+ return FALSE;
+}
+
+static void
+on_tick (GtkWidget *bvw,
+ gint64 current_time,
+ gint64 stream_length,
+ float current_position,
+ gboolean seekable,
+ TotemEmbedded *emb)
+{
+ if (emb->state != STATE_STOPPED) {
+ gtk_widget_set_sensitive (emb->seek, seekable);
+ if (emb->seeking == FALSE)
+ gtk_adjustment_set_value (emb->seekadj,
+ current_position * 65535);
+ if (stream_length == 0) {
+ totem_statusbar_set_time_and_length (emb->statusbar,
+ (int) (current_time / 1000), -1);
+ } else {
+ totem_statusbar_set_time_and_length (emb->statusbar,
+ (int) (current_time / 1000),
+ (int) (stream_length / 1000));
+ }
+ }
+}
+
+static gboolean
+on_seek_start (GtkWidget *widget, GdkEventButton *event, TotemEmbedded *emb)
+{
+ emb->seeking = TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+cb_on_seek (GtkWidget *widget, GdkEventButton *event, TotemEmbedded *emb)
+{
+ bacon_video_widget_seek (emb->bvw,
+ gtk_range_get_value (GTK_RANGE (widget)) / 65535, NULL);
+ emb->seeking = FALSE;
+
+ return FALSE;
+}
+
+#ifdef GNOME_ENABLE_DEBUG
+static void
+controls_size_allocate_cb (GtkWidget *controls,
+ GtkAllocation *allocation,
+ gpointer data)
+{
+ g_message ("Viewer: Controls height is %dpx", allocation->height);
+ g_signal_handlers_disconnect_by_func (controls, G_CALLBACK (controls_size_allocate_cb), NULL);
+}
+#endif
+
+static gboolean
+totem_embedded_construct (TotemEmbedded *emb,
+ GdkNativeWindow xid,
+ int width,
+ int height)
+{
+ GtkWidget *child, *container, *pp_button, *vbut;
+ BvwUseType type;
+ GError *err = NULL;
+ GConfClient *gc;
+ char *logo_path;
+ int volume;
+
+ if (xid != 0) {
+ g_assert (!emb->hidden);
+
+ emb->window = gtk_plug_new (xid);
+
+ /* Can't do anything before it's realized */
+ gtk_widget_realize (emb->window);
+
+ emb->xml = totem_interface_load_with_root ("mozilla-viewer.glade",
+ "content_box", _("Plugin") /* FIXME! */, TRUE,
+ GTK_WINDOW (emb->window));
+ g_assert (emb->xml);
+
+ child = glade_xml_get_widget (emb->xml, "content_box");
+ gtk_container_add (GTK_CONTAINER (emb->window), child);
+ } else {
+ g_assert (emb->hidden);
+
+ emb->xml = totem_interface_load_with_root ("mozilla-viewer.glade",
+ "window", _("Plugin") /* FIXME! */, TRUE,
+ GTK_WINDOW (emb->window));
+ g_assert (emb->xml);
+
+ emb->window = glade_xml_get_widget (emb->xml, "window");
+ }
+
+ if (emb->hidden)
+ type = BVW_USE_TYPE_AUDIO;
+ else
+ type = BVW_USE_TYPE_VIDEO;
+
+ emb->bvw = BACON_VIDEO_WIDGET (bacon_video_widget_new
+ (-1, -1, type, &err));
+
+ /* FIXME! */
+ if (emb->bvw == NULL)
+ {
+ /* FIXME! */
+ /* FIXME construct and show error message */
+ totem_embedded_error_and_exit (_("The Totem plugin could not startup."), err != NULL ? err->message : _("No reason."), emb);
+
+ if (err != NULL)
+ g_error_free (err);
+ }
+
+ logo_path = g_build_filename (SHAREDIR, LOGO_NAME, NULL);
+ bacon_video_widget_set_logo (emb->bvw, logo_path);
+ g_free (logo_path);
+
+ bacon_video_widget_set_logo_mode (emb->bvw, TRUE);
+
+ g_signal_connect (G_OBJECT(emb->bvw), "got-redirect",
+ G_CALLBACK (on_got_redirect), emb);
+ g_signal_connect (G_OBJECT (emb->bvw), "eos",
+ G_CALLBACK (on_eos_event), emb);
+ g_signal_connect (G_OBJECT (emb->bvw), "error",
+ G_CALLBACK (on_error_event), emb);
+ g_signal_connect (G_OBJECT(emb->bvw), "button-press-event",
+ G_CALLBACK (on_video_button_press_event), emb);
+ g_signal_connect (G_OBJECT(emb->bvw), "tick",
+ G_CALLBACK (on_tick), emb);
+
+ container = glade_xml_get_widget (emb->xml, "video_box");
+ gtk_container_add (GTK_CONTAINER (container), GTK_WIDGET (emb->bvw));
+ if (type == BVW_USE_TYPE_VIDEO) {
+ /* FIXME: why can't this wait until the whole window is realised? */
+ gtk_widget_realize (GTK_WIDGET (emb->bvw));
+ gtk_widget_show (GTK_WIDGET (emb->bvw));
+ }
+
+ emb->seek = glade_xml_get_widget (emb->xml, "time_hscale");
+ emb->seekadj = gtk_range_get_adjustment (GTK_RANGE (emb->seek));
+ g_signal_connect (emb->seek, "button-press-event",
+ G_CALLBACK (on_seek_start), emb);
+ g_signal_connect (emb->seek, "button-release-event",
+ G_CALLBACK (cb_on_seek), emb);
+
+ pp_button = glade_xml_get_widget (emb->xml, "pp_button");
+ g_signal_connect (G_OBJECT (pp_button), "clicked",
+ G_CALLBACK (on_play_pause), emb);
+
+ gc = gconf_client_get_default ();
+ volume = gconf_client_get_int (gc, GCONF_PREFIX"/volume", NULL);
+ g_object_unref (G_OBJECT (gc));
+
+ bacon_video_widget_set_volume (emb->bvw, volume);
+ vbut = glade_xml_get_widget (emb->xml, "volume_button");
+ bacon_volume_button_set_value (BACON_VOLUME_BUTTON (vbut), volume);
+ g_signal_connect (G_OBJECT (vbut), "value-changed",
+ G_CALLBACK (cb_vol), emb);
+ gtk_widget_add_events (vbut, GDK_SCROLL_MASK);
+ g_signal_connect (G_OBJECT (vbut), "scroll_event",
+ G_CALLBACK (on_volume_scroll_event), emb);
+
+ emb->statusbar = TOTEM_STATUSBAR (glade_xml_get_widget (emb->xml, "statusbar"));
+
+ gtk_widget_set_size_request (emb->window, width, height);
+
+#if GNOME_ENABLE_DEBUG
+ child = glade_xml_get_widget (emb->xml, "controls");
+ g_signal_connect_after (child, "size-allocate", G_CALLBACK (controls_size_allocate_cb), NULL);
+#endif
+
+ if (emb->controller_hidden != FALSE) {
+ child = glade_xml_get_widget (emb->xml, "controls");
+ gtk_widget_hide (child);
+ }
+
+ if (!emb->show_statusbar) {
+ child = glade_xml_get_widget (emb->xml, "statusbar");
+ gtk_widget_hide (child);
+ }
+
+ /* Try to make controls smaller */
+ {
+ GtkRcStyle *rcstyle;
+
+ rcstyle = gtk_rc_style_new ();
+ rcstyle->xthickness = rcstyle->ythickness = 0;
+
+ child = glade_xml_get_widget (emb->xml, "pp_button");
+ gtk_widget_modify_style (child, rcstyle);
+
+ child = glade_xml_get_widget (emb->xml, "time_hscale");
+ gtk_widget_modify_style (child, rcstyle);
+
+ child = glade_xml_get_widget (emb->xml, "volume_button");
+ gtk_widget_modify_style (child, rcstyle);
+
+ gtk_rc_style_unref (rcstyle);
+ }
+
+ totem_embedded_set_state (emb, STATE_STOPPED);
+
+ if (!emb->hidden) {
+ gtk_widget_show (emb->window);
+ }
+
+ /* popup */
+ emb->menuxml = totem_interface_load_with_root ("mozilla-viewer.glade",
+ "menu", _("Menu"), TRUE,
+ GTK_WINDOW (emb->window));
+ g_assert (emb->menuxml);
+
+ child = glade_xml_get_widget (emb->menuxml, "about1");
+ g_signal_connect (G_OBJECT (child), "activate",
+ G_CALLBACK (on_about1_activate), emb);
+ child = glade_xml_get_widget (emb->menuxml, "copy_location1");
+ g_signal_connect (G_OBJECT (child), "activate",
+ G_CALLBACK (on_copy_location1_activate), emb);
+ child = glade_xml_get_widget (emb->menuxml, "preferences1");
+ gtk_widget_hide (child);
+
+ /* Create cursor */
+ /* FIXME: this looks hideous! */
+ if (!emb->hidden) {
+ emb->cursor = gdk_cursor_new_for_display (gtk_widget_get_display (emb->window),
+ GDK_HAND1);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+totem_embedded_construct_placeholder (TotemEmbedded *emb,
+ GdkNativeWindow xid,
+ int width,
+ int height)
+{
+ GtkWidget *window, *label;
+
+ if (xid == 0)
+ return TRUE;
+
+ window = gtk_plug_new (xid);
+ /* FIXME why? */
+ gtk_widget_realize (window);
+
+ label = gtk_label_new ("Not yet supported");
+ gtk_container_add (GTK_CONTAINER (window), label);
+
+ gtk_widget_show_all (window);
+
+ return TRUE;
+}
+
+static gboolean
+totem_embedded_set_window (TotemEmbedded *embedded,
+ const char *controls,
+ guint window,
+ int width,
+ int height,
+ GError **error)
+{
+ g_print ("Viewer: SetWindow XID %u size %d:%d\n", window, width, height);
+
+ if (embedded->type == TOTEM_PLUGIN_TYPE_COMPLEX) {
+ /* FIXME!!! */
+ if (strcmp (controls, "All") != 0 &&
+ strcmp (controls, "ImageWindow") != 0) {
+ totem_embedded_construct_placeholder (embedded, (GdkNativeWindow) window, width, height);
+ return TRUE;
+ }
+ } else {
+ if (strcmp (controls, "All") != 0 &&
+ strcmp (controls, "ImageWindow") != 0) {
+ g_set_error (error,
+ TOTEM_EMBEDDED_ERROR_QUARK,
+ TOTEM_EMBEDDED_SETWINDOW_UNSUPPORTED_CONTROLS,
+ "Unsupported controls '%s'", controls);
+ return FALSE;
+ }
+ }
+
+ if (embedded->window != NULL) {
+ g_warning ("Viewer: Already have a window!");
+
+ g_set_error (error,
+ TOTEM_EMBEDDED_ERROR_QUARK,
+ TOTEM_EMBEDDED_SETWINDOW_HAVE_WINDOW,
+ "Already have a window");
+ return FALSE;
+ }
+
+ if (window == 0) {
+ g_set_error (error,
+ TOTEM_EMBEDDED_ERROR_QUARK,
+ TOTEM_EMBEDDED_SETWINDOW_INVALID_XID,
+ "Invalid XID");
+ return FALSE;
+ }
+
+ embedded->width = width;
+ embedded->height = height;
+
+ totem_embedded_construct (embedded, (GdkNativeWindow) window,
+ width, height);
+
+ return TRUE;
+}
+
+static gboolean
+totem_embedded_unset_window (TotemEmbedded *embedded,
+ guint window,
+ GError **error)
+{
+ g_warning ("UnsetWindow unimplemented");
+ return TRUE;
+}
+
+static void
+totem_embedded_clear_playlist (TotemEmbedded *embedded)
+{
+ g_list_foreach (embedded->playlist, (GFunc) g_free, NULL);
+ g_list_free (embedded->playlist);
+
+ embedded->playlist = NULL;
+ embedded->current = NULL;
+ embedded->num_items = 0;
+}
+
+static void
+entry_added (TotemPlParser *parser,
+ const char *uri,
+ const char *title,
+ const char *genre,
+ gpointer data)
+{
+ GList **list = (GList **) data;
+
+ g_print ("added URI '%s' with title '%s' genre '%s'\n", uri,
+ title ? title : "empty", genre);
+
+ //FIXMEchpe
+ //FIXME need new struct to hold that
+ *list = g_list_prepend (*list, g_strdup (uri));
+}
+
+static gboolean
+totem_embedded_push_parser (gpointer data)
+{
+ TotemEmbedded *emb = (TotemEmbedded *) data;
+ TotemPlParser *parser;
+ TotemPlParserResult res;
+ GList *list = NULL;
+
+ emb->parser_id = 0;
+
+ totem_embedded_clear_playlist (emb);
+
+ parser = totem_pl_parser_new ();
+ g_object_set (parser, "force", TRUE,
+ "disable-unsafe", TRUE,
+ NULL);
+ g_signal_connect (parser, "entry", G_CALLBACK (entry_added), &list);
+ res = totem_pl_parser_parse (parser, emb->current_uri, FALSE); /* FIXME base_uri? */
+ g_object_unref (parser);
+
+ if (res != TOTEM_PL_PARSER_RESULT_SUCCESS) {
+ //FIXME show a proper error message
+ switch (res) {
+ case TOTEM_PL_PARSER_RESULT_UNHANDLED:
+ g_print ("url '%s' unhandled\n", emb->current_uri);
+ break;
+ case TOTEM_PL_PARSER_RESULT_ERROR:
+ g_print ("error handling url '%s'\n", emb->current_uri);
+ break;
+ case TOTEM_PL_PARSER_RESULT_IGNORED:
+ g_print ("ignored url '%s'\n", emb->current_uri);
+ break;
+ default:
+ g_assert_not_reached ();
+ ;;
+ }
+ }
+
+ /* Check if we have anything in the playlist now */
+ if (list == NULL) {
+ g_message ("No playlist or playlist empty");
+ totem_embedded_set_error (emb, _("No playlist or playlist empty") /* FIXME */,
+ NULL);
+ return FALSE;
+ }
+
+ emb->playlist = g_list_reverse (list);
+ emb->num_items = g_list_length (emb->playlist);
+
+ totem_embedded_open_playlist_item (emb, NULL /* first */);
+
+ /* don't run again */
+ return FALSE;
+}
+
+G_MODULE_EXPORT GtkWidget *
+totem_volume_create (void)
+{
+ GtkWidget *widget;
+
+ widget = bacon_volume_button_new (GTK_ICON_SIZE_MENU,
+ 0, 100, -1);
+ gtk_button_set_focus_on_click (GTK_BUTTON (widget), FALSE);
+ gtk_widget_show (widget);
+
+ return widget;
+}
+
+G_MODULE_EXPORT GtkWidget *
+totem_statusbar_create (void)
+{
+ GtkWidget *widget;
+
+ widget = totem_statusbar_new ();
+ totem_statusbar_set_has_resize_grip (TOTEM_STATUSBAR (widget), FALSE);
+ gtk_widget_show (widget);
+
+ return widget;
+}
+
+static char *arg_user_agent = NULL;
+static char *arg_mime_type = NULL;
+static char **arg_remaining = NULL;
+static gboolean arg_no_controls = FALSE;
+static gboolean arg_statusbar = FALSE;
+static gboolean arg_hidden = FALSE;
+static gboolean arg_is_playlist = FALSE;
+static gboolean arg_repeat = FALSE;
+static gboolean arg_no_autostart = FALSE;
+static TotemPluginType arg_plugin_type = TOTEM_PLUGIN_TYPE_LAST;
+
+static gboolean
+parse_plugin_type (const gchar *option_name,
+ const gchar *value,
+ gpointer data,
+ GError **error)
+{
+ const char types[TOTEM_PLUGIN_TYPE_LAST][12] = {
+ "basic",
+ "gmp",
+ "complex",
+ "narrowspace",
+ "mully"
+ };
+ TotemPluginType type;
+
+ for (type = 0; type < TOTEM_PLUGIN_TYPE_LAST; ++type) {
+ if (strcmp (value, types[type]) == 0) {
+ arg_plugin_type = type;
+ return TRUE;
+ }
+ }
+
+ g_print ("Unknown plugin type '%s'\n", value);
+ exit (1);
+}
+
+static GOptionEntry option_entries [] =
+{
+ { TOTEM_OPTION_PLUGIN_TYPE, 0, 0, G_OPTION_ARG_CALLBACK, parse_plugin_type, NULL, NULL },
+ { TOTEM_OPTION_USER_AGENT, 0, 0, G_OPTION_ARG_STRING, &arg_user_agent, NULL, NULL },
+ { TOTEM_OPTION_MIMETYPE, 0, 0, G_OPTION_ARG_STRING, &arg_mime_type, NULL, NULL },
+ { TOTEM_OPTION_CONTROLS_HIDDEN, 0, 0, G_OPTION_ARG_NONE, &arg_no_controls, NULL, NULL },
+ { TOTEM_OPTION_STATUSBAR, 0, 0, G_OPTION_ARG_NONE, &arg_statusbar, NULL, NULL },
+ { TOTEM_OPTION_HIDDEN, 0, 0, G_OPTION_ARG_NONE, &arg_hidden, NULL, NULL },
+ { TOTEM_OPTION_PLAYLIST, 0, 0, G_OPTION_ARG_NONE, &arg_is_playlist, NULL, NULL },
+ { TOTEM_OPTION_REPEAT, 0, 0, G_OPTION_ARG_NONE, &arg_repeat, NULL, NULL },
+ { TOTEM_OPTION_NOAUTOSTART, 0, 0, G_OPTION_ARG_NONE, &arg_no_autostart, NULL, NULL },
+ { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY /* STRING? */, &arg_remaining, NULL },
+ { NULL }
+};
+
+#include "totem-plugin-viewer-interface.h"
+
+int main (int argc, char **argv)
+{
+ TotemEmbedded *emb;
+ DBusGProxy *proxy;
+ DBusGConnection *conn;
+ guint res;
+ GError *e = NULL;
+ char svcname[256];
+
+ bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+#ifdef GNOME_ENABLE_DEBUG
+ {
+ int i;
+ g_print ("Viewer: PID %d, args: ", getpid ());
+ for (i = 0; i < argc; i++)
+ g_print ("%s ", argv[i]);
+ g_print ("\n");
+ }
+#endif
+
+ if (XInitThreads () == 0)
+ {
+ gtk_init (&argc, &argv);
+ totem_embedded_error_and_exit (_("Could not initialise the thread-safe libraries."), _("Verify your system installation. The Totem plugin will now exit."), NULL);
+ }
+
+ g_thread_init (NULL);
+ dbus_g_thread_init ();
+
+#ifdef GNOME_ENABLE_DEBUG
+{
+ const char *env;
+
+ env = g_getenv ("TOTEM_EMBEDDED_GDB");
+ if (env && g_ascii_strtoull (env, NULL, 10) == 1) {
+ char *gdbargv[6];
+ char pid[32];
+ GError *gdberr = NULL;
+ int gdbargc = 0;
+
+ g_snprintf (pid, sizeof (pid), "%d", getpid ());
+
+ gdbargv[gdbargc++] = "/usr/bin/xterm";
+ gdbargv[gdbargc++] = "-e";
+ gdbargv[gdbargc++] = "gdb";
+ gdbargv[gdbargc++] = argv[0];
+ gdbargv[gdbargc++] = pid;
+ gdbargv[gdbargc++] = NULL;
+
+ if (!g_spawn_async (NULL,
+ gdbargv,
+ NULL /* env */,
+ 0,
+ NULL, NULL,
+ NULL,
+ &gdberr)) {
+ g_warning ("Failed to spawn debugger: %s", gdberr->message);
+ g_error_free (gdberr);
+ } else {
+ g_print ("Sleeping....\n");
+ g_usleep (10* 1000 * 1000); /* 10s */
+ }
+ }
+}
+#endif
+
+ if (!gtk_init_with_args (&argc, &argv, NULL, option_entries, GETTEXT_PACKAGE, &e))
+ {
+ g_print ("%s\n", e->message);
+ g_error_free (e);
+ exit (1);
+ }
+
+ // FIXME check that ALL necessary params were given!
+ if (arg_plugin_type == TOTEM_PLUGIN_TYPE_LAST) {
+ g_warning ("Plugin type is required\n");
+ exit (1);
+ }
+
+ /* FIXME: check the UA strings of the legacy plugins themselves */
+ /* FIXME: at least hxplayer seems to send different UAs depending on the protocol!? */
+ if (arg_user_agent != NULL) {
+ g_setenv ("GNOME_VFS_HTTP_USER_AGENT", arg_user_agent, TRUE);
+ g_free (arg_user_agent);
+ arg_user_agent = NULL;
+ }
+
+ bacon_video_widget_init_backend (NULL, NULL);
+ gnome_vfs_init ();
+
+ dbus_g_object_type_install_info (TOTEM_TYPE_EMBEDDED,
+ &dbus_glib_totem_embedded_object_info);
+ g_snprintf (svcname, sizeof (svcname),
+ TOTEM_PLUGIN_VIEWER_NAME_TEMPLATE, getpid());
+
+ if (!(conn = dbus_g_bus_get (DBUS_BUS_SESSION, &e))) {
+ g_warning ("Failed to get DBUS connection: %s", e->message);
+ g_error_free (e);
+ exit (1);
+ }
+
+ proxy = dbus_g_proxy_new_for_name (conn,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus");
+ g_assert (proxy != NULL);
+
+ if (!dbus_g_proxy_call (proxy, "RequestName", &e,
+ G_TYPE_STRING, svcname,
+ G_TYPE_UINT, DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, &res,
+ G_TYPE_INVALID)) {
+ g_warning ("RequestName for '%s'' failed: %s\n",
+ svcname, e->message);
+ g_error_free (e);
+
+ exit (1);
+ }
+
+ emb = g_object_new (TOTEM_TYPE_EMBEDDED, NULL);
+
+ emb->state = LAST_STATE;
+ emb->width = -1;
+ emb->height = -1;
+ emb->controller_hidden = arg_no_controls;
+ emb->show_statusbar = arg_statusbar;
+ emb->current_uri = arg_remaining ? arg_remaining[0] : NULL;
+ emb->mimetype = arg_mime_type;
+ emb->hidden = arg_hidden;
+ emb->is_playlist = arg_is_playlist;
+ emb->repeat = arg_repeat;
+ emb->autostart = !arg_no_autostart;
+ emb->type = arg_plugin_type;
+
+ /* FIXME: register this BEFORE requesting the service name? */
+ dbus_g_connection_register_g_object (conn, TOTEM_PLUGIN_VIEWER_DBUS_PATH,
+ G_OBJECT (emb));
+
+ /* If we're hidden, construct a hidden window;
+ * else wait to be plugged in.
+ */
+ if (emb->hidden) {
+ totem_embedded_construct (emb, 0, -1, -1);
+ }
+
+ gtk_main ();
+
+ g_object_unref (emb);
+
+ g_message ("Viewer [PID %d]: exiting\n", getpid ());
+
+ return 0;
+}
diff --git a/browser-plugin/totemBasicPlugin.cpp b/browser-plugin/totemBasicPlugin.cpp
index 1704784be..790a6cd7e 100644
--- a/browser-plugin/totemBasicPlugin.cpp
+++ b/browser-plugin/totemBasicPlugin.cpp
@@ -183,7 +183,7 @@ totemScriptablePlugin::Play ()
{
NS_ENSURE_STATE (IsValid ());
- return mPlugin->Play ();
+ return mPlugin->DoCommand (TOTEM_COMMAND_PLAY);
}
NS_IMETHODIMP
@@ -191,7 +191,7 @@ totemScriptablePlugin::Rewind ()
{
NS_ENSURE_STATE (IsValid ());
- return mPlugin->Pause ();
+ return mPlugin->DoCommand (TOTEM_COMMAND_PAUSE);
}
NS_IMETHODIMP
@@ -199,5 +199,5 @@ totemScriptablePlugin::Stop ()
{
NS_ENSURE_STATE (IsValid ());
- return mPlugin->Stop ();
+ return mPlugin->DoCommand (TOTEM_COMMAND_STOP);
}
diff --git a/browser-plugin/totemBasicPlugin.h b/browser-plugin/totemBasicPlugin.h
index 57b277773..dbc15c7b6 100644
--- a/browser-plugin/totemBasicPlugin.h
+++ b/browser-plugin/totemBasicPlugin.h
@@ -40,7 +40,7 @@ class totemScriptablePlugin : public totemIBasicPlayer,
totemScriptablePlugin (totemPlugin *aPlugin);
PRBool IsValid () { return mPlugin != nsnull; }
- void UnsetPlugin () { mPlugin = nsnull; }
+ void SetPlugin (totemPlugin *aPlugin) { mPlugin = aPlugin; }
static char *PluginDescription ();
static void PluginMimeTypes (const totemPluginMimeEntry **, PRUint32 *);
diff --git a/browser-plugin/totemComplexPlugin.cpp b/browser-plugin/totemComplexPlugin.cpp
index b1db7fec6..70de3c2db 100644
--- a/browser-plugin/totemComplexPlugin.cpp
+++ b/browser-plugin/totemComplexPlugin.cpp
@@ -181,7 +181,7 @@ totemScriptablePlugin::DoPause (PRBool *_retval)
{
NS_ENSURE_STATE (IsValid ());
- nsresult rv = mPlugin->Pause ();
+ nsresult rv = mPlugin->DoCommand (TOTEM_COMMAND_PAUSE);
*_retval = PR_TRUE;
return rv;
@@ -192,7 +192,7 @@ totemScriptablePlugin::DoPlay (PRBool *_retval)
{
NS_ENSURE_STATE (IsValid ());
- nsresult rv = mPlugin->Play ();
+ nsresult rv = mPlugin->DoCommand (TOTEM_COMMAND_PLAY);
*_retval = PR_TRUE;
return rv;
@@ -203,7 +203,7 @@ totemScriptablePlugin::DoStop (PRBool *_retval)
{
NS_ENSURE_STATE (IsValid ());
- nsresult rv = mPlugin->Stop ();
+ nsresult rv = mPlugin->DoCommand (TOTEM_COMMAND_STOP);
*_retval = PR_TRUE;
return rv;
diff --git a/browser-plugin/totemComplexPlugin.h b/browser-plugin/totemComplexPlugin.h
index 8d842e823..7fa46a0de 100644
--- a/browser-plugin/totemComplexPlugin.h
+++ b/browser-plugin/totemComplexPlugin.h
@@ -40,7 +40,7 @@ class totemScriptablePlugin : public totemIComplexPlayer,
totemScriptablePlugin (totemPlugin *aPlugin);
PRBool IsValid () { return mPlugin != nsnull; }
- void UnsetPlugin () { mPlugin = nsnull; }
+ void SetPlugin (totemPlugin *aPlugin) { mPlugin = aPlugin; }
static char *PluginDescription ();
static void PluginMimeTypes (const totemPluginMimeEntry **, PRUint32 *);
diff --git a/browser-plugin/totemGMPPlugin.cpp b/browser-plugin/totemGMPPlugin.cpp
index ea95e5b7a..29b31c868 100644
--- a/browser-plugin/totemGMPPlugin.cpp
+++ b/browser-plugin/totemGMPPlugin.cpp
@@ -208,7 +208,7 @@ totemScriptablePlugin::Pause ()
{
NS_ENSURE_STATE (IsValid ());
- return mPlugin->Pause ();
+ return mPlugin->DoCommand (TOTEM_COMMAND_PAUSE);
}
NS_IMETHODIMP
@@ -216,7 +216,7 @@ totemScriptablePlugin::Play ()
{
NS_ENSURE_STATE (IsValid ());
- return mPlugin->Play ();
+ return mPlugin->DoCommand (TOTEM_COMMAND_PLAY);
}
NS_IMETHODIMP
@@ -224,5 +224,5 @@ totemScriptablePlugin::Stop ()
{
NS_ENSURE_STATE (IsValid ());
- return mPlugin->Stop ();
+ return mPlugin->DoCommand (TOTEM_COMMAND_STOP);
}
diff --git a/browser-plugin/totemGMPPlugin.h b/browser-plugin/totemGMPPlugin.h
index f2a530d42..8a54fe4e2 100644
--- a/browser-plugin/totemGMPPlugin.h
+++ b/browser-plugin/totemGMPPlugin.h
@@ -44,7 +44,7 @@ class totemScriptablePlugin : public totemIGMPPlayer,
totemScriptablePlugin (totemPlugin *aPlugin);
PRBool IsValid () { return mPlugin != nsnull; }
- void UnsetPlugin () { mPlugin = nsnull; }
+ void SetPlugin (totemPlugin *aPlugin) { mPlugin = aPlugin; }
static char *PluginDescription ();
static void PluginMimeTypes (const totemPluginMimeEntry **, PRUint32 *);
diff --git a/browser-plugin/totemMullYPlugin.cpp b/browser-plugin/totemMullYPlugin.cpp
index a60aad89d..dbd58588e 100644
--- a/browser-plugin/totemMullYPlugin.cpp
+++ b/browser-plugin/totemMullYPlugin.cpp
@@ -179,7 +179,7 @@ totemScriptablePlugin::Rewind ()
{
NS_ENSURE_STATE (IsValid ());
- return mPlugin->Pause ();
+ return mPlugin->DoCommand (TOTEM_COMMAND_PAUSE);
}
NS_IMETHODIMP
@@ -187,7 +187,7 @@ totemScriptablePlugin::Play ()
{
NS_ENSURE_STATE (IsValid ());
- return mPlugin->Play ();
+ return mPlugin->DoCommand (TOTEM_COMMAND_PLAY);
}
NS_IMETHODIMP
@@ -195,5 +195,5 @@ totemScriptablePlugin::Stop ()
{
NS_ENSURE_STATE (IsValid ());
- return mPlugin->Stop ();
+ return mPlugin->DoCommand (TOTEM_COMMAND_STOP);
}
diff --git a/browser-plugin/totemMullYPlugin.h b/browser-plugin/totemMullYPlugin.h
index 8117531f1..476523e3c 100644
--- a/browser-plugin/totemMullYPlugin.h
+++ b/browser-plugin/totemMullYPlugin.h
@@ -41,7 +41,7 @@ class totemScriptablePlugin : public totemIMullYPlayer,
totemScriptablePlugin (totemPlugin *aPlugin);
PRBool IsValid () { return mPlugin != nsnull; }
- void UnsetPlugin () { mPlugin = nsnull; }
+ void SetPlugin (totemPlugin *aPlugin) { mPlugin = aPlugin; }
static char *PluginDescription ();
static void PluginMimeTypes (const totemPluginMimeEntry **, PRUint32 *);
diff --git a/browser-plugin/totemNarrowSpacePlugin.cpp b/browser-plugin/totemNarrowSpacePlugin.cpp
index 9275b8bdc..2c22e45ac 100644
--- a/browser-plugin/totemNarrowSpacePlugin.cpp
+++ b/browser-plugin/totemNarrowSpacePlugin.cpp
@@ -181,7 +181,7 @@ totemScriptablePlugin::Play ()
{
NS_ENSURE_STATE (IsValid ());
- return mPlugin->Play ();
+ return mPlugin->DoCommand (TOTEM_COMMAND_PLAY);
}
NS_IMETHODIMP
@@ -189,7 +189,7 @@ totemScriptablePlugin::Rewind ()
{
NS_ENSURE_STATE (IsValid ());
- return mPlugin->Pause ();
+ return mPlugin->DoCommand (TOTEM_COMMAND_PAUSE);
}
NS_IMETHODIMP
@@ -197,5 +197,5 @@ totemScriptablePlugin::Stop ()
{
NS_ENSURE_STATE (IsValid ());
- return mPlugin->Stop ();
+ return mPlugin->DoCommand (TOTEM_COMMAND_STOP);
}
diff --git a/browser-plugin/totemNarrowSpacePlugin.h b/browser-plugin/totemNarrowSpacePlugin.h
index 0028a2cf8..840e9c47b 100644
--- a/browser-plugin/totemNarrowSpacePlugin.h
+++ b/browser-plugin/totemNarrowSpacePlugin.h
@@ -40,7 +40,7 @@ class totemScriptablePlugin : public totemINarrowSpacePlayer,
totemScriptablePlugin (totemPlugin *aPlugin);
PRBool IsValid () { return mPlugin != nsnull; }
- void UnsetPlugin () { mPlugin = nsnull; }
+ void SetPlugin (totemPlugin *aPlugin) { mPlugin = aPlugin; }
static char *PluginDescription ();
static void PluginMimeTypes (const totemPluginMimeEntry **, PRUint32 *);
diff --git a/browser-plugin/totemPlugin.cpp b/browser-plugin/totemPlugin.cpp
index e55a7bf21..2661b6b25 100644
--- a/browser-plugin/totemPlugin.cpp
+++ b/browser-plugin/totemPlugin.cpp
@@ -1,8 +1,8 @@
/* Totem Mozilla plugin
*
- * Copyright (C) 2004-2006 Bastien Nocera <hadess@hadess.net>
- * Copyright (C) 2002 David A. Schleef <ds@schleef.org>
- * Copyright (C) 2006 Christian Persch
+ * Copyright © 2004-2006 Bastien Nocera <hadess@hadess.net>
+ * Copyright © 2002 David A. Schleef <ds@schleef.org>
+ * Copyright © 2006 Christian Persch
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -37,7 +37,7 @@
#include <libgnomevfs/gnome-vfs-mime-utils.h>
#include "totem-pl-parser-mini.h"
-#include "totem-mozilla-options.h"
+#include "totem-plugin-viewer-options.h"
#include "npapi.h"
#include "npupp.h"
@@ -49,10 +49,27 @@
#include <nsIInterfaceRequestorUtils.h>
#include <nsIWebNavigation.h>
+#include <nsIServiceManager.h>
+#include <nsIDOMDocument.h>
+#include <nsIDOMElement.h>
+#include <nsIDOM3Node.h>
+#include <nsIIOService.h>
+#include <nsIURI.h>
+#include <nsITimer.h>
+#include <nsIComponentManager.h>
+#include <nsIServiceManager.h>
+
+/* for NS_IOSERVICE_CONTRACTID */
+#include <nsNetCID.h>
+
#define GNOME_ENABLE_DEBUG 1
/* define GNOME_ENABLE_DEBUG for more debug spew */
+/* FIXME define D() so that it prints the |this| pointer, so we can differentiate between different concurrent plugins! */
#include "debug.h"
+// really noisy debug
+#define DD(args...)
+
#include "totemPluginGlue.h"
#include "totemPlugin.h"
@@ -61,102 +78,672 @@
/* How much data bytes to request */
#define PLUGIN_STREAM_CHUNK_SIZE (8 * 1024)
-extern NPNetscapeFuncs sMozillaFuncs;
+NPNetscapeFuncs totemPlugin::sNPN;
+
+#if defined(TOTEM_COMPLEX_PLUGIN) && defined(HAVE_NSTARRAY_H)
+nsTArray<totemPlugin*> *totemPlugin::sPlugins;
+
+/* Keep the same order as totemPlugin::Control enum! */
+static const char *kControl[] = {
+ "All",
+ "ControlPanel",
+ "FFCtrl",
+ "HomeCtrl",
+ "ImageWindow",
+ "InfoPanel",
+ "InfoVolumePanel",
+ "MuteCtrl",
+ "MuteVolume",
+ "PauseButton",
+ "PlayButton",
+ "PlayOnlyButton",
+ "PositionField",
+ "PositionSlider",
+ "RWCtrl",
+ "StatusBar",
+ "StatusField",
+ "StopButton",
+ "TACCtrl",
+ "VolumeSlider",
+};
+#endif /* TOTEM_COMPLEX_PLUGIN */
void*
totemPlugin::operator new (size_t aSize) CPP_THROW_NEW
{
- void *object = ::operator new (aSize);
- if (object) {
- memset (object, 0, aSize);
- }
+ void *object = ::operator new (aSize);
+ if (object) {
+ memset (object, 0, aSize);
+ }
- return object;
+ return object;
}
totemPlugin::totemPlugin (NPP aInstance)
-: mInstance(aInstance),
- mWidth(-1),
- mHeight(-1),
- mSendFD(-1)
+: mInstance (aInstance),
+ mWidth (-1),
+ mHeight (-1),
+ mViewerFD (-1),
+#ifdef TOTEM_COMPLEX_PLUGIN
+ mAutostart (PR_FALSE),
+#else
+ mAutostart (PR_TRUE),
+#endif /* TOTEM_NARROWSPACE_PLUGIN */
+ mNeedViewer (PR_TRUE)
{
- D ("totemPlugin ctor [%p]", (void*) this);
+ D ("totemPlugin ctor [%p]", (void*) this);
+
+#if defined(TOTEM_COMPLEX_PLUGIN) && defined(HAVE_NSTARRAY_H)
+ /* Add |this| to the global plugins list */
+ NS_ASSERTION (sPlugins->IndexOf (this) == NoIndex, "WTF?");
+ if (!sPlugins->AppendElement (this)) {
+ D ("Couldn't maintain plugin list!");
+ }
+#endif /* TOTEM_COMPLEX_PLUGIN */
}
totemPlugin::~totemPlugin ()
{
- if (mScriptable) {
- mScriptable->UnsetPlugin ();
- NS_RELEASE (mScriptable);
- }
-
- if (mSendFD >= 0) {
- close (mSendFD);
- mSendFD = -1;
- }
-
- if (mPlayerPID) {
- kill (mPlayerPID, SIGKILL);
- g_spawn_close_pid (mPlayerPID);
- mPlayerPID = 0;
- }
-
- g_free (mLocal);
- g_free (mTarget);
- g_free (mSrc);
- g_free (mHref);
-
- if (mProxy)
- g_object_unref (mProxy);
-
- D ("totemPlugin dtor [%p]", (void*) this);
+#if defined(TOTEM_COMPLEX_PLUGIN) && defined(HAVE_NSTARRAY_H)
+ /* Remove us from the plugins list */
+ NS_ASSERTION (sPlugins->IndexOf (this) != NoIndex, "WTF?");
+ sPlugins->RemoveElement (this);
+
+ TransferConsole ();
+#endif /* TOTEM_COMPLEX_PLUGIN */
+
+ if (mScriptable) {
+ mScriptable->SetPlugin (nsnull);
+ NS_RELEASE (mScriptable);
+ mScriptable = nsnull;
+ }
+
+ if (mBusProxy) {
+ dbus_g_proxy_disconnect_signal (mBusProxy,
+ "NameOwnerChanged",
+ G_CALLBACK (NameOwnerChangedCallback),
+ NS_REINTERPRET_CAST (void*, this));
+ g_object_unref (mBusProxy);
+ mBusProxy = NULL;
+ }
+
+ ViewerCleanup ();
+
+ if (mTimer) {
+ mTimer->Cancel ();
+ NS_RELEASE (mTimer);
+ mTimer = nsnull;
+ }
+
+ NS_IF_RELEASE (mServiceManager);
+ NS_IF_RELEASE (mIOService);
+ NS_IF_RELEASE (mPluginDOMElement);
+ NS_IF_RELEASE (mBaseURI);
+ NS_IF_RELEASE (mRequestBaseURI);
+ NS_IF_RELEASE (mRequestURI);
+ NS_IF_RELEASE (mSrcURI);
+
+#ifdef TOTEM_GMP_PLUGIN
+ NS_IF_RELEASE (mURLURI);
+#endif
+
+#ifdef TOTEM_NARROWSPACE_PLUGIN
+ NS_IF_RELEASE (mHrefURI);
+ NS_IF_RELEASE (mQtsrcURI);
+#endif
+
+#if defined(TOTEM_COMPLEX_PLUGIN) && defined(HAVE_NSTARRAY_H)
+ NS_IF_RELEASE (mPluginOwnerDocument);
+#endif /* TOTEM_COMPLEX_PLUGIN */
+
+ D ("totemPlugin dtor [%p]", (void*) this);
}
/* public functions */
nsresult
-totemPlugin::Play ()
+totemPlugin::DoCommand (const char *aCommand)
{
- D ("play");
+ D ("DoCommand '%s'", aCommand);
- if (!mGotSvc)
+ /* FIXME: queue the action instead */
+ if (!mViewerReady)
return NS_OK;
- NS_ASSERTION (mProxy, "No DBUS proxy!");
- dbus_g_proxy_call_no_reply(mProxy, "Play",
- G_TYPE_INVALID, G_TYPE_INVALID);
+ NS_ASSERTION (mViewerProxy, "No viewer proxy");
+ dbus_g_proxy_call_no_reply (mViewerProxy,
+ "DoCommand",
+ G_TYPE_STRING, aCommand,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
return NS_OK;
}
-nsresult
-totemPlugin::Stop ()
+/* Viewer interaction */
+
+NPError
+totemPlugin::ViewerFork ()
{
- D ("stop");
+#if defined(TOTEM_COMPLEX_PLUGIN) && defined(HAVE_NSTARRAY_H)
+ /* Don't fork a viewer if we're going to use another one */
+ if (!mNeedViewer)
+ return NPERR_NO_ERROR;
+#endif /* TOTEM_COMPLEX_PLUGIN */
+
+ const char *userAgent = CallNPN_UserAgentProc (sNPN.uagent,
+ mInstance);
+ if (!userAgent) {
+ /* See https://bugzilla.mozilla.org/show_bug.cgi?id=328778 */
+ D ("User agent has more than 127 characters; fix your browser!");
+ }
- if (!mGotSvc)
- return NS_OK;
+ GPtrArray *arr = g_ptr_array_new ();
+ /* FIXME! no need to strdup, all args are const! */
- NS_ASSERTION (mProxy, "No DBUS proxy!");
- dbus_g_proxy_call_no_reply (mProxy, "Stop",
- G_TYPE_INVALID, G_TYPE_INVALID);
+ /* FIXME what use is this anyway? */
+#ifdef TOTEM_RUN_IN_SOURCE_TREE
+ if (g_file_test ("../src/totem-plugin-viewer",
+ G_FILE_TEST_EXISTS) != FALSE) {
+ g_ptr_array_add (arr, g_strdup ("../src/totem-plugin-viewer"));
+ } else {
+ g_ptr_array_add (arr,
+ g_build_filename (LIBEXECDIR, "totem-plugin-viewer", NULL));
+ }
+#else
+ g_ptr_array_add (arr,
+ g_build_filename (LIBEXECDIR, "totem-plugin-viewer", NULL));
+#endif
- return NS_OK;
+ /* So we can debug X errors in the viewer */
+ const char *sync = g_getenv ("TOTEM_EMBEDDED_DEBUG_SYNC");
+ if (sync && sync[0] == '1') {
+ g_ptr_array_add (arr, g_strdup ("--sync"));
+ }
+
+ g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_PLUGIN_TYPE));
+#if defined(TOTEM_BASIC_PLUGIN)
+ g_ptr_array_add (arr, g_strdup ("basic"));
+#elif defined(TOTEM_GMP_PLUGIN)
+ g_ptr_array_add (arr, g_strdup ("gmp"));
+#elif defined(TOTEM_COMPLEX_PLUGIN)
+ g_ptr_array_add (arr, g_strdup ("complex"));
+#elif defined(TOTEM_NARROWSPACE_PLUGIN)
+ g_ptr_array_add (arr, g_strdup ("narrowspace"));
+#elif defined(TOTEM_MULLY_PLUGIN)
+ g_ptr_array_add (arr, g_strdup ("mully"));
+#else
+#error Unknown plugin type
+#endif
+
+ if (userAgent) {
+ g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_USER_AGENT));
+ g_ptr_array_add (arr, g_strdup (userAgent));
+ }
+
+ /* FIXME: remove this */
+ if (!mMimeType.IsEmpty ()) {
+ g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_MIMETYPE));
+ g_ptr_array_add (arr, g_strdup (mMimeType.get()));
+ }
+
+ if (mControllerHidden) {
+ g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_CONTROLS_HIDDEN));
+ }
+
+ if (mShowStatusbar) {
+ g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_STATUSBAR));
+ }
+
+ if (mHidden) {
+ g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_HIDDEN));
+ }
+
+ if (mRepeat) {
+ g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_REPEAT));
+ }
+
+ if (!mAutostart) {
+ g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_NOAUTOSTART));
+ }
+
+ g_ptr_array_add (arr, NULL);
+ char **argv = (char **) g_ptr_array_free (arr, FALSE);
+
+#ifdef GNOME_ENABLE_DEBUG
+ {
+ GString *s;
+ int i;
+
+ s = g_string_new ("Launching: ");
+ for (i = 0; argv[i] != NULL; i++) {
+ g_string_append (s, argv[i]);
+ g_string_append (s, " ");
+ }
+ g_string_append (s, "\n");
+ D("%s", s->str);
+ g_string_free (s, TRUE);
+ }
+#endif
+
+ mViewerReady = PR_FALSE;
+
+ /* Don't wait forever! */
+ const PRUint32 kViewerTimeout = 30 * 1000; /* ms */
+ nsresult rv = mTimer->InitWithFuncCallback (ViewerForkTimeoutCallback,
+ NS_REINTERPRET_CAST (void*, this),
+ kViewerTimeout,
+ nsITimer::TYPE_ONE_SHOT);
+ if (NS_FAILED (rv)) {
+ D ("Failed to initialise timer");
+ return NPERR_GENERIC_ERROR;
+ }
+
+ /* FIXME: once gecko is multihead-safe, this should use gdk_spawn_on_screen_with_pipes */
+ GError *error = NULL;
+ if (g_spawn_async_with_pipes (NULL /* working directory FIXME: use $TMPDIR ? */,
+ argv,
+ NULL /* environment */,
+ GSpawnFlags(0),
+ NULL /* child setup func */, NULL,
+ &mViewerPID,
+ &mViewerFD, NULL, NULL,
+ &error) == FALSE)
+ {
+ g_warning ("Failed to spawn viewer: %s", error->message);
+ g_error_free(error);
+
+ g_strfreev (argv);
+
+ return NPERR_GENERIC_ERROR;
+ }
+
+ g_strfreev (argv);
+
+ D("Viewer spawned, PID %d", mViewerPID);
+
+ /* FIXME: can this happen? */
+ if (mViewerFD < 0) {
+ ViewerCleanup ();
+ return NPERR_GENERIC_ERROR;
+ }
+
+ /* Set mViewerFD nonblocking */
+ fcntl (mViewerFD, F_SETFL, O_NONBLOCK);
+
+ return NPERR_NO_ERROR;
}
-nsresult
-totemPlugin::Pause ()
+void
+totemPlugin::ViewerSetup ()
{
- D ("pause");
+ /* already set up */
+ if (mViewerSetUp)
+ return;
- if (!mGotSvc)
- return NS_OK;
+ mViewerSetUp = PR_TRUE;
- NS_ASSERTION (mProxy, "No DBUS proxy!");
- dbus_g_proxy_call_no_reply (mProxy, "Pause",
- G_TYPE_INVALID, G_TYPE_INVALID);
+ D ("ViewerSetup");
- return NS_OK;
+ /* Cancel timeout */
+ nsresult rv = mTimer->Cancel ();
+ if (NS_FAILED (rv)) {
+ D ("Failed to cancel timer");
+ }
+
+ mViewerProxy = dbus_g_proxy_new_for_name (mBusConnection,
+ mViewerServiceName.get (),
+ TOTEM_PLUGIN_VIEWER_DBUS_PATH,
+ TOTEM_PLUGIN_VIEWER_INTERFACE_NAME);
+
+ dbus_g_proxy_add_signal (mViewerProxy, "ButtonPress",
+ G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal (mViewerProxy,
+ "ButtonPress",
+ G_CALLBACK (ButtonPressCallback),
+ NS_REINTERPRET_CAST (void*, this),
+ NULL);
+
+ dbus_g_proxy_add_signal (mViewerProxy,
+ "StopStream",
+ G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal (mViewerProxy,
+ "StopStream",
+ G_CALLBACK (StopStreamCallback),
+ NS_REINTERPRET_CAST (void*, this),
+ NULL);
+
+ if (mHidden) {
+ ViewerReady ();
+ } else {
+ ViewerSetWindow ();
+ }
+
+#if defined(TOTEM_COMPLEX_PLUGIN) && defined(HAVE_NSTARRAY_H)
+ /* Notify all consoles */
+ PRUint32 count = sPlugins->Length ();
+ for (PRUint32 i = 0; i < count; ++i) {
+ totemPlugin *plugin = sPlugins->ElementAt (i);
+
+ if (plugin->mConsoleClassRepresentant == this)
+ plugin->UnownedViewerSetup ();
+ }
+#endif /* TOTEM_COMPLEX_PLUGIN */
+}
+
+
+void
+totemPlugin::ViewerCleanup ()
+{
+ mViewerBusAddress.SetLength (0);
+ mViewerServiceName.SetLength (0);
+
+ if (mViewerPendingCall) {
+ dbus_g_proxy_cancel_call (mViewerProxy, mViewerPendingCall);
+ mViewerPendingCall = NULL;
+ }
+
+ if (mViewerProxy) {
+ dbus_g_proxy_disconnect_signal (mViewerProxy,
+ "ButtonPress",
+ G_CALLBACK (ButtonPressCallback),
+ NS_REINTERPRET_CAST (void*, this));
+ dbus_g_proxy_disconnect_signal (mViewerProxy,
+ "StopStream",
+ G_CALLBACK (StopStreamCallback),
+ NS_REINTERPRET_CAST (void*, this));
+
+ g_object_unref (mViewerProxy);
+ mViewerProxy = NULL;
+ }
+
+ /* FIXME: we shouldn't get this! */
+ if (mViewerStream) {
+ fclose (mViewerStream);
+ mViewerStream = NULL;
+ }
+
+ if (mViewerFD >= 0) {
+ close (mViewerFD);
+ mViewerFD = -1;
+ }
+
+ if (mViewerPID) {
+ kill (mViewerPID, SIGKILL);
+ g_spawn_close_pid (mViewerPID);
+ mViewerPID = 0;
+ }
+}
+
+void
+totemPlugin::ViewerSetWindow ()
+{
+ if (mWindowSet || mWindow == 0)
+ return;
+
+ if (!mViewerProxy) {
+ D ("No viewer proxy yet, deferring SetWindow");
+ return;
+ }
+
+ /* FIXME this shouldn't happen here */
+ if (mHidden) {
+ mWindowSet = PR_TRUE;
+ ViewerReady ();
+ return;
+ }
+
+ NS_ASSERTION (mViewerPendingCall == NULL, "Have a pending call");
+
+ D ("Calling SetWindow");
+ mViewerPendingCall =
+ dbus_g_proxy_begin_call (mViewerProxy,
+ "SetWindow",
+ ViewerSetWindowCallback,
+ NS_REINTERPRET_CAST (void*, this),
+ NULL,
+#if defined(TOTEM_COMPLEX_PLUGIN) && defined(HAVE_NSTARRAY_H)
+ G_TYPE_STRING, mControls.get (),
+#else
+ G_TYPE_STRING, "All",
+#endif
+ G_TYPE_UINT, (guint) mWindow,
+ G_TYPE_INT, (gint) mWidth,
+ G_TYPE_INT, (gint) mHeight,
+ G_TYPE_INVALID);
+
+ mWindowSet = PR_TRUE;
+}
+
+void
+totemPlugin::ViewerReady ()
+{
+ D ("ViewerReady");
+
+ NS_ASSERTION (!mViewerReady, "Viewer already ready");
+
+ mViewerReady = PR_TRUE;
+
+ if (mAutostart) {
+ RequestStream ();
+ } else {
+ mWaitingForButtonPress = PR_TRUE;
+ }
+}
+
+void
+totemPlugin::ViewerButtonPressed ()
+{
+ D ("ButtonPress");
+
+#ifdef TOTEM_NARROWSPACE_PLUGIN
+ /* FIXME set href="" afterwards, so we don't try to launch again when the user clicks again? */
+ if (!mHref.IsEmpty () &&
+ !mTarget.IsEmpty ()) {
+ if (g_ascii_strcasecmp (mTarget.get (), "quicktimeplayer") == 0) {
+ D ("Launching totem with URL '%s'", mHref.get ());
+ LaunchTotem (mHref, 0 /* FIXME */);
+ return;
+ }
+ if (g_ascii_strcasecmp (mTarget.get (), "myself") == 0 ||
+ mTarget.Equals (NS_LITERAL_CSTRING ("_current")) ||
+ mTarget.Equals (NS_LITERAL_CSTRING ("_self"))) {
+ D ("Opening movie '%s'", mHref.get ());
+ /* FIXME this isn't right, we should just create a mHrefURI and instruct to load that one */
+ SetQtsrc (mHref);
+ RequestStream ();
+ return;
+ }
+
+ /* Load URL in browser. This will either open a new website,
+ * or execute some javascript.
+ */
+ nsCString href;
+ if (mHrefURI) {
+ mHrefURI->GetSpec (href);
+ } else {
+ href = mHref;
+ }
+
+ if (CallNPN_GetURLProc (sNPN.geturl,
+ mInstance,
+ href.get (),
+ mTarget.get ()) != NPERR_NO_ERROR) {
+ D ("Failed to launch URL '%s' in browser", mHref.get ());
+ }
+
+ return;
+ }
+#endif
+
+ if (!mWaitingForButtonPress)
+ return;
+
+ mWaitingForButtonPress = PR_FALSE;
+
+ /* Now is the time to start the stream */
+ if (!mAutostart &&
+ !mStream) {
+ RequestStream ();
+ }
+}
+
+void
+totemPlugin::NameOwnerChanged (const char *aName,
+ const char *aOldOwner,
+ const char *aNewOwner)
+{
+ if (!mViewerPID)
+ return;
+
+ /* Construct viewer interface name */
+ if (NS_UNLIKELY (mViewerServiceName.IsEmpty ())) {
+ char name[256];
+
+ g_snprintf (name, sizeof (name),
+ TOTEM_PLUGIN_VIEWER_NAME_TEMPLATE,
+ mViewerPID);
+ mViewerServiceName.Assign (name);
+
+ D ("Viewer DBus interface name is '%s'", mViewerServiceName.get ());
+ }
+
+ if (!mViewerServiceName.Equals (nsDependentCString (aName)))
+ return;
+
+ D ("NameOwnerChanged old-owner '%s' new-owner '%s'", aOldOwner, aNewOwner);
+
+ if (aOldOwner[0] == '\0' /* empty */ &&
+ aNewOwner[0] != '\0' /* non-empty */) {
+ if (mViewerBusAddress.Equals (nsDependentCString (aNewOwner))) {
+ D ("Already have owner, why are we notified again?");
+ } else if (!mViewerBusAddress.IsEmpty ()) {
+ D ("WTF, new owner!?");
+ } else {
+ /* This is the regular case */
+ D ("Viewer now connected to the bus");
+ }
+
+ mViewerBusAddress.Assign (aNewOwner);
+
+ ViewerSetup ();
+ } else if (!mViewerBusAddress.IsEmpty () &&
+ mViewerBusAddress.Equals (nsDependentCString (aOldOwner))) {
+ D ("Viewer lost connection!");
+
+ mViewerBusAddress.SetLength (0); /* truncate */
+ /* FIXME */
+ /* ViewerCleanup () ? */
+ /* FIXME if we're not quitting, put up error viewer */
+ }
+ /* FIXME do we really need the lost-connection case?
+ * We could just disconnect the handler in ViewerSetup
+ */
+}
+
+/* Stream handling */
+
+void
+totemPlugin::ClearRequest ()
+{
+ if (mRequestBaseURI) {
+ NS_RELEASE (mRequestBaseURI);
+ mRequestBaseURI = nsnull;
+ }
+ if (mRequestURI) {
+ NS_RELEASE (mRequestURI);
+ mRequestURI = nsnull;
+ }
+}
+
+void
+totemPlugin::RequestStream ()
+{
+ NS_ASSERTION (mViewerReady, "Viewer not ready");
+
+ if (mStream) {
+ D ("Unexpectedly have a stream!");
+ /* FIXME cancel existing stream, schedule new timer to try again */
+ return;
+ }
+
+ ClearRequest ();
+
+ /* Now work out which URL to request */
+ nsIURI *baseURI = nsnull;
+ nsIURI *requestURI = nsnull;
+
+#ifdef TOTEM_GMP_PLUGIN
+ /* Prefer filename over src */
+ if (mURLURI) {
+ requestURI = mURLURI;
+ baseURI = mSrcURI; /* FIXME: that correct? */
+ }
+#endif
+#ifdef TOTEM_NARROWSPACE_PLUGIN
+ /* Prefer qtsrc over src */
+ if (mQtsrcURI) {
+ requestURI = mQtsrcURI;
+ baseURI = mSrcURI;
+ }
+#if 0
+ if (href && !requestURL) {
+ /* FIXME this looks wrong? any real-world testcase sites around? */
+ requestURL = href;
+ }
+#endif
+#endif
+
+ /* Fallback */
+ if (!requestURI)
+ requestURI = mSrcURI;
+
+ if (!baseURI)
+ baseURI = mBaseURI;
+
+ /* Nothing to do */
+ if (!requestURI)
+ return;
+
+ NS_ADDREF (mRequestBaseURI = baseURI);
+ NS_ADDREF (mRequestURI = requestURI);
+
+ /* FIXME use the right base! */
+ nsCString baseSpec, spec;
+ baseURI->GetSpec (baseSpec);
+ requestURI->GetSpec (spec);
+
+ /* Shouldn't happen, but who knows */
+ if (spec.IsEmpty ())
+ return;
+
+ /* If the URL is supported we call OpenStream, and otherwise OpenURI. */
+ if (IsSchemeSupported (requestURI)) {
+ /* FIXME: Purge any buffered output from mViewerFD */
+ // __fpurge (mViewerFD);
+
+ mViewerPendingCall =
+ dbus_g_proxy_begin_call (mViewerProxy,
+ "OpenStream",
+ ViewerOpenStreamCallback,
+ NS_REINTERPRET_CAST (void*, this),
+ NULL,
+ G_TYPE_STRING, spec.get (),
+ G_TYPE_STRING, baseSpec.get (),
+ G_TYPE_INVALID);
+ } else {
+ mViewerPendingCall =
+ dbus_g_proxy_begin_call (mViewerProxy,
+ "OpenURI",
+ ViewerOpenURICallback,
+ NS_REINTERPRET_CAST (void*, this),
+ NULL,
+ G_TYPE_STRING, spec.get (),
+ G_TYPE_STRING, baseSpec.get (),
+ G_TYPE_INVALID);
+ }
+
+ /* FIXME: start playing in the callbacks ! */
}
void
@@ -165,72 +752,201 @@ totemPlugin::UnsetStream ()
if (!mStream)
return;
- if (CallNPN_DestroyStreamProc (sMozillaFuncs.destroystream,
+ if (CallNPN_DestroyStreamProc (sNPN.destroystream,
mInstance,
mStream,
NPRES_DONE) != NPERR_NO_ERROR) {
g_warning ("Couldn't destroy the stream");
+ /* FIXME: set mStream to NULL here too? */
return;
}
- mStream = nsnull;
+ /* Calling DestroyStream should already have set this to NULL */
+ NS_ASSERTION (!mStream, "Should not have a stream anymore");
+ mStream = nsnull; /* just to make sure */
}
+/* Callbacks */
+
/* static */ void PR_CALLBACK
totemPlugin::NameOwnerChangedCallback (DBusGProxy *proxy,
- const char *svc,
- const char *old_owner,
- const char *new_owner,
- totemPlugin *plugin)
+ const char *aName,
+ const char *aOldOwner,
+ const char *aNewOwner,
+ void *aData)
{
- D ("Received notification for '%s' old-owner '%s' new-owner '%s'",
- svc, old_owner, new_owner);
+ totemPlugin *plugin = NS_REINTERPRET_CAST (totemPlugin*, aData);
- if (plugin->mWaitForSvc &&
- strcmp (svc, plugin->mWaitForSvc) == 0) {
- plugin->mGotSvc = TRUE;
- }
+ plugin->NameOwnerChanged (aName, aOldOwner, aNewOwner);
}
/* static */ void PR_CALLBACK
-totemPlugin::StopSendingDataCallback (DBusGProxy *proxy,
- totemPlugin *plugin)
+totemPlugin::ViewerForkTimeoutCallback (nsITimer *aTimer,
+ void *aData)
{
- D("Stop sending data signal received");
+ totemPlugin *plugin = NS_REINTERPRET_CAST (totemPlugin*, aData);
+
+ D ("ViewerForkTimeoutCallback");
+
+ /* FIXME: can this really happen? */
+ NS_ASSERTION (!plugin->mViewerReady, "Viewer ready but timeout running?");
+
+ plugin->ViewerCleanup ();
+ /* FIXME start error viewer */
+}
+
+/* static */ void PR_CALLBACK
+totemPlugin::ButtonPressCallback (DBusGProxy *proxy,
+ //guint aButton,
+ //guint aTimestamp,
+ void *aData)
+{
+ totemPlugin *plugin = NS_REINTERPRET_CAST (totemPlugin*, aData);
+
+ D ("ButtonPress signal received");
+
+ plugin->ViewerButtonPressed ();
+}
+
+/* static */ void PR_CALLBACK
+totemPlugin::StopStreamCallback (DBusGProxy *proxy,
+ void *aData)
+{
+ totemPlugin *plugin = NS_REINTERPRET_CAST (totemPlugin*, aData);
+
+ D ("StopStream signal received");
- /* FIXME do it from a timer? */
plugin->UnsetStream ();
}
-char *
-totemPlugin::GetRealMimeType (const char *mimetype)
+/* static */ void PR_CALLBACK
+totemPlugin::ViewerSetWindowCallback (DBusGProxy *aProxy,
+ DBusGProxyCall *aCall,
+ void *aData)
+{
+ totemPlugin *plugin = NS_REINTERPRET_CAST (totemPlugin*, aData);
+
+ D ("SetWindow reply");
+
+ NS_ASSERTION (aCall == plugin->mViewerPendingCall, "SetWindow not the current call");
+
+ plugin->mViewerPendingCall = NULL;
+
+ GError *error = NULL;
+ if (!dbus_g_proxy_end_call (aProxy, aCall, &error, G_TYPE_INVALID)) {
+ /* FIXME: mViewerFailed = PR_TRUE */
+ g_warning ("SetWindow failed: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ plugin->ViewerReady ();
+}
+
+/* static */ void PR_CALLBACK
+totemPlugin::ViewerOpenStreamCallback (DBusGProxy *aProxy,
+ DBusGProxyCall *aCall,
+ void *aData)
+{
+ totemPlugin *plugin = NS_REINTERPRET_CAST (totemPlugin*, aData);
+
+ D ("OpenStream reply");
+
+ NS_ASSERTION (aCall == plugin->mViewerPendingCall, "OpenStream not the current call");
+
+ plugin->mViewerPendingCall = NULL;
+
+ GError *error = NULL;
+ if (!dbus_g_proxy_end_call (aProxy, aCall, &error, G_TYPE_INVALID)) {
+ g_warning ("OpenStream failed: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ /* FIXME this isn't the best way... */
+ if (plugin->mHidden &&
+ plugin->mAutostart) {
+ plugin->DoCommand (TOTEM_COMMAND_PLAY);
+ }
+
+ NS_ASSERTION (!plugin->mExpectingStream, "Already expecting a stream");
+ NS_ENSURE_TRUE (plugin->mRequestURI, );
+
+ plugin->mExpectingStream = PR_TRUE;
+
+ nsCString spec;
+ plugin->mRequestURI->GetSpec (spec);
+
+ NPError err = CallNPN_GetURLProc (sNPN.geturl,
+ plugin->mInstance,
+ spec.get (),
+ NULL);
+ if (err != NPERR_NO_ERROR) {
+ plugin->mExpectingStream = PR_FALSE;
+
+ D ("GetURL '%s' failed with error %d", spec.get (), err);
+ }
+}
+
+/* static */ void PR_CALLBACK
+totemPlugin::ViewerOpenURICallback (DBusGProxy *aProxy,
+ DBusGProxyCall *aCall,
+ void *aData)
+{
+ totemPlugin *plugin = NS_REINTERPRET_CAST (totemPlugin*, aData);
+
+ D ("OpenURI reply");
+
+ NS_ASSERTION (aCall == plugin->mViewerPendingCall, "OpenURI not the current call");
+
+ plugin->mViewerPendingCall = NULL;
+
+ GError *error = NULL;
+ if (!dbus_g_proxy_end_call (aProxy, aCall, &error, G_TYPE_INVALID)) {
+ g_warning ("OpenURI failed: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ /* FIXME this isn't the best way... */
+ if (plugin->mAutostart) {
+ plugin->DoCommand (TOTEM_COMMAND_PLAY);
+ }
+}
+
+/* Auxiliary functions */
+
+void
+totemPlugin::GetRealMimeType (const char *mimetype,
+ nsACString &_retval)
{
+ _retval.SetLength (0);
+
const totemPluginMimeEntry *mimetypes;
PRUint32 count;
-
totemScriptablePlugin::PluginMimeTypes (&mimetypes, &count);
for (PRUint32 i = 0; i < count; ++i) {
if (strcmp (mimetypes[i].mimetype, mimetype) == 0) {
- if (mimetypes[i].mime_alias != NULL)
- return g_strdup (mimetypes[i].mime_alias);
- else
- return g_strdup (mimetype);
+ if (mimetypes[i].mime_alias != NULL) {
+ _retval.Assign (mimetypes[i].mime_alias);
+ } else {
+ _retval.Assign (mimetype);
+ }
+ return;
}
}
D ("Real mime-type for '%s' not found", mimetype);
- return NULL;
}
PRBool
-totemPlugin::IsMimeTypeSupported (const char *mimetype, const char *url)
+totemPlugin::IsMimeTypeSupported (const char *mimetype,
+ const char *url)
{
- const totemPluginMimeEntry *mimetypes;
- PRUint32 count;
- const char *guessed;
+ NS_ENSURE_TRUE (mimetype, PR_FALSE);
-#if defined(TOTEM_MULLY_PLUGIN) || defined (TOTEM_GMP_PLUGIN)
+#if defined(TOTEM_MULLY_PLUGIN) || defined(TOTEM_GMP_PLUGIN)
/* We can always play those image types */
if (strcmp (mimetype, "image/jpeg") == 0)
return PR_TRUE;
@@ -242,6 +958,8 @@ totemPlugin::IsMimeTypeSupported (const char *mimetype, const char *url)
if (strcmp (mimetype, GNOME_VFS_MIME_TYPE_UNKNOWN) == 0)
return PR_TRUE;
+ const totemPluginMimeEntry *mimetypes;
+ PRUint32 count;
totemScriptablePlugin::PluginMimeTypes (&mimetypes, &count);
for (PRUint32 i = 0; i < count; ++i) {
@@ -250,7 +968,7 @@ totemPlugin::IsMimeTypeSupported (const char *mimetype, const char *url)
}
/* Not supported? Probably a broken webserver */
- guessed = gnome_vfs_get_mime_type_for_name (url);
+ const char *guessed = gnome_vfs_get_mime_type_for_name (url);
D ("Guessed mime-type '%s' for '%s'", guessed, url);
for (PRUint32 i = 0; i < count; ++i) {
@@ -278,301 +996,482 @@ totemPlugin::IsMimeTypeSupported (const char *mimetype, const char *url)
}
PRBool
-totemPlugin::IsSchemeSupported (const char *url)
+totemPlugin::IsSchemeSupported (nsIURI *aURI)
{
- if (url == NULL)
+ if (!aURI)
return PR_FALSE;
- if (g_str_has_prefix (url, "mms:") != FALSE)
+ /* FIXME: use protocol handler to find out if gecko supports this proto, instead */
+
+ PRBool value;
+ /* FIXME what about mmsh etc? */
+ if (NS_SUCCEEDED (aURI->SchemeIs ("mms", &value)) && value)
return PR_FALSE;
- if (g_str_has_prefix (url, "rtsp:") != FALSE)
+
+ if (NS_SUCCEEDED (aURI->SchemeIs ("rtsp", &value)) && value)
return PR_FALSE;
return PR_TRUE;
}
PRBool
-totemPlugin::Fork ()
+totemPlugin::ParseBoolean (const char *key,
+ const char *value,
+ PRBool default_val)
{
- GTimeVal then, now;
- GPtrArray *arr;
- char **argv;
- GError *err = NULL;
- gboolean use_fd = FALSE;
+ if (value == NULL || strcmp (value, "") == 0)
+ return default_val;
+ if (g_ascii_strcasecmp (value, "false") == 0
+ || g_ascii_strcasecmp (value, "0") == 0)
+ return PR_FALSE;
+ if (g_ascii_strcasecmp (value, "true") == 0
+ || g_ascii_strcasecmp (value, "1") == 0)
+ return PR_TRUE;
- if (mSrc == NULL) {
- g_warning ("No URLs passed!");
- return FALSE;
- }
+ D ("Unknown value '%s' for parameter '%s'", value, key);
- /* Make sure we don't get both an XID and hidden */
- if (mWindow && mHidden) {
- g_warning ("Both hidden and a window!");
- return FALSE;
- }
+ return default_val;
+}
- arr = g_ptr_array_new ();
+PRBool
+totemPlugin::GetBooleanValue (GHashTable *args,
+ const char *key,
+ PRBool default_val)
+{
+ const char *value;
-#ifdef TOTEM_RUN_IN_SOURCE_TREE
- if (g_file_test ("./totem-mozilla-viewer",
- G_FILE_TEST_EXISTS) != FALSE) {
- g_ptr_array_add (arr, g_strdup ("./totem-mozilla-viewer"));
- } else {
- g_ptr_array_add (arr,
- g_strdup (LIBEXECDIR"/totem-mozilla-viewer"));
- }
-#else
- g_ptr_array_add (arr,
- g_strdup (LIBEXECDIR"/totem-mozilla-viewer"));
-#endif
+ value = (const char *) g_hash_table_lookup (args, key);
+ if (value == NULL)
+ return default_val;
- /* Most for RealAudio streams, but also used as a replacement for
- * HIDDEN=TRUE */
- if (mWidth == 0 && mHeight == 0) {
- mWindow = 0;
- mHidden = TRUE;
- }
+ return ParseBoolean (key, value, default_val);
+}
- if (mWindow) {
- g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_XID));
- g_ptr_array_add (arr, g_strdup_printf ("%lu", mWindow));
+PRUint32
+totemPlugin::GetEnumIndex (GHashTable *args,
+ const char *key,
+ const char *values[],
+ PRUint32 n_values,
+ PRUint32 default_value)
+{
+ const char *value = (const char *) g_hash_table_lookup (args, key);
+ if (!value)
+ return default_value;
+
+ for (PRUint32 i = 0; i < n_values; ++i) {
+ if (g_ascii_strcasecmp (value, values[i]) == 0)
+ return i;
}
- if (mWidth > 0) {
- g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_WIDTH));
- g_ptr_array_add (arr, g_strdup_printf ("%d", mWidth));
+ return default_value;
+}
+
+/* Public functions for use by the scriptable plugin */
+
+nsresult
+totemPlugin::SetSrc (const nsACString& aURL)
+{
+ if (mSrcURI) {
+ NS_RELEASE (mSrcURI);
+ mSrcURI = nsnull;
}
- if (mHeight > 0) {
- g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_HEIGHT));
- g_ptr_array_add (arr, g_strdup_printf ("%d", mHeight));
+ mSrc = aURL;
+
+ /* If |src| is empty, don't resolve the URI! Otherwise we may
+ * try to load an (probably iframe) html document as our video stream.
+ */
+ if (mSrc.IsEmpty ())
+ return NS_OK;
+
+ nsresult rv = mIOService->NewURI (aURL, nsnull /* FIXME! use document charset */,
+ mBaseURI, &mSrcURI);
+ if (NS_FAILED (rv)) {
+ D ("Failed to create src URI (rv=%x)", rv);
+ mSrcURI = nsnull;
}
- if (mSrc) {
- g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_URL));
- g_ptr_array_add (arr, g_strdup (mSrc));
+ return rv;
+}
+
+#ifdef TOTEM_GMP_PLUGIN
+
+nsresult
+totemPlugin::SetURL (const nsACString& aURL)
+{
+ if (mURLURI) {
+ NS_RELEASE (mURLURI);
+ mURLURI = nsnull;
}
- if (mHref) {
- g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_HREF));
- g_ptr_array_add (arr, g_strdup (mHref));
+ /* Don't allow empty URL */
+ if (aURL.IsEmpty ())
+ return NS_OK;
+
+ /* FIXME: what is the correct base for the URL param? */
+ nsresult rv;
+ nsIURI *baseURI;
+ if (mSrcURI) {
+ baseURI = mSrcURI;
+ } else {
+ baseURI = mBaseURI;
}
- if (mTarget) {
- g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_TARGET));
- g_ptr_array_add (arr, g_strdup (mTarget));
+ rv = mIOService->NewURI (aURL, nsnull /* FIXME document charset? */,
+ baseURI, &mURLURI);
+ if (NS_FAILED (rv)) {
+ D ("Failed to create URL URI (rv=%x)", rv);
}
- if (mMimeType) {
- g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_MIMETYPE));
- g_ptr_array_add (arr, g_strdup (mMimeType));
+ /* FIXME: security checks? */
+
+ return rv;
+}
+
+#endif /* TOTEM_GMP_PLUGIN */
+
+#ifdef TOTEM_NARROWSPACE_PLUGIN
+
+nsresult
+totemPlugin::SetQtsrc (const nsACString& aURL)
+{
+ /* FIXME can qtsrc have URL extensions? */
+
+ if (mQtsrcURI) {
+ NS_RELEASE (mQtsrcURI);
+ mQtsrcURI = nsnull;
}
- if (mControllerHidden) {
- g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_CONTROLS_HIDDEN));
+ /* Don't allow empty qtsrc */
+ if (aURL.IsEmpty ())
+ return NS_OK;
+
+ nsresult rv;
+ nsIURI *baseURI;
+ if (mSrcURI) {
+ baseURI = mSrcURI;
+ } else {
+ baseURI = mBaseURI;
}
- if (mStatusbar) {
- g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_STATUSBAR));
+ rv = mIOService->NewURI (aURL, nsnull /* FIXME document charset? */,
+ baseURI, &mQtsrcURI);
+ if (NS_FAILED (rv)) {
+ D ("Failed to create QTSRC URI (rv=%x)", rv);
}
- if (mHidden) {
- g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_HIDDEN));
+ /* FIXME: security checks? */
+
+ return rv;
+}
+
+nsresult
+totemPlugin::SetHref (const nsACString& aURL)
+{
+ nsCString url, target;
+ PRBool hasExtensions = ParseURLExtensions (aURL, url, target);
+
+ D ("SetHref '%s' has-extensions %d (url: '%s' target: '%s')",
+ nsCString (aURL).get (), hasExtensions, url.get (), target.get ());
+
+ nsresult rv;
+ nsIURI *baseURI;
+ if (mQtsrcURI) {
+ baseURI = mQtsrcURI;
+ } else if (mSrcURI) {
+ baseURI = mSrcURI;
+ } else {
+ baseURI = mBaseURI;
}
- if (mRepeat) {
- g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_REPEAT));
- }
+ if (hasExtensions) {
+ rv = baseURI->Resolve (url, mHref);
- if (mNoAutostart) {
- g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_NOAUTOSTART));
+ if (!target.IsEmpty ())
+ mTarget = target;
+ } else {
+ rv = baseURI->Resolve (aURL, mHref);
}
-
- if (mIsPlaylist) {
- g_ptr_array_add (arr, g_strdup (DASHES TOTEM_OPTION_PLAYLIST));
- g_ptr_array_add (arr, g_strdup (mLocal));
- } else {
- /* mLocal is only TRUE for playlists */
- if (mIsSupportedSrc == FALSE) {
- g_ptr_array_add (arr, g_strdup (mSrc));
- } else {
- g_ptr_array_add (arr, g_strdup ("fd://0"));
- use_fd = TRUE;
- }
+ if (NS_SUCCEEDED (rv)) {
+ D ("Resolved HREF '%s'", mHref.get());
+ } else {
+ D ("Failed to resolve HREF (rv=%x)", rv);
+ mHref = hasExtensions ? url : aURL; /* save unresolved HREF */
}
- g_ptr_array_add (arr, NULL);
- argv = (char **) g_ptr_array_free (arr, FALSE);
+ return rv;
+}
-#ifdef GNOME_ENABLE_DEBUG
- {
- GString *s;
- int i;
+PRBool
+totemPlugin::ParseURLExtensions (const nsACString &aString,
+ nsACString &_url,
+ nsACString &_target)
+{
+ const nsCString string (aString);
- s = g_string_new ("Launching: ");
- for (i = 0; argv[i] != NULL; i++) {
- g_string_append (s, argv[i]);
- g_string_append (s, " ");
+ const char *str = string.get ();
+ if (str[0] != '<')
+ return PR_FALSE;
+
+ /* The expected form is "<URL> T<target> E<name=value pairs>".
+ * But since this is untrusted input from the web, we'll make sure it conforms to this!
+ */
+ const char *end = strchr (str, '>');
+ if (!end)
+ return PR_FALSE;
+
+ _url = nsDependentCSubstring (string, 1, PRUint32 (end - str - 1));
+
+ const char *ext = strstr (end, " T<");
+ if (ext) {
+ const char *extend = strchr (ext, '>');
+ if (extend) {
+ _target = nsDependentCSubstring (ext + 3, PRUint32 (extend - ext - 3));
+ }
+ }
+
+#if 0
+ ext = strstr (end, " E<");
+ if (ext) {
+ const char *extend = strchr (ext, '>');
+ if (extend) {
+ D ("E = %s", nsCString (ext + 3, PRUint32 (extend - ext - 3)).get ());
}
- g_string_append (s, "\n");
- D("%s", s->str);
- g_string_free (s, TRUE);
}
#endif
- if (g_spawn_async_with_pipes (NULL, argv, NULL,
- GSpawnFlags(0), NULL, NULL, &mPlayerPID,
- use_fd ? &mSendFD : NULL, NULL, NULL, &err) == FALSE)
+ return PR_TRUE;
+}
+
+void
+totemPlugin::LaunchTotem (const nsCString &aURL,
+ PRUint32 aTimestamp)
+{
+ const char *argv[3];
+
+#ifdef TOTEM_RUN_IN_SOURCE_TREE
+ if (g_file_test ("./totem", G_FILE_TEST_EXISTS)) {
+ argv[0] = "./totem";
+ } else
+#endif
{
- D("Spawn failed");
+ /* FIXME: g_build_filename */
+ argv[0] = BINDIR "/totem";
+ }
- if (err) {
- g_warning ("%s\n", err->message);
- g_error_free(err);
- }
+ argv[1] = aURL.get ();
+ argv[2] = NULL;
+
+ /* FIXME use startup notification and startup timestamp */
+ /* FIXME Shouldn't this use gdk_spawn_on_screen? */
+ GError *error = NULL;
+ if (!g_spawn_async (NULL /* FIXME working directory, $TMPDIR? */,
+ (char **) argv,
+ NULL /* env */,
+ GSpawnFlags (0),
+ NULL, NULL,
+ NULL,
+ &error)) {
+ /* FIXME: show an error dialogue? */
+ D ("Spawning totem failed: %s", error->message);
+ g_error_free (error);
+ }
+}
- g_strfreev (argv);
- return FALSE;
+#endif /* TOTEM_NARROWSPACE_PLUGIN */
+
+#if defined(TOTEM_COMPLEX_PLUGIN) && defined(HAVE_NSTARRAY_H)
+
+totemPlugin *
+totemPlugin::FindConsoleClassRepresentant ()
+{
+ /* FIXME: this treats "master" incorrectly */
+ if (!mSrcURI ||
+ mConsole.IsEmpty () ||
+ mConsole.Equals (NS_LITERAL_CSTRING ("_unique")) ||
+ mConsole.Equals (NS_LITERAL_CSTRING ("_master"))) {
+ D ("We're the representant for the console class");
+ return nsnull;
}
- g_strfreev (argv);
+ totemPlugin *representant = nsnull;
- D("player PID: %d", mPlayerPID);
-
- /* FIXME: not >= 0 ? */
- if (mSendFD > 0)
- fcntl(mSendFD, F_SETFL, O_NONBLOCK);
-
- /* now wait until startup is complete */
- mGotSvc = FALSE;
- mWaitForSvc = g_strdup_printf
- ("org.totem_%d.MozillaPluginService", mPlayerPID);
- D("waiting for signal %s", mWaitForSvc);
- dbus_g_proxy_add_signal (mProxy, "NameOwnerChanged",
- G_TYPE_STRING, G_TYPE_STRING,
- G_TYPE_STRING, G_TYPE_INVALID);
- dbus_g_proxy_connect_signal (mProxy, "NameOwnerChanged",
- G_CALLBACK (NameOwnerChangedCallback),
- this, NULL);
-
- /* Store this in a local, since we cannot access mScriptable if we get deleted in the loop */
- totemScriptablePlugin *scriptable = mScriptable;
- g_get_current_time (&then);
- g_time_val_add (&then, G_USEC_PER_SEC * 5);
- NS_ADDREF (scriptable);
- /* FIXME FIXME! this loop is evil! */
- do {
- g_main_context_iteration (NULL, TRUE);
- g_get_current_time (&now);
- } while (scriptable->IsValid () &&
- !mGotSvc &&
- (now.tv_sec <= then.tv_sec));
-
- if (!scriptable->IsValid ()) {
- /* we were destroyed in one of the iterations of the
- * mainloop, get out ASAP */
- D("We no longer exist");
- NS_RELEASE (scriptable);
- return FALSE;
- }
- NS_RELEASE (scriptable);
-
- dbus_g_proxy_disconnect_signal (mProxy, "NameOwnerChanged",
- G_CALLBACK (NameOwnerChangedCallback), this);
- if (!mGotSvc) {
- g_warning ("Failed to receive DBUS interface response");
- g_free (mWaitForSvc);
- mWaitForSvc = nsnull;
-
- if (mPlayerPID) {
- kill (mPlayerPID, SIGKILL);
- g_spawn_close_pid (mPlayerPID);
- mPlayerPID = 0;
+ /* Try to find a the representant of the console class */
+ PRUint32 count = sPlugins->Length ();
+ for (PRUint32 i = 0; i < count; ++i) {
+ totemPlugin *plugin = sPlugins->ElementAt (i);
+
+ PRBool equal = PR_FALSE;
+ /* FIXME: is this correct? Maybe we should use the toplevel document
+ * to allow frames (and check the frames for same-origin, obviously) ?
+ */
+ if (plugin != this &&
+ plugin->mPluginOwnerDocument == mPluginOwnerDocument &&
+ mConsole.Equals (plugin->mConsole) &&
+ plugin->mSrcURI &&
+ NS_SUCCEEDED (plugin->mSrcURI->Equals (mSrcURI, &equal)) &&
+ equal) {
+ if (plugin->mConsoleClassRepresentant) {
+ representant = plugin->mConsoleClassRepresentant;
+ } else {
+ representant = plugin;
+ }
+ break;
}
- return FALSE;
}
- g_object_unref (mProxy);
- /* now get the proxy for the player functions */
- mProxy =
- dbus_g_proxy_new_for_name (mConn, mWaitForSvc,
- "/TotemEmbedded",
- "org.totem.MozillaPluginInterface");
- dbus_g_proxy_add_signal (mProxy, "StopSendingData",
- G_TYPE_INVALID);
- dbus_g_proxy_connect_signal (mProxy, "StopSendingData",
- G_CALLBACK (StopSendingDataCallback),
- this, NULL);
+ D ("Representant for the console class is %p", (void*) representant);
- g_free (mWaitForSvc);
- mWaitForSvc = nsnull;
- D("Done forking, new proxy=%p", mProxy);
+ return representant;
+}
+
+nsresult
+totemPlugin::SetConsole (const nsACString &aConsole)
+{
+ /* Can't change console group */
+ if (!mConsole.IsEmpty ())
+ return NS_ERROR_ALREADY_INITIALIZED;
+
+ /* FIXME: we might allow this, and kill the viewer instead.
+ * Or maybe not spawn the viewer if we don't have a console yet?
+ */
+ if (mViewerPID)
+ return NS_ERROR_ALREADY_INITIALIZED;
- return TRUE;
+ mConsole = aConsole;
+
+ NS_ASSERTION (mConsoleClassRepresentant == nsnull, "Already have a representant");
+
+ mConsoleClassRepresentant = FindConsoleClassRepresentant ();
+ mNeedViewer = (nsnull == mConsoleClassRepresentant);
+
+ return NS_OK;
}
-static char *
-resolve_relative_uri (nsIURI *docURI,
- const char *uri)
+void
+totemPlugin::TransferConsole ()
{
- if (docURI) {
- nsresult rv;
- nsEmbedCString resolved;
- rv = docURI->Resolve (nsEmbedCString (uri), resolved);
- if (NS_SUCCEEDED (rv)) {
- return g_strdup (resolved.get());
+ /* Find replacement representant */
+ totemPlugin *representant = nsnull;
+
+ PRUint32 i, count = sPlugins->Length ();
+ for (i = 0; i < count; ++i) {
+ totemPlugin *plugin = sPlugins->ElementAt (i);
+
+ if (plugin->mConsoleClassRepresentant == this) {
+ representant = plugin;
+ break;
}
}
- return g_strdup (uri);
+ /* If there are no other elements in this console class, there's nothing to do */
+ if (!representant)
+ return;
+
+ D ("Transferring console from %p to %p", (void*) this, (void*) representant);
+
+ /* Store new representant in the plugins */
+ representant->mConsoleClassRepresentant = nsnull;
+ /* We can start at i since we got out when we found the first one in the loop above */
+ for ( ; i < count; ++i) {
+ totemPlugin *plugin = sPlugins->ElementAt (i);
+
+ if (plugin->mConsoleClassRepresentant == this)
+ plugin->mConsoleClassRepresentant = representant;
+ }
+
+ /* Now transfer viewer ownership */
+ if (mScriptable) {
+ NS_ASSERTION (!representant->mScriptable, "WTF");
+ representant->mScriptable = mScriptable;
+ mScriptable->SetPlugin (representant);
+ mScriptable = nsnull;
+ }
+
+ representant->mNeedViewer = PR_TRUE;
+
+ representant->mViewerPID = mViewerPID;
+ mViewerPID = 0;
+
+ representant->mViewerFD = mViewerFD;
+ mViewerFD = -1;
+
+ representant->mViewerBusAddress = mViewerBusAddress;
+ representant->mViewerServiceName = mViewerServiceName;
+
+ /* FIXME correct condition? */
+ if (mViewerSetUp)
+ representant->ViewerSetup ();
}
-#ifdef TOTEM_NARROWSPACE_PLUGIN
-static char *
-parse_url_extensions (char *href)
+void
+totemPlugin::UnownedViewerSetup ()
{
- char *uri, *s1, *s2;
+ /* already set up */
+ if (mUnownedViewerSetUp)
+ return;
- g_return_val_if_fail (href != NULL || href[0] != '<', NULL);
+ mUnownedViewerSetUp = PR_TRUE;
- s1 = href + 1;
- s2 = strchr (s1, '>');
- if (s2 == NULL)
- return g_strdup (href);
+ D ("UnownedViewerSetup");
- uri = g_strndup (s1, s2 - s1);
+ NS_ASSERTION (mConsoleClassRepresentant, "We own the viewer!?");
- return uri;
+ UnownedViewerSetWindow ();
}
-#endif
-gboolean
-totem_parse_boolean (char *key, char *value, gboolean default_val)
+void
+totemPlugin::UnownedViewerSetWindow ()
{
- if (value == NULL || strcmp (value, "") == 0)
- return default_val;
- if (g_ascii_strcasecmp (value, "false") == 0
- || g_ascii_strcasecmp (value, "0") == 0)
- return FALSE;
- if (g_ascii_strcasecmp (value, "true") == 0
- || g_ascii_strcasecmp (value, "1") == 0)
- return TRUE;
+ if (mWindowSet || mWindow == 0)
+ return;
- g_warning ("Unknown value '%s' for parameter '%s'", value, key);
- return default_val;
+ if (!mUnownedViewerSetUp) {
+ D ("No unowned viewer yet, deferring SetWindow");
+ return;
+ }
+
+ NS_ASSERTION (mConsoleClassRepresentant, "We own the viewer!");
+
+ NS_ENSURE_TRUE (mConsoleClassRepresentant->mViewerProxy, );
+
+ /* FIXME: do we need a reply callback? */
+ dbus_g_proxy_call_no_reply (mConsoleClassRepresentant->mViewerProxy,
+ "SetWindow",
+ G_TYPE_STRING, mControls.get (),
+ G_TYPE_UINT, (guint) mWindow,
+ G_TYPE_INT, (gint) mWidth,
+ G_TYPE_INT, (gint) mHeight,
+ G_TYPE_INVALID);
+
+ mWindowSet = PR_TRUE;
}
-gboolean
-totem_get_boolean_value (GHashTable *args, char *key, gboolean default_val)
+void
+totemPlugin::UnownedViewerUnsetWindow ()
{
- char *value;
+ if (!mWindowSet || mWindow == 0)
+ return;
- value = (char *) g_hash_table_lookup (args, key);
- if (value == NULL)
- return default_val;
- return totem_parse_boolean (key, value, default_val);
+ if (!mUnownedViewerSetUp)
+ return;
+
+ NS_ASSERTION (mConsoleClassRepresentant, "We own the viewer!");
+
+ NS_ENSURE_TRUE (mConsoleClassRepresentant->mViewerProxy, );
+
+ dbus_g_proxy_call_no_reply (mConsoleClassRepresentant->mViewerProxy,
+ "UnsetWindow",
+ G_TYPE_UINT, (guint) mWindow,
+ G_TYPE_INVALID);
+
+ mWindowSet = PR_FALSE;
}
+#endif /* TOTEM_COMPLEX_PLUGIN */
+
+/* Plugin glue functions */
+
NPError
totemPlugin::Init (NPMIMEType mimetype,
uint16_t mode,
@@ -581,168 +1480,296 @@ totemPlugin::Init (NPMIMEType mimetype,
char *argv[],
NPSavedData *saved)
{
- GError *e = NULL;
- gboolean need_req = FALSE;
- int i;
- GHashTable *args;
- char *value;
-
- mScriptable = new totemScriptablePlugin (this);
- if (!mScriptable)
- return NPERR_OUT_OF_MEMORY_ERROR;
+ D ("Init mimetype '%s' mode %d", (const char *) mimetype, mode);
- NS_ADDREF (mScriptable);
+ /* Make sure the plugin stays resident, to avoid
+ * reloading the GObject types.
+ */
+ CallNPN_SetValueProc (sNPN.setvalue,
+ mInstance,
+ NPPVpluginKeepLibraryInMemory,
+ NS_INT32_TO_PTR (PR_TRUE));
- if (!(mConn = dbus_g_bus_get (DBUS_BUS_SESSION, &e))) {
- printf ("Failed to open DBUS session: %s\n", e->message);
- g_error_free (e);
- return NPERR_OUT_OF_MEMORY_ERROR;
- } else if (!(mProxy = dbus_g_proxy_new_for_name (mConn,
- "org.freedesktop.DBus",
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus"))) {
- printf ("Failed to open DBUS proxy: %s\n", e->message);
- g_error_free (e);
- return NPERR_OUT_OF_MEMORY_ERROR;
+ /* mode is NP_EMBED, NP_FULL, or NP_BACKGROUND (see npapi.h) */
+ /* FIXME we should error out if we are in fullscreen mode
+ * FIXME: This might be possible on gecko trunk by returning an
+ * error code from the NewStream function.
+ */
+
+ NPError err;
+ err = CallNPN_GetValueProc (sNPN.getvalue,
+ mInstance, NPNVserviceManager,
+ NS_REINTERPRET_CAST (void *,
+ NS_REINTERPRET_CAST (void **, &mServiceManager)));
+ if (err != NPERR_NO_ERROR || !mServiceManager) {
+ D ("Failed to get the service manager");
+ return NPERR_GENERIC_ERROR;
}
- /* mode is NP_EMBED, NP_FULL, or NP_BACKGROUND (see npapi.h) */
- //FIXME we should error out if we are in fullscreen mode
- printf("mode %d\n",mode);
- printf("mime type: %s\n", mimetype);
+ nsresult rv;
+ rv = mServiceManager->GetServiceByContractID (NS_IOSERVICE_CONTRACTID,
+ NS_GET_IID (nsIIOService),
+ NS_REINTERPRET_CAST (void **, &mIOService));
+ if (NS_FAILED (rv) || !mIOService) {
+ D ("Failed to get IO service");
+ return NPERR_GENERIC_ERROR;
+ }
- /* to resolve relative URLs */
- nsIDOMWindow *domWin = nsnull;
- sMozillaFuncs.getvalue (mInstance, NPNVDOMWindow,
- NS_REINTERPRET_CAST (void**, &domWin));
- nsIInterfaceRequestor *irq = nsnull;
- if (domWin) {
- domWin->QueryInterface (NS_GET_IID (nsIInterfaceRequestor),
- NS_REINTERPRET_CAST (void**, &irq));
- NS_RELEASE (domWin);
+ err = CallNPN_GetValueProc (sNPN.getvalue,
+ mInstance, NPNVDOMElement,
+ NS_REINTERPRET_CAST (void *,
+ NS_REINTERPRET_CAST (void **, &mPluginDOMElement)));
+ if (err != NPERR_NO_ERROR || !mPluginDOMElement) {
+ D ("Failed to get our DOM Element");
+ return NPERR_GENERIC_ERROR;
}
- nsIWebNavigation *webNav = nsnull;
- if (irq) {
- irq->GetInterface (NS_GET_IID (nsIWebNavigation),
- NS_REINTERPRET_CAST (void**, &webNav));
- NS_RELEASE (irq);
+#if defined(TOTEM_COMPLEX_PLUGIN) && defined(HAVE_NSTARRAY_H)
+ rv = mPluginDOMElement->GetOwnerDocument (&mPluginOwnerDocument);
+ if (NS_FAILED (rv) || !mPluginOwnerDocument) {
+ D ("Plugin in a document!?");
+ return NPERR_GENERIC_ERROR;
+ }
+#endif /* TOTEM_COMPLEX_PLUGIN */
+
+ /* We'd like to get the base URI of our DOM element as a nsIURI,
+ * but there's no frozen method to do so (nsIContent/nsINode isn't available
+ * for non-MOZILLA_INTERNAL_API code). nsIDOM3Node isn't frozen either,
+ * but should be safe enough.
+ */
+ nsIDOM3Node *dom3Node = nsnull;
+ rv = CallQueryInterface (mPluginDOMElement, &dom3Node);
+ if (NS_FAILED (rv) || !dom3Node) {
+ D ("Failed to QI the DOM element to nsIDOM3Node");
+ return NPERR_GENERIC_ERROR;
}
- nsIURI *docURI = nsnull;
- if (webNav) {
- webNav->GetCurrentURI (&docURI);
- NS_RELEASE (webNav);
+ /* FIXME: can we cache this, or can it change (so we'll need to re-get every time we use it)? */
+ nsString baseASpec;
+ rv = dom3Node->GetBaseURI (baseASpec);
+ if (NS_FAILED (rv) || baseASpec.IsEmpty ()) {
+ /* We can't go on without a base URI ! */
+ D ("Failed to get base URI spec");
+ return NPERR_GENERIC_ERROR;
+ }
+
+ NS_ConvertUTF16toUTF8 baseSpec (baseASpec);
+
+ D ("Base URI is '%s'", baseSpec.get ());
+
+ rv = mIOService->NewURI (baseSpec, nsnull /* FIXME: use document charset */,
+ nsnull, &mBaseURI);
+ if (NS_FAILED (rv) || !mBaseURI) {
+ D ("Failed to construct base URI");
+ return NPERR_GENERIC_ERROR;
}
+ /* Create timer */
+ nsIComponentManager *compMan = nsnull;
+ rv = CallQueryInterface (mServiceManager, &compMan);
+ if (NS_FAILED (rv) || !compMan) {
+ D ("Failed to get component manager");
+ return NPERR_GENERIC_ERROR;
+ }
+
+ /* FIXME ? */
+ rv = compMan->CreateInstanceByContractID (NS_TIMER_CONTRACTID,
+ nsnull,
+ NS_GET_IID (nsITimer),
+ NS_REINTERPRET_CAST (void **, &mTimer));
+ if (NS_FAILED (rv) || !mTimer) {
+ D ("Failed to create timer: rv=%x", rv);
+ return NPERR_GENERIC_ERROR;
+ }
+
+ /* Setup DBus connection handling */
+ GError *error = NULL;
+ if (!(mBusConnection = dbus_g_bus_get (DBUS_BUS_SESSION, &error))) {
+ g_message ("Failed to open DBUS session: %s", error->message);
+ g_error_free (error);
+
+ return NPERR_GENERIC_ERROR;
+ };
+
+ if (!(mBusProxy = dbus_g_proxy_new_for_name (mBusConnection,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS))) {
+ D ("Failed to get DBUS proxy");
+ return NPERR_OUT_OF_MEMORY_ERROR;
+ }
+
+ dbus_g_proxy_add_signal (mBusProxy,
+ "NameOwnerChanged",
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal (mBusProxy,
+ "NameOwnerChanged",
+ G_CALLBACK (NameOwnerChangedCallback),
+ NS_REINTERPRET_CAST (void*, this),
+ NULL);
+
/* Find the "real" mime-type */
- mMimeType = GetRealMimeType (mimetype);
+ GetRealMimeType (mimetype, mMimeType);
+
+ D ("Real mimetype for '%s' is '%s'", mimetype, mMimeType.get());
- args = g_hash_table_new_full (g_str_hash, g_str_equal,
- (GDestroyNotify) g_free, (GDestroyNotify) g_free);
- for (i = 0; i < argc; i++) {
+ /* Now parse the attributes */
+ GHashTable *args = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_free);
+ for (int16_t i = 0; i < argc; i++) {
printf ("argv[%d] %s %s\n", i, argn[i], argv[i]);
g_hash_table_insert (args, g_ascii_strdown (argn[i], -1),
- g_strdup (argv[i]));
+ g_strdup (argv[i]));
}
- /* The QuickTime href system, with the src video just being a link
- * to this video */
-#ifdef TOTEM_NARROWSPACE_PLUGIN
- /* New URLs extensions:
- * http://developer.apple.com/documentation/QuickTime/WhatsNewQT5/QT5NewChapt1/chapter_1_section_32.html
- * http://developer.apple.com/documentation/QuickTime/Conceptual/QTScripting_HTML/QTScripting_HTML_Document/chapter_1000_section_3.html */
+ const char *value;
+
+ /* We only use the size attributes to detect whether we're hidden;
+ * we'll get our real size from SetWindow.
+ */
+ PRInt32 width = -1, height = -1;
- value = (char *) g_hash_table_lookup (args, "href");
+ value = (const char *) g_hash_table_lookup (args, "width");
if (value != NULL) {
- if (value[0] == '<') {
- //FIXME fill the hashtable with the new values
- //from the extended URLs
- char *href = parse_url_extensions (value);
-
- //FIXME
- // http://developer.apple.com/documentation/QuickTime/Conceptual/QTScripting_HTML/QTScripting_HTML_Document/chapter_1000_section_3.html
- // "Important: If you pass a relative URL in the HREF parameter, it must be relative to the currentlyloadedmovie, not relative to the current web page. If your movies are in a separate folder, specify URLs relative to the movies folder."
- mHref = resolve_relative_uri (docURI, href);
- g_free (href);
- } else {
- //FIXME see above
- mHref = resolve_relative_uri (docURI, value);
- }
+ width = strtol (value, NULL, 0);
}
-#endif /* TOTEM_NARROWSPACE_PLUGIN */
-
- value = (char *) g_hash_table_lookup (args, "width");
+ value = (const char *) g_hash_table_lookup (args, "height");
if (value != NULL) {
- /* FIXME! sanitize this value */
- mWidth = strtol (value, NULL, 0);
+ height = strtol (value, NULL, 0);
}
+
+ /* Are we hidden? */
+ mHidden = GetBooleanValue (args, "hidden", PR_FALSE);
- value = (char *) g_hash_table_lookup (args, "height");
- if (value != NULL) {
- /* FIXME! sanitize this value */
- mHeight = strtol (value, NULL, 0);
+ /* Most for RealAudio streams, but also used as a replacement for
+ * HIDDEN=TRUE attribute.
+ */
+ if (width == 0 && height == 0) {
+ mHidden = PR_TRUE;
}
- //FIXME get the base URL here
+ /* Whether to automatically stream and play the content */
+ mAutostart = GetBooleanValue (args, "autoplay",
+ GetBooleanValue (args, "autostart", mAutostart));
- value = (char *) g_hash_table_lookup (args, "src");
- if (value != NULL)
- mSrc = resolve_relative_uri (docURI, value);
+ /* Whether to loop */
+ mRepeat = GetBooleanValue (args, "repeat",
+ GetBooleanValue (args, "loop", PR_FALSE));
+
+ /* Now collect URI attributes */
+ const char *src = nsnull, *href = nsnull, *qtsrc = nsnull, *filename = nsnull;
+
+ src = (const char *) g_hash_table_lookup (args, "src");
/* DATA is only used in OBJECTs, see:
- * http://developer.mozilla.org/en/docs/Gecko_Plugin_API_Reference:Plug-in_Basics#Plug-in_Display_Modes */
- if (mSrc == NULL) {
- value = (char *) g_hash_table_lookup (args, "data");
- if (value != NULL)
- mSrc = resolve_relative_uri (docURI, value);
+ * http://developer.mozilla.org/en/docs/Gecko_Plugin_API_Reference:Plug-in_Basics#Plug-in_Display_Modes
+ */
+ /* FIXME: this is unnecessary, since gecko will automatically a synthetic
+ * "src" attribute with the "data" atttribute's content if "src" is missing,
+ * see http://lxr.mozilla.org/seamonkey/source/layout/generic/nsObjectFrame.cpp#2479
+ */
+ if (!src) {
+ src = (const char *) g_hash_table_lookup (args, "data");
+ }
+ if (src) {
+ SetSrc (nsDependentCString (src));
}
- /* Those parameters might replace the current src */
#ifdef TOTEM_GMP_PLUGIN
/* http://windowssdk.msdn.microsoft.com/en-us/library/aa392440(VS.80).aspx */
- value = (char *) g_hash_table_lookup (args, "filename");
- if (value == NULL)
- value = (char *) g_hash_table_lookup (args, "url");
-#elif TOTEM_NARROWSPACE_PLUGIN
+ filename = (const char *) g_hash_table_lookup (args, "filename");
+ if (!filename)
+ filename = (const char *) g_hash_table_lookup (args, "url");
+ if (filename) {
+ SetURL (nsDependentCString (filename));
+ }
+#endif /* TOTEM_GMP_PLUGIN */
+
+#ifdef TOTEM_NARROWSPACE_PLUGIN
+ /* Target */
+ value = (const char *) g_hash_table_lookup (args, "target");
+ if (value) {
+ mTarget.Assign (value);
+ }
+
+ href = (const char *) g_hash_table_lookup (args, "href");
+ if (href) {
+ SetHref (nsDependentCString (href));
+ }
+
/* http://developer.apple.com/documentation/QuickTime/QT6WhatsNew/Chap1/chapter_1_section_13.html */
- value = (char *) g_hash_table_lookup (args, "qtsrc");
-#elif TOTEM_MULLY_PLUGIN
+ qtsrc = (const char *) g_hash_table_lookup (args, "qtsrc");
+ if (qtsrc) {
+ SetQtsrc (nsDependentCString (qtsrc));
+ }
+#endif /* TOTEM_NARROWSPACE_PLUGIN */
+
+/* FIXME */
+#if 0 //def TOTEM_MULLY_PLUGIN
/* Click to play behaviour of the DivX plugin */
- value = (char *) g_hash_table_lookup (args, "previewimage");
+ char *previewimage = (const char *) g_hash_table_lookup (args, "previewimage");
if (value != NULL)
mHref = g_strdup (mSrc);
-#else
- value = NULL;
-#endif
- if (value != NULL) {
- if (mSrc == NULL || strcmp (mSrc, value) != 0) {
- //FIXME need to cancel SRC if there's one
- g_free (mSrc);
- mSrc = resolve_relative_uri (docURI, value);
- need_req = TRUE;
- }
+#endif /* TOTEM_NARROWSPACE_PLUGIN */
+
+ /* If we're set to start automatically, we'll use the src stream */
+ if (mRequestURI &&
+ mRequestURI == mSrcURI) {
+ mExpectingStream = mAutostart;
}
-#ifdef TOTEM_NARROWSPACE_PLUGIN
/* Caching behaviour */
- mCache = totem_get_boolean_value (args, "cache", FALSE);
- /* Target */
- value = (char *) g_hash_table_lookup (args, "target");
- if (value != NULL)
- mTarget = g_strdup (value);
-#endif /* TOTEM_NARROWSPACE_PLUGIN */
+#ifdef TOTEM_NARROWSPACE_PLUGIN
+ if (strcmp (mimetype, "video/quicktime") != 0) {
+ mCache = PR_TRUE;
+ }
- /* Whether the controls are all hidden, MSIE parameter
- * http://www.htmlcodetutorial.com/embeddedobjects/_EMBED_CONTROLLER.html */
- gboolean controller;
- controller = totem_get_boolean_value (args, "controller", TRUE);
- mControllerHidden = (controller == FALSE);
+ mCache = GetBooleanValue (args, "cache", mCache);
- //FIXME add Netscape controls support
- // http://www.htmlcodetutorial.com/embeddedobjects/_EMBED_CONTROLS.html
+ mControllerHidden = !GetBooleanValue (args, "controller", PR_TRUE);
- /* Are we hidden? */
- mHidden = totem_get_boolean_value (args, "hidden", FALSE);
+#endif /* TOTEM_NARROWSPACE_PLUGIN */
+
+#if defined(TOTEM_COMPLEX_PLUGIN) && defined(HAVE_NSTARRAY_H)
+ value = (const char *) g_hash_table_lookup (args, "console");
+ if (value) {
+ rv = SetConsole (nsDependentCString (value));
+ if (NS_FAILED (rv))
+ return NPERR_GENERIC_ERROR;
+ }
+
+ const char *kControls[] = {
+ "All",
+ "ControlPanel",
+ "FFCtrl",
+ "HomeCtrl",
+ "ImageWindow",
+ "InfoPanel",
+ "InfoVolumePanel",
+ "MuteCtrl",
+ "MuteVolume",
+ "PauseButton",
+ "PlayButton",
+ "PlayOnlyButton",
+ "PositionField",
+ "PositionSlider",
+ "RWCtrl",
+ "StatusBar",
+ "StatusField",
+ "StopButton",
+ "TACCtrl",
+ "VolumeSlider",
+ };
+ PRUint32 control = GetEnumIndex (args, "controls",
+ kControls, G_N_ELEMENTS (kControls),
+ 0);
+ mControls = kControls[control];
+
+#endif /* TOTEM_COMPLEX_PLUGIN */
#ifdef TOTEM_GMP_PLUGIN
/* uimode is either invisible, none, mini, or full
@@ -750,23 +1777,24 @@ totemPlugin::Init (NPMIMEType mimetype,
value = (char *) g_hash_table_lookup (args, "uimode");
if (value != NULL) {
if (g_ascii_strcasecmp (value, "none") == 0) {
- mControllerHidden = TRUE;
+ mControllerHidden = PR_TRUE;
} else if (g_ascii_strcasecmp (value, "invisible") == 0) {
- mHidden = TRUE;
+ mHidden = PR_TRUE;
} else if (g_ascii_strcasecmp (value, "full") == 0) {
- mStatusbar = TRUE;
+ mShowStatusbar = PR_TRUE;
} else if (g_ascii_strcasecmp (value, "mini") == 0) {
;
}
}
+
+ /* Whether the controls are all hidden, MSIE parameter
+ * http://www.htmlcodetutorial.com/embeddedobjects/_EMBED_CONTROLLER.html */
/* ShowXXX parameters as per http://support.microsoft.com/kb/285154 */
- controller = totem_get_boolean_value (args, "showcontrols", TRUE);
- if (mControllerHidden == FALSE)
- mControllerHidden = (controller == FALSE);
+ mControllerHidden = !GetBooleanValue (args, "controller",
+ GetBooleanValue (args, "showcontrols", PR_TRUE));
+
+ mShowStatusbar = GetBooleanValue (args, "showstatusbar", mShowStatusbar);
- gboolean statusbar;
- statusbar = totem_get_boolean_value (args, "showstatusbar", mStatusbar);
- mStatusbar = (statusbar == FALSE);
//FIXME add showdisplay
// see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmp6sdk/htm/userinterfaceelements.asp
#endif /* TOTEM_GMP_PLUGIN */
@@ -774,105 +1802,147 @@ totemPlugin::Init (NPMIMEType mimetype,
/* Whether to NOT autostart */
//FIXME Doesn't handle playcount, or loop with numbers
// http://www.htmlcodetutorial.com/embeddedobjects/_EMBED_LOOP.html
- gboolean autostart;
- autostart = totem_get_boolean_value (args, "autostart", TRUE);
- autostart = totem_get_boolean_value (args, "autoplay", autostart);
- mNoAutostart = (autostart == FALSE);
-
- /* Whether to loop */
- mRepeat = totem_get_boolean_value (args, "loop", FALSE);
- mRepeat = totem_get_boolean_value (args, "repeat", mRepeat);
-
- g_message ("mSrc: %s", mSrc);
- g_message ("mHref: %s", mHref);
- g_message ("mHeight: %d mWidth: %d", mHeight, mWidth);
- g_message ("mCache: %d", mCache);
- g_message ("mTarget: %s", mTarget);
- g_message ("mControllerHidden: %d", mControllerHidden);
- g_message ("mStatusbar: %d", mStatusbar);
- g_message ("mHidden: %d", mHidden);
- g_message ("mNoAutostart: %d mRepeat: %d", mNoAutostart, mRepeat);
//FIXME handle starttime and endtime
// http://www.htmlcodetutorial.com/embeddedobjects/_EMBED_STARTTIME.html
- g_hash_table_destroy (args);
- NS_IF_RELEASE (docURI);
-
- mIsSupportedSrc = IsSchemeSupported (mSrc);
+ /* Dump some disagnostics */
+ D ("mSrc: %s", mSrc.get ());
+ D ("mCache: %d", mCache);
+ D ("mControllerHidden: %d", mControllerHidden);
+ D ("mShowStatusbar: %d", mShowStatusbar);
+ D ("mHidden: %d", mHidden);
+ D ("mAutostart: %d, mRepeat: %d", mAutostart, mRepeat);
+#ifdef TOTEM_NARROWSPACE_PLUGIN
+ D ("mHref: %s", mHref.get ());
+ D ("mTarget: %s", mTarget.get ());
+#endif /* TOTEM_NARROWSPACE_PLUGIN */
+#if defined(TOTEM_COMPLEX_PLUGIN) && defined(HAVE_NSTARRAY_H)
+ D ("mConsole: %s", mConsole.get ());
+ D ("mControls: %s", mControls.get ());
+#endif /* TOTEM_COMPLEX_PLUGIN */
- /* If filename is used, we need to request the stream ourselves */
- if (need_req != FALSE) {
- if (mIsSupportedSrc != FALSE) {
- CallNPN_GetURLProc(sMozillaFuncs.geturl,
- mInstance, mSrc, NULL);
- }
- }
+ g_hash_table_destroy (args);
- return NPERR_NO_ERROR;
+ return ViewerFork ();
}
NPError
totemPlugin::SetWindow (NPWindow *window)
{
- D("SetWindow [%p]", (void*) this);
-
- if (mWindow) {
- D ("existing window");
- if (mWindow == (Window) window->window) {
- D("resize");
- /* Resize event */
- /* Not currently handled */
- } else {
- D("change");
- printf ("ack. window changed!\n");
- }
- } else {
- /* If not, wait for the first bits of data to come,
- * but not when the stream type isn't supported */
- mWindow = (Window) window->window;
- if (mStream && mIsSupportedSrc) {
- if (!Fork ())
- return NPERR_GENERIC_ERROR;
- /* If it's not a supported stream, we need
- * to launch now */
- } else if (!mIsSupportedSrc) {
- if (!Fork ())
- return NPERR_GENERIC_ERROR;
- } else {
- D("waiting for data to come");
- }
+ if (mHidden && window->window != 0) {
+ D("SetWindow: hidden, can't set window");
+ return NPERR_GENERIC_ERROR;
}
- D("leaving plugin_set_window");
+ if (mWindow != 0 &&
+ mWindow == (Window) window->window) {
+ mWidth = window->width;
+ mHeight = window->height;
+ DD ("Window resized or moved, now %dx%d", mWidth, mHeight);
+ } else if (mWindow == 0) {
+ mWindow = (Window) window->window;
+
+ mWidth = window->width;
+ mHeight = window->height;
+
+ D ("Initial window set, XID %x size %dx%d",
+ (guint) (Window) window->window, mWidth, mHeight);
+
+ ViewerSetWindow ();
+ } else {
+ D ("Setting a new window != mWindow, this is unsupported!");
+ }
return NPERR_NO_ERROR;
}
NPError
totemPlugin::NewStream (NPMIMEType type,
- NPStream* stream_ptr,
+ NPStream* stream,
NPBool seekable,
uint16* stype)
{
- D("plugin_new_stream");
+ if (!stream || !stream->url)
+ return NPERR_GENERIC_ERROR;
+
+ D ("NewStream mimetype '%s' URL '%s'", (const char *) type, stream->url);
/* We already have a live stream */
if (mStream) {
- D("plugin_new_stream exiting, already have a live stream");
- return NPERR_GENERIC_ERROR;
+ D ("Already have a live stream, aborting stream");
+
+ /* We don't just return NPERR_GENERIC_ERROR (or any other error code),
+ * since, using gecko trunk (1.9), this causes the plugin to be destroyed,
+ * if this is the automatic |src| stream. Same for the other calls below.
+ */
+ return CallNPN_DestroyStreamProc (sNPN.destroystream,
+ mInstance,
+ stream,
+ NPRES_DONE);
}
- D("plugin_new_stream type: %s url: %s", type, mSrc);
+ /* Either:
+ * - this is the automatic first stream from the |src| or |data| attribute,
+ * but we want to request a different URL, or
+ * - Gecko sometimes sends us 2 stream, and if the first is already in cache we'll
+ * be done it before it starts the 2nd time so the "if (mStream)" check above
+ * doesn't catch always this.
+ */
+ if (!mExpectingStream) {
+ D ("Not expecting a new stream; aborting stream");
+
+ return CallNPN_DestroyStreamProc (sNPN.destroystream,
+ mInstance,
+ stream,
+ NPRES_DONE);
+ }
+
+ /* This was an expected stream, no more expected */
+ mExpectingStream = PR_FALSE;
+
+#if 1 // #if 0
+ // This is fixed now _except_ the "if (!mViewerReady)" problem in StreamAsFile
- if (IsMimeTypeSupported (type, mSrc) == FALSE) {
- D("plugin_new_stream type: %s not supported, exiting\n", type);
- return NPERR_INVALID_PLUGIN_ERROR;
+ /* For now, we'll re-request the stream when the viewer is ready.
+ * As an optimisation, we could either just allow small (< ~128ko) streams
+ * (which are likely to be playlists!), or any stream and cache them to disk
+ * until the viewer is ready.
+ */
+ if (!mViewerReady) {
+ D ("Viewer not ready, aborting stream");
+
+ return CallNPN_DestroyStreamProc (sNPN.destroystream,
+ mInstance,
+ stream,
+ NPRES_DONE);
}
+#endif
- //FIXME need to find better semantics?
- //what about saving the state, do we get confused?
- if (g_str_has_prefix (mSrc, "file://")) {
+ if (!IsMimeTypeSupported (type, stream->url)) {
+ D ("Unsupported mimetype, aborting stream");
+
+ return CallNPN_DestroyStreamProc (sNPN.destroystream,
+ mInstance,
+ stream,
+ NPRES_DONE);
+ }
+
+ /* FIXME: assign the stream URL to mRequestURI ? */
+
+ /* Open a FILE* for our FD */
+ mViewerStream = fdopen (mViewerFD, "w");
+ if (!mViewerStream) {
+ int err = errno;
+ D ("Failed to fdopen the viewer fd, errno: %d", err);
+
+ return CallNPN_DestroyStreamProc (sNPN.destroystream,
+ mInstance,
+ stream,
+ NPRES_DONE);
+ }
+
+ if (g_str_has_prefix (stream->url, "file://")) {
*stype = NP_ASFILEONLY;
mStreamType = NP_ASFILEONLY;
} else {
@@ -880,7 +1950,13 @@ totemPlugin::NewStream (NPMIMEType type,
mStreamType = NP_ASFILE;
}
- mStream = stream_ptr;
+ mStream = stream;
+
+ mCheckedForPlaylist = PR_FALSE;
+ mIsPlaylist = PR_FALSE;
+
+ /* To track how many data we get from ::Write */
+ mBytesStreamed = 0;
return NPERR_NO_ERROR;
}
@@ -889,35 +1965,57 @@ NPError
totemPlugin::DestroyStream (NPStream* stream,
NPError reason)
{
- D("plugin_destroy_stream, reason: %d", reason);
+ if (!mStream || mStream != stream)
+ return NPERR_GENERIC_ERROR;
- if (mSendFD >= 0) {
- close(mSendFD);
- mSendFD = -1;
- }
+ D ("DestroyStream reason %d", reason);
mStream = nsnull;
+ NS_ASSERTION (mViewerStream, "No viewer stream?");
+
+ int ret = fclose (mViewerStream);
+ if (ret < 0) {
+ int err = errno;
+ D ("Failed to close viewer stream with errno %d: %s", err, g_strerror (err));
+ }
+
+ mViewerStream = NULL;
+
+#if 0
+ /* Close the viewer */
+ dbus_g_proxy_call_no_reply (mViewerProxy,
+ "CloseStream",
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+#endif
+
return NPERR_NO_ERROR;
}
int32
totemPlugin::WriteReady (NPStream *stream)
{
- //D("plugin_write_ready");
+ /* FIXME this could probably be an assertion instead */
+ if (!mStream || mStream != stream)
+ return -1;
- if (mIsSupportedSrc == FALSE)
- return 0; /* FIXME not -1 ? */
+ /* Suspend the request until the viewer is ready;
+ * we'll wake up in 100ms for another try.
+ */
+ if (!mViewerReady)
+ return 0;
- if (mSendFD < 0)
- return (PLUGIN_STREAM_CHUNK_SIZE);
+ DD ("WriteReady");
+ /* FIXME: does this mix well with using mViewerStream ? */
struct pollfd fds;
fds.events = POLLOUT;
- fds.fd = mSendFD;
+ fds.fd = mViewerFD;
if (poll (&fds, 1, 0) > 0)
return (PLUGIN_STREAM_CHUNK_SIZE);
+ /* suspend the request, we'll wake up in 100ms for another try */
return 0;
}
@@ -927,59 +2025,58 @@ totemPlugin::Write (NPStream *stream,
int32 len,
void *buffer)
{
- int ret;
+ /* FIXME this could probably be an assertion instead */
+ if (!mStream || mStream != stream)
+ return -1;
- //D("plugin_write");
+ DD ("Write offset %d len %d", offset, len);
- /* We already know it's a playlist, don't try to check it again
- * and just wait for it to be on-disk */
- if (mIsPlaylist != FALSE)
+ /* We already know it's a playlist, just wait for it to be on-disk. */
+ if (mIsPlaylist)
return len;
- if (!mPlayerPID) {
- if (!mStream) {
- g_warning ("No stream in NPP_Write!?");
- return -1;
- }
+ /* Check for playlist.
+ * Ideally we'd just always forward the data to the viewer and the viewer
+ * always parse the playlist itself, but that's not yet implemented.
+ */
+ /* FIXME we can only look at the current buffer, not at all the data so far.
+ * So we can only do this at the start of the stream.
+ */
+ if (!mCheckedForPlaylist) {
+ NS_ASSERTION (offset == 0, "Not checked for playlist but not at the start of the stream!?");
- mTriedWrite = TRUE;
+ mCheckedForPlaylist = PR_TRUE;
+
+ if (totem_pl_parser_can_parse_from_data ((const char *) buffer, len, TRUE /* FIXME */)) {
+ D ("Is playlist; need to wait for the file to be downloaded completely");
+ mIsPlaylist = PR_TRUE;
- /* FIXME this looks wrong since it'll look at the current data buffer,
- * not the cumulative data since the stream started
- */
- if (totem_pl_parser_can_parse_from_data ((const char *) buffer, len, TRUE /* FIXME */) != FALSE) {
- D("Need to wait for the file to be downloaded completely");
- mIsPlaylist = TRUE;
return len;
}
-
- if (!Fork ())
- return -1;
}
- if (mSendFD < 0)
- return -1;
-
- if (mIsSupportedSrc == FALSE)
- return -1;
+ int ret = fwrite (buffer, 1, len, mViewerStream);
+ /* FIXME shouldn't we retry if errno is EINTR ? */
- ret = write (mSendFD, buffer, len);
- if (ret < 0) {
- /* FIXME what's this for? gecko will destroy the stream automatically if we return -1 */
+ if (NS_UNLIKELY (ret < 0)) {
int err = errno;
- D("ret %d: [%d]%s", ret, errno, g_strerror (err));
+ D ("Write failed with errno %d: %s", err, g_strerror (err));
+
if (err == EPIPE) {
/* fd://0 got closed, probably because the backend
- * crashed on us */
- if (CallNPN_DestroyStreamProc
- (sMozillaFuncs.destroystream,
- mInstance,
- mStream,
- NPRES_DONE) != NPERR_NO_ERROR) {
+ * crashed on us. Destroy the stream.
+ */
+ if (CallNPN_DestroyStreamProc (sNPN.destroystream,
+ mInstance,
+ mStream,
+ NPRES_DONE) != NPERR_NO_ERROR) {
g_warning ("Couldn't destroy the stream");
}
}
- /* FIXME shouldn't we set ret=0 here? otherwise the stream will be destroyed */
+ } else /* ret >= 0 */ {
+ DD ("Wrote %d bytes", ret);
+
+ mBytesStreamed += ret;
}
return ret;
@@ -989,49 +2086,142 @@ void
totemPlugin::StreamAsFile (NPStream *stream,
const char* fname)
{
- NS_ASSERTION (stream == mStream, "Unknown stream");
+ if (!mStream || mStream != stream)
+ return;
- D("plugin_stream_as_file: %s", fname);
+ D ("StreamAsFile filename '%s'", fname);
- if (!mTriedWrite) {
+ /* FIXME: this reads the whole file into memory... try to
+ * find a way to avoid it.
+ */
+ if (!mCheckedForPlaylist) {
mIsPlaylist = totem_pl_parser_can_parse_from_filename
- (fname, TRUE);
+ (fname, TRUE) != FALSE;
}
- if (!mPlayerPID && mIsPlaylist) {
- mLocal = g_filename_to_uri (fname, NULL, NULL);
- Fork ();
+ /* FIXME! This happens when we're using the automatic |src| stream and
+ * it finishes before we're ready.
+ */
+ if (!mViewerReady) {
+ D ("Viewer not ready yet, deferring SetLocalFile");
return;
- } else if (!mPlayerPID) {
- if (!Fork ())
- return;
}
- if (mIsPlaylist != FALSE)
- return;
-
- GError *err = NULL;
- if (!dbus_g_proxy_call (mProxy, "SetLocalFile", &err,
- G_TYPE_STRING, fname, G_TYPE_INVALID,
- G_TYPE_INVALID)) {
- g_warning ("Error: %s", err->message);
- g_error_free (err);
+ NS_ASSERTION (mViewerProxy, "No viewer proxy");
+ NS_ASSERTION (mViewerReady, "Viewer not ready");
+
+ NS_ENSURE_TRUE (mRequestBaseURI && mRequestURI, );
+
+ nsCString baseSpec, spec;
+ mRequestBaseURI->GetSpec (baseSpec);
+ mRequestURI->GetSpec (spec);
+
+ /* FIXME: these calls need to be async!!
+ * But the file may be unlinked as soon as we return from this
+ * function... do we need to keep a link?
+ */
+ gboolean retval = TRUE;
+ GError *error = NULL;
+ if (mIsPlaylist) {
+ retval = dbus_g_proxy_call (mViewerProxy,
+ "SetPlaylist",
+ &error,
+ G_TYPE_STRING, fname,
+ G_TYPE_STRING, spec.get (),
+ G_TYPE_STRING, baseSpec.get (),
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+ }
+ /* Only call SetLocalFile if we haven't already streamed the file!
+ * (It happens that we get no ::Write calls if the file is
+ * completely in the cache.)
+ */
+ else if (mBytesStreamed == 0) {
+ retval = dbus_g_proxy_call (mViewerProxy,
+ "SetLocalFile",
+ &error,
+ G_TYPE_STRING, fname,
+ G_TYPE_STRING, spec.get (),
+ G_TYPE_STRING, baseSpec.get (),
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+ } else {
+ D ("mBytesStreamed %u", mBytesStreamed);
}
- D("plugin_stream_as_file done");
+ if (!retval) {
+ g_warning ("Viewer error: %s", error->message);
+ g_error_free (error);
+ }
+}
+
+void
+totemPlugin::URLNotify (const char *url,
+ NPReason reason,
+ void *notifyData)
+{
+ D ("URLNotify URL '%s' reason %d", url ? url : "", reason);
+
+ /* If we get called when we expect a stream,
+ * it means that the stream failed.
+ */
+ if (reason == NPRES_NETWORK_ERR &&
+ mExpectingStream) {
+ /* FIXME: set/show error */
+ mExpectingStream = PR_FALSE;
+ }
}
NPError
totemPlugin::GetScriptable (void *_retval)
{
- D ("GetScriptable [%p], mInstance %p", (void*) this, mInstance);
+ D ("GetScriptable [%p]", (void*) this);
+
+#if defined(TOTEM_COMPLEX_PLUGIN) && defined(HAVE_NSTARRAY_H)
+ if (mConsoleClassRepresentant) {
+ return mConsoleClassRepresentant->GetScriptable (_retval);
+ }
+#endif /* TOTEM_COMPLEX_PLUGIN */
+
+ if (!mScriptable) {
+ mScriptable = new totemScriptablePlugin (this);
+ if (!mScriptable)
+ return NPERR_OUT_OF_MEMORY_ERROR;
- /* FIXME this shouldn't happen, but seems to happen nevertheless?!? */
- if (!mScriptable)
- return NPERR_INVALID_PLUGIN_ERROR;
+ NS_ADDREF (mScriptable);
+ }
nsresult rv = mScriptable->QueryInterface (NS_GET_IID (nsISupports),
NS_REINTERPRET_CAST (void **, _retval));
return NS_SUCCEEDED (rv) ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR;
}
+
+/* static */ NPError
+totemPlugin::Initialise ()
+{
+#if defined(TOTEM_COMPLEX_PLUGIN) && defined(HAVE_NSTARRAY_H)
+ sPlugins = new nsTArray<totemPlugin*> (32);
+ if (!sPlugins)
+ return NPERR_OUT_OF_MEMORY_ERROR;
+#endif /* TOTEM_COMPLEX_PLUGIN */
+
+ return NPERR_NO_ERROR;
+}
+
+/* static */ NPError
+totemPlugin::Shutdown ()
+{
+#if defined(TOTEM_COMPLEX_PLUGIN) && defined(HAVE_NSTARRAY_H)
+ if (sPlugins) {
+ if (!sPlugins->IsEmpty ()) {
+ D ("WARNING: sPlugins not empty on shutdown, count: %d", sPlugins->Length ());
+ }
+
+ delete sPlugins;
+ sPlugins = nsnull;
+ }
+#endif /* TOTEM_COMPLEX_PLUGIN */
+
+ return NPERR_NO_ERROR;
+}
diff --git a/browser-plugin/totemPlugin.h b/browser-plugin/totemPlugin.h
index aa7e9564a..8fc5162dc 100644
--- a/browser-plugin/totemPlugin.h
+++ b/browser-plugin/totemPlugin.h
@@ -1,7 +1,8 @@
-/* Totem Mozilla plugin
+/* Totem browser plugin
*
- * Copyright (C) 2004 Bastien Nocera <hadess@hadess.net>
- * Copyright (C) 2002 David A. Schleef <ds@schleef.org>
+ * Copyright © 2004 Bastien Nocera <hadess@hadess.net>
+ * Copyright © 2002 David A. Schleef <ds@schleef.org>
+ * Copyright © 2006 Christian Persch
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -24,9 +25,24 @@
#include <stdint.h>
#include <dbus/dbus-glib.h>
-#include "npapi.h"
+#include <npapi.h>
+#include <nsStringAPI.h>
+#if defined(TOTEM_COMPLEX_PLUGIN) && defined(HAVE_NSTARRAY_H)
+#include <nsTArray.h>
+#endif /* TOTEM_COMPLEX_PLUGIN */
+
+#include "totem-plugin-viewer-commands.h"
+
+class nsIDOMDocument;
+class nsIDOMElement;
+class nsIIOService;
+class nsIServiceManager;
+class nsITimer;
+class nsIURI;
+class nsVoidArray;
class totemScriptablePlugin;
+struct _NPNetscapeFuncs;
class totemPlugin {
public:
@@ -35,9 +51,17 @@ class totemPlugin {
void* operator new (size_t aSize) CPP_THROW_NEW;
- nsresult Play ();
- nsresult Stop ();
- nsresult Pause ();
+ /* Interface to scriptable */
+
+ nsresult DoCommand (const char *aCommand);
+
+ nsresult SetSrc (const nsACString &aURL);
+
+ /* plugin glue */
+ static _NPNetscapeFuncs sNPN;
+
+ static NPError Initialise ();
+ static NPError Shutdown ();
NPError Init (NPMIMEType mimetype,
uint16_t mode,
@@ -49,11 +73,11 @@ class totemPlugin {
NPError SetWindow (NPWindow *aWindow);
NPError NewStream (NPMIMEType type,
- NPStream* stream_ptr,
- NPBool seekable,
- uint16* stype);
+ NPStream* stream_ptr,
+ NPBool seekable,
+ uint16* stype);
NPError DestroyStream (NPStream* stream,
- NPError reason);
+ NPError reason);
int32 WriteReady (NPStream *stream);
int32 Write (NPStream *stream,
@@ -61,64 +85,187 @@ class totemPlugin {
int32 len,
void *buffer);
void StreamAsFile (NPStream *stream,
- const char* fname);
-
+ const char* fname);
+
+ void URLNotify (const char *url,
+ NPReason reason,
+ void *notifyData);
+
NPError GetScriptable (void *_retval);
+ private:
+
static void PR_CALLBACK NameOwnerChangedCallback (DBusGProxy *proxy,
const char *svc,
const char *old_owner,
const char *new_owner,
- totemPlugin *plugin);
+ void *aData);
- static void PR_CALLBACK StopSendingDataCallback (DBusGProxy *proxy,
- totemPlugin *plugin);
+ static void PR_CALLBACK ViewerForkTimeoutCallback (nsITimer *aTimer,
+ void *aData);
- private:
+ static void PR_CALLBACK ButtonPressCallback (DBusGProxy *proxy,
+ //guint aButton,
+ //guint aTimestamp,
+ void *aData);
+
+ static void PR_CALLBACK StopStreamCallback (DBusGProxy *proxy,
+ void *aData);
+
+ static void PR_CALLBACK ViewerSetWindowCallback (DBusGProxy *aProxy,
+ DBusGProxyCall *aCall,
+ void *aData);
+ static void PR_CALLBACK ViewerOpenStreamCallback (DBusGProxy *aProxy,
+ DBusGProxyCall *aCall,
+ void *aData);
+ static void PR_CALLBACK ViewerOpenURICallback (DBusGProxy *aProxy,
+ DBusGProxyCall *aCall,
+ void *aData);
+
+ NPError ViewerFork ();
+ void ViewerSetup ();
+ void ViewerSetWindow ();
+ void ViewerReady ();
+ void ViewerCleanup ();
+ void ViewerButtonPressed ();
+
+ void NameOwnerChanged (const char *aName,
+ const char *aOldOwner,
+ const char *aNewOwner);
- PRBool Fork ();
+ void ComputeRequest ();
+ void ClearRequest ();
+ void RequestStream ();
void UnsetStream ();
- PRBool IsMimeTypeSupported (const char *aMimeType, const char *aURL);
- PRBool IsSchemeSupported (const char *aURL);
- char *GetRealMimeType (const char *aMimeType);
+ PRBool IsMimeTypeSupported (const char *aMimeType,
+ const char *aURL);
+ PRBool IsSchemeSupported (nsIURI *aURI);
+ void GetRealMimeType (const char *aMimeType,
+ nsACString &_retval);
+ PRBool ParseBoolean (const char *key,
+ const char *value,
+ PRBool default_val);
+ PRBool GetBooleanValue (GHashTable *args,
+ const char *key,
+ PRBool default_val);
+ PRUint32 GetEnumIndex (GHashTable *args,
+ const char *key,
+ const char *values[],
+ PRUint32 n_values,
+ PRUint32 default_value);
NPP mInstance;
- /* FIXME make this a nsCOMPtr */
+ /* FIXME make these use nsCOMPtr<> !! */
totemScriptablePlugin *mScriptable;
+ nsIServiceManager *mServiceManager;
+ nsIIOService *mIOService;
+ nsIDOMElement *mPluginDOMElement;
+ nsITimer *mTimer;
+ nsIURI *mBaseURI;
+
+ nsIURI *mRequestBaseURI;
+ nsIURI *mRequestURI;
NPStream *mStream;
- char *mMimeType;
+ PRUint32 mBytesStreamed;
PRUint8 mStreamType;
+ nsCString mMimeType;
+
+ nsCString mSrc;
+ nsIURI *mSrcURI;
+
Window mWindow;
+ PRInt32 mWidth;
+ PRInt32 mHeight;
- char *mSrc;
- char *mLocal;
- char *mHref;
- char *mTarget;
+ DBusGConnection *mBusConnection;
+ DBusGProxy *mBusProxy;
+ DBusGProxy *mViewerProxy;
+ DBusGProxyCall *mViewerPendingCall;
+ nsCString mViewerBusAddress;
+ nsCString mViewerServiceName;
+ int mViewerPID;
+ int mViewerFD;
+ FILE *mViewerStream;
- int mWidth;
- int mHeight;
+#ifdef TOTEM_GMP_PLUGIN
+ public:
+ nsresult SetURL (const nsACString &aURL);
- DBusGConnection *mConn;
- DBusGProxy *mProxy;
- char *mWaitForSvc;
+ private:
+ nsIURI *mURLURI;
+#endif
- int mSendFD;
- int mPlayerPID;
+#ifdef TOTEM_NARROWSPACE_PLUGIN
+ public:
+ nsresult SetQtsrc (const nsACString &aURL);
+ nsresult SetHref (const nsACString& aURL);
+
+ private:
+ PRBool ParseURLExtensions (const nsACString &aString,
+ nsACString &_url,
+ nsACString &_target);
+
+ void LaunchTotem (const nsCString &aURL,
+ PRUint32 aTimestamp);
+
+ nsIURI *mQtsrcURI;
+
+ nsCString mHref;
+ nsIURI *mHrefURI;
+
+ nsCString mTarget;
+#endif
+
+#if defined(TOTEM_COMPLEX_PLUGIN) && defined(HAVE_NSTARRAY_H)
+ public:
+
+ nsresult SetConsole (const nsACString &aConsole);
+
+ private:
+
+ totemPlugin* FindConsoleClassRepresentant ();
+ void TransferConsole ();
+
+ void UnownedViewerSetup ();
+ void UnownedViewerSetWindow ();
+ void UnownedViewerUnsetWindow ();
+
+ nsIDOMDocument *mPluginOwnerDocument;
+ nsCString mConsole;
+ nsCString mControls;
+
+ /* nsnull if we're the representant ourself */
+ totemPlugin *mConsoleClassRepresentant;
+
+ static nsTArray<totemPlugin*> *sPlugins;
+
+#endif /* TOTEM_COMPLEX_PLUGIN */
+
+ private:
+ PRUint32 mAutostart : 1;
PRUint32 mCache : 1;
+ PRUint32 mCheckedForPlaylist : 1;
PRUint32 mControllerHidden : 1;
- PRUint32 mGotSvc : 1;
+ PRUint32 mExpectingStream : 1;
+ PRUint32 mHadStream : 1;
PRUint32 mHidden : 1;
PRUint32 mIsPlaylist : 1;
PRUint32 mIsSupportedSrc : 1;
- PRUint32 mNoAutostart : 1;
+ PRUint32 mNeedViewer : 1;
PRUint32 mRepeat : 1;
- PRUint32 mTriedWrite : 1;
- PRUint32 mStatusbar : 1;
+ PRUint32 mRequestIsSrc : 1;
+ PRUint32 mShowStatusbar : 1;
+ PRUint32 mTimerRunning : 1;
+ PRUint32 mUnownedViewerSetUp : 1;
+ PRUint32 mViewerReady : 1;
+ PRUint32 mViewerSetUp : 1;
+ PRUint32 mWaitingForButtonPress : 1;
+ PRUint32 mWindowSet : 1;
};
typedef struct {
diff --git a/browser-plugin/totemPluginGlue.cpp b/browser-plugin/totemPluginGlue.cpp
index 0db55ec5e..9eb573b9e 100644
--- a/browser-plugin/totemPluginGlue.cpp
+++ b/browser-plugin/totemPluginGlue.cpp
@@ -37,7 +37,6 @@
#include "totemPluginGlue.h"
#include "totemPlugin.h"
-NPNetscapeFuncs sMozillaFuncs;
static char *mime_list = NULL;
static NPError
@@ -49,20 +48,10 @@ totem_plugin_new_instance (NPMIMEType mimetype,
char *argv[],
NPSavedData *savedData)
{
- totemPlugin *plugin;
-
- D("totem_plugin_new_instance");
-
if (!instance)
return NPERR_INVALID_INSTANCE_ERROR;
- /* Make sure the plugin stays resident to avoid crashers when
- * reloading the GObject types.
- */
- CallNPN_SetValueProc (sMozillaFuncs.setvalue, instance,
- NPPVpluginKeepLibraryInMemory, NS_INT32_TO_PTR(PR_TRUE));
-
- plugin = new totemPlugin (instance);
+ totemPlugin *plugin = new totemPlugin (instance);
if (!plugin)
return NPERR_OUT_OF_MEMORY_ERROR;
@@ -81,8 +70,6 @@ static NPError
totem_plugin_destroy_instance (NPP instance,
NPSavedData **save)
{
- D("plugin_destroy");
-
if (!instance)
return NPERR_INVALID_INSTANCE_ERROR;
@@ -198,14 +185,21 @@ totem_plugin_url_notify (NPP instance,
NPReason reason,
void* notifyData)
{
- D("plugin_url_notify");
+ if (!instance)
+ return;
+
+ totemPlugin *plugin = (totemPlugin *) instance->pdata;
+ if (!plugin)
+ return;
+
+ plugin->URLNotify (url, reason, notifyData);
}
static void
totem_plugin_print (NPP instance,
NPPrint* platformPrint)
{
- D("plugin_print");
+ D ("Print");
}
static char *
@@ -223,7 +217,7 @@ totem_plugin_get_value (NPP instance,
NPError err = NPERR_NO_ERROR;
/* See NPPVariable in npapi.h */
- D("plugin_get_value %d (%x)\n", variable, variable);
+ D ("GetValue variable %d (%x)", variable, variable);
if (instance) {
plugin = (totemPlugin *) instance->pdata;
@@ -240,7 +234,7 @@ totem_plugin_get_value (NPP instance,
*((NPBool *)value) = TRUE;
break;
case NPPVpluginScriptableIID: {
- nsIID* ptr = NS_STATIC_CAST (nsIID *, sMozillaFuncs.memalloc (sizeof (nsIID)));
+ nsIID* ptr = NS_STATIC_CAST (nsIID *, totemPlugin::sNPN.memalloc (sizeof (nsIID)));
if (ptr) {
*ptr = NS_GET_IID (nsISupports);
*NS_STATIC_CAST (nsIID **, value) = ptr;
@@ -259,7 +253,7 @@ totem_plugin_get_value (NPP instance,
break;
}
default:
- D("unhandled variable %d (%x)", variable, variable);
+ D ("Unhandled variable");
err = NPERR_INVALID_PARAM;
break;
}
@@ -272,7 +266,7 @@ totem_plugin_set_value (NPP instance,
NPNVariable variable,
void *value)
{
- D("plugin_set_value %d (%x)", variable, variable);
+ D ("SetValue variable %d (%x)", variable, variable);
return NPERR_NO_ERROR;
}
@@ -332,7 +326,7 @@ NP_Initialize (NPNetscapeFuncs * aMozillaFuncs,
NPBool supportsXEmbed = PR_FALSE;
NPNToolkitType toolkit = (NPNToolkitType) 0;
- D("NP_Initialize\n");
+ D ("NP_Initialize");
/* Do we support XEMBED? */
err = CallNPN_GetValueProc (aMozillaFuncs->getvalue, NULL,
@@ -354,6 +348,7 @@ NP_Initialize (NPNetscapeFuncs * aMozillaFuncs,
if ((aMozillaFuncs->version >> 8) > NP_VERSION_MAJOR)
return NPERR_INCOMPATIBLE_VERSION_ERROR;
+ /* FIXME: check instead: indexof (last known entry in NPNetscapeFuncs) */
if (aMozillaFuncs->size < sizeof (NPNetscapeFuncs))
return NPERR_INVALID_FUNCTABLE_ERROR;
if (plugin_funcs->size < sizeof (NPPluginFuncs))
@@ -366,29 +361,29 @@ NP_Initialize (NPNetscapeFuncs * aMozillaFuncs,
* structure, because the Mozilla function table could actually be
* bigger than what we expect.
*/
- sMozillaFuncs.size = aMozillaFuncs->size;
- sMozillaFuncs.version = aMozillaFuncs->version;
- sMozillaFuncs.geturl = aMozillaFuncs->geturl;
- sMozillaFuncs.posturl = aMozillaFuncs->posturl;
- sMozillaFuncs.requestread = aMozillaFuncs->requestread;
- sMozillaFuncs.newstream = aMozillaFuncs->newstream;
- sMozillaFuncs.write = aMozillaFuncs->write;
- sMozillaFuncs.destroystream = aMozillaFuncs->destroystream;
- sMozillaFuncs.status = aMozillaFuncs->status;
- sMozillaFuncs.uagent = aMozillaFuncs->uagent;
- sMozillaFuncs.memalloc = aMozillaFuncs->memalloc;
- sMozillaFuncs.memfree = aMozillaFuncs->memfree;
- sMozillaFuncs.memflush = aMozillaFuncs->memflush;
- sMozillaFuncs.reloadplugins = aMozillaFuncs->reloadplugins;
- sMozillaFuncs.getJavaEnv = aMozillaFuncs->getJavaEnv;
- sMozillaFuncs.getJavaPeer = aMozillaFuncs->getJavaPeer;
- sMozillaFuncs.geturlnotify = aMozillaFuncs->geturlnotify;
- sMozillaFuncs.posturlnotify = aMozillaFuncs->posturlnotify;
- sMozillaFuncs.getvalue = aMozillaFuncs->getvalue;
- sMozillaFuncs.setvalue = aMozillaFuncs->setvalue;
- sMozillaFuncs.invalidaterect = aMozillaFuncs->invalidaterect;
- sMozillaFuncs.invalidateregion = aMozillaFuncs->invalidateregion;
- sMozillaFuncs.forceredraw = aMozillaFuncs->forceredraw;
+ totemPlugin::sNPN.size = aMozillaFuncs->size;
+ totemPlugin::sNPN.version = aMozillaFuncs->version;
+ totemPlugin::sNPN.geturl = aMozillaFuncs->geturl;
+ totemPlugin::sNPN.posturl = aMozillaFuncs->posturl;
+ totemPlugin::sNPN.requestread = aMozillaFuncs->requestread;
+ totemPlugin::sNPN.newstream = aMozillaFuncs->newstream;
+ totemPlugin::sNPN.write = aMozillaFuncs->write;
+ totemPlugin::sNPN.destroystream = aMozillaFuncs->destroystream;
+ totemPlugin::sNPN.status = aMozillaFuncs->status;
+ totemPlugin::sNPN.uagent = aMozillaFuncs->uagent;
+ totemPlugin::sNPN.memalloc = aMozillaFuncs->memalloc;
+ totemPlugin::sNPN.memfree = aMozillaFuncs->memfree;
+ totemPlugin::sNPN.memflush = aMozillaFuncs->memflush;
+ totemPlugin::sNPN.reloadplugins = aMozillaFuncs->reloadplugins;
+ totemPlugin::sNPN.getJavaEnv = aMozillaFuncs->getJavaEnv;
+ totemPlugin::sNPN.getJavaPeer = aMozillaFuncs->getJavaPeer;
+ totemPlugin::sNPN.geturlnotify = aMozillaFuncs->geturlnotify;
+ totemPlugin::sNPN.posturlnotify = aMozillaFuncs->posturlnotify;
+ totemPlugin::sNPN.getvalue = aMozillaFuncs->getvalue;
+ totemPlugin::sNPN.setvalue = aMozillaFuncs->setvalue;
+ totemPlugin::sNPN.invalidaterect = aMozillaFuncs->invalidaterect;
+ totemPlugin::sNPN.invalidateregion = aMozillaFuncs->invalidateregion;
+ totemPlugin::sNPN.forceredraw = aMozillaFuncs->forceredraw;
/*
* Set up a plugin function table that Mozilla will use to call
@@ -422,14 +417,18 @@ NP_Initialize (NPNetscapeFuncs * aMozillaFuncs,
plugin_funcs->getvalue = NewNPP_GetValueProc(totem_plugin_get_value);
plugin_funcs->setvalue = NewNPP_SetValueProc(totem_plugin_set_value);
- return NPERR_NO_ERROR;
+ D ("NP_Initialize succeeded");
+
+ return totemPlugin::Initialise ();
}
NPError
NP_Shutdown(void)
{
+ D ("NP_Shutdown");
+
g_free (mime_list);
mime_list = NULL;
- return NPERR_NO_ERROR;
+ return totemPlugin::Shutdown ();
}
diff --git a/configure.in b/configure.in
index 2a2465a4c..2577642bc 100644
--- a/configure.in
+++ b/configure.in
@@ -158,6 +158,10 @@ if test x$HAVE_XINE = xno; then
done
fi
+if test "$HAVE_GSTREAMER" = "yes"; then
+ AC_DEFINE([HAVE_GSTREAMER],[1],[Define if using gst backend])
+fi
+
AM_CONDITIONAL(TOTEM_GST, test "x$HAVE_GSTREAMER" = "xyes")
AC_ARG_ENABLE(vanity,
@@ -243,25 +247,28 @@ AC_MSG_CHECKING([whether to compile the browser plugins])
AC_ARG_ENABLE([browser-plugins],
AS_HELP_STRING([--enable-mozilla],[compile the mozilla plugin]),
- [ENABLE_MOZILLA=$enableval],
- [ENABLE_MOZILLA=autodetect])
+ [],[enable_browser_plugins=autodetect])
# Backward compatibility
AC_ARG_ENABLE([mozilla],[],[enable_browser_plugins=$enableval],[enable_browser_plugins=autodetect])
-AC_MSG_RESULT([$ENABLE_MOZILLA])
+AC_MSG_RESULT([$enable_browser_plugins])
-dnl Check which mozilla to use
-if test "x$ENABLE_MOZILLA" != "xno" ; then
+# Check which mozilla to use
+
+if test "$enable_browser_plugins" != "no" ; then
AC_MSG_CHECKING([which gecko to use])
- AC_ARG_WITH([mozilla],
- AS_HELP_STRING([--with-mozilla],[Which gecko engine to use (default: autodetect)]))
+ AC_ARG_WITH([gecko],
+ [AS_HELP_STRING([--with-gecko],[Which gecko engine to use (default: autodetect)])])
+
+ # backward compat
+ AC_ARG_WITH([mozilla],[],[with_gecko=$withval])
GECKOS="xulrunner firefox mozilla-firefox seamonkey mozilla"
- gecko=$with_mozilla
+ gecko=$with_gecko
- if test "x$gecko" = "x"; then
+ if test -z "$with_gecko"; then
dnl Autodetect gecko
for g in $GECKOS; do
if $PKG_CONFIG --exists $g-xpcom; then
@@ -273,16 +280,16 @@ if test "x$ENABLE_MOZILLA" != "xno" ; then
AC_MSG_ERROR([Gecko "$gecko" not found])
fi
- if test "x$gecko" = "x" -a "x$ENABLE_MOZILLA" = "xautodetect"; then
+ if test -z "$gecko" -a "$enable_browser_plugins" = "autodetect"; then
dnl No gecko found, disable plugin
AC_MSG_WARN([No gecko found, disabling plugin])
- ENABLE_MOZILLA=no
- elif test "x$gecko" = "x"; then
+ enable_browser_plugins=no
+ elif test -z "$gecko"; then
AC_MSG_ERROR([No gecko found])
elif ! ( echo "$GECKOS" | egrep "(^| )$gecko(\$| )" > /dev/null); then
AC_MSG_ERROR([Unknown gecko "$gecko" specified])
else
- ENABLE_MOZILLA=yes
+ enable_browser_plugins=yes
fi
AC_MSG_RESULT([$gecko])
@@ -297,7 +304,7 @@ if test "x$ENABLE_MOZILLA" != "xno" ; then
MOZILLA=$gecko
AC_SUBST([MOZILLA])
- if test "$enable_cxx_warnings" != "no" -a "$GCC" = "yes"; then
+ if test "$enable_cxx_warnings" != "no" -a "$GXX" = "yes"; then
PLUGIN_EXTRA_WARN_CXXFLAGS="-Wno-ctor-dtor-privacy -Wno-non-virtual-dtor -Woverloaded-virtual"
else
PLUGIN_EXTRA_WARN_CXXFLAGS=
@@ -305,23 +312,23 @@ if test "x$ENABLE_MOZILLA" != "xno" ; then
AC_SUBST([PLUGIN_EXTRA_WARN_CXXFLAGS])
fi
-dnl Check for mozilla modules, but keep the CFLAGS and LIBS in
-dnl separate vars
-if test "x$ENABLE_MOZILLA" = "xyes" ; then
+# Check for mozilla modules, but keep the CFLAGS and LIBS in
+# separate vars
+if test "$enable_browser_plugins" = "yes" ; then
PKG_CHECK_MODULES([MOZILLA_NOT_LINKED],
[$MOZILLA-xpcom >= $MOZILLA_VERSION_MIN \
$MOZILLA-plugin],,
- [ENABLE_MOZILLA=no])
+ [enable_browser_plugins=no])
fi
-dnl Check for other required modules, and merge CFLAGS, but not link
-dnl flags to avoid linking against -lxpcom -lplds4 -lplc4 -lnspr4
-if test "x$ENABLE_MOZILLA" = "xyes" ; then
+# Check for other required modules, and merge CFLAGS, but not link
+# flags to avoid linking against -lxpcom -lplds4 -lplc4 -lnspr4
+if test "$enable_browser_plugins" = "yes" ; then
PKG_CHECK_MODULES([BROWSER_PLUGIN],
[glib-2.0
gnome-vfs-2.0 >= $GNOMEVFS_REQS
gnome-vfs-module-2.0 >= $GNOMEVFS_REQS
gthread-2.0],
- [],[ENABLE_MOZILLA=no])
+ [],[enable_browser_plugins=no])
BROWSER_PLUGIN_CFLAGS="$MOZILLA_NOT_LINKED_CFLAGS $BROWSER_PLUGIN_CFLAGS"
AC_SUBST([BROWSER_PLUGIN_CFLAGS])
@@ -335,20 +342,20 @@ if test "x$ENABLE_MOZILLA" = "xyes" ; then
>= 0.17 to function.])])
fi
-if test "x$ENABLE_MOZILLA" = "xyes" ; then
+if test "$enable_browser_plugins" = "yes" ; then
PKG_CHECK_MODULES([DBUS], [dbus-glib-1 >= $DBUS_REQS],,
- [ENABLE_MOZILLA=no])
+ [enable_browser_plugins=no])
DBUSLIBDIR="`$PKG_CONFIG dbus-glib-1 --variable=libdir`"
DBUSBINDIR="`echo $DBUSLIBDIR | sed -e s/lib/bin/`"
AC_PATH_PROG([DBUS_BIND], [dbus-binding-tool], [no], [$DBUSBINDIR:$PATH])
if test "x$DBUS_BIND" = "xno"; then
AC_MSG_WARN([dbus-binding-tool not found])
- ENABLE_MOZILLA=no
+ enable_browser_plugins=no
fi
fi
-dnl Sets some variables, and check for xpidl
-if test "x$ENABLE_MOZILLA" = "xyes" ; then
+# Sets some variables, and check for xpidl
+if test "$enable_browser_plugins" = "yes" ; then
MOZILLA_PREFIX="`$PKG_CONFIG $MOZILLA-xpcom --variable=prefix`"
MOZILLA_LIBDIR="`$PKG_CONFIG $MOZILLA-xpcom --variable=libdir`"
MOZILLA_INCLUDE_ROOT="`$PKG_CONFIG --variable=includedir $MOZILLA-xpcom`"
@@ -372,8 +379,8 @@ if test "x$ENABLE_MOZILLA" = "xyes" ; then
AC_ARG_VAR([MOZILLA_PLUGINDIR],[Where to install the plugin to])
fi
-dnl Search for the idl include directory
-if test "x$ENABLE_MOZILLA" = "xyes" ; then
+# Search for the idl include directory
+if test "$enable_browser_plugins" = "yes" ; then
dnl This only works on gecko 1.8
MOZILLA_IDLDIR="`$PKG_CONFIG --variable=idldir $MOZILLA-xpcom`"
dnl Fallback for older versions
@@ -388,13 +395,71 @@ if test "x$ENABLE_MOZILLA" = "xyes" ; then
AC_SUBST([MOZILLA_IDLDIR])
fi
-if test "$ENABLE_MOZILLA" = "yes" ; then
- AC_DEFINE([HAVE_MOZILLA],[1],[Define if you build the mozilla plugin])
+if test "$enable_browser_plugins" = "yes" ; then
+ AC_DEFINE([ENABLE_BROWSER_PLUGINS],[1],[Define if you build the mozilla plugin])
+fi
+
+AM_CONDITIONAL([ENABLE_BROWSER_PLUGINS], [test "$enable_browser_plugins" = "yes"])
+
+# check for libxpcomglue_s
+
+LIBXPCOMGLUE_S=
+
+if test "$enable_browser_plugins" = "yes"; then
+ AC_LANG_PUSH([C++])
+ __SAVE_CPPFLAGS=$CPPFLAGS
+ __SAVE_CXXFLAGS=$CXXFLAGS
+ __SAVE_LIBS=$LIBS
+ __SAVE_LDFLAGS=$LDFLAGS
+
+ CPPFLAGS="$CPPFLAGS -I$MOZILLA_INCLUDE_ROOT"
+ CXXFLAGS="$CXXFLAGS $MOZILLA_NOT_LINKED_CFLAGS"
+ LIBS="$LIBS -L$MOZILLA_LIBDIR -lxpcom -lxpcomglue_s"
+ LDFLAGS="$LDFLAGS -Wl,--rpath -Wl,$MOZILLA_LIBDIR"
+
+ AC_MSG_CHECKING([for libxpcomglue_s])
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+#include <mozilla-config.h>
+#include <nsStringAPI.h>
+ ]],[[
+nsCString s;
+const char *t = s.get ();
+ ]])],
+ [have_libxpcomglue_s=yes],
+ [have_libxpcomglue_s=no])
+ AC_MSG_RESULT([$have_libxpcomglue_s])
+
+ CPPFLAGS=$__SAVE_CPPFLAGS
+ CXXFLAGS=$__SAVE_CXXFLAGS
+ LIBS=$__SAVE_LIBS
+ LDFLAGS=$__SAVE_LDFLAGS
+ AC_LANG_POP([C++])
+
+ if test "$have_libxpcomglue_s" = "yes"; then
+ LIBXPCOMGLUE_S="-L$MOZILLA_LIBDIR -lxpcomglue_s"
+ else
+ AC_MSG_WARN([libxpcomglue_s not available; plugins may not be portable])
+ fi
+fi
+
+AC_SUBST([LIBXPCOMGLUE_S])
+
+# check for some additional xpcom headers
+
+if test "$enable_browser_plugins" = "yes"; then
+ AC_LANG_PUSH([C++])
+ __SAVE_CPPFLAGS=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $MOZILLA_NOT_LINKED_CFLAGS -I$MOZILLA_INCLUDE_ROOT/xpcom"
+
+ AC_CHECK_HEADERS([nsTArray.h])
+
+ CPPFLAGS=$__SAVE_CPPFLAGS
+ AC_LANG_POP([C++])
fi
-AM_CONDITIONAL([HAVE_MOZILLA], [test "x$ENABLE_MOZILLA" = "xyes"])
+# check which plugins to enable
-if test "$ENABLE_MOZILLA" = "yes"; then
+if test "$enable_browser_plugins" = "yes"; then
AC_MSG_CHECKING([whether to enable the basic browser plugin])
AC_ARG_ENABLE([basic-plugin],
diff --git a/data/mozilla-viewer.glade b/data/mozilla-viewer.glade
index 59ecaa4ec..3034148e9 100644
--- a/data/mozilla-viewer.glade
+++ b/data/mozilla-viewer.glade
@@ -4,8 +4,7 @@
<glade-interface>
<widget class="GtkWindow" id="window">
- <property name="visible">True</property>
- <property name="title" translatable="yes">window1</property>
+ <property name="title"></property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">False</property>
@@ -20,13 +19,13 @@
<property name="urgency_hint">False</property>
<child>
- <widget class="GtkVBox" id="vbox1">
+ <widget class="GtkVBox" id="content_box">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
- <widget class="GtkHBox" id="hbox4">
+ <widget class="GtkHBox" id="video_box">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
@@ -53,7 +52,7 @@
<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>
+ <property name="focus_on_click">False</property>
<child>
<widget class="GtkAlignment" id="alignment1">
@@ -146,7 +145,7 @@
</child>
<child>
- <widget class="Custom" id="emb_statusbar">
+ <widget class="Custom" id="statusbar">
<property name="visible">True</property>
<property name="creation_function">totem_statusbar_create</property>
<property name="int1">0</property>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 9c8999a13..436fd62b4 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -16,7 +16,6 @@ src/bacon-video-widget-properties.c
src/bacon-volume.c
src/totem-interface.c
src/totem-menu.c
-src/totem-mozilla-viewer.c
src/totem-options.c
src/totem-playlist.c
src/totem-preferences.c
@@ -37,4 +36,4 @@ src/backend/bacon-video-widget-xine.c
src/backend/video-utils.c
src/plparse/totem-disc.c
src/plparse/totem-pl-parser.c
-
+browser-plugin/totem-plugin-viewer.c
diff --git a/src/Makefile.am b/src/Makefile.am
index c68d4118f..93746349c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,5 @@
SUBDIRS = backend plparse
-
if TOTEM_VANITY
VANITY=vanity
else
@@ -19,10 +18,6 @@ bin_PROGRAMS = totem totem-video-thumbnailer totem-video-indexer $(VANITY)
libexec_PROGRAMS =
noinst_PROGRAMS = list_v4l disc-test $(TOTEM_PROPERTIES_PAGE_TEST)
-if HAVE_MOZILLA
-libexec_PROGRAMS += totem-mozilla-viewer
-endif
-
noinst_LTLIBRARIES = \
libbaconpropertiespage.la \
libbaconmessageconnection.la \
@@ -102,7 +97,7 @@ totem_video_thumbnailer_LDADD = \
$(XTEST_LIBS) $(X_LIBS)
nautilusdir = $(libdir)/nautilus/extensions-1.0/
-libtotem_properties_page_la_CFLAGS = -I$(top_srcdir)
+libtotem_properties_page_la_CFLAGS = -I$(top_srcdir) $(WARN_CFLAGS)
libtotem_properties_page_la_SOURCES = \
totem-properties-main.c \
totem-properties-view.c \
@@ -114,7 +109,7 @@ libtotem_properties_page_la_LIBADD = \
$(XTEST_LIBS) $(X_LIBS)
libtotem_properties_page_la_LDFLAGS = $(modules_flags)
-test_properties_page_CFLAGS = -I$(top_srcdir)
+test_properties_page_CFLAGS = -I$(top_srcdir) $(WARN_CFLAGS)
test_properties_page_SOURCES = \
totem-properties-main.c \
totem-properties-view.c \
@@ -129,27 +124,6 @@ test_properties_page_LDADD = \
BUILT_SOURCES =
-if HAVE_MOZILLA
-
-BUILT_SOURCES += \
- totem-mozilla-interface.h
-
-totem-mozilla-interface.h: totem-mozilla-interface.xml
- $(DBUS_BIND) --prefix=totem_embedded --mode=glib-server \
- --output=totem-mozilla-interface.h $<
-
-totem_mozilla_viewer_SOURCES = \
- totem-mozilla-viewer.c \
- totem-mozilla-options.h
-
-totem_mozilla_viewer_LDADD = \
- backend/libbaconvideowidget.la libbaconpropertiespage.la \
- libtotem_player.la plparse/libtotem-plparser.la \
- $(EXTRA_GNOME_LIBS) $(XVIDMODE_LIBS) \
- $(DBUS_LIBS) $(NVTV_LIBS) \
- $(XTEST_LIBS) $(X_LIBS)
-endif
-
vanity_SOURCES = \
$(BACON_V4L_SELECTION) \
totem-screenshot.c totem-screenshot.h \
@@ -182,11 +156,9 @@ INCLUDES = \
-I$(top_builddir)/src/plparse \
-I$(top_builddir)/src/backend \
$(EXTRA_GNOME_CFLAGS) \
+ $(WARN_CFLAGS) \
-DDBUS_API_SUBJECT_TO_CHANGE \
$(DBUS_CFLAGS) \
- $(MOZILLA_CFLAGS) \
- $(MOZILLA_SUBDIR_INCLUDES) \
- $(MOZILLA_XPCOM_CFLAGS) \
$(NVTV_CFLAGS) \
$(NAUTILUS_CFLAGS) \
-DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
@@ -199,6 +171,4 @@ INCLUDES = \
CLEANFILES = *.bak *.gladep core* *.orig *~ $(desktop_DATA) $(BUILT_SOURCES)
EXTRA_DIST = \
$(BACON_V4L_SELECTION) \
- vanity.c \
- totem-mozilla-viewer.c \
- totem-mozilla-interface.xml
+ vanity.c
diff --git a/src/backend/bvw-test.c b/src/backend/bvw-test.c
index 012ba7fcb..0ece0fbf6 100644
--- a/src/backend/bvw-test.c
+++ b/src/backend/bvw-test.c
@@ -16,6 +16,11 @@ static void test_xine_set_mrl(char *path)
bacon_video_widget_open (BACON_VIDEO_WIDGET (xine), mrl, NULL);
}
+static void on_redirect (GtkWidget *bvw, const char *mrl, gpointer data)
+{
+ g_message ("Redirect to: %s", mrl);
+}
+
static void on_eos_event(GtkWidget *widget, gpointer user_data)
{
bacon_video_widget_stop (BACON_VIDEO_WIDGET (xine));
@@ -59,6 +64,7 @@ int main(int argc, char *argv[])
gtk_widget_realize (xine);
g_signal_connect(G_OBJECT (xine),"eos",G_CALLBACK (on_eos_event),NULL);
+ g_signal_connect (G_OBJECT(xine), "got-redirect", G_CALLBACK (on_redirect), NULL);
gtk_widget_show(win);
gtk_widget_show(xine);
diff --git a/src/plparse/totem-pl-parser.c b/src/plparse/totem-pl-parser.c
index 5628d9b9c..c4446dcff 100644
--- a/src/plparse/totem-pl-parser.c
+++ b/src/plparse/totem-pl-parser.c
@@ -2674,17 +2674,17 @@ totem_pl_parser_can_parse_from_data (const char *data,
for (i = 0; i < G_N_ELEMENTS(special_types); i++) {
if (strcmp (special_types[i].mimetype, mimetype) == 0) {
- D(g_message ("Is special type '%s'\n", mimetype));
+ D(g_message ("Is special type '%s'", mimetype));
return TRUE;
}
}
for (i = 0; i < G_N_ELEMENTS(dual_types); i++) {
if (strcmp (dual_types[i].mimetype, mimetype) == 0) {
- D(g_message ("Should be dual type '%s', making sure now\n", mimetype));
+ D(g_message ("Should be dual type '%s', making sure now", mimetype));
if (dual_types[i].iden != NULL) {
gboolean retval = (* dual_types[i].iden) (data, len);
- D(g_message ("%s dual type '%s'\n",
+ D(g_message ("%s dual type '%s'",
retval ? "Is" : "Is not", mimetype));
return retval;
}
diff --git a/src/totem-mozilla-interface.xml b/src/totem-mozilla-interface.xml
deleted file mode 100644
index e7696bd53..000000000
--- a/src/totem-mozilla-interface.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<node name="/">
- <interface name="org.totem.MozillaPluginInterface">
- <method name="Play"/>
- <method name="Pause"/>
- <method name="Stop"/>
- <method name="SetLocalFile">
- <arg type="s"/>
- </method>
- <signal name="StopSendingData"/>
- </interface>
-</node>
diff --git a/src/totem-mozilla-viewer.c b/src/totem-mozilla-viewer.c
deleted file mode 100644
index 20b5977a5..000000000
--- a/src/totem-mozilla-viewer.c
+++ /dev/null
@@ -1,1077 +0,0 @@
-/* Totem Mozilla Embedded Viewer
- *
- * Copyright (C) <2004-2006> Bastien Nocera <hadess@hadess.net>
- * Copyright (C) <2002> David A. Schleef <ds@schleef.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "config.h"
-
-#include <gtk/gtk.h>
-#include <glib/gi18n.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <gdk/gdkx.h>
-#include <glade/glade.h>
-#include <gconf/gconf-client.h>
-#include <totem-pl-parser.h>
-
-#include <dbus/dbus-glib.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <libgnomevfs/gnome-vfs.h>
-#include <libgnomevfs/gnome-vfs-mime-handlers.h>
-
-#include "bacon-video-widget.h"
-#include "totem-interface.h"
-#include "totem-mozilla-options.h"
-#include "totem-statusbar.h"
-#include "bacon-volume.h"
-#include "video-utils.h"
-
-GtkWidget *totem_statusbar_create (void);
-GtkWidget *totem_volume_create (void);
-
-#define IS_FD_STREAM (strcmp(emb->filename, "fd://0") == 0)
-
-#define VOLUME_DOWN_OFFSET -8
-#define VOLUME_UP_OFFSET 8
-
-/* For newer D-Bus version */
-#ifndef DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT
-#define DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT 0
-#endif
-
-typedef enum {
- STATE_PLAYING,
- STATE_PAUSED,
- STATE_STOPPED
-} TotemStates;
-
-#define TOTEM_TYPE_EMBEDDED (totem_embedded_get_type ())
-typedef struct {
- GObjectClass parent_class;
-
- void (*stop_sending_data) (GObject *emb);
-} TotemEmbeddedClass;
-
-typedef struct _TotemEmbedded {
- GObject parent;
-
- GtkWidget *window;
- GladeXML *menuxml, *xml;
- GtkWidget *about;
- TotemStatusbar *statusbar;
- int width, height;
- const char *orig_filename;
- const char *mimetype;
- char *filename, *href, *target;
- BaconVideoWidget *bvw;
- TotemStates state;
- GdkCursor *cursor;
-
- /* Playlist */
- GList *playlist, *current;
- GMainLoop *loop;
- int num_items;
-
- /* Open menu item */
- GnomeVFSMimeApplication *app;
- GtkWidget *menu_item;
-
- /* Seek bits */
- GtkAdjustment *seekadj;
- GtkWidget *seek;
-
- guint is_playlist : 1;
- guint embedded_done : 1;
- guint controller_hidden : 1;
- guint hidden : 1;
- guint repeat : 1;
- guint seeking : 1;
- guint noautostart : 1;
-} TotemEmbedded;
-
-GType totem_embedded_get_type (void);
-
-G_DEFINE_TYPE (TotemEmbedded, totem_embedded, G_TYPE_OBJECT);
-static void totem_embedded_init (TotemEmbedded *emb) { }
-
-gboolean totem_embedded_play (TotemEmbedded *emb, GError **err);
-gboolean totem_embedded_pause (TotemEmbedded *emb, GError **err);
-gboolean totem_embedded_stop (TotemEmbedded *emb, GError **err);
-gboolean totem_embedded_set_local_file (TotemEmbedded *emb, const char *url, GError **err);
-
-static void totem_embedded_set_menu (TotemEmbedded *emb, gboolean enable);
-static void on_open1_activate (GtkButton *button, TotemEmbedded *emb);
-
-#include "totem-mozilla-interface.h"
-
-enum {
- STOP_SENDING_DATA,
- LAST_SIGNAL
-};
-static int totem_emb_table_signals[LAST_SIGNAL] = { 0 };
-
-static void totem_embedded_class_init (TotemEmbeddedClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = (GObjectClass *) klass;
-
- totem_emb_table_signals[STOP_SENDING_DATA] =
- g_signal_new ("stop-sending-data",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (TotemEmbeddedClass, stop_sending_data),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-}
-
-static void
-totem_embedded_exit (TotemEmbedded *emb)
-{
- //FIXME what happens when embedded, and we can't go on?
- exit (1);
-}
-
-static void
-totem_embedded_error_and_exit (char *title, char *reason, TotemEmbedded *emb)
-{
- totem_interface_error_blocking (title, reason,
- GTK_WINDOW (emb->window));
- totem_embedded_exit (emb);
-}
-
-static void
-totem_embedded_emit_stop_sending_data (TotemEmbedded *emb)
-{
- g_return_if_fail (emb->filename != NULL);
- if (IS_FD_STREAM) {
- g_signal_emit (G_OBJECT (emb),
- totem_emb_table_signals[STOP_SENDING_DATA],
- 0, NULL);
- }
-}
-
-static void
-totem_embedded_set_state (TotemEmbedded *emb, TotemStates state)
-{
- char *id = NULL;
- GtkWidget *image;
- GdkCursor *cursor;
-
- if (state == emb->state)
- return;
-
- cursor = NULL;
- image = glade_xml_get_widget (emb->xml, "emb_pp_button_image");
-
- switch (state) {
- case STATE_STOPPED:
- if (emb->href != NULL)
- cursor = emb->cursor;
- id = g_strdup_printf ("gtk-media-play-%s",
- gtk_widget_get_direction (image) ? "ltr" : "rtl");
- totem_statusbar_set_text (emb->statusbar, _("Stopped"));
- totem_statusbar_set_time_and_length (emb->statusbar, 0, 0);
- break;
- case STATE_PAUSED:
- id = g_strdup_printf ("gtk-media-play-%s",
- gtk_widget_get_direction (image) ? "ltr" : "rtl");
- totem_statusbar_set_text (emb->statusbar, _("Paused"));
- break;
- case STATE_PLAYING:
- id = g_strdup ("gtk-media-pause");
- totem_statusbar_set_text (emb->statusbar, _("Playing"));
- break;
- default:
- break;
- }
-
- gtk_image_set_from_icon_name (GTK_IMAGE (image), id, GTK_ICON_SIZE_MENU);
- g_free (id);
- if (emb->hidden == FALSE && cursor != NULL)
- gdk_window_set_cursor (GTK_WIDGET (emb->bvw)->window, cursor);
-
- emb->state = state;
-}
-
-static void
-totem_embedded_set_pp_state (TotemEmbedded *emb, gboolean state)
-{
- GtkWidget *item;
-
- item = glade_xml_get_widget (emb->xml, "pp_button");
- gtk_widget_set_sensitive (item, state);
-}
-
-static gboolean
-totem_embedded_open (TotemEmbedded *emb)
-{
- GError *err = NULL;
- gboolean retval;
-
- g_message ("totem_embedded_open '%s'", emb->filename);
-
- retval = bacon_video_widget_open (emb->bvw, emb->filename, &err);
- if (retval == FALSE)
- {
- char *msg, *disp;
-
- totem_embedded_emit_stop_sending_data (emb);
-
- totem_embedded_set_state (emb, STATE_STOPPED);
-
- //FIXME if emb->filename is fd://0 or stdin:///
- //we should use a better name than that
- disp = g_strdup (emb->filename);
- //disp = gnome_vfs_unescape_string_for_display (totem->mrl);
- msg = g_strdup_printf(_("Totem could not play '%s'."), disp);
- g_free (disp);
-
- g_message ("error: %s", err->message);
- totem_interface_error_blocking (msg, err->message,
- GTK_WINDOW (emb->window));
- g_free (msg);
- g_error_free (err);
-
- totem_embedded_set_pp_state (emb, FALSE);
- } else {
- totem_embedded_set_state (emb, STATE_PAUSED);
- totem_embedded_set_pp_state (emb, TRUE);
- }
-
- if (IS_FD_STREAM && emb->num_items > 1) {
- totem_embedded_set_menu (emb, FALSE);
- } else {
- totem_embedded_set_menu (emb, TRUE);
- }
-
- return retval;
-}
-
-gboolean
-totem_embedded_play (TotemEmbedded *emb, GError **err)
-{
- if (bacon_video_widget_play (emb->bvw, NULL))
- totem_embedded_set_state (emb, STATE_PLAYING);
- return TRUE;
-}
-
-gboolean
-totem_embedded_pause (TotemEmbedded *emb, GError **err)
-{
- bacon_video_widget_pause (emb->bvw);
- totem_embedded_set_state (emb, STATE_PAUSED);
- return TRUE;
-}
-
-gboolean
-totem_embedded_stop (TotemEmbedded *emb, GError **err)
-{
- bacon_video_widget_stop (emb->bvw);
- totem_embedded_set_state (emb, STATE_STOPPED);
- return TRUE;
-}
-
-gboolean
-totem_embedded_set_local_file (TotemEmbedded *emb,
- const char *path, GError **err)
-{
- g_message ("Setting the current path to %s", path);
-
- g_free (emb->filename);
- emb->filename = g_filename_to_uri (path, NULL, NULL);
-
- return TRUE;
-}
-
-static void
-totem_embedded_set_menu (TotemEmbedded *emb, gboolean enable)
-{
- GtkWidget *menu, *item, *image;
- GtkWidget *copy;
- char *label;
-
- copy = glade_xml_get_widget (emb->menuxml, "copy_location1");
- gtk_widget_set_sensitive (copy, enable);
-
- if (emb->menu_item != NULL) {
- gtk_widget_destroy (emb->menu_item);
- emb->menu_item = NULL;
- }
- if (emb->app != NULL) {
- gnome_vfs_mime_application_free (emb->app);
- emb->app = NULL;
- }
-
- if (enable == FALSE)
- return;
-
- if (IS_FD_STREAM) {
- emb->app = gnome_vfs_mime_get_default_application_for_uri
- (emb->orig_filename, emb->mimetype);
- } else {
- emb->app = gnome_vfs_mime_get_default_application_for_uri
- (emb->filename, emb->mimetype);
- }
-
- if (emb->app == NULL)
- return;
-
- /* translators: this is:
- * Open With ApplicationName
- * as in nautilus' right-click menu */
- label = g_strdup_printf ("_Open with \"%s\"", emb->app->name);
- item = gtk_image_menu_item_new_with_mnemonic (label);
- g_free (label);
- image = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
- g_signal_connect (G_OBJECT (item), "activate",
- G_CALLBACK (on_open1_activate), emb);
- gtk_widget_show (item);
- emb->menu_item = item;
-
- menu = glade_xml_get_widget (emb->menuxml, "menu");
- gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
-}
-
-static void
-on_open1_activate (GtkButton *button, TotemEmbedded *emb)
-{
- GList *l = NULL;
-
- g_return_if_fail (emb->app != NULL);
-
- if (IS_FD_STREAM) {
- l = g_list_prepend (l, (gpointer) emb->orig_filename);
- } else if (emb->href != NULL) {
- l = g_list_prepend (l, emb->href);
- } else {
- l = g_list_prepend (l, emb->filename);
- }
-
- if (gnome_vfs_mime_application_launch (emb->app, l) == GNOME_VFS_OK) {
- totem_embedded_stop (emb, NULL);
- }
-
- g_list_free (l);
-}
-
-static void
-on_about1_activate (GtkButton *button, TotemEmbedded *emb)
-{
- char *backend_version, *description;
-
- const char *authors[] =
- {
- "Bastien Nocera <hadess@hadess.net>",
- "Ronald Bultje <rbultje@ronald.bitfreak.net>",
- NULL
- };
-
- if (emb->about != NULL)
- {
- gtk_window_present (GTK_WINDOW (emb->about));
- return;
- }
-
- backend_version = bacon_video_widget_get_backend_name (emb->bvw);
- description = g_strdup_printf (_("Browser Plugin using %s"),
- backend_version);
-
- emb->about = g_object_new (GTK_TYPE_ABOUT_DIALOG,
- "name", _("Totem Browser Plugin"),
- "version", VERSION,
- "copyright", _("Copyright \xc2\xa9 2002-2006 Bastien Nocera"),
- "comments", description,
- "authors", authors,
- "translator-credits", _("translator-credits"),
- "logo-icon-name", "totem",
- NULL);
-
- g_free (backend_version);
- g_free (description);
-
- totem_interface_set_transient_for (GTK_WINDOW (emb->about),
- GTK_WINDOW (emb->window));
-
- g_object_add_weak_pointer (G_OBJECT (emb->about),
- (gpointer *)&emb->about);
- g_signal_connect (G_OBJECT (emb->about), "response",
- G_CALLBACK (gtk_widget_destroy), NULL);
-
- gtk_widget_show (emb->about);
-}
-
-static void
-on_copy_location1_activate (GtkButton *button, TotemEmbedded *emb)
-{
- GtkClipboard *clip;
- const char *filename;
-
- if (IS_FD_STREAM) {
- filename = emb->orig_filename;
- } else if (emb->href != NULL) {
- filename = emb->href;
- } else {
- filename = emb->filename;
- }
-
- /* Set both the middle-click and the super-paste buffers */
- clip = gtk_clipboard_get_for_display
- (gdk_display_get_default(), GDK_SELECTION_CLIPBOARD);
- gtk_clipboard_set_text (clip, filename, -1);
- clip = gtk_clipboard_get_for_display
- (gdk_display_get_default(), GDK_SELECTION_PRIMARY);
- gtk_clipboard_set_text (clip, filename, -1);
-}
-
-static void
-on_play_pause (GtkWidget *widget, TotemEmbedded *emb)
-{
- if (emb->state == STATE_PLAYING) {
- totem_embedded_pause (emb, NULL);
- } else {
- totem_embedded_play (emb, NULL);
- }
-}
-
-static void
-on_got_redirect (GtkWidget *bvw, const char *mrl, TotemEmbedded *emb)
-{
- gchar *new_filename;
-
- g_message ("url: %s", emb->orig_filename);
- g_message ("redirect: %s", mrl);
-
- if (emb->orig_filename)
- new_filename = totem_resolve_relative_link (emb->orig_filename, mrl);
- else
- new_filename = totem_resolve_relative_link (emb->filename, mrl);
-
- g_free (emb->filename);
- emb->filename = new_filename;
-
- bacon_video_widget_close (emb->bvw);
- totem_embedded_set_state (emb, STATE_STOPPED);
-
- if (totem_embedded_open (emb) != FALSE)
- totem_embedded_play (emb, NULL);
-}
-
-static gboolean
-on_video_button_press_event (BaconVideoWidget *bvw, GdkEventButton *event,
- TotemEmbedded *emb)
-{
- if (event->type == GDK_BUTTON_PRESS &&
- event->button == 1 &&
- emb->href != NULL)
- {
- if (emb->target != NULL &&
- !g_ascii_strcasecmp (emb->target, "QuicktimePlayer")) {
- gchar *cmd;
- GError *err = NULL;
-
- if (g_file_test ("./totem",
- G_FILE_TEST_EXISTS) != FALSE) {
- cmd = g_strdup_printf ("./totem %s",
- emb->href);
- } else {
- cmd = g_strdup_printf (BINDIR"/totem %s",
- emb->href);
- }
- if (!g_spawn_command_line_async (cmd, &err)) {
- totem_interface_error_blocking (
- _("Failed to start stand-alone movie player"),
- err ? err->message : _("Unknown reason"),
- GTK_WINDOW (emb->window));
- }
- g_free (cmd);
- } else {
- g_free (emb->filename);
- emb->filename = emb->href;
- emb->href = NULL;
- bacon_video_widget_close (emb->bvw);
- totem_embedded_set_state (emb, STATE_STOPPED);
-
- if (emb->controller_hidden != FALSE) {
- GtkWidget *controls;
- controls = glade_xml_get_widget (emb->xml, "controls");
- gtk_widget_show (controls);
- }
-
-
- if (totem_embedded_open (emb) != FALSE)
- totem_embedded_play (emb, NULL);
-
- return TRUE;
- }
- } else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
- GtkMenu *menu;
-
- menu = GTK_MENU (glade_xml_get_widget (emb->menuxml, "menu"));
- gtk_menu_popup (menu, NULL, NULL, NULL, NULL,
- event->button, event->time);
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-static void
-on_eos_event (GtkWidget *bvw, TotemEmbedded *emb)
-{
- totem_embedded_set_state (emb, STATE_STOPPED);
- gtk_adjustment_set_value (emb->seekadj, 0);
-
- /* No playlist if we have fd://0, right? */
- if (IS_FD_STREAM) {
- totem_embedded_set_pp_state (emb, FALSE);
- } else if (emb->num_items == 1) {
- if (g_str_has_prefix (emb->filename, "file://") != FALSE) {
- if (bacon_video_widget_is_seekable (emb->bvw) != FALSE) {
- bacon_video_widget_pause (emb->bvw);
- bacon_video_widget_seek (emb->bvw, 0.0, NULL);
- } else {
- bacon_video_widget_close (emb->bvw);
- totem_embedded_open (emb);
- }
- } else {
- bacon_video_widget_close (emb->bvw);
- totem_embedded_open (emb);
- }
- if (emb->repeat != FALSE && emb->noautostart == FALSE)
- totem_embedded_play (emb, NULL);
- } else {
- /* Multiple items on the playlist */
- gboolean eop = FALSE, res;
-
- if (emb->current->next == NULL) {
- emb->current = emb->playlist;
- eop = TRUE;
- } else {
- emb->current = emb->current->next;
- }
-
- g_free (emb->filename);
- emb->filename = g_strdup (emb->current->data);
- bacon_video_widget_close (emb->bvw);
- res = totem_embedded_open (emb);
- if (res != FALSE &&
- ((eop != FALSE && emb->repeat != FALSE)
- || (eop == FALSE))) {
- totem_embedded_play (emb, NULL);
- }
- }
-}
-
-static void
-on_error_event (BaconVideoWidget *bvw, char *message,
- gboolean playback_stopped, gboolean fatal, TotemEmbedded *emb)
-{
- if (playback_stopped)
- totem_embedded_set_state (emb, STATE_STOPPED);
-
- if (fatal == FALSE) {
- totem_interface_error (_("An error occurred"), message,
- GTK_WINDOW (emb->window));
- } else {
- totem_embedded_error_and_exit (_("An error occurred"),
- message, emb);
- }
-}
-
-static void
-cb_vol (GtkWidget *val, TotemEmbedded *emb)
-{
- bacon_video_widget_set_volume (emb->bvw,
- bacon_volume_button_get_value (BACON_VOLUME_BUTTON (val)));
-}
-
-static gboolean
-on_volume_scroll_event (GtkWidget *win, GdkEventScroll *event, TotemEmbedded *emb)
-{
- GtkWidget *vbut;
- int vol, offset;
-
- switch (event->direction) {
- case GDK_SCROLL_UP:
- offset = VOLUME_UP_OFFSET;
- break;
- case GDK_SCROLL_DOWN:
- offset = VOLUME_DOWN_OFFSET;
- break;
- default:
- return FALSE;
- }
-
- vbut = glade_xml_get_widget (emb->xml, "volume_button");
- vol = bacon_volume_button_get_value (BACON_VOLUME_BUTTON (vbut));
- bacon_volume_button_set_value (BACON_VOLUME_BUTTON (vbut),
- vol + offset);
-
- return FALSE;
-}
-
-static void
-on_tick (GtkWidget *bvw,
- gint64 current_time,
- gint64 stream_length,
- float current_position,
- gboolean seekable,
- TotemEmbedded *emb)
-{
- if (emb->state != STATE_STOPPED) {
- gtk_widget_set_sensitive (emb->seek, seekable);
- if (emb->seeking == FALSE)
- gtk_adjustment_set_value (emb->seekadj,
- current_position * 65535);
- if (stream_length == 0) {
- totem_statusbar_set_time_and_length (emb->statusbar,
- (int) (current_time / 1000), -1);
- } else {
- totem_statusbar_set_time_and_length (emb->statusbar,
- (int) (current_time / 1000),
- (int) (stream_length / 1000));
- }
- }
-}
-
-static gboolean
-on_seek_start (GtkWidget *widget, GdkEventButton *event, TotemEmbedded *emb)
-{
- emb->seeking = TRUE;
-
- return FALSE;
-}
-
-static gboolean
-cb_on_seek (GtkWidget *widget, GdkEventButton *event, TotemEmbedded *emb)
-{
- bacon_video_widget_seek (emb->bvw,
- gtk_range_get_value (GTK_RANGE (widget)) / 65535, NULL);
- emb->seeking = FALSE;
-
- return FALSE;
-}
-
-static void
-totem_embedded_add_children (TotemEmbedded *emb)
-{
- GtkWidget *child, *container, *pp_button, *vbut;
- BvwUseType type = BVW_USE_TYPE_VIDEO;
- GError *err = NULL;
- GConfClient *gc;
- int volume;
-
- emb->xml = totem_interface_load_with_root ("mozilla-viewer.glade",
- "vbox1", _("Plugin"), TRUE,
- GTK_WINDOW (emb->window));
- emb->menuxml = totem_interface_load_with_root ("mozilla-viewer.glade",
- "menu", _("Menu"), TRUE,
- GTK_WINDOW (emb->window));
-
- if (emb->xml == NULL || emb->menuxml == NULL)
- totem_embedded_exit (emb);
-
- child = glade_xml_get_widget (emb->xml, "vbox1");
- gtk_container_add (GTK_CONTAINER (emb->window), child);
-
- if (emb->hidden)
- type = BVW_USE_TYPE_AUDIO;
-
- emb->bvw = BACON_VIDEO_WIDGET (bacon_video_widget_new
- (-1, -1, type, &err));
-
- if (emb->bvw == NULL)
- {
- totem_embedded_error_and_exit (_("The Totem plugin could not startup."), err != NULL ? err->message : _("No reason."), emb);
- if (err != NULL)
- g_error_free (err);
- }
-
- g_signal_connect (G_OBJECT(emb->bvw), "got-redirect",
- G_CALLBACK (on_got_redirect), emb);
- g_signal_connect (G_OBJECT (emb->bvw), "eos",
- G_CALLBACK (on_eos_event), emb);
- g_signal_connect (G_OBJECT (emb->bvw), "error",
- G_CALLBACK (on_error_event), emb);
- g_signal_connect (G_OBJECT(emb->bvw), "button-press-event",
- G_CALLBACK (on_video_button_press_event), emb);
- g_signal_connect (G_OBJECT(emb->bvw), "tick",
- G_CALLBACK (on_tick), emb);
-
- container = glade_xml_get_widget (emb->xml, "hbox4");
- gtk_container_add (GTK_CONTAINER (container), GTK_WIDGET (emb->bvw));
- if (type == BVW_USE_TYPE_VIDEO) {
- gtk_widget_realize (GTK_WIDGET (emb->bvw));
- gtk_widget_show (GTK_WIDGET (emb->bvw));
- }
-
- emb->seek = glade_xml_get_widget (emb->xml, "time_hscale");
- emb->seekadj = gtk_range_get_adjustment (GTK_RANGE (emb->seek));
- g_signal_connect (emb->seek, "button-press-event",
- G_CALLBACK (on_seek_start), emb);
- g_signal_connect (emb->seek, "button-release-event",
- G_CALLBACK (cb_on_seek), emb);
-
- pp_button = glade_xml_get_widget (emb->xml, "pp_button");
- g_signal_connect (G_OBJECT (pp_button), "clicked",
- G_CALLBACK (on_play_pause), emb);
-
- gc = gconf_client_get_default ();
- volume = gconf_client_get_int (gc, GCONF_PREFIX"/volume", NULL);
- g_object_unref (G_OBJECT (gc));
-
- bacon_video_widget_set_volume (emb->bvw, volume);
- vbut = glade_xml_get_widget (emb->xml, "volume_button");
- bacon_volume_button_set_value (BACON_VOLUME_BUTTON (vbut), volume);
- g_signal_connect (G_OBJECT (vbut), "value-changed",
- G_CALLBACK (cb_vol), emb);
- gtk_widget_add_events (vbut, GDK_SCROLL_MASK);
- g_signal_connect (G_OBJECT (vbut), "scroll_event",
- G_CALLBACK (on_volume_scroll_event), emb);
-
- emb->statusbar = TOTEM_STATUSBAR (glade_xml_get_widget
- (emb->xml, "emb_statusbar"));
-
- gtk_widget_realize (emb->window);
- gtk_widget_set_size_request (emb->window, emb->width, emb->height);
-
- if (emb->controller_hidden != FALSE) {
- child = glade_xml_get_widget (emb->xml, "controls");
- gtk_widget_hide (child);
- }
-
- /* popup */
- child = glade_xml_get_widget (emb->menuxml, "about1");
- g_signal_connect (G_OBJECT (child), "activate",
- G_CALLBACK (on_about1_activate), emb);
- child = glade_xml_get_widget (emb->menuxml, "copy_location1");
- g_signal_connect (G_OBJECT (child), "activate",
- G_CALLBACK (on_copy_location1_activate), emb);
- child = glade_xml_get_widget (emb->menuxml, "preferences1");
- gtk_widget_hide (child);
-}
-
-static void
-totem_embedded_create_cursor (TotemEmbedded *emb)
-{
- GtkWidget *label;
- GdkPixbuf *icon;
-
- label = gtk_label_new ("");
- icon = gtk_widget_render_icon (label, GTK_STOCK_MEDIA_PLAY,
- GTK_ICON_SIZE_BUTTON, NULL);
- gtk_widget_destroy (label);
- emb->cursor = gdk_cursor_new_from_pixbuf (gdk_display_get_default (),
- icon,
- gdk_pixbuf_get_width (icon) / 2,
- gdk_pixbuf_get_height (icon) / 2);
- gdk_pixbuf_unref (icon);
-}
-
-static void
-entry_added (TotemPlParser *parser, const char *uri, const char *title,
- const char *genre, gpointer data)
-{
- TotemEmbedded *emb = (TotemEmbedded *) data;
-
- g_print ("added URI '%s' with title '%s' genre '%s'\n", uri,
- title ? title : "empty", genre);
-
- //FIXME need new struct to hold that
- emb->playlist = g_list_prepend (emb->playlist, g_strdup (uri));
- emb->num_items++;
-}
-
-static gboolean
-totem_embedded_push_parser (gpointer data)
-{
- TotemPlParser *parser = totem_pl_parser_new ();
- TotemEmbedded *emb = (TotemEmbedded *) data;
- TotemPlParserResult res;
-
- parser = totem_pl_parser_new ();
- g_object_set (G_OBJECT (parser), "force", TRUE, NULL);
- g_object_set (G_OBJECT (parser), "disable-unsafe", TRUE, NULL);
- g_signal_connect (G_OBJECT (parser), "entry", G_CALLBACK (entry_added), emb);
- res = totem_pl_parser_parse (parser, emb->filename, FALSE);
- g_object_unref (parser);
-
- if (res != TOTEM_PL_PARSER_RESULT_SUCCESS) {
- //FIXME show a proper error message
- switch (res) {
- case TOTEM_PL_PARSER_RESULT_UNHANDLED:
- g_print ("url '%s' unhandled\n", emb->filename);
- break;
- case TOTEM_PL_PARSER_RESULT_ERROR:
- g_print ("error handling url '%s'\n", emb->filename);
- break;
- case TOTEM_PL_PARSER_RESULT_IGNORED:
- g_print ("ignored url '%s'\n", emb->filename);
- break;
- default:
- g_assert_not_reached ();
- ;;
- }
- }
-
- /* Check if we have anything in the playlist now */
- if (emb->playlist == NULL) {
- g_message ("NO PLAYLIST");
- totem_embedded_error_and_exit ("Can't parse that",
- "no files",
- emb);
- //FIXME error out
- return FALSE;
- }
-
- emb->playlist = g_list_reverse (emb->playlist);
- g_free (emb->filename);
- emb->filename = g_strdup (emb->playlist->data);
- emb->current = emb->playlist;
-
- g_main_loop_quit (emb->loop);
-
- return FALSE;
-}
-
-static void embedded (GtkPlug *plug, TotemEmbedded *emb)
-{
- emb->embedded_done = TRUE;
-}
-
-static int arg_width = -1;
-static int arg_height = -1;
-static char *arg_url = NULL;
-static char *arg_href = NULL;
-static char *arg_target = NULL;
-static char *arg_mime_type = NULL;
-static char **arg_remaining = NULL;
-static Window xid = 0;
-static gboolean arg_no_controls = FALSE;
-static gboolean arg_statusbar = FALSE;
-static gboolean arg_hidden = FALSE;
-static gboolean arg_is_playlist = FALSE;
-static gboolean arg_repeat = FALSE;
-static gboolean arg_no_autostart = FALSE;
-
-GtkWidget *
-totem_volume_create (void)
-{
- GtkWidget *widget;
-
- widget = bacon_volume_button_new (GTK_ICON_SIZE_MENU,
- 0, 100, -1);
- gtk_widget_show (widget);
-
- return widget;
-}
-
-GtkWidget *
-totem_statusbar_create (void)
-{
- GtkWidget *widget;
-
- widget = totem_statusbar_new ();
- totem_statusbar_set_has_resize_grip (TOTEM_STATUSBAR (widget), FALSE);
- if (arg_statusbar != FALSE)
- gtk_widget_show (widget);
-
- return widget;
-}
-
-static gboolean
-parse_xid (const gchar *option_name,
- const gchar *value,
- gpointer data,
- GError **error)
-{
- xid = (Window) g_ascii_strtoull (value, NULL, 10);
-
- return TRUE;
-}
-
-static GOptionEntry option_entries [] =
-{
- { TOTEM_OPTION_WIDTH, 0, 0, G_OPTION_ARG_INT, &arg_width, NULL, NULL },
- { TOTEM_OPTION_HEIGHT, 0, 0, G_OPTION_ARG_INT, &arg_height, NULL, NULL },
- { TOTEM_OPTION_URL, 0, 0, G_OPTION_ARG_STRING, &arg_url, NULL, NULL },
- { TOTEM_OPTION_HREF, 0, 0, G_OPTION_ARG_STRING, &arg_href, NULL, NULL },
- { TOTEM_OPTION_XID, 0, 0, G_OPTION_ARG_CALLBACK, parse_xid, NULL, NULL },
- { TOTEM_OPTION_TARGET, 0, 0, G_OPTION_ARG_STRING, &arg_target, NULL, NULL },
- { TOTEM_OPTION_MIMETYPE, 0, 0, G_OPTION_ARG_STRING, &arg_mime_type, NULL, NULL },
- { TOTEM_OPTION_CONTROLS_HIDDEN, 0, 0, G_OPTION_ARG_NONE, &arg_no_controls, NULL, NULL },
- { TOTEM_OPTION_STATUSBAR, 0, 0, G_OPTION_ARG_NONE, &arg_statusbar, NULL, NULL },
- { TOTEM_OPTION_HIDDEN, 0, 0, G_OPTION_ARG_NONE, &arg_hidden, NULL, NULL },
- { TOTEM_OPTION_PLAYLIST, 0, 0, G_OPTION_ARG_NONE, &arg_is_playlist, NULL, NULL },
- { TOTEM_OPTION_REPEAT, 0, 0, G_OPTION_ARG_NONE, &arg_repeat, NULL, NULL },
- { TOTEM_OPTION_NOAUTOSTART, 0, 0, G_OPTION_ARG_NONE, &arg_no_autostart, NULL, NULL },
- { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY /* STRING? */, &arg_remaining, NULL },
- { NULL }
-};
-
-
-int main (int argc, char **argv)
-{
- TotemEmbedded *emb;
- DBusGProxy *proxy;
- DBusGConnection *conn;
- guint res;
- gchar *svcname;
- GError *e = NULL;
-
- bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
- bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
- textdomain (GETTEXT_PACKAGE);
-
-#ifdef GNOME_ENABLE_DEBUG
- {
- int i;
- g_print ("Viewer args: ");
- for (i = 0; i < argc; i++)
- g_print ("%s ", argv[i]);
- g_print ("\n");
- }
-#endif
-
- if (XInitThreads () == 0)
- {
- gtk_init (&argc, &argv);
- totem_embedded_error_and_exit (_("Could not initialise the thread-safe libraries."), _("Verify your system installation. The Totem plugin will now exit."), NULL);
- }
-
- g_thread_init (NULL);
-
- if (!gtk_init_with_args (&argc, &argv, NULL, option_entries, GETTEXT_PACKAGE, &e))
- {
- g_print ("%s\n", e->message);
- g_error_free (e);
- exit (1);
- }
-
- /* FIXME: are there enough checks? */
- if (arg_remaining == NULL) {
- return 1;
- }
-
- bacon_video_widget_init_backend (NULL, NULL);
- gnome_vfs_init ();
-
- dbus_g_object_type_install_info (TOTEM_TYPE_EMBEDDED,
- &dbus_glib_totem_embedded_object_info);
- svcname = g_strdup_printf ("org.totem_%d.MozillaPluginService",
- getpid());
- if (!(conn = dbus_g_bus_get (DBUS_BUS_SESSION, &e)) ||
- !(proxy = dbus_g_proxy_new_for_name (conn, "org.freedesktop.DBus",
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus")) ||
- !dbus_g_proxy_call (proxy, "RequestName", &e,
- G_TYPE_STRING, svcname,
- G_TYPE_UINT, DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT,
- G_TYPE_INVALID,
- G_TYPE_UINT, &res,
- G_TYPE_INVALID)) {
- g_print ("Failed to get DBUS connection for %s: %s\n",
- svcname, e->message);
- return 1;
- }
- g_free (svcname);
-
- emb = g_object_new (TOTEM_TYPE_EMBEDDED, NULL);
-
- emb->state = STATE_STOPPED;
- emb->width = arg_width;
- emb->height = arg_height;
- emb->controller_hidden = arg_no_controls;
- emb->orig_filename = arg_url;
- emb->href = arg_href;
- emb->filename = arg_remaining ? arg_remaining[0] : NULL;
- emb->target = arg_target;
- if (arg_mime_type != NULL) {
- emb->mimetype = arg_mime_type;
- } else {
- emb->mimetype = g_strdup (gnome_vfs_get_mime_type_for_name (emb->filename));
- }
- emb->hidden = arg_hidden;
- emb->is_playlist = arg_is_playlist;
- emb->repeat = arg_repeat;
- emb->noautostart = arg_no_autostart;
-
- dbus_g_connection_register_g_object (conn, "/TotemEmbedded",
- G_OBJECT (emb));
-
- /* XEMBED or stand-alone */
- if (xid != 0) {
- GtkWidget *window;
-
- /* The miraculous XEMBED protocol */
- window = gtk_plug_new ((GdkNativeWindow) xid);
- gtk_signal_connect (GTK_OBJECT(window), "embedded",
- G_CALLBACK (embedded), NULL);
- gtk_widget_realize (window);
-
- emb->window = window;
- } else {
- /* Stand-alone version */
- emb->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- }
-
- /* Hidden or not as well? */
- totem_embedded_add_children (emb);
- totem_embedded_create_cursor (emb);
- if (emb->hidden == FALSE)
- gtk_widget_show (emb->window);
-
- /* wait until we're embedded if we're to be, or shown */
- if (xid != 0) {
- while (emb->embedded_done == FALSE && gtk_events_pending ())
- gtk_main_iteration ();
- } else {
- while (gtk_events_pending ())
- gtk_main_iteration ();
- }
-
- /* Do we have a playlist we need to setup ourselves? */
- if (emb->is_playlist != FALSE) {
- g_idle_add (totem_embedded_push_parser, emb);
- emb->loop = g_main_loop_new (NULL, FALSE);
- g_main_loop_run (emb->loop);
- g_main_loop_unref (emb->loop);
- } else {
- emb->playlist = g_list_prepend (emb->playlist,
- g_strdup (emb->filename));
- emb->num_items++;
- }
-
- if (totem_embedded_open (emb) != FALSE
- && emb->noautostart == FALSE) {
- totem_embedded_play (emb, NULL);
- }
-
- gtk_main ();
-
- return 0;
-}
-