summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--common.h15
-rw-r--r--configure.ac108
-rw-r--r--deadbeef.h13
-rw-r--r--main.c75
-rw-r--r--plugins.c29
-rw-r--r--plugins.h8
-rw-r--r--plugins/adplug/Makefile.am8
-rw-r--r--plugins/adplug/adplug-db.cpp12
-rw-r--r--plugins/artwork/artwork.c35
-rw-r--r--plugins/artwork/artwork.h1
-rw-r--r--plugins/gme/Makefile.am4
-rw-r--r--plugins/gme/cgme.c12
-rw-r--r--plugins/gtkui/callbacks.c12
-rw-r--r--plugins/gtkui/coverart.c7
-rw-r--r--plugins/gtkui/gtkui.c3
-rw-r--r--plugins/mpris/Makefile.am8
-rw-r--r--plugins/mpris/mpris-spec.h91
-rw-r--r--plugins/mpris/mpris.c1310
-rw-r--r--plugins/shellexec/Makefile.am2
-rw-r--r--plugins/sid/Makefile.am6
-rw-r--r--plugins/sid/csid.cpp12
-rw-r--r--plugins/supereq/Equ.cpp12
-rw-r--r--plugins/supereq/Makefile.am4
-rw-r--r--plugins/vfs_curl/Makefile.am2
25 files changed, 1726 insertions, 64 deletions
diff --git a/.gitignore b/.gitignore
index fa4d4231..bfcca357 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,3 +45,4 @@ vala.stamp
POTFILES
stamp-it
po/Makevars.template
+*.so
diff --git a/common.h b/common.h
index dfecb27a..fd270c3e 100644
--- a/common.h
+++ b/common.h
@@ -18,12 +18,21 @@
#ifndef __COMMON_H
#define __COMMON_H
+#include <limits.h>
+#ifndef PATH_MAX
+#define PATH_MAX 1024 /* max # of characters in a path name */
+#endif
+
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
// those are defined in main.c
-extern char confdir[1024]; // $HOME/.config
-extern char dbconfdir[1024]; // $HOME/.config/deadbeef
-extern char sessfile[1024]; // $HOME/.config/deadbeef/session
+extern char confdir[PATH_MAX]; // $HOME/.config
+extern char dbconfdir[PATH_MAX]; // $HOME/.config/deadbeef
+extern char dbinstalldir[PATH_MAX]; // see deadbeef->get_prefix
+extern char dbdocdir[PATH_MAX]; // see deadbeef->get_doc_dir
+extern char dbplugindir[PATH_MAX]; // see deadbeef->get_plugin_dir
+extern char dbpixmapdir[PATH_MAX]; // see deadbeef->get_pixmap_dir
+
#endif // __COMMON_H
diff --git a/configure.ac b/configure.ac
index 7a113167..38455ae0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -33,15 +33,19 @@ fi
case "$host" in
i386-*-* | i486-*-* | i586-*-* | i686-*-* | i86pc-*-*)
AC_DEFINE(ARCH_X86_32, 1, [architecture is x86])
+ LIB="lib-x86-32"
;;
x86_64-*-* | amd64-*-*)
AC_DEFINE(ARCH_X86_64, 1, [architecture is x86_64])
+ LIB="lib-x86-64"
;;
powerpc-*-* )
AC_DEFINE(ARCH_PPC_32, 1, [architecture is ppc32])
+ LIB="lib-ppc-32"
;;
powerpc64-*-* )
AC_DEFINE(ARCH_PPC_64, 1, [architecture is ppc64])
+ LIB="lib-ppc-64"
;;
*)
AC_DEFINE(ARCH_UNKNOWN, 1, [architecture is unknown])
@@ -56,9 +60,6 @@ dnl INSANE_CXXFLAGS="-Wcomment -Wchar-subscripts -Wunused-function -Wunused-valu
AC_SUBST(INSANE_CFLAGS)
AC_SUBST(INSANE_CXXFLAGS)
-CXXFLAGS="$CXXFLAGS $INSANE_CXXFLAGS -D_GNU_SOURCE -DLIBDIR=\\\"$libdir\\\" -DPREFIX=\\\"$prefix\\\" -DDOCDIR=\\\"$docdir\\\""
-CFLAGS="$CFLAGS $INSANE_CFLAGS -D_GNU_SOURCE -DLIBDIR=\\\"$libdir\\\" -DPREFIX=\\\"$prefix\\\" -DDOCDIR=\\\"$docdir\\\""
-
AC_ARG_ENABLE(nullout, [AS_HELP_STRING([--disable-nullout ], [disable NULL output plugin (default: enabled)])], [enable_nullout=$enableval], [enable_nullout=yes])
AC_ARG_ENABLE(alsa, [AS_HELP_STRING([--disable-alsa ], [disable ALSA output plugin (default: enabled)])], [enable_alsa=$enableval], [enable_alsa=yes])
AC_ARG_ENABLE(oss, [AS_HELP_STRING([--disable-oss ], [disable Open Sound System output plugin (default: enabled)])], [enable_oss=$enableval], [enable_oss=yes])
@@ -93,8 +94,27 @@ AC_ARG_ENABLE(aac, [AS_HELP_STRING([--disable-aac ], [disable AAC decod
AC_ARG_ENABLE(mms, [AS_HELP_STRING([--disable-mms ], [disable MMS streaming vfs plugin (default: enabled)])], [enable_mms=$enableval], [enable_mms=yes])
AC_ARG_ENABLE(shn, [AS_HELP_STRING([--disable-shn ], [disable shorten plugin (default: enabled)])], [enable_shn=$enableval], [enable_shn=yes])
AC_ARG_ENABLE(ao, [AS_HELP_STRING([--disable-ao ], [disable audio overload plugin (default: enabled)])], [enable_ao=$enableval], [enable_ao=yes])
+AC_ARG_ENABLE(mpris, [ --enable-mpris enable Ubuntu Sound Menu plugin (default: disabled)], [enable_mpris=$enableval], [enable_mpris=no])
+AC_ARG_ENABLE(portable, [ --enable-portable make portable static build (default: disabled)], [enable_portable=$enableval], [enable_portable=no])
+
+if test "x$enable_portable" != "xno" ; then
+ AC_DEFINE_UNQUOTED([PORTABLE], [1], [Define if building portable version])
+ PORTABLE=yes
+ PREFIXFLAGS="-DPREFIX=donotuse -DLIBDIR=donotuse -DDOCDIR=donotuse -I./include"
+else
+ PREFIXFLAGS=" -DLIBDIR=\\\"$libdir\\\" -DPREFIX=\\\"$prefix\\\" -DDOCDIR=\\\"$docdir\\\""
+fi
+
+CXXFLAGS="$CXXFLAGS $INSANE_CXXFLAGS -D_GNU_SOURCE $PREFIXFLAGS"
+CFLAGS="$CFLAGS $INSANE_CFLAGS -D_GNU_SOURCE $PREFIXFLAGS"
PKG_CHECK_MODULES(DEPS, samplerate)
+if test "x$enable_portable" != "xno" ; then
+ DEPS_LIBS="$LIB/libsamplerate.a -lpthread -ldl"
+ AC_SUBST(DEPS_LIBS)
+else
+ PKG_CHECK_MODULES(DEPS, samplerate)
+fi
if test "x$enable_gtkui" != "xno" ; then
if test "x$enable_gtk3" == "xyes" ; then
@@ -118,8 +138,8 @@ if test "x$enable_pulse" != "xno" ; then
PKG_CHECK_MODULES(PULSE_DEPS, libpulse-simple, HAVE_PULSE=yes, HAVE_PULSE=no)
fi
-AC_CHECK_LIB([pthread], [main])
-AC_CHECK_LIB([dl], [main])
+dnl AC_CHECK_LIB([pthread], [main])
+dnl AC_CHECK_LIB([dl], [main])
AC_CHECK_HEADER([iconv.h],[],[iconv.h not found.])
@@ -136,17 +156,33 @@ if test ${HAVE_SSE2}; then
fi
dnl curl lib
-AC_CHECK_LIB([curl], [main], [HAVE_CURL=yes])
-if test "x$HAVE_CURL" = "xyes"; then
+if test "x$enable_portable" != "xno" ; then
+ HAVE_CURL=yes
+ CURL_LIBS="../../$LIB/libcurl.a -lrt"
+ AC_SUBST(CURL_LIBS)
+else
+ AC_CHECK_LIB([curl], [main], [HAVE_CURL=yes])
CURL_LIBS="-lcurl"
AC_SUBST(CURL_LIBS)
fi
-PKG_CHECK_MODULES(DBUS_DEPS, dbus-1, HAVE_DBUS=yes, HAVE_DBUS=no)
+if test "x$enable_portable" != "xno" ; then
+ HAVE_DBUS=yes
+ DBUS_DEPS_LIBS="../../$LIB/libdbus-1.a ../../$LIB/libexpat.a -lrt"
+ DBUS_DEPS_CFLAGS="-I../../include/dbus-1"
+ AC_SUBST(DBUS_DEPS_LIBS)
+else
+ PKG_CHECK_MODULES(DBUS_DEPS, dbus-1, HAVE_DBUS=yes, HAVE_DBUS=no)
+fi
dnl mpgmad plugin
if test "x$enable_mpgmad" != "xno" ; then
+if test "x$enable_portable" != "xno" ; then
+ HAVE_MPGMAD=yes
+ MAD_LIBS="../../$LIB/libmad.a"
+ AC_SUBST(MAD_LIBS)
+else
AC_CHECK_LIB([mad], [main], [HAVE_LIBMAD=yes])
if test "x$HAVE_LIBMAD" = "xyes" ; then
HAVE_MPGMAD=yes
@@ -154,9 +190,15 @@ if test "x$enable_mpgmad" != "xno" ; then
AC_SUBST(MAD_LIBS)
fi
fi
+fi
dnl vorbis plugin
if test "x$enable_vorbis" != "xno" ; then
+if test "x$enable_portable" != "xno" ; then
+ HAVE_VORBISPLUGIN=yes
+ VORBIS_LIBS="../../$LIB/libogg.a ../../$LIB/libvorbis.a ../../$LIB/libvorbisenc.a ../../$LIB/libvorbisfile.a"
+ AC_SUBST(VORBIS_LIBS)
+else
AC_CHECK_LIB([vorbis], [main], [HAVE_VORBIS=yes])
AC_CHECK_LIB([vorbisfile], [main], [HAVE_VORBISFILE=yes])
if test "x$HAVE_VORBIS" = "xyes" && test "x$HAVE_VORBISFILE" = "xyes" ; then
@@ -165,9 +207,15 @@ if test "x$enable_vorbis" != "xno" ; then
AC_SUBST(VORBIS_LIBS)
fi
fi
+fi
dnl flac plugin
if test "x$enable_flac" != "xno" ; then
+if test "x$enable_portable" != "xno" ; then
+ HAVE_FLACPLUGIN=yes
+ FLAC_LIBS="../../$LIB/libFLAC.a ../../$LIB/libogg.a"
+ AC_SUBST(FLAC_LIBS)
+else
AC_CHECK_LIB([FLAC], [main], [HAVE_FLAC=yes])
if test "x$HAVE_FLAC" = "xyes" ; then
HAVE_FLACPLUGIN=yes
@@ -175,9 +223,15 @@ if test "x$enable_flac" != "xno" ; then
AC_SUBST(FLAC_LIBS)
fi
fi
+fi
dnl wavpack plugin
if test "x$enable_wavpack" != "xno" ; then
+if test "x$enable_portable" != "xno" ; then
+ HAVE_WAVPACKPLUGIN=yes
+ WAVPACK_LIBS="../../$LIB/libwavpack.a"
+ AC_SUBST(WAVPACK_LIBS)
+else
AC_CHECK_LIB([wavpack], [main], [HAVE_WAVPACK=yes])
if test "x$HAVE_WAVPACK" = "xyes" ; then
HAVE_WAVPACKPLUGIN=yes
@@ -185,9 +239,15 @@ if test "x$enable_wavpack" != "xno" ; then
AC_SUBST(WAVPACK_LIBS)
fi
fi
+fi
dnl libsndfile plugin
if test "x$enable_sndfile" != "xno" ; then
+if test "x$enable_portable" != "xno" ; then
+ HAVE_SNDFILEPLUGIN=yes
+ SNDFILE_LIBS="../../$LIB/libsndfile.a"
+ AC_SUBST(SNDFILE_LIBS)
+else
AC_CHECK_LIB([sndfile], [main], [HAVE_SNDFILE=yes])
if test "x$HAVE_SNDFILE" = "xyes" ; then
HAVE_SNDFILEPLUGIN=yes
@@ -195,18 +255,24 @@ if test "x$enable_sndfile" != "xno" ; then
AC_SUBST(SNDFILE_LIBS)
fi
fi
+fi
dnl vfs_curl plugin
if test "x$enable_vfs_curl" != "xno" ; then
if test "x$HAVE_CURL" = "xyes" ; then
HAVE_VFS_CURL=yes
- VFS_CURL_LIBS="-lcurl"
+ VFS_CURL_LIBS="$CURL_LIBS"
AC_SUBST(VFS_CURL_LIBS)
fi
fi
dnl cdda plugin
if test "x$enable_cdda" != "xno" ; then
+if test "x$enable_portable" != "xno" ; then
+ HAVE_CDDAPLUGIN=yes
+ CDDA_LIBS="../../$LIB/libcdio.a ../../$LIB/libudf.a ../../$LIB/libiso9660.a ../../$LIB/libcddb.a"
+ AC_SUBST(CDDA_LIBS)
+else
AC_CHECK_LIB([cdio], [main], [HAVE_CDIO=yes])
AC_CHECK_LIB([cddb], [main], [HAVE_CDDB=yes])
if test "x$HAVE_CDIO" = "xyes" && test "x$HAVE_CDDB" = "xyes" ; then
@@ -215,6 +281,7 @@ if test "x$enable_cdda" != "xno" ; then
AC_SUBST(CDDA_LIBS)
fi
fi
+fi
dnl gtkui plugin
if test "x$enable_gtkui" != "xno" ; then
@@ -365,6 +432,11 @@ if test "x$enable_dca" != "xno" ; then
fi
if test "x$enable_aac" != "xno" ; then
+if test "x$enable_portable" != "xno" ; then
+ FAAD2_LIBS="../../$LIB/libfaad.a"
+ AC_SUBST(FAAD2_LIBS)
+ HAVE_AAC=yes
+else
AC_CHECK_LIB([faad], [main], [HAVE_FAAD=1])
if test ${HAVE_FAAD} ; then
FAAD2_LIBS="-lfaad"
@@ -372,6 +444,7 @@ if test "x$enable_aac" != "xno" ; then
HAVE_AAC=yes
fi
fi
+fi
if test "x$enable_mms" != "xno" ; then
LIBMMS_LIBS=""
@@ -384,15 +457,24 @@ if test "x$enable_shn" != "xno" ; then
fi
if test "x$enable_ao" != "xno" ; then
+if test "x$enable_portable" != "xno" ; then
+ HAVE_ZLIB=yes
+ ZLIB_LIBS="../../$LIB/libz.a"
+else
AC_CHECK_LIB([z], [main], [HAVE_ZLIB=yes])
+ ZLIB_LIBS="-lz"
+fi
if test "x$HAVE_ZLIB" = "xyes"; then
- ZLIB_LIBS="-lz"
AC_SUBST(ZLIB_LIBS)
HAVE_AO=yes
fi
fi
-PLUGINS_DIRS="plugins/lastfm plugins/mpgmad plugins/vorbis plugins/flac plugins/wavpack plugins/sndfile plugins/vfs_curl plugins/cdda plugins/gtkui plugins/alsa plugins/ffmpeg plugins/hotkeys plugins/oss plugins/artwork plugins/adplug plugins/ffap plugins/sid plugins/nullout plugins/supereq plugins/vtx plugins/gme plugins/dumb plugins/pulse plugins/notify plugins/musepack plugins/wildmidi plugins/tta plugins/dca plugins/aac plugins/mms plugins/shn plugins/ao plugins/shellexec"
+if test "x$enable_mpris" != "xno" ; then
+ PKG_CHECK_MODULES(MPRIS_DEPS, gio-2.0 glib-2.0 >= 2.26.0, HAVE_MPRIS=yes, HAVE_MPRIS=no)
+fi
+
+PLUGINS_DIRS="plugins/lastfm plugins/mpgmad plugins/vorbis plugins/flac plugins/wavpack plugins/sndfile plugins/vfs_curl plugins/cdda plugins/gtkui plugins/alsa plugins/ffmpeg plugins/hotkeys plugins/oss plugins/artwork plugins/adplug plugins/ffap plugins/sid plugins/nullout plugins/supereq plugins/vtx plugins/gme plugins/dumb plugins/pulse plugins/notify plugins/musepack plugins/wildmidi plugins/tta plugins/dca plugins/aac plugins/mms plugins/shn plugins/ao plugins/shellexec plugins/mpris"
AM_CONDITIONAL(HAVE_VORBIS, test "x$HAVE_VORBISPLUGIN" = "xyes")
AM_CONDITIONAL(HAVE_FLAC, test "x$HAVE_FLACPLUGIN" = "xyes")
@@ -427,6 +509,8 @@ AM_CONDITIONAL(HAVE_AAC, test "x$HAVE_AAC" = "xyes")
AM_CONDITIONAL(HAVE_MMS, test "x$HAVE_MMS" = "xyes")
AM_CONDITIONAL(HAVE_SHN, test "x$HAVE_SHN" = "xyes")
AM_CONDITIONAL(HAVE_AO, test "x$HAVE_AO" = "xyes")
+AM_CONDITIONAL(HAVE_MPRIS, test "x$HAVE_MPRIS" = "xyes")
+AM_CONDITIONAL(PORTABLE, test "x$PORTABLE" = "xyes")
AC_SUBST(PLUGINS_DIRS)
@@ -487,6 +571,7 @@ PRINT_PLUGIN_INFO([aac],[AAC player (m4a, aac, mp4) based on FAAD2],[test "x$HAV
PRINT_PLUGIN_INFO([mms],[mms streaming support],[test "x$HAVE_MMS" = "xyes"])
PRINT_PLUGIN_INFO([shn],[shorten player based on xmms-shn],[test "x$HAVE_SHN" = "xyes"])
PRINT_PLUGIN_INFO([ao],[psf1/psf2/spu/ssf player using Audio Overload],[test "x$HAVE_AO" = "xyes"])
+PRINT_PLUGIN_INFO([mpris],[Ubuntu Sound Menu integration],[test "x$HAVE_MPRIS" = "xyes"])
echo
@@ -527,6 +612,7 @@ plugins/aac/Makefile
plugins/mms/Makefile
plugins/shn/Makefile
plugins/ao/Makefile
+plugins/mpris/Makefile
intl/Makefile
po/Makefile.in
deadbeef.desktop
diff --git a/deadbeef.h b/deadbeef.h
index 556ef1b6..93ed804b 100644
--- a/deadbeef.h
+++ b/deadbeef.h
@@ -64,8 +64,8 @@ extern "C" {
// 0.2 -- deadbeef-0.2.3
// 0.1 -- deadbeef-0.2.0
-#define DB_API_VERSION_MAJOR 0
-#define DB_API_VERSION_MINOR 8
+#define DB_API_VERSION_MAJOR 9
+#define DB_API_VERSION_MINOR 9
#define DB_PLUGIN_SET_API_VERSION\
.plugin.api_vmajor = DB_API_VERSION_MAJOR,\
@@ -317,8 +317,15 @@ typedef struct {
int (*streamer_get_apx_bitrate) (void);
struct DB_fileinfo_s *(*streamer_get_current_fileinfo) (void);
int (*streamer_get_current_playlist) (void);
+ // system folders
+ // normally functions will return standard folders derived from --prefix
+ // portable version will return pathes specified in comments below
+ const char *(*get_config_dir) (void); // installdir/config | $XDG_CONFIG_HOME/.config/deadbeef
+ const char *(*get_prefix) (void); // installdir | PREFIX
+ const char *(*get_doc_dir) (void); // installdir/doc | DOCDIR
+ const char *(*get_plugin_dir) (void); // installdir/plugins | LIBDIR/deadbeef
+ const char *(*get_pixmap_dir) (void); // installdir/pixmaps | PREFIX "/share/deadbeef/pixmaps"
// process control
- const char *(*get_config_dir) (void);
void (*quit) (void);
// threading
intptr_t (*thread_start) (void (*fn)(void *ctx), void *ctx);
diff --git a/main.c b/main.c
index 5e776b73..890b1c77 100644
--- a/main.c
+++ b/main.c
@@ -54,10 +54,7 @@
#include "conf.h"
#include "volume.h"
#include "plugins.h"
-
-#ifndef PATH_MAX
-#define PATH_MAX 1024 /* max # of characters in a path name */
-#endif
+#include "common.h"
#ifndef PREFIX
#error PREFIX must be defined
@@ -67,12 +64,18 @@
#define USE_ABSTRACT_NAME 0
#endif
-//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
-#define trace(fmt,...)
+#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+//#define trace(fmt,...)
+
// some common global variables
-char confdir[1024]; // $HOME/.config
-char dbconfdir[1024]; // $HOME/.config/deadbeef
+char sys_install_path[PATH_MAX]; // see deadbeef->get_prefix
+char confdir[PATH_MAX]; // $HOME/.config
+char dbconfdir[PATH_MAX]; // $HOME/.config/deadbeef
+char dbinstalldir[PATH_MAX]; // see deadbeef->get_prefix
+char dbdocdir[PATH_MAX]; // see deadbeef->get_doc_dir
+char dbplugindir[PATH_MAX]; // see deadbeef->get_plugin_dir
+char dbpixmapdir[PATH_MAX]; // see deadbeef->get_pixmap_dir
// client-side commandline support
// -1 error, program must exit with error code -1
@@ -531,11 +534,45 @@ main (int argc, char *argv[]) {
bind_textdomain_codeset (PACKAGE, "UTF-8");
textdomain (PACKAGE);
#endif
- fprintf (stderr, "starting deadbeef " VERSION "\n");
+ fprintf (stderr, "starting deadbeef " VERSION "%s\n", PORTABLE ? " [portable build]" : "");
srand (time (NULL));
#ifdef __linux__
prctl (PR_SET_NAME, "deadbeef-main", 0, 0, 0, 0);
#endif
+
+#if PORTABLE
+ strcpy (dbinstalldir, argv[0]);
+ char *e = dbinstalldir + strlen (dbinstalldir);
+ while (e >= dbinstalldir && *e != '/') {
+ e--;
+ }
+ *e = 0;
+ if (snprintf (confdir, sizeof (confdir), "%s/config", dbinstalldir) > sizeof (confdir)) {
+ fprintf (stderr, "fatal: too long install path %s\n", dbinstalldir);
+ return -1;
+ }
+
+ strcpy (dbconfdir, confdir);
+
+ if (snprintf (dbdocdir, sizeof (dbdocdir), "%s/doc", dbinstalldir) > sizeof (dbdocdir)) {
+ fprintf (stderr, "fatal: too long install path %s\n", dbinstalldir);
+ return -1;
+ }
+ if (snprintf (dbplugindir, sizeof (dbplugindir), "%s/plugins", dbinstalldir) > sizeof (dbplugindir)) {
+ fprintf (stderr, "fatal: too long install path %s\n", dbinstalldir);
+ return -1;
+ }
+ if (snprintf (dbpixmapdir, sizeof (dbpixmapdir), "%s/pixmaps", dbinstalldir) > sizeof (dbpixmapdir)) {
+ fprintf (stderr, "fatal: too long install path %s\n", dbinstalldir);
+ return -1;
+ }
+ trace ("installdir: %s\n", dbinstalldir);
+ trace ("confdir: %s\n", confdir);
+ trace ("docdir: %s\n", dbdocdir);
+ trace ("plugindir: %s\n", dbplugindir);
+ mkdir (dbplugindir, 0755);
+ trace ("pixmapdir: %s\n", dbpixmapdir);
+#else
char *homedir = getenv ("HOME");
if (!homedir) {
fprintf (stderr, "unable to find home directory. stopping.\n");
@@ -555,11 +592,25 @@ main (int argc, char *argv[]) {
return -1;
}
}
- mkdir (confdir, 0755);
if (snprintf (dbconfdir, sizeof (dbconfdir), "%s/deadbeef", confdir) > sizeof (dbconfdir)) {
fprintf (stderr, "fatal: out of memory while configuring\n");
return -1;
}
+ mkdir (confdir, 0755);
+ if (snprintf (dbdocdir, sizeof (dbdocdir), "%s", DOCDIR) > sizeof (dbdocdir)) {
+ fprintf (stderr, "fatal: too long install path %s\n", dbinstalldir);
+ return -1;
+ }
+ if (snprintf (dbplugindir, sizeof (dbplugindir), "%s/deadbeef", LIBDIR) > sizeof (dbplugindir)) {
+ fprintf (stderr, "fatal: too long install path %s\n", dbinstalldir);
+ return -1;
+ }
+ if (snprintf (dbpixmapdir, sizeof (dbpixmapdir), "%s/share/deadbeef/pixmaps", PREFIX) > sizeof (dbpixmapdir)) {
+ fprintf (stderr, "fatal: too long install path %s\n", dbinstalldir);
+ return -1;
+ }
+#endif
+
mkdir (dbconfdir, 0755);
char cmdline[2048];
@@ -681,7 +732,9 @@ main (int argc, char *argv[]) {
conf_load (); // required by some plugins at startup
volume_set_db (conf_get_float ("playback.volume", 0)); // volume need to be initialized before plugins start
messagepump_init (); // required to push messages while handling commandline
- plug_load_all (); // required to add files to playlist from commandline
+ if (plug_load_all ()) { // required to add files to playlist from commandline
+ exit (-1);
+ }
pl_load_all ();
plt_set_curr (conf_get_int ("playlist.current", 0));
diff --git a/plugins.c b/plugins.c
index 331baab9..61a95d33 100644
--- a/plugins.c
+++ b/plugins.c
@@ -88,8 +88,13 @@ static DB_functions_t deadbeef_api = {
.streamer_get_apx_bitrate = streamer_get_apx_bitrate,
.streamer_get_current_fileinfo = streamer_get_current_fileinfo,
.streamer_get_current_playlist = streamer_get_current_playlist,
- // process control
+ // folders
.get_config_dir = plug_get_config_dir,
+ .get_prefix = plug_get_prefix,
+ .get_doc_dir = plug_get_doc_dir,
+ .get_plugin_dir = plug_get_plugin_dir,
+ .get_pixmap_dir = plug_get_pixmap_dir,
+ // process control
.quit = plug_quit,
// threading
.thread_start = thread_start,
@@ -267,6 +272,26 @@ plug_get_config_dir (void) {
return dbconfdir;
}
+const char *
+plug_get_prefix (void) {
+ return dbinstalldir;
+}
+
+const char *
+plug_get_doc_dir (void) {
+ return dbdocdir;
+}
+
+const char *
+plug_get_plugin_dir (void) {
+ return dbplugindir;
+}
+
+const char *
+plug_get_pixmap_dir (void) {
+ return dbpixmapdir;
+}
+
void
plug_volume_set_db (float db) {
volume_set_db (db);
@@ -566,7 +591,7 @@ plug_load_all (void) {
const char *conf_blacklist_plugins = conf_get_str ("blacklist_plugins", "");
trace ("plug: mutex_create\n");
mutex = mutex_create ();
- const char *dirname = LIBDIR "/deadbeef";
+ const char *dirname = deadbeef->get_plugin_dir ();
struct dirent **namelist = NULL;
char *xdg_local_home = getenv ("XDG_LOCAL_HOME");
diff --git a/plugins.h b/plugins.h
index 231eaf1f..fc49930e 100644
--- a/plugins.h
+++ b/plugins.h
@@ -113,6 +113,14 @@ plug_volume_set_amp (float amp);
const char *
plug_get_config_dir (void);
+const char *
+plug_get_prefix (void);
+const char *
+plug_get_doc_dir (void);
+const char *
+plug_get_plugin_dir (void);
+const char *
+plug_get_pixmap_dir (void);
int
plug_activate (DB_plugin_t *plug, int activate);
diff --git a/plugins/adplug/Makefile.am b/plugins/adplug/Makefile.am
index a75f38b5..393f2d59 100644
--- a/plugins/adplug/Makefile.am
+++ b/plugins/adplug/Makefile.am
@@ -5,11 +5,12 @@ adlibdir = $(libdir)/$(PACKAGE)
pkglib_LTLIBRARIES = adplug.la
AM_CFLAGS = $(CFLAGS) -std=c99 -I$(adplugpath)/adplug -I$(adplugpath)/libbinio
+adplug_la_LDFLAGS = -module -nostdlib -lsupc++
-AM_CPPFLAGS = $(CXXFLAGS) -Dstricmp=strcasecmp -DVERSION=\"2.1\" -I$(adplugpath)/adplug -I$(adplugpath)/libbinio
+AM_CPPFLAGS = $(CXXFLAGS) -Dstricmp=strcasecmp -DVERSION=\"2.1\" -I$(adplugpath)/adplug -I$(adplugpath)/libbinio -fno-exceptions -fno-rtti -nostdlib -fno-unwind-tables
-adplug_la_SOURCES = adplug-db.cpp\
- plugin.c\
+adplug_la_SOURCES = plugin.c\
+ adplug-db.cpp\
libbinio/binfile.h\
libbinio/binio.h\
libbinio/binstr.h\
@@ -134,5 +135,4 @@ adplug_la_SOURCES = adplug-db.cpp\
# adplug/database.cpp
# adplug/database.h
-adplug_la_LDFLAGS = -module
endif
diff --git a/plugins/adplug/adplug-db.cpp b/plugins/adplug/adplug-db.cpp
index 567d55ca..a7b1f6b2 100644
--- a/plugins/adplug/adplug-db.cpp
+++ b/plugins/adplug/adplug-db.cpp
@@ -31,6 +31,18 @@
//#define trace(...) { fprintf (stderr, __VA_ARGS__); }
#define trace(fmt,...)
+int _Unwind_Resume_or_Rethrow;
+int _Unwind_RaiseException;
+int _Unwind_GetLanguageSpecificData;
+int _Unwind_Resume;
+int _Unwind_DeleteException;
+int _Unwind_GetTextRelBase;
+int _Unwind_SetIP;
+int _Unwind_GetDataRelBase;
+int _Unwind_GetRegionStart;
+int _Unwind_SetGR;
+int _Unwind_GetIPInfo;
+
extern "C" {
extern DB_decoder_t adplug_plugin;
diff --git a/plugins/artwork/artwork.c b/plugins/artwork/artwork.c
index fbbe71d9..469ec8bb 100644
--- a/plugins/artwork/artwork.c
+++ b/plugins/artwork/artwork.c
@@ -16,7 +16,7 @@
//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
#define trace(...)
-#define DEFAULT_COVER_PATH (PREFIX "/share/deadbeef/pixmaps/noartwork.jpg")
+static char default_cover[PATH_MAX];
#define DEFAULT_FILEMASK "*cover*.jpg;*front*.jpg"
static DB_artwork_plugin_t plugin;
@@ -41,12 +41,16 @@ static volatile int terminate;
static volatile int clear_queue;
static intptr_t tid;
-int artwork_enable_embedded;
-int artwork_enable_local;
-int artwork_enable_lfm;
-int artwork_enable_aao;
-int artwork_reset_time;
-char artwork_filemask[200];
+static int artwork_enable_embedded;
+static int artwork_enable_local;
+static int artwork_enable_lfm;
+static int artwork_enable_aao;
+static int artwork_reset_time;
+static char artwork_filemask[200];
+
+static const char *get_default_cover (void) {
+ return default_cover;
+}
void
make_cache_dir_path (char *path, int size, const char *album, const char *artist) {
@@ -568,11 +572,11 @@ get_album_art (const char *fname, const char *artist, const char *album, artwork
if (!*artist || !*album)
{
//give up
- return strdup (DEFAULT_COVER_PATH);
+ return strdup (get_default_cover ());
}
if (!deadbeef->is_local_file (fname)) {
- return strdup (DEFAULT_COVER_PATH);
+ return strdup (get_default_cover ());
}
make_cache_path (path, sizeof (path), album, artist);
@@ -586,7 +590,7 @@ get_album_art (const char *fname, const char *artist, const char *album, artwork
trace ("reloading cached file %s\n", path);
unlink (path);
queue_add (fname, artist, album, callback, user_data);
- return strdup (DEFAULT_COVER_PATH);
+ return strdup (get_default_cover ());
}
trace ("found %s in cache\n", path);
@@ -594,7 +598,7 @@ get_album_art (const char *fname, const char *artist, const char *album, artwork
}
queue_add (fname, artist, album, callback, user_data);
- return strdup (DEFAULT_COVER_PATH);
+ return strdup (get_default_cover ());
}
DB_plugin_t *
@@ -664,6 +668,13 @@ artwork_on_configchanged (DB_event_t *ev, uintptr_t data) {
static int
artwork_plugin_start (void)
{
+ const char *def_art = deadbeef->conf_get_str ("gtkui.nocover_pixmap", NULL);
+ if (!def_art) {
+ snprintf (default_cover, sizeof (default_cover), "%s/noartwork.jpg", deadbeef->get_pixmap_dir ());
+ }
+ else {
+ strcpy (default_cover, def_art);
+ }
terminate = 0;
artwork_enable_embedded = deadbeef->conf_get_int ("artwork.enable_embedded", 1);
@@ -720,6 +731,7 @@ static const char settings_dlg[] =
"property \"Fetch from last.fm\" checkbox artwork.enable_lastfm 0;\n"
"property \"Fetch from albumart.org\" checkbox artwork.enable_albumartorg 0;\n"
;
+
// define plugin interface
static DB_artwork_plugin_t plugin = {
.plugin.plugin.api_vmajor = DB_API_VERSION_MAJOR,
@@ -736,4 +748,5 @@ static DB_artwork_plugin_t plugin = {
.plugin.plugin.configdialog = settings_dlg,
.get_album_art = get_album_art,
.reset = artwork_reset,
+ .get_default_cover = get_default_cover,
};
diff --git a/plugins/artwork/artwork.h b/plugins/artwork/artwork.h
index ab0fead6..ed5357df 100644
--- a/plugins/artwork/artwork.h
+++ b/plugins/artwork/artwork.h
@@ -14,6 +14,7 @@ typedef struct {
// this has to be called to clear queue on exit, before caller terminates
// `fast=1' means "don't wait, just flush queue"
void (*reset) (int fast);
+ const char *(*get_default_cover) (void);
} DB_artwork_plugin_t;
#endif /*__ARTWORK_H*/
diff --git a/plugins/gme/Makefile.am b/plugins/gme/Makefile.am
index 61351f9c..ed815899 100644
--- a/plugins/gme/Makefile.am
+++ b/plugins/gme/Makefile.am
@@ -112,8 +112,8 @@ game-music-emu-0.5.5/gme/Ym2413_Emu.h\
game-music-emu-0.5.5/gme/Ym2612_Emu.h\
game-music-emu-0.5.5/gme/gme_types.h
-gme_la_LDFLAGS = -module
+gme_la_LDFLAGS = -module -nostdlib -lsupc++
-gme_la_LIBADD = $(LDADD) -lstdc++
AM_CFLAGS = $(CFLAGS) -I$(gmepath) -std=c99 -DGME_VERSION_055
+AM_CPPFLAGS = $(CXXFLAGS) -fno-exceptions -fno-rtti -nostdlib -fno-unwind-tables
endif
diff --git a/plugins/gme/cgme.c b/plugins/gme/cgme.c
index 5d2920f0..27880d3f 100644
--- a/plugins/gme/cgme.c
+++ b/plugins/gme/cgme.c
@@ -21,6 +21,18 @@
#include "gme/gme.h"
#include "../../deadbeef.h"
+int _Unwind_Resume_or_Rethrow;
+int _Unwind_RaiseException;
+int _Unwind_GetLanguageSpecificData;
+int _Unwind_Resume;
+int _Unwind_DeleteException;
+int _Unwind_GetTextRelBase;
+int _Unwind_SetIP;
+int _Unwind_GetDataRelBase;
+int _Unwind_GetRegionStart;
+int _Unwind_SetGR;
+int _Unwind_GetIPInfo;
+
//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
#define trace(fmt,...)
diff --git a/plugins/gtkui/callbacks.c b/plugins/gtkui/callbacks.c
index dd26a422..84a585ee 100644
--- a/plugins/gtkui/callbacks.c
+++ b/plugins/gtkui/callbacks.c
@@ -689,7 +689,7 @@ on_help1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
char fname[PATH_MAX];
- snprintf (fname, sizeof (fname), DOCDIR "/%s", _("help.txt"));
+ snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), _("help.txt"));
show_info_window (fname, _("Help"), &helpwindow);
}
@@ -702,7 +702,7 @@ on_about1_activate (GtkMenuItem *menuitem,
char s[200];
snprintf (s, sizeof (s), _("About DeaDBeeF %s"), VERSION);
char fname[PATH_MAX];
- snprintf (fname, sizeof (fname), DOCDIR "/%s", "about.txt");
+ snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), "about.txt");
show_info_window (fname, s, &aboutwindow);
}
@@ -715,7 +715,7 @@ on_changelog1_activate (GtkMenuItem *menuitem,
char s[200];
snprintf (s, sizeof (s), _("DeaDBeeF %s ChangeLog"), VERSION);
char fname[PATH_MAX];
- snprintf (fname, sizeof (fname), DOCDIR "/%s", "ChangeLog");
+ snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), "ChangeLog");
show_info_window (fname, s, &changelogwindow);
}
@@ -726,7 +726,7 @@ on_gpl1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
char fname[PATH_MAX];
- snprintf (fname, sizeof (fname), DOCDIR "/%s", "COPYING.GPLv2");
+ snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), "COPYING.GPLv2");
show_info_window (fname, "GNU GENERAL PUBLIC LICENSE Version 2", &gplwindow);
}
@@ -737,7 +737,7 @@ on_lgpl1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
char fname[PATH_MAX];
- snprintf (fname, sizeof (fname), DOCDIR "/%s", "COPYING.LGPLv2.1");
+ snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), "COPYING.LGPLv2.1");
show_info_window (fname, "GNU LESSER GENERAL PUBLIC LICENSE Version 2.1", &lgplwindow);
}
@@ -1079,7 +1079,7 @@ on_translators1_activate (GtkMenuItem *menuitem,
char s[200];
snprintf (s, sizeof (s), _("DeaDBeeF Translators"));
char fname[PATH_MAX];
- snprintf (fname, sizeof (fname), DOCDIR "/%s", "translators.txt");
+ snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), "translators.txt");
show_info_window (fname, s, &translatorswindow);
}
diff --git a/plugins/gtkui/coverart.c b/plugins/gtkui/coverart.c
index 7fb50554..ffd2c2b2 100644
--- a/plugins/gtkui/coverart.c
+++ b/plugins/gtkui/coverart.c
@@ -25,8 +25,6 @@
#include "../artwork/artwork.h"
#include "gtkui.h"
-#define DEFAULT_COVER_PATH (PREFIX "/share/deadbeef/pixmaps/noartwork.jpg")
-
//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
#define trace(...)
@@ -151,9 +149,10 @@ loading_thread (void *none) {
g_error_free (error);
error = NULL;
}
- pixbuf = gdk_pixbuf_new_from_file_at_scale (DEFAULT_COVER_PATH, queue->width, queue->width, TRUE, &error);
+ const char *defpath = coverart_plugin->get_default_cover ();
+ pixbuf = gdk_pixbuf_new_from_file_at_scale (defpath, queue->width, queue->width, TRUE, &error);
if (!pixbuf) {
- fprintf (stderr, "gdk_pixbuf_new_from_file_at_scale %s %d failed, error: %s\n", DEFAULT_COVER_PATH, queue->width, error->message);
+ fprintf (stderr, "gdk_pixbuf_new_from_file_at_scale %s %d failed, error: %s\n", defpath, queue->width, error->message);
}
}
if (error) {
diff --git a/plugins/gtkui/gtkui.c b/plugins/gtkui/gtkui.c
index 35da1527..1c2b9b9f 100644
--- a/plugins/gtkui/gtkui.c
+++ b/plugins/gtkui/gtkui.c
@@ -900,7 +900,8 @@ void
gtkui_thread (void *ctx) {
// let's start some gtk
g_thread_init (NULL);
- add_pixmap_directory (PREFIX "/share/deadbeef/pixmaps");
+// add_pixmap_directory (PREFIX "/share/deadbeef/pixmaps");
+ add_pixmap_directory (deadbeef->get_pixmap_dir ());
gdk_threads_init ();
gdk_threads_enter ();
diff --git a/plugins/mpris/Makefile.am b/plugins/mpris/Makefile.am
new file mode 100644
index 00000000..da59d242
--- /dev/null
+++ b/plugins/mpris/Makefile.am
@@ -0,0 +1,8 @@
+if HAVE_MPRIS
+mprisdir = $(libdir)/$(PACKAGE)
+pkglib_LTLIBRARIES = mpris.la
+AM_CFLAGS = $(CFLAGS) $(MPRIS_DEPS_CFLAGS) -std=c99
+mpris_la_SOURCES = mpris.c mpris-spec.h
+mpris_la_LDFLAGS = -module
+mpris_la_LIBADD = $(LDADD) $(MPRIS_DEPS_LIBS)
+endif
diff --git a/plugins/mpris/mpris-spec.h b/plugins/mpris/mpris-spec.h
new file mode 100644
index 00000000..dba8f542
--- /dev/null
+++ b/plugins/mpris/mpris-spec.h
@@ -0,0 +1,91 @@
+#define MPRIS_BUS_NAME_PREFIX "org.mpris.MediaPlayer2"
+#define MPRIS_OBJECT_NAME "/org/mpris/MediaPlayer2"
+
+#define MPRIS_ROOT_INTERFACE "org.mpris.MediaPlayer2"
+#define MPRIS_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
+#define MPRIS_TRACKLIST_INTERFACE "org.mpris.MediaPlayer2.TrackList"
+
+const char *mpris_introspection_xml =
+ "<node>"
+ " <interface name='org.mpris.MediaPlayer2'>"
+ " <method name='Raise'/>"
+ " <method name='Quit'/>"
+ " <property name='CanQuit' type='b' access='read'/>"
+ " <property name='CanRaise' type='b' access='read'/>"
+ " <property name='HasTrackList' type='b' access='read'/>"
+ " <property name='Identity' type='s' access='read'/>"
+ " <property name='DesktopEntry' type='s' access='read'/>"
+ " <property name='SupportedUriSchemes' type='as' access='read'/>"
+ " <property name='SupportedMimeTypes' type='as' access='read'/>"
+ " </interface>"
+ " <interface name='org.mpris.MediaPlayer2.Player'>"
+ " <method name='Next'/>"
+ " <method name='Previous'/>"
+ " <method name='Pause'/>"
+ " <method name='PlayPause'/>"
+ " <method name='Stop'/>"
+ " <method name='Play'/>"
+ " <method name='Seek'>"
+ " <arg direction='in' name='Offset' type='x'/>"
+ " </method>"
+ " <method name='SetPosition'>"
+ " <arg direction='in' name='TrackId' type='o'/>"
+ " <arg direction='in' name='Position' type='x'/>"
+ " </method>"
+ " <method name='OpenUri'>"
+ " <arg direction='in' name='Uri' type='s'/>"
+ " </method>"
+ " <signal name='Seeked'>"
+ " <arg name='Position' type='x'/>"
+ " </signal>"
+ " <property name='PlaybackStatus' type='s' access='read'/>"
+ " <property name='LoopStatus' type='s' access='readwrite'/>"
+ " <property name='Rate' type='d' access='readwrite'/>"
+ " <property name='Shuffle' type='b' access='readwrite'/>"
+ " <property name='Metadata' type='a{sv}' access='read'/>"
+ " <property name='Volume' type='d' access='readwrite'/>"
+ " <property name='Position' type='x' access='read'/>"
+ " <property name='MinimumRate' type='d' access='read'/>"
+ " <property name='MaximumRate' type='d' access='read'/>"
+ " <property name='CanGoNext' type='b' access='read'/>"
+ " <property name='CanGoPrevious' type='b' access='read'/>"
+ " <property name='CanPlay' type='b' access='read'/>"
+ " <property name='CanPause' type='b' access='read'/>"
+ " <property name='CanSeek' type='b' access='read'/>"
+ " <property name='CanControl' type='b' access='read'/>"
+ " </interface>"
+ " <interface name='org.mpris.MediaPlayer2.TrackList'>"
+ " <method name='GetTracksMetadata'>"
+ " <arg direction='in' name='TrackIds' type='ao'/>"
+ " <arg direction='out' name='Metadata' type='aa{sv}'/>"
+ " </method>"
+ " <method name='AddTrack'>"
+ " <arg direction='in' name='Uri' type='s'/>"
+ " <arg direction='in' name='AfterTrack' type='o'/>"
+ " <arg direction='in' name='SetAsCurrent' type='b'/>"
+ " </method>"
+ " <method name='RemoveTrack'>"
+ " <arg direction='in' name='TrackId' type='o'/>"
+ " </method>"
+ " <method name='GoTo'>"
+ " <arg direction='in' name='TrackId' type='o'/>"
+ " </method>"
+ " <signal name='TrackListReplaced'>"
+ " <arg name='Tracks' type='ao'/>"
+ " <arg name='CurrentTrack' type='o'/>"
+ " </signal>"
+ " <signal name='TrackAdded'>"
+ " <arg name='Metadata' type='a{sv}'/>"
+ " <arg name='AfterTrack' type='o'/>"
+ " </signal>"
+ " <signal name='TrackRemoved'>"
+ " <arg name='TrackId' type='o'/>"
+ " </signal>"
+ " <signal name='TrackMetadataChanged'>"
+ " <arg name='TrackId' type='o'/>"
+ " <arg name='Metadata' type='a{sv}'/>"
+ " </signal>"
+ " <property name='Tracks' type='ao' access='read'/>"
+ " <property name='CanEditTracks' type='b' access='read'/>"
+ " </interface>"
+ "</node>";
diff --git a/plugins/mpris/mpris.c b/plugins/mpris/mpris.c
new file mode 100644
index 00000000..040de84c
--- /dev/null
+++ b/plugins/mpris/mpris.c
@@ -0,0 +1,1310 @@
+/*
+ Sound Menu plugin for DeaDBeeF
+ Copyright (C) 2010 Robert Y <Decatf@gmail.com>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <time.h>
+#include <gio/gio.h>
+//#include <libindicate/server.h>
+
+#include <deadbeef/deadbeef.h>
+#include "../artwork/artwork.h"
+
+#include "mpris-spec.h"
+
+#define trace(...)
+#define ENTRY_OBJECT_PATH_PREFIX "/org/mpris/MediaPlayer2/Track/"
+#define DESKTOP_FILE "/usr/share/applications/deadbeef.desktop"
+
+static DB_dsp_t plugin;
+DB_functions_t *deadbeef;
+
+static short enabled = 0;
+DB_artwork_plugin_t *coverart_plugin = NULL;
+
+//static IndicateServer *indicate_server;
+static GDBusConnection *connection;
+static guint name_own_id;
+static guint root_id;
+static guint player_id;
+
+static GHashTable *player_property_changes = NULL;
+static guint player_property_emit_id = 0;
+uintptr_t hash_table_mtx;
+uintptr_t emit_id_mtx;
+
+double prev_track_pos;
+
+
+static gboolean check_can_go_next();
+static gboolean check_can_go_prev();
+void cover_avail_callback (const char *fname, const char *artist, const char *album, void *user_data);
+
+
+/* MPRIS root interface */
+static void
+handle_root_method_call (GDBusConnection *connection,
+ const char *sender,
+ const char *object_path,
+ const char *interface_name,
+ const char *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer *user_data)
+{
+ if (g_strcmp0 (object_path, MPRIS_OBJECT_NAME) != 0 ||
+ g_strcmp0 (interface_name, MPRIS_ROOT_INTERFACE) != 0) {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NOT_SUPPORTED,
+ "Method %s.%s not supported",
+ interface_name,
+ method_name);
+ return;
+ }
+
+ if (g_strcmp0 (method_name, "Raise") == 0) {
+ /* TODO: need way to talk to gtkui plugin */
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "Quit") == 0) {
+ deadbeef->quit();
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NOT_SUPPORTED,
+ "Method %s.%s not supported",
+ interface_name,
+ method_name);
+ }
+}
+
+static GVariant *
+get_root_property (GDBusConnection *connection,
+ const char *sender,
+ const char *object_path,
+ const char *interface_name,
+ const char *property_name,
+ GError **error,
+ gpointer *user_data)
+{
+ if (g_strcmp0 (object_path, MPRIS_OBJECT_NAME) != 0 ||
+ g_strcmp0 (interface_name, MPRIS_ROOT_INTERFACE) != 0) {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NOT_SUPPORTED,
+ "Property %s.%s not supported",
+ interface_name,
+ property_name);
+ return NULL;
+ }
+
+ if (g_strcmp0 (property_name, "CanQuit") == 0) {
+ return g_variant_new_boolean (TRUE);
+ } else if (g_strcmp0 (property_name, "CanRaise") == 0) {
+ return g_variant_new_boolean (FALSE);
+ } else if (g_strcmp0 (property_name, "HasTrackList") == 0) {
+ return g_variant_new_boolean (FALSE);
+ } else if (g_strcmp0 (property_name, "Identity") == 0) {
+ return g_variant_new_string ("DeaDBeef audio player");
+ } else if (g_strcmp0 (property_name, "DesktopEntry") == 0) {
+ return g_variant_new_string(DESKTOP_FILE);
+ } else if (g_strcmp0 (property_name, "SupportedUriSchemes") == 0) {
+ /* need some way to fetch these values */
+ const char *fake_supported_schemes[] = {
+ "file", "http", "cdda", "smb", "sftp", NULL
+ };
+ return g_variant_new_strv (fake_supported_schemes, -1);
+ } else if (g_strcmp0 (property_name, "SupportedMimeTypes") == 0) {
+ const char *fake_supported_mimetypes[] = {
+ "application/ogg", "audio/x-vorbis+ogg", "audio/x-flac", "audio/mpeg", NULL
+ };
+ return g_variant_new_strv (fake_supported_mimetypes, -1);
+ }
+
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NOT_SUPPORTED,
+ "Property %s.%s not supported",
+ interface_name,
+ property_name);
+ return NULL;
+}
+
+static const GDBusInterfaceVTable root_vtable =
+{
+ (GDBusInterfaceMethodCallFunc) handle_root_method_call,
+ (GDBusInterfaceGetPropertyFunc) get_root_property,
+ NULL
+};
+
+
+/* MPRIS player interface */
+
+static void
+playpause () {
+ DB_output_t *output = NULL;
+ int state = -1;
+
+ output = deadbeef->get_output();
+ if (output == NULL) {
+ //printf ("[mpris] playpause(): Could not get output\n");
+ return;
+ }
+
+ state = output->state();
+
+ if (state == OUTPUT_STATE_STOPPED) {
+ deadbeef->playback_play();
+ }
+ else if (state == OUTPUT_STATE_PLAYING) {
+ deadbeef->playback_pause();
+ }
+ else if (state == OUTPUT_STATE_PAUSED) {
+ deadbeef->playback_play();
+ }
+ else {
+ printf ("[mpris] playpause(): Error\n");
+ }
+}
+
+static void
+seek (gint64 offset)
+{
+ DB_playItem_t *play_item = NULL;
+ play_item = deadbeef->streamer_get_playing_track ();
+ if (play_item == NULL) {
+ //printf ("[mpris] seek(): No play item\n");
+ return;
+ }
+
+ // Play position in seconds
+ float playpos = deadbeef->streamer_get_playpos();
+ float newpos = playpos+(offset/G_USEC_PER_SEC);
+
+ if (newpos < 0) {
+ newpos = 0.f;
+ } else if (newpos > play_item->playtime) {
+ deadbeef->playback_next();
+ return;
+ }
+
+ deadbeef->pl_item_unref(play_item);
+ deadbeef->streamer_seek (newpos);
+}
+
+static GVariant *
+get_playback_status (void)
+{
+ GVariant *v = NULL;
+ DB_output_t *output = NULL;
+ int state = -1;
+
+ output = deadbeef->get_output();
+ if (output == NULL) {
+ printf ("[mpris] get_playback_status: Could not get output\n");
+ return v;
+ }
+
+ state = output->state();
+
+ if (state == OUTPUT_STATE_STOPPED) {
+ v = g_variant_new_string ("Stopped");
+ //printf ("[mpris] get_playback_status: Stopped\n");
+ }
+ else if (state == OUTPUT_STATE_PLAYING) {
+ v = g_variant_new_string ("Playing");
+ //printf ("[mpris] get_playback_status: Playing\n");
+ }
+ else if (state == OUTPUT_STATE_PAUSED) {
+ v = g_variant_new_string ("Paused");
+ //printf ("[mpris] get_playback_status: Paused\n");
+ }
+ else {
+ //printf ("[mpris] get_playback_status: Error\n");
+ }
+
+ return v;
+}
+
+static GVariant *
+get_loop_status (void)
+{
+ GVariant *v = NULL;
+ int loop_mode;
+ loop_mode = deadbeef->conf_get_int ("playback.loop", 0);
+
+ if (loop_mode == PLAYBACK_MODE_NOLOOP) {
+ //printf ("[mpris] get_loop_status: None\n");
+ v = g_variant_new_string ("None");
+ }
+ else if (loop_mode == PLAYBACK_MODE_LOOP_ALL) {
+ //printf ("[mpris] get_loop_status: Playlist\n");
+ v = g_variant_new_string ("Playlist");
+ }
+ else if (loop_mode == PLAYBACK_MODE_LOOP_SINGLE) {
+ //printf ("[mpris] get_loop_status: Track\n");
+ v = g_variant_new_string ("Track");
+ }
+
+ return v;
+}
+
+static gboolean
+set_loop_status (GVariant *value)
+{
+ gchar *loop_status;
+ g_variant_get (value, "s", &loop_status);
+
+ if (g_strcmp0 (loop_status, "None") == 0) {
+ deadbeef->conf_set_int ("playback.loop", PLAYBACK_MODE_NOLOOP);
+ return TRUE;
+ } else if (g_strcmp0 (loop_status, "Playlist") == 0) {
+ deadbeef->conf_set_int ("playback.loop", PLAYBACK_MODE_LOOP_ALL);
+ return TRUE;
+ } else if (g_strcmp0 (loop_status, "Track") == 0) {
+ deadbeef->conf_set_int ("playback.loop", PLAYBACK_MODE_LOOP_SINGLE);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static GVariant *
+get_shuffle (void)
+{
+ GVariant *v = NULL;
+ int shuffle_mode;
+ shuffle_mode = deadbeef->conf_get_int ("playback.order", 0);
+
+ if (shuffle_mode == PLAYBACK_ORDER_LINEAR) {
+ //printf ("[mpris] get_shuffle: None\n");
+ v = g_variant_new_boolean (FALSE);
+ }
+ else if (shuffle_mode == PLAYBACK_ORDER_SHUFFLE) {
+ //printf ("[mpris] get_shuffle: Playlist\n");
+ v = g_variant_new_boolean (TRUE);
+ }
+ else if (shuffle_mode == PLAYBACK_ORDER_RANDOM) {
+ //printf ("[mpris] get_shuffle: Track\n");
+ v = g_variant_new_boolean (TRUE);
+ }
+
+ return v;
+}
+
+static gboolean
+set_shuffle (GVariant *value)
+{
+ gboolean shuffle;
+ g_variant_get (value, "b", &shuffle);
+
+ if (shuffle == FALSE) {
+ deadbeef->conf_set_int ("playback.order",PLAYBACK_ORDER_LINEAR);
+ } else {
+ deadbeef->conf_set_int ("playback.order", PLAYBACK_ORDER_SHUFFLE);
+ }
+
+ return TRUE;
+}
+
+static GVariant *
+get_metadata (void)
+{
+ GVariantBuilder *b;
+ DB_playItem_t *play_item = NULL;
+
+ b = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
+
+ play_item = deadbeef->streamer_get_playing_track ();
+ if (play_item == NULL) {
+ //printf ("[mpris] get_metadata: No play item\n");
+ return g_variant_builder_end (b);;
+ }
+
+ char buf[200];
+ int buf_size = sizeof(buf);
+
+ gchar *trackid_str;
+ deadbeef->pl_format_title (play_item, -1, buf, buf_size, DB_COLUMN_FILENUMBER, NULL);
+ trackid_str = g_strdup_printf(ENTRY_OBJECT_PATH_PREFIX "%s", buf);
+ //printf ("[mpris] get_metadata: trackid %s\n", trackid_str);
+ g_variant_builder_add (b, "{sv}", "mpris:trackid", g_variant_new("s", trackid_str));
+ g_free(trackid_str);
+
+ gchar *title_str;
+ deadbeef->pl_format_title (play_item, -1, buf, buf_size, -1, "%t");
+ title_str = g_strdup_printf("%s", buf);
+ //printf ("[mpris] get_metadata: title_str %s\n", title_str);
+ g_variant_builder_add (b, "{sv}", "xesam:title", g_variant_new("s", title_str));
+ g_free(title_str);
+
+ gchar *artist_str;
+ deadbeef->pl_format_title (play_item, -1, buf, buf_size, -1, "%a");
+ artist_str = g_strdup_printf("%s", buf);
+ //printf ("[mpris] get_metadata: artist_str %s\n", artist_str);
+ const char *artist_strv[] = {artist_str, NULL};
+ g_variant_builder_add (b, "{sv}", "xesam:artist", g_variant_new_strv (artist_strv, -1));
+
+
+ gchar *albumartist_str;
+ deadbeef->pl_format_title (play_item, -1, buf, buf_size, -1, "%B");
+ albumartist_str = g_strdup_printf("%s", buf);
+ //printf ("[mpris] get_metadata: albumartist_str %s\n", albumartist_str);
+ const char *albumartist_strv[] = {albumartist_str, NULL};
+ g_variant_builder_add (b, "{sv}", "xesam:albumArtist", g_variant_new_strv (albumartist_strv, -1));
+ g_free(albumartist_str);
+
+ gchar *album_str;
+ deadbeef->pl_format_title (play_item, -1, buf, buf_size, -1, "%b");
+ album_str = g_strdup_printf("%s", buf);
+ //printf ("[mpris] get_metadata: album_str %s\n", album_str);
+ g_variant_builder_add (b, "{sv}", "xesam:album", g_variant_new("s", album_str));
+
+ if (coverart_plugin != NULL) {
+ gchar *image_fname = coverart_plugin->get_album_art (play_item->fname,
+ artist_str,
+ album_str,
+ cover_avail_callback, NULL);
+ g_free(artist_str);
+ g_free(album_str);
+ if (image_fname) {
+ gchar *art_str = g_strjoin (NULL, "file://", image_fname, NULL);
+ g_variant_builder_add (b, "{sv}", "mpris:artUrl", g_variant_new("s", art_str));
+ //printf ("[mpris] get_metadata: image_fname %s\n", art_str);
+ g_free (image_fname);
+ g_free (art_str);
+ }
+ }
+
+ gchar *track_num_str;
+ deadbeef->pl_format_title (play_item, -1, buf, buf_size, -1, "%n");
+ track_num_str = g_strdup_printf("%s", buf);
+ gint64 track_num = g_ascii_strtoll (track_num_str, NULL, 10);
+ //printf ("[mpris] get_metadata: tracknum %ld\n", (long int) track_num);
+ g_variant_builder_add (b, "{sv}", "xesam:trackNumber", g_variant_new("x", track_num));
+ g_free(track_num_str);
+
+ gint64 length = play_item->playtime * G_USEC_PER_SEC;
+ //printf ("[mpris] get_metadata: length %ld\n", (long int) length);
+ g_variant_builder_add (b, "{sv}", "mpris:length", g_variant_new("x", length));
+
+ gchar *genre_str;
+ deadbeef->pl_format_title (play_item, -1, buf, buf_size, -1, "%g");
+ genre_str = g_strdup_printf("%s", buf);
+ //printf ("[mpris] get_metadata: genre_str %s\n", genre_str);
+ const char *genre_strv[] = {genre_str, NULL};
+ g_variant_builder_add (b, "{sv}", "xesam:genre", g_variant_new_strv (genre_strv, -1));
+ g_free(genre_str);
+
+ gchar *comment_str;
+ deadbeef->pl_format_title (play_item, -1, buf, buf_size, -1, "%c");
+ comment_str = g_strdup_printf("%s", buf);
+ //printf ("[mpris] get_metadata: comment_str %s\n", comment_str);
+ const char *comment_strv[] = {comment_str, NULL};
+ g_variant_builder_add (b, "{sv}", "xesam:comment", g_variant_new_strv (comment_strv, -1));
+ g_free(comment_str);
+
+ deadbeef->pl_item_unref(play_item);
+ //printf ("[mpris] get_metadata: done\n");
+
+ return g_variant_builder_end (b);
+}
+
+static GVariant *
+get_position (void)
+{
+ GVariant *v = NULL;
+
+ DB_playItem_t *play_item = NULL;
+ play_item = deadbeef->streamer_get_playing_track ();
+ if (play_item == NULL) {
+ //printf ("[mpris] get_position: No play item\n");
+ return v;
+ }
+
+ deadbeef->pl_item_unref(play_item);
+
+ float playpos = deadbeef->streamer_get_playpos();
+ return g_variant_new_int64 (playpos*G_USEC_PER_SEC);
+}
+
+void
+set_position (const gchar* track_id, gint64 position)
+{
+ DB_playItem_t *play_item = NULL;
+ play_item = deadbeef->streamer_get_playing_track ();
+ if (play_item == NULL) {
+ //printf ("[mpris] set_position: No play item\n");
+ return;
+ }
+
+ gint64 play_time = play_item->playtime*G_USEC_PER_SEC;
+ if (position > play_time)
+ return;
+
+ char *trackid_str;
+ trackid_str = g_strdup_printf(ENTRY_OBJECT_PATH_PREFIX "%s", play_item->fname);
+ if (g_strcmp0(trackid_str, track_id) != 0) {
+ g_free(trackid_str);
+ return;
+ }
+ g_free(trackid_str);
+ deadbeef->pl_item_unref(play_item);
+
+ deadbeef->streamer_seek((float)position/G_USEC_PER_SEC);
+}
+
+static GVariant *
+get_canplay (void)
+{
+ DB_playItem_t *play_item = NULL;
+ play_item = deadbeef->streamer_get_playing_track ();
+ if (play_item == NULL) {
+ return g_variant_new_boolean(FALSE);
+ }
+ deadbeef->pl_item_unref(play_item);
+
+ return g_variant_new_boolean(TRUE);
+}
+
+static GVariant *
+get_canpause (void)
+{
+ DB_playItem_t *play_item = NULL;
+ play_item = deadbeef->streamer_get_playing_track ();
+ if (play_item == NULL) {
+ return g_variant_new_boolean(FALSE);
+ }
+ deadbeef->pl_item_unref(play_item);
+
+ DB_output_t *output = NULL;
+ output = deadbeef->get_output();
+ if (output != NULL) {
+ if (output->state == OUTPUT_STATE_STOPPED) {
+ return g_variant_new_boolean(FALSE);
+ }
+ }
+ //else printf ("[mpris] get_canpause: Could not get output\n");
+
+ return g_variant_new_boolean(TRUE);
+}
+
+
+///
+// PropertiesChanged signal
+///
+/*
+static void
+emit_property_change (const gchar *name, GVariant *value)
+{
+ GError *error = NULL;
+ GVariantBuilder *properties;
+ GVariant *properties_changed = NULL;
+ const char *invalidated[] = { NULL };
+
+ properties = g_variant_builder_new (G_VARIANT_TYPE("a{sv}"));
+ g_variant_builder_add (properties, "{sv}", name, value);
+
+ properties_changed = g_variant_new ("(sa{sv}^as)",
+ MPRIS_PLAYER_INTERFACE,
+ properties,
+ invalidated);
+ g_variant_builder_unref (properties);
+
+ g_dbus_connection_emit_signal (connection,
+ NULL,
+ MPRIS_OBJECT_NAME,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ properties_changed,
+ &error);
+
+ if (error != NULL) {
+ printf ("[mpris] Unable to send MPRIS property changes: %s", error->message);
+ g_clear_error (&error);
+ }
+ //printf ("[mpris] Sent property change: %s\n", name);
+}
+*/
+
+static gboolean
+emit_player_properties (gpointer data)
+{
+ //printf ("[mpris] emit_player_properties\n");
+
+ GError *error = NULL;
+ GVariantBuilder *properties;
+ GVariant *properties_changed = NULL;
+ const char *invalidated[] = { NULL };
+ GHashTableIter iter;
+ gpointer propname, propvalue;
+
+
+ deadbeef->mutex_lock(hash_table_mtx);
+ properties = g_variant_builder_new (G_VARIANT_TYPE("a{sv}"));
+ g_hash_table_iter_init (&iter, player_property_changes);
+ while (g_hash_table_iter_next (&iter, &propname, &propvalue)) {
+ g_variant_builder_add (properties, "{sv}", propname, propvalue);
+ }
+ g_hash_table_destroy (player_property_changes);
+ player_property_changes = NULL;
+ deadbeef->mutex_unlock(hash_table_mtx);
+
+ properties_changed = g_variant_new ("(sa{sv}^as)",
+ MPRIS_PLAYER_INTERFACE,
+ properties,
+ invalidated);
+ g_variant_builder_unref (properties);
+
+ g_dbus_connection_emit_signal (connection,
+ NULL,
+ MPRIS_OBJECT_NAME,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ properties_changed,
+ &error);
+
+ deadbeef->mutex_lock(emit_id_mtx);
+ player_property_emit_id = 0;
+ deadbeef->mutex_unlock(emit_id_mtx);
+
+ if (error != NULL) {
+ printf ("[mpris] Unable to send MPRIS property changes: %s", error->message);
+ g_clear_error (&error);
+ }
+
+ //printf ("[mpris] emit_player_properties: done %d\n", player_property_emit_id);
+
+ return FALSE;
+}
+
+
+static void
+add_property_change (const gchar *property, GVariant *value)
+{
+ //printf ("[mpris] add_property_change\n");
+
+ deadbeef->mutex_lock(hash_table_mtx);
+ if (player_property_changes == NULL) {
+ player_property_changes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ }
+ g_hash_table_insert (player_property_changes, g_strdup (property), value);
+ deadbeef->mutex_unlock(hash_table_mtx);
+
+ if (player_property_emit_id == 0) {
+ deadbeef->mutex_lock(emit_id_mtx);
+ player_property_emit_id = g_idle_add ((GSourceFunc)emit_player_properties, NULL);
+ //printf ("[mpris] add_property_change: done\n");
+ deadbeef->mutex_unlock(emit_id_mtx);
+
+ return;
+ }
+
+ //printf ("[mpris] add_property_change: source exists %d\n", player_property_emit_id);
+}
+
+
+// Events from DeaDBeef
+
+/*
+ PlaybackStatus: Working
+ LoopStatus: need event on playback.loop config change
+ Rate: not supported
+ Shuffle: need event on playback.order config change
+ Metadata: Working
+ Volume: Working(?)
+ MinimumRate: not supported
+ MaximumRate: not supported
+ CanGoNext: check&emit value on song start
+ CanGoPrevious: check&emit value on song start
+ CanPlay: not implemented
+ CanPause: dunno how to check this
+ CanSeek: dunno how to check this
+*/
+
+static int
+db_paused (DB_event_t *ev, uintptr_t data)
+{
+ //printf ("[mpris] db_paused: PlaybackStatus\n");
+ //emit_property_change ("PlaybackStatus", get_playback_status());
+ add_property_change ("PlaybackStatus", get_playback_status());
+ return 0;
+}
+
+static int
+db_track_info_changed (DB_event_t *ev, uintptr_t data)
+{
+
+ //printf ("[mpris] db_track_info_changed\n");
+ GVariant *v = NULL;
+ DB_output_t *output = NULL;
+ int state = -1;
+
+ // Playback state change
+ output = deadbeef->get_output();
+ if (output == NULL) {
+ //printf ("[mpris] db_track_info_changed(): Could not get output\n");
+ return 0;
+ }
+
+ state = output->state();
+ if (state == OUTPUT_STATE_STOPPED) {
+ v = g_variant_new_string ("Stopped");
+ //printf ("[mpris] db_track_info_changed: Stopped\n");
+ }
+ else if (state == OUTPUT_STATE_PLAYING) {
+ v = g_variant_new_string ("Playing");
+ //printf ("[mpris] db_track_info_changed: Playing\n");
+ }
+ else if (state == OUTPUT_STATE_PAUSED) {
+ v = g_variant_new_string ("Paused");
+ //printf ("[mpris] db_track_info_changed: Paused\n");
+ }
+ else {
+ //printf ("[mpris] db_track_info_changed: Error\n");
+ }
+ //printf ("[mpris] db_track_info_changed: PlaybackStatus\n");
+ //emit_property_change ("PlaybackStatus", v);
+ add_property_change ("PlaybackStatus", v);
+
+ // Seek
+
+ // A change of greater than 1 second from the
+ // previous track position is considered a seek.
+ // (including the time change from track changes)
+ DB_playItem_t *play_item = NULL;
+ play_item = deadbeef->streamer_get_playing_track ();
+ if (play_item != NULL) {
+
+ float playpos = deadbeef->streamer_get_playpos();
+ float diff = playpos - prev_track_pos;
+ if (diff > 1.f || diff < -1.f) {
+ //printf ("[mpris] db_track_info_changed(): Seeked: %f\n", diff);
+
+ GError *error = NULL;
+ g_dbus_connection_emit_signal (connection,
+ NULL,
+ MPRIS_OBJECT_NAME,
+ MPRIS_PLAYER_INTERFACE,
+ "Seeked",
+ g_variant_new ("(x)", (int)(deadbeef->streamer_get_playpos())*G_USEC_PER_SEC),
+ &error);
+ if (error != NULL) {
+ g_warning ("[mpris] Unable to set MPRIS Seeked signal: %s", error->message);
+ g_clear_error (&error);
+ }
+ }
+ deadbeef->pl_item_unref(play_item);
+ }
+
+
+ // Metadata changes
+ v = get_metadata();
+ if (v != NULL) {
+ //emit_property_change ("Metadata", v);
+ add_property_change ("Metadata", v);
+ }
+ else {
+ printf ("[mpris] db_track_info_changed: no track\n");
+ }
+
+ return 0;
+}
+
+static int
+db_song_changed (DB_event_t *ev, uintptr_t data)
+{
+/*
+ printf ("[mpris] db_song_changed\n");
+ GVariant *v = NULL;
+ v = get_metadata();
+ if (v != NULL) {
+ emit_property_change ("Metadata", v);
+ }
+*/
+ return 0;
+}
+
+static int
+db_song_started (DB_event_t *ev, uintptr_t data)
+{
+ //printf ("[mpris] db_song_started\n");
+
+ GVariant *v = NULL;
+ v = get_metadata();
+ if (v != NULL) {
+ //emit_property_change ("Metadata", v);
+ add_property_change ("Metadata", v);
+ }
+
+ gboolean can_go_next = check_can_go_next();
+ //emit_property_change ("CanGoNext", g_variant_new_boolean(can_go_next));
+ add_property_change ("CanGoNext", g_variant_new_boolean(can_go_next));
+
+ gboolean can_go_prev = check_can_go_prev();
+ //emit_property_change ("CanGoPrev", g_variant_new_boolean(can_go_prev));
+ add_property_change ("CanGoPrev", g_variant_new_boolean(can_go_prev));
+
+ return 0;
+}
+
+static int
+db_song_finished (DB_event_t *ev, uintptr_t data)
+{
+ //printf ("[mpris] db_song_finished\n");
+/*
+ GVariant *v = NULL;
+ v = get_metadata();
+ if (v != NULL) {
+ emit_property_change ("Metadata", v);
+ }
+*/
+ return 0;
+}
+
+static int
+db_volume_changed (DB_event_t *ev, uintptr_t data)
+{
+ gdouble volume = deadbeef->volume_get_amp();
+ if (volume < 0)
+ volume = 0;
+ //emit_property_change ("Volume", g_variant_new_double (volume));
+ add_property_change ("Volume", g_variant_new_double (volume));
+ printf ("[mpris] db_volume_changed: Volume %lf\n", volume);
+ return 0;
+}
+
+static int
+db_frameupdate (DB_event_t *ev, uintptr_t data)
+{
+
+ DB_playItem_t *play_item = NULL;
+ play_item = deadbeef->streamer_get_playing_track ();
+ if (play_item != NULL) {
+ prev_track_pos = deadbeef->streamer_get_playpos();
+ deadbeef->pl_item_unref(play_item);
+ }
+ return 0;
+}
+
+static int
+db_playlist_switched (DB_event_t *ev, uintptr_t data)
+{
+ //printf ("[mpris] db_playlist_switched\n");
+ return 0;
+}
+
+static int
+db_activate (DB_event_t *ev, uintptr_t data)
+{
+ printf ("[mpris] db_activate()\n");
+ return 0;
+}
+
+// non callback emit helper functions
+static gboolean
+check_can_go_next() {
+
+
+ int loop_mode = deadbeef->conf_get_int ("playback.loop", 0);
+ if (loop_mode == PLAYBACK_MODE_NOLOOP) {
+ int playlist_size = deadbeef->pl_getcount(deadbeef->plt_get_curr());
+
+ // Check if playlist is on last track
+ DB_playItem_t *play_item = NULL;
+ play_item = deadbeef->streamer_get_playing_track ();
+ if (play_item == NULL) {
+ deadbeef->pl_item_unref(play_item);
+ return FALSE;
+ }
+
+ int pl_current = deadbeef->pl_get_idx_of(play_item);
+ if (pl_current == playlist_size) {
+ deadbeef->pl_item_unref(play_item);
+ return FALSE;
+ }
+ deadbeef->pl_item_unref(play_item);
+ //printf ("[mpris] check_cangonext() plt count: %d plt current: %d\n", playlist_size, pl_current);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+check_can_go_prev() {
+
+ int loop_mode = deadbeef->conf_get_int ("playback.loop", 0);
+ if (loop_mode == PLAYBACK_MODE_NOLOOP) {
+ // Check if playlist is on first track
+ DB_playItem_t *play_item = NULL;
+ play_item = deadbeef->streamer_get_playing_track ();
+ if (play_item == NULL) {
+ return FALSE;
+ }
+
+ int pl_current = deadbeef->pl_get_idx_of(play_item);
+ if (pl_current == 0) {
+ deadbeef->pl_item_unref(play_item);
+ return TRUE;
+ }
+ deadbeef->pl_item_unref(play_item);
+ //printf ("[mpris] check_cangoprev() plt current: %d\n", pl_current);
+ }
+ return TRUE;
+}
+
+// Artwork plugin callback
+void cover_avail_callback (const char *fname, const char *artist, const char *album, void *user_data) {
+ //printf ("[mpris] cover_avail_callback\n");
+ GVariant *v = get_metadata();
+ //emit_property_change ("Metadata", v);
+ add_property_change ("Metadata", v);
+}
+
+
+///
+// MediaPlayer2.Player handlers
+///
+static void
+handle_result (GDBusMethodInvocation *invocation)
+{
+ g_dbus_method_invocation_return_error_literal (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Unknown error");
+}
+
+static void
+handle_player_method_call (GDBusConnection *connection,
+ const char *sender,
+ const char *object_path,
+ const char *interface_name,
+ const char *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer *user_data)
+{
+
+ if (g_strcmp0 (object_path, MPRIS_OBJECT_NAME) != 0 ||
+ g_strcmp0 (interface_name, MPRIS_PLAYER_INTERFACE) != 0) {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NOT_SUPPORTED,
+ "Method %s.%s not supported",
+ interface_name,
+ method_name);
+ return;
+ }
+
+ if (g_strcmp0 (method_name, "Next") == 0) {
+ deadbeef->playback_next();
+ handle_result (invocation);
+ } else if (g_strcmp0 (method_name, "Previous") == 0) {
+ deadbeef->playback_prev();
+ handle_result (invocation);
+ } else if (g_strcmp0 (method_name, "PlayPause") == 0) {
+ playpause();
+ handle_result (invocation);
+ } else if (g_strcmp0 (method_name, "Stop") == 0) {
+ deadbeef->playback_stop();
+ handle_result (invocation);
+ } else if (g_strcmp0 (method_name, "Play") == 0) {
+ deadbeef->playback_play();
+ handle_result (invocation);
+ } else if (g_strcmp0 (method_name, "Seek") == 0) {
+ gint64 offset;
+ g_variant_get (parameters, "(x)", &offset);
+ seek (offset);
+ handle_result (invocation);
+ } else if (g_strcmp0 (method_name, "SetPosition") == 0) {
+ gint64 position;
+ const gchar *track_id;
+ g_variant_get (parameters, "&ox", &track_id, &position);
+ set_position (track_id, position);
+ handle_result (invocation);
+ } else if (g_strcmp0 (method_name, "OpenUri") == 0) {
+ /* TODO: implement this */
+ const char *uri;
+ g_variant_get (parameters, "(&s)", &uri);
+
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NOT_SUPPORTED,
+ "Method %s.%s not supported",
+ interface_name,
+ method_name);
+
+ } else {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NOT_SUPPORTED,
+ "Method %s.%s not supported",
+ interface_name,
+ method_name);
+ }
+}
+
+static GVariant *
+get_player_property (GDBusConnection *connection,
+ const char *sender,
+ const char *object_path,
+ const char *interface_name,
+ const char *property_name,
+ GError **error,
+ gpointer *user_data)
+{
+
+ //printf ("[mpris] get_player_property\n");
+ if (g_strcmp0 (property_name, "PlaybackStatus") == 0) {
+ return get_playback_status();
+ } else if (g_strcmp0 (property_name, "LoopStatus") == 0) {
+ return get_loop_status ();
+ } else if (g_strcmp0 (property_name, "Rate") == 0) {
+ return g_variant_new_double (1.0);
+ } else if (g_strcmp0 (property_name, "Shuffle") == 0) {
+ return get_shuffle ();
+ } else if (g_strcmp0 (property_name, "Metadata") == 0) {
+ //printf ("[mpris] get_player_property: Metadata\n");
+ return get_metadata ();
+ } else if (g_strcmp0 (property_name, "Volume") == 0) {
+ gdouble volume = deadbeef->volume_get_amp();
+ return g_variant_new_double(volume);
+ } else if (g_strcmp0 (property_name, "Position") == 0) {
+ return get_position();
+ } else if (g_strcmp0 (property_name, "MinimumRate") == 0) {
+ return g_variant_new_double (1.0);
+ } else if (g_strcmp0 (property_name, "MaximumRate") == 0) {
+ return g_variant_new_double (1.0);
+ } else if (g_strcmp0 (property_name, "CanGoNext") == 0) {
+ return g_variant_new_boolean (TRUE);
+ } else if (g_strcmp0 (property_name, "CanGoPrevious") == 0) {
+ return g_variant_new_boolean (TRUE);
+ } else if (g_strcmp0 (property_name, "CanPlay") == 0) {
+ return get_canplay();
+ } else if (g_strcmp0 (property_name, "CanPause") == 0) {
+ return get_canpause();
+ } else if (g_strcmp0 (property_name, "CanSeek") == 0) {
+ /* Not sure how to check if a track is seekable
+ return true anyways */
+ return g_variant_new_boolean(TRUE);
+ } else if (g_strcmp0 (property_name, "CanControl") == 0) {
+ return g_variant_new_boolean(TRUE);
+ }
+
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NOT_SUPPORTED,
+ "Property %s.%s not supported",
+ interface_name,
+ property_name);
+ return NULL;
+}
+
+static gboolean
+set_player_property (GDBusConnection *connection,
+ const char *sender,
+ const char *object_path,
+ const char *interface_name,
+ const char *property_name,
+ GVariant *value,
+ GError **error,
+ gpointer *user_data)
+{
+
+ if (g_strcmp0 (object_path, MPRIS_OBJECT_NAME) != 0 ||
+ g_strcmp0 (interface_name, MPRIS_PLAYER_INTERFACE) != 0) {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NOT_SUPPORTED,
+ "%s:%s not supported",
+ object_path,
+ interface_name);
+ return FALSE;
+ }
+
+ if (g_strcmp0 (property_name, "LoopStatus") == 0) {
+ return set_loop_status(value);
+ } else if (g_strcmp0 (property_name, "Rate") == 0) {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "[mpris] Can't modify playback rate");
+ return FALSE;
+ } else if (g_strcmp0 (property_name, "Shuffle") == 0) {
+ set_shuffle (value);
+ return TRUE;
+ } else if (g_strcmp0 (property_name, "Volume") == 0) {
+ gdouble volume;
+ volume = g_variant_get_double (value);
+ if (volume < 0) volume = 0;
+ deadbeef->volume_set_amp((float)volume);
+ printf ("[mpris] set_player_property: volume %lf\n", volume);
+ return TRUE;
+ }
+
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NOT_SUPPORTED,
+ "Property %s.%s not supported",
+ interface_name,
+ property_name);
+ return FALSE;
+}
+
+static const GDBusInterfaceVTable player_vtable =
+{
+ (GDBusInterfaceMethodCallFunc) handle_player_method_call,
+ (GDBusInterfaceGetPropertyFunc) get_player_property,
+ (GDBusInterfaceSetPropertyFunc) set_player_property,
+};
+
+
+/* DeaDBeef plugin */
+
+static void
+name_acquired_cb (GDBusConnection *connection, const char *name, gpointer *user_data)
+{
+ trace ("[mpris] Successfully acquired dbus name %s\n", name);
+}
+
+static void
+name_lost_cb (GDBusConnection *connection, const char *name, gpointer *user_data)
+{
+ trace ("[mpris] Lost dbus name %s\n", name);
+}
+
+static gboolean
+mpris_begin ()
+{
+// indicate_server = indicate_server_ref_default ();
+// indicate_server_set_type (indicate_server, "music.deadbeef");
+// indicate_server_set_desktop_file (indicate_server, DESKTOP_FILE);
+// indicate_server_show (indicate_server);
+
+ GError *error = NULL;
+ GDBusInterfaceInfo *ifaceinfo;
+ GDBusNodeInfo *node_info;
+
+ connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+ if (error != NULL) {
+ g_warning ("[mpris] Unnable to connect to D-Bus session bus: %s", error->message);
+ return FALSE;
+ }
+
+ // Introspection data
+ node_info = g_dbus_node_info_new_for_xml (mpris_introspection_xml, &error);
+ if (error != NULL) {
+ g_warning ("[mpris] Unnable to read MPRIS interface specification: %s", error->message);
+ return -1;
+ }
+
+ // Root interface
+ ifaceinfo = g_dbus_node_info_lookup_interface (node_info, MPRIS_ROOT_INTERFACE);
+ root_id = g_dbus_connection_register_object (connection,
+ MPRIS_OBJECT_NAME,
+ ifaceinfo,
+ &root_vtable,
+ NULL,
+ NULL,
+ &error);
+ if (error != NULL) {
+ g_warning ("[mpris] Unnable to register MPRIS root interface: %s", error->message);
+ return FALSE;
+ }
+
+ // Player interface
+ ifaceinfo = g_dbus_node_info_lookup_interface (node_info, MPRIS_PLAYER_INTERFACE);
+ player_id = g_dbus_connection_register_object (connection,
+ MPRIS_OBJECT_NAME,
+ ifaceinfo,
+ &player_vtable,
+ NULL,
+ NULL,
+ &error);
+ if (error != NULL) {
+ g_warning ("[mpris] Unable to register MPRIS player interface: %s", error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ name_own_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+ MPRIS_BUS_NAME_PREFIX ".deadbeef",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ NULL,
+ (GBusNameAcquiredCallback) name_acquired_cb,
+ (GBusNameLostCallback) name_lost_cb,
+ NULL,
+ NULL);
+
+
+ // DeaDBeef event callbacks
+ deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_PAUSED, DB_CALLBACK (db_paused), 0);
+ deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_TRACKINFOCHANGED, DB_CALLBACK (db_track_info_changed), 0);
+ deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_SONGCHANGED, DB_CALLBACK (db_song_changed), 0);
+ deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_SONGSTARTED, DB_CALLBACK (db_song_started), 0);
+ deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_SONGFINISHED, DB_CALLBACK (db_song_finished), 0);
+ deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_VOLUMECHANGED, DB_CALLBACK (db_volume_changed), 0);
+ deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_ACTIVATE, DB_CALLBACK (db_activate), 0);
+ deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_PLAYLISTSWITCH, DB_CALLBACK (db_playlist_switched), 0);
+ deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_FRAMEUPDATE, DB_CALLBACK (db_frameupdate), 0);
+
+ //
+ player_property_changes = NULL;
+ player_property_emit_id = 0;
+ hash_table_mtx = deadbeef->mutex_create();
+ emit_id_mtx = deadbeef->mutex_create();
+
+ //printf ("[mpris] begin %d\n", name_own_id);
+ return TRUE;
+}
+
+static void
+mpris_end ()
+{
+ if (coverart_plugin) {
+ //coverart_plugin->plugin.plugin.stop ();
+ coverart_plugin = NULL;
+ }
+ deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_PAUSED, DB_CALLBACK (db_paused), 0);
+ deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_TRACKINFOCHANGED, DB_CALLBACK (db_track_info_changed), 0);
+ deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_SONGCHANGED, DB_CALLBACK (db_song_changed), 0);
+ deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_SONGSTARTED, DB_CALLBACK (db_song_started), 0);
+ deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_SONGFINISHED, DB_CALLBACK (db_song_finished), 0);
+ deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_VOLUMECHANGED, DB_CALLBACK (db_volume_changed), 0);
+ deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_ACTIVATE, DB_CALLBACK (db_activate), 0);
+ deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_PLAYLISTSWITCH, DB_CALLBACK (db_playlist_switched), 0);
+ deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_FRAMEUPDATE, DB_CALLBACK (db_frameupdate), 0);
+
+ if (root_id != 0) {
+ g_dbus_connection_unregister_object (connection, root_id);
+ root_id = 0;
+ }
+
+ if (player_id != 0) {
+ g_dbus_connection_unregister_object (connection, player_id);
+ player_id = 0;
+ }
+
+ if (name_own_id != 0) {
+ g_bus_unown_name (name_own_id);
+ name_own_id = 0;
+ }
+
+// indicate_server_hide (indicate_server);
+
+ deadbeef->mutex_lock(emit_id_mtx);
+ if (player_property_emit_id != 0) {
+ g_source_remove (player_property_emit_id);
+ player_property_emit_id = 0;
+ }
+ deadbeef->mutex_unlock(emit_id_mtx);
+ deadbeef->mutex_free (emit_id_mtx);
+
+ deadbeef->mutex_lock(hash_table_mtx);
+ if (player_property_changes != NULL) {
+ g_hash_table_destroy (player_property_changes);
+ player_property_changes = NULL;
+ }
+ deadbeef->mutex_unlock(hash_table_mtx);
+ deadbeef->mutex_free (hash_table_mtx);
+
+ //printf ("[mpris] end\n");
+}
+
+
+static int
+mpris_connect (void) {
+ //printf ("[mpris] mpris_connect\n");
+ DB_plugin_t **plugins = deadbeef->plug_get_list ();
+ for (int i = 0; plugins[i]; i++) {
+ DB_plugin_t *p = plugins[i];
+ if (p->id && !g_strcmp0 (p->id, "cover_loader")) {
+ trace ("gtkui: found cover-art loader plugin\n");
+ coverart_plugin = (DB_artwork_plugin_t *)p;
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static int
+mpris_on_configchanged (DB_event_t *ev, uintptr_t data) {
+ int e = deadbeef->conf_get_int ("mpris.enable", 0);
+ //printf ("[mpris] configchanged(): enable %d\n", e);
+ if (e != enabled) {
+ if (e) {
+ mpris_begin ();
+ mpris_connect ();
+ db_track_info_changed (NULL, 0);
+ } else {
+ mpris_end ();
+ }
+ enabled = e;
+ }
+ return 0;
+}
+
+static int
+mpris_plugin_start (void) {
+
+ deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_CONFIGCHANGED, DB_CALLBACK (mpris_on_configchanged), 0);
+
+ int e = deadbeef->conf_get_int ("mpris.enable", 0);
+ if (e != enabled) {
+ enabled = e;
+ if (enabled == 1) {
+ mpris_begin ();
+ }
+ }
+
+ return 0;
+}
+
+static int
+mpris_plugin_stop (void) {
+
+ deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_CONFIGCHANGED, DB_CALLBACK (mpris_on_configchanged), 0);
+
+ if (enabled == 1) {
+ mpris_end ();
+ }
+
+ return 0;
+}
+
+static const char settings_dlg[] =
+ "property \"Enable\" checkbox mpris.enable 0;\n"
+;
+
+static DB_dsp_t plugin = {
+ .plugin.api_vmajor = DB_API_VERSION_MAJOR,
+ .plugin.api_vminor = DB_API_VERSION_MINOR,
+ .plugin.type = DB_PLUGIN_MISC,
+ .plugin.id = "mpris",
+ .plugin.name = "MPRIS",
+ .plugin.descr = "MPRIS",
+ .plugin.author = "Robert Y",
+ .plugin.email = "Decatf@gmail.com",
+ .plugin.website = "http://deadbeef.sf.net",
+ .plugin.start = mpris_plugin_start,
+ .plugin.stop = mpris_plugin_stop,
+ .plugin.configdialog = settings_dlg,
+ .plugin.connect = mpris_connect,
+};
+
+DB_plugin_t *
+mpris_load (DB_functions_t *api) {
+ deadbeef = api;
+ return DB_PLUGIN (&plugin);
+}
diff --git a/plugins/shellexec/Makefile.am b/plugins/shellexec/Makefile.am
index 65d6a5b8..212f6a0b 100644
--- a/plugins/shellexec/Makefile.am
+++ b/plugins/shellexec/Makefile.am
@@ -4,6 +4,6 @@ pkglib_LTLIBRARIES = shellexec.la
shellexec_la_SOURCES = shellexec.c
shellexec_la_LDFLAGS = -module
-shellexec_la_LIBADD = $(LDADD) $(HOTKEYS_LIBS)
+shellexec_la_LIBADD = $(LDADD)
AM_CFLAGS = $(CFLAGS) -std=c99
endif
diff --git a/plugins/sid/Makefile.am b/plugins/sid/Makefile.am
index 38caa014..f5408088 100644
--- a/plugins/sid/Makefile.am
+++ b/plugins/sid/Makefile.am
@@ -103,9 +103,9 @@ sidplay-libs/libsidplay/src/kernal.bin\
sidplay-libs/libsidplay/src/psiddrv.bin\
sidplay-libs/libsidplay/src/poweron.bin
-sid_la_LIBADD = -lstdc++
-sid_la_LDFLAGS = -module
+sid_la_LDFLAGS = -module -nostdlib -lsupc++
AM_CFLAGS = $(CFLAGS) -std=c99 -I$(sidpath)/libsidplay/include -I$(sidpath)/builders/resid-builder/include -fPIC
-AM_CPPFLAGS = $(CXXFLAGS) -DHAVE_UNIX -I$(sidpath) -I$(sidpath)/unix -I$(sidpath)/libsidplay -I$(sidpath)/libsidplay/include -I$(sidpath)/libsidplay/include/sidplay -I$(sidpath)/libsidutils/include/sidplay/utils -I$(sidpath)/builders/resid-builder/include/sidplay/builders -I$(sidpath)/builders/resid-builder/include -DHAVE_STRCASECMP -DHAVE_STRNCASECMP
+AM_CPPFLAGS = $(CXXFLAGS) -DHAVE_UNIX -I$(sidpath) -I$(sidpath)/unix -I$(sidpath)/libsidplay -I$(sidpath)/libsidplay/include -I$(sidpath)/libsidplay/include/sidplay -I$(sidpath)/libsidutils/include/sidplay/utils -I$(sidpath)/builders/resid-builder/include/sidplay/builders -I$(sidpath)/builders/resid-builder/include -DHAVE_STRCASECMP -DHAVE_STRNCASECMP -fno-exceptions -fno-rtti -fno-unwind-tables
+
endif
diff --git a/plugins/sid/csid.cpp b/plugins/sid/csid.cpp
index ccb2ecb3..57035291 100644
--- a/plugins/sid/csid.cpp
+++ b/plugins/sid/csid.cpp
@@ -34,6 +34,18 @@
#include "../../deadbeef.h"
#include "csid.h"
+int _Unwind_Resume_or_Rethrow;
+int _Unwind_RaiseException;
+int _Unwind_GetLanguageSpecificData;
+int _Unwind_Resume;
+int _Unwind_DeleteException;
+int _Unwind_GetTextRelBase;
+int _Unwind_SetIP;
+int _Unwind_GetDataRelBase;
+int _Unwind_GetRegionStart;
+int _Unwind_SetGR;
+int _Unwind_GetIPInfo;
+
extern DB_decoder_t sid_plugin;
//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
diff --git a/plugins/supereq/Equ.cpp b/plugins/supereq/Equ.cpp
index f53b99d1..4411dbd9 100644
--- a/plugins/supereq/Equ.cpp
+++ b/plugins/supereq/Equ.cpp
@@ -4,6 +4,18 @@
#include <assert.h>
#include "paramlist.hpp"
+int _Unwind_Resume_or_Rethrow;
+int _Unwind_RaiseException;
+int _Unwind_GetLanguageSpecificData;
+int _Unwind_Resume;
+int _Unwind_DeleteException;
+int _Unwind_GetTextRelBase;
+int _Unwind_SetIP;
+int _Unwind_GetDataRelBase;
+int _Unwind_GetRegionStart;
+int _Unwind_SetGR;
+int _Unwind_GetIPInfo;
+
typedef float REAL;
void rfft(int n,int isign,REAL x[]);
diff --git a/plugins/supereq/Makefile.am b/plugins/supereq/Makefile.am
index 0fffd6d6..eecade68 100644
--- a/plugins/supereq/Makefile.am
+++ b/plugins/supereq/Makefile.am
@@ -3,7 +3,9 @@ supereqdir = $(libdir)/$(PACKAGE)
pkglib_LTLIBRARIES = supereq.la
supereq_la_SOURCES = supereq.c supereq.h Equ.cpp Fftsg_fl.cpp paramlist.hpp
-supereq_la_LDFLAGS = -module
+AM_CPPFLAGS = $(CXXFLAGS) -fno-exceptions -fno-rtti -nostdlib -fno-unwind-tables
+
+supereq_la_LDFLAGS = -module -nostdlib -lsupc++
supereq_la_LIBADD = $(LDADD)
AM_CFLAGS = -std=c99
diff --git a/plugins/vfs_curl/Makefile.am b/plugins/vfs_curl/Makefile.am
index 95794831..4c69c51f 100644
--- a/plugins/vfs_curl/Makefile.am
+++ b/plugins/vfs_curl/Makefile.am
@@ -4,6 +4,6 @@ pkglib_LTLIBRARIES = vfs_curl.la
vfs_curl_la_SOURCES = vfs_curl.c
vfs_curl_la_LDFLAGS = -module
-vfs_curl_la_LIBADD = $(LDADD) $(CURL_LIBS)
+vfs_curl_la_LIBADD = $(LDADD) $(VFS_CURL_LIBS)
AM_CFLAGS = $(CFLAGS) -std=c99
endif