diff options
84 files changed, 1180 insertions, 11518 deletions
@@ -1,90 +1,41 @@ -*.o -*~ -compile -m4 -depcomp -Makefile.in Makefile -configure -aclocal.m4 -autom4te.cache -config.guess -config.h -config.h.in -config.log -config.status -config.ac -configure -config.sub.cdbs-orig -install-sh -INSTALL -libtool -ltmain.sh -missing -mkinstalldirs -ruby_dbus_scripts -stamp-h1 -data/indicator-sound.schemas -data/Makefile.in -data/Makefile -data/indicator-sound.service +Makefile.in +Makefile.in.in .deps .libs -po/stamp-it -po/POTFILES -po/.intltool-merge-cache -po/Makefile.in.in -config.h -config.log -config.sub -src/Makefile -src/Makefile.in -src/libsoundmenu.la -src/indicator-sound-service -src/sound-service-client.h -src/sound-service-server.h -src/sound-service-marshal.c -src/sound-service-marshal.h -src/sound_service_outtakes.txt -src/libsoundmenu_la-indicator-sound.lo -src/libsoundmenu_la-sound-service-marshal.lo -ruby_dbus_scripts/dbus_monitor.rb +*.gschema.valid + +/INSTALL +/aclocal.m4 +/autom4te.cache +/compile +/config.guess +/config.h +/config.h.in +/config.log +/config.status +/config.sub +/configure +/depcomp +/install-sh +/libtool +/ltmain.sh +/missing +/stamp-h1 +/m4/* + +/po/POTFILES +/po/stamp-it + +/data/indicator-sound.service -.anjuta -.anjuta_sym_db.db -TODO.tasks -make_output.txt -swap-over.anjuta -src/fetch-file.c -src/freedesktop-interfaces.c -src/gen-sound-service.xml.c -src/gen-sound-service.xml.h -src/libsoundmenu_la-metadata-widget.lo -src/libsoundmenu_la-title-widget.lo -src/libsoundmenu_la-transport-widget.lo -src/libsoundmenu_la-volume-widget.lo -src/metadata-menu-item.c -src/mpris2-controller.c -src/mpris2-interfaces.c -src/mpris2-watcher.c -src/music-player-bridge.c -src/music-player-bridge.h -src/music_bridge_vala.stamp -src/player-controller.c -src/player-item.c -src/playlists-menu-item.c -src/settings-manager.c -src/title-menu-item.c -src/transport-menu-item.c -modified: -src/indicator-sound.c -data/com.canonical.indicators.sound.gschema.valid -tests/libmockpulse.la -tests/libmockpulse_la-mockpulse.lo -src/libsoundmenu_la-gen-sound-service.xml.lo -src/libsoundmenu_la-mute-widget.lo -src/libsoundmenu_la-sound-state-manager.lo -src/libsoundmenu_la-sound-state.lo -src/libsoundmenu_la-voip-input-widget.lo -src/specific-items-manager.c -src/stamp-marshal +/src/indicator-sound-service +/src/indicator_sound_service_vala.stamp +/src/main.c +/src/media-player-list.c +/src/media-player.c +/src/mpris2-interfaces.c +/src/mpris2-watcher.c +/src/service.c +/src/volume-control.c +/src/freedesktop-interfaces.c diff --git a/Makefile.am b/Makefile.am index 1f64b51..3544dc4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,13 +2,11 @@ SUBDIRS = \ src \ data \ - po + po \ + tests EXTRA_DIST = \ autogen.sh \ - vapi/common-defs.vapi \ vapi/config.vapi -DISTCHECK_CONFIGURE_FLAGS = --enable-localinstall - include $(top_srcdir)/Makefile.am.coverage diff --git a/Makefile.am.marshal b/Makefile.am.marshal deleted file mode 100644 index a6ab024..0000000 --- a/Makefile.am.marshal +++ /dev/null @@ -1,45 +0,0 @@ -# Rules for generating marshal files using glib-genmarshal -# -# Define: -# glib_marshal_list = marshal list file -# glib_marshal_prefix = prefix for marshal functions -# -# before including Makefile.am.marshal. You will also need to have -# the following targets already defined: -# -# CLEANFILES -# DISTCLEANFILES -# BUILT_SOURCES -# EXTRA_DIST -# -# Author: Emmanuele Bassi <ebassi@linux.intel.com> - -marshal_h = $(glib_marshal_list:.list=.h) -marshal_c = $(glib_marshal_list:.list=.c) - -CLEANFILES += stamp-marshal -DISTCLEANFILES += $(marshal_h) $(marshal_c) -BUILT_SOURCES += $(marshal_h) $(marshal_c) -EXTRA_DIST += $(glib_marshal_list) - -stamp-marshal: $(glib_marshal_list) - $(QUIET_GEN)$(GLIB_GENMARSHAL) \ - --prefix=$(glib_marshal_prefix) \ - --header \ - $(srcdir)/$(glib_marshal_list) > xgen-mh \ - && (cmp -s xgen-mh $(marshal_h) || cp -f xgen-mh $(marshal_h)) \ - && rm -f xgen-mh \ - && echo timestamp > $(@F) - -$(marshal_h): stamp-marshal - @true - -$(marshal_c): $(marshal_h) - $(QUIET_GEN)(echo "#include \"$(marshal_h)\"" ; \ - $(GLIB_GENMARSHAL) \ - --prefix=$(glib_marshal_prefix) \ - --body \ - $(srcdir)/$(glib_marshal_list)) > xgen-mc \ - && cp xgen-mc $(marshal_c) \ - && rm -f xgen-mc - diff --git a/configure.ac b/configure.ac index 3a72c5c..5c0be0f 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,4 @@ AC_INIT([indicator-sound],[12.10.1],[conor.curran@canonical.com]) -AC_CONFIG_SRCDIR([src/sound-service.c]) AM_INIT_AUTOMAKE([check-news]) AC_CONFIG_HEADERS([config.h]) @@ -8,8 +7,7 @@ AC_PREREQ(2.53) AM_MAINTAINER_MODE IT_PROG_INTLTOOL([0.35.0]) -AM_PROG_VALAC([0.11.2]) -AS_IF([test -z "$VALAC"], [AC_MSG_ERROR(["No valac compiler found."])]) +AM_PROG_VALAC([0.18]) AC_ISC_POSIX AC_PROG_CC @@ -22,47 +20,20 @@ AC_CONFIG_MACRO_DIR([m4]) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) -AC_PATH_PROG([GLIB_GENMARSHAL], [glib-genmarshal]) - ########################### # Dependencies ########################### -GTK_REQUIRED_VERSION=3.0 -INDICATOR_REQUIRED_VERSION=0.3.19 -DBUSMENUGTK_REQUIRED_VERSION=0.5.90 -POLKIT_REQUIRED_VERSION=0.92 PULSE_AUDIO_REQUIRED_VERSION=0.9.19 -INDICATOR_DISPLAY_OBJECTS=0.1.11 -DBUSMENUGLIB_REQUIRED_VERSION=0.3.101 GIO_2_0_REQUIRED_VERSION=2.25.13 -LIBNOTIFY_REQUIRED_VERSION=0.7.0 PKG_CHECK_MODULES(PULSEAUDIO, libpulse-mainloop-glib >= $PULSE_AUDIO_REQUIRED_VERSION gio-unix-2.0) -AC_SUBST(PULSEAUDIO_CFLAGS) -AC_SUBST(PULSEAUDIO_LIBS) - -PKG_CHECK_MODULES(APPLET, gtk+-3.0 >= $GTK_REQUIRED_VERSION - indicator3-0.4 >= $INDICATOR_REQUIRED_VERSION - dbusmenu-gtk3-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION - libido3-0.1 >= $INDICATOR_DISPLAY_OBJECTS - libnotify >= $LIBNOTIFY_REQUIRED_VERSION) - -PKG_CHECK_MODULES(SOUNDSERVICE, dbusmenu-glib-0.4 >= $DBUSMENUGLIB_REQUIRED_VERSION - indicator3-0.4 - gee-1.0 - gdk-x11-3.0 + +PKG_CHECK_MODULES(SOUNDSERVICE, gee-1.0 gio-unix-2.0 - libbamf3 libxml-2.0) -AC_SUBST(APPLET_CFLAGS) -AC_SUBST(APPLET_LIBS) - -AC_SUBST(SOUNDSERVICE_CFLAGS) -AC_SUBST(SOUNDSERVICE_LIBS) - ########################### # gcov coverage reporting ########################### @@ -77,45 +48,20 @@ AC_SUBST(COVERAGE_CXXFLAGS) AC_SUBST(COVERAGE_LDFLAGS) ########################### -# Check to see if we're local -########################### - -with_localinstall="no" -AC_ARG_ENABLE(localinstall, AS_HELP_STRING([--enable-localinstall], [install all of the files localy instead of system directories (for distcheck)]), with_localinstall=$enableval, with_localinstall=no) - -########################### -# Indicator Info -########################### - -AS_IF([test "x$with_localinstall" = "xyes"], - [ - INDICATORDIR="${libdir}/indicators/2/" - INDICATORICONSDIR="${datadir}/indicator-sound/icons/" - ], - [ - INDICATORDIR=`$PKG_CONFIG --variable=indicatordir indicator3-0.4` - INDICATORICONSDIR=`$PKG_CONFIG --variable=iconsdir indicator3-0.4` - ]) -AC_SUBST(INDICATORDIR) -AC_SUBST(INDICATORICONSDIR) - -########################### # Grab the GSettings Macros ########################### GLIB_GSETTINGS -GLIB_GENMARSHAL ########################### # DBus Service Info ########################### -if test "x$with_localinstall" = "xyes"; then - DBUSSERVICEDIR="${datadir}/dbus-1/services/" -else - DBUSSERVICEDIR=`$PKG_CONFIG --variable=session_bus_services_dir dbus-1` -fi -AC_SUBST(DBUSSERVICEDIR) +AC_ARG_WITH([indicator-dir], + [AS_HELP_STRING([--with-indicator-dir=DIR], [Indicator directory [default=$datadir/unity/indicators]])], + [], + [with_indicator_dir=$datadir/unity/indicators]) +AC_SUBST([INDICATOR_DIR], [$with_indicator_dir]) ############################## # Custom Junk @@ -152,12 +98,8 @@ AC_OUTPUT([ Makefile src/Makefile data/Makefile -data/icons/Makefile -data/icons/16x16/Makefile -data/icons/16x16/status/Makefile -data/icons/scalable/Makefile -data/icons/scalable/status/Makefile po/Makefile.in +tests/Makefile ]) ########################### diff --git a/data/Makefile.am b/data/Makefile.am index 2891606..7647d73 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -1,14 +1,15 @@ -SUBDIRS = icons - gsettings_SCHEMAS = \ com.canonical.indicator.sound.gschema.xml @GSETTINGS_RULES@ -dbus_servicesdir = $(DBUSSERVICEDIR) +dbus_servicesdir = $(datadir)/dbus-1/services dbus_services_DATA = indicator-sound.service %.service: %.service.in - sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ + sed -e "s|\@pkglibexecdir\@|$(pkglibexecdir)|" $< > $@ + +indicatordir = $(INDICATOR_DIR) +dist_indicator_DATA = com.canonical.indicator.sound EXTRA_DIST = \ $(gsettings_SCHEMAS) \ @@ -16,4 +17,4 @@ EXTRA_DIST = \ CLEANFILES = \ $(dbus_services_DATA) -
\ No newline at end of file + diff --git a/data/com.canonical.indicator.sound b/data/com.canonical.indicator.sound new file mode 100644 index 0000000..0831462 --- /dev/null +++ b/data/com.canonical.indicator.sound @@ -0,0 +1,7 @@ +[Indicator Service] +Name=indicator-sound +ObjectPath=/com/canonical/indicator/sound +Position=30 + +[desktop] +ObjectPath=/com/canonical/indicator/sound/desktop diff --git a/data/icons/16x16/Makefile.am b/data/icons/16x16/Makefile.am deleted file mode 100644 index d52da2b..0000000 --- a/data/icons/16x16/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -SUBDIRS = status diff --git a/data/icons/16x16/status/Makefile.am b/data/icons/16x16/status/Makefile.am deleted file mode 100644 index 79da679..0000000 --- a/data/icons/16x16/status/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ - -iconsdir = $(INDICATORICONSDIR)/hicolor/16x16/status - -icons_DATA = \ - sound-icon.png - -EXTRA_DIST = $(icons_DATA) - diff --git a/data/icons/16x16/status/sound-icon.png b/data/icons/16x16/status/sound-icon.png Binary files differdeleted file mode 100644 index 992c6bd..0000000 --- a/data/icons/16x16/status/sound-icon.png +++ /dev/null diff --git a/data/icons/Makefile.am b/data/icons/Makefile.am deleted file mode 100644 index b671b5c..0000000 --- a/data/icons/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -SUBDIRS = scalable 16x16 - -gtk_update_icon_cache = gtk-update-icon-cache -f -t $(pkgdatadir)/icons/hicolor - -install-data-hook: update-icon-cache -uninstall-hook: update-icon-cache -update-icon-cache: - @-if test -z "$(DESTDIR)"; then \ - echo "Updating Gtk icon cache."; \ - $(gtk_update_icon_cache); \ - else \ - echo "*** Icon cache not updated. After (un)install, run this:"; \ - echo "*** $(gtk_update_icon_cache)"; \ - fi - diff --git a/data/icons/scalable/Makefile.am b/data/icons/scalable/Makefile.am deleted file mode 100644 index d52da2b..0000000 --- a/data/icons/scalable/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -SUBDIRS = status diff --git a/data/icons/scalable/status/Makefile.am b/data/icons/scalable/status/Makefile.am deleted file mode 100644 index 4b3b974..0000000 --- a/data/icons/scalable/status/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ - -iconsdir = $(INDICATORICONSDIR)/hicolor/scalable/status - -icons_DATA = \ - sound-icon.svg - -EXTRA_DIST = $(icons_DATA) - diff --git a/data/icons/scalable/status/sound-icon.svg b/data/icons/scalable/status/sound-icon.svg deleted file mode 100644 index a94bb48..0000000 --- a/data/icons/scalable/status/sound-icon.svg +++ /dev/null @@ -1,102 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - version="1.1" - width="16" - height="16" - id="svg3809"> - <defs - id="defs3811"> - <linearGradient - x1="28.739122" - y1="144.11652" - x2="26.256771" - y2="125.39074" - id="linearGradient2974" - xlink:href="#linearGradient2372" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.2545239,0,0,0.12875595,6.0849926,-15.173532)" /> - <linearGradient - id="linearGradient2372"> - <stop - id="stop2374" - style="stop-color:#ffffff;stop-opacity:1" - offset="0" /> - <stop - id="stop2376" - style="stop-color:#ffffff;stop-opacity:0.37931034" - offset="1" /> - </linearGradient> - <linearGradient - x1="28.739122" - y1="144.11652" - x2="25.400293" - y2="119.86452" - id="linearGradient2977" - xlink:href="#linearGradient2372" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.12649532,0,0,0.12875595,2.1139996,-14.056928)" /> - <radialGradient - cx="17.058823" - cy="41.058823" - r="5.7384715" - fx="15.970393" - fy="39.105911" - id="radialGradient2980" - xlink:href="#linearGradient7067-814-120-245" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.3698584,-0.06212313,0,0.35879901,4.6705097,-1.5148309)" /> - <linearGradient - id="linearGradient7067-814-120-245"> - <stop - id="stop3877" - style="stop-color:#aaaaaa;stop-opacity:1" - offset="0" /> - <stop - id="stop3879" - style="stop-color:#4d4d4d;stop-opacity:1" - offset="1" /> - </linearGradient> - <radialGradient - cx="17.058823" - cy="41.058823" - r="5.7384715" - fx="15.544384" - fy="39.027378" - id="radialGradient2983" - xlink:href="#linearGradient7067-814-120-245" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.37667571,-0.06311262,0,0.36451394,-2.446246,-0.69065449)" /> - </defs> - <g - id="layer1"> - <path - d="M 12.887143,11.242639 12.520463,8.2875931" - id="path2931" - style="fill:none;stroke:none" /> - <path - d="M 12.862181,0.50107998 C 10.505078,0.88091513 7.3505507,1.2719259 5,1.6729744 4.3775618,1.9766657 4.5174948,2.758676 4.4899572,3.3260967 c 0,2.5319424 0,5.0638848 0,7.5958273 -1.3117262,-0.246608 -2.9113558,0.837273 -2.9807337,2.553424 -0.1132522,1.068438 0.8342068,1.998453 1.8644819,2.023461 1.844664,0.04478 3.1062853,-1.179076 3.1262946,-2.726857 -0.020145,-2.599408 0.00566,-5.1998384 0,-7.7996448 0.2855763,-0.02115 4.61103,-0.8465037 5,-0.901457 0,1.9471472 0,3.8942945 0,5.8414417 -1.146387,-0.2746364 -2.6118971,0.4787211 -2.9752697,2.0172541 -0.15337,0.862385 0.1364969,1.944831 1.0115464,2.309984 1.7082373,0.784936 4.0532683,-0.805037 3.9579313,-2.671065 -0.02646,-3.4661732 0.02169,-6.933764 0,-10.4003066 -0.04486,-0.32575865 -0.265607,-0.69059252 -0.632027,-0.66707842 z" - id="path4031" - style="fill:#4d4d4d;fill-opacity:1;stroke:#333333;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> - <path - d="m 5.9735639,12.865117 a 1.7166647,2.0994822 57.095252 0 1 -3.9883314,0.66825 1.7166647,2.0994822 57.095252 0 1 3.9883314,-0.66825 z" - id="path2937" - style="fill:url(#radialGradient2983);fill-opacity:1;stroke:none" /> - <path - d="M 12.937933,11.82841 A 1.6885125,2.0629959 56.769744 0 1 9.0217849,12.486184 1.6885125,2.0629959 56.769744 1 1 12.937933,11.82841 z" - id="path2941" - style="fill:url(#radialGradient2980);fill-opacity:1;stroke:none" /> - <path - d="M 5.0536869,11.476373 5,2.7939369 c 0,0 0.05877,-0.6637646 0.4947159,-0.6657879 0.1546126,-0.027048 6.9317151,-1.15654738 6.9317151,-1.15654738 0,0 0.132983,0.70947368 -6.0694897,1.62965478 -0.516931,0.077068 -0.76544,0.068481 -0.7627163,0.5583664 0.00735,1.3216244 -0.030358,3.795953 -0.030358,8.6082552 0,0.03443 -0.3254384,-0.243938 -0.5101806,-0.291505 z" - id="path2945" - style="opacity:0.4;fill:url(#linearGradient2977);fill-opacity:1;fill-rule:evenodd;stroke:none" /> - <path - d="m 12,10.271349 0.03393,-6.5590211 c 0.357493,-0.0323 0.05489,-0.00519 0.53695,-0.053577 0.0066,1.2251582 2.74e-4,2.2420961 2.74e-4,6.8691941 0,0.03443 -0.199425,-0.209029 -0.571151,-0.256596 z" - id="path2947" - style="opacity:0.4;fill:url(#linearGradient2974);fill-opacity:1;fill-rule:evenodd;stroke:none" /> - </g> -</svg> diff --git a/data/indicator-sound.service.in b/data/indicator-sound.service.in index 4cee062..e8b77c6 100644 --- a/data/indicator-sound.service.in +++ b/data/indicator-sound.service.in @@ -1,3 +1,3 @@ [D-BUS Service] Name=com.canonical.indicator.sound -Exec=@libexecdir@/indicator-sound-service +Exec=@pkglibexecdir@/indicator-sound-service diff --git a/debian/control b/debian/control index 4ef0c56..8abcf59 100644 --- a/debian/control +++ b/debian/control @@ -6,23 +6,15 @@ XSBC-Original-Maintainer: Conor Curran <conor.curran@canonical.com> Build-Depends: debhelper (>= 9.0), dh-autoreconf, dh-translations, - quilt, gnome-common, autotools-dev, valac (>= 0.18), - libbamf3-dev, libglib2.0-dev (>= 2.22.3), - libgtk-3-dev, - libdbusmenu-glib-dev (>= 0.5.90), - libdbusmenu-gtk3-dev (>= 0.5.90), - libindicator3-dev (>= 0.3.90), libpulse-dev (>= 0.9.18), libpulse-mainloop-glib0 (>= 0.9.18), - libido3-0.1-dev (>= 0.2.90), libgee-dev, libxml2-dev, - libnotify-dev, -Standards-Version: 3.9.3 +Standards-Version: 3.9.4 Homepage: https://launchpad.net/indicator-sound # If you aren't a member of ~indicator-applet-developers but need to upload # packaging changes, just go ahead. ~indicator-applet-developers will notice diff --git a/debian/patches/series b/debian/patches/series deleted file mode 100644 index 92929c8..0000000 --- a/debian/patches/series +++ /dev/null @@ -1,3 +0,0 @@ -sound_nua.patch -sound_xubuntu.patch -sound_ubuntustudio.patch diff --git a/debian/patches/sound_nua.patch b/debian/patches/sound_nua.patch deleted file mode 100644 index 869ae24..0000000 --- a/debian/patches/sound_nua.patch +++ /dev/null @@ -1,20 +0,0 @@ -=== modified file 'src/sound-service-dbus.c' ---- old/src/sound-service-dbus.c 2012-03-16 17:59:34 +0000 -+++ new/src/sound-service-dbus.c 2012-03-19 14:54:30 +0000 -@@ -227,8 +227,14 @@ - gpointer user_data) - { - GError * error = NULL; -+ gchar* cmd; -+ if (!g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity")) -+ cmd = "gnome-control-center sound-nua"; -+ else -+ cmd = "gnome-control-center sound"; -+ - if (!g_spawn_command_line_async("gnome-volume-control --page=applications", &error) && -- !g_spawn_command_line_async("gnome-control-center sound", &error) && -+ !g_spawn_command_line_async(cmd, &error) && - !g_spawn_command_line_async("xfce4-mixer", &error)) - { - g_warning("Unable to show dialog: %s", error->message); - diff --git a/debian/patches/sound_ubuntustudio.patch b/debian/patches/sound_ubuntustudio.patch deleted file mode 100644 index 23d27de..0000000 --- a/debian/patches/sound_ubuntustudio.patch +++ /dev/null @@ -1,18 +0,0 @@ -Description: Use pavucontrol on Ubuntu Studio by default - Xfce4-mixer uses gstreamer0.10-pulseaudio, which doesn't provide full access - to all audio channels, only to 'Master'. -Author: Lionel Le Folgoc <mrpouit@ubuntu.com> -Author: Janne Jokitalo (astraljava) <astraljava@kapsi.fi> -Last-Update: 2012-04-03 - ---- indicator-sound-0.8.5.0.orig/src/sound-service-dbus.c -+++ indicator-sound-0.8.5.0/src/sound-service-dbus.c -@@ -232,6 +232,8 @@ show_sound_settings_dialog (DbusmenuMenu - cmd = "gnome-control-center sound-nua"; - else if (!g_strcmp0 (g_getenv ("DESKTOP_SESSION"), "xubuntu")) - cmd = "pavucontrol"; -+ else if (!g_strcmp0 (g_getenv ("DESKTOP_SESSION"), "ubuntustudio")) -+ cmd = "pavucontrol"; - else - cmd = "gnome-control-center sound"; - diff --git a/debian/patches/sound_xubuntu.patch b/debian/patches/sound_xubuntu.patch deleted file mode 100644 index bbf3db2..0000000 --- a/debian/patches/sound_xubuntu.patch +++ /dev/null @@ -1,17 +0,0 @@ -Description: Use pavucontrol on Xubuntu by default - Xfce4-mixer uses gstreamer0.10-pulseaudio, which doesn't provide full access - to all audio channels, only to 'Master'. -Author: Lionel Le Folgoc <mrpouit@ubuntu.com> -Last-Update: 2012-03-21 - ---- indicator-sound-0.8.4.1.orig/src/sound-service-dbus.c -+++ indicator-sound-0.8.4.1/src/sound-service-dbus.c -@@ -230,6 +230,8 @@ show_sound_settings_dialog (DbusmenuMenu - gchar* cmd; - if (!g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity")) - cmd = "gnome-control-center sound-nua"; -+ else if (!g_strcmp0 (g_getenv ("DESKTOP_SESSION"), "xubuntu")) -+ cmd = "pavucontrol"; - else - cmd = "gnome-control-center sound"; - diff --git a/debian/rules b/debian/rules index bbe2908..2ce3519 100755 --- a/debian/rules +++ b/debian/rules @@ -3,7 +3,7 @@ export DPKG_GENSYMBOLS_CHECK_LEVEL=4 %: - dh $@ --with translations,autoreconf,quilt + dh $@ --with translations,autoreconf override_dh_autoreconf: NOCONFIGURE=1 dh_autoreconf ./autogen.sh diff --git a/po/POTFILES.in b/po/POTFILES.in index d4c45cb..09797c8 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,6 +1,3 @@ [encoding: UTF-8] -src/indicator-sound.c -src/mute-menu-item.c -src/playlists-menu-item.c -src/sound-service-dbus.c -src/volume-widget.c +src/service.vala +src/service.c diff --git a/src/Makefile.am b/src/Makefile.am index 55df0f6..da3df5b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,173 +1,36 @@ -libexec_PROGRAMS = indicator-sound-service +pkglibexec_PROGRAMS = indicator-sound-service -################### -# Indicator Stuff -################### - -soundmenulibdir = $(INDICATORDIR) -soundmenulib_LTLIBRARIES = libsoundmenu.la -libsoundmenu_la_SOURCES = \ - common-defs.h \ - indicator-sound.h \ - indicator-sound.c \ - sound-state.c \ - sound-state.h \ - sound-state-manager.c \ - sound-state-manager.h \ - transport-widget.c \ - transport-widget.h \ - metadata-widget.c \ - metadata-widget.h \ - mute-widget.c \ - mute-widget.h \ - volume-widget.c \ - volume-widget.h \ - voip-input-widget.c \ - voip-input-widget.h \ - gen-sound-service.xml.h \ - gen-sound-service.xml.c \ - dbus-shared-names.h - -libsoundmenu_la_CFLAGS = \ - $(APPLET_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - -Wall -Werror -DG_LOG_DOMAIN=\"Indicator-Sound\" -libsoundmenu_la_LIBADD = $(APPLET_LIBS) -lm -libsoundmenu_la_LDFLAGS = \ - $(COVERAGE_LDFLAGS) \ - -module -avoid-version - - -checkxml: $(srcdir)/sound-service.xml - @xmllint -valid -noout $< - @echo $< checks out ok - - -#################################################################### -# Sound Service -#################################################################### - -glib_marshal_list = sound-service-marshal.list -glib_marshal_prefix = _sound_service_marshal - - -##################### -# Sound service vala -##################### -music_bridge_VALASOURCES = \ - music-player-bridge.vala \ - transport-menu-item.vala \ - specific-items-manager.vala \ - metadata-menu-item.vala \ - player-controller.vala \ +indicator_sound_service_SOURCES = \ + service.vala \ + main.vala \ + volume-control.vala \ + media-player.vala \ + media-player-list.vala \ mpris2-interfaces.vala \ mpris2-watcher.vala \ - mpris2-controller.vala \ - player-item.vala \ - settings-manager.vala \ - playlists-menu-item.vala \ - freedesktop-interfaces.vala \ - fetch-file.vala \ - player-activator.vala + freedesktop-interfaces.vala -music_bridge_VALAFLAGS = \ +indicator_sound_service_VALAFLAGS = \ --ccode \ - -H music-player-bridge.h -d . \ --vapidir=$(top_srcdir)/vapi/ \ --vapidir=./ \ --thread \ - --pkg gee-1.0 \ - --pkg Dbusmenu-0.4 \ - --pkg common-defs \ --pkg config \ --pkg gio-2.0 \ --pkg gio-unix-2.0 \ - --pkg gdk-3.0 \ - --pkg gdk-x11-3.0 \ - --pkg gdk-pixbuf-2.0 \ - --pkg libbamf3 \ - --pkg libxml-2.0 - - $(MAINTAINER_VALAFLAGS) - -music_bridge_APIFILES = \ - music-player-bridge.h - -music_bridge_vala.stamp $(music_bridge_APIFILES): $(music_bridge_VALASOURCES) - $(AM_V_GEN) $(VALAC) $(music_bridge_VALAFLAGS) $^ - touch music_bridge_vala.stamp - -############################### -# Sound Service C -############################### -indicator_sound_service_SOURCES = \ - common-defs.h \ - sound-service.h \ - sound-service.c \ - sound-state.c \ - sound-state.h \ - pulseaudio-mgr.h \ - pulseaudio-mgr.c \ - device.c \ - device.h \ - sound-service-dbus.h \ - sound-service-dbus.c \ - slider-menu-item.h \ - slider-menu-item.c \ - voip-input-menu-item.h \ - voip-input-menu-item.c \ - mute-menu-item.h \ - mute-menu-item.c \ - gen-sound-service.xml.h \ - gen-sound-service.xml.c \ - sound-service-marshal.c \ - sound-service-marshal.h \ - $(music_bridge_VALASOURCES:.vala=.c) + --pkg libxml-2.0 \ + --pkg libpulse \ + --pkg libpulse-mainloop-glib \ + --target-glib=2.36 +# -w to disable warnings for vala-generated code indicator_sound_service_CFLAGS = $(PULSEAUDIO_CFLAGS) \ $(SOUNDSERVICE_CFLAGS) \ $(GCONF_CFLAGS) \ $(COVERAGE_CFLAGS) \ - -DLIBEXECDIR=\"$(libexecdir)\" -Wall + -DLIBEXECDIR=\"$(libexecdir)\" \ + -w \ + -DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" + indicator_sound_service_LDADD = $(PULSEAUDIO_LIBS) $(SOUNDSERVICE_LIBS) $(GCONF_LIBS) indicator_sound_service_LDFLAGS = $(COVERAGE_LDFLAGS) - -######################### -# Service xml compilation -######################### -DBUS_SPECS = \ - sound-service.xml - -gen-%.xml.h: %.xml - @echo "Building $@ from $<" - @echo "extern const char * _$(subst -,_,$(subst .,_,$(basename $(notdir $<))));" > $@ - -gen-%.xml.c: %.xml - @echo "Building $@ from $<" - @echo "const char * _$(subst -,_,$(subst .,_,$(basename $(notdir $<)))) = " > $@ - @sed -e "s:\":\\\\\":g" -e s:^:\": -e s:\$$:\\\\n\": $< >> $@ - @echo ";" >> $@ - - -EXTRA_DIST = \ - $(DBUS_SPECS) \ - sound-service.xml \ - $(music_bridge_APIFILES) \ - $(music_bridge_VALASOURCES) - -####################### -# Stuff to clean Stuff -####################### -BUILT_SOURCES = \ - music_bridge_vala.stamp \ - $(music_bridge_APIFILES) \ - gen-sound-service.xml.h \ - gen-sound-service.xml.c \ - $(music_bridge_VALASOURCES:.vala=.c) - -CLEANFILES = \ - $(BUILT_SOURCES) - -DISTCLEANFILES = - -include $(top_srcdir)/Makefile.am.marshal diff --git a/src/common-defs.h b/src/common-defs.h deleted file mode 100644 index efca5b2..0000000 --- a/src/common-defs.h +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#ifndef __COMMON_DEFS_H__ -#define __COMMON_DEFS_H__ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -typedef enum { - MUTED, - ZERO_LEVEL, - LOW_LEVEL, - MEDIUM_LEVEL, - HIGH_LEVEL, - BLOCKED, - UNAVAILABLE, - AVAILABLE -}SoundState; - -typedef enum { - TRANSPORT_ACTION_PREVIOUS, - TRANSPORT_ACTION_PLAY_PAUSE, - TRANSPORT_ACTION_NEXT, - TRANSPORT_ACTION_REWIND, - TRANSPORT_ACTION_FORWIND, - TRANSPORT_ACTION_NO_ACTION -}TransportAction; - -typedef enum { - TRANSPORT_STATE_PLAYING, - TRANSPORT_STATE_PAUSED, - TRANSPORT_STATE_LAUNCHING -}TransportState; - -#define NOT_ACTIVE -1 -#define DBUSMENU_PROPERTY_EMPTY -1 - -/* DBUS Custom Items */ -#define DBUSMENU_VOLUME_MENUITEM_TYPE "x-canonical-ido-volume-type" -#define DBUSMENU_VOLUME_MENUITEM_LEVEL "x-canonical-ido-volume-level" -#define DBUSMENU_VOLUME_MENUITEM_MUTE "x-canonical-ido-volume-mute" - -#define DBUSMENU_VOIP_INPUT_MENUITEM_TYPE "x-canonical-ido-voip-input-type" -#define DBUSMENU_VOIP_INPUT_MENUITEM_LEVEL "x-canonical-ido-voip-input-level" -#define DBUSMENU_VOIP_INPUT_MENUITEM_MUTE "x-canonical-ido-voip-input-mute" - -#define DBUSMENU_MUTE_MENUITEM_TYPE "x-canonical-sound-menu-mute-type" -#define DBUSMENU_MUTE_MENUITEM_VALUE "x-canonical-sound-menu-mute-value" - -#define DBUSMENU_TRANSPORT_MENUITEM_TYPE "x-canonical-sound-menu-player-transport-type" -#define DBUSMENU_TRANSPORT_MENUITEM_PLAY_STATE "x-canonical-sound-menu-player-transport-state" -#define DBUSMENU_TRANSPORT_MENUITEM_STATE_CHANGE "Transport state change" - -#define DBUSMENU_TRACK_SPECIFIC_MENUITEM_TYPE "x-canonical-sound-menu-player-track-specific-type" - -#define DBUSMENU_METADATA_MENUITEM_TYPE "x-canonical-sound-menu-player-metadata-type" -#define DBUSMENU_METADATA_MENUITEM_ARTIST "x-canonical-sound-menu-player-metadata-xesam:artist" -#define DBUSMENU_METADATA_MENUITEM_TITLE "x-canonical-sound-menu-player-metadata-xesam:title" -#define DBUSMENU_METADATA_MENUITEM_ALBUM "x-canonical-sound-menu-player-metadata-xesam:album" -#define DBUSMENU_METADATA_MENUITEM_ARTURL "x-canonical-sound-menu-player-metadata-mpris:artUrl" -#define DBUSMENU_METADATA_MENUITEM_PLAYER_NAME "x-canonical-sound-menu-player-metadata-player-name" -#define DBUSMENU_METADATA_MENUITEM_PLAYER_ICON "x-canonical-sound-menu-player-metadata-player-icon" -#define DBUSMENU_METADATA_MENUITEM_PLAYER_RUNNING "x-canonical-sound-menu-player-metadata-player-running" -#define DBUSMENU_METADATA_MENUITEM_HIDE_TRACK_DETAILS "x-canonical-sound-menu-player-metadata-hide-track-details" - -#define DBUSMENU_SCRUB_MENUITEM_TYPE "x-canonical-sound-menu-player-scrub-type" -#define DBUSMENU_SCRUB_MENUITEM_DURATION "x-canonical-sound-menu-player-scrub-mpris:length" -#define DBUSMENU_SCRUB_MENUITEM_POSITION "x-canonical-sound-menu-player-scrub-position" -#define DBUSMENU_SCRUB_MENUITEM_PLAY_STATE "x-canonical-sound-menu-player-scrub-play-state" - -#define DBUSMENU_PLAYLISTS_MENUITEM_TYPE "x-canonical-sound-menu-player-playlists-type" -#define DBUSMENU_PLAYLISTS_MENUITEM_TITLE "x-canonical-sound-menu-player-playlists-title" -#define DBUSMENU_PLAYLISTS_MENUITEM_PLAYLISTS "x-canonical-sound-menu-player-playlists-playlists" - -#define DBUSMENU_PLAYLIST_MENUITEM_PATH "x-canonical-sound-menu-player-playlist-path" - -#endif diff --git a/src/dbus-shared-names.h b/src/dbus-shared-names.h deleted file mode 100644 index 2517eb9..0000000 --- a/src/dbus-shared-names.h +++ /dev/null @@ -1,37 +0,0 @@ -/* -A small wrapper utility to load indicators and put them as menu items -into the gnome-panel using it's applet interface. - -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - Ted Gould <ted@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - - -#ifndef __DBUS_SHARED_NAMES_H__ -#define __DBUS_SHARED_NAMES_H__ - -#define INDICATOR_SOUND_DBUS_NAME "com.canonical.indicator.sound" -#define INDICATOR_SOUND_MENU_DBUS_OBJECT_PATH "/com/canonical/indicator/sound/menu" -#define INDICATOR_SOUND_SERVICE_DBUS_OBJECT_PATH "/com/canonical/indicator/sound/service" -#define INDICATOR_SOUND_DBUS_INTERFACE "com.canonical.indicator.sound" -#define INDICATOR_SOUND_DBUS_VERSION 0 - -#define INDICATOR_SOUND_SIGNAL_STATE_UPDATE "SoundStateUpdate" - - -#endif /* __DBUS_SHARED_NAMES_H__ */ diff --git a/src/device.c b/src/device.c deleted file mode 100644 index 84db596..0000000 --- a/src/device.c +++ /dev/null @@ -1,276 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#include <libdbusmenu-glib/menuitem.h> - -#include "device.h" -#include "slider-menu-item.h" -#include "mute-menu-item.h" -#include "voip-input-menu-item.h" -#include "pulseaudio-mgr.h" -#include "sound-state.h" - -typedef struct _DevicePrivate DevicePrivate; - -struct _DevicePrivate -{ - SliderMenuItem* volume_slider_menuitem; - MuteMenuItem* mute_menuitem; - VoipInputMenuItem* voip_input_menu_item; - SoundState current_sound_state; - SoundServiceDbus* service; -}; - -#define DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DEVICE_TYPE, DevicePrivate)) - -/* Prototypes */ -static void device_class_init (DeviceClass *klass); -static void device_init (Device *self); -static void device_dispose (GObject *object); -static void device_finalize (GObject *object); - -static SoundState device_get_state_from_volume (Device* self); -static void device_mute_update (Device* self, gboolean muted); - -G_DEFINE_TYPE (Device, device, G_TYPE_OBJECT); - -static void -device_class_init (DeviceClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (DevicePrivate)); - - gobject_class->dispose = device_dispose; - gobject_class->finalize = device_finalize; -} - -static void -device_init (Device *self) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE (self); - priv->mute_menuitem = NULL; - priv->volume_slider_menuitem = NULL; - priv->voip_input_menu_item = NULL; - priv->current_sound_state = UNAVAILABLE; - priv->service = NULL; - - // Init our menu items. - priv->mute_menuitem = g_object_new (MUTE_MENU_ITEM_TYPE, NULL); - priv->voip_input_menu_item = g_object_new (VOIP_INPUT_MENU_ITEM_TYPE, NULL);; - priv->volume_slider_menuitem = slider_menu_item_new (self); - mute_menu_item_enable (priv->mute_menuitem, FALSE); - slider_menu_item_enable (priv->volume_slider_menuitem, FALSE); -} - -static void -device_dispose (GObject *object) -{ - G_OBJECT_CLASS (device_parent_class)->dispose (object); -} - -static void -device_finalize (GObject *object) -{ - G_OBJECT_CLASS (device_parent_class)->finalize (object); -} - -void -device_sink_populate (Device* self, - const pa_sink_info* update) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE(self); - mute_menu_item_enable (priv->mute_menuitem, TRUE); - slider_menu_item_populate (priv->volume_slider_menuitem, update); - SoundState state = device_get_state_from_volume (self); - if (priv->current_sound_state != state){ - priv->current_sound_state = state; - sound_service_dbus_update_sound_state (priv->service, - priv->current_sound_state); - } - device_mute_update (self, update->mute); -} - -void -device_sink_update (Device* self, - const pa_sink_info* update) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE (self); - slider_menu_item_update (priv->volume_slider_menuitem, update); - - SoundState state = device_get_state_from_volume (self); - if (priv->current_sound_state != state){ - priv->current_sound_state = state; - sound_service_dbus_update_sound_state (priv->service, - priv->current_sound_state); - } - - device_mute_update (self, update->mute); -} - -gint -device_get_voip_source_output_index (Device* self) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE (self); - return voip_input_menu_item_get_source_output_index (priv->voip_input_menu_item); -} - -static void -device_mute_update (Device* self, gboolean muted) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE (self); - mute_menu_item_update (priv->mute_menuitem, muted); - SoundState state = device_get_state_from_volume (self); - - if (muted == TRUE){ - state = MUTED; - } - // Only send signals if something has changed - if (priv->current_sound_state != state){ - priv->current_sound_state = state; - sound_service_dbus_update_sound_state (priv->service, state); - } -} - -void -device_ensure_sink_is_unmuted (Device* self) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE (self); - if (mute_menu_item_is_muted (priv->mute_menuitem)){ - pm_update_mute (FALSE); - } -} - - -static SoundState -device_get_state_from_volume (Device* self) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE (self); - GVariant* v = dbusmenu_menuitem_property_get_variant (DBUSMENU_MENUITEM(priv->volume_slider_menuitem), - DBUSMENU_VOLUME_MENUITEM_LEVEL); - gdouble volume_percent = g_variant_get_double (v); - - return sound_state_get_from_volume ((int)volume_percent); -} - -void -device_determine_blocking_state (Device* self) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE (self); - if (mute_menu_item_is_muted (priv->mute_menuitem)){ - /** - We don't want to set the current state to blocking - as this is a fire and forget event. - */ - sound_service_dbus_update_sound_state (priv->service, - BLOCKED); - } -} - -gint -device_get_sink_index (Device* self) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE (self); - return slider_menu_item_get_sink_index (priv->volume_slider_menuitem); -} - -gboolean -device_is_sink_populated (Device* self) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE (self); - return dbusmenu_menuitem_property_get_bool (DBUSMENU_MENUITEM (priv->volume_slider_menuitem), - DBUSMENU_MENUITEM_PROP_ENABLED); -} - -void -device_activate_voip_item (Device* self, gint source_output_index, gint client_index) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE (self); - if (voip_input_menu_item_is_interested (priv->voip_input_menu_item, - source_output_index, - client_index)){ - voip_input_menu_item_enable (priv->voip_input_menu_item, TRUE); - } -} - -void -device_deactivate_voip_source (Device* self, gboolean visible) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE (self); - visible &= voip_input_menu_item_is_active (priv->voip_input_menu_item); - voip_input_menu_item_deactivate_source (priv->voip_input_menu_item, visible); -} - -void -device_deactivate_voip_client (Device* self) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE (self); - voip_input_menu_item_deactivate_voip_client (priv->voip_input_menu_item); -} - -void -device_sink_deactivated (Device* self) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE (self); - priv->current_sound_state = UNAVAILABLE; - sound_service_dbus_update_sound_state (priv->service, - priv->current_sound_state); - mute_menu_item_enable (priv->mute_menuitem, FALSE); - slider_menu_item_enable (priv->volume_slider_menuitem, FALSE); -} - -SoundState -device_get_state (Device* self) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE (self); - return priv->current_sound_state; -} - -void -device_update_voip_input_source (Device* self, const pa_source_info* update) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE (self); - voip_input_menu_item_update (priv->voip_input_menu_item, update); -} - -gboolean -device_is_voip_source_populated (Device* self) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE (self); - return voip_input_menu_item_is_populated (priv->voip_input_menu_item); -} - -gint device_get_source_index (Device* self) -{ - DevicePrivate* priv = DEVICE_GET_PRIVATE (self); - return voip_input_menu_item_get_index (priv->voip_input_menu_item); -} - -Device* -device_new (SoundServiceDbus* service) -{ - Device* sink = g_object_new (DEVICE_TYPE, NULL); - DevicePrivate* priv = DEVICE_GET_PRIVATE (sink); - priv->service = service; - sound_service_dbus_build_sound_menu (service, - mute_menu_item_get_button (priv->mute_menuitem), - DBUSMENU_MENUITEM (priv->volume_slider_menuitem), - DBUSMENU_MENUITEM (priv->voip_input_menu_item)); - pm_establish_pulse_connection (sink); - return sink; -} diff --git a/src/device.h b/src/device.h deleted file mode 100644 index ccaf4ea..0000000 --- a/src/device.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2010 Canonical Ltd. - * - * Authors: - * Conor Curran <conor.curran@canonical.com> - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __DEVICE_H__ -#define __DEVICE_H__ - -#include <glib.h> -#include <glib-object.h> - -#include "common-defs.h" -#include "sound-service-dbus.h" - -#include <pulse/pulseaudio.h> - -G_BEGIN_DECLS - -#define DEVICE_TYPE (device_get_type ()) -#define DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DEVICE_TYPE, Device)) -#define DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), DEVICE_TYPE, DeviceClass)) -#define IS_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DEVICE_TYPE)) -#define IS_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DEVICE_TYPE)) -#define DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DEVICE_TYPE, DeviceClass)) - -typedef struct _Device Device; -typedef struct _DeviceClass DeviceClass; - -struct _Device { - GObject parent; -}; - -struct _DeviceClass { - GObjectClass parent_class; -}; - -GType device_get_type (void) G_GNUC_CONST; - -/** - * TODO - * Refactor this to become a device manager obj basically acting as wrapper for - * the communication between pulseaudio-mgr and the individual items. - * First steps collapse slider/volume related stuff into slider-menu-item. - */ - -// Sink related -void device_sink_populate (Device* sink, const pa_sink_info* update); -void device_sink_update (Device* sink, const pa_sink_info* update); -gboolean device_is_sink_populated (Device* sink); -gint device_get_sink_index (Device* self); -void device_sink_deactivated (Device* self); -void device_update_mute (Device* self, gboolean mute_update); -void device_ensure_sink_is_unmuted (Device* self); - -// source and sinkinput/client related for VOIP functionality -void device_update_voip_input_source (Device* sink, const pa_source_info* update); -void device_activate_voip_item (Device* sink, gint source_output_index, gint client_index); -gint device_get_voip_source_output_index (Device* sink); -gboolean device_is_voip_source_populated (Device* sink); -gint device_get_source_index (Device* self); -void device_determine_blocking_state (Device* self); -void device_deactivate_voip_source (Device* self, gboolean visible); -void device_deactivate_voip_client (Device* self); -SoundState device_get_state (Device* self); - -Device* device_new (SoundServiceDbus* service); - -G_END_DECLS - -#endif diff --git a/src/fetch-file.vala b/src/fetch-file.vala deleted file mode 100644 index e94afef..0000000 --- a/src/fetch-file.vala +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2010 Canonical, Ltd. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License - * version 3.0 as published by the Free Software Foundation. - * - * 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 Lesser General Public License version 3.0 for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * <http://www.gnu.org/licenses/>. - * - * Authors - * Gordon Allott <gord.allott@canonical.com> - * Conor Curran <conor.curran@canonical.com> - */ - -public class FetchFile : Object -{ - /* public variables */ - public string uri {get; construct;} - public string intended_property {get; construct;} - - /* private variables */ - private DataInputStream stream; - private File? file; - private ByteArray data; - - /* public signals */ - public signal void failed (); - public signal void completed (ByteArray data, string property); - - public FetchFile (string uri, string prop) - { - Object (uri: uri, intended_property: prop); - } - - construct - { - this.file = File.new_for_uri(this.uri); - this.data = new ByteArray (); - } - - public async void fetch_data () - { - try { - this.stream = new DataInputStream(this.file.read(null)); - this.stream.set_byte_order (DataStreamByteOrder.LITTLE_ENDIAN); - } catch (GLib.Error e) { - this.failed (); - } - this.read_something_async (); - } - - private async void read_something_async () - { - ssize_t size = 1024; - uint8[] buffer = new uint8[size]; - - ssize_t bufsize = 1; - do { - try { - bufsize = yield this.stream.read_async (buffer, GLib.Priority.DEFAULT, null); - if (bufsize < 1) { break;} - - if (bufsize != size) - { - uint8[] cpybuf = new uint8[bufsize]; - Memory.copy (cpybuf, buffer, bufsize); - this.data.append (cpybuf); - } - else - { - this.data.append (buffer); - } - } catch (Error e) { - this.failed (); - } - } while (bufsize > 0); - this.completed (this.data, this.intended_property); - } -} diff --git a/src/indicator-sound.c b/src/indicator-sound.c deleted file mode 100644 index d21d722..0000000 --- a/src/indicator-sound.c +++ /dev/null @@ -1,834 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "config.h" - -#include <math.h> -#include <glib.h> -#include <glib-object.h> -#include <glib/gi18n-lib.h> -#include <gtk/gtk.h> -#include <gdk/gdkkeysyms.h> -#include <libdbusmenu-gtk/menu.h> -#include <libido/idoscalemenuitem.h> - -#include <gio/gio.h> - -#include "indicator-sound.h" -#include "transport-widget.h" -#include "metadata-widget.h" -#include "volume-widget.h" -#include "voip-input-widget.h" -#include "dbus-shared-names.h" -#include "sound-state-manager.h" -#include "mute-widget.h" - -#include "gen-sound-service.xml.h" -#include "common-defs.h" - -typedef struct _IndicatorSoundPrivate IndicatorSoundPrivate; - -struct _IndicatorSoundPrivate -{ - GtkWidget* volume_widget; - GtkWidget* voip_widget; - MuteWidget *mute_widget; - GList* transport_widgets_list; - GDBusProxy *dbus_proxy; - SoundStateManager* state_manager; - gchar *accessible_desc; - GSettings *settings; -}; - -#define INDICATOR_SOUND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_SOUND_TYPE, IndicatorSoundPrivate)) - -#define SOUND_INDICATOR_GSETTINGS_SCHEMA_ID "com.canonical.indicator.sound" - -// GObject Boiler plate -INDICATOR_SET_VERSION -INDICATOR_SET_TYPE(INDICATOR_SOUND_TYPE) - -// GObject Boiler plate -static void indicator_sound_class_init (IndicatorSoundClass *klass); -static void indicator_sound_init (IndicatorSound *self); -static void indicator_sound_dispose (GObject *object); -static void indicator_sound_finalize (GObject *object); -G_DEFINE_TYPE (IndicatorSound, indicator_sound, INDICATOR_OBJECT_TYPE); - -//GTK+ items -static GtkLabel * get_label (IndicatorObject * io); -static GtkImage * get_icon (IndicatorObject * io); -static GtkMenu * get_menu (IndicatorObject * io); -static const gchar * get_accessible_desc (IndicatorObject * io); -static const gchar * get_name_hint (IndicatorObject * io); -static void indicator_sound_scroll (IndicatorObject * io, - IndicatorObjectEntry * entry, gint delta, - IndicatorScrollDirection direction); -static void indicator_sound_middle_click (IndicatorObject * io, - IndicatorObjectEntry * entry, - guint time, gpointer data); - -//key/moust event handlers -static gboolean key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data); -static gboolean key_release_cb(GtkWidget* widget, GdkEventKey* event, gpointer data); - -//custom widget realisation methods -static gboolean new_volume_slider_widget (DbusmenuMenuitem * newitem, - DbusmenuMenuitem * parent, - DbusmenuClient * client, - gpointer user_data); -static gboolean new_voip_slider_widget (DbusmenuMenuitem * newitem, - DbusmenuMenuitem * parent, - DbusmenuClient * client, - gpointer user_data); -static gboolean new_transport_widget (DbusmenuMenuitem * newitem, - DbusmenuMenuitem * parent, - DbusmenuClient * client, - gpointer user_data); -static gboolean new_metadata_widget (DbusmenuMenuitem * newitem, - DbusmenuMenuitem * parent, - DbusmenuClient * client, - gpointer user_data); -static gboolean new_mute_widget (DbusmenuMenuitem * newitem, - DbusmenuMenuitem * parent, - DbusmenuClient * client, - gpointer user_data); - -// DBUS communication -static GDBusNodeInfo *node_info = NULL; -static GDBusInterfaceInfo *interface_info = NULL; -static void create_connection_to_service (GObject *source_object, - GAsyncResult *res, - gpointer user_data); -static void connection_changed (IndicatorServiceManager * sm, - gboolean connected, - gpointer userdata); - -// Visiblity -static void settings_init (IndicatorSound * self); - - -static void -indicator_sound_class_init (IndicatorSoundClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = indicator_sound_dispose; - object_class->finalize = indicator_sound_finalize; - - IndicatorObjectClass *io_class = INDICATOR_OBJECT_CLASS(klass); - - g_type_class_add_private (klass, sizeof (IndicatorSoundPrivate)); - - io_class->get_label = get_label; - io_class->get_image = get_icon; - io_class->get_menu = get_menu; - io_class->get_accessible_desc = get_accessible_desc; - io_class->get_name_hint = get_name_hint; - io_class->entry_scrolled = indicator_sound_scroll; - io_class->secondary_activate = indicator_sound_middle_click; -} - -static void -indicator_sound_init (IndicatorSound *self) -{ - self->service = NULL; - self->service = indicator_service_manager_new_version(INDICATOR_SOUND_DBUS_NAME, - INDICATOR_SOUND_DBUS_VERSION); - - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self); - priv->volume_widget = NULL; - priv->voip_widget = NULL; - priv->mute_widget = NULL; - priv->dbus_proxy = NULL; - GList* t_list = NULL; - priv->transport_widgets_list = t_list; - priv->state_manager = g_object_new (SOUND_TYPE_STATE_MANAGER, NULL); - priv->accessible_desc = NULL; - priv->settings = NULL; - - settings_init (self); - - g_signal_connect ( G_OBJECT(self->service), - INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, - G_CALLBACK(connection_changed), self ); -} - -static void -indicator_sound_dispose (GObject *object) -{ - IndicatorSound * self = INDICATOR_SOUND(object); - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self); - - if (priv->settings != NULL) { - g_object_unref (G_OBJECT(priv->settings)); - priv->settings = NULL; - } - - if (self->service != NULL) { - g_object_unref(G_OBJECT(self->service)); - self->service = NULL; - } - g_list_free (priv->transport_widgets_list); - - G_OBJECT_CLASS (indicator_sound_parent_class)->dispose (object); -} - -static void -indicator_sound_finalize (GObject *object) -{ - IndicatorSound * self = INDICATOR_SOUND(object); - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self); - - if (priv->accessible_desc) { - g_free (priv->accessible_desc); - priv->accessible_desc = NULL; - } - - G_OBJECT_CLASS (indicator_sound_parent_class)->finalize (object); -} - -static GtkLabel * -get_label (IndicatorObject * io) -{ - return NULL; -} - -static GtkImage * -get_icon (IndicatorObject * io) -{ - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io)); - gtk_widget_show( GTK_WIDGET(sound_state_manager_get_current_icon (priv->state_manager)) ); - return sound_state_manager_get_current_icon (priv->state_manager); -} - -/* Indicator based function to get the menu for the whole - applet. This starts up asking for the parts of the menu - from the various services. */ -static GtkMenu * -get_menu (IndicatorObject * io) -{ - DbusmenuGtkMenu* menu = dbusmenu_gtkmenu_new(INDICATOR_SOUND_DBUS_NAME, - INDICATOR_SOUND_MENU_DBUS_OBJECT_PATH); - - DbusmenuGtkClient *client = dbusmenu_gtkmenu_get_client(menu); - g_object_set_data (G_OBJECT (client), "indicator", io); - dbusmenu_client_add_type_handler (DBUSMENU_CLIENT(client), - DBUSMENU_VOLUME_MENUITEM_TYPE, - new_volume_slider_widget); - dbusmenu_client_add_type_handler (DBUSMENU_CLIENT(client), - DBUSMENU_VOIP_INPUT_MENUITEM_TYPE, - new_voip_slider_widget); - dbusmenu_client_add_type_handler (DBUSMENU_CLIENT(client), - DBUSMENU_TRANSPORT_MENUITEM_TYPE, - new_transport_widget); - dbusmenu_client_add_type_handler (DBUSMENU_CLIENT(client), - DBUSMENU_METADATA_MENUITEM_TYPE, - new_metadata_widget); - dbusmenu_client_add_type_handler (DBUSMENU_CLIENT(client), - DBUSMENU_MUTE_MENUITEM_TYPE, - new_mute_widget); - // Note: Not ideal but all key handling needs to be managed here and then - // delegated to the appropriate widget. - g_signal_connect (menu, "key-press-event", G_CALLBACK(key_press_cb), io); - g_signal_connect (menu, "key-release-event", G_CALLBACK(key_release_cb), io); - - return GTK_MENU(menu); -} - -static const gchar * -get_accessible_desc (IndicatorObject * io) -{ - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(io); - return priv->accessible_desc; -} - -static const gchar *get_name_hint (IndicatorObject * io) -{ - return PACKAGE_NAME; -} - -static void -connection_changed (IndicatorServiceManager * sm, - gboolean connected, - gpointer user_data) -{ - IndicatorSound* indicator = INDICATOR_SOUND(user_data); - g_return_if_fail ( IS_INDICATOR_SOUND (indicator) ); - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE (indicator); - GError *error = NULL; - - if (connected == FALSE){ - sound_state_manager_deal_with_disconnect (priv->state_manager); - return; - //TODO: Gracefully handle disconnection - // do a timeout to wait for reconnection - // for 5 seconds and then if no connection message - // is received put the state at 'sink not available' - } - // If the proxy is not null and connected is true => its a reconnect, - // we don't need to anything, gdbus takes care of the rest - bless. - // just fetch the state. - if (priv->dbus_proxy != NULL){ - g_dbus_proxy_call ( priv->dbus_proxy, - "GetSoundState", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - (GAsyncReadyCallback)sound_state_manager_get_state_cb, - priv->state_manager); - return; - } - - if ( node_info == NULL ){ - node_info = g_dbus_node_info_new_for_xml ( _sound_service, - &error ); - if (error != NULL) { - g_critical ( "Failed to get create interface info from xml: %s", - error->message ); - g_error_free(error); - return; - } - } - - if (interface_info == NULL) { - interface_info = g_dbus_node_info_lookup_interface (node_info, - INDICATOR_SOUND_DBUS_INTERFACE); - if (interface_info == NULL) { - g_critical ("Unable to find interface '" INDICATOR_SOUND_DBUS_INTERFACE "'"); - } - } - - g_dbus_proxy_new_for_bus( G_BUS_TYPE_SESSION, - G_DBUS_PROXY_FLAGS_NONE, - interface_info, - INDICATOR_SOUND_DBUS_NAME, - INDICATOR_SOUND_SERVICE_DBUS_OBJECT_PATH, - INDICATOR_SOUND_DBUS_INTERFACE, - NULL, - create_connection_to_service, - indicator ); -} - -static void create_connection_to_service (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - IndicatorSound *self = INDICATOR_SOUND(user_data); - GError *error = NULL; - - g_return_if_fail( IS_INDICATOR_SOUND(self) ); - - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self); - - priv->dbus_proxy = g_dbus_proxy_new_finish(res, &error); - - if (error != NULL) { - g_critical ("Failed to get dbus proxy: %s", error->message); - g_error_free(error); - return; - } - sound_state_manager_connect_to_dbus (priv->state_manager, - priv->dbus_proxy); - -} - -static gboolean -new_transport_widget (DbusmenuMenuitem * newitem, - DbusmenuMenuitem * parent, - DbusmenuClient * client, - gpointer user_data) -{ - g_debug("indicator-sound: new_transport_bar() called "); - - GtkWidget* bar = NULL; - IndicatorObject *io = NULL; - - g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); - g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); - - bar = transport_widget_new(newitem); - io = g_object_get_data (G_OBJECT (client), "indicator"); - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io)); - priv->transport_widgets_list = g_list_append ( priv->transport_widgets_list, bar ); - - GtkMenuItem *menu_transport_bar = GTK_MENU_ITEM(bar); - - gtk_widget_show_all(bar); - dbusmenu_gtkclient_newitem_base (DBUSMENU_GTKCLIENT(client), - newitem, - menu_transport_bar, - parent); - return TRUE; -} - -static gboolean -new_metadata_widget (DbusmenuMenuitem * newitem, - DbusmenuMenuitem * parent, - DbusmenuClient * client, - gpointer user_data) -{ - g_debug("indicator-sound: new_metadata_widget"); - - GtkWidget* metadata = NULL; - - g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); - g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); - - - metadata = metadata_widget_new (newitem); - - g_debug ("%s (\"%s\")", __func__, - dbusmenu_menuitem_property_get(newitem, DBUSMENU_METADATA_MENUITEM_PLAYER_NAME)); - - GtkMenuItem *menu_metadata_widget = GTK_MENU_ITEM(metadata); - - gtk_widget_show_all(metadata); - dbusmenu_gtkclient_newitem_base (DBUSMENU_GTKCLIENT(client), - newitem, - menu_metadata_widget, - parent); - return TRUE; -} - -static gboolean -new_volume_slider_widget(DbusmenuMenuitem * newitem, - DbusmenuMenuitem * parent, - DbusmenuClient * client, - gpointer user_data) -{ - g_debug("indicator-sound: new_volume_slider_widget"); - - GtkWidget* volume_widget = NULL; - IndicatorObject *io = NULL; - - g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); - g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); - - io = g_object_get_data (G_OBJECT (client), "indicator"); - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io)); - - if (priv->volume_widget != NULL){ - volume_widget_tidy_up (priv->volume_widget); - gtk_widget_destroy (priv->volume_widget); - priv->volume_widget = NULL; - } - volume_widget = volume_widget_new (newitem, io); - priv->volume_widget = volume_widget; - // Don't forget to set the accessible desc. - update_accessible_desc (io); - - - GtkWidget* ido_slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget)); - - gtk_widget_show_all(ido_slider_widget); - // register the style callback on this widget with state manager's style change - // handler (needs to remake the blocking animation for each style). - g_signal_connect (ido_slider_widget, "style-set", - G_CALLBACK(sound_state_manager_style_changed_cb), - priv->state_manager); - - GtkMenuItem *menu_volume_item = GTK_MENU_ITEM(ido_slider_widget); - dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), - newitem, - menu_volume_item, - parent); - return TRUE; -} -/** - * new_voip_slider_widget - * Create the voip menu item widget, must of the time this widget will be hidden. - * @param newitem - * @param parent - * @param client - * @param user_data - * @return - */ -static gboolean -new_voip_slider_widget (DbusmenuMenuitem * newitem, - DbusmenuMenuitem * parent, - DbusmenuClient * client, - gpointer user_data) -{ - g_debug("indicator-sound: new_voip_slider_widget"); - GtkWidget* voip_widget = NULL; - IndicatorObject *io = NULL; - - g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); - g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); - - io = g_object_get_data (G_OBJECT (client), "indicator"); - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io)); - - if (priv->voip_widget != NULL){ - voip_input_widget_tidy_up (priv->voip_widget); - gtk_widget_destroy (priv->voip_widget); - priv->voip_widget = NULL; - } - - voip_widget = voip_input_widget_new (newitem); - priv->voip_widget = voip_widget; - - GtkWidget* ido_slider_widget = voip_input_widget_get_ido_slider(VOIP_INPUT_WIDGET(voip_widget)); - - gtk_widget_show_all(ido_slider_widget); - - GtkMenuItem *menu_volume_item = GTK_MENU_ITEM(ido_slider_widget); - dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), - newitem, - menu_volume_item, - parent); - return TRUE; -} - -static gboolean -new_mute_widget(DbusmenuMenuitem * newitem, - DbusmenuMenuitem * parent, - DbusmenuClient * client, - gpointer user_data) -{ - IndicatorObject *io = NULL; - - g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); - g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); - - io = g_object_get_data (G_OBJECT (client), "indicator"); - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io)); - - if (priv->mute_widget != NULL){ - g_object_unref (priv->mute_widget); - priv->mute_widget = NULL; - } - - priv->mute_widget = mute_widget_new(newitem); - GtkMenuItem *item = mute_widget_get_menu_item (priv->mute_widget); - - dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), - newitem, - item, - parent); - - return TRUE; -} - -/*******************************************************************/ -//UI callbacks -/******************************************************************/ - -static GtkWidget * -get_current_item (GtkContainer * container) -{ - GList *children = gtk_container_get_children (container); - GList *iter; - GtkWidget *rv = NULL; - - /* Suprisingly, GTK+ doesn't really let us query "what is the currently - selected item?". But it does note it internally by prelighting the - widget, so we watch for that. */ - for (iter = children; iter; iter = iter->next) { - if (gtk_widget_get_state (GTK_WIDGET (iter->data)) & GTK_STATE_PRELIGHT) { - rv = GTK_WIDGET (iter->data); - break; - } - } - - return rv; -} - -/** -key_press_cb: -**/ -static gboolean -key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data) -{ - gboolean digested = FALSE; - - g_return_val_if_fail(IS_INDICATOR_SOUND(data), FALSE); - - IndicatorSound *indicator = INDICATOR_SOUND (data); - - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(indicator); - GtkWidget *menuitem; - menuitem = get_current_item (GTK_CONTAINER (widget)); - - if (IDO_IS_SCALE_MENU_ITEM(menuitem) == TRUE){ - gdouble current_value = 0; - gdouble new_value = 0; - const gdouble five_percent = 5; - gboolean is_voip_slider = FALSE; - - if (g_ascii_strcasecmp (ido_scale_menu_item_get_primary_label (IDO_SCALE_MENU_ITEM(menuitem)), "VOLUME") == 0) { - g_debug ("vOLUME SLIDER KEY PRESS"); - GtkWidget* slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget)); - GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)slider_widget); - GtkRange* range = (GtkRange*)slider; - g_return_val_if_fail(GTK_IS_RANGE(range), FALSE); - current_value = gtk_range_get_value(range); - new_value = current_value; - } - else if (g_ascii_strcasecmp (ido_scale_menu_item_get_primary_label (IDO_SCALE_MENU_ITEM(menuitem)), "VOIP") == 0) { - g_debug ("VOIP SLIDER KEY PRESS"); - GtkWidget* slider_widget = voip_input_widget_get_ido_slider(VOIP_INPUT_WIDGET(priv->voip_widget)); - GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)slider_widget); - GtkRange* range = (GtkRange*)slider; - g_return_val_if_fail(GTK_IS_RANGE(range), FALSE); - current_value = gtk_range_get_value(range); - new_value = current_value; - is_voip_slider = TRUE; - } - - switch (event->keyval) { - case GDK_KEY_Right: - digested = TRUE; - new_value = current_value + five_percent; - break; - case GDK_KEY_Left: - digested = TRUE; - new_value = current_value - five_percent; - break; - case GDK_KEY_plus: - digested = TRUE; - new_value = current_value + five_percent; - break; - case GDK_KEY_minus: - digested = TRUE; - new_value = current_value - five_percent; - break; - default: - break; - } - new_value = CLAMP(new_value, 0, 100); - if (new_value != current_value){ - if (is_voip_slider == TRUE){ - voip_input_widget_update (VOIP_INPUT_WIDGET(priv->voip_widget), new_value); - } - else{ - volume_widget_update (VOLUME_WIDGET(priv->volume_widget), new_value, "keypress-update"); - } - } - } - else if (IS_TRANSPORT_WIDGET(menuitem) == TRUE) { - TransportWidget* transport_widget = NULL; - GList* elem; - - for ( elem = priv->transport_widgets_list; elem; elem = elem->next ) { - transport_widget = TRANSPORT_WIDGET ( elem->data ); - if ( transport_widget_is_selected( transport_widget ) ) - break; - } - - switch (event->keyval) { - case GDK_KEY_Right: - transport_widget_react_to_key_press_event ( transport_widget, - TRANSPORT_ACTION_NEXT ); - digested = TRUE; - break; - case GDK_KEY_Left: - transport_widget_react_to_key_press_event ( transport_widget, - TRANSPORT_ACTION_PREVIOUS ); - digested = TRUE; - break; - case GDK_KEY_space: - transport_widget_react_to_key_press_event ( transport_widget, - TRANSPORT_ACTION_PLAY_PAUSE ); - digested = TRUE; - break; - case GDK_KEY_Up: - case GDK_KEY_Down: - digested = FALSE; - break; - default: - break; - } - } - return digested; -} - - -/** -key_release_cb: -**/ -static gboolean -key_release_cb(GtkWidget* widget, GdkEventKey* event, gpointer data) -{ - gboolean digested = FALSE; - - g_return_val_if_fail(IS_INDICATOR_SOUND(data), FALSE); - - IndicatorSound *indicator = INDICATOR_SOUND (data); - - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(indicator); - - GtkWidget *menuitem; - - menuitem = get_current_item (GTK_CONTAINER (widget)); - if (IS_TRANSPORT_WIDGET(menuitem) == TRUE) { - TransportWidget* transport_widget = NULL; - GList* elem; - - for(elem = priv->transport_widgets_list; elem; elem = elem->next) { - transport_widget = TRANSPORT_WIDGET (elem->data); - if ( transport_widget_is_selected( transport_widget ) ) - break; - } - - switch (event->keyval) { - case GDK_KEY_Right: - transport_widget_react_to_key_release_event ( transport_widget, - TRANSPORT_ACTION_NEXT ); - digested = TRUE; - break; - case GDK_KEY_Left: - transport_widget_react_to_key_release_event ( transport_widget, - TRANSPORT_ACTION_PREVIOUS ); - digested = TRUE; - break; - case GDK_KEY_space: - transport_widget_react_to_key_release_event ( transport_widget, - TRANSPORT_ACTION_PLAY_PAUSE ); - digested = TRUE; - break; - case GDK_KEY_Up: - case GDK_KEY_Down: - digested = FALSE; - break; - default: - break; - } - } - return digested; -} - -static void -indicator_sound_scroll (IndicatorObject * io, IndicatorObjectEntry * entry, - gint delta, IndicatorScrollDirection direction) -{ - //g_debug("indicator-sound-scroll - current slider value"); - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io)); - SoundState current_state = sound_state_manager_get_current_state (priv->state_manager); - - if (current_state == UNAVAILABLE || current_state == MUTED) - return; - - GtkWidget* slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget)); - GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)slider_widget); - GtkRange* range = (GtkRange*)slider; - g_return_if_fail(GTK_IS_RANGE(range)); - - gdouble value = gtk_range_get_value(range); - GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (slider)); - //g_debug("indicator-sound-scroll - current slider value %f", value); - if (direction == INDICATOR_OBJECT_SCROLL_UP) { - value += gtk_adjustment_get_step_increment (adj); - } else { - value -= gtk_adjustment_get_step_increment (adj); - } - //g_debug("indicator-sound-scroll - update slider with value %f", value); - volume_widget_update(VOLUME_WIDGET(priv->volume_widget), value, "scroll updates"); - - if (!gtk_widget_get_mapped(GTK_WIDGET (entry->menu))) - sound_state_manager_show_notification (priv->state_manager, value); -} - -static void -indicator_sound_middle_click (IndicatorObject * io, IndicatorObjectEntry * entry, - guint time, gpointer data) -{ - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(io); - g_return_if_fail (priv); - - mute_widget_toggle(priv->mute_widget); -} - -void -update_accessible_desc (IndicatorObject * io) -{ - GList *entries = indicator_object_get_entries(io); - if (!entries) - return; - IndicatorObjectEntry * entry = (IndicatorObjectEntry *)entries->data; - - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(io); - gchar *old_desc = priv->accessible_desc; - - if (priv->volume_widget) { - priv->accessible_desc = g_strdup_printf(_("Volume (%'.0f%%)"), - volume_widget_get_current_volume (priv->volume_widget)); - } - else { - priv->accessible_desc = NULL; - } - - entry->accessible_desc = priv->accessible_desc; - g_free (old_desc); - g_signal_emit(G_OBJECT(io), - INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE_ID, - 0, - entry, - TRUE); - g_list_free(entries); -} - -/*** -**** -***/ - -#define VISIBLE_KEY "visible" - -static void -on_visible_changed (GSettings * settings, gchar * key, gpointer user_data) -{ - g_return_if_fail (!g_strcmp0 (key, VISIBLE_KEY)); - - IndicatorObject * io = INDICATOR_OBJECT(user_data); - const gboolean visible = g_settings_get_boolean (settings, key); - indicator_object_set_visible (io, visible); - if (visible) - update_accessible_desc (io); // requires an entry -} - -static void -settings_init (IndicatorSound *self) -{ - const char * schema = SOUND_INDICATOR_GSETTINGS_SCHEMA_ID; - - gint i; - gboolean schema_exists = FALSE; - const char * const * schemas = g_settings_list_schemas (); - for (i=0; !schema_exists && schemas && schemas[i]; i++) - if (!g_strcmp0 (schema, schemas[i])) - schema_exists = TRUE; - - IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self); - if (schema_exists) { - priv->settings = g_settings_new (schema); - } else { - priv->settings = NULL; - } - - if (priv->settings != NULL) { - g_signal_connect (G_OBJECT(priv->settings), "changed::" VISIBLE_KEY, - G_CALLBACK(on_visible_changed), self); - const gboolean b = g_settings_get_boolean (priv->settings, VISIBLE_KEY); - g_object_set (G_OBJECT(self), - "indicator-object-default-visibility", b, - NULL); - } -} diff --git a/src/indicator-sound.h b/src/indicator-sound.h deleted file mode 100644 index c945efa..0000000 --- a/src/indicator-sound.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef __INCLUDE_INDICATOR_SOUND_H__ -#define __INCLUDE_INDICATOR_SOUND_H__ - -/* -A small wrapper utility to load indicators and put them as menu items -into the gnome-panel using it's applet interface. - -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curra@canonical.com> - Ted Gould <ted@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "config.h" - -#include <libindicator/indicator.h> -#include <libindicator/indicator-object.h> -#include <libindicator/indicator-service-manager.h> - -#define INDICATOR_SOUND_TYPE (indicator_sound_get_type ()) -#define INDICATOR_SOUND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_SOUND_TYPE, IndicatorSound)) -#define INDICATOR_SOUND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_SOUND_TYPE, IndicatorSoundClass)) -#define IS_INDICATOR_SOUND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_SOUND_TYPE)) -#define IS_INDICATOR_SOUND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_SOUND_TYPE)) -#define INDICATOR_SOUND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_SOUND_TYPE, IndicatorSoundClass)) - -typedef struct _IndicatorSound IndicatorSound; -typedef struct _IndicatorSoundClass IndicatorSoundClass; - -//GObject class struct -struct _IndicatorSoundClass { - IndicatorObjectClass parent_class; -}; - -//GObject instance struct -struct _IndicatorSound { - IndicatorObject parent; - IndicatorServiceManager *service; -}; - -// GObject Boiler plate -GType indicator_sound_get_type (void); - -// Update the accessible description -void update_accessible_desc (IndicatorObject * io); - -#endif diff --git a/src/main.vala b/src/main.vala new file mode 100644 index 0000000..97f311f --- /dev/null +++ b/src/main.vala @@ -0,0 +1,12 @@ + +[CCode (cheader_filename="libintl.h", type="char *")] +extern unowned string bind_textdomain_codeset (string domainname, string codeset); + +static int main (string[] args) { + bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); + Intl.setlocale (LocaleCategory.ALL, ""); + Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.GNOMELOCALEDIR); + + var service = new IndicatorSound.Service (); + return service.run (); +} diff --git a/src/media-player-list.vala b/src/media-player-list.vala new file mode 100644 index 0000000..6eb5fc9 --- /dev/null +++ b/src/media-player-list.vala @@ -0,0 +1,132 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * 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; version 3. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: + * Lars Uebernickel <lars.uebernickel@canonical.com> + */ + +/** + * MediaPlayerList is a list of media players that should appear in the sound menu. Its main responsibility is + * to listen for MPRIS players on the bus and attach them to the corresponding %Player objects. + */ +public class MediaPlayerList { + + public MediaPlayerList () { + this._players = new HashTable<string, MediaPlayer> (str_hash, str_equal); + + this.mpris_watcher = new Mpris2Watcher (); + this.mpris_watcher.client_appeared.connect (this.player_appeared); + this.mpris_watcher.client_disappeared.connect (this.player_disappeared); + } + + /* only valid while the list is not changed */ + public class Iterator { + HashTableIter<string, MediaPlayer> iter; + + public Iterator (MediaPlayerList list) { + this.iter = HashTableIter<string, MediaPlayer> (list._players); + } + + public MediaPlayer? next_value () { + MediaPlayer? player; + + if (this.iter.next (null, out player)) + return player; + else + return null; + } + } + + public Iterator iterator () { + return new Iterator (this); + } + + /** + * Adds the player associated with @desktop_id. Does nothing if such a player already exists. + */ + MediaPlayer? insert (string desktop_id) { + var id = desktop_id.has_suffix (".desktop") ? desktop_id : desktop_id + ".desktop"; + MediaPlayer? player = this._players.lookup (id); + + if (player == null) { + var appinfo = new DesktopAppInfo (id); + if (appinfo == null) { + warning ("unable to find application '%s'", id); + return null; + } + + player = new MediaPlayer (appinfo); + this._players.insert (player.id, player); + this.player_added (player); + } + + return player; + } + + /** + * Removes the player associated with @desktop_id, unless it is currently running. + */ + void remove (string desktop_id) { + MediaPlayer? player = this._players.lookup (desktop_id); + + if (player != null && !player.is_running) { + this._players.remove (desktop_id); + this.player_removed (player); + } + } + + /** + * Synchronizes the player list with @desktop_ids. After this call, this list will only contain the players + * in @desktop_ids. Players that were running but are not in @desktop_ids will remain in the list. + */ + public void sync (string[] desktop_ids) { + + /* hash desktop_ids for faster lookup */ + var hash = new HashTable<string, unowned string> (str_hash, str_equal); + foreach (var id in desktop_ids) + hash.add (id); + + /* remove players that are not desktop_ids */ + foreach (var id in this._players.get_keys ()) { + if (!hash.contains (id)) + this.remove (id); + } + + /* insert all players (insert() takes care of not adding a player twice */ + foreach (var id in desktop_ids) + this.insert (id); + } + + public signal void player_added (MediaPlayer player); + public signal void player_removed (MediaPlayer player); + + HashTable<string, MediaPlayer> _players; + Mpris2Watcher mpris_watcher; + + void player_appeared (string desktop_id, string dbus_name, bool use_playlists) { + var player = this.insert (desktop_id); + if (player != null) + player.attach (dbus_name); + } + + void player_disappeared (string dbus_name) { + MediaPlayer? player = this._players.find ( (name, player) => { + return player.dbus_name == dbus_name; + }); + + if (player != null) + player.detach (); + } +} diff --git a/src/media-player.vala b/src/media-player.vala new file mode 100644 index 0000000..7326708 --- /dev/null +++ b/src/media-player.vala @@ -0,0 +1,297 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * 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; version 3. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: + * Lars Uebernickel <lars.uebernickel@canonical.com> + */ + +/** + * MediaPlayer represents an MRPIS-capable media player. + */ +public class MediaPlayer: Object { + + public MediaPlayer (DesktopAppInfo appinfo) { + this.appinfo = appinfo; + } + + /** Desktop id of the player */ + public string id { + get { + return this.appinfo.get_id (); + } + } + + /** Display name of the player */ + public string name { + get { + return this.appinfo.get_name (); + } + } + + /** Application icon of the player */ + public Icon icon { + get { + return this.appinfo.get_icon (); + } + } + + /** + * True if an instance of the player is currently running. + * + * See also: attach(), detach() + */ + public bool is_running { + get { + return this.proxy != null; + } + } + + /** Name of the player on the bus, if an instance is currently running */ + public string dbus_name { + get { + return this._dbus_name; + } + } + + public string state { + get; private set; default = "Paused"; + } + + public class Track : Object { + public string artist { get; construct; } + public string title { get; construct; } + public string album { get; construct; } + public string art_url { get; construct; } + + public Track (string artist, string title, string album, string art_url) { + Object (artist: artist, title: title, album: album, art_url: art_url); + } + } + + public Track current_track { + get; set; + } + + public signal void playlists_changed (); + + /** + * Attach this object to a process of the associated media player. The player must own @dbus_name and + * implement the org.mpris.MediaPlayer2.Player interface. + * + * Only one player can be attached at any given time. Use detach() to detach a player. + * + * This method does not block. If it is successful, "is-running" will be set to %TRUE. + */ + public void attach (string dbus_name) { + return_if_fail (this._dbus_name == null && this.proxy == null); + + this._dbus_name = dbus_name; + Bus.get_proxy.begin<MprisPlayer> (BusType.SESSION, dbus_name, "/org/mpris/MediaPlayer2", + DBusProxyFlags.GET_INVALIDATED_PROPERTIES, null, got_proxy); + Bus.get_proxy.begin<MprisPlaylists> (BusType.SESSION, dbus_name, "/org/mpris/MediaPlayer2", + DBusProxyFlags.GET_INVALIDATED_PROPERTIES, null, got_playlists_proxy); + } + + /** + * Detach this object from a process running the associated media player. + * + * See also: attach() + */ + public void detach () { + this.proxy = null; + this._dbus_name = null; + this.notify_property ("is-running"); + this.state = "Paused"; + this.current_track = null; + } + + /** + * Launch the associated media player. + * + * Note: this will _not_ call attach(), because it doesn't know on which dbus-name the player will appear. + * Use attach() to attach this object to a running instance of the player. + */ + public void launch () { + try { + this.appinfo.launch (null, null); + } + catch (Error e) { + warning ("unable to launch %s: %s", appinfo.get_name (), e.message); + } + + if (this.proxy == null) + this.state = "Launching"; + } + + /** + * Toggles playing status. + */ + public void play_pause () { + if (this.proxy != null) { + this.proxy.PlayPause.begin (); + } + else if (this.state != "Launching") { + this.play_when_attached = true; + this.launch (); + } + } + + /** + * Skips to the next track. + */ + public void next () { + if (this.proxy != null) + this.proxy.Next.begin (); + } + + /** + * Skips to the previous track. + */ + public void previous () { + if (this.proxy != null) + this.proxy.Previous.begin (); + } + + public uint get_n_playlists () { + return this.playlists != null ? this.playlists.length : 0; + } + + public string get_playlist_id (int index) { + return_val_if_fail (index < this.playlists.length, ""); + return this.playlists[index].path; + } + + public string get_playlist_name (int index) { + return_val_if_fail (index < this.playlists.length, ""); + return this.playlists[index].name; + } + + public void activate_playlist_by_name (string name) { + if (this.playlists_proxy != null) + this.playlists_proxy.ActivatePlaylist.begin (new ObjectPath (name)); + } + + DesktopAppInfo appinfo; + MprisPlayer? proxy; + MprisPlaylists ?playlists_proxy; + string _dbus_name; + bool play_when_attached = false; + PlaylistDetails[] playlists = null; + + void got_proxy (Object? obj, AsyncResult res) { + try { + this.proxy = Bus.get_proxy.end (res); + + /* Connecting to GDBusProxy's "g-properties-changed" signal here, because vala's dbus objects don't + * emit notify signals */ + var gproxy = this.proxy as DBusProxy; + gproxy.g_properties_changed.connect (this.proxy_properties_changed); + + this.notify_property ("is-running"); + this.state = this.proxy.PlaybackStatus; + this.update_current_track (gproxy.get_cached_property ("Metadata")); + + if (this.play_when_attached) { + /* wait a little before calling PlayPause, some players need some time to + set themselves up */ + Timeout.add (1000, () => { proxy.PlayPause.begin (); return false; } ); + this.play_when_attached = false; + } + } + catch (Error e) { + this._dbus_name = null; + warning ("unable to attach to media player: %s", e.message); + } + } + + void fetch_playlists () { + /* The proxy is created even when the interface is not supported. GDBusProxy will + return 0 for the PlaylistCount property in that case. */ + if (this.playlists_proxy != null && this.playlists_proxy.PlaylistCount > 0) { + this.playlists_proxy.GetPlaylists.begin (0, 100, "Alphabetical", false, (obj, res) => { + try { + this.playlists = playlists_proxy.GetPlaylists.end (res); + this.playlists_changed (); + } + catch (Error e) { + warning ("could not fetch playlists: %s", e.message); + this.playlists = null; + } + }); + } + else { + this.playlists = null; + this.playlists_changed (); + } + } + + void got_playlists_proxy (Object? obj, AsyncResult res) { + try { + this.playlists_proxy = Bus.get_proxy.end (res); + + var gproxy = this.proxy as DBusProxy; + gproxy.g_properties_changed.connect (this.playlists_proxy_properties_changed); + } + catch (Error e) { + warning ("unable to create mpris plalists proxy: %s", e.message); + return; + } + + Timeout.add (500, () => { this.fetch_playlists (); return false; } ); + } + + /* some players (e.g. Spotify) don't follow the spec closely and pass single strings in metadata fields + * where an array of string is expected */ + static string sanitize_metadata_value (Variant? v) { + if (v == null) + return ""; + else if (v.is_of_type (VariantType.STRING)) + return v.get_string (); + else if (v.is_of_type (VariantType.STRING_ARRAY)) + return string.joinv (",", v.get_strv ()); + + warn_if_reached (); + return ""; + } + + void proxy_properties_changed (DBusProxy proxy, Variant changed_properties, string[] invalidated_properties) { + if (changed_properties.lookup ("PlaybackStatus", "s", null)) { + this.state = this.proxy.PlaybackStatus; + } + + var metadata = changed_properties.lookup_value ("Metadata", new VariantType ("a{sv}")); + if (metadata != null) + this.update_current_track (metadata); + } + + void playlists_proxy_properties_changed (DBusProxy proxy, Variant changed_properties, string[] invalidated_properties) { + if (changed_properties.lookup ("PlaylistCount", "u", null)) + this.fetch_playlists (); + } + + void update_current_track (Variant metadata) { + if (metadata != null) { + this.current_track = new Track ( + sanitize_metadata_value (metadata.lookup_value ("xesam:artist", null)), + sanitize_metadata_value (metadata.lookup_value ("xesam:title", null)), + sanitize_metadata_value (metadata.lookup_value ("xesam:album", null)), + sanitize_metadata_value (metadata.lookup_value ("mpris:artUrl", null)) + ); + } + else { + this.current_track = null; + } + } +} diff --git a/src/metadata-menu-item.vala b/src/metadata-menu-item.vala deleted file mode 100644 index f4a7e68..0000000 --- a/src/metadata-menu-item.vala +++ /dev/null @@ -1,224 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -using Gee; -using Dbusmenu; -using DbusmenuMetadata; -using Gdk; - -public class MetadataMenuitem : PlayerItem -{ - public const string ALBUM_ART_DIR_SUFFIX = "indicator/sound/album-art-cache"; - - public static string album_art_cache_dir; - private static FetchFile fetcher; - private string previous_temp_album_art_path; - - public MetadataMenuitem (PlayerController parent) - { - Object(item_type: MENUITEM_TYPE, owner: parent); - } - - construct{ - MetadataMenuitem.clean_album_art_temp_dir(); - this.previous_temp_album_art_path = null; - this.album_art_cache_dir = MetadataMenuitem.create_album_art_temp_dir(); - //debug ("JUST ABOUT TO ATTEMPT PLAYER NAME SETTING %s", this.owner.app_info.get_name()); - this.property_set (MENUITEM_PLAYER_NAME, this.owner.app_info.get_name()); - this.property_set (MENUITEM_PLAYER_ICON, this.owner.icon_name); - this.property_set_bool (MENUITEM_PLAYER_RUNNING, false); - this.property_set_bool (MENUITEM_HIDE_TRACK_DETAILS, true); - reset (relevant_attributes_for_ui()); - } - - private static void clean_album_art_temp_dir() - { - string path = GLib.Path.build_filename(Environment.get_user_cache_dir(), ALBUM_ART_DIR_SUFFIX); - - GLib.File? album_art_dir = GLib.File.new_for_path(path); - - if(delete_album_art_contents(album_art_dir) == false) - { - warning("could not remove the temp album art files %s", path); - } - } - - private static string? create_album_art_temp_dir() - { - string path = GLib.Path.build_filename(Environment.get_user_cache_dir(), ALBUM_ART_DIR_SUFFIX); - if(DirUtils.create_with_parents(path, 0700) == -1){ - warning("could not create temp dir %s for remote album art, it must have been created already", path); - } - return path; - } - - private static bool delete_album_art_contents (GLib.File dir) - { - bool result = true; - try { - var e = dir.enumerate_children (FILE_ATTRIBUTE_STANDARD_NAME, - FileQueryInfoFlags.NOFOLLOW_SYMLINKS, - null); - while (true) - { - var file = e.next_file (null); - - if (file == null) - break; - - debug("file name = %s", file.get_name()); - - var child = dir.get_child (file.get_name ()); - - try { - child.delete (null); - } catch (Error error_) { - warning (@"Unable to delete file '$(child.get_basename ()): $(error_.message)"); - result = false; - } - } - } catch (Error error) { - warning (@"Unable to read files from directory '$(dir.get_basename ())': %s", - error.message); - result = false; - } - return result; - } - - public void fetch_art(string uri, string prop) - { - File art_file = File.new_for_uri(uri); - if (art_file.is_native() == true){ - if (art_file.query_exists() == false){ - // Can't load the image, set prop to empty and return. - this.property_set_int ( prop, EMPTY ); - return; - } - string path; - try{ - path = Filename.from_uri ( uri.strip() ); - debug ("Populating the artwork field with %s", uri.strip()); - this.property_set ( prop, path ); - } - catch(ConvertError e){ - warning("Problem converting URI %s to file path", - uri); - } - // eitherway return, the artwork was local - return; - } - debug("fetch_art -remotely %s", this.album_art_cache_dir); - // If we didn't manage to create the temp dir - // don't bother with remote - if(this.album_art_cache_dir == null){ - return; - } - // green light to go remote - this.fetcher = new FetchFile (uri, prop); - this.fetcher.failed.connect (() => { this.on_fetcher_failed ();}); - this.fetcher.completed.connect (this.on_fetcher_completed); - this.fetcher.fetch_data (); - } - - private void on_fetcher_failed () - { - warning("on_fetcher_failed -> could not fetch artwork"); - } - - private void on_fetcher_completed(ByteArray update, string property) - { - try{ - PixbufLoader loader = new PixbufLoader (); - loader.write (update.data); - loader.close (); - Pixbuf icon = loader.get_pixbuf (); - string path = this.album_art_cache_dir.concat("/downloaded-coverart-XXXXXX"); - int r = FileUtils.mkstemp(path); - if(r != -1){ - icon.save (path, loader.get_format().get_name()); - this.property_set(property, path); - if(this.previous_temp_album_art_path != null){ - FileUtils.remove(this.previous_temp_album_art_path); - } - this.previous_temp_album_art_path = path; - } - } - catch(GLib.Error e){ - warning("Problem creating file from bytearray fetched from the interweb - error: %s", - e.message); - } - } - - public override void handle_event (string name, - Variant input_value, - uint timestamp) - { - if (name != Dbusmenu.MENUITEM_EVENT_ACTIVATED) - return; - - if(this.owner.current_state == PlayerController.state.OFFLINE) - { - this.owner.instantiate(timestamp); - } - else if (this.owner.current_state == PlayerController.state.CONNECTED) { - this.owner.player_activator.activate(timestamp); - this.owner.mpris_bridge.expose(timestamp); - } - } - - public void alter_label (string? new_title) - { - if (new_title == null) return; - this.property_set (MENUITEM_PLAYER_NAME, new_title); - } - - public void toggle_active_triangle (bool update) - { - debug ("toggle active triangle"); - this.property_set_bool (MENUITEM_PLAYER_RUNNING, update); - } - - public void should_collapse(bool collapse) - { - this.property_set_bool (MENUITEM_HIDE_TRACK_DETAILS, collapse); - } - - public static HashSet<string> attributes_format() - { - HashSet<string> attrs = new HashSet<string>(); - attrs.add(MENUITEM_TITLE); - attrs.add(MENUITEM_ARTIST); - attrs.add(MENUITEM_ALBUM); - attrs.add(MENUITEM_ARTURL); - attrs.add(MENUITEM_PLAYER_NAME); - attrs.add(MENUITEM_PLAYER_ICON); - attrs.add(MENUITEM_PLAYER_RUNNING); - return attrs; - } - - public static HashSet<string> relevant_attributes_for_ui() - { - HashSet<string> attrs = new HashSet<string>(); - attrs.add(MENUITEM_TITLE); - attrs.add(MENUITEM_ARTIST); - attrs.add(MENUITEM_ALBUM); - attrs.add(MENUITEM_ARTURL); - return attrs; - } -} diff --git a/src/metadata-widget.c b/src/metadata-widget.c deleted file mode 100644 index 812f340..0000000 --- a/src/metadata-widget.c +++ /dev/null @@ -1,880 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - Mirco Müller <mirco.mueller@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <glib/gi18n-lib.h> -#include "metadata-widget.h" -#include "common-defs.h" -#include <gtk/gtk.h> -#include <glib.h> -#include "transport-widget.h" -#include <libindicator/indicator-image-helper.h> - -typedef struct _MetadataWidgetPrivate MetadataWidgetPrivate; - -struct _MetadataWidgetPrivate -{ - gboolean theme_change_occured; - GtkWidget* meta_data_h_box; - GtkWidget* meta_data_v_box; - GtkWidget* album_art; - GString* image_path; - GString* old_image_path; - GtkWidget* artist_label; - GtkWidget* piece_label; - GtkWidget* container_label; - GtkWidget* player_label; - GtkWidget* player_icon; - DbusmenuMenuitem* twin_item; - gint current_height; -}; - -#define METADATA_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), METADATA_WIDGET_TYPE, MetadataWidgetPrivate)) - -/* Prototypes */ -static void metadata_widget_class_init (MetadataWidgetClass *klass); -static void metadata_widget_init (MetadataWidget *self); -static void metadata_widget_dispose (GObject *object); -static void metadata_widget_finalize (GObject *object); -static void metadata_widget_set_style (GtkWidget* button, GtkStyle* style); -static void metadata_widget_set_twin_item (MetadataWidget* self, - DbusmenuMenuitem* twin_item); -// keyevent consumers -static gboolean metadata_widget_button_release_event (GtkWidget *menuitem, - GdkEventButton *event); -// Dbusmenuitem properties update callback -static void metadata_widget_property_update (DbusmenuMenuitem* item, - gchar* property, - GVariant* value, - gpointer userdata); -static void metadata_widget_style_labels ( MetadataWidget* self, - GtkLabel* label); -static void draw_album_art_placeholder (GtkWidget *metadata); - -static void draw_album_border (GtkWidget *metadata, gboolean selected); -static void metadata_widget_selection_received_event_callback( GtkWidget *widget, - GtkSelectionData *data, - guint time, - gpointer user_data); - - - -#if GTK_CHECK_VERSION(3, 0, 0) -static void metadata_widget_get_preferred_width (GtkWidget* self, - gint* minimum_width, - gint* natural_width); -static gboolean metadata_widget_icon_triangle_draw_cb_gtk_3 (GtkWidget *image, - cairo_t* cr, - gpointer user_data); -static gboolean metadata_image_expose_gtk_3 (GtkWidget *image, - cairo_t* cr, - gpointer user_data); -#else -static gboolean metadata_widget_icon_triangle_draw_cb (GtkWidget *image, - GdkEventExpose *event, - gpointer user_data); -static gboolean metadata_image_expose (GtkWidget *image, - GdkEventExpose *event, - gpointer user_data); -#endif - -static void metadata_widget_set_icon (MetadataWidget *self); -static void metadata_widget_handle_resizing (MetadataWidget* self); - - -G_DEFINE_TYPE (MetadataWidget, metadata_widget, GTK_TYPE_MENU_ITEM); - -static void -metadata_widget_class_init (MetadataWidgetClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - widget_class->button_release_event = metadata_widget_button_release_event; - #if GTK_CHECK_VERSION(3, 0, 0) - widget_class->get_preferred_width = metadata_widget_get_preferred_width; - #endif - g_type_class_add_private (klass, sizeof (MetadataWidgetPrivate)); - - gobject_class->dispose = metadata_widget_dispose; - gobject_class->finalize = metadata_widget_finalize; -} - -static void -metadata_widget_init (MetadataWidget *self) -{ - MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(self); - GtkWidget *hbox; - GtkWidget *outer_v_box; - - #if GTK_CHECK_VERSION(3, 0, 0) - outer_v_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - #else - outer_v_box = gtk_vbox_new (FALSE, 0); - #endif - - #if GTK_CHECK_VERSION(3, 0, 0) - hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - #else - hbox = gtk_hbox_new(FALSE, 0); - #endif - - priv->meta_data_h_box = hbox; - priv->current_height = 1; - - // image - priv->album_art = gtk_image_new(); - priv->image_path = g_string_new(""); - priv->old_image_path = g_string_new(""); - - #if GTK_CHECK_VERSION(3, 0, 0) - g_signal_connect(priv->album_art, "draw", - G_CALLBACK(metadata_image_expose_gtk_3), - GTK_WIDGET(self)); - - g_signal_connect_after (GTK_WIDGET(self), "draw", - G_CALLBACK(metadata_widget_icon_triangle_draw_cb_gtk_3), - GTK_WIDGET(self)); - #else - g_signal_connect(priv->album_art, "expose-event", - G_CALLBACK(metadata_image_expose), - GTK_WIDGET(self)); - - g_signal_connect_after (GTK_WIDGET(self), "expose-event", - G_CALLBACK(metadata_widget_icon_triangle_draw_cb), - GTK_WIDGET(self)); - #endif - gtk_box_pack_start (GTK_BOX (priv->meta_data_h_box), - priv->album_art, - FALSE, - FALSE, - 1); - priv->theme_change_occured = FALSE; - - #if GTK_CHECK_VERSION(3, 0, 0) - GtkWidget* vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - #else - GtkWidget* vbox = gtk_vbox_new(FALSE, 0); - #endif - - // artist - GtkWidget* artist; - artist = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(artist), (gfloat)0, (gfloat)0); - gtk_misc_set_padding (GTK_MISC(artist), (gfloat)10, (gfloat)0); - gtk_widget_set_size_request (artist, 140, 15); - - gtk_label_set_ellipsize(GTK_LABEL(artist), PANGO_ELLIPSIZE_MIDDLE); - metadata_widget_style_labels(self, GTK_LABEL(artist)); - priv->artist_label = artist; - - // title - GtkWidget* piece; - piece = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(piece), (gfloat)0, (gfloat)0); - gtk_misc_set_padding (GTK_MISC(piece), (gfloat)10, (gfloat)-5); - - gtk_widget_set_size_request (piece, 140, 15); - gtk_label_set_ellipsize(GTK_LABEL(piece), PANGO_ELLIPSIZE_MIDDLE); - metadata_widget_style_labels(self, GTK_LABEL(piece)); - priv->piece_label = piece; - - // container - GtkWidget* container; - container = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(container), (gfloat)0, (gfloat)0); - gtk_misc_set_padding (GTK_MISC(container), (gfloat)10, (gfloat)0); - gtk_widget_set_size_request (container, 140, 15); - - gtk_label_set_ellipsize(GTK_LABEL(container), PANGO_ELLIPSIZE_MIDDLE); - metadata_widget_style_labels(self, GTK_LABEL(container)); - priv->container_label = container; - - gtk_box_pack_start (GTK_BOX (vbox), priv->piece_label, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (vbox), priv->artist_label, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (vbox), priv->container_label, FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX (priv->meta_data_h_box), vbox, FALSE, FALSE, 0); - - g_signal_connect(self, "style-set", - G_CALLBACK(metadata_widget_set_style), GTK_WIDGET(self)); - g_signal_connect (self, "selection-received", - G_CALLBACK(metadata_widget_selection_received_event_callback), - GTK_WIDGET(self)); - - gint padding = 4; - gtk_widget_style_get(GTK_WIDGET(self), "toggle-spacing", &padding, NULL); - -#if GTK_CHECK_VERSION(3, 0, 0) - GtkWidget * tophbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, padding); -#else - GtkWidget * tophbox = gtk_hbox_new(FALSE, padding); -#endif - - GtkWidget *player_icon; - player_icon = gtk_image_new(); - priv->player_icon = player_icon; - - gtk_misc_set_alignment (GTK_MISC(priv->player_icon), 1.0 /* right aligned */, 0.5); - gtk_box_pack_start (GTK_BOX (tophbox), priv->player_icon, FALSE, FALSE, 0); - GtkWidget* spacer; - spacer = gtk_alignment_new (0,0,0,0); - gtk_container_add (GTK_CONTAINER (spacer), priv->meta_data_h_box); - gtk_alignment_set_padding (GTK_ALIGNMENT (spacer),5,0,0,0); - - // player label - GtkWidget* player_label; - player_label = gtk_label_new (""); - gtk_misc_set_alignment(GTK_MISC(player_label), (gfloat)0, 0.5); - priv->player_label = player_label; - gtk_box_pack_start (GTK_BOX (tophbox), priv->player_label, TRUE, TRUE, 0); - - gtk_box_pack_start (GTK_BOX(outer_v_box), tophbox, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX(outer_v_box), spacer, FALSE, FALSE, 0); - - gtk_container_add (GTK_CONTAINER (self), outer_v_box); - - gtk_widget_show_all (priv->meta_data_h_box); - gtk_widget_set_no_show_all (priv->meta_data_h_box, TRUE); - - gtk_widget_hide (priv->meta_data_h_box); -} - -static void -metadata_widget_dispose (GObject *object) -{ - G_OBJECT_CLASS (metadata_widget_parent_class)->dispose (object); -} - -static void -metadata_widget_finalize (GObject *object) -{ - MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(METADATA_WIDGET(object)); - g_string_free (priv->image_path, TRUE); - g_string_free (priv->old_image_path, TRUE); - - G_OBJECT_CLASS (metadata_widget_parent_class)->finalize (object); -} - -/** -* Make sure to only clear the album art only when it is not empty -* Otherwise it will continuously call queue_draw after each empty call. -*/ -static void -clear_album_art (GtkImage* album_art) -{ - if (gtk_image_get_storage_type(album_art) != GTK_IMAGE_EMPTY){ - gtk_image_clear (album_art); - } -} - - -#if GTK_CHECK_VERSION(3, 0, 0) -static void -metadata_widget_get_preferred_width (GtkWidget* self, - gint* minimum_width, - gint* natural_width) -{ - *minimum_width = *natural_width = 200; -} - -/** - * We override the expose method to enable primitive drawing of the - * empty album art image. - */ -static gboolean -metadata_image_expose_gtk_3 (GtkWidget *metadata, - cairo_t* cr, - gpointer user_data) -{ - g_return_val_if_fail(IS_METADATA_WIDGET(user_data), FALSE); - MetadataWidget* widget = METADATA_WIDGET(user_data); - MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(widget); - - if ( TRUE == dbusmenu_menuitem_property_get_bool (DBUSMENU_MENUITEM(priv->twin_item), - DBUSMENU_METADATA_MENUITEM_HIDE_TRACK_DETAILS)) - { - return FALSE; - } - - if((guint)priv->image_path->len != 0){ - - if(g_string_equal (priv->image_path, priv->old_image_path) == FALSE || - priv->theme_change_occured == TRUE){ - priv->theme_change_occured = FALSE; - GdkPixbuf* pixbuf; - pixbuf = gdk_pixbuf_new_from_file_at_size(priv->image_path->str, 60, 60, NULL); - - if(GDK_IS_PIXBUF(pixbuf) == FALSE){ - clear_album_art (GTK_IMAGE(priv->album_art)); - gtk_widget_set_size_request(GTK_WIDGET(priv->album_art), 60, 60); - draw_album_border (metadata, FALSE); - draw_album_art_placeholder(metadata); - return FALSE; - } - - gtk_image_set_from_pixbuf(GTK_IMAGE(priv->album_art), pixbuf); - gtk_widget_set_size_request(GTK_WIDGET(priv->album_art), - gdk_pixbuf_get_width(pixbuf), - gdk_pixbuf_get_height(pixbuf)); - - draw_album_border (metadata, FALSE); - g_string_erase (priv->old_image_path, 0, -1); - g_string_overwrite (priv->old_image_path, 0, priv->image_path->str); - g_object_unref(pixbuf); - } - return FALSE; - } - clear_album_art (GTK_IMAGE(priv->album_art)); - g_string_erase (priv->old_image_path, 0, -1); - gtk_widget_set_size_request(GTK_WIDGET(priv->album_art), 60, 60); - draw_album_border (metadata, FALSE); - draw_album_art_placeholder(metadata); - return FALSE; -} - -// Draw the triangle if the player is running ... -static gboolean -metadata_widget_icon_triangle_draw_cb_gtk_3 (GtkWidget *widget, - cairo_t* cr, - gpointer user_data) -{ - g_return_val_if_fail (IS_METADATA_WIDGET (user_data), FALSE); - MetadataWidget* meta = METADATA_WIDGET (user_data); - MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(meta); - - gboolean running = dbusmenu_menuitem_property_get_bool (priv->twin_item, - DBUSMENU_METADATA_MENUITEM_PLAYER_RUNNING); - - if (!running) - return FALSE; - - GtkStyle *style; - int x, y, arrow_width, arrow_height; - - arrow_width = 5; - arrow_height = 9; - - style = gtk_widget_get_style (widget); - - GtkAllocation allocation; - gtk_widget_get_allocation (widget, &allocation); - x = allocation.x; - y = 0; - - // Draw triangle but only if the player is running. - y += gtk_image_get_pixel_size (GTK_IMAGE (priv->player_icon)) / 3 + 5; - cairo_set_line_width (cr, 1.0); - - cairo_move_to (cr, x, y); - cairo_line_to (cr, x, y + arrow_height); - cairo_line_to (cr, x + arrow_width, y + (double)arrow_height/2.0); - cairo_close_path (cr); - cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0, - style->fg[gtk_widget_get_state(widget)].green/65535.0, - style->fg[gtk_widget_get_state(widget)].blue/65535.0); - cairo_fill (cr); - - return FALSE; -} - -// GTK 2 Expose handler -#else - -static gboolean -metadata_image_expose (GtkWidget *metadata, - GdkEventExpose *event, - gpointer user_data) -{ - g_return_val_if_fail(IS_METADATA_WIDGET(user_data), FALSE); - MetadataWidget* widget = METADATA_WIDGET(user_data); - MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(widget); - - if ( TRUE == dbusmenu_menuitem_property_get_bool (DBUSMENU_MENUITEM(priv->twin_item), - DBUSMENU_METADATA_MENUITEM_HIDE_TRACK_DETAILS)) - { - return FALSE; - } - - draw_album_border(metadata, FALSE); - - if(priv->image_path->len > 0){ - if(g_string_equal(priv->image_path, priv->old_image_path) == FALSE || - priv->theme_change_occured == TRUE){ - priv->theme_change_occured = FALSE; - GdkPixbuf* pixbuf; - pixbuf = gdk_pixbuf_new_from_file_at_size(priv->image_path->str, 60, 60, NULL); - - if(GDK_IS_PIXBUF(pixbuf) == FALSE){ - clear_album_art (GTK_IMAGE(priv->album_art)); - gtk_widget_set_size_request(GTK_WIDGET(priv->album_art), 60, 60); - draw_album_art_placeholder(metadata); - return FALSE; - } - - gtk_image_set_from_pixbuf(GTK_IMAGE(priv->album_art), pixbuf); - gtk_widget_set_size_request(GTK_WIDGET(priv->album_art), - gdk_pixbuf_get_width(pixbuf), - gdk_pixbuf_get_height(pixbuf)); - - g_string_erase (priv->old_image_path, 0, -1); - g_string_overwrite (priv->old_image_path, 0, priv->image_path->str); - g_object_unref(pixbuf); - } - return FALSE; - } - clear_album_art (GTK_IMAGE(priv->album_art)); - g_string_erase (priv->old_image_path, 0, -1); - gtk_widget_set_size_request(GTK_WIDGET(priv->album_art), 60, 60); - draw_album_art_placeholder(metadata); - return FALSE; -} - - -// Draw the triangle if the player is running ... -static gboolean -metadata_widget_icon_triangle_draw_cb (GtkWidget *widget, - GdkEventExpose *event, - gpointer user_data) -{ - g_return_val_if_fail(IS_METADATA_WIDGET(user_data), FALSE); - - MetadataWidget* meta = METADATA_WIDGET(user_data); - MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(meta); - - gboolean running = dbusmenu_menuitem_property_get_bool (priv->twin_item, - DBUSMENU_METADATA_MENUITEM_PLAYER_RUNNING); - - if (!running) - return FALSE; - - GtkStyle *style; - cairo_t *cr; - int x, y, arrow_width, arrow_height; - - arrow_width = 5; - arrow_height = 9; - - style = gtk_widget_get_style (widget); - - cr = (cairo_t*) gdk_cairo_create (gtk_widget_get_window (widget)); - - GtkAllocation allocation; - gtk_widget_get_allocation (widget, &allocation); - x = allocation.x; - y = allocation.y; - - // Draw triangle but only if the player is running. - y += allocation.height/2.0 - (double)arrow_height/2.0; - cairo_set_line_width (cr, 1.0); - - cairo_move_to (cr, x, y); - cairo_line_to (cr, x, y + arrow_height); - cairo_line_to (cr, x + arrow_width, y + (double)arrow_height/2.0); - cairo_close_path (cr); - cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0, - style->fg[gtk_widget_get_state(widget)].green/65535.0, - style->fg[gtk_widget_get_state(widget)].blue/65535.0); - cairo_fill (cr); - - cairo_destroy (cr); - return FALSE; -} -#endif - -static void -draw_album_border(GtkWidget *metadata, - gboolean selected) -{ - cairo_t *cr; - cr = gdk_cairo_create (gtk_widget_get_window (metadata)); - #if GTK_CHECK_VERSION(3, 0, 0) - gtk_style_context_add_class (gtk_widget_get_style_context (metadata), - "menu"); - #endif - - GtkStyle *style; - style = gtk_widget_get_style (metadata); - - GtkAllocation alloc; - gtk_widget_get_allocation (metadata, &alloc); - gint offset = 1; - - alloc.width = alloc.width + (offset * 2); - alloc.height = alloc.height + (offset * 2) - 7; - alloc.x = alloc.x - offset; - alloc.y = alloc.y - offset + 3; - - CairoColorRGB bg_normal, fg_normal; - - bg_normal.r = style->bg[0].red/65535.0; - bg_normal.g = style->bg[0].green/65535.0; - bg_normal.b = style->bg[0].blue/65535.0; - - const gint state = selected ? GTK_STATE_SELECTED : GTK_STATE_NORMAL; - - fg_normal.r = style->fg[state].red/65535.0; - fg_normal.g = style->fg[state].green/65535.0; - fg_normal.b = style->fg[state].blue/65535.0; - - CairoColorRGB dark_top_color; - CairoColorRGB light_bottom_color; - CairoColorRGB background_color; - - _color_shade ( &bg_normal, 0.93, &background_color ); - _color_shade ( &bg_normal, 0.23, &dark_top_color ); - _color_shade ( &fg_normal, 0.55, &light_bottom_color ); - - cairo_rectangle (cr, - alloc.x, alloc.y, - alloc.width, alloc.height); - - cairo_set_line_width (cr, 1.0); - - cairo_clip ( cr ); - - cairo_move_to (cr, alloc.x, alloc.y ); - cairo_line_to (cr, alloc.x + alloc.width, - alloc.y ); - cairo_line_to ( cr, alloc.x + alloc.width, - alloc.y + alloc.height ); - cairo_line_to ( cr, alloc.x, alloc.y + alloc.height ); - cairo_line_to ( cr, alloc.x, alloc.y); - cairo_close_path (cr); - - cairo_set_source_rgba ( cr, - background_color.r, - background_color.g, - background_color.b, - 1.0 ); - - cairo_fill ( cr ); - - cairo_move_to (cr, alloc.x, alloc.y ); - cairo_line_to (cr, alloc.x + alloc.width, - alloc.y ); - - cairo_close_path (cr); - cairo_set_source_rgba ( cr, - dark_top_color.r, - dark_top_color.g, - dark_top_color.b, - 1.0 ); - - cairo_stroke ( cr ); - - cairo_move_to ( cr, alloc.x + alloc.width, - alloc.y + alloc.height ); - cairo_line_to ( cr, alloc.x, alloc.y + alloc.height ); - - cairo_close_path (cr); - cairo_set_source_rgba ( cr, - light_bottom_color.r, - light_bottom_color.g, - light_bottom_color.b, - 1.0); - - cairo_stroke ( cr ); - cairo_destroy (cr); -} - -static void -draw_album_art_placeholder(GtkWidget *metadata) -{ - cairo_t *cr; - cr = gdk_cairo_create (gtk_widget_get_window (metadata)); - GtkStyle *style; - style = gtk_widget_get_style (metadata); - - GtkAllocation alloc; - gtk_widget_get_allocation (metadata, &alloc); - - PangoLayout *layout; - PangoFontDescription *desc; - layout = pango_cairo_create_layout(cr); - PangoContext* pcontext = pango_cairo_create_context(cr); - pango_cairo_context_set_resolution (pcontext, 96); - - GString* string = g_string_new(""); - gssize size = -1; - gunichar code = g_utf8_get_char_validated("\342\231\253", size); - g_string_append_unichar (string, code); - - pango_layout_set_text(layout, string->str, -1); - desc = pango_font_description_from_string("Sans Bold 30"); - pango_layout_set_font_description(layout, desc); - pango_font_description_free(desc); - - CairoColorRGB fg_normal, light_bottom_color; - - fg_normal.r = style->fg[0].red/65535.0; - fg_normal.g = style->fg[0].green/65535.0; - fg_normal.b = style->fg[0].blue/65535.0; - - _color_shade ( &fg_normal, 0.78, &light_bottom_color ); - - cairo_set_source_rgba (cr, - light_bottom_color.r, - light_bottom_color.g, - light_bottom_color.b, - 1.0); - - pango_cairo_update_layout(cr, layout); - cairo_move_to (cr, alloc.x + alloc.width/6, alloc.y + 3); - pango_cairo_show_layout(cr, layout); - - g_object_unref(layout); - g_object_unref(pcontext); - g_string_free (string, TRUE); - cairo_destroy (cr); -} - -static void -metadata_widget_selection_received_event_callback ( GtkWidget *widget, - GtkSelectionData *data, - guint time, - gpointer user_data ) - -{ - draw_album_border(widget, TRUE); -} - -/* Suppress/consume keyevents */ -static gboolean -metadata_widget_button_release_event (GtkWidget *menuitem, - GdkEventButton *event) -{ - g_return_val_if_fail (IS_METADATA_WIDGET (menuitem), FALSE); - MetadataWidgetPrivate* priv = METADATA_WIDGET_GET_PRIVATE(METADATA_WIDGET(menuitem)); - // For the left raise/launch the player - if (event->button == 1){ - GVariant* new_title_event = g_variant_new_boolean(TRUE); - dbusmenu_menuitem_handle_event (priv->twin_item, - "Title menu event", - new_title_event, - 0); - } - // For the right copy track details to clipboard only if the player is running - // and there is something there - else if (event->button == 3){ - gboolean running = dbusmenu_menuitem_property_get_bool (priv->twin_item, - DBUSMENU_METADATA_MENUITEM_PLAYER_RUNNING); - gboolean hidden = dbusmenu_menuitem_property_get_bool (priv->twin_item, - DBUSMENU_METADATA_MENUITEM_HIDE_TRACK_DETAILS); - g_return_val_if_fail ( running, FALSE ); - - g_return_val_if_fail ( !hidden, FALSE ); - - GtkClipboard* board = gtk_clipboard_get (GDK_NONE); - gchar* contents = g_strdup_printf("artist: %s \ntitle: %s \nalbum: %s", - dbusmenu_menuitem_property_get(priv->twin_item, - DBUSMENU_METADATA_MENUITEM_ARTIST), - dbusmenu_menuitem_property_get(priv->twin_item, - DBUSMENU_METADATA_MENUITEM_TITLE), - dbusmenu_menuitem_property_get(priv->twin_item, - DBUSMENU_METADATA_MENUITEM_ALBUM)); - gtk_clipboard_set_text (board, contents, -1); - gtk_clipboard_store (board); - g_free(contents); - } - return FALSE; -} - -static void -metadata_widget_property_update(DbusmenuMenuitem* item, gchar* property, - GVariant* value, gpointer userdata) -{ - g_return_if_fail (IS_METADATA_WIDGET (userdata)); - - if(g_variant_is_of_type(value, G_VARIANT_TYPE_INT32) == TRUE && - g_variant_get_int32(value) == DBUSMENU_PROPERTY_EMPTY){ - GVariant* new_value = g_variant_new_string (""); - value = new_value; - } - - MetadataWidget* mitem = METADATA_WIDGET(userdata); - MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(mitem); - - if(g_ascii_strcasecmp(DBUSMENU_METADATA_MENUITEM_ARTIST, property) == 0){ - gtk_label_set_text(GTK_LABEL(priv->artist_label), g_variant_get_string(value, NULL)); - metadata_widget_style_labels(mitem, GTK_LABEL(priv->artist_label)); - } - else if(g_ascii_strcasecmp(DBUSMENU_METADATA_MENUITEM_TITLE, property) == 0){ - gtk_label_set_text(GTK_LABEL(priv->piece_label), g_variant_get_string(value, NULL)); - metadata_widget_style_labels(mitem, GTK_LABEL(priv->piece_label)); - } - else if(g_ascii_strcasecmp(DBUSMENU_METADATA_MENUITEM_ALBUM, property) == 0){ - gtk_label_set_text(GTK_LABEL(priv->container_label), g_variant_get_string(value, NULL)); - metadata_widget_style_labels(mitem, GTK_LABEL(priv->container_label)); - } - else if(g_ascii_strcasecmp(DBUSMENU_METADATA_MENUITEM_ARTURL, property) == 0){ - g_string_erase(priv->image_path, 0, -1); - g_string_overwrite (priv->image_path, 0, g_variant_get_string (value, NULL)); - gtk_widget_queue_draw(GTK_WIDGET(mitem)); - } - else if (g_ascii_strcasecmp (DBUSMENU_METADATA_MENUITEM_PLAYER_NAME, property) == 0){ - gtk_label_set_label (GTK_LABEL (priv->player_label), - g_variant_get_string(value, NULL)); - } - else if (g_ascii_strcasecmp (DBUSMENU_METADATA_MENUITEM_PLAYER_ICON, property) == 0){ - metadata_widget_set_icon (mitem); - } - else if(g_ascii_strcasecmp(DBUSMENU_METADATA_MENUITEM_HIDE_TRACK_DETAILS, property) == 0){ - metadata_widget_handle_resizing (mitem); - } -} - -static void -metadata_widget_handle_resizing (MetadataWidget* self) -{ - MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(self); - - if (dbusmenu_menuitem_property_get_bool (priv->twin_item, - DBUSMENU_METADATA_MENUITEM_HIDE_TRACK_DETAILS) == TRUE){ - gtk_widget_hide (priv->meta_data_h_box); - } - else{ - gtk_widget_show (priv->meta_data_h_box); - } - gtk_widget_queue_draw(GTK_WIDGET(self)); -} - -static void -metadata_widget_style_labels(MetadataWidget* self, GtkLabel* label) -{ - char* markup; - markup = g_markup_printf_escaped ("<span size=\"smaller\">%s</span>", - gtk_label_get_text(GTK_LABEL(label))); - gtk_label_set_markup (GTK_LABEL (label), markup); - g_free(markup); -} - -static void -metadata_widget_set_style(GtkWidget* metadata, GtkStyle* style) -{ - g_return_if_fail(IS_METADATA_WIDGET(metadata)); - MetadataWidget* widg = METADATA_WIDGET(metadata); - MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(widg); - priv->theme_change_occured = TRUE; - gtk_widget_queue_draw (GTK_WIDGET(metadata)); -} - -static void -metadata_widget_set_icon (MetadataWidget *self) -{ - MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(self); - - GString* banshee_string = g_string_new ( "banshee" ); - gchar * tmp = g_utf8_strdown (dbusmenu_menuitem_property_get(priv->twin_item, DBUSMENU_METADATA_MENUITEM_PLAYER_NAME), -1); - GString* app_panel = g_string_new (tmp); - g_free (tmp); - - // Banshee Special case! - // Not ideal but apparently we want the banshee icon to be the greyscale one - // and any others to be the icon from the desktop file => colour. - if ( g_string_equal ( banshee_string, app_panel ) == TRUE && - gtk_icon_theme_has_icon ( gtk_icon_theme_get_default(), app_panel->str ) ){ - g_string_append ( app_panel, "-panel" ); - } - else{ - // Otherwise use what is stored in the props - g_string_erase (app_panel, 0, -1); - g_string_overwrite (app_panel, - 0, - dbusmenu_menuitem_property_get ( priv->twin_item, - DBUSMENU_METADATA_MENUITEM_PLAYER_ICON )); - } - - const GtkIconSize icon_size = GTK_ICON_SIZE_MENU; - if (g_path_is_absolute(app_panel->str) && g_file_test (app_panel->str, G_FILE_TEST_IS_REGULAR)){ - gint width, height; - gtk_icon_size_lookup (icon_size, &width, &height); - GdkPixbuf *pix = gdk_pixbuf_new_from_file_at_scale(app_panel->str, width, height, TRUE, NULL); - gtk_image_set_from_pixbuf (GTK_IMAGE (priv->player_icon), pix); - g_object_unref (pix); - } - else{ - gtk_image_set_from_icon_name(GTK_IMAGE (priv->player_icon), app_panel->str, icon_size); - } - - g_string_free ( app_panel, TRUE); - g_string_free ( banshee_string, TRUE); -} - -static void -metadata_widget_set_twin_item (MetadataWidget* self, - DbusmenuMenuitem* twin_item) -{ - MetadataWidgetPrivate* priv = METADATA_WIDGET_GET_PRIVATE(self); - priv->twin_item = twin_item; - g_signal_connect( G_OBJECT(priv->twin_item), "property-changed", - G_CALLBACK(metadata_widget_property_update), self); - gtk_label_set_text( GTK_LABEL(priv->container_label), - dbusmenu_menuitem_property_get( priv->twin_item, - DBUSMENU_METADATA_MENUITEM_ALBUM)); - metadata_widget_style_labels( self, GTK_LABEL(priv->container_label)); - - gtk_label_set_text( GTK_LABEL(priv->piece_label), - dbusmenu_menuitem_property_get( priv->twin_item, - DBUSMENU_METADATA_MENUITEM_TITLE)); - metadata_widget_style_labels( self, GTK_LABEL(priv->piece_label)); - gtk_label_set_text( GTK_LABEL(priv->artist_label), - dbusmenu_menuitem_property_get( priv->twin_item, - DBUSMENU_METADATA_MENUITEM_ARTIST)); - metadata_widget_style_labels( self, GTK_LABEL(priv->artist_label)); - - g_string_erase(priv->image_path, 0, -1); - const gchar *arturl = dbusmenu_menuitem_property_get( priv->twin_item, - DBUSMENU_METADATA_MENUITEM_ARTURL ); - - gtk_label_set_label (GTK_LABEL(priv->player_label), - dbusmenu_menuitem_property_get(priv->twin_item, - DBUSMENU_METADATA_MENUITEM_PLAYER_NAME)); - - metadata_widget_set_icon(self); - - if (arturl != NULL){ - g_string_overwrite( priv->image_path, - 0, - arturl); - // if its a remote image queue a redraw incase the download took too long - if (g_str_has_prefix (arturl, g_get_user_cache_dir())){ - gtk_widget_queue_draw(GTK_WIDGET(self)); - } - } - metadata_widget_handle_resizing (self); -} - - /** - * transport_new: - * @returns: a new #MetadataWidget. - **/ -GtkWidget* -metadata_widget_new(DbusmenuMenuitem *item) -{ - GtkWidget* widget = g_object_new(METADATA_WIDGET_TYPE, NULL); - metadata_widget_set_twin_item ( METADATA_WIDGET(widget), - item ); - return widget; -} - diff --git a/src/metadata-widget.h b/src/metadata-widget.h deleted file mode 100644 index fc6944e..0000000 --- a/src/metadata-widget.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#ifndef __METADATA_WIDGET_H__ -#define __METADATA_WIDGET_H__ - -#include <gtk/gtk.h> -#include <libdbusmenu-gtk/menuitem.h> - -G_BEGIN_DECLS - -#define METADATA_WIDGET_TYPE (metadata_widget_get_type ()) -#define METADATA_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), METADATA_WIDGET_TYPE, MetadataWidget)) -#define METADATA_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), METADATA_WIDGET_TYPE, MetadataWidgetClass)) -#define IS_METADATA_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), METADATA_WIDGET_TYPE)) -#define IS_METADATA_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), METADATA_WIDGET_TYPE)) -#define METADATA_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), METADATA_WIDGET_TYPE, MetadataWidgetClass)) - -typedef struct _MetadataWidget MetadataWidget; -typedef struct _MetadataWidgetClass MetadataWidgetClass; - -struct _MetadataWidgetClass { - GtkMenuItemClass parent_class; -}; - -struct _MetadataWidget { - GtkMenuItem parent; -}; - -GType metadata_widget_get_type (void); -GtkWidget* metadata_widget_new(DbusmenuMenuitem *twin_item); - -G_END_DECLS - -#endif - diff --git a/src/mpris2-controller.vala b/src/mpris2-controller.vala deleted file mode 100644 index 9230a59..0000000 --- a/src/mpris2-controller.vala +++ /dev/null @@ -1,286 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -using Dbusmenu; -using Transport; - -public class Mpris2Controller : GLib.Object -{ - public const int MAX_PLAYLIST_COUNT = 100; - - public MprisRoot mpris2_root {get; construct;} - public MprisPlayer player {get; construct;} - public MprisPlaylists playlists {get; construct;} - public FreeDesktopProperties properties_interface {get; construct;} - public PlayerController owner {get; construct;} - - public Mpris2Controller(PlayerController ctrl) - { - GLib.Object(owner: ctrl); - } - - construct{ - try { - this.mpris2_root = Bus.get_proxy_sync ( BusType.SESSION, - this.owner.dbus_name, - "/org/mpris/MediaPlayer2" ); - this.player = Bus.get_proxy_sync ( BusType.SESSION, - this.owner.dbus_name, - "/org/mpris/MediaPlayer2" ); - this.properties_interface = Bus.get_proxy_sync ( BusType.SESSION, - "org.freedesktop.Properties.PropertiesChanged", - "/org/mpris/MediaPlayer2" ); - this.properties_interface.PropertiesChanged.connect ( property_changed_cb ); - if ( this.owner.use_playlists == true ){ - this.playlists = Bus.get_proxy_sync ( BusType.SESSION, - this.owner.dbus_name, - "/org/mpris/MediaPlayer2" ); - this.playlists.PlaylistChanged.connect (on_playlistdetails_changed); - } - } - catch (IOError e) { - critical("Problems connecting to the session bus - %s", e.message); - } - } - /* - * property_changed_cb - * Called when a property changed signal is emitted from any of mpris - * objects on the bus. - * Note that the signal will be received by each instance for each player - * and at that moment there is no way to know what player that signal - * came from therefore it is necessary to query each relevant property - * to update the respective dbusmenuitem property inorder to keep the UI in sync - * Please also note due to some race condition in the depths of gdbus - * a timeout is needed between receiving the prop update and query the respective property. - * This can be seen at various points below. - */ - public void property_changed_cb ( string interface_source, - HashTable<string, Variant?> changed_properties, - string[] invalid ) - { - if ( changed_properties == null || - interface_source.has_prefix ( MPRIS_PREFIX ) == false ){ - warning("Property-changed hash is null or this is an interface that doesn't concern us"); - return; - } - Variant? play_v = changed_properties.lookup("PlaybackStatus"); - if(play_v != null){ - string state = this.player.PlaybackStatus; - Timeout.add ( 200, ensure_correct_playback_status ); - Transport.State p = (Transport.State)this.determine_play_state(state); - (this.owner.custom_items[PlayerController.widget_order.TRANSPORT] as TransportMenuitem).change_play_state(p); - } - Variant? meta_v = changed_properties.lookup("Metadata"); - if(meta_v != null) - { - Timeout.add ( 200, ensure_correct_metadata ); - } - Variant? playlist_v = changed_properties.lookup("ActivePlaylist"); - if ( playlist_v != null && this.owner.use_playlists == true ){ - Timeout.add (500, this.fetch_active_playlist); - } - Variant? playlist_count_v = changed_properties.lookup("PlaylistCount"); - if ( playlist_count_v != null && this.owner.use_playlists == true ){ - this.fetch_playlists.begin(); - this.fetch_active_playlist(); - } - Variant? playlist_orderings_v = changed_properties.lookup("Orderings"); - if ( playlist_orderings_v != null && this.owner.use_playlists == true ){ - this.fetch_playlists.begin(); - this.fetch_active_playlist(); - } - Variant? identity_v = changed_properties.lookup("Identity"); - if (identity_v != null){ - MetadataMenuitem md = this.owner.custom_items[PlayerController.widget_order.METADATA] as MetadataMenuitem; - md.alter_label (this.mpris2_root.Identity); - } - } - - private bool ensure_correct_metadata () - { - GLib.HashTable<string, Variant?> changed_updates = clean_metadata(); - PlayerItem metadata = this.owner.custom_items[PlayerController.widget_order.METADATA]; - metadata.reset (MetadataMenuitem.relevant_attributes_for_ui()); - metadata.update ( changed_updates, - MetadataMenuitem.relevant_attributes_for_ui()); - MetadataMenuitem md = this.owner.custom_items[PlayerController.widget_order.METADATA] as MetadataMenuitem; - bool collapsing = !metadata.populated(MetadataMenuitem.relevant_attributes_for_ui()); - md.should_collapse(collapsing); - - return false; - } - - private bool ensure_correct_playback_status() - { - Transport.State p = (Transport.State)this.determine_play_state(this.player.PlaybackStatus); - (this.owner.custom_items[PlayerController.widget_order.TRANSPORT] as TransportMenuitem).change_play_state(p); - return false; - } - - private GLib.HashTable<string, Variant?>? clean_metadata() - { - GLib.HashTable<string, Variant?> changed_updates = this.player.Metadata; - - Variant? artist_v = this.player.Metadata.lookup("xesam:artist"); - if(artist_v != null){ - string display_artists; - // Accomodate Spotify (should return 'as' and not 's') - if(artist_v.get_type_string() == "s"){ - display_artists = artist_v.get_string(); - } - else{ - string[] artists = artist_v.dup_strv(); - display_artists = string.joinv(", ", artists); - } - changed_updates.replace("xesam:artist", display_artists); - } - return changed_updates; - } - - private Transport.State determine_play_state(string? status){ - if(status != null && status == "Playing"){ - return Transport.State.PLAYING; - } - return Transport.State.PAUSED; - } - - public void initial_update() - { - Transport.State update; - - if(this.player.PlaybackStatus == null){ - update = Transport.State.PAUSED; - } - else{ - update = determine_play_state (this.player.PlaybackStatus); - } - if (this.mpris2_root.Identity != null){ - MetadataMenuitem md = this.owner.custom_items[PlayerController.widget_order.METADATA] as MetadataMenuitem; - md.alter_label (this.mpris2_root.Identity); - } - (this.owner.custom_items[PlayerController.widget_order.TRANSPORT] as TransportMenuitem).change_play_state (update); - GLib.HashTable<string, Value?>? cleaned_metadata = this.clean_metadata(); - this.owner.custom_items[PlayerController.widget_order.METADATA].update (cleaned_metadata, - MetadataMenuitem.attributes_format()); - - if ( this.owner.use_playlists == true ){ - this.fetch_playlists.begin(); - this.fetch_active_playlist(); - } - } - - public void transport_update(Transport.Action command) - { - if(command == Transport.Action.PLAY_PAUSE){ - this.player.PlayPause.begin(); - } - else if(command == Transport.Action.PREVIOUS){ - this.player.Previous.begin(); - } - else if(command == Transport.Action.NEXT){ - this.player.Next.begin(); - } - else if(command == Transport.Action.REWIND){ - this.player.Seek.begin(-500000); - } - else if(command == Transport.Action.FORWIND){ - this.player.Seek.begin(400000); - } - } - - public bool connected() - { - return (this.player != null && this.mpris2_root != null); - } - - public void expose(uint timestmap) - { - if (this.connected() == true) { - this.mpris2_root.Raise.begin(); - } - } - - private void on_playlistdetails_changed (PlaylistDetails details) - { - PlaylistsMenuitem playlists_item = this.owner.custom_items[PlayerController.widget_order.PLAYLISTS] as PlaylistsMenuitem; - playlists_item.update_individual_playlist (details); - } - - public async void fetch_playlists() - { - PlaylistDetails[] current_playlists = null; - - try{ - current_playlists = yield this.playlists.GetPlaylists (0, - MAX_PLAYLIST_COUNT, - "Alphabetical", - false); - } - catch (IOError e){ - return; - } - - if( current_playlists != null ){ - PlaylistsMenuitem playlists_item = this.owner.custom_items[PlayerController.widget_order.PLAYLISTS] as PlaylistsMenuitem; - playlists_item.update(current_playlists); - } - else{ - warning(" Playlists are on but %s is returning no current_playlists ?", - this.owner.app_info.get_name()); - this.owner.use_playlists = false; - } - } - - private bool validate_playlists_details() - { - if (this.playlists.ActivePlaylist == null){ - return false; - } - if (this.playlists.ActivePlaylist.valid == false){ - return false; - } - if (this.playlists.ActivePlaylist.details == null){ - return false; - } - if (this.playlists.ActivePlaylist.details.path == null || - this.playlists.ActivePlaylist.details.name == null){ - return false; - } - return true; - } - - private bool fetch_active_playlist() - { - if (this.validate_playlists_details() == false){ - return false; - } - PlaylistsMenuitem playlists_item = this.owner.custom_items[PlayerController.widget_order.PLAYLISTS] as PlaylistsMenuitem; - playlists_item.active_playlist_update ( this.playlists.ActivePlaylist.details ); - return false; - } - - public void activate_playlist (ObjectPath path) - { - try{ - this.playlists.ActivatePlaylist.begin(path); - } - catch(IOError e){ - warning ("Could not activate playlist %s because %s", (string)path, e.message); - } - } -} diff --git a/src/mpris2-watcher.vala b/src/mpris2-watcher.vala index cdfb9c6..4a1ab6e 100644 --- a/src/mpris2-watcher.vala +++ b/src/mpris2-watcher.vala @@ -69,7 +69,7 @@ public class Mpris2Watcher : GLib.Object // At startup check to see if there are clients up that we are interested in // More relevant for development and daemon's like mpd. - public async void check_for_active_clients() + async void check_for_active_clients() { Variant interfaces; @@ -94,12 +94,12 @@ public class Mpris2Watcher : GLib.Object MprisRoot? mpris2_root = this.create_mpris_root(address); if (mpris2_root == null) return; bool use_playlists = this.supports_playlists ( address ); - client_appeared (mpris2_root.DesktopEntry, address, use_playlists); + client_appeared (mpris2_root.DesktopEntry + ".desktop", address, use_playlists); } } } - public void name_owner_changed (DBusConnection con, string sender, string object_path, + void name_owner_changed (DBusConnection con, string sender, string object_path, string interface_name, string signal_name, Variant parameters) { string name, previous_owner, current_owner; @@ -116,7 +116,7 @@ public class Mpris2Watcher : GLib.Object else if (previous_owner == "" && current_owner != "") { debug ("Client '%s' has appeared", name); bool use_playlists = this.supports_playlists ( name ); - client_appeared (mpris2_root.DesktopEntry, name, use_playlists); + client_appeared (mpris2_root.DesktopEntry + ".desktop", name, use_playlists); } } diff --git a/src/music-player-bridge.vala b/src/music-player-bridge.vala deleted file mode 100644 index 59ced36..0000000 --- a/src/music-player-bridge.vala +++ /dev/null @@ -1,305 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -using Dbusmenu; -using Gee; -using GLib; - -public class MusicPlayerBridge : GLib.Object -{ - const int DEVICE_ITEMS_COUNT = 3; - - private SettingsManager settings_manager; - private Dbusmenu.Menuitem root_menu; - private HashMap<string, PlayerController> registered_clients; - private HashMap<string, string> file_monitors; - private HashMap<string, string> mpris_to_desktop; - private Mpris2Watcher watcher; - - public MusicPlayerBridge() - { - } - - construct{ - this.registered_clients = new HashMap<string, PlayerController> (); - this.file_monitors = new HashMap<string, string> (); - this.mpris_to_desktop = new HashMap<string, string> (); - this.settings_manager = new SettingsManager(); - this.settings_manager.blacklist_updates.connect ( this.on_blacklist_update ); - this.settings_manager.preferred_updates.connect ( this.on_preferred_update ); - } - - private void on_blacklist_update ( string[] blacklist ) - { - debug("some blacklist update"); - - foreach(var desktop_id in blacklist){ - string key = desktop_id; - if (this.registered_clients.has_key (key)){ - debug ("Apparently %s is now blacklisted - remove thy self", key); - this.registered_clients[key].remove_from_menu(); - this.registered_clients.unset (key); - } - } - // double check present players to ensure dynamic removal/addition - this.watcher.check_for_active_clients.begin(); - } - - private void on_preferred_update ( Gee.ArrayList<string> preferred ) - { - debug ("Preferred players update. Clearing current preferred players..."); - - foreach (var player_controller in this.registered_clients.values) { - player_controller.set_as_preferred (false); - } - - foreach (var desktop_id in preferred) { - string key = desktop_id; - if (this.registered_clients.has_key (key)) { - debug ("Setting %s as preferred player", key); - this.registered_clients[key].set_as_preferred (true); - } - } - } - - private void try_to_add_inactive_familiar_clients() - { - var preferred_players = this.settings_manager.fetch_preferred (); - foreach ( string desktop in this.settings_manager.fetch_interested()){ - debug ( "interested client found : %s", desktop ); - AppInfo? app_info = create_app_info ( desktop.concat( ".desktop" ) ); - if ( app_info == null ){ - warning ( "Could not create app_info for path %s \n Getting out of here ", - desktop ); - continue; - } - bool is_preferred = desktop in preferred_players; - PlayerController ctrl = new PlayerController ( this.root_menu, - app_info, - null, - this.fetch_icon_name(desktop), - calculate_menu_position(), - null, - PlayerController.state.OFFLINE, - is_preferred ); - var mpris_key = desktop; - this.registered_clients.set(mpris_key, ctrl); - this.establish_file_monitoring (app_info, mpris_key); - } - } - - private void establish_file_monitoring (AppInfo info, string mpris_key){ - DesktopAppInfo desktop_info = info as DesktopAppInfo; - var file_path = desktop_info.get_filename (); - File f = File.new_for_path (file_path); - try { - FileMonitor monitor = f.monitor (FileMonitorFlags.SEND_MOVED, null); - unowned FileMonitor weak_monitor = monitor; - monitor.changed.connect ((desktop_file, other_file, event_type) => { - this.relevant_desktop_file_changed (desktop_file, other_file, event_type, weak_monitor); - }); - monitor.ref(); // will be unref()ed by relevant_desktop_file_changed() - GLib.debug ("monitoring file '%s'", file_path); - this.file_monitors.set (file_path, mpris_key); - } - catch (Error e){ - warning ("Unable to create a file monitor for %s", info.get_name()); - return; - } - } - - private void relevant_desktop_file_changed (File desktop_file, - File? other_file, - FileMonitorEvent event_type, - FileMonitor monitor) - { - if (event_type != FileMonitorEvent.DELETED) - return; - - string? path = desktop_file.get_path (); - if (path == null){ - warning ("relevant_desktop_file_changed is returning a file with no path !"); - return; - } - if (!this.file_monitors.has_key (path)){ - warning ("relevant_desktop_file_changed is returning a file which we know nothing about - %s", - path); - return; - } - - var mpris_key = this.file_monitors[path]; - GLib.debug ("file \"%s\" was removed; stopping monitoring \"%s\"", path, mpris_key); - this.registered_clients[mpris_key].remove_from_menu(); - this.settings_manager.remove_interested (mpris_key); - this.registered_clients.unset (mpris_key); - monitor.cancel (); - monitor.unref(); - } - - private int calculate_menu_position() - { - if(this.registered_clients.size == 0){ - return DEVICE_ITEMS_COUNT; - } - else{ - return (DEVICE_ITEMS_COUNT + (this.registered_clients.size * PlayerController.WIDGET_QUANTITY)); - } - } - - public void client_has_become_available ( string desktop, - string dbus_name, - bool use_playlists ) - { - if (desktop == null || desktop == ""){ - warning("Client %s attempting to register without desktop entry being set on the mpris root", - dbus_name); - return; - } - if (desktop in this.settings_manager.fetch_blacklist()) { - debug ("Client %s attempting to register but I'm afraid it is blacklisted", - desktop); - return; - } - - debug ( "client_has_become_available %s", desktop ); - AppInfo? app_info = create_app_info ( desktop.concat( ".desktop" ) ); - if ( app_info == null ){ - warning ( "Could not create app_info for path %s \n Getting out of here ", - desktop ); - return; - } - - var mpris_key = desktop; - bool is_preferred = desktop in this.settings_manager.fetch_preferred (); - - mpris_to_desktop.set (dbus_name, desktop); - if ( this.registered_clients.has_key (mpris_key) == false ){ - debug("New client has registered that we have not seen before: %s", dbus_name ); - PlayerController ctrl = new PlayerController ( this.root_menu, - app_info, - dbus_name, - this.fetch_icon_name(desktop), - this.calculate_menu_position(), - use_playlists, - PlayerController.state.READY, - is_preferred); - this.registered_clients.set ( mpris_key, ctrl ); - debug ( "Have not seen this %s before, new controller created.", desktop ); - this.settings_manager.add_interested ( desktop ); - this.establish_file_monitoring (app_info, mpris_key); - debug ( "application added to the interested list" ); - } - else{ - this.registered_clients[mpris_key].use_playlists = use_playlists; - this.registered_clients[mpris_key].update_state ( PlayerController.state.READY ); - this.registered_clients[mpris_key].activate ( dbus_name ); - debug("Application has already registered - awaken the hibernation: %s with playlists %s \n", dbus_name, use_playlists.to_string() ); - } - } - - public void client_has_vanished ( string mpris_root_interface ) - { - debug("\n MusicPlayerBridge -> client with dbus interface %s has vanished", - mpris_root_interface ); - if (root_menu != null){ - debug("\n attempt to remove %s", mpris_root_interface); - if (mpris_to_desktop.has_key(mpris_root_interface)){ - var mpris_key = mpris_to_desktop[mpris_root_interface]; - mpris_to_desktop.unset(mpris_root_interface); - if ( mpris_key != null && this.registered_clients.has_key(mpris_key)){ - registered_clients[mpris_key].hibernate(); - debug("\n Successively offlined client %s", mpris_key); - } - } - } - } - - public void set_root_menu_item ( Dbusmenu.Menuitem menu ) - { - this.root_menu = menu; - this.try_to_add_inactive_familiar_clients(); - this.watcher = new Mpris2Watcher (); - this.watcher.client_appeared.connect (this.client_has_become_available); - this.watcher.client_disappeared.connect (this.client_has_vanished); - } - - public void enable_player_specific_items_for_client (string object_path, - string desktop_id) - { - var mpris_key = desktop_id; - if (this.registered_clients.has_key (mpris_key) == false){ - warning ("we don't have a client with desktop id %s registered", desktop_id); - return; - } - this.registered_clients[mpris_key].enable_player_specific_items(object_path); - } - - public void enable_track_specific_items_for_client (string object_path, - string desktop_id) - { - var mpris_key = desktop_id; - if (this.registered_clients.has_key (mpris_key) == false){ - warning ("we don't have a client with desktop id %s registered", desktop_id); - return; - } - this.registered_clients[mpris_key].enable_track_specific_items(object_path); - } - - private static AppInfo? create_app_info ( string desktop ) - { - DesktopAppInfo info = new DesktopAppInfo ( desktop ); - if ( desktop == null || info == null ){ - warning ( "Could not create a desktopappinfo instance from app: %s", desktop ); - return null; - } - GLib.AppInfo app_info = info as GLib.AppInfo; - return app_info; - } - - private static string? fetch_icon_name(string desktop) - { - // We know the appinfo is good because it was loaded in the previous reg step. - DesktopAppInfo info = new DesktopAppInfo ( desktop.concat( ".desktop" ) ) ; - KeyFile desktop_keyfile = new KeyFile (); - try{ - desktop_keyfile.load_from_file (info.get_filename(), KeyFileFlags.NONE); - } - catch(GLib.FileError error){ - warning("Error loading keyfile - FileError"); - return null; - } - catch(GLib.KeyFileError error){ - warning("Error loading keyfile - KeyFileError"); - return null; - } - - try{ - return desktop_keyfile.get_string (KeyFileDesktop.GROUP, - KeyFileDesktop.KEY_ICON); - } - catch(GLib.KeyFileError error){ - warning("Error trying to fetch the icon name from the keyfile"); - return null; - } - } -} - - - - diff --git a/src/mute-menu-item.c b/src/mute-menu-item.c deleted file mode 100644 index 0e6a46f..0000000 --- a/src/mute-menu-item.c +++ /dev/null @@ -1,154 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <glib/gi18n.h> - -#include "common-defs.h" -#include "mute-menu-item.h" -#include "pulseaudio-mgr.h" - -typedef struct _MuteMenuItemPrivate MuteMenuItemPrivate; - -struct _MuteMenuItemPrivate { - DbusmenuMenuitem* button; -}; - -#define MUTE_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MUTE_MENU_ITEM_TYPE, MuteMenuItemPrivate)) - -/* Prototypes */ -static void mute_menu_item_class_init (MuteMenuItemClass *klass); -static void mute_menu_item_init (MuteMenuItem *self); -static void mute_menu_item_dispose (GObject *object); -static void mute_menu_item_finalize (GObject *object); -static void mute_menu_item_set_global_mute_from_ui (gpointer user_data); - -G_DEFINE_TYPE (MuteMenuItem, mute_menu_item, G_TYPE_OBJECT); - -static void -mute_menu_item_class_init (MuteMenuItemClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (MuteMenuItemPrivate)); - - object_class->dispose = mute_menu_item_dispose; - object_class->finalize = mute_menu_item_finalize; - - return; -} - -static void -mute_menu_item_init (MuteMenuItem *self) -{ - g_debug("Building new Mute Menu Item"); - MuteMenuItemPrivate* priv = MUTE_MENU_ITEM_GET_PRIVATE(self); - priv->button = NULL; - priv->button = dbusmenu_menuitem_new(); - - dbusmenu_menuitem_property_set(priv->button, - DBUSMENU_MENUITEM_PROP_TYPE, - DBUSMENU_MUTE_MENUITEM_TYPE); - - dbusmenu_menuitem_property_set_bool (priv->button, - DBUSMENU_MENUITEM_PROP_VISIBLE, - TRUE); - - g_signal_connect (G_OBJECT (priv->button), - DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK (mute_menu_item_set_global_mute_from_ui), - self); - return; -} - -static void -mute_menu_item_dispose (GObject *object) -{ - G_OBJECT_CLASS (mute_menu_item_parent_class)->dispose (object); - return; -} - -static void -mute_menu_item_finalize (GObject *object) -{ - G_OBJECT_CLASS (mute_menu_item_parent_class)->finalize (object); -} - -static void -mute_menu_item_set_global_mute_from_ui (gpointer user_data) -{ - g_return_if_fail (DBUSMENU_IS_MENUITEM (user_data)); - DbusmenuMenuitem* button = DBUSMENU_MENUITEM (user_data); - gboolean current_value = dbusmenu_menuitem_property_get_bool (button, - DBUSMENU_MUTE_MENUITEM_VALUE); - gboolean new_value = !current_value; - pm_update_mute (new_value); -} - -void -mute_menu_item_update (MuteMenuItem* item, gboolean value_update) -{ - MuteMenuItemPrivate* priv = MUTE_MENU_ITEM_GET_PRIVATE (item); - - dbusmenu_menuitem_property_set_bool (priv->button, - DBUSMENU_MUTE_MENUITEM_VALUE, - value_update); - dbusmenu_menuitem_property_set (priv->button, - DBUSMENU_MENUITEM_PROP_LABEL, - value_update == FALSE ? _("Mute") : _("Unmute")); -} - -void -mute_menu_item_enable (MuteMenuItem* item, gboolean active) -{ - MuteMenuItemPrivate* priv = MUTE_MENU_ITEM_GET_PRIVATE (item); - dbusmenu_menuitem_property_set_bool (priv->button, - DBUSMENU_MENUITEM_PROP_VISIBLE, - TRUE); - - dbusmenu_menuitem_property_set_bool (priv->button, - DBUSMENU_MENUITEM_PROP_ENABLED, - active); -} - -DbusmenuMenuitem* -mute_menu_item_get_button (MuteMenuItem* item) -{ - MuteMenuItemPrivate* priv = MUTE_MENU_ITEM_GET_PRIVATE (item); - return priv->button; -} - -gboolean -mute_menu_item_is_muted (MuteMenuItem* item) -{ - MuteMenuItemPrivate* priv = MUTE_MENU_ITEM_GET_PRIVATE (item); - return dbusmenu_menuitem_property_get_bool (priv->button, - DBUSMENU_MUTE_MENUITEM_VALUE); -} - -MuteMenuItem* -mute_menu_item_new (gboolean initial_update, gboolean enabled) -{ - MuteMenuItem *self = g_object_new (MUTE_MENU_ITEM_TYPE, NULL); - mute_menu_item_update (self, initial_update); - mute_menu_item_enable (self, enabled); - return self; -} diff --git a/src/mute-menu-item.h b/src/mute-menu-item.h deleted file mode 100644 index 81a4b33..0000000 --- a/src/mute-menu-item.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef __MUTE_MENU_ITEM_H__ -#define __MUTE_MENU_ITEM_H__ - -#include <glib.h> -#include <glib-object.h> -#include <libdbusmenu-glib/menuitem.h> - -G_BEGIN_DECLS - -#define MUTE_MENU_ITEM_TYPE (mute_menu_item_get_type ()) -#define MUTE_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MUTE_MENU_ITEM_TYPE, MuteMenuItem)) -#define MUTE_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MUTE_MENU_ITEM_TYPE, MuteMenuItemClass)) -#define IS_MUTE_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MUTE_MENU_ITEM_TYPE)) -#define IS_MUTE_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MUTE_MENU_ITEM_TYPE)) -#define MUTE_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MUTE_MENU_ITEM_TYPE, MuteMenuItemClass)) - -typedef struct _MuteMenuItem MuteMenuItem; -typedef struct _MuteMenuItemClass MuteMenuItemClass; - -struct _MuteMenuItemClass { - GObjectClass parent_class; -}; - -struct _MuteMenuItem { - GObject parent; -}; - -GType mute_menu_item_get_type (void); - -MuteMenuItem* mute_menu_item_new (); - -void mute_menu_item_update (MuteMenuItem* item, gboolean update); -void mute_menu_item_enable (MuteMenuItem* item, gboolean active); -gboolean mute_menu_item_is_muted (MuteMenuItem* item); - -DbusmenuMenuitem* mute_menu_item_get_button (MuteMenuItem* item); - -G_END_DECLS - -#endif
\ No newline at end of file diff --git a/src/mute-widget.c b/src/mute-widget.c deleted file mode 100644 index 500f575..0000000 --- a/src/mute-widget.c +++ /dev/null @@ -1,134 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Marco Trevisan (Treviño) <mail@3v1n0.net> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <glib.h> -#include "mute-widget.h" -#include "common-defs.h" -#include "indicator-sound.h" - -typedef struct _MuteWidgetPrivate MuteWidgetPrivate; - -struct _MuteWidgetPrivate -{ - DbusmenuMenuitem *item; - GtkMenuItem *gitem; -}; - -#define MUTE_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MUTE_WIDGET_TYPE, MuteWidgetPrivate)) - -/* Prototypes */ -static void mute_widget_class_init (MuteWidgetClass *klass); -static void mute_widget_init (MuteWidget *self); -static void mute_widget_dispose (GObject *object); -static void mute_widget_finalize (GObject *object); - -G_DEFINE_TYPE (MuteWidget, mute_widget, G_TYPE_OBJECT); - -static void -mute_widget_class_init (MuteWidgetClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - gobject_class->dispose = mute_widget_dispose; - gobject_class->finalize = mute_widget_finalize; - g_type_class_add_private (klass, sizeof (MuteWidgetPrivate)); -} - -static void -mute_widget_init (MuteWidget *self) -{ - MuteWidgetPrivate *priv = MUTE_WIDGET_GET_PRIVATE(self); - priv->item = NULL; - priv->gitem = GTK_MENU_ITEM(gtk_menu_item_new ()); -} - -static void -mute_widget_dispose (GObject *object) -{ - G_OBJECT_CLASS (mute_widget_parent_class)->dispose (object); -} - -static void -mute_widget_finalize (GObject *object) -{ - MuteWidget *self = MUTE_WIDGET (object); - MuteWidgetPrivate *priv = MUTE_WIDGET_GET_PRIVATE(self); - - g_object_unref (priv->item); - g_object_unref (G_OBJECT (priv->gitem)); - G_OBJECT_CLASS (mute_widget_parent_class)->finalize (object); -} - -GtkMenuItem * -mute_widget_get_menu_item(MuteWidget *self) -{ - MuteWidgetPrivate *priv = MUTE_WIDGET_GET_PRIVATE(self); - return priv->gitem; -} - -MuteStatus -mute_widget_get_status (MuteWidget *self) -{ - g_return_val_if_fail(self, MUTE_STATUS_UNAVAILABLE); - MuteStatus status = MUTE_STATUS_UNAVAILABLE; - MuteWidgetPrivate *priv = MUTE_WIDGET_GET_PRIVATE(self); - - GVariant *vstatus = dbusmenu_menuitem_property_get_variant(priv->item, - DBUSMENU_MUTE_MENUITEM_VALUE); - - if (g_variant_is_of_type (vstatus, G_VARIANT_TYPE_BOOLEAN)) - { - if (g_variant_get_boolean (vstatus)) - status = MUTE_STATUS_MUTED; - else - status = MUTE_STATUS_UNMUTED; - } - - return status; -} - -void mute_widget_toggle (MuteWidget *self) -{ - g_return_if_fail (self); - MuteWidgetPrivate *priv = MUTE_WIDGET_GET_PRIVATE(self); - gtk_menu_item_activate (priv->gitem); -} - -/** - * mute_widget_new: - * @returns: a new #MuteWidget. - **/ -MuteWidget * -mute_widget_new (DbusmenuMenuitem *item) -{ - MuteWidget* widget = g_object_new(MUTE_WIDGET_TYPE, NULL); - MuteWidgetPrivate* priv = MUTE_WIDGET_GET_PRIVATE(widget); - priv->item = g_object_ref(item); - - GVariant *label = dbusmenu_menuitem_property_get_variant(priv->item, - DBUSMENU_MENUITEM_PROP_LABEL); - - if (g_variant_is_of_type(label, G_VARIANT_TYPE_STRING)) - gtk_menu_item_set_label(priv->gitem, g_variant_get_string(label, NULL)); - - return widget; -} diff --git a/src/mute-widget.h b/src/mute-widget.h deleted file mode 100644 index 88ddd41..0000000 --- a/src/mute-widget.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Marco Trevisan (Treviño) <mail@3v1n0.net> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#ifndef __MUTE_WIDGET_H__ -#define __MUTE_WIDGET_H__ - -#include <glib.h> -#include <glib-object.h> -#include <gtk/gtk.h> -#include <libdbusmenu-gtk/menuitem.h> -#include <libindicator/indicator-object.h> - -G_BEGIN_DECLS - -#define MUTE_WIDGET_TYPE (mute_widget_get_type ()) -#define MUTE_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MUTE_WIDGET_TYPE, MuteWidget)) -#define MUTE_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MUTE_WIDGET_TYPE, MuteWidgetClass)) -#define IS_MUTE_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MUTE_WIDGET_TYPE)) -#define IS_MUTE_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MUTE_WIDGET_TYPE)) -#define MUTE_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MUTE_WIDGET_TYPE, MuteWidgetClass)) - -typedef struct _MuteWidget MuteWidget; -typedef struct _MuteWidgetClass MuteWidgetClass; - -struct _MuteWidgetClass { - GObjectClass parent_class; -}; - -struct _MuteWidget { - GObject parent; -}; - -typedef enum { - MUTE_STATUS_UNAVAILABLE, - MUTE_STATUS_MUTED, - MUTE_STATUS_UNMUTED -} MuteStatus; - -GType mute_widget_get_type (void) G_GNUC_CONST; -MuteWidget* mute_widget_new (DbusmenuMenuitem *item); -MuteStatus mute_widget_get_status (MuteWidget *self); -void mute_widget_toggle (MuteWidget *self); -GtkMenuItem *mute_widget_get_menu_item (MuteWidget *self); - -G_END_DECLS - -#endif - diff --git a/src/player-activator.vala b/src/player-activator.vala deleted file mode 100644 index 7437a35..0000000 --- a/src/player-activator.vala +++ /dev/null @@ -1,199 +0,0 @@ -/* -Copyright 2013 Canonical Ltd. - -Authors: - Marco Trevisan <marco.trevisan@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -[DBus (name = "org.gtk.Application")] -public interface DBusGtkApplication : Object { - public abstract void Activate(GLib.HashTable<string, Variant?> platform_data) throws IOError; -} - -public class PlayerActivator : GLib.Object -{ - public PlayerController owner {get; construct;} - - private bool gtk_application_searched = false; - private DBusGtkApplication gtk_application; - private Bamf.Application bamf_application; - - private const uint MAX_BAMF_APPLICATION_WAIT_MS = 1000; - private int64 last_check_time; - - public PlayerActivator(PlayerController ctrl) - { - GLib.Object(owner: ctrl); - } - - public void activate(uint timestamp) - { - if (!activate_gtk_appplication(timestamp)) { - if (!activate_bamf_appplication(timestamp)) { - // Let's wait BAMF to update its windows list - this.last_check_time = get_monotonic_time(); - - Idle.add(() => { - bool activated = activate_bamf_appplication(timestamp); - int64 waited = (get_monotonic_time() - this.last_check_time) / 1000; - return !activated && waited < MAX_BAMF_APPLICATION_WAIT_MS; - }); - } - } - } - - private bool activate_gtk_appplication(uint timestamp) - { - this.setup_gtk_application(); - - if (this.gtk_application == null) { - return false; - } - - var context = Gdk.Display.get_default().get_app_launch_context(); - context.set_timestamp(timestamp); - - var data = new GLib.HashTable<string, Variant?>(str_hash, str_equal); - data["desktop-startup-id"] = context.get_startup_notify_id(this.owner.app_info, new GLib.List<GLib.File>()); - - try { - this.gtk_application.Activate(data); - } - catch (IOError e) { - return false; - } - - return true; - } - - private void setup_gtk_application() - { - if (owner.current_state != PlayerController.state.CONNECTED) - return; - - if (this.gtk_application != null || this.gtk_application_searched) - return; - - try { - var connection = Bus.get_sync(BusType.SESSION); - var name = this.owner.dbus_name; - string gtk_application_path; - this.find_iface_path(connection, name, "/", "org.gtk.Application", out gtk_application_path); - this.gtk_application_searched = true; - - if (gtk_application_path != null) { - this.gtk_application = Bus.get_proxy_sync(BusType.SESSION, this.owner.dbus_name, gtk_application_path); - } - } catch (Error e) { - return; - } - } - - private void find_iface_path(DBusConnection connection, string name, string path, string target_iface, out string found_path) - { - found_path = null; - DBusNodeInfo node = null; - - try { - unowned string xml_string; - var xml = connection.call_sync(name, path, "org.freedesktop.DBus.Introspectable", "Introspect", null, new VariantType("(s)"), DBusCallFlags.NONE, 1000); - xml.get("(&s)", out xml_string); - node = new DBusNodeInfo.for_xml(xml_string); - } catch (Error e) { - return; - } - - if (node == null) { - return; - } - - foreach (var iface in node.interfaces) { - if (iface.name == target_iface) { - found_path = path; - return; - } - } - - bool is_root = (path == "/"); - - foreach (var subnode in node.nodes) { - string new_path = path; - - if (!is_root) { - new_path += "/"; - } - - new_path += subnode.path; - - find_iface_path(connection, name, new_path, target_iface, out found_path); - - if (found_path != null) { - return; - } - } - } - - private void setup_bamf_application() - { - this.bamf_application = null; - var desktop_app = this.owner.app_info as DesktopAppInfo; - - if (desktop_app == null) - return; - - foreach (var app in Bamf.Matcher.get_default().get_applications()) { - if (app.get_desktop_file() == desktop_app.get_filename()) { - this.bamf_application = app; - break; - } - } - } - - private bool activate_bamf_appplication(uint timestamp) - { - this.setup_bamf_application(); - - if (this.bamf_application == null) - return false; - - bool focused = false; - var dpy = Gdk.Display.get_default(); - - foreach (var win in this.bamf_application.get_windows()) { - X.Window xid = 0; - - if (win is Bamf.Window) { - if (win.get_window_type() != Bamf.WindowType.NORMAL) - continue; - - xid = win.get_xid(); - } - else if (win is Bamf.Tab) { - xid = (X.Window) (win as Bamf.Tab).get_xid(); - } - - if (xid > 0) { - var xwin = Gdk.X11Window.foreign_new_for_display(dpy, xid); - - if (xwin != null) { - xwin.focus(timestamp); - focused = true; - } - } - } - - return focused; - } -} diff --git a/src/player-controller.vala b/src/player-controller.vala deleted file mode 100644 index 8c3339e..0000000 --- a/src/player-controller.vala +++ /dev/null @@ -1,252 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -using Dbusmenu; -using Gee; - -public class PlayerController : GLib.Object -{ - public const int WIDGET_QUANTITY = 4; - - public enum widget_order{ - SEPARATOR, - METADATA, - TRANSPORT, - PLAYLISTS - } - - public enum state{ - OFFLINE, - INSTANTIATING, - READY, - CONNECTED, - DISCONNECTED - } - - public int current_state = state.OFFLINE; - - public Dbusmenu.Menuitem root_menu; - public string dbus_name { get; set;} - public ArrayList<PlayerItem> custom_items; - public Mpris2Controller mpris_bridge; - public PlayerActivator player_activator; - public AppInfo? app_info { get; set;} - public int menu_offset { get; set;} - public string icon_name { get; set; } - public bool? use_playlists; - public bool is_preferred { get; private set; } - private SpecificItemsManager track_specific_mgr; - private SpecificItemsManager player_specific_mgr; - - public PlayerController(Dbusmenu.Menuitem root, - GLib.AppInfo app, - string? dbus_name, - string icon_name, - int offset, - bool? use_playlists, - state initial_state, - bool is_preferred) - { - this.use_playlists = use_playlists; - this.root_menu = root; - this.app_info = app; - this.dbus_name = dbus_name; - this.icon_name = icon_name; - this.custom_items = new ArrayList<PlayerItem>(); - this.current_state = initial_state; - this.menu_offset = offset; - this.is_preferred = is_preferred; - - this.construct_widgets(); - this.establish_mpris_connection(); - this.update_layout(); - debug ("New player controller for %s with icon name %s", this.app_info.get_name(), this.icon_name); - } - - public void update_state(state new_state) - { - debug("update_state - player controller %s : new state %i", this.app_info.get_name(), - new_state); - this.current_state = new_state; - this.update_layout(); - } - - public void activate( string dbus_name ) - { - this.dbus_name = dbus_name; - this.establish_mpris_connection(); - } - - /* - instantiate() - The user should be able to start the app from the transport bar when in an offline state - There is a need to wait before the application is on DBus before attempting to access its mpris address - Hence only when the it has registered with us via libindicate do we attempt to kick off mpris communication - */ - public void instantiate(uint timestamp) - { - debug("instantiate in player controller for %s", this.app_info.get_name() ); - - try{ - var context = Gdk.Display.get_default().get_app_launch_context(); - context.set_timestamp(timestamp); - this.app_info.launch(null, context); - this.update_state(state.INSTANTIATING); - } - catch(GLib.Error error){ - warning("Failed to launch app %s with error message: %s", this.app_info.get_name(), - error.message ); - } - } - - public void enable_track_specific_items (string object_path) - { - if (this.track_specific_mgr == null){ - track_specific_mgr = new SpecificItemsManager (this, - object_path, - SpecificItemsManager.category.TRACK); - } - } - - public void enable_player_specific_items (string object_path) - { - if (this.player_specific_mgr == null){ - player_specific_mgr = new SpecificItemsManager (this, - object_path, - SpecificItemsManager.category.PLAYER); - } - } - - public int track_specific_count () - { - if (this.track_specific_mgr == null) { - return 0; - } - return this.track_specific_mgr.proxy_items.size; - } - - private void establish_mpris_connection() - { - if(this.current_state != state.READY || this.dbus_name == null ){ - debug("establish_mpris_connection - Not ready to connect"); - return; - } - debug ( " establish mpris connection - use playlists value = %s ", - this.use_playlists.to_string() ); - this.mpris_bridge = new Mpris2Controller (this); - this.player_activator = new PlayerActivator (this); - this.determine_state (); - } - - public void remove_from_menu() - { - foreach(PlayerItem item in this.custom_items){ - this.root_menu.child_delete(item); - } - if (this.use_playlists == true){ - PlaylistsMenuitem playlists_menuitem = this.custom_items[widget_order.PLAYLISTS] as PlaylistsMenuitem; - this.root_menu.child_delete (playlists_menuitem.root_item); - } - } - - public void set_as_preferred (bool val) { - this.is_preferred = val; - this.update_layout(); - } - - public void hibernate() - { - update_state(PlayerController.state.OFFLINE); - TransportMenuitem transport = this.custom_items[widget_order.TRANSPORT] as TransportMenuitem; - transport.change_play_state (Transport.State.PAUSED); - this.custom_items[widget_order.METADATA].reset(MetadataMenuitem.relevant_attributes_for_ui()); - MetadataMenuitem md = this.custom_items[widget_order.METADATA] as MetadataMenuitem; - md.toggle_active_triangle (false); - this.mpris_bridge = null; - } - - public void update_layout() - { - PlaylistsMenuitem playlists_menuitem = this.custom_items[widget_order.PLAYLISTS] as PlaylistsMenuitem; - MetadataMenuitem metadata_menuitem = this.custom_items[widget_order.METADATA] as MetadataMenuitem; - if(this.current_state != state.CONNECTED){ - metadata_menuitem.should_collapse (true); - playlists_menuitem.root_item.property_set_bool (MENUITEM_PROP_VISIBLE, - false); - this.custom_items[widget_order.TRANSPORT].property_set_bool (MENUITEM_PROP_VISIBLE, is_preferred); - return; - } - - bool should_collapse = !this.custom_items[widget_order.METADATA].populated (MetadataMenuitem.relevant_attributes_for_ui()); - metadata_menuitem.should_collapse (should_collapse); - - if (is_preferred){ - TransportMenuitem transport = this.custom_items[widget_order.TRANSPORT] as TransportMenuitem; - transport.handle_cached_action(); - } - else{ - this.custom_items[widget_order.TRANSPORT].property_set_bool (MENUITEM_PROP_VISIBLE, - true); - } - playlists_menuitem.root_item.property_set_bool ( MENUITEM_PROP_VISIBLE, - this.use_playlists ); - } - - private void construct_widgets() - { - // Separator item - this.custom_items.add(new PlayerItem(CLIENT_TYPES_SEPARATOR)); - - // Metadata item - MetadataMenuitem metadata_item = new MetadataMenuitem(this); - this.custom_items.add(metadata_item); - - // Transport item - TransportMenuitem transport_item = new TransportMenuitem(this); - this.custom_items.add(transport_item); - - // Playlist item - PlaylistsMenuitem playlist_menuitem = new PlaylistsMenuitem(this); - this.custom_items.add(playlist_menuitem); - - foreach(PlayerItem item in this.custom_items){ - if (this.custom_items.index_of(item) == WIDGET_QUANTITY-1) { - PlaylistsMenuitem playlists_menuitem = item as PlaylistsMenuitem; - root_menu.child_add_position(playlists_menuitem.root_item, this.menu_offset + this.custom_items.index_of(item)); - } - else{ - root_menu.child_add_position (item, - this.menu_offset + this.custom_items.index_of(item)); - } - } - } - - private void determine_state() - { - if(this.mpris_bridge.connected() == true){ - this.update_state(state.CONNECTED); - MetadataMenuitem md = this.custom_items[widget_order.METADATA] as MetadataMenuitem; - md.toggle_active_triangle(true); - this.mpris_bridge.initial_update(); - } - else{ - this.update_state(state.DISCONNECTED); - } - } -} diff --git a/src/player-item.vala b/src/player-item.vala deleted file mode 100644 index 7867653..0000000 --- a/src/player-item.vala +++ /dev/null @@ -1,104 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -using Dbusmenu; -using Gee; - -public class PlayerItem : Dbusmenu.Menuitem -{ - public PlayerController owner {get; construct;} - public string item_type { get; construct; } - public const int EMPTY = -1; - - public PlayerItem(string type) - { - Object(item_type: type); - } - - construct { - this.property_set(MENUITEM_PROP_TYPE, item_type); - } - - public void reset(HashSet<string> attrs){ - foreach(string s in attrs){ - this.property_set_int(s, EMPTY); - } - } - - /** - * update() - * Base update method for playeritems, takes the attributes and the incoming updates - * and attmepts to update the appropriate props on the object. - * Album art is handled separately to deal with remote and local file paths. - */ - public void update(HashTable<string, Variant?> data, HashSet<string> attributes) - { - //debug("PlayerItem::update()"); - if(data == null){ - warning("PlayerItem::Update -> The hashtable was null - just leave it!"); - return; - } - - foreach(string property in attributes){ - string[] input_keys = property.split("-"); - string search_key = input_keys[input_keys.length-1 : input_keys.length][0]; - //debug("search key = %s", search_key); - Variant? v = data.lookup(search_key); - - if (v == null) continue; - - if (v.is_of_type ( VariantType.STRING )){ - string update = v.get_string().strip(); - //debug("with value : %s", update); - if(property.contains("mpris:artUrl")){ - // We know its a metadata instance because thats the only - // object with the arturl prop - MetadataMenuitem metadata = this as MetadataMenuitem; - metadata.fetch_art ( update, property ); - continue; - } - this.property_set(property, update); - } - else if (v.is_of_type (VariantType.INT32 )){ - //debug("with value : %i", v.get_int32()); - this.property_set_int(property, v.get_int32()); - } - else if (v.is_of_type (VariantType.INT64 )){ - //debug("with value : %i", (int)v.get_int64()); - this.property_set_int(property, (int)v.get_int64()); - } - else if(v.is_of_type ( VariantType.BOOLEAN )){ - //debug("with value : %s", v.get_boolean().to_string()); - this.property_set_bool(property, v.get_boolean()); - } - } - } - - public bool populated(HashSet<string> attrs) - { - foreach(string prop in attrs){ - if(property_get_int(prop) != EMPTY){ - return true; - } - } - return false; - } - -} - diff --git a/src/playlists-menu-item.vala b/src/playlists-menu-item.vala deleted file mode 100644 index 4666a50..0000000 --- a/src/playlists-menu-item.vala +++ /dev/null @@ -1,154 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -using Config; -using Dbusmenu; -using DbusmenuPlaylists; -using DbusmenuPlaylist; -using Gee; - - -public class PlaylistsMenuitem : PlayerItem -{ - private HashMap<int, Dbusmenu.Menuitem> current_playlists; - public Menuitem root_item; - - public PlaylistsMenuitem ( PlayerController parent ) - { - Object ( item_type: MENUITEM_TYPE, owner: parent ); - } - - construct{ - this.current_playlists = new HashMap<int, Dbusmenu.Menuitem>(); - this.root_item = new Menuitem(); - this.root_item.property_set ( MENUITEM_PROP_LABEL, _("Choose Playlist") ); - this.root_item.property_set ( MENUITEM_PATH, "" ); - } - - public new void update (PlaylistDetails[] playlists) - { - foreach ( PlaylistDetails detail in playlists ){ - // We don't want to list playlists which are for videos)' - if (this.already_observed(detail) || this.is_video_related(detail)) - continue; - - Dbusmenu.Menuitem menuitem = new Menuitem(); - menuitem.property_set (MENUITEM_PROP_LABEL, - truncate_item_label_if_needs_be (detail.name)); - menuitem.property_set (MENUITEM_PROP_ICON_NAME, "playlist-symbolic"); - - menuitem.property_set (MENUITEM_PATH, (string)detail.path); - menuitem.property_set_bool (MENUITEM_PROP_VISIBLE, true); - menuitem.property_set_bool (MENUITEM_PROP_ENABLED, true); - - menuitem.item_activated.connect(() => { - submenu_item_activated (menuitem.id ); - } - ); - this.current_playlists.set( menuitem.id, menuitem ); - this.root_item.child_append( menuitem ); - debug ("populating valid playlists %s", detail.name); - } - // Finally remove any that might have been deleted - foreach (Dbusmenu.Menuitem item in this.current_playlists.values) { - bool within = false; - foreach (PlaylistDetails detail in playlists){ - if (detail.path == item.property_get (MENUITEM_PATH)) { - within = true; - break; - } - } - if (within == false){ - if (this.root_item.property_get (MENUITEM_PATH) == item.property_get (MENUITEM_PATH)){ - this.root_item.property_set (MENUITEM_PROP_LABEL, _("Choose Playlist")); - } - this.root_item.child_delete (item); - } - } - } - - public void update_individual_playlist (PlaylistDetails new_detail) - { - foreach ( Dbusmenu.Menuitem item in this.current_playlists.values ){ - if (new_detail.path == item.property_get (MENUITEM_PATH)){ - item.property_set (MENUITEM_PROP_LABEL, - truncate_item_label_if_needs_be (new_detail.name)); - } - } - // If its active make sure the name is updated on the root item. - if (this.root_item.property_get (MENUITEM_PATH) == new_detail.path) { - this.root_item.property_set (MENUITEM_PROP_LABEL, - truncate_item_label_if_needs_be (new_detail.name)); - } - } - - private bool already_observed (PlaylistDetails new_detail) - { - foreach ( Dbusmenu.Menuitem item in this.current_playlists.values ){ - var path = item.property_get (MENUITEM_PATH); - if (new_detail.path == path) return true; - } - return false; - } - - private bool is_video_related (PlaylistDetails new_detail) - { - var location = (string)new_detail.path; - if (location.contains ("/VideoLibrarySource/")) return true; - return false; - } - - public void active_playlist_update (PlaylistDetails detail) - { - var update = detail.name; - if ( update == "" ) update = _("Choose Playlist"); - this.root_item.property_set (MENUITEM_PROP_LABEL, - truncate_item_label_if_needs_be(update)); - this.root_item.property_set (MENUITEM_PATH, detail.path); - } - - private void submenu_item_activated (int menu_item_id) - { - if (!this.current_playlists.has_key(menu_item_id)) { - warning( "item %i was activated but we don't have a corresponding playlist", - menu_item_id ); - return; - } - this.owner.mpris_bridge.activate_playlist ( (GLib.ObjectPath)this.current_playlists[menu_item_id].property_get (MENUITEM_PATH) ); - } - - private string truncate_item_label_if_needs_be(string item_label) - { - var result = item_label; - if (item_label.char_count(-1) > 17){ - result = item_label.slice ((long)0, (long)15); - result += "…"; - } - return result; - } - - public static HashSet<string> attributes_format() - { - HashSet<string> attrs = new HashSet<string>(); - attrs.add(MENUITEM_TITLE); - attrs.add(MENUITEM_PLAYLISTS); - return attrs; - } - -} diff --git a/src/pulseaudio-mgr.c b/src/pulseaudio-mgr.c deleted file mode 100644 index f205723..0000000 --- a/src/pulseaudio-mgr.c +++ /dev/null @@ -1,717 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -/**Notes - * - * Approach now is to set up the communication channels, query the server - * fetch its default sink/source. If this fails then fetch the list of sinks/sources - * and take the first one which is not the auto-null sink. - * TODO: need to handle the situation where one chink in this linear chain breaks - * i.e. start off the process again and count the attempts (note different to - reconnect attempts) - */ -#include <pulse/gccmacro.h> -#include <pulse/glib-mainloop.h> -#include <pulse/error.h> - -#include "pulseaudio-mgr.h" -#include "config.h" - -#define RECONNECT_DELAY 5 - - -static void pm_context_state_callback(pa_context *c, void *userdata); -static void pm_subscribed_events_callback (pa_context *c, - enum pa_subscription_event_type t, - uint32_t index, - void* userdata); -static void pm_server_info_callback (pa_context *c, - const pa_server_info *info, - void *userdata); -static void pm_default_sink_info_callback (pa_context *c, - const pa_sink_info *info, - int eol, - void *userdata); -static void pm_default_source_info_callback (pa_context *c, - const pa_source_info *info, - int eol, - void *userdata); -static void pm_sink_info_callback (pa_context *c, - const pa_sink_info *sink, - int eol, - void *userdata); -static void pm_source_info_callback (pa_context *c, - const pa_source_info *info, - int eol, - void *userdata); -static void pm_update_source_info_callback (pa_context *c, - const pa_source_info *info, - int eol, - void *userdata); -static void pm_sink_input_info_callback (pa_context *c, - const pa_sink_input_info *info, - int eol, - void *userdata); -static void pm_update_device (pa_context *c, - const pa_sink_info *info, - int eol, - void *userdata); -static void pm_toggle_mute_for_every_sink_callback (pa_context *c, - const pa_sink_info *sink, - int eol, - void* userdata); -static void pm_source_output_info_callback (pa_context *c, - const pa_source_output_info *info, - int eol, - void *userdata); - -static gboolean reconnect_to_pulse (gpointer user_data); - -static gint connection_attempts = 0; -static gint reconnect_idle_id = 0; -static pa_context *pulse_context = NULL; -static pa_glib_mainloop *pa_main_loop = NULL; - -/** - Entry Point - **/ -void -pm_establish_pulse_connection (Device* device) -{ - pa_main_loop = pa_glib_mainloop_new (g_main_context_default ()); - g_assert (pa_main_loop); - reconnect_to_pulse ((gpointer)device); -} - -/** -close_pulse_activites() -Gracefully close our connection with the Pulse async library. -**/ -void close_pulse_activites() -{ - if (pulse_context != NULL) { - pa_context_unref(pulse_context); - pulse_context = NULL; - } - pa_glib_mainloop_free(pa_main_loop); - pa_main_loop = NULL; -} - -/** -reconnect_to_pulse (gpointer user_data) -Method which connects to the pulse server and is used to track reconnects. - */ -static gboolean -reconnect_to_pulse (gpointer user_data) -{ - g_debug("Attempt a pulse connection"); - g_return_val_if_fail (IS_DEVICE (user_data), FALSE); - - connection_attempts += 1; - if (pulse_context != NULL) { - pa_context_unref(pulse_context); - pulse_context = NULL; - } - - pa_proplist *proplist; - - proplist = pa_proplist_new (); - pa_proplist_sets (proplist, - PA_PROP_APPLICATION_NAME, - "Indicator Sound"); - pa_proplist_sets (proplist, - PA_PROP_APPLICATION_ID, - "com.canonical.indicator.sound"); - pa_proplist_sets (proplist, - PA_PROP_APPLICATION_ICON_NAME, - "multimedia-volume-control"); - pa_proplist_sets (proplist, - PA_PROP_APPLICATION_VERSION, - PACKAGE_VERSION); - - pulse_context = pa_context_new_with_proplist (pa_glib_mainloop_get_api( pa_main_loop ), - NULL, - proplist); - pa_proplist_free (proplist); - g_assert(pulse_context); - pa_context_set_state_callback (pulse_context, - pm_context_state_callback, - user_data); - int result = pa_context_connect (pulse_context, - NULL, - (pa_context_flags_t)PA_CONTEXT_NOFAIL, - NULL); - - if (result < 0) { - g_warning ("Failed to connect context: %s", - pa_strerror (pa_context_errno (pulse_context))); - } - if (connection_attempts > 5){ - return FALSE; - } - else{ - return TRUE; - } -} - -void -pm_update_volume (gint sink_index, pa_cvolume new_volume) -{ - if (sink_index < 0 || pulse_context == NULL){ - g_warning ("pm_update_volume sink index is negative or the context is null"); - return; - } - - if (pa_context_get_state (pulse_context) != PA_CONTEXT_READY ){ - g_warning ("pm_update_volume context is not in a ready state"); - return; - } - - pa_operation *operation = NULL; - - operation = pa_context_set_sink_volume_by_index (pulse_context, - sink_index, - &new_volume, - NULL, - NULL); - if (!operation){ - g_warning ("pm_update_volume operation failed for some reason"); - return; - } - pa_operation_unref (operation); -} - -void -pm_update_mute (gboolean update) -{ - if (pulse_context == NULL){ - g_warning ("pm_update_mute - the context is null"); - return; - } - - if (pa_context_get_state (pulse_context) != PA_CONTEXT_READY ){ - g_warning ("pm_update_mute context is not in a ready state"); - return; - } - - pa_operation *operation = NULL; - - operation = pa_context_get_sink_info_list (pulse_context, - pm_toggle_mute_for_every_sink_callback, - GINT_TO_POINTER (update)); - if (!operation){ - g_warning ("pm_update_mute operation failed for some reason"); - return; - } - pa_operation_unref (operation); -} - -void -pm_update_mic_gain (gint source_index, pa_cvolume new_gain) -{ - if (source_index < 0 || pulse_context == NULL){ - g_warning ("pm_update_mic_gain source index is negative or the context is null"); - return; - } - - if (pa_context_get_state (pulse_context) != PA_CONTEXT_READY ){ - g_warning ("pm_update_mic_gain context is not in a ready state"); - return; - } - - pa_operation *operation = NULL; - - operation = pa_context_set_source_volume_by_index (pulse_context, - source_index, - &new_gain, - NULL, - NULL); - if (!operation){ - g_warning ("pm_update_mic_gain operation failed for some reason"); - return; - } - pa_operation_unref (operation); -} - -void -pm_update_mic_mute (gint source_index, gint mute_update) -{ - if (source_index < 0){ - return; - } - - if (pa_context_get_state (pulse_context) != PA_CONTEXT_READY ){ - g_warning ("pm_update_mic_mute context is not in a ready state"); - return; - } - - pa_operation *operation = NULL; - - operation = pa_context_set_source_mute_by_index (pulse_context, - source_index, - mute_update, - NULL, - NULL); - if (!operation){ - g_warning ("pm_update_mic_mute operation failed for some reason"); - return; - } - pa_operation_unref (operation); -} - -/**********************************************************************************************************************/ -// Pulse-Audio asychronous call-backs -/**********************************************************************************************************************/ - - -static void -pm_subscribed_events_callback (pa_context *c, - enum pa_subscription_event_type t, - uint32_t index, - void* userdata) -{ - if (IS_DEVICE (userdata) == FALSE){ - g_critical ("subscribed events callback - our userdata is not what we think it should be"); - return; - } - Device* sink = DEVICE (userdata); - - switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { - case PA_SUBSCRIPTION_EVENT_SINK: - - // We don't care about any other sink other than the active one. - if (index != device_get_sink_index (sink)) - return; - - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - device_sink_deactivated (sink); - - } - else{ - pa_operation_unref (pa_context_get_sink_info_by_index (c, - index, - pm_update_device, - userdata) ); - } - break; - case PA_SUBSCRIPTION_EVENT_SOURCE: - g_debug ("Looks like source event of some description - index = %i", index); - // We don't care about any other sink other than the active one. - if (index != device_get_source_index (sink)) - return; - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - g_debug ("Source removal event - index = %i", index); - device_deactivate_voip_source (sink, FALSE); - } - else{ - pa_operation_unref (pa_context_get_source_info_by_index (c, - index, - pm_update_source_info_callback, - userdata) ); - } - break; - case PA_SUBSCRIPTION_EVENT_SINK_INPUT: - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { - g_debug ("some new sink input event ? - index = %i", index); - // Maybe blocking state ?. - pa_operation_unref (pa_context_get_sink_input_info (c, - index, - pm_sink_input_info_callback, userdata)); - } - break; - case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: - g_debug ("source output event"); - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - gint cached_source_output_index = device_get_voip_source_output_index (sink); - if (index == cached_source_output_index){ - g_debug ("Just saw a source output removal event - index = %i and cached index = %i", index, cached_source_output_index); - device_deactivate_voip_client (sink); - } - } - else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { - g_debug ("some new source output event ? - index = %i", index); - // Determine if its a VOIP app. - pa_operation_unref (pa_context_get_source_output_info (c, - index, - pm_source_output_info_callback, userdata)); - } - break; - case PA_SUBSCRIPTION_EVENT_SERVER: - g_debug("PA_SUBSCRIPTION_EVENT_SERVER event triggered."); - pa_operation *o; - if (!(o = pa_context_get_server_info (c, pm_server_info_callback, userdata))) { - g_warning("subscribed_events_callback - pa_context_get_server_info() failed"); - return; - } - pa_operation_unref(o); - break; - } -} - -static void -pm_context_state_callback (pa_context *c, void *userdata) -{ - switch (pa_context_get_state(c)) { - case PA_CONTEXT_UNCONNECTED: - g_debug("unconnected"); - break; - case PA_CONTEXT_CONNECTING: - g_debug("connecting - waiting for the server to become available"); - break; - case PA_CONTEXT_AUTHORIZING: - g_debug ("Authorizing"); - break; - case PA_CONTEXT_SETTING_NAME: - g_debug ("Setting name"); - break; - case PA_CONTEXT_FAILED: - g_warning("PA_CONTEXT_FAILED - Is PulseAudio Daemon running ?"); - device_sink_deactivated (DEVICE (userdata)); - if (reconnect_idle_id == 0){ - reconnect_idle_id = g_timeout_add_seconds (RECONNECT_DELAY, - reconnect_to_pulse, - (gpointer)userdata); - } - break; - case PA_CONTEXT_TERMINATED: - g_debug ("Terminated"); - device_sink_deactivated (DEVICE (userdata)); - - if (reconnect_idle_id != 0){ - g_source_remove (reconnect_idle_id); - reconnect_idle_id = 0; - } - break; - case PA_CONTEXT_READY: - connection_attempts = 0; - g_debug("PA_CONTEXT_READY"); - - if (reconnect_idle_id != 0){ - g_source_remove (reconnect_idle_id); - reconnect_idle_id = 0; - } - - pa_context_set_subscribe_callback(c, pm_subscribed_events_callback, userdata); - pa_operation *o = NULL; - - o = pa_context_subscribe (c, (pa_subscription_mask_t) - (PA_SUBSCRIPTION_MASK_SINK| - PA_SUBSCRIPTION_MASK_SOURCE| - PA_SUBSCRIPTION_MASK_SINK_INPUT| - PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT| - PA_SUBSCRIPTION_MASK_SERVER), - NULL, - NULL); - - - if (!o){ - g_critical("pa_context_subscribe() failed - ?"); - return; - } - - pa_operation_unref(o); - - o = pa_context_get_server_info (c, pm_server_info_callback, userdata); - - if (!o){ - g_warning("pa_context_get_server_info() failed - ?"); - return; - } - - pa_operation_unref(o); - - break; - } -} - -/** - After startup we go straight for the server info to see if it has details of - the default sink and source. Normally these are valid, if there is none set - fetch the list of each and try to determine the sink. - **/ -static void -pm_server_info_callback (pa_context *c, - const pa_server_info *info, - void *userdata) -{ - pa_operation *operation; - g_debug ("server info callback"); - - if (info == NULL) { - g_warning("No PA server - get the hell out of here"); - device_sink_deactivated (DEVICE (userdata)); - return; - } - // Go for the default sink - if (info->default_sink_name != NULL) { - g_debug ("default sink name from the server ain't null'"); - if (!(operation = pa_context_get_sink_info_by_name (c, - info->default_sink_name, - pm_default_sink_info_callback, - userdata) )) { - g_warning("pa_context_get_sink_info_by_namet() failed"); - device_sink_deactivated (DEVICE (userdata)); - pa_operation_unref(operation); - return; - } - } // If there is no default sink, try to determine a sink from the list of sinks - else if (!(operation = pa_context_get_sink_info_list(c, - pm_sink_info_callback, - userdata))) { - g_warning("pa_context_get_sink_info_list() failed"); - device_sink_deactivated (DEVICE (userdata)); - pa_operation_unref(operation); - return; - } - // And the source - if (info->default_source_name != NULL) { - g_debug ("default source name from the server is not null'"); - if (!(operation = pa_context_get_source_info_by_name (c, - info->default_source_name, - pm_default_source_info_callback, - userdata) )) { - g_warning("pa_context_get_default_source_info() failed"); - // TODO: call some input deactivate method on active sink - pa_operation_unref(operation); - return; - } - } - else if (!(operation = pa_context_get_source_info_list(c, - pm_source_info_callback, - userdata))) { - g_warning("pa_context_get_sink_info_list() failed"); - // TODO: call some input deactivate method for the source - } - pa_operation_unref(operation); -} - -// If the server doesn't have a default sink to give us -// we should attempt to pick up the first of the list of sinks which doesn't have -// the name 'auto_null' (that was all really I was doing before) -static void -pm_sink_info_callback (pa_context *c, - const pa_sink_info *sink, - int eol, - void* userdata) -{ - if (eol > 0) { - return; - } - else { - if (IS_DEVICE (userdata) == FALSE || sink == NULL){ - g_warning ("sink info callback - our user data is not what we think it should be or the sink parameter is null"); - return; - } - Device* a_sink = DEVICE (userdata); - if (device_is_sink_populated (a_sink) == FALSE && - g_ascii_strncasecmp("auto_null", sink->name, 9) != 0){ - device_sink_populate (a_sink, sink); - } - } -} - -static void -pm_default_sink_info_callback (pa_context *c, - const pa_sink_info *info, - int eol, - void *userdata) -{ - if (eol > 0) { - return; - } - else { - if (IS_DEVICE (userdata) == FALSE || info == NULL){ - g_warning ("Default sink info callback - our user data is not what we think it should be or the info parameter is null"); - return; - } - // Only repopulate if there is a change with regards the index - if (device_get_sink_index (DEVICE (userdata)) == info->index) - return; - - g_debug ("Pulse Server has handed us a new default sink"); - device_sink_populate (DEVICE (userdata), info); - } -} - -static void -pm_sink_input_info_callback (pa_context *c, - const pa_sink_input_info *info, - int eol, - void *userdata) -{ - if (eol > 0) { - return; - } - else { - if (info == NULL || IS_DEVICE (userdata) == FALSE) { - g_warning("Sink input info callback : SINK INPUT INFO IS NULL or our user_data is not what we think it should be"); - return; - } - Device* a_sink = DEVICE (userdata); - // And finally check for the mute blocking state - if (device_get_sink_index (a_sink) == info->sink){ - device_determine_blocking_state (a_sink); - } - } -} - -static void -pm_source_output_info_callback (pa_context *c, - const pa_source_output_info *info, - int eol, - void *userdata) -{ - if (eol > 0) { - return; - } - else { - if (info == NULL || IS_DEVICE (userdata) == FALSE) { - g_warning("Source output callback: SOURCE OUTPUT INFO IS NULL or our user_data is not what we think it should be"); - return; - } - - // Check if this is Voip sink input - gint result = pa_proplist_contains (info->proplist, PA_PROP_MEDIA_ROLE); - Device* a_sink = DEVICE (userdata); - - if (result == 1){ - //g_debug ("Source output info has media role property"); - const char* value = pa_proplist_gets (info->proplist, PA_PROP_MEDIA_ROLE); - //g_debug ("prop role = %s", value); - if (g_strcmp0 (value, "phone") == 0 || g_strcmp0 (value, "production") == 0) { - g_debug ("We have a VOIP/PRODUCTION ! - index = %i", info->index); - device_activate_voip_item (a_sink, (gint)info->index, (gint)info->client); - // TODO to start with we will assume our source is the same as what this 'client' - // is pointing at. This should probably be more intelligent : - // query for the list of source output info's and going on the name of the client - // from the sink input ensure our voip item is using the right source. - } - } - } -} - -static void -pm_update_device (pa_context *c, - const pa_sink_info *info, - int eol, - void *userdata) -{ - if (eol > 0) { - return; - } - else{ - if (IS_DEVICE (userdata) == FALSE || info == NULL){ - g_warning ("update_device - our user data is not what we think it should be or the info parameter is null"); - return; - } - device_sink_update (DEVICE(userdata), info); - } -} - -static void -pm_toggle_mute_for_every_sink_callback (pa_context *c, - const pa_sink_info *sink, - int eol, - void* userdata) -{ - if (eol > 0) { - return; - } - - if (sink == NULL) { - g_warning ("toggle_mute cb - sink parameter is null - why ?"); - return; - } - - pa_operation *operation = NULL; - operation = pa_context_set_sink_mute_by_index (c, - sink->index, - GPOINTER_TO_INT(userdata), - NULL, - NULL); - if (!operation){ - g_warning ("pm_update_mic_mute operation failed for some reason"); - return; - } - pa_operation_unref (operation); -} - -// Source info related callbacks -static void -pm_default_source_info_callback (pa_context *c, - const pa_source_info *info, - int eol, - void *userdata) -{ - if (eol > 0) { - return; - } - else { - if (IS_DEVICE (userdata) == FALSE || info == NULL){ - g_warning ("Default source info callback - our user data is not what we think it should be or the source info parameter is null"); - return; - } - // If there is an index change we need to change our cached source - if (device_get_source_index (DEVICE (userdata)) == info->index) - return; - g_debug ("Pulse Server has handed us a new default source"); - device_deactivate_voip_source (DEVICE (userdata), TRUE); - device_update_voip_input_source (DEVICE (userdata), info); - } -} - -static void -pm_source_info_callback (pa_context *c, - const pa_source_info *info, - int eol, - void *userdata) -{ - if (eol > 0) { - return; - } - else { - if (IS_DEVICE (userdata) == FALSE || info == NULL){ - g_warning ("source info callback - our user data is not what we think it should be or the source info parameter is null"); - return; - } - // For now we will take the first available - if (device_is_voip_source_populated (DEVICE (userdata)) == FALSE){ - device_update_voip_input_source (DEVICE (userdata), info); - } - } -} - -static void -pm_update_source_info_callback (pa_context *c, - const pa_source_info *info, - int eol, - void *userdata) -{ - if (eol > 0) { - return; - } - else { - if (IS_DEVICE (userdata) == FALSE || info == NULL ){ - g_warning ("source info update callback - our user data is not what we think it should be or the source info paramter is null"); - return; - } - g_debug ("Got a source update for %s , index %i", info->name, info->index); - device_update_voip_input_source (DEVICE (userdata), info); - } -} diff --git a/src/pulseaudio-mgr.h b/src/pulseaudio-mgr.h deleted file mode 100644 index ace47f3..0000000 --- a/src/pulseaudio-mgr.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "device.h" - -void pm_establish_pulse_connection (Device* device); -void close_pulse_activites(); -void pm_update_volume (gint sink_index, pa_cvolume new_volume); -void pm_update_mic_gain (gint source_index, pa_cvolume new_gain); -void pm_update_mic_mute (gint source_index, int mute_update); -void pm_update_mute (gboolean update); - - - - - - diff --git a/src/scrub-menu-item.vala b/src/scrub-menu-item.vala deleted file mode 100644 index e300050..0000000 --- a/src/scrub-menu-item.vala +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -using Dbusmenu; -using DbusmenuScrub; -using Gee; - -public class ScrubMenuitem : PlayerItem -{ - public ScrubMenuitem(PlayerController parent) - { - Object(item_type: MENUITEM_TYPE, owner: parent); - reset(attributes_format()); - } - - public override void handle_event(string name, GLib.Value input_value, uint timestamp) - { - debug("handle_event for owner %s with value: %f", this.owner.name, input_value.get_double()); - this.owner.mpris_bridge.set_track_position(input_value.get_double()); - } - - public void update_position(int32 new_position) - { - this.property_set_int(MENUITEM_POSITION, new_position); - } - - public void update_playstate(int state) - { - this.property_set_int(MENUITEM_PLAY_STATE, state); - } - - public static HashSet<string> attributes_format() - { - HashSet<string> attrs = new HashSet<string>(); - attrs.add(MENUITEM_DURATION); - attrs.add(MENUITEM_POSITION); - attrs.add(MENUITEM_PLAY_STATE); - return attrs; - } -}
\ No newline at end of file diff --git a/src/service.vala b/src/service.vala new file mode 100644 index 0000000..3d14d5e --- /dev/null +++ b/src/service.vala @@ -0,0 +1,378 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * 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; version 3. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: + * Lars Uebernickel <lars.uebernickel@canonical.com> + */ + +/* Icon.serialize() is not yet in gio-2.0.vapi; remove this when it is */ +extern Variant? g_icon_serialize (Icon icon); + +public class IndicatorSound.Service { + public Service () { + this.settings = new Settings ("com.canonical.indicator.sound"); + + this.volume_control = new VolumeControl (); + this.volume_control.notify["active-mic"].connect (active_mic_changed); + + this.players = new MediaPlayerList (); + this.players.player_added.connect (this.player_added); + this.players.player_removed.connect (this.player_removed); + + this.actions = new SimpleActionGroup (); + this.actions.add_entries (action_entries, this); + this.actions.add_action (this.create_mute_action ()); + this.actions.add_action (this.create_volume_action ()); + this.actions.add_action (this.create_mic_volume_action ()); + + this.menu = create_menu (); + this.root_menu = create_root_menu (this.menu); + + this.players.sync (settings.get_strv ("interested-media-players")); + this.settings.changed["interested-media-players"].connect ( () => { + this.players.sync (settings.get_strv ("interested-media-players")); + }); + } + + public int run () { + if (this.loop != null) { + warning ("service is already running"); + return 1; + } + + Bus.own_name (BusType.SESSION, "com.canonical.indicator.sound", BusNameOwnerFlags.NONE, + this.bus_acquired, null, this.name_lost); + + this.loop = new MainLoop (null, false); + this.loop.run (); + + return 0; + } + + const ActionEntry[] action_entries = { + { "root", null, null, "{ 'icon': <'audio-volume-high-panel'> }", null }, + { "settings", activate_settings, null, null, null }, + }; + + MainLoop loop; + SimpleActionGroup actions; + Menu root_menu; + Menu menu; + Settings settings; + VolumeControl volume_control; + MediaPlayerList players; + uint player_action_update_id; + + void activate_settings (SimpleAction action, Variant? param) { + var env = Environment.get_variable ("DESKTOP_SESSION"); + string cmd; + if (env == "unity") + cmd = "gnome-control-center sound-nua"; + else if (env == "xubuntu" || env == "ubuntustudio") + cmd = "pavucontrol"; + else + cmd = "gnome-control-center sound"; + + try { + Process.spawn_command_line_async (cmd); + } catch (Error e) { + warning ("unable to launch sound settings: %s", e.message); + } + } + + static Menu create_root_menu (Menu submenu) { + var root = new MenuItem (null, "indicator.root"); + root.set_attribute ("x-canonical-type", "s", "com.canonical.indicator.root"); + root.set_submenu (submenu); + + var menu = new Menu (); + menu.append_item (root); + + return menu; + } + + static Menu create_menu () { + var volume_section = new Menu (); + volume_section.append (_("Mute"), "indicator.mute"); + + var slider = new MenuItem (null, "indicator.volume"); + slider.set_attribute ("x-canonical-type", "s", "com.canonical.unity.slider"); + slider.set_attribute_value ("min-icon", g_icon_serialize (new ThemedIcon ("audio-volume-low-zero-panel"))); + slider.set_attribute_value ("max-icon", g_icon_serialize (new ThemedIcon ("audio-volume-high-panel"))); + slider.set_attribute ("min-value", "d", 0.0); + slider.set_attribute ("max-value", "d", 1.0); + slider.set_attribute ("step", "d", 0.01); + volume_section.append_item (slider); + + var menu = new Menu (); + menu.append_section (null, volume_section); + menu.append (_("Sound Settings…"), "indicator.settings"); + + return menu; + } + + void active_mic_changed () { + var volume_section = this.menu.get_item_link (0, "section") as Menu; + if (this.volume_control.active_mic) { + if (volume_section.get_n_items () < 3) { + var slider = new MenuItem (null, "indicator.mic-volume"); + slider.set_attribute ("x-canonical-type", "s", "com.canonical.unity.slider"); + slider.set_attribute_value ("min-icon", g_icon_serialize (new ThemedIcon ("audio-input-microphone-low-zero-panel"))); + slider.set_attribute_value ("max-icon", g_icon_serialize (new ThemedIcon ("audio-input-microphone-high-panel"))); + slider.set_attribute ("min-value", "d", 0.0); + slider.set_attribute ("max-value", "d", 1.0); + slider.set_attribute ("step", "d", 0.01); + volume_section.append_item (slider); + } + } + else { + if (volume_section.get_n_items () > 2) + volume_section.remove (2); + } + } + + void update_root_icon () { + double volume = this.volume_control.get_volume (); + string icon; + if (this.volume_control.mute) + icon = "audio-volume-muted-panel"; + else if (volume <= 0.0) + icon = "audio-volume-low-zero-panel"; + else if (volume <= 0.3) + icon = "audio-volume-low-panel"; + else if (volume <= 0.7) + icon = "audio-volume-medium-panel"; + else + icon = "audio-volume-high-panel"; + + var root_action = this.actions.lookup ("root") as SimpleAction; + root_action.set_state (new Variant.parsed ("{ 'icon': <%s> }", icon)); + } + + Action create_mute_action () { + var mute_action = new SimpleAction.stateful ("mute", null, this.volume_control.mute); + + mute_action.activate.connect ( (action, param) => { + action.change_state (!action.get_state ().get_boolean ()); + }); + + mute_action.change_state.connect ( (action, val) => { + volume_control.set_mute (val.get_boolean ()); + }); + + this.volume_control.notify["mute"].connect ( () => { + mute_action.set_state (this.volume_control.mute); + this.update_root_icon (); + }); + + return mute_action; + } + + void volume_changed (double volume) { + var volume_action = this.actions.lookup ("volume") as SimpleAction; + volume_action.set_state (volume); + + this.update_root_icon (); + } + + Action create_volume_action () { + var volume_action = new SimpleAction.stateful ("volume", null, this.volume_control.get_volume ()); + + volume_action.change_state.connect ( (action, val) => { + volume_control.set_volume (val.get_double ()); + }); + + this.volume_control.volume_changed.connect (volume_changed); + + this.volume_control.bind_property ("ready", volume_action, "enabled", BindingFlags.SYNC_CREATE); + + return volume_action; + } + + Action create_mic_volume_action () { + var volume_action = new SimpleAction.stateful ("mic-volume", null, this.volume_control.get_mic_volume ()); + + volume_action.change_state.connect ( (action, val) => { + volume_control.set_mic_volume (val.get_double ()); + }); + + this.volume_control.mic_volume_changed.connect ( (volume) => { + volume_action.set_state (volume); + }); + + this.volume_control.bind_property ("ready", volume_action, "enabled", BindingFlags.SYNC_CREATE); + + return volume_action; + } + + void bus_acquired (DBusConnection connection, string name) { + try { + connection.export_action_group ("/com/canonical/indicator/sound", this.actions); + connection.export_menu_model ("/com/canonical/indicator/sound/desktop", this.root_menu); + } catch (Error e) { + critical ("%s", e.message); + } + } + + void name_lost (DBusConnection connection, string name) { + this.loop.quit (); + } + + Variant action_state_for_player (MediaPlayer player) { + var builder = new VariantBuilder (new VariantType ("a{sv}")); + builder.add ("{sv}", "running", new Variant ("b", player.is_running)); + builder.add ("{sv}", "state", new Variant ("s", player.state)); + if (player.current_track != null) { + builder.add ("{sv}", "title", new Variant ("s", player.current_track.title)); + builder.add ("{sv}", "artist", new Variant ("s", player.current_track.artist)); + builder.add ("{sv}", "album", new Variant ("s", player.current_track.album)); + builder.add ("{sv}", "art-url", new Variant ("s", player.current_track.art_url)); + } + return builder.end (); + } + + bool update_player_actions () { + foreach (var player in this.players) { + SimpleAction? action = this.actions.lookup (player.id) as SimpleAction; + if (action != null) + action.set_state (this.action_state_for_player (player)); + } + + this.player_action_update_id = 0; + return false; + } + + void eventually_update_player_actions () { + if (player_action_update_id == 0) + this.player_action_update_id = Idle.add (this.update_player_actions); + } + + void update_preferred_players () { + var builder = new VariantBuilder (VariantType.STRING_ARRAY); + foreach (var player in this.players) + builder.add ("s", player.id); + this.settings.set_value ("interested-media-players", builder.end ()); + } + + void update_playlists (MediaPlayer player) { + int index = find_player_section (player); + if (index < 0) + return; + + var section = this.menu.get_item_link (index, Menu.LINK_SECTION) as Menu; + + /* if a section has three items, the playlists menu is in it */ + if (section.get_n_items () == 3) + section.remove (2); + + if (!player.is_running) + return; + + var count = player.get_n_playlists (); + if (count == 0) + return; + + var playlists_section = new Menu (); + for (int i = 0; i < count; i++) { + var playlist_id = player.get_playlist_id (i); + playlists_section.append (player.get_playlist_name (i), + @"indicator.play-playlist.$(player.id)::$playlist_id"); + + } + + var submenu = new Menu (); + submenu.append_section (null, playlists_section); + section.append_submenu ("Choose Playlist", submenu); + } + + void player_added (MediaPlayer player) { + var player_item = new MenuItem (player.name, "indicator." + player.id); + player_item.set_attribute ("x-canonical-type", "s", "com.canonical.unity.media-player"); + player_item.set_attribute_value ("icon", g_icon_serialize (player.icon)); + + var playback_item = new MenuItem (null, null); + playback_item.set_attribute ("x-canonical-type", "s", "com.canonical.unity.playback-item"); + playback_item.set_attribute ("x-canonical-play-action", "s", "indicator.play." + player.id); + playback_item.set_attribute ("x-canonical-next-action", "s", "indicator.next." + player.id); + playback_item.set_attribute ("x-canonical-previous-action", "s", "indicator.previous." + player.id); + + var section = new Menu (); + section.append_item (player_item); + section.append_item (playback_item); + + this.menu.insert_section (this.menu.get_n_items () -1, null, section); + + SimpleAction action = new SimpleAction.stateful (player.id, null, this.action_state_for_player (player)); + action.activate.connect ( () => { player.launch (); }); + this.actions.insert (action); + + var play_action = new SimpleAction.stateful ("play." + player.id, null, player.state); + play_action.activate.connect ( () => player.play_pause () ); + this.actions.insert (play_action); + player.notify.connect ( (object, pspec) => { + if (pspec.name == "state") + play_action.set_state (player.state); + }); + + var next_action = new SimpleAction ("next." + player.id, null); + next_action.activate.connect ( () => player.next () ); + this.actions.insert (next_action); + + var prev_action = new SimpleAction ("previous." + player.id, null); + prev_action.activate.connect ( () => player.previous () ); + this.actions.insert (prev_action); + + var playlist_action = new SimpleAction ("play-playlist." + player.id, VariantType.STRING); + playlist_action.activate.connect ( (parameter) => player.activate_playlist_by_name (parameter.get_string ()) ); + this.actions.insert (playlist_action); + + player.notify.connect (this.eventually_update_player_actions); + + player.playlists_changed.connect (this.update_playlists); + player.notify["is-running"].connect ( () => this.update_playlists (player) ); + update_playlists (player); + + this.update_preferred_players (); + } + + /* returns the position in this.menu of the section that's associated with @player */ + int find_player_section (MediaPlayer player) { + string action_name = @"indicator.$(player.id)"; + int n = this.menu.get_n_items () -1; + for (int i = 1; i < n; i++) { + var section = this.menu.get_item_link (i, Menu.LINK_SECTION); + string action; + section.get_item_attribute (0, "action", "s", out action); + if (action == action_name) + return i; + } + + return -1; + } + + void player_removed (MediaPlayer player) { + this.actions.remove (player.id); + this.actions.remove ("play." + player.id); + this.actions.remove ("next." + player.id); + this.actions.remove ("previous." + player.id); + this.actions.remove ("play-playlist." + player.id); + + int index = this.find_player_section (player); + if (index >= 0) + this.menu.remove (index); + + this.update_preferred_players (); + } +} diff --git a/src/settings-manager.vala b/src/settings-manager.vala deleted file mode 100644 index 458ac21..0000000 --- a/src/settings-manager.vala +++ /dev/null @@ -1,136 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -using Gee; - -public class SettingsManager : GLib.Object -{ - private Settings settings; - public signal void blacklist_updates ( string[] new_blacklist ); - public signal void preferred_updates (Gee.ArrayList<string> new_preferred); - - public SettingsManager ( ){ - } - construct{ - this.settings = new Settings ("com.canonical.indicator.sound"); - this.settings.changed["blacklisted-media-players"].connect (on_blacklist_event); - this.settings.changed["preferred-media-players"].connect (on_preferred_event); - } - - public string[] fetch_blacklist() - { - return this.settings.get_strv ("blacklisted-media-players"); - } - - public ArrayList<string> fetch_preferred() - { - var list = new ArrayList<string>(); - - var preferred = this.settings.get_strv ("preferred-media-players"); - var interested = fetch_interested (); - - foreach (var s in preferred) { - if (!(s in list) && interested.contains (s)) - list.add (s); - } - - return list; - } - - public ArrayList<string> fetch_interested() - { - var blacklisted = fetch_blacklist (); - var interested = this.settings.get_strv ("interested-media-players"); - var list = new ArrayList<string>(); - foreach(var s in interested){ - if (s == "banshee-1"){ - s = "banshee"; - } - if (s in list) continue; - if (s in blacklisted) continue; - list.add(s); - } - return list; - } - - public void clear_list() - { - this.settings.reset("interested-media-players"); - } - - public void remove_interested (string app_desktop_name) - { - const string key = "interested-media-players"; - var players = new GLib.VariantBuilder (new VariantType ("as")); // array of strings - - foreach (var player in this.settings.get_strv (key)) { - if (player != app_desktop_name) - players.add ("s", player); - } - - this.settings.set_value(key, players.end()); - this.settings.apply(); - } - - public void add_interested (string app_desktop_name) - { - const string key = "interested-media-players"; - var players = new GLib.VariantBuilder (new VariantType ("as")); // array of strings - - foreach (var player in this.settings.get_strv (key)) { - if (player == app_desktop_name) - return; - players.add ("s", player); - } - - players.add ("s", app_desktop_name); - this.settings.set_value(key, players.end()); - this.settings.apply(); - } - - private void on_blacklist_event() - { - this.blacklist_updates(this.settings.get_strv ("blacklisted-media-players")); - } - - private void on_preferred_event() - { - this.preferred_updates (this.fetch_preferred()); - } - - // Convenient debug method inorder to provide visability over - // the contents of both interested and blacklisted containers in its gsettings -/** - private void reveal_contents() - { - var already_interested = this.settings.get_strv ("interested-media-players"); - foreach (var s in already_interested) - { - debug ("client %s is in interested array", s); - } - var blacklisted = this.settings.get_strv ("blacklisted-media-players"); - foreach (var s in blacklisted) - { - debug ("client %s is in blacklisted array", s); - } - - debug ("interested array size = %i", already_interested.length); - debug ("blacklisted array size = %i", blacklisted.length); - } -**/ -} diff --git a/src/slider-menu-item.c b/src/slider-menu-item.c deleted file mode 100644 index dc0671c..0000000 --- a/src/slider-menu-item.c +++ /dev/null @@ -1,258 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <glib/gi18n.h> -#include "slider-menu-item.h" -#include "common-defs.h" -#include "pulseaudio-mgr.h" - -typedef struct _SliderMenuItemPrivate SliderMenuItemPrivate; - -struct _SliderMenuItemPrivate { - Device* a_sink; - gint index; - gchar* name; - gboolean mute; - pa_cvolume volume; - pa_channel_map channel_map; - pa_volume_t base_volume; -}; - -#define SLIDER_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SLIDER_MENU_ITEM_TYPE, SliderMenuItemPrivate)) - -/* Prototypes */ -static void slider_menu_item_class_init (SliderMenuItemClass *klass); -static void slider_menu_item_init (SliderMenuItem *self); -static void slider_menu_item_dispose (GObject *object); -static void slider_menu_item_finalize (GObject *object); -static void handle_event (DbusmenuMenuitem * mi, const gchar * name, - GVariant * value, guint timestamp); -static pa_cvolume slider_menu_item_construct_mono_volume (const pa_cvolume* vol); -static void slider_menu_item_update_volume (SliderMenuItem* self, gdouble percent); - -G_DEFINE_TYPE (SliderMenuItem, slider_menu_item, DBUSMENU_TYPE_MENUITEM); - -static void -slider_menu_item_class_init (SliderMenuItemClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (SliderMenuItemPrivate)); - - object_class->dispose = slider_menu_item_dispose; - object_class->finalize = slider_menu_item_finalize; - - DbusmenuMenuitemClass * mclass = DBUSMENU_MENUITEM_CLASS(klass); - mclass->handle_event = handle_event; - return; -} - -static void -slider_menu_item_init (SliderMenuItem *self) -{ - dbusmenu_menuitem_property_set( DBUSMENU_MENUITEM(self), - DBUSMENU_MENUITEM_PROP_TYPE, - DBUSMENU_VOLUME_MENUITEM_TYPE ); - - SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (self); - - priv->index = NOT_ACTIVE; - priv->name = NULL; - - return; -} - -static void -slider_menu_item_dispose (GObject *object) -{ - G_OBJECT_CLASS (slider_menu_item_parent_class)->dispose (object); - return; -} - -static void -slider_menu_item_finalize (GObject *object) -{ - G_OBJECT_CLASS (slider_menu_item_parent_class)->finalize (object); -} - -static void -handle_event (DbusmenuMenuitem * mi, - const gchar * name, - GVariant * value, - guint timestamp) -{ - g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE)); - g_return_if_fail (IS_SLIDER_MENU_ITEM (mi)); - - SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (SLIDER_MENU_ITEM (mi)); - gdouble volume_input = g_variant_get_double (value); - -/* - g_debug ("slider menu item handle event with value %f on name %s", - volume_input, - name); -*/ - - slider_menu_item_update_volume (SLIDER_MENU_ITEM (mi), volume_input); - if (volume_input > 0) - device_ensure_sink_is_unmuted (priv->a_sink); -} - - -void -slider_menu_item_populate (SliderMenuItem* self, const pa_sink_info* update) -{ - SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (self); - priv->name = g_strdup (update->name); - priv->index = update->index; - priv->volume = slider_menu_item_construct_mono_volume (&update->volume); - priv->base_volume = update->base_volume; - priv->channel_map = update->channel_map; - priv->mute = update->mute; - - pa_volume_t vol = pa_cvolume_max (&update->volume); - gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; - GVariant* new_volume = g_variant_new_double (volume_percent); - dbusmenu_menuitem_property_set_variant (DBUSMENU_MENUITEM(self), - DBUSMENU_VOLUME_MENUITEM_LEVEL, - new_volume); - GVariant* new_mute_update = g_variant_new_boolean (update->mute == 1); - dbusmenu_menuitem_property_set_variant (DBUSMENU_MENUITEM(self), - DBUSMENU_VOLUME_MENUITEM_MUTE, - new_mute_update); - - slider_menu_item_enable (self, TRUE); -} - -// From the UI -static void -slider_menu_item_update_volume (SliderMenuItem* self, gdouble percent) -{ - g_return_if_fail (IS_SLIDER_MENU_ITEM (self)); - - pa_cvolume mono_new_volume; - pa_cvolume_init(&mono_new_volume); - mono_new_volume.channels = 1; - pa_volume_t new_volume_value = (pa_volume_t) ((percent * PA_VOLUME_NORM) / 100); - - if (new_volume_value == PA_VOLUME_INVALID || new_volume_value >= PA_VOLUME_MAX){ - g_warning ("slider_menu_item_update_volume - volume is out of range !"); - return; - } - - pa_cvolume_set(&mono_new_volume, 1, new_volume_value); - - SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (self); - if (!pa_cvolume_valid (&mono_new_volume)){ - g_warning ("Invalid volume - ignore it!"); - return; - } - if (!pa_channel_map_valid(&priv->channel_map)){ - g_warning ("Invalid channel map - ignore update volume!"); - return; - } - pa_cvolume_set(&priv->volume, priv->channel_map.channels, new_volume_value); - pm_update_volume (priv->index, mono_new_volume); -} - -// To the UI -void -slider_menu_item_update (SliderMenuItem* self, const pa_sink_info* update) -{ - SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (self); - - priv->volume = slider_menu_item_construct_mono_volume (&update->volume); - priv->base_volume = update->base_volume; - priv->channel_map = update->channel_map; - - pa_volume_t vol = pa_cvolume_max (&update->volume); - gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM; - - GVariant* new_volume = g_variant_new_double (volume_percent); - -/* - g_debug ("slider menu item update - volume update to ui to %f", volume_percent); -*/ - - dbusmenu_menuitem_property_set_variant (DBUSMENU_MENUITEM(self), - DBUSMENU_VOLUME_MENUITEM_LEVEL, - new_volume); - - if (priv->mute != update->mute){ - priv->mute = update->mute; -/* - g_debug ("volume menu item - update - mute on ui = %i", update->mute); -*/ - GVariant* new_mute_update = g_variant_new_boolean (update->mute == 1); - dbusmenu_menuitem_property_set_variant (DBUSMENU_MENUITEM(self), - DBUSMENU_VOLUME_MENUITEM_MUTE, - new_mute_update); - } -} - -/* - * Enable/Disabled can be considered the equivalent of whether we have an active - * sink or not, let the widget have inherent state. - */ -void -slider_menu_item_enable (SliderMenuItem* self, gboolean active) -{ - SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (self); - - dbusmenu_menuitem_property_set_bool (DBUSMENU_MENUITEM(self), - DBUSMENU_MENUITEM_PROP_ENABLED, - active); - if(active == FALSE){ - priv->index = NOT_ACTIVE; - if(priv->name != NULL){ - g_free(priv->name); - priv->name = NULL; - } - } -} - -gint -slider_menu_item_get_sink_index (SliderMenuItem* self) -{ - SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (self); - return priv->index; -} - -static pa_cvolume -slider_menu_item_construct_mono_volume (const pa_cvolume* vol) -{ - pa_cvolume new_volume; - pa_cvolume_init(&new_volume); - new_volume.channels = 1; - pa_volume_t max_vol = pa_cvolume_max(vol); - pa_cvolume_set(&new_volume, 1, max_vol); - return new_volume; -} - -SliderMenuItem* -slider_menu_item_new (Device* sink) -{ - SliderMenuItem *self = g_object_new(SLIDER_MENU_ITEM_TYPE, NULL); - SliderMenuItemPrivate* priv = SLIDER_MENU_ITEM_GET_PRIVATE (self); - priv->a_sink = sink; - return self; -} diff --git a/src/slider-menu-item.h b/src/slider-menu-item.h deleted file mode 100644 index 4375971..0000000 --- a/src/slider-menu-item.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#ifndef __SLIDER_MENU_ITEM_H__ -#define __SLIDER_MENU_ITEM_H__ - -#include <glib.h> -#include <glib-object.h> - -#include <libdbusmenu-glib/menuitem.h> -#include "device.h" - -G_BEGIN_DECLS - -#define SLIDER_MENU_ITEM_TYPE (slider_menu_item_get_type ()) -#define SLIDER_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SLIDER_MENU_ITEM_TYPE, SliderMenuItem)) -#define SLIDER_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SLIDER_MENU_ITEM_TYPE, SliderMenuItemClass)) -#define IS_SLIDER_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SLIDER_MENU_ITEM_TYPE)) -#define IS_SLIDER_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SLIDER_MENU_ITEM_TYPE)) -#define SLIDER_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SLIDER_MENU_ITEM_TYPE, SliderMenuItemClass)) - -typedef struct _SliderMenuItem SliderMenuItem; -typedef struct _SliderMenuItemClass SliderMenuItemClass; - -struct _SliderMenuItemClass { - DbusmenuMenuitemClass parent_class; -}; - -struct _SliderMenuItem { - DbusmenuMenuitem parent; -}; - -GType slider_menu_item_get_type (void); - -void slider_menu_item_update(SliderMenuItem* item, const pa_sink_info* update); -void slider_menu_item_enable(SliderMenuItem* item, gboolean active); -void slider_menu_item_populate (SliderMenuItem* self, const pa_sink_info* update); -//void -//active_sink_update (ActiveSink* sink, -// const pa_sink_info* update) - -gint slider_menu_item_get_sink_index (SliderMenuItem* self); - -SliderMenuItem* slider_menu_item_new (Device* sink); - -G_END_DECLS - -#endif - diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c deleted file mode 100644 index 5e004cb..0000000 --- a/src/sound-service-dbus.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Copyright 2010 Canonical Ltd. - * - * Authors: - * Conor Curran <conor.curran@canonical.com> - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gio/gio.h> -#include <unistd.h> -#include <glib/gi18n.h> -#include <libindicator/indicator-service.h> -#include <libdbusmenu-glib/server.h> -#include <libdbusmenu-glib/client.h> - -#include "sound-service-dbus.h" -#include "device.h" -#include "gen-sound-service.xml.h" -#include "dbus-shared-names.h" -#include "sound-service-marshal.h" - -// DBUS methods -static void bus_method_call (GDBusConnection * connection, - const gchar * sender, - const gchar * path, - const gchar * interface, - const gchar * method, - GVariant * params, - GDBusMethodInvocation * invocation, - gpointer user_data); - -static GDBusInterfaceVTable interface_table = { - method_call: bus_method_call, - get_property: NULL, /* No properties */ - set_property: NULL /* No properties */ -}; - - -typedef struct _SoundServiceDbusPrivate SoundServiceDbusPrivate; - -struct _SoundServiceDbusPrivate { - GDBusConnection* connection; - DbusmenuMenuitem* root_menuitem; - Device* device; - gboolean greeter_mode; - guint registration_id; -}; - -enum { - TRACK_SPECIFIC_ITEM, - PLAYER_SPECIFIC_ITEM, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -static GDBusNodeInfo * node_info = NULL; -static GDBusInterfaceInfo * interface_info = NULL; - -#define SOUND_SERVICE_DBUS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUND_SERVICE_DBUS_TYPE, SoundServiceDbusPrivate)) - -static void sound_service_dbus_class_init (SoundServiceDbusClass *klass); -static void sound_service_dbus_init (SoundServiceDbus *self); -static void sound_service_dbus_dispose (GObject *object); -static void sound_service_dbus_finalize (GObject *object); - -static void show_sound_settings_dialog (DbusmenuMenuitem *mi, - gpointer user_data); -static gboolean sound_service_dbus_blacklist_player (SoundServiceDbus* self, - const gchar* player_name, - gboolean blacklist); - -static gboolean sound_service_dbus_is_blacklisted (SoundServiceDbus* self, - const gchar* player_name); - -G_DEFINE_TYPE (SoundServiceDbus, sound_service_dbus, G_TYPE_OBJECT); - -static void -sound_service_dbus_class_init (SoundServiceDbusClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (object_class, sizeof(SoundServiceDbusPrivate)); - - object_class->dispose = sound_service_dbus_dispose; - object_class->finalize = sound_service_dbus_finalize; - - g_assert(klass != NULL); - - if (node_info == NULL) { - GError * error = NULL; - - node_info = g_dbus_node_info_new_for_xml(_sound_service, &error); - if (error != NULL) { - g_critical ("Unable to parse Indicator Service Interface description: %s", - error->message); - g_error_free(error); - } - } - - if (interface_info == NULL) { - interface_info = g_dbus_node_info_lookup_interface (node_info, - INDICATOR_SOUND_DBUS_INTERFACE); - - if (interface_info == NULL) { - g_critical("Unable to find interface '" INDICATOR_SOUND_DBUS_INTERFACE "'"); - } - } - signals[TRACK_SPECIFIC_ITEM] = g_signal_new("track-specific-item-requested", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - _sound_service_marshal_VOID__STRING_STRING, - G_TYPE_NONE, 2, G_TYPE_STRING, - G_TYPE_STRING); - signals[PLAYER_SPECIFIC_ITEM] = g_signal_new("player-specific-item-requested", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - _sound_service_marshal_VOID__STRING_STRING, - G_TYPE_NONE, 2, G_TYPE_STRING, - G_TYPE_STRING); -} - -static void -sound_service_dbus_init (SoundServiceDbus *self) -{ - GError *error = NULL; - SoundServiceDbusPrivate * priv = SOUND_SERVICE_DBUS_GET_PRIVATE(self); - - priv->connection = NULL; - - /* Fetch the session bus */ - priv->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); - - if (error != NULL) { - g_critical ("sound-service-dbus:Unable to connect to the session bus when creating indicator sound service : %s", error->message); - g_error_free (error); - return; - } - /* register the service on it */ - priv->registration_id = g_dbus_connection_register_object (priv->connection, - INDICATOR_SOUND_SERVICE_DBUS_OBJECT_PATH, - interface_info, - &interface_table, - self, - NULL, - &error); - if (error != NULL) { - g_critical ("Unable to register the sound service on DBus: %s", error->message); - g_error_free (error); - } -} - -DbusmenuMenuitem* -sound_service_dbus_create_root_item (SoundServiceDbus* self, gboolean greeter_mode) -{ - SoundServiceDbusPrivate * priv = SOUND_SERVICE_DBUS_GET_PRIVATE(self); - priv->greeter_mode = greeter_mode; - priv->root_menuitem = dbusmenu_menuitem_new(); - DbusmenuServer *server = dbusmenu_server_new (INDICATOR_SOUND_MENU_DBUS_OBJECT_PATH); - dbusmenu_server_set_root (server, priv->root_menuitem); - g_object_unref (priv->root_menuitem); - priv->device = device_new (self); - return priv->root_menuitem; -} - -void -sound_service_dbus_build_sound_menu ( SoundServiceDbus* self, - DbusmenuMenuitem* mute_item, - DbusmenuMenuitem* slider_item, - DbusmenuMenuitem* voip_input_menu_item) -{ - SoundServiceDbusPrivate * priv = SOUND_SERVICE_DBUS_GET_PRIVATE(self); - - // Mute, Volume and Voip widgets - dbusmenu_menuitem_child_add_position (priv->root_menuitem, mute_item, 0); - dbusmenu_menuitem_child_add_position (priv->root_menuitem, slider_item, 1); - dbusmenu_menuitem_child_add_position (priv->root_menuitem, voip_input_menu_item, 2); - - if (!priv->greeter_mode) { - // Separator - DbusmenuMenuitem* separator = dbusmenu_menuitem_new(); - - dbusmenu_menuitem_property_set (separator, - DBUSMENU_MENUITEM_PROP_TYPE, - DBUSMENU_CLIENT_TYPES_SEPARATOR); - dbusmenu_menuitem_child_add_position (priv->root_menuitem, separator, 3); - g_object_unref (separator); - - // Sound preferences dialog - DbusmenuMenuitem* settings_mi = dbusmenu_menuitem_new(); - - dbusmenu_menuitem_property_set( settings_mi, - DBUSMENU_MENUITEM_PROP_LABEL, - _("Sound Settings...")); - dbusmenu_menuitem_child_append(priv->root_menuitem, settings_mi); - g_object_unref (settings_mi); - g_signal_connect(G_OBJECT(settings_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(show_sound_settings_dialog), NULL); - } -} - -/** -show_sound_settings_dialog: -Bring up the gnome volume preferences dialog -**/ -static void -show_sound_settings_dialog (DbusmenuMenuitem *mi, - gpointer user_data) -{ - GError * error = NULL; - if (!g_spawn_command_line_async("gnome-volume-control --page=applications", &error) && - !g_spawn_command_line_async("gnome-control-center sound", &error) && - !g_spawn_command_line_async("xfce4-mixer", &error)) - { - g_warning("Unable to show dialog: %s", error->message); - g_error_free(error); - } -} - -static void -sound_service_dbus_dispose (GObject *object) -{ - SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (object); - - if (priv->connection && priv->registration_id) { - g_dbus_connection_unregister_object (priv->connection, priv->registration_id); - priv->registration_id = 0; - } - - g_clear_object(&priv->connection); - - G_OBJECT_CLASS (sound_service_dbus_parent_class)->dispose (object); - //TODO dispose of the active sink instance ! - return; -} - -static void -sound_service_dbus_finalize (GObject *object) -{ - G_OBJECT_CLASS (sound_service_dbus_parent_class)->finalize (object); - return; -} - - -// EMIT STATE SIGNAL -void -sound_service_dbus_update_sound_state (SoundServiceDbus* self, - SoundState new_state) -{ - SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (self); - - GVariant* v_output = g_variant_new("(i)", (int)new_state); - - GError * error = NULL; - - if (priv->connection == NULL || - g_dbus_connection_is_closed (priv->connection) == TRUE){ - g_critical ("sound_service_dbus_update_sound_state - dbus connection is %s !!", - priv->connection == NULL? "NULL" : "closed"); - return; - } - - //g_debug ("emitting state signal with value %i", (int)new_state); - g_dbus_connection_emit_signal( priv->connection, - NULL, - INDICATOR_SOUND_SERVICE_DBUS_OBJECT_PATH, - INDICATOR_SOUND_DBUS_INTERFACE, - INDICATOR_SOUND_SIGNAL_STATE_UPDATE, - v_output, - &error ); - if (error != NULL) { - g_critical ("Unable to emit signal because : %s", error->message); - g_error_free(error); - } -} - -//HANDLE DBUS METHOD CALLS -static void -bus_method_call (GDBusConnection * connection, - const gchar * sender, - const gchar * path, - const gchar * interface, - const gchar * method, - GVariant * params, - GDBusMethodInvocation * invocation, - gpointer user_data) -{ - SoundServiceDbus* service = SOUND_SERVICE_DBUS(user_data); - g_return_if_fail ( IS_SOUND_SERVICE_DBUS(service) ); - GVariant * retval = NULL; - SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (service); - - if (g_strcmp0(method, "GetSoundState") == 0) { - g_debug("Get state - %i", device_get_state (priv->device)); - retval = g_variant_new ( "(i)", device_get_state (priv->device)); - } - else if (g_strcmp0(method, "BlacklistMediaPlayer") == 0) { - gboolean blacklist; - const gchar* player_name; - g_variant_get (params, "(&sb)", &player_name, &blacklist); - - g_debug ("BlacklistMediaPlayer - bool %i", blacklist); - g_debug ("BlacklistMediaPlayer - name %s", player_name); - gboolean result = sound_service_dbus_blacklist_player (service, - player_name, - blacklist); - retval = g_variant_new ("(b)", result); - } - else if (g_strcmp0(method, "IsBlacklisted") == 0) { - const gchar* player_name; - g_variant_get (params, "(&s)", &player_name); - - g_debug ("IsBlacklisted - name %s", player_name); - gboolean result = sound_service_dbus_is_blacklisted (service, - player_name); - retval = g_variant_new ("(b)", result); - } - else if (g_strcmp0(method, "EnableTrackSpecificItems") == 0) { - g_debug ("EnableTrackSpecificItems"); - gchar* player_object_path; - gchar* player_id; - g_variant_get (params, "(os)", &player_object_path, &player_id); - //g_debug ("object path = %s and id = %s", player_object_path, player_id); - g_signal_emit (service, - signals[TRACK_SPECIFIC_ITEM], - 0, - player_object_path, - player_id); - g_free (player_object_path); - g_free (player_id); - - } - else if (g_strcmp0(method, "EnablePlayerSpecificItems") == 0) { - gchar* player_object_path; - gchar* player_id; - g_variant_get (params, "(os)", &player_object_path, &player_id); - g_debug ("PLayer specific item - object path = %s and id = %s", - player_object_path, - player_id); - g_signal_emit (service, - signals[PLAYER_SPECIFIC_ITEM], - 0, - player_object_path, - player_id); - g_free (player_object_path); - g_free (player_id); - } - else { - g_warning("Calling method '%s' on the sound service but it's unknown", method); - } - g_dbus_method_invocation_return_value (invocation, retval); -} - -/** - TODO - Works nicely but refactor into at least two different methods -**/ -static gboolean sound_service_dbus_blacklist_player (SoundServiceDbus* self, - const gchar* player_name, - gboolean blacklist) -{ - g_return_val_if_fail (player_name != NULL, FALSE); - g_return_val_if_fail (IS_SOUND_SERVICE_DBUS (self), FALSE); - - GVariant* the_black_list; - gboolean result = FALSE; - GSettings* our_settings; - GVariantIter iter; - gchar *str; - GVariantBuilder builder; - - our_settings = g_settings_new ("com.canonical.indicator.sound"); - the_black_list = g_settings_get_value (our_settings, - "blacklisted-media-players"); - g_variant_iter_init (&iter, the_black_list); - g_variant_builder_init(&builder, G_VARIANT_TYPE_STRING_ARRAY); - - while (g_variant_iter_loop (&iter, "s", &str)){ - g_variant_builder_add (&builder, "s", str); - } - g_variant_iter_init (&iter, the_black_list); - - if (blacklist == TRUE){ - while (g_variant_iter_loop (&iter, "s", &str)){ - g_print ("first pass to check if %s is present\n", str); - if (g_strcmp0 (player_name, str) == 0){ - // Return if its already there - g_debug ("we have this already blacklisted, no need to do anything"); - g_variant_builder_clear (&builder); - g_object_unref (our_settings); - g_variant_unref (the_black_list); - return result; - } - } - // Otherwise blacklist it ! - g_debug ("about to blacklist %s", player_name); - g_variant_builder_add (&builder, "s", player_name); - } - else{ - gboolean present = FALSE; - g_variant_iter_init (&iter, the_black_list); - g_debug ("attempting to UN-blacklist %s", player_name); - - while (g_variant_iter_loop (&iter, "s", &str)){ - if (g_strcmp0 (player_name, str) == 0){ - present = TRUE; - } - } - // It was not there anyway, return false - if (present == FALSE){ - g_debug ("it was not blacklisted ?, no need to do anything"); - g_variant_builder_clear (&builder); - g_object_unref (our_settings); - g_variant_unref (the_black_list); - return result; - } - - // Otherwise free the builder and reconstruct ensuring no duplicates. - g_variant_builder_clear (&builder); - g_variant_builder_init (&builder, G_VARIANT_TYPE_STRING_ARRAY); - - g_variant_iter_init (&iter, the_black_list); - - while (g_variant_iter_loop (&iter, "s", &str)){ - if (g_strcmp0 (player_name, str) != 0){ - g_variant_builder_add (&builder, "s", str); - } - } - } - GVariant* value = g_variant_builder_end (&builder); - result = g_settings_set_value (our_settings, - "blacklisted-media-players", - value); - - g_object_unref (our_settings); - g_variant_unref (the_black_list); - - return result; -} - -static gboolean sound_service_dbus_is_blacklisted (SoundServiceDbus *self, - const gchar *player_name) -{ - GSettings *our_settings; - GVariant *the_black_list; - GVariantIter iter; - gchar *str; - gboolean result = FALSE; - - g_return_val_if_fail (player_name != NULL, FALSE); - g_return_val_if_fail (IS_SOUND_SERVICE_DBUS (self), FALSE); - - our_settings = g_settings_new ("com.canonical.indicator.sound"); - the_black_list = g_settings_get_value (our_settings, - "blacklisted-media-players"); - g_variant_iter_init (&iter, the_black_list); - while (g_variant_iter_next (&iter, "s", &str)){ - if (g_strcmp0 (player_name, str) == 0) { - result = TRUE; - g_free (str); - break; - } - g_free (str); - } - - g_object_unref (our_settings); - g_variant_unref (the_black_list); - - return result; -} - diff --git a/src/sound-service-dbus.h b/src/sound-service-dbus.h deleted file mode 100644 index 1c15fc7..0000000 --- a/src/sound-service-dbus.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2010 Canonical Ltd. - * - * Authors: - * Conor Curran <conor.curran@canonical.com> - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __SOUND_SERVICE_DBUS_H__ -#define __SOUND_SERVICE_DBUS_H__ - -#include <glib.h> -#include <glib-object.h> -#include <libdbusmenu-glib/menuitem.h> -#include "common-defs.h" - - -G_BEGIN_DECLS - -#define SOUND_SERVICE_DBUS_TYPE (sound_service_dbus_get_type ()) -#define SOUND_SERVICE_DBUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SOUND_SERVICE_DBUS_TYPE, SoundServiceDbus)) -#define SOUND_SERVICE_DBUS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SOUND_SERVICE_DBUS_TYPE, SoundServiceDbusClass)) -#define IS_SOUND_SERVICE_DBUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SOUND_SERVICE_DBUS_TYPE)) -#define IS_SOUND_SERVICE_DBUS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SOUND_SERVICE_DBUS_TYPE)) -#define SOUND_SERVICE_DBUS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SOUND_SERVICE_DBUS_TYPE, SoundServiceDbusClass)) - -typedef struct _SoundServiceDbus SoundServiceDbus; -typedef struct _SoundServiceDbusClass SoundServiceDbusClass; -typedef struct _SoundData SoundData; - -struct _SoundData { - SoundServiceDbus *service; -}; - -struct _SoundServiceDbus { - GObject parent; -}; - -struct _SoundServiceDbusClass { - GObjectClass parent_class; -}; - -GType sound_service_dbus_get_type (void) G_GNUC_CONST; - -DbusmenuMenuitem* sound_service_dbus_create_root_item (SoundServiceDbus* self, gboolean greeter_mode); -void sound_service_dbus_update_sound_state (SoundServiceDbus* self, SoundState new_state); -void sound_service_dbus_build_sound_menu ( SoundServiceDbus* self, - DbusmenuMenuitem* mute_item, - DbusmenuMenuitem* slider_item, - DbusmenuMenuitem* voip_input_menu_item); - - -G_END_DECLS - -#endif diff --git a/src/sound-service-marshal.list b/src/sound-service-marshal.list deleted file mode 100644 index 4c756d4..0000000 --- a/src/sound-service-marshal.list +++ /dev/null @@ -1,2 +0,0 @@ -VOID:STRING,STRING - diff --git a/src/sound-service.c b/src/sound-service.c deleted file mode 100644 index 66ef7b0..0000000 --- a/src/sound-service.c +++ /dev/null @@ -1,127 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <locale.h> - -#include "sound-service.h" -#include "pulseaudio-mgr.h" -#include "sound-service-dbus.h" -#include "music-player-bridge.h" - -static GMainLoop *mainloop = NULL; -static MusicPlayerBridge* player_bridge = NULL; -/***********************************************************************************************************/ -// Init and exit functions -/**********************************************************************************************************************/ -/** -service_shutdown: -When the service interface starts to shutdown, we -should follow it. -**/ - -void -service_shutdown (IndicatorService *service, gpointer user_data) -{ - if (mainloop != NULL) { - g_debug("Service shutdown !"); - close_pulse_activites(); - g_main_loop_quit(mainloop); - } - return; -} - -static gboolean -get_greeter_mode (void) -{ - const gchar *var; - var = g_getenv("INDICATOR_GREETER_MODE"); - return (g_strcmp0(var, "1") == 0); -} - -void -on_player_specific_item_requested (SoundServiceDbus* sound_service, - const gchar* desktop_id, - const gchar* player_object_path, - gpointer userdata) -{ - if (player_bridge != NULL){ - music_player_bridge_enable_player_specific_items_for_client (player_bridge, - desktop_id, - player_object_path); - } -} - -void -on_track_specific_item_requested (SoundServiceDbus* sound_service, - const gchar* desktop_id, - const gchar* player_object_path, - gpointer userdata) -{ - if (player_bridge != NULL){ - music_player_bridge_enable_track_specific_items_for_client (player_bridge, - desktop_id, - player_object_path); - } -} - -/** -main: -**/ -int -main (int argc, char ** argv) -{ - gboolean greeter_mode; - - gdk_init(&argc, &argv); - textdomain (GETTEXT_PACKAGE); - bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); - setlocale (LC_ALL, ""); - - IndicatorService *service = indicator_service_new_version (INDICATOR_SOUND_DBUS_NAME, - INDICATOR_SOUND_DBUS_VERSION); - g_signal_connect(G_OBJECT(service), - INDICATOR_SERVICE_SIGNAL_SHUTDOWN, - G_CALLBACK(service_shutdown), NULL); - - SoundServiceDbus* sound_service = g_object_new(SOUND_SERVICE_DBUS_TYPE, NULL); - g_signal_connect(G_OBJECT(sound_service), - "track-specific-item-requested", - G_CALLBACK(on_track_specific_item_requested), NULL); - g_signal_connect(G_OBJECT(sound_service), - "player-specific-item-requested", - G_CALLBACK(on_player_specific_item_requested), NULL); - - greeter_mode = get_greeter_mode(); - - DbusmenuMenuitem* root_menuitem = sound_service_dbus_create_root_item(sound_service, greeter_mode); - if (!greeter_mode) { - player_bridge = music_player_bridge_new(); - music_player_bridge_set_root_menu_item(player_bridge, root_menuitem); - } - - // Run the loop - mainloop = g_main_loop_new(NULL, FALSE); - g_main_loop_run(mainloop); - - return 0; -} - - - - diff --git a/src/sound-service.h b/src/sound-service.h deleted file mode 100644 index 7c5d0c3..0000000 --- a/src/sound-service.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef __INCLUDE_SOUND_SERVICE_H__ -#define __INCLUDE_SOUND_SERVICE_H__ - -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <config.h> -#include <unistd.h> -#include <glib/gi18n.h> - -#include <libindicator/indicator-service.h> - -#include "dbus-shared-names.h" - -// ENTRY AND EXIT POINTS -void service_shutdown(IndicatorService * service, gpointer user_data); -int main (int argc, char ** argv); - -#endif diff --git a/src/sound-service.xml b/src/sound-service.xml deleted file mode 100644 index cb1d928..0000000 --- a/src/sound-service.xml +++ /dev/null @@ -1,34 +0,0 @@ -<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> -<node name="/com/canonical/indicator/sound"> - <interface name="com.canonical.indicator.sound"> - <method name = "BlacklistMediaPlayer"> - <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/> - <arg type='s' name='player_desktop_name' direction="in"/> - <arg type='b' name='blacklist' direction="in"/> - <arg type='b' name='result' direction="out"/> - </method> - <method name = "IsBlacklisted"> - <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/> - <arg type='s' name='player_desktop_name' direction="in"/> - <arg type='b' name='result' direction="out"/> - </method> - <method name = "GetSoundState"> - <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/> - <arg type='i' name='current_state' direction="out"/> - </method> - <method name = "EnableTrackSpecificItems"> - <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/> - <arg type='o' name='player_object_path' direction="in"/> - <arg type='s' name='player_desktop_id' direction="in"/> - </method> - <method name = "EnablePlayerSpecificItems"> - <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/> - <arg type='o' name='player_object_path' direction="in"/> - <arg type='s' name='player_desktop_id' direction="in"/> - </method> - <signal name="SoundStateUpdate"> - <arg name="new_state" type="i" direction="out"/> - </signal> - </interface> -</node> - diff --git a/src/sound-state-manager.c b/src/sound-state-manager.c deleted file mode 100644 index c6b14ca..0000000 --- a/src/sound-state-manager.c +++ /dev/null @@ -1,480 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <libindicator/indicator-image-helper.h> -#include <libnotify/notify.h> - -#include "config.h" - -#include "sound-state-manager.h" -#include "dbus-shared-names.h" -#include "sound-state.h" - -typedef struct _SoundStateManagerPrivate SoundStateManagerPrivate; - -struct _SoundStateManagerPrivate -{ - GDBusProxy* dbus_proxy; - GHashTable* volume_states; - GList* blocked_animation_list; - SoundState current_state; - GtkImage* speaker_image; - NotifyNotification* notification; - GSettings *settings_manager; -}; - -#define SOUND_STATE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUND_TYPE_STATE_MANAGER, SoundStateManagerPrivate)) -G_DEFINE_TYPE (SoundStateManager, sound_state_manager, G_TYPE_OBJECT); - -static GtkIconSize design_team_size; -static gint blocked_id; -static gint animation_id; -static GList* blocked_iter = NULL; -static gboolean can_animate = FALSE; - -//Notifications -static void sound_state_manager_notification_init (SoundStateManager* self); - -//Animation/State related -static void sound_state_manager_prepare_blocked_animation (SoundStateManager* self); -static gboolean sound_state_manager_start_animation (gpointer user_data); -static gboolean sound_state_manager_fade_back_to_mute_image (gpointer user_data); -static void sound_state_manager_reset_mute_blocking_animation (SoundStateManager* self); -static void sound_state_manager_free_the_animation_list (SoundStateManager* self); -static void sound_state_manager_prepare_state_image_names (SoundStateManager* self); -static void sound_state_signal_cb ( GDBusProxy* proxy, - gchar* sender_name, - gchar* signal_name, - GVariant* parameters, - gpointer user_data ); -static gboolean sound_state_manager_can_proceed_with_blocking_animation (SoundStateManager* self); - - -static void -sound_state_manager_init (SoundStateManager* self) -{ - SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); - - priv->dbus_proxy = NULL; - priv->volume_states = NULL; - priv->speaker_image = NULL; - priv->blocked_animation_list = NULL; - priv->notification = NULL; - priv->settings_manager = NULL; - - priv->settings_manager = g_settings_new("com.canonical.indicator.sound"); - - sound_state_manager_prepare_state_image_names (self); - sound_state_manager_prepare_blocked_animation (self); - - priv->current_state = UNAVAILABLE; - priv->speaker_image = indicator_image_helper (g_hash_table_lookup (priv->volume_states, - GINT_TO_POINTER(priv->current_state))); -} - -static void -sound_state_manager_finalize (GObject *object) -{ - /* TODO: Add deinitalization code here */ - - G_OBJECT_CLASS (sound_state_manager_parent_class)->finalize (object); -} - -static void -sound_state_manager_dispose (GObject *object) -{ - SoundStateManager* self = SOUND_STATE_MANAGER (object); - SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); - - g_hash_table_destroy (priv->volume_states); - - sound_state_manager_free_the_animation_list (self); - - if (priv->notification) { - notify_uninit(); - } - - g_object_unref(priv->settings_manager); - - G_OBJECT_CLASS (sound_state_manager_parent_class)->dispose (object); -} - - -static void -sound_state_manager_class_init (SoundStateManagerClass *klass) -{ - GObjectClass* object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = sound_state_manager_finalize; - object_class->dispose = sound_state_manager_dispose; - - g_type_class_add_private (klass, sizeof (SoundStateManagerPrivate)); - - design_team_size = gtk_icon_size_register("design-team-size", 22, 22); -} - -static void -sound_state_manager_notification_init (SoundStateManager* self) -{ - static gboolean initialized = FALSE; - - /* one-time lazy initialization */ - if (initialized) - return; - initialized = TRUE; - - SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); - - if (!notify_init(PACKAGE_NAME)) - return; - - GList* caps = notify_get_server_caps(); - gboolean has_notify_osd = FALSE; - - if (caps) { - if (g_list_find_custom(caps, "x-canonical-private-synchronous", - (GCompareFunc) g_strcmp0)) { - has_notify_osd = TRUE; - } - g_list_foreach(caps, (GFunc) g_free, NULL); - g_list_free(caps); - } - - if (has_notify_osd) { - priv->notification = notify_notification_new(PACKAGE_NAME, NULL, NULL); - notify_notification_set_hint_string(priv->notification, - "x-canonical-private-synchronous", PACKAGE_NAME); - } -} - -void -sound_state_manager_show_notification (SoundStateManager *self, - double value) -{ - SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); - - sound_state_manager_notification_init (self); - - if (priv->notification == NULL || - g_settings_get_boolean (priv->settings_manager, "show-notify-osd-on-scroll") == FALSE){ - return; - } - - char *icon; - const int notify_value = CLAMP((int)value, -1, 101); - - SoundState state = sound_state_get_from_volume ((int)value); - - if (state == ZERO_LEVEL) { - // Not available for all the themes - icon = "notification-audio-volume-off"; - } else if (state == LOW_LEVEL) { - icon = "notification-audio-volume-low"; - } else if (state == MEDIUM_LEVEL) { - icon = "notification-audio-volume-medium"; - } else if (state == HIGH_LEVEL) { - icon = "notification-audio-volume-high"; - } else { - icon = "notification-audio-volume-muted"; - } - - notify_notification_update(priv->notification, PACKAGE_NAME, NULL, icon); - notify_notification_set_hint_int32(priv->notification, "value", notify_value); - notify_notification_show(priv->notification, NULL); -} - - -/* -Prepare states versus images names hash. -*/ -static void -sound_state_manager_prepare_state_image_names (SoundStateManager* self) -{ - SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); - priv->volume_states = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); - - g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(MUTED), g_strdup("audio-volume-muted-panel")); - g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(ZERO_LEVEL), g_strdup("audio-volume-low-zero-panel")); - g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(LOW_LEVEL), g_strdup("audio-volume-low-panel")); - g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(MEDIUM_LEVEL), g_strdup("audio-volume-medium-panel")); - g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(HIGH_LEVEL), g_strdup("audio-volume-high-panel")); - g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(BLOCKED), g_strdup("audio-volume-muted-blocking-panel")); - g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(UNAVAILABLE), g_strdup("audio-output-none-panel")); -} - -/* -prepare_blocked_animation: -Prepares the array of images to be used in the blocked animation. -Only called at startup. -*/ -static void -sound_state_manager_prepare_blocked_animation (SoundStateManager* self) -{ - SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); - - gchar* blocked_name = g_hash_table_lookup(priv->volume_states, - GINT_TO_POINTER(BLOCKED)); - gchar* muted_name = g_hash_table_lookup(priv->volume_states, - GINT_TO_POINTER(MUTED)); - - GtkImage* temp_image = indicator_image_helper(muted_name); - GdkPixbuf* mute_buf = gtk_image_get_pixbuf(temp_image); - - temp_image = indicator_image_helper(blocked_name); - GdkPixbuf* blocked_buf = gtk_image_get_pixbuf(temp_image); - - if (mute_buf == NULL || blocked_buf == NULL) { - //g_debug("Don bother with the animation, the theme aint got the goods !"); - return; - } - - int i; - - // sample 51 snapshots - range : 0-256 - for (i = 0; i < 51; i++) { - gdk_pixbuf_composite(mute_buf, blocked_buf, 0, 0, - gdk_pixbuf_get_width(mute_buf), - gdk_pixbuf_get_height(mute_buf), - 0, 0, 1, 1, GDK_INTERP_BILINEAR, MIN(255, i * 5)); - priv->blocked_animation_list = g_list_append(priv->blocked_animation_list, - gdk_pixbuf_copy(blocked_buf)); - } - can_animate = TRUE; - g_object_ref_sink(mute_buf); - g_object_unref(mute_buf); - g_object_ref_sink(blocked_buf); - g_object_unref(blocked_buf); -} - - -GtkImage* -sound_state_manager_get_current_icon (SoundStateManager* self) -{ - SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); - return priv->speaker_image; -} - -SoundState -sound_state_manager_get_current_state (SoundStateManager* self) -{ - SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); - return priv->current_state; -} - -/** - * sound_state_manager_connect_to_dbus: - * @returns: void - * When ready the indicator-sound calls this method to enable state communication - * between the indicator and the service. - **/ -void -sound_state_manager_connect_to_dbus (SoundStateManager* self, GDBusProxy* proxy) -{ - SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); - priv->dbus_proxy = proxy; - g_signal_connect (priv->dbus_proxy, "g-signal", - G_CALLBACK (sound_state_signal_cb), self); - - g_dbus_proxy_call ( priv->dbus_proxy, - "GetSoundState", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - (GAsyncReadyCallback)sound_state_manager_get_state_cb, - self); -} - -void -sound_state_manager_get_state_cb (GObject *object, - GAsyncResult *res, - gpointer user_data) -{ - g_return_if_fail (SOUND_IS_STATE_MANAGER (user_data)); - SoundStateManager* self = SOUND_STATE_MANAGER (user_data); - SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); - - GVariant *result, *value; - GError *error = NULL; - result = g_dbus_proxy_call_finish ( priv->dbus_proxy, - res, - &error ); - - if (error != NULL) { - g_warning("get_sound_state call failed: %s", error->message); - g_error_free(error); - return; - } - - value = g_variant_get_child_value(result, 0); - priv->current_state = (SoundState)g_variant_get_int32(value); - - gchar* image_name = g_hash_table_lookup (priv->volume_states, - GINT_TO_POINTER(priv->current_state) ); - indicator_image_helper_update (priv->speaker_image, image_name); - - g_variant_unref(value); - g_variant_unref(result); -} - -void -sound_state_manager_deal_with_disconnect (SoundStateManager* self) -{ - SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); - priv->current_state = UNAVAILABLE; - - gchar* image_name = g_hash_table_lookup (priv->volume_states, - GINT_TO_POINTER(priv->current_state) ); - indicator_image_helper_update (priv->speaker_image, image_name); -} - -static void -sound_state_signal_cb ( GDBusProxy* proxy, - gchar* sender_name, - gchar* signal_name, - GVariant* parameters, - gpointer user_data) -{ - //g_debug ( "!!! sound state manager signal_cb" ); - - g_return_if_fail (SOUND_IS_STATE_MANAGER (user_data)); - SoundStateManager* self = SOUND_STATE_MANAGER (user_data); - SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); - - g_variant_ref (parameters); - GVariant *value = g_variant_get_child_value (parameters, 0); - gint update = g_variant_get_int32 (value); - - //g_debug ( "!!! signal_cb with value %i", update); - - priv->current_state = (SoundState)update; - - g_variant_unref (parameters); - - if (g_strcmp0(signal_name, INDICATOR_SOUND_SIGNAL_STATE_UPDATE) == 0){ - - gchar* image_name = g_hash_table_lookup (priv->volume_states, - GINT_TO_POINTER(priv->current_state) ); - if (priv->current_state == BLOCKED && - sound_state_manager_can_proceed_with_blocking_animation (self) == TRUE) { - blocked_id = g_timeout_add_seconds (4, - sound_state_manager_start_animation, - self); - indicator_image_helper_update (priv->speaker_image, image_name); - } - else{ - indicator_image_helper_update (priv->speaker_image, image_name); - } - } - else { - g_warning ("sorry don't know what signal this is - %s", signal_name); - } -} - -void -sound_state_manager_style_changed_cb (GtkWidget *widget, - GtkStyle *previous_style, - gpointer user_data) -{ - g_debug("Just caught a style change event"); - g_return_if_fail (SOUND_IS_STATE_MANAGER (user_data)); - SoundStateManager* self = SOUND_STATE_MANAGER (user_data); - sound_state_manager_reset_mute_blocking_animation (self); - sound_state_manager_free_the_animation_list (self); - sound_state_manager_prepare_blocked_animation (self); -} - -static void -sound_state_manager_reset_mute_blocking_animation (SoundStateManager* self) -{ - if (animation_id != 0) { - //g_debug("about to remove the animation_id callback from the mainloop!!**"); - g_source_remove(animation_id); - animation_id = 0; - } - if (blocked_id != 0) { - //g_debug("about to remove the blocked_id callback from the mainloop!!**"); - g_source_remove(blocked_id); - blocked_id = 0; - } -} - -static void -sound_state_manager_free_the_animation_list (SoundStateManager* self) -{ - SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); - - if (priv->blocked_animation_list != NULL) { - g_list_foreach (priv->blocked_animation_list, (GFunc)g_object_unref, NULL); - g_list_free (priv->blocked_animation_list); - priv->blocked_animation_list = NULL; - } -} - - -static gboolean -sound_state_manager_start_animation (gpointer userdata) -{ - g_return_val_if_fail (SOUND_IS_STATE_MANAGER (userdata), FALSE); - SoundStateManager* self = SOUND_STATE_MANAGER (userdata); - SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); - - blocked_iter = priv->blocked_animation_list; - blocked_id = 0; - animation_id = g_timeout_add (50, - sound_state_manager_fade_back_to_mute_image, - self); - return FALSE; -} - -static gboolean -sound_state_manager_fade_back_to_mute_image (gpointer user_data) -{ - g_return_val_if_fail (SOUND_IS_STATE_MANAGER (user_data), FALSE); - SoundStateManager* self = SOUND_STATE_MANAGER (user_data); - SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE (self); - - if (blocked_iter != NULL) { - gtk_image_set_from_pixbuf (priv->speaker_image, blocked_iter->data); - blocked_iter = blocked_iter->next; - return TRUE; - } else { - animation_id = 0; - //g_debug("exit from animation now\n"); - g_dbus_proxy_call ( priv->dbus_proxy, - "GetSoundState", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - (GAsyncReadyCallback)sound_state_manager_get_state_cb, - self); - - return FALSE; - } -} - - -// Simple static helper to determine if the coast is clear to animate -static -gboolean sound_state_manager_can_proceed_with_blocking_animation (SoundStateManager* self) -{ - return (can_animate && blocked_id == 0 && animation_id == 0 ); -} - diff --git a/src/sound-state-manager.h b/src/sound-state-manager.h deleted file mode 100644 index 9287897..0000000 --- a/src/sound-state-manager.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef _SOUND_STATE_MANAGER_H_ -#define _SOUND_STATE_MANAGER_H_ - -#include <glib.h> -#include "common-defs.h" - -G_BEGIN_DECLS - -#define SOUND_TYPE_STATE_MANAGER (sound_state_manager_get_type ()) -#define SOUND_STATE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUND_TYPE_STATE_MANAGER, SoundStateManager)) -#define SOUND_STATE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUND_TYPE_STATE_MANAGER, SoundStateManagerClass)) -#define SOUND_IS_STATE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SOUND_TYPE_STATE_MANAGER)) -#define SOUND_IS_STATE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SOUND_TYPE_STATE_MANAGER)) -#define SOUND_STATE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUND_TYPE_STATE_MANAGER, SoundStateManagerClass)) - -typedef struct _SoundStateManagerClass SoundStateManagerClass; -typedef struct _SoundStateManager SoundStateManager; - -struct _SoundStateManagerClass -{ - GObjectClass parent_class; -}; - -struct _SoundStateManager -{ - GObject parent_instance; -}; - -GType sound_state_manager_get_type (void) G_GNUC_CONST; - -void sound_state_manager_style_changed_cb (GtkWidget *widget, - GtkStyle *previous_style, - gpointer user_data); -GtkImage* sound_state_manager_get_current_icon (SoundStateManager* self); -SoundState sound_state_manager_get_current_state (SoundStateManager* self); -void sound_state_manager_connect_to_dbus (SoundStateManager* self, - GDBusProxy* proxy); -void sound_state_manager_deal_with_disconnect (SoundStateManager* self); -void sound_state_manager_get_state_cb (GObject *object, - GAsyncResult *res, - gpointer user_data); -void sound_state_manager_show_notification (SoundStateManager *self, - double value); - - -G_END_DECLS - -#endif /* _SOUND_STATE_MANAGER_H_ */ diff --git a/src/sound-state.c b/src/sound-state.c deleted file mode 100644 index 72e411a..0000000 --- a/src/sound-state.c +++ /dev/null @@ -1,43 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "config.h" - -#include "sound-state.h" - -SoundState -sound_state_get_from_volume (int volume_percent) -{ - SoundState state = LOW_LEVEL; - - if (volume_percent < 30 && volume_percent > 0) { - state = LOW_LEVEL; - } - else if (volume_percent < 70 && volume_percent >= 30) { - state = MEDIUM_LEVEL; - } - else if (volume_percent >= 70) { - state = HIGH_LEVEL; - } - else if (volume_percent <= 0) { - state = ZERO_LEVEL; - } - return state; -} - diff --git a/src/sound-state.h b/src/sound-state.h deleted file mode 100644 index 9527c8e..0000000 --- a/src/sound-state.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef _SOUND_STATE_H_ -#define _SOUND_STATE_H_ - -#include <glib.h> -#include "common-defs.h" - -/* Helper functions for determining SOUNDSTATE */ - -SoundState sound_state_get_from_volume (int volume_percent); - -#endif /* _SOUND_STATE_H_ */ - diff --git a/src/specific-items-manager.vala b/src/specific-items-manager.vala deleted file mode 100644 index 923cf3f..0000000 --- a/src/specific-items-manager.vala +++ /dev/null @@ -1,109 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -using Dbusmenu; -using Gee; - -public class SpecificItemsManager : GLib.Object -{ - public enum category{ - TRACK, - PLAYER - } - - private PlayerController owner {get; set;} - private string dbus_path; - private Dbusmenu.Client client; - public Gee.ArrayList<Dbusmenu.MenuitemProxy> proxy_items {get; construct;} - private int of_type; - - public SpecificItemsManager (PlayerController controller, - string path, - category which_type) - { - this.of_type = which_type; - this.owner = controller; - this.dbus_path = path; - this.client = new Dbusmenu.Client (this.owner.dbus_name, this.dbus_path); - this.client.root_changed.connect (on_root_changed); - } - construct{ - this.proxy_items = new ArrayList<Dbusmenu.MenuitemProxy>(); - } - - private int figure_out_positioning() - { - int result = 0 ; - if (this.of_type == category.TRACK){ - result = this.owner.menu_offset + this.owner.WIDGET_QUANTITY + this.proxy_items.size; - } - else if (this.of_type == category.PLAYER){ - int pos = this.owner.menu_offset + this.owner.WIDGET_QUANTITY + this.owner.track_specific_count(); - //Surely the playlists item is there whether its visible or not ? - //TODO test playlists and player specific item positioning. - pos += this.owner.use_playlists == true ? 1 : 0; - result = pos; - } - debug ("!!!!! Menu pos of type %i is = %i", this.of_type, result); - return result; - } - - private void on_root_changed (GLib.Object? newroot) - { - if (newroot == null){ - debug ("root disappeared -remove proxyitems"); - foreach(var p in proxy_items){ - this.owner.root_menu.child_delete (p); - } - this.proxy_items.clear(); - debug ("array list size is now %i", this.proxy_items.size); - //this.proxy_items = new ArrayList<Dbusmenu.MenuitemProxy>(); - return; - } - - Dbusmenu.Menuitem? root = this.client.get_root(); - root.child_added.connect (on_child_added); - root.child_removed.connect (on_child_removed); - - // Fetch what children are there already. - GLib.List<weak void*> children = root.get_children().copy(); - - foreach (void* child in children) { - int pos = figure_out_positioning(); - unowned Dbusmenu.Menuitem item = (Dbusmenu.Menuitem)child; - Dbusmenu.MenuitemProxy proxy = new Dbusmenu.MenuitemProxy(item); - proxy_items.add (proxy); - debug ("Proxy item of label = %s added to collection", - item.property_get (MENUITEM_PROP_LABEL)); - this.owner.root_menu.child_add_position (proxy, pos); - - } - } - - private void on_child_added (GLib.Object child, uint position) - { - debug ("On child added Specific root node"); - } - - private void on_child_removed (GLib.Object child) - { - debug ("On child removed Specific root node"); - } - -} diff --git a/src/transport-menu-item.vala b/src/transport-menu-item.vala deleted file mode 100644 index 2a77d5a..0000000 --- a/src/transport-menu-item.vala +++ /dev/null @@ -1,100 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -using Dbusmenu; -using Gee; -using DbusmenuTransport; -using Transport; - -public class TransportMenuitem : PlayerItem -{ - private Transport.Action cached_action; - - private bool running { - get{ - return this.owner.current_state == PlayerController.state.CONNECTED; - } - } - - public TransportMenuitem(PlayerController parent) - { - Object(item_type: MENUITEM_TYPE, owner: parent); - } - construct{ - this.property_set_int(MENUITEM_PLAY_STATE, (int)Transport.State.PAUSED); - this.property_set (MENUITEM_PROP_LABEL, this.owner.app_info.get_name()); - this.cached_action = Transport.Action.NO_ACTION; - } - - /** - Please remove this timeout when the default player can handle mpris commands - immediately once it raises its dbus interface - **/ - public void handle_cached_action() - { - if (this.cached_action != Transport.Action.NO_ACTION){ - Timeout.add_seconds (1, send_cached_action); - } - } - - private bool send_cached_action() - { - this.owner.mpris_bridge.transport_update(this.cached_action); - this.cached_action = Transport.Action.NO_ACTION; - return false; - } - - public void change_play_state (Transport.State update) - { - int temp = (int)update; - this.property_set_int(MENUITEM_PLAY_STATE, temp); - } - - public override void handle_event(string name, - Variant input_value, - uint timestamp) - { - if (name != DbusmenuTransport.MENUITEM_STATE_CHANGE) - return; - - Variant v = input_value; - if ( input_value.is_of_type (VariantType.VARIANT)){ - v = input_value.get_variant(); - } - - int32 input = v.get_int32(); - - if (this.running == true){ - this.owner.mpris_bridge.transport_update((Transport.Action)input); - } - else{ - this.cached_action = (Transport.Action)input; - this.owner.instantiate(timestamp); - this.property_set_int (MENUITEM_PLAY_STATE, (int)Transport.State.LAUNCHING); - } - } - - public static HashSet<string> attributes_format() - { - HashSet<string> attrs = new HashSet<string>(); - attrs.add(MENUITEM_PLAY_STATE); - return attrs; - } - -} diff --git a/src/transport-widget.c b/src/transport-widget.c deleted file mode 100644 index 7df656e..0000000 --- a/src/transport-widget.c +++ /dev/null @@ -1,1886 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - Mirco Müller <mirco.mueller@canonical.com> - Andrea Cimitan <andrea.cimitan@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. - -Uses code from ctk -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <math.h> -#include "transport-widget.h" - - -#define RECT_WIDTH 130.0f -#define Y 7.0f -#define X 70.0f -#define INNER_RADIUS 12.5 -#define MIDDLE_RADIUS 13.0f -#define OUTER_RADIUS 14.5f -#define CIRCLE_RADIUS 21.0f -#define PREV_WIDTH 25.0f -#define PREV_HEIGHT 17.0f -#define NEXT_WIDTH 25.0f //PREV_WIDTH -#define NEXT_HEIGHT 17.0f //PREV_HEIGHT -#define TRI_WIDTH 11.0f -#define TRI_HEIGHT 13.0f -#define TRI_OFFSET 6.0f -#define PREV_X 68.0f -#define PREV_Y 13.0f -#define NEXT_X 146.0f -#define NEXT_Y 13.0f //prev_y -#define PAUSE_WIDTH 21.0f -#define PAUSE_HEIGHT 27.0f -#define BAR_WIDTH 4.5f -#define BAR_HEIGHT 24.0f -#define BAR_OFFSET 10.0f -#define PAUSE_X 111.0f -#define PAUSE_Y 7.0f -#define PLAY_WIDTH 28.0f -#define PLAY_HEIGHT 29.0f -#define PLAY_PADDING 5.0f -#define INNER_START_SHADE 0.98 -#define INNER_END_SHADE 0.98 -#define MIDDLE_START_SHADE 1.0 -#define MIDDLE_END_SHADE 1.0 -#define OUTER_START_SHADE 0.75 -#define OUTER_END_SHADE 1.3 -#define SHADOW_BUTTON_SHADE 0.8 -#define OUTER_PLAY_START_SHADE 0.7 -#define OUTER_PLAY_END_SHADE 1.38 -#define BUTTON_START_SHADE 1.1 -#define BUTTON_END_SHADE 0.9 -#define BUTTON_SHADOW_SHADE 0.8 -#define INNER_COMPRESSED_START_SHADE 1.0 -#define INNER_COMPRESSED_END_SHADE 1.0 - -typedef struct _TransportWidgetPrivate TransportWidgetPrivate; - -struct _TransportWidgetPrivate -{ - TransportAction current_command; - TransportAction key_event; - TransportAction motion_event; - TransportState current_state; - GHashTable* command_coordinates; - DbusmenuMenuitem* twin_item; - gboolean has_focus; - gint hold_timer; - gint skip_frequency; -}; - -#if GTK_CHECK_VERSION(3, 0, 0) -static GList *transport_widget_list = NULL; -static GtkStyleContext *spinner_style_context = NULL; -static GtkWidgetPath *spinner_widget_path = NULL; -#endif - -// TODO refactor the UI handlers, consolidate functionality between key press /release -// and button press / release. -#define TRANSPORT_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRANSPORT_WIDGET_TYPE, TransportWidgetPrivate)) - -/* Gobject boiler plate */ -static void transport_widget_class_init (TransportWidgetClass *klass); -static void transport_widget_init (TransportWidget *self); -static void transport_widget_dispose (GObject *object); -static void transport_widget_finalize (GObject *object); -G_DEFINE_TYPE (TransportWidget, transport_widget, GTK_TYPE_MENU_ITEM); - -/* essentials */ -static void transport_widget_set_twin_item ( TransportWidget* self, - DbusmenuMenuitem* twin_item); -#if ! GTK_CHECK_VERSION(3, 0, 0) -static gboolean transport_widget_expose ( GtkWidget *button, GdkEventExpose *event); -#endif -static gboolean draw (GtkWidget* button, cairo_t *cr); - -/* UI and dbusmenu callbacks */ -static gboolean transport_widget_button_press_event (GtkWidget *menuitem, - GdkEventButton *event); -static gboolean transport_widget_button_release_event (GtkWidget *menuitem, - GdkEventButton *event); -static gboolean transport_widget_motion_notify_event (GtkWidget *menuitem, - GdkEventMotion *event); -static gboolean transport_widget_leave_notify_event (GtkWidget *menuitem, - GdkEventCrossing *event); -static void transport_widget_property_update ( DbusmenuMenuitem* item, - gchar * property, - GVariant * value, - gpointer userdata ); -static void transport_widget_menu_hidden ( GtkWidget *menu, - TransportWidget *transport); -static void transport_widget_notify ( GObject *item, - GParamSpec *pspec, - gpointer user_data ); -static TransportAction transport_widget_determine_button_event ( TransportWidget* button, - GdkEventButton* event); -static TransportAction transport_widget_determine_motion_event ( TransportWidget* button, - GdkEventMotion* event); -static void transport_widget_react_to_button_release ( TransportWidget* button, - TransportAction command); -static void transport_widget_toggle_play_pause ( TransportWidget* button, - TransportState update); -static void transport_widget_select (GtkWidget* menu, gpointer Userdata); -static void transport_widget_deselect (GtkWidget* menu, gpointer Userdata); -static TransportAction transport_widget_collision_detection (gint x, gint y); -static void transport_widget_start_timing (TransportWidget* widget); -static gboolean transport_widget_trigger_seek (gpointer userdata); -static gboolean transport_widget_seek (gpointer userdata); - - -/// Init functions ////////////////////////////////////////////////////////// -static void -transport_widget_class_init (TransportWidgetClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass); - - g_type_class_add_private (klass, sizeof (TransportWidgetPrivate)); - - widget_class->button_press_event = transport_widget_button_press_event; - widget_class->button_release_event = transport_widget_button_release_event; - widget_class->motion_notify_event = transport_widget_motion_notify_event; - widget_class->leave_notify_event = transport_widget_leave_notify_event; -#if GTK_CHECK_VERSION(3, 0, 0) - widget_class->draw = draw; -#else - widget_class->expose_event = transport_widget_expose; -#endif - - gobject_class->dispose = transport_widget_dispose; - gobject_class->finalize = transport_widget_finalize; -} - -static void -transport_widget_init (TransportWidget *self) -{ - TransportWidgetPrivate* priv = TRANSPORT_WIDGET_GET_PRIVATE(self); - #if GTK_CHECK_VERSION(3, 0, 0) - if (transport_widget_list == NULL){ - /* append the object to the static linked list. */ - transport_widget_list = g_list_append (transport_widget_list, self); - - /* create widget path */ - spinner_widget_path = gtk_widget_path_new(); - - gtk_widget_path_append_type (spinner_widget_path, GTK_TYPE_MENU); - gtk_widget_path_append_type (spinner_widget_path, GTK_TYPE_MENU_ITEM); - gint pos = gtk_widget_path_append_type (spinner_widget_path, GTK_TYPE_SPINNER); - gtk_widget_path_iter_set_name (spinner_widget_path, pos, "IndicatorSoundSpinner"); - - /* create style context and append path */ - spinner_style_context = gtk_style_context_new(); - - gtk_style_context_set_path (spinner_style_context, spinner_widget_path); - gtk_style_context_add_class (spinner_style_context, GTK_STYLE_CLASS_MENU); - gtk_style_context_add_class (spinner_style_context, GTK_STYLE_CLASS_MENUITEM); - gtk_style_context_add_class (spinner_style_context, GTK_STYLE_CLASS_SPINNER); - } - #endif - priv->current_command = TRANSPORT_ACTION_NO_ACTION; - priv->current_state = TRANSPORT_STATE_PAUSED; - priv->key_event = TRANSPORT_ACTION_NO_ACTION; - priv->motion_event = TRANSPORT_ACTION_NO_ACTION; - priv->has_focus = FALSE; - priv->hold_timer = 0; - priv->skip_frequency = 0; - priv->command_coordinates = g_hash_table_new_full(g_direct_hash, - g_direct_equal, - NULL, - (GDestroyNotify)g_list_free); - GList* previous_list = NULL; - previous_list = g_list_insert(previous_list, GINT_TO_POINTER(15), 0); - previous_list = g_list_insert(previous_list, GINT_TO_POINTER(5), 1); - previous_list = g_list_insert(previous_list, GINT_TO_POINTER(60), 2); - previous_list = g_list_insert(previous_list, GINT_TO_POINTER(34), 3); - g_hash_table_insert(priv->command_coordinates, - GINT_TO_POINTER(TRANSPORT_ACTION_PREVIOUS), - previous_list); - - GList* play_list = NULL; - play_list = g_list_insert(play_list, GINT_TO_POINTER(58), 0); - play_list = g_list_insert(play_list, GINT_TO_POINTER(0), 1); - play_list = g_list_insert(play_list, GINT_TO_POINTER(50), 2); - play_list = g_list_insert(play_list, GINT_TO_POINTER(43), 3); - - g_hash_table_insert(priv->command_coordinates, - GINT_TO_POINTER(TRANSPORT_ACTION_PLAY_PAUSE), - play_list); - - GList* next_list = NULL; - next_list = g_list_insert(next_list, GINT_TO_POINTER(100), 0); - next_list = g_list_insert(next_list, GINT_TO_POINTER(5), 1); - next_list = g_list_insert(next_list, GINT_TO_POINTER(60), 2); - next_list = g_list_insert(next_list, GINT_TO_POINTER(34), 3); - - g_hash_table_insert(priv->command_coordinates, - GINT_TO_POINTER(TRANSPORT_ACTION_NEXT), - next_list); - gtk_widget_set_size_request(GTK_WIDGET(self), 200, 43); - g_signal_connect (G_OBJECT(self), - "notify", - G_CALLBACK (transport_widget_notify), - NULL); - g_signal_connect (G_OBJECT(self), - "select", - G_CALLBACK (transport_widget_select), - NULL); - g_signal_connect (G_OBJECT(self), - "deselect", - G_CALLBACK (transport_widget_deselect), - NULL); - gtk_widget_realize ( GTK_WIDGET (self) ); - -} - -static void -transport_widget_dispose (GObject *object) -{ - #if GTK_CHECK_VERSION(3, 0, 0) - transport_widget_list = g_list_remove (transport_widget_list, object); - - if (transport_widget_list == NULL){ - if (spinner_widget_path != NULL){ - gtk_widget_path_free (spinner_widget_path); - spinner_widget_path = NULL; - } - - if (spinner_style_context != NULL){ - g_object_unref (spinner_style_context); - spinner_style_context = NULL; - } - } - #endif - - TransportWidgetPrivate* priv = TRANSPORT_WIDGET_GET_PRIVATE(object); - if (priv->command_coordinates != NULL) { - g_hash_table_destroy (priv->command_coordinates); - priv->command_coordinates = NULL; - } - - G_OBJECT_CLASS (transport_widget_parent_class)->dispose (object); -} - -static void -transport_widget_finalize (GObject *object) -{ - - - G_OBJECT_CLASS (transport_widget_parent_class)->finalize (object); -} - -#if ! GTK_CHECK_VERSION(3, 0, 0) -static gboolean -transport_widget_expose (GtkWidget *button, GdkEventExpose *event) -{ - cairo_t *cr; - cr = gdk_cairo_create (gtk_widget_get_window (button)); - - cairo_rectangle (cr, - event->area.x, event->area.y, - event->area.width, event->area.height); - - cairo_clip(cr); - draw (button, cr); - - cairo_destroy (cr); - return FALSE; -} -#endif - -gboolean -transport_widget_is_selected ( TransportWidget* widget ) -{ - g_return_val_if_fail (IS_TRANSPORT_WIDGET (widget), FALSE); - TransportWidgetPrivate* priv = TRANSPORT_WIDGET_GET_PRIVATE(widget); - return priv->has_focus; -} - -static void -transport_widget_toggle_play_pause(TransportWidget* button, - TransportState update) -{ - TransportWidgetPrivate* priv = TRANSPORT_WIDGET_GET_PRIVATE(button); - priv->current_state = update; - gtk_widget_queue_draw (GTK_WIDGET(button)); -} - -static void -transport_widget_notify ( GObject *item, - GParamSpec *pspec, - gpointer user_data ) -{ - if (g_strcmp0 (pspec->name, "parent")){ - GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (item)); - if (parent){ - g_signal_connect ( parent, "hide", - G_CALLBACK (transport_widget_menu_hidden), - item ); - } - } -} - -static void -transport_widget_menu_hidden ( GtkWidget *menu, - TransportWidget *transport) -{ - g_return_if_fail(IS_TRANSPORT_WIDGET(transport)); - transport_widget_react_to_button_release(transport, TRANSPORT_ACTION_NO_ACTION); -} - -static gboolean -transport_widget_motion_notify_event (GtkWidget *menuitem, - GdkEventMotion *event) -{ - //g_debug("transport_widget_motion_notify_event()"); - - g_return_val_if_fail ( IS_TRANSPORT_WIDGET(menuitem), FALSE ); - TransportWidgetPrivate* priv = TRANSPORT_WIDGET_GET_PRIVATE ( TRANSPORT_WIDGET(menuitem) ); - TransportAction result = transport_widget_determine_motion_event ( TRANSPORT_WIDGET(menuitem), - event); - priv->motion_event = result; - gtk_widget_queue_draw (menuitem); - if (priv->hold_timer != 0){ - g_source_remove (priv->hold_timer); - priv->hold_timer = 0; - } - if(priv->skip_frequency != 0){ - g_source_remove (priv->skip_frequency); - priv->skip_frequency = 0; - } - return TRUE; -} - -static gboolean -transport_widget_leave_notify_event (GtkWidget *menuitem, - GdkEventCrossing *event) -{ - //g_debug("transport_widget_leave_notify_event()"); - - g_return_val_if_fail ( IS_TRANSPORT_WIDGET(menuitem), FALSE ); - TransportWidgetPrivate* priv = TRANSPORT_WIDGET_GET_PRIVATE ( TRANSPORT_WIDGET(menuitem) ); - - priv->motion_event = TRANSPORT_ACTION_NO_ACTION; - priv->current_command = TRANSPORT_ACTION_NO_ACTION; - gtk_widget_queue_draw (GTK_WIDGET(menuitem)); - - return TRUE; -} - -static gboolean -transport_widget_button_press_event (GtkWidget *menuitem, - GdkEventButton *event) -{ - //g_debug("transport_widget_button_press_event()"); - - g_return_val_if_fail ( IS_TRANSPORT_WIDGET(menuitem), FALSE ); - TransportWidgetPrivate* priv = TRANSPORT_WIDGET_GET_PRIVATE ( TRANSPORT_WIDGET(menuitem) ); - TransportAction result = transport_widget_determine_button_event ( TRANSPORT_WIDGET(menuitem), - event); - if(result != TRANSPORT_ACTION_NO_ACTION){ - priv->current_command = result; - gtk_widget_queue_draw (GTK_WIDGET(menuitem)); - if (priv->current_command == TRANSPORT_ACTION_PREVIOUS || - priv->current_command == TRANSPORT_ACTION_NEXT){ - transport_widget_start_timing (TRANSPORT_WIDGET(menuitem)); - } - } - return TRUE; -} -/** - * TODO rename or merge - * @param widget - */ -static void -transport_widget_start_timing (TransportWidget* widget) -{ - TransportWidgetPrivate* priv = TRANSPORT_WIDGET_GET_PRIVATE (widget); - if (priv->hold_timer == 0){ - priv->hold_timer = g_timeout_add (800, - transport_widget_trigger_seek, - widget); - } -} - -static gboolean -transport_widget_trigger_seek (gpointer userdata) -{ - g_return_val_if_fail ( IS_TRANSPORT_WIDGET(userdata), FALSE ); - TransportWidgetPrivate* priv = TRANSPORT_WIDGET_GET_PRIVATE (TRANSPORT_WIDGET(userdata)); - if (priv->skip_frequency == 0){ - priv->skip_frequency = g_timeout_add (100, - transport_widget_seek, - userdata); - } - priv->hold_timer = 0; - return FALSE; -} - -/** - * This will be called repeatedly until a key/button release is received - * @param userdata - * @return - */ -static gboolean -transport_widget_seek (gpointer userdata) -{ - g_return_val_if_fail ( IS_TRANSPORT_WIDGET(userdata), FALSE ); - TransportWidgetPrivate* priv = TRANSPORT_WIDGET_GET_PRIVATE (TRANSPORT_WIDGET(userdata)); - GVariant* new_transport_state; - if(priv->current_command == TRANSPORT_ACTION_NEXT){ - //g_debug ("we should be skipping forward"); - new_transport_state = g_variant_new_int32 ((int)TRANSPORT_ACTION_FORWIND); - - dbusmenu_menuitem_handle_event ( priv->twin_item, - DBUSMENU_TRANSPORT_MENUITEM_STATE_CHANGE, - new_transport_state, - 0 ); - - } - else if(priv->current_command == TRANSPORT_ACTION_PREVIOUS){ - //g_debug ("we should be skipping back"); - new_transport_state = g_variant_new_int32 ((int)TRANSPORT_ACTION_REWIND); - - dbusmenu_menuitem_handle_event ( priv->twin_item, - DBUSMENU_TRANSPORT_MENUITEM_STATE_CHANGE, - new_transport_state, - 0 ); - } - - return TRUE; -} - -static gboolean -transport_widget_button_release_event (GtkWidget *menuitem, - GdkEventButton *event) -{ - g_return_val_if_fail(IS_TRANSPORT_WIDGET(menuitem), FALSE); - TransportWidget* transport = TRANSPORT_WIDGET(menuitem); - TransportWidgetPrivate * priv = TRANSPORT_WIDGET_GET_PRIVATE ( transport ); - TransportAction result = transport_widget_determine_button_event ( transport, - event ); - if (result != TRANSPORT_ACTION_NO_ACTION && - priv->current_command == result && - priv->skip_frequency == 0){ - GVariant* new_transport_state = g_variant_new_int32 ((int)result); - dbusmenu_menuitem_handle_event ( priv->twin_item, - DBUSMENU_TRANSPORT_MENUITEM_STATE_CHANGE, - new_transport_state, - 0 ); - } - transport_widget_react_to_button_release ( transport, - result ); - return TRUE; -} - -static void -transport_widget_select (GtkWidget* item, gpointer Userdata) -{ - TransportWidget* transport = TRANSPORT_WIDGET(item); - TransportWidgetPrivate * priv = TRANSPORT_WIDGET_GET_PRIVATE ( transport ); - priv->has_focus = TRUE; -} - -static void -transport_widget_deselect (GtkWidget* item, gpointer Userdata) -{ - TransportWidget* transport = TRANSPORT_WIDGET(item); - TransportWidgetPrivate * priv = TRANSPORT_WIDGET_GET_PRIVATE ( transport ); - priv->has_focus = FALSE; -} - -void -transport_widget_react_to_key_press_event ( TransportWidget* transport, - TransportAction transport_event ) -{ - if(transport_event != TRANSPORT_ACTION_NO_ACTION){ - TransportWidgetPrivate * priv = TRANSPORT_WIDGET_GET_PRIVATE ( transport ); - priv->current_command = transport_event; - priv->key_event = transport_event; - gtk_widget_realize ( GTK_WIDGET(transport) ); - gtk_widget_queue_draw (GTK_WIDGET(transport) ); - if (priv->current_command == TRANSPORT_ACTION_PREVIOUS || - priv->current_command == TRANSPORT_ACTION_NEXT){ - transport_widget_start_timing (transport); - } - } -} - -void -transport_widget_react_to_key_release_event ( TransportWidget* transport, - TransportAction transport_event ) -{ - if(transport_event != TRANSPORT_ACTION_NO_ACTION){ - TransportWidgetPrivate * priv = TRANSPORT_WIDGET_GET_PRIVATE ( transport ); - GVariant* new_transport_event = g_variant_new_int32((int)transport_event); - if (priv->skip_frequency == 0){ - dbusmenu_menuitem_handle_event ( priv->twin_item, - DBUSMENU_TRANSPORT_MENUITEM_STATE_CHANGE, - new_transport_event, - 0 ); - } - } - transport_widget_react_to_button_release ( transport, - transport_event ); -} - -void -transport_widget_focus_update ( TransportWidget* transport, gboolean focus ) -{ - TransportWidgetPrivate * priv = TRANSPORT_WIDGET_GET_PRIVATE ( transport ); - priv->has_focus = focus; -} - -static TransportAction -transport_widget_determine_button_event( TransportWidget* button, - GdkEventButton* event ) -{ - return transport_widget_collision_detection (event->x, event->y); -} - -static TransportAction -transport_widget_determine_motion_event( TransportWidget* button, - GdkEventMotion* event ) -{ - return transport_widget_collision_detection (event->x, event->y); -} - -static TransportAction -transport_widget_collision_detection ( gint x, - gint y ) -{ - TransportAction event = TRANSPORT_ACTION_NO_ACTION; - - if (x > 57 && x < 102 - && y > 12 && y < 40){ - event = TRANSPORT_ACTION_PREVIOUS; - } - else if (x > 101 && x < 143 - && y > 5 && y < 47){ - event = TRANSPORT_ACTION_PLAY_PAUSE; - } - else if (x > 142 && x < 187 - && y > 12 && y < 40){ - event = TRANSPORT_ACTION_NEXT; - } - return event; -} - -static void -transport_widget_react_to_button_release ( TransportWidget* button, - TransportAction command ) -{ - g_return_if_fail(IS_TRANSPORT_WIDGET(button)); - TransportWidgetPrivate* priv = TRANSPORT_WIDGET_GET_PRIVATE(button); - - priv->current_command = TRANSPORT_ACTION_NO_ACTION; - priv->key_event = TRANSPORT_ACTION_NO_ACTION; - - gtk_widget_queue_draw (GTK_WIDGET(button)); - if (priv->hold_timer != 0){ - g_source_remove (priv->hold_timer); - priv->hold_timer = 0; - } - if(priv->skip_frequency != 0){ - g_source_remove (priv->skip_frequency); - priv->skip_frequency = 0; - } -} - -/// internal helper functions ////////////////////////////////////////////////// - -static void -draw_gradient (cairo_t* cr, - double x, - double y, - double w, - double r, - double* rgba_start, - double* rgba_end) -{ - cairo_pattern_t* pattern = NULL; - - cairo_move_to (cr, x, y); - cairo_line_to (cr, x + w - 2.0f * r, y); - cairo_arc (cr, - x + w - 2.0f * r, - y + r, - r, - -90.0f * G_PI / 180.0f, - 90.0f * G_PI / 180.0f); - cairo_line_to (cr, x, y + 2.0f * r); - cairo_arc (cr, - x, - y + r, - r, - 90.0f * G_PI / 180.0f, - 270.0f * G_PI / 180.0f); - cairo_close_path (cr); - - pattern = cairo_pattern_create_linear (x, y, x, y + 2.0f * r); - cairo_pattern_add_color_stop_rgba (pattern, - 0.0f, - rgba_start[0], - rgba_start[1], - rgba_start[2], - rgba_start[3]); - cairo_pattern_add_color_stop_rgba (pattern, - 1.0f, - rgba_end[0], - rgba_end[1], - rgba_end[2], - rgba_end[3]); - cairo_set_source (cr, pattern); - cairo_fill (cr); - cairo_pattern_destroy (pattern); -} - -static void -draw_circle (cairo_t* cr, - double x, - double y, - double r, - double* rgba_start, - double* rgba_end) -{ - cairo_pattern_t* pattern = NULL; - - cairo_move_to (cr, x, y); - cairo_arc (cr, - x + r, - y + r, - r, - 0.0f * G_PI / 180.0f, - 360.0f * G_PI / 180.0f); - - pattern = cairo_pattern_create_linear (x, y, x, y + 2.0f * r); - cairo_pattern_add_color_stop_rgba (pattern, - 0.0f, - rgba_start[0], - rgba_start[1], - rgba_start[2], - rgba_start[3]); - cairo_pattern_add_color_stop_rgba (pattern, - 1.0f, - rgba_end[0], - rgba_end[1], - rgba_end[2], - rgba_end[3]); - cairo_set_source (cr, pattern); - cairo_fill (cr); - cairo_pattern_destroy (pattern); -} - -static void -_setup (cairo_t** cr, - cairo_surface_t** surf, - gint width, - gint height) -{ - if (!cr || !surf) - return; - - *surf = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); - *cr = cairo_create (*surf); - cairo_scale (*cr, 1.0f, 1.0f); - cairo_set_operator (*cr, CAIRO_OPERATOR_CLEAR); - cairo_paint (*cr); - cairo_set_operator (*cr, CAIRO_OPERATOR_OVER); -} - -static void -_mask_prev (cairo_t* cr, - double x, - double y, - double tri_width, - double tri_height, - double tri_offset) -{ - if (!cr) - return; - - cairo_move_to (cr, x, y + tri_height / 2.0f); - cairo_line_to (cr, x + tri_width, y); - cairo_line_to (cr, x + tri_width, y + tri_height); - x += tri_offset; - cairo_move_to (cr, x, y + tri_height / 2.0f); - cairo_line_to (cr, x + tri_width, y); - cairo_line_to (cr, x + tri_width, y + tri_height); - x -= tri_offset; - cairo_rectangle (cr, x, y, 2.5f, tri_height); - cairo_close_path (cr); -} - -static void -_mask_next (cairo_t* cr, - double x, - double y, - double tri_width, - double tri_height, - double tri_offset) -{ - if (!cr) - return; - - cairo_move_to (cr, x, y); - cairo_line_to (cr, x + tri_width, y + tri_height / 2.0f); - cairo_line_to (cr, x, y + tri_height); - x += tri_offset; - cairo_move_to (cr, x, y); - cairo_line_to (cr, x + tri_width, y + tri_height / 2.0f); - cairo_line_to (cr, x, y + tri_height); - x -= tri_offset; - x += 2.0f * tri_width - tri_offset - 1.0f; - cairo_rectangle (cr, x, y, 2.5f, tri_height); - - cairo_close_path (cr); -} - -static void -_mask_pause (cairo_t* cr, - double x, - double y, - double bar_width, - double bar_height, - double bar_offset) -{ - if (!cr) - return; - - cairo_set_line_width (cr, bar_width); - cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); - - x += bar_width; - y += bar_width; - cairo_move_to (cr, x, y); - cairo_line_to (cr, x, y + bar_height); - cairo_move_to (cr, x + bar_offset, y); - cairo_line_to (cr, x + bar_offset, y + bar_height); - -} - -static void -_mask_play (cairo_t* cr, - double x, - double y, - double tri_width, - double tri_height) -{ - if (!cr) - return; - - cairo_move_to (cr, x, y); - cairo_line_to (cr, x + tri_width, y + tri_height / 2.0f); - cairo_line_to (cr, x, y + tri_height); - cairo_close_path (cr); - -} - -static void -_fill (cairo_t* cr, - double x_start, - double y_start, - double x_end, - double y_end, - double* rgba_start, - double* rgba_end, - gboolean stroke) -{ - cairo_pattern_t* pattern = NULL; - - if (!cr || !rgba_start || !rgba_end) - return; - - pattern = cairo_pattern_create_linear (x_start, y_start, x_end, y_end); - cairo_pattern_add_color_stop_rgba (pattern, - 0.0f, - rgba_start[0], - rgba_start[1], - rgba_start[2], - rgba_start[3]); - cairo_pattern_add_color_stop_rgba (pattern, - 1.0f, - rgba_end[0], - rgba_end[1], - rgba_end[2], - rgba_end[3]); - cairo_set_source (cr, pattern); - if (stroke) - cairo_stroke (cr); - else - cairo_fill (cr); - cairo_pattern_destroy (pattern); -} - -static void -_finalize (cairo_t* cr, - cairo_t** cr_surf, - cairo_surface_t** surf, - double x, - double y) -{ - if (!cr || !cr_surf || !surf) - return; - - cairo_set_source_surface (cr, *surf, x, y); - cairo_paint (cr); - cairo_surface_destroy (*surf); - cairo_destroy (*cr_surf); -} - -static void -_finalize_repaint (cairo_t* cr, - cairo_t** cr_surf, - cairo_surface_t** surf, - double x, - double y, - int repaints) -{ - if (!cr || !cr_surf || !surf) - return; - - while (repaints > 0) - { - cairo_set_source_surface (cr, *surf, x, y); - cairo_paint (cr); - repaints--; - } - - cairo_surface_destroy (*surf); - cairo_destroy (*cr_surf); -} - -static void -_color_rgb_to_hls (gdouble *r, - gdouble *g, - gdouble *b) -{ - gdouble min; - gdouble max; - gdouble red; - gdouble green; - gdouble blue; - gdouble h = 0; - gdouble l; - gdouble s; - gdouble delta; - - red = *r; - green = *g; - blue = *b; - - if (red > green) - { - if (red > blue) - max = red; - else - max = blue; - - if (green < blue) - min = green; - else - min = blue; - } - else - { - if (green > blue) - max = green; - else - max = blue; - - if (red < blue) - min = red; - else - min = blue; - } - l = (max+min)/2; - if (fabs (max-min) < 0.0001) - { - h = 0; - s = 0; - } - else - { - if (l <= 0.5) - s = (max-min)/(max+min); - else - s = (max-min)/(2-max-min); - - delta = (max -min) != 0 ? (max -min) : 1; - - if(delta == 0) - delta = 1; - if (red == max) - h = (green-blue)/delta; - else if (green == max) - h = 2+(blue-red)/delta; - else if (blue == max) - h = 4+(red-green)/delta; - - h *= 60; - if (h < 0.0) - h += 360; - } - - *r = h; - *g = l; - *b = s; -} - -static void -_color_hls_to_rgb (gdouble *h, - gdouble *l, - gdouble *s) -{ - gdouble hue; - gdouble lightness; - gdouble saturation; - gdouble m1, m2; - gdouble r, g, b; - - lightness = *l; - saturation = *s; - - if (lightness <= 0.5) - m2 = lightness*(1+saturation); - else - m2 = lightness+saturation-lightness*saturation; - - m1 = 2*lightness-m2; - - if (saturation == 0) - { - *h = lightness; - *l = lightness; - *s = lightness; - } - else - { - hue = *h+120; - while (hue > 360) - hue -= 360; - while (hue < 0) - hue += 360; - - if (hue < 60) - r = m1+(m2-m1)*hue/60; - else if (hue < 180) - r = m2; - else if (hue < 240) - r = m1+(m2-m1)*(240-hue)/60; - else - r = m1; - - hue = *h; - while (hue > 360) - hue -= 360; - while (hue < 0) - hue += 360; - - if (hue < 60) - g = m1+(m2-m1)*hue/60; - else if (hue < 180) - g = m2; - else if (hue < 240) - g = m1+(m2-m1)*(240-hue)/60; - else - g = m1; - - hue = *h-120; - while (hue > 360) - hue -= 360; - while (hue < 0) - hue += 360; - - if (hue < 60) - b = m1+(m2-m1)*hue/60; - else if (hue < 180) - b = m2; - else if (hue < 240) - b = m1+(m2-m1)*(240-hue)/60; - else - b = m1; - - *h = r; - *l = g; - *s = b; - } -} - -void -_color_shade (const CairoColorRGB *a, float k, CairoColorRGB *b) -{ - double red; - double green; - double blue; - - red = a->r; - green = a->g; - blue = a->b; - - if (k == 1.0) - { - b->r = red; - b->g = green; - b->b = blue; - return; - } - - _color_rgb_to_hls (&red, &green, &blue); - - green *= k; - if (green > 1.0) - green = 1.0; - else if (green < 0.0) - green = 0.0; - - blue *= k; - if (blue > 1.0) - blue = 1.0; - else if (blue < 0.0) - blue = 0.0; - - _color_hls_to_rgb (&red, &green, &blue); - - b->r = red; - b->g = green; - b->b = blue; -} - -static inline void -_blurinner (guchar* pixel, - gint* zR, - gint* zG, - gint* zB, - gint* zA, - gint alpha, - gint aprec, - gint zprec) -{ - gint R; - gint G; - gint B; - guchar A; - - R = *pixel; - G = *(pixel + 1); - B = *(pixel + 2); - A = *(pixel + 3); - - *zR += (alpha * ((R << zprec) - *zR)) >> aprec; - *zG += (alpha * ((G << zprec) - *zG)) >> aprec; - *zB += (alpha * ((B << zprec) - *zB)) >> aprec; - *zA += (alpha * ((A << zprec) - *zA)) >> aprec; - - *pixel = *zR >> zprec; - *(pixel + 1) = *zG >> zprec; - *(pixel + 2) = *zB >> zprec; - *(pixel + 3) = *zA >> zprec; -} - -static inline void -_blurrow (guchar* pixels, - gint width, - gint height, - gint channels, - gint line, - gint alpha, - gint aprec, - gint zprec) -{ - gint zR; - gint zG; - gint zB; - gint zA; - gint index; - guchar* scanline; - - scanline = &(pixels[line * width * channels]); - - zR = *scanline << zprec; - zG = *(scanline + 1) << zprec; - zB = *(scanline + 2) << zprec; - zA = *(scanline + 3) << zprec; - - for (index = 0; index < width; index ++) - _blurinner (&scanline[index * channels], - &zR, - &zG, - &zB, - &zA, - alpha, - aprec, - zprec); - - for (index = width - 2; index >= 0; index--) - _blurinner (&scanline[index * channels], - &zR, - &zG, - &zB, - &zA, - alpha, - aprec, - zprec); -} - -static inline void -_blurcol (guchar* pixels, - gint width, - gint height, - gint channels, - gint x, - gint alpha, - gint aprec, - gint zprec) -{ - gint zR; - gint zG; - gint zB; - gint zA; - gint index; - guchar* ptr; - - ptr = pixels; - - ptr += x * channels; - - zR = *((guchar*) ptr ) << zprec; - zG = *((guchar*) ptr + 1) << zprec; - zB = *((guchar*) ptr + 2) << zprec; - zA = *((guchar*) ptr + 3) << zprec; - - for (index = width; index < (height - 1) * width; index += width) - _blurinner ((guchar*) &ptr[index * channels], - &zR, - &zG, - &zB, - &zA, - alpha, - aprec, - zprec); - - for (index = (height - 2) * width; index >= 0; index -= width) - _blurinner ((guchar*) &ptr[index * channels], - &zR, - &zG, - &zB, - &zA, - alpha, - aprec, - zprec); -} - -void -_expblur (guchar* pixels, - gint width, - gint height, - gint channels, - gint radius, - gint aprec, - gint zprec) -{ - gint alpha; - gint row = 0; - gint col = 0; - - if (radius < 1) - return; - - // calculate the alpha such that 90% of - // the kernel is within the radius. - // (Kernel extends to infinity) - alpha = (gint) ((1 << aprec) * (1.0f - expf (-2.3f / (radius + 1.f)))); - - for (; row < height; row++) - _blurrow (pixels, - width, - height, - channels, - row, - alpha, - aprec, - zprec); - - for(; col < width; col++) - _blurcol (pixels, - width, - height, - channels, - col, - alpha, - aprec, - zprec); - - return; -} - -void -_surface_blur (cairo_surface_t* surface, - guint radius) -{ - guchar* pixels; - guint width; - guint height; - cairo_format_t format; - - // before we mess with the surface execute any pending drawing - cairo_surface_flush (surface); - - pixels = cairo_image_surface_get_data (surface); - width = cairo_image_surface_get_width (surface); - height = cairo_image_surface_get_height (surface); - format = cairo_image_surface_get_format (surface); - - switch (format) - { - case CAIRO_FORMAT_ARGB32: - _expblur (pixels, width, height, 4, radius, 16, 7); - break; - - case CAIRO_FORMAT_RGB24: - _expblur (pixels, width, height, 3, radius, 16, 7); - break; - - case CAIRO_FORMAT_A8: - _expblur (pixels, width, height, 1, radius, 16, 7); - break; - - default : - // do nothing - break; - } - - // inform cairo we altered the surfaces contents - cairo_surface_mark_dirty (surface); -} - -static gboolean -draw (GtkWidget* button, cairo_t *cr) -{ - g_return_val_if_fail(IS_TRANSPORT_WIDGET(button), FALSE); - g_return_val_if_fail(cr != NULL, FALSE); - TransportWidgetPrivate* priv = TRANSPORT_WIDGET_GET_PRIVATE(button); - - //g_debug("transport-widget draw()"); - - cairo_surface_t* surf = NULL; - cairo_t* cr_surf = NULL; - -#if ! GTK_CHECK_VERSION(3, 0, 0) - GtkAllocation allocation; - gtk_widget_get_allocation (button, &allocation); - cairo_translate (cr, allocation.x, allocation.y); -#endif - - GtkStyle *style; - -#if GTK_CHECK_VERSION(3, 0, 0) - gtk_style_context_add_class (gtk_widget_get_style_context (button), - GTK_STYLE_CLASS_MENU); -#endif - CairoColorRGB bg_color, fg_color, bg_selected, bg_prelight; - CairoColorRGB color_middle[2], color_middle_prelight[2], color_outer[2], color_outer_prelight[2], - color_play_outer[2], color_play_outer_prelight[2], - color_button[4], color_button_shadow, color_inner[2], color_inner_compressed[2]; - - /* Use the menu's style instead of that of the menuitem ('button' is a - * menuitem that is packed in a menu directly). The menuitem's style - * can't be used due to a change in light-themes (lp #1130183). - * Menuitems now have a transparent background, which confuses - * GtkStyle. - * - * This is a workaround until this code gets refactored to use - * GtkStyleContext. - */ - style = gtk_widget_get_style (gtk_widget_get_parent (button)); - - bg_color.r = style->bg[0].red/65535.0; - bg_color.g = style->bg[0].green/65535.0; - bg_color.b = style->bg[0].blue/65535.0; - - bg_prelight.r = style->bg[GTK_STATE_PRELIGHT].red/65535.0; - bg_prelight.g = style->bg[GTK_STATE_PRELIGHT].green/65535.0; - bg_prelight.b = style->bg[GTK_STATE_PRELIGHT].blue/65535.0; - - bg_selected.r = style->bg[GTK_STATE_SELECTED].red/65535.0; - bg_selected.g = style->bg[GTK_STATE_SELECTED].green/65535.0; - bg_selected.b = style->bg[GTK_STATE_SELECTED].blue/65535.0; - - fg_color.r = style->fg[0].red/65535.0; - fg_color.g = style->fg[0].green/65535.0; - fg_color.b = style->fg[0].blue/65535.0; - - _color_shade (&bg_color, MIDDLE_START_SHADE, &color_middle[0]); - _color_shade (&bg_color, MIDDLE_END_SHADE, &color_middle[1]); - _color_shade (&bg_prelight, MIDDLE_START_SHADE, &color_middle_prelight[0]); - _color_shade (&bg_prelight, MIDDLE_END_SHADE, &color_middle_prelight[1]); - _color_shade (&bg_color, OUTER_START_SHADE, &color_outer[0]); - _color_shade (&bg_color, OUTER_END_SHADE, &color_outer[1]); - _color_shade (&bg_prelight, OUTER_START_SHADE, &color_outer_prelight[0]); - _color_shade (&bg_prelight, OUTER_END_SHADE, &color_outer_prelight[1]); - _color_shade (&bg_color, OUTER_PLAY_START_SHADE, &color_play_outer[0]); - _color_shade (&bg_color, OUTER_PLAY_END_SHADE, &color_play_outer[1]); - _color_shade (&bg_prelight, OUTER_PLAY_START_SHADE, &color_play_outer_prelight[0]); - _color_shade (&bg_prelight, OUTER_PLAY_END_SHADE, &color_play_outer_prelight[1]); - _color_shade (&bg_color, INNER_START_SHADE, &color_inner[0]); - _color_shade (&bg_color, INNER_END_SHADE, &color_inner[1]); - _color_shade (&fg_color, BUTTON_START_SHADE, &color_button[0]); - _color_shade (&fg_color, BUTTON_END_SHADE, &color_button[1]); - _color_shade (&bg_color, BUTTON_SHADOW_SHADE, &color_button[2]); - _color_shade (&bg_color, SHADOW_BUTTON_SHADE, &color_button_shadow); - _color_shade (&bg_selected, 1.0, &color_button[3]); - _color_shade (&bg_color, INNER_COMPRESSED_START_SHADE, &color_inner_compressed[0]); - _color_shade (&bg_color, INNER_COMPRESSED_END_SHADE, &color_inner_compressed[1]); - - double MIDDLE_END[] = {color_middle[0].r, color_middle[0].g, color_middle[0].b, 1.0f}; - double MIDDLE_START[] = {color_middle[1].r, color_middle[1].g, color_middle[1].b, 1.0f}; - double MIDDLE_END_PRELIGHT[] = {color_middle_prelight[0].r, color_middle_prelight[0].g, color_middle_prelight[0].b, 1.0f}; - double MIDDLE_START_PRELIGHT[] = {color_middle_prelight[1].r, color_middle_prelight[1].g, color_middle_prelight[1].b, 1.0f}; - double OUTER_END[] = {color_outer[0].r, color_outer[0].g, color_outer[0].b, 1.0f}; - double OUTER_START[] = {color_outer[1].r, color_outer[1].g, color_outer[1].b, 1.0f}; - double OUTER_END_PRELIGHT[] = {color_outer_prelight[0].r, color_outer_prelight[0].g, color_outer_prelight[0].b, 1.0f}; - double OUTER_START_PRELIGHT[] = {color_outer_prelight[1].r, color_outer_prelight[1].g, color_outer_prelight[1].b, 1.0f}; - double SHADOW_BUTTON[] = {color_button_shadow.r, color_button_shadow.g, color_button_shadow.b, 0.3f}; - double OUTER_PLAY_END[] = {color_play_outer[0].r, color_play_outer[0].g, color_play_outer[0].b, 1.0f}; - double OUTER_PLAY_START[] = {color_play_outer[1].r, color_play_outer[1].g, color_play_outer[1].b, 1.0f}; - double OUTER_PLAY_END_PRELIGHT[] = {color_play_outer_prelight[0].r, color_play_outer_prelight[0].g, color_play_outer_prelight[0].b, 1.0f}; - double OUTER_PLAY_START_PRELIGHT[] = {color_play_outer_prelight[1].r, color_play_outer_prelight[1].g, color_play_outer_prelight[1].b, 1.0f}; - double BUTTON_END[] = {color_button[0].r, color_button[0].g, color_button[0].b, 1.0f}; - double BUTTON_START[] = {color_button[1].r, color_button[1].g, color_button[1].b, 1.0f}; - double BUTTON_SHADOW[] = {color_button[2].r, color_button[2].g, color_button[2].b, 0.75f}; - double BUTTON_SHADOW_FOCUS[] = {color_button[3].r, color_button[3].g, color_button[3].b, 1.0f}; - double INNER_COMPRESSED_END[] = {color_inner_compressed[1].r, color_inner_compressed[1].g, color_inner_compressed[1].b, 1.0f}; - double INNER_COMPRESSED_START[] = {color_inner_compressed[0].r, color_inner_compressed[0].g, color_inner_compressed[0].b, 1.0f}; - - - draw_gradient (cr, - X, - Y, - RECT_WIDTH, - OUTER_RADIUS, - OUTER_START, - OUTER_END); - - draw_gradient (cr, - X, - Y + 1, - RECT_WIDTH - 2, - MIDDLE_RADIUS, - MIDDLE_START, - MIDDLE_END); - - draw_gradient (cr, - X, - Y + 2, - RECT_WIDTH - 4, - MIDDLE_RADIUS, - MIDDLE_START, - MIDDLE_END); - - //prev/next button - if(priv->current_command == TRANSPORT_ACTION_PREVIOUS) - { - draw_gradient (cr, - X, - Y, - RECT_WIDTH/2, - OUTER_RADIUS, - OUTER_END, - OUTER_START); - - draw_gradient (cr, - X, - Y + 1, - RECT_WIDTH/2, - MIDDLE_RADIUS, - INNER_COMPRESSED_START, - INNER_COMPRESSED_END); - - draw_gradient (cr, - X, - Y + 2, - RECT_WIDTH/2, - MIDDLE_RADIUS, - INNER_COMPRESSED_START, - INNER_COMPRESSED_END); - } - else if(priv->current_command == TRANSPORT_ACTION_NEXT) - { - draw_gradient (cr, - RECT_WIDTH / 2 + X, - Y, - RECT_WIDTH/2, - OUTER_RADIUS, - OUTER_END, - OUTER_START); - - draw_gradient (cr, - RECT_WIDTH / 2 + X, - Y + 1, - (RECT_WIDTH - 4.5)/2, - MIDDLE_RADIUS, - INNER_COMPRESSED_START, - INNER_COMPRESSED_END); - - draw_gradient (cr, - RECT_WIDTH / 2 + X, - Y + 2, - (RECT_WIDTH - 7)/2, - MIDDLE_RADIUS, - INNER_COMPRESSED_START, - INNER_COMPRESSED_END); - } - else if (priv->motion_event == TRANSPORT_ACTION_PREVIOUS) - { - draw_gradient (cr, - X, - Y, - RECT_WIDTH/2, - OUTER_RADIUS, - OUTER_START_PRELIGHT, - OUTER_END_PRELIGHT); - - draw_gradient (cr, - X, - Y + 1, - RECT_WIDTH/2, - MIDDLE_RADIUS, - MIDDLE_START_PRELIGHT, - MIDDLE_END_PRELIGHT); - - draw_gradient (cr, - X, - Y + 2, - RECT_WIDTH/2, - MIDDLE_RADIUS, - MIDDLE_START_PRELIGHT, - MIDDLE_END_PRELIGHT); - } - else if (priv->motion_event == TRANSPORT_ACTION_NEXT) - { - draw_gradient (cr, - RECT_WIDTH / 2 + X, - Y, - RECT_WIDTH/2, - OUTER_RADIUS, - OUTER_START_PRELIGHT, - OUTER_END_PRELIGHT); - - draw_gradient (cr, - RECT_WIDTH / 2 + X, - Y + 1, - (RECT_WIDTH - 4.5)/2, - MIDDLE_RADIUS, - MIDDLE_START_PRELIGHT, - MIDDLE_END_PRELIGHT); - - draw_gradient (cr, - RECT_WIDTH / 2 + X, - Y + 2, - (RECT_WIDTH - 7)/2, - MIDDLE_RADIUS, - MIDDLE_START_PRELIGHT, - MIDDLE_END_PRELIGHT); - } - - // play/pause shadow - if(priv->current_command != TRANSPORT_ACTION_PLAY_PAUSE) - { - cairo_save (cr); - cairo_rectangle (cr, X, Y, RECT_WIDTH, MIDDLE_RADIUS*2); - cairo_clip (cr); - - draw_circle (cr, - X + RECT_WIDTH / 2.0f - 2.0f * OUTER_RADIUS - 5.5f - 1.0f, - Y - ((CIRCLE_RADIUS - OUTER_RADIUS)) - 1.0f, - CIRCLE_RADIUS + 1.0f, - SHADOW_BUTTON, - SHADOW_BUTTON); - - cairo_restore (cr); - } - - // play/pause button - if(priv->current_command == TRANSPORT_ACTION_PLAY_PAUSE) - { - draw_circle (cr, - X + RECT_WIDTH / 2.0f - 2.0f * OUTER_RADIUS - 5.5f, - Y - ((CIRCLE_RADIUS - OUTER_RADIUS)) , - CIRCLE_RADIUS, - OUTER_PLAY_END, - OUTER_PLAY_START); - - draw_circle (cr, - X + RECT_WIDTH / 2.0f - 2.0f * OUTER_RADIUS - 5.5f + 1.25f, - Y - ((CIRCLE_RADIUS - OUTER_RADIUS)) + 1.25f, - CIRCLE_RADIUS - 1.25, - INNER_COMPRESSED_START, - INNER_COMPRESSED_END); - } - else if (priv->motion_event == TRANSPORT_ACTION_PLAY_PAUSE) - { - /* this subtle offset is to fix alpha borders, should be removed once this draw routine will be refactored */ - draw_circle (cr, - X + RECT_WIDTH / 2.0f - 2.0f * OUTER_RADIUS - 5.5f + 0.1, - Y - ((CIRCLE_RADIUS - OUTER_RADIUS)) + 0.1, - CIRCLE_RADIUS - 0.1, - OUTER_PLAY_START_PRELIGHT, - OUTER_PLAY_END_PRELIGHT); - - draw_circle (cr, - X + RECT_WIDTH / 2.0f - 2.0f * OUTER_RADIUS - 5.5f + 1.25f, - Y - ((CIRCLE_RADIUS - OUTER_RADIUS)) + 1.25f, - CIRCLE_RADIUS - 1.25, - MIDDLE_START_PRELIGHT, - MIDDLE_END_PRELIGHT); - } - else - { - draw_circle (cr, - X + RECT_WIDTH / 2.0f - 2.0f * OUTER_RADIUS - 5.5f, - Y - ((CIRCLE_RADIUS - OUTER_RADIUS)), - CIRCLE_RADIUS, - OUTER_PLAY_START, - OUTER_PLAY_END); - - draw_circle (cr, - X + RECT_WIDTH / 2.0f - 2.0f * OUTER_RADIUS - 5.5f + 1.25f, - Y - ((CIRCLE_RADIUS - OUTER_RADIUS)) + 1.25f, - CIRCLE_RADIUS - 1.25, - MIDDLE_START, - MIDDLE_END); - } - - // draw previous-button drop-shadow - if (priv->has_focus && priv->key_event == TRANSPORT_ACTION_PREVIOUS) - { - _setup (&cr_surf, &surf, PREV_WIDTH+6, PREV_HEIGHT+6); - _mask_prev (cr_surf, - (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (PREV_HEIGHT - TRI_HEIGHT) / 2.0f, - TRI_WIDTH, - TRI_HEIGHT, - TRI_OFFSET); - _fill (cr_surf, - (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (PREV_HEIGHT - TRI_HEIGHT) / 2.0f, - (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (double) TRI_HEIGHT, - BUTTON_SHADOW_FOCUS, - BUTTON_SHADOW_FOCUS, - FALSE); - _surface_blur (surf, 3); - _finalize_repaint (cr, &cr_surf, &surf, PREV_X, PREV_Y + 0.5f, 3); - } - else - { - _setup (&cr_surf, &surf, PREV_WIDTH, PREV_HEIGHT); - _mask_prev (cr_surf, - (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (PREV_HEIGHT - TRI_HEIGHT) / 2.0f, - TRI_WIDTH, - TRI_HEIGHT, - TRI_OFFSET); - _fill (cr_surf, - (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (PREV_HEIGHT - TRI_HEIGHT) / 2.0f, - (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (double) TRI_HEIGHT, - BUTTON_SHADOW, - BUTTON_SHADOW, - FALSE); - _surface_blur (surf, 1); - _finalize (cr, &cr_surf, &surf, PREV_X, PREV_Y + 1.0f); - } - - // draw previous-button - _setup (&cr_surf, &surf, PREV_WIDTH, PREV_HEIGHT); - _mask_prev (cr_surf, - (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (PREV_HEIGHT - TRI_HEIGHT) / 2.0f, - TRI_WIDTH, - TRI_HEIGHT, - TRI_OFFSET); - _fill (cr_surf, - (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (PREV_HEIGHT - TRI_HEIGHT) / 2.0f, - (PREV_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (double) TRI_HEIGHT, - BUTTON_START, - BUTTON_END, - FALSE); - _finalize (cr, &cr_surf, &surf, PREV_X, PREV_Y); - - // draw next-button drop-shadow - if (priv->has_focus && priv->key_event == TRANSPORT_ACTION_NEXT) - { - _setup (&cr_surf, &surf, NEXT_WIDTH+6, NEXT_HEIGHT+6); - _mask_next (cr_surf, - (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (NEXT_HEIGHT - TRI_HEIGHT) / 2.0f, - TRI_WIDTH, - TRI_HEIGHT, - TRI_OFFSET); - _fill (cr_surf, - (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (NEXT_HEIGHT - TRI_HEIGHT) / 2.0f, - (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (double) TRI_HEIGHT, - BUTTON_SHADOW_FOCUS, - BUTTON_SHADOW_FOCUS, - FALSE); - _surface_blur (surf, 3); - _finalize_repaint (cr, &cr_surf, &surf, NEXT_X, NEXT_Y + 0.5f, 3); - } - else - { - _setup (&cr_surf, &surf, NEXT_WIDTH, NEXT_HEIGHT); - _mask_next (cr_surf, - (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (NEXT_HEIGHT - TRI_HEIGHT) / 2.0f, - TRI_WIDTH, - TRI_HEIGHT, - TRI_OFFSET); - _fill (cr_surf, - (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (NEXT_HEIGHT - TRI_HEIGHT) / 2.0f, - (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (double) TRI_HEIGHT, - BUTTON_SHADOW, - BUTTON_SHADOW, - FALSE); - _surface_blur (surf, 1); - _finalize (cr, &cr_surf, &surf, NEXT_X, NEXT_Y + 1.0f); - } - - // draw next-button - _setup (&cr_surf, &surf, NEXT_WIDTH, NEXT_HEIGHT); - _mask_next (cr_surf, - (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (NEXT_HEIGHT - TRI_HEIGHT) / 2.0f, - TRI_WIDTH, - TRI_HEIGHT, - TRI_OFFSET); - _fill (cr_surf, - (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (NEXT_HEIGHT - TRI_HEIGHT) / 2.0f, - (NEXT_WIDTH - (2.0f * TRI_WIDTH - TRI_OFFSET)) / 2.0f, - (double) TRI_HEIGHT, - BUTTON_START, - BUTTON_END, - FALSE); - _finalize (cr, &cr_surf, &surf, NEXT_X, NEXT_Y); - - // draw pause-button drop-shadow - if(priv->current_state == TRANSPORT_STATE_PLAYING) - { - if (priv->has_focus && (priv->key_event == TRANSPORT_ACTION_NO_ACTION || - priv->key_event == TRANSPORT_ACTION_PLAY_PAUSE)) - { - _setup (&cr_surf, &surf, PAUSE_WIDTH+6, PAUSE_HEIGHT+6); - _mask_pause (cr_surf, - (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, - (PAUSE_HEIGHT - BAR_HEIGHT) / 2.0f, - BAR_WIDTH, - BAR_HEIGHT - 2.0f * BAR_WIDTH, - BAR_OFFSET); - _fill (cr_surf, - (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, - (PAUSE_HEIGHT - BAR_HEIGHT) / 2.0f, - (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, - (double) BAR_HEIGHT, - BUTTON_SHADOW_FOCUS, - BUTTON_SHADOW_FOCUS, - TRUE); - _surface_blur (surf, 3); - _finalize_repaint (cr, &cr_surf, &surf, PAUSE_X, PAUSE_Y + 0.5f, 3); - } - else - { - _setup (&cr_surf, &surf, PAUSE_WIDTH, PAUSE_HEIGHT); - _mask_pause (cr_surf, - (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, - (PAUSE_HEIGHT - BAR_HEIGHT) / 2.0f, - BAR_WIDTH, - BAR_HEIGHT - 2.0f * BAR_WIDTH, - BAR_OFFSET); - _fill (cr_surf, - (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, - (PAUSE_HEIGHT - BAR_HEIGHT) / 2.0f, - (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, - (double) BAR_HEIGHT, - BUTTON_SHADOW, - BUTTON_SHADOW, - TRUE); - _surface_blur (surf, 1); - _finalize (cr, &cr_surf, &surf, PAUSE_X, PAUSE_Y + 1.0f); - } - - // draw pause-button - _setup (&cr_surf, &surf, PAUSE_WIDTH, PAUSE_HEIGHT); - _mask_pause (cr_surf, - (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, - (PAUSE_HEIGHT - BAR_HEIGHT) / 2.0f, - BAR_WIDTH, - BAR_HEIGHT - 2.0f * BAR_WIDTH, - BAR_OFFSET); - _fill (cr_surf, - (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, - (PAUSE_HEIGHT - BAR_HEIGHT) / 2.0f, - (PAUSE_WIDTH - (2.0f * BAR_WIDTH + BAR_OFFSET)) / 2.0f, - (double) BAR_HEIGHT, - BUTTON_START, - BUTTON_END, - TRUE); - _finalize (cr, &cr_surf, &surf, PAUSE_X, PAUSE_Y); - } - else if(priv->current_state == TRANSPORT_STATE_PAUSED) - { - if (priv->has_focus && (priv->key_event == TRANSPORT_ACTION_NO_ACTION || - priv->key_event == TRANSPORT_ACTION_PLAY_PAUSE)) - { - _setup (&cr_surf, &surf, PLAY_WIDTH+6, PLAY_HEIGHT+6); - _mask_play (cr_surf, - PLAY_PADDING, - PLAY_PADDING, - PLAY_WIDTH - (2*PLAY_PADDING), - PLAY_HEIGHT - (2*PLAY_PADDING)); - _fill (cr_surf, - PLAY_PADDING, - PLAY_PADDING, - PLAY_WIDTH - (2*PLAY_PADDING), - PLAY_HEIGHT - (2*PLAY_PADDING), - BUTTON_SHADOW_FOCUS, - BUTTON_SHADOW_FOCUS, - FALSE); - _surface_blur (surf, 3); - _finalize_repaint (cr, &cr_surf, &surf, PAUSE_X-0.5f, PAUSE_Y + 0.5f, 3); - } - else - { - _setup (&cr_surf, &surf, PLAY_WIDTH, PLAY_HEIGHT); - _mask_play (cr_surf, - PLAY_PADDING, - PLAY_PADDING, - PLAY_WIDTH - (2*PLAY_PADDING), - PLAY_HEIGHT - (2*PLAY_PADDING)); - _fill (cr_surf, - PLAY_PADDING, - PLAY_PADDING, - PLAY_WIDTH - (2*PLAY_PADDING), - PLAY_HEIGHT - (2*PLAY_PADDING), - BUTTON_SHADOW, - BUTTON_SHADOW, - FALSE); - _surface_blur (surf, 1); - _finalize (cr, &cr_surf, &surf, PAUSE_X-0.75f, PAUSE_Y + 1.0f); - } - - // draw play-button - _setup (&cr_surf, &surf, PLAY_WIDTH, PLAY_HEIGHT); - cairo_set_line_width (cr, 10.5); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - _mask_play (cr_surf, - PLAY_PADDING, - PLAY_PADDING, - PLAY_WIDTH - (2*PLAY_PADDING), - PLAY_HEIGHT - (2*PLAY_PADDING)); - _fill (cr_surf, - PLAY_PADDING, - PLAY_PADDING, - PLAY_WIDTH - (2*PLAY_PADDING), - PLAY_HEIGHT - (2*PLAY_PADDING), - BUTTON_START, - BUTTON_END, - FALSE); - _finalize (cr, &cr_surf, &surf, PAUSE_X-0.5f, PAUSE_Y); - } - #if GTK_CHECK_VERSION(3, 0, 0) - else if(priv->current_state == TRANSPORT_STATE_LAUNCHING) - { - // the spinner is not aligned, why? because the play button has odd width/height numbers - gtk_render_activity (spinner_style_context, cr, 106, 6, 30, 30); - } - #endif - return FALSE; -} - -static void -transport_widget_set_twin_item(TransportWidget* self, - DbusmenuMenuitem* twin_item) -{ - TransportWidgetPrivate* priv = TRANSPORT_WIDGET_GET_PRIVATE(self); - priv->twin_item = twin_item; - g_signal_connect(G_OBJECT(priv->twin_item), "property-changed", - G_CALLBACK(transport_widget_property_update), self); - gint initial_state = dbusmenu_menuitem_property_get_int (twin_item, - DBUSMENU_TRANSPORT_MENUITEM_PLAY_STATE ); - //g_debug("TRANSPORT WIDGET - INITIAL UPDATE = %i", initial_state); - transport_widget_toggle_play_pause (self, - (TransportState)initial_state); -} - -/** -* transport_widget_update_state() -* Callback for updates from the other side of dbus -**/ -static void -transport_widget_property_update(DbusmenuMenuitem* item, gchar* property, - GVariant* value, gpointer userdata) -{ - //g_debug("transport_widget_update_state - with property %s", property); - TransportWidget* bar = (TransportWidget*)userdata; - g_return_if_fail(IS_TRANSPORT_WIDGET(bar)); - TransportWidgetPrivate* priv = TRANSPORT_WIDGET_GET_PRIVATE(bar); - - if(g_ascii_strcasecmp(DBUSMENU_TRANSPORT_MENUITEM_PLAY_STATE, property) == 0) - { - TransportState new_state = (TransportState)g_variant_get_int32(value); - //g_debug("transport_widget_update_state - with value %i", new_state); - if (new_state == TRANSPORT_STATE_LAUNCHING){ - #if GTK_CHECK_VERSION(3, 0, 0) - gtk_style_context_set_state (spinner_style_context, GTK_STATE_FLAG_ACTIVE); - #endif - - priv->current_state = TRANSPORT_STATE_LAUNCHING; - g_debug("TransportWidget::toggle play state : %i", priv->current_state); - } - else{ - transport_widget_toggle_play_pause(bar, new_state); - } - } -} - - -/** -* transport_widget_new: -* @returns: a new #TransportWidget. -**/ -GtkWidget* -transport_widget_new ( DbusmenuMenuitem *item ) -{ - GtkWidget* widget = g_object_new(TRANSPORT_WIDGET_TYPE, NULL); - gtk_widget_set_app_paintable (widget, TRUE); - transport_widget_set_twin_item((TransportWidget*)widget, item); - return widget; -} - diff --git a/src/transport-widget.h b/src/transport-widget.h deleted file mode 100644 index b68845f..0000000 --- a/src/transport-widget.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#ifndef __TRANSPORT_WIDGET_H__ -#define __TRANSPORT_WIDGET_H__ - -#include <gtk/gtk.h> -#include <libdbusmenu-gtk/menuitem.h> - -#include "common-defs.h" - -G_BEGIN_DECLS - -#define TRANSPORT_WIDGET_TYPE (transport_widget_get_type ()) -#define TRANSPORT_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TRANSPORT_WIDGET_TYPE, TransportWidget)) -#define TRANSPORT_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TRANSPORT_WIDGET_TYPE, TransportWidgetClass)) -#define IS_TRANSPORT_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TRANSPORT_WIDGET_TYPE)) -#define IS_TRANSPORT_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TRANSPORT_WIDGET_TYPE)) -#define TRANSPORT_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TRANSPORT_WIDGET_TYPE, TransportWidgetClass)) - -typedef struct _TransportWidget TransportWidget; -typedef struct _TransportWidgetClass TransportWidgetClass; - - -struct _TransportWidgetClass { - GtkMenuItemClass parent_class; -}; - -struct _TransportWidget { - GtkMenuItem parent; -}; - -typedef struct -{ - double r; - double g; - double b; -} CairoColorRGB; - - -void _color_shade (const CairoColorRGB *a, float k, CairoColorRGB *b); -GType transport_widget_get_type (void); -GtkWidget* transport_widget_new (DbusmenuMenuitem *item); -void transport_widget_react_to_key_press_event (TransportWidget* widget, - TransportAction transport_event); -void transport_widget_react_to_key_release_event (TransportWidget* widget, - TransportAction transport_event); -gboolean transport_widget_is_selected (TransportWidget* widget); -G_END_DECLS - -#endif - diff --git a/src/voip-input-menu-item.c b/src/voip-input-menu-item.c deleted file mode 100644 index 7cbdd45..0000000 --- a/src/voip-input-menu-item.c +++ /dev/null @@ -1,278 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <glib/gi18n.h> -#include "voip-input-menu-item.h" -#include "common-defs.h" -#include "pulseaudio-mgr.h" - -typedef struct _VoipInputMenuItemPrivate VoipInputMenuItemPrivate; - -struct _VoipInputMenuItemPrivate { - Device* a_sink; - pa_cvolume volume; - gint mute; - guint32 volume_steps; - pa_channel_map channel_map; - pa_volume_t base_volume; - gint source_index; - gint source_output_index; - gint client_index; -}; - -#define VOIP_INPUT_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), VOIP_INPUT_MENU_ITEM_TYPE, VoipInputMenuItemPrivate)) - -/* Prototypes */ -static void voip_input_menu_item_class_init (VoipInputMenuItemClass *klass); -static void voip_input_menu_item_init (VoipInputMenuItem *self); -static void voip_input_menu_item_dispose (GObject *object); -static void voip_input_menu_item_finalize (GObject *object); -static void handle_event (DbusmenuMenuitem * mi, const gchar * name, - GVariant * value, guint timestamp); -// TODO: -// This method should really be shared between this and the volume slider obj -// perfectly static - wait until the device mgr wrapper is properly sorted and -// then consolidate -static pa_cvolume voip_input_menu_item_construct_mono_volume (const pa_cvolume* vol); - -G_DEFINE_TYPE (VoipInputMenuItem, voip_input_menu_item, DBUSMENU_TYPE_MENUITEM); - -static void -voip_input_menu_item_class_init (VoipInputMenuItemClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (VoipInputMenuItemPrivate)); - - object_class->dispose = voip_input_menu_item_dispose; - object_class->finalize = voip_input_menu_item_finalize; - - DbusmenuMenuitemClass * mclass = DBUSMENU_MENUITEM_CLASS(klass); - mclass->handle_event = handle_event; -} - -static void -voip_input_menu_item_init (VoipInputMenuItem *self) -{ - dbusmenu_menuitem_property_set( DBUSMENU_MENUITEM(self), - DBUSMENU_MENUITEM_PROP_TYPE, - DBUSMENU_VOIP_INPUT_MENUITEM_TYPE ); - VoipInputMenuItemPrivate* priv = VOIP_INPUT_MENU_ITEM_GET_PRIVATE (self); - dbusmenu_menuitem_property_set_bool( DBUSMENU_MENUITEM(self), - DBUSMENU_MENUITEM_PROP_VISIBLE, - FALSE ); - - priv->source_index = NOT_ACTIVE; - priv->source_output_index = NOT_ACTIVE; - priv->client_index = NOT_ACTIVE; - priv->mute = NOT_ACTIVE; -} - -static void -voip_input_menu_item_dispose (GObject *object) -{ - G_OBJECT_CLASS (voip_input_menu_item_parent_class)->dispose (object); - return; -} - -static void -voip_input_menu_item_finalize (GObject *object) -{ - G_OBJECT_CLASS (voip_input_menu_item_parent_class)->finalize (object); -} - -static void -handle_event (DbusmenuMenuitem * mi, - const gchar * name, - GVariant * value, - guint timestamp) -{ - GVariant* input = NULL; - input = value; - if (g_variant_is_of_type(value, G_VARIANT_TYPE_VARIANT) == TRUE) { - input = g_variant_get_variant(value); - } - - gdouble percent = g_variant_get_double(input); - if (value != NULL){ - if (IS_VOIP_INPUT_MENU_ITEM (mi)) { - VoipInputMenuItemPrivate* priv = VOIP_INPUT_MENU_ITEM_GET_PRIVATE (VOIP_INPUT_MENU_ITEM (mi)); -/* - g_debug ("Handle event in the voip input level backend instance - %f", percent); -*/ - pa_cvolume new_volume; - pa_cvolume_init(&new_volume); - new_volume.channels = 1; - pa_volume_t new_volume_value = (pa_volume_t) ((percent * PA_VOLUME_NORM) / 100); - pa_cvolume_set(&new_volume, 1, new_volume_value); - - pm_update_mic_gain (priv->source_index, new_volume); - // finally unmute if needed - if (priv->mute == 1) { - pm_update_mic_mute (priv->source_index, 0); - } - } - } -} - -static pa_cvolume -voip_input_menu_item_construct_mono_volume (const pa_cvolume* vol) -{ - pa_cvolume new_volume; - pa_cvolume_init(&new_volume); - new_volume.channels = 1; - pa_volume_t max_vol = pa_cvolume_max(vol); - pa_cvolume_set(&new_volume, 1, max_vol); - return new_volume; -} - -void -voip_input_menu_item_update (VoipInputMenuItem* item, - const pa_source_info* source) -{ - VoipInputMenuItemPrivate* priv = VOIP_INPUT_MENU_ITEM_GET_PRIVATE (item); - // only overwrite the constants of each source if the device has changed - if (priv->source_index == NOT_ACTIVE){ - priv->base_volume = source->base_volume; - priv->volume_steps = source->n_volume_steps; - priv->channel_map = source->channel_map; - priv->source_index = source->index; - } - priv->volume = voip_input_menu_item_construct_mono_volume (&source->volume); - pa_volume_t vol = pa_cvolume_max (&source->volume); - gdouble update = ((gdouble) vol * 100) / PA_VOLUME_NORM; - - GVariant* new_volume = g_variant_new_double(update); - dbusmenu_menuitem_property_set_variant(DBUSMENU_MENUITEM(item), - DBUSMENU_VOIP_INPUT_MENUITEM_LEVEL, - new_volume); - // Only send over the mute updates if the state has changed. - // in this order - volume first mute last!! - if (priv->mute != source->mute){ -/* - g_debug ("voip menu item - update - mute = %i", priv->mute); -*/ - GVariant* new_mute_update = g_variant_new_int32 (source->mute); - dbusmenu_menuitem_property_set_variant (DBUSMENU_MENUITEM(item), - DBUSMENU_VOIP_INPUT_MENUITEM_MUTE, - new_mute_update); - } - - priv->mute = source->mute; - -} - -gboolean -voip_input_menu_item_is_interested (VoipInputMenuItem* item, - gint source_output_index, - gint client_index) -{ - VoipInputMenuItemPrivate* priv = VOIP_INPUT_MENU_ITEM_GET_PRIVATE (item); - // Check to make sure we are not handling another voip beforehand and that we - // have an active sink (might need to match up at start up) - if (priv->source_output_index != NOT_ACTIVE && - priv->source_index != NOT_ACTIVE){ - return FALSE; - } - - priv->source_output_index = source_output_index; - priv->client_index = client_index; - - return TRUE; -} - -gboolean -voip_input_menu_item_is_active (VoipInputMenuItem* item) -{ - VoipInputMenuItemPrivate* priv = VOIP_INPUT_MENU_ITEM_GET_PRIVATE (item); - return (priv->source_output_index != NOT_ACTIVE && priv->client_index != NOT_ACTIVE); -} - - -gboolean -voip_input_menu_item_is_populated (VoipInputMenuItem* item) -{ - VoipInputMenuItemPrivate* priv = VOIP_INPUT_MENU_ITEM_GET_PRIVATE (item); - return priv->source_index != NOT_ACTIVE; -} - -gint -voip_input_menu_item_get_index (VoipInputMenuItem* item) -{ - VoipInputMenuItemPrivate* priv = VOIP_INPUT_MENU_ITEM_GET_PRIVATE (item); - return priv->source_index; -} - -gint -voip_input_menu_item_get_source_output_index (VoipInputMenuItem* item) -{ - VoipInputMenuItemPrivate* priv = VOIP_INPUT_MENU_ITEM_GET_PRIVATE (item); - - return priv->source_output_index; -} - -/** - * If the pulse server informs of a default source change - * or the source in question is removed. - * @param item - */ -void -voip_input_menu_item_deactivate_source (VoipInputMenuItem* item, gboolean visible) -{ - VoipInputMenuItemPrivate* priv = VOIP_INPUT_MENU_ITEM_GET_PRIVATE (item); - priv->source_index = NOT_ACTIVE; - dbusmenu_menuitem_property_set_bool( DBUSMENU_MENUITEM(item), - DBUSMENU_MENUITEM_PROP_VISIBLE, - visible ); -} - -void -voip_input_menu_item_deactivate_voip_client (VoipInputMenuItem* item) -{ - VoipInputMenuItemPrivate* priv = VOIP_INPUT_MENU_ITEM_GET_PRIVATE (item); - priv->client_index = NOT_ACTIVE; - priv->source_output_index = NOT_ACTIVE; - voip_input_menu_item_enable (item, FALSE); -} - -void -voip_input_menu_item_enable (VoipInputMenuItem* item, - gboolean active) -{ - VoipInputMenuItemPrivate* priv = VOIP_INPUT_MENU_ITEM_GET_PRIVATE (item); - if (priv->source_index == NOT_ACTIVE && active == TRUE) { - g_warning ("Tried to enable the VOIP menuitem but we don't have an active source ??"); - active = FALSE; - } - dbusmenu_menuitem_property_set_bool( DBUSMENU_MENUITEM(item), - DBUSMENU_MENUITEM_PROP_VISIBLE, - active ); -} - -VoipInputMenuItem* -voip_input_menu_item_new (Device* sink) -{ - VoipInputMenuItem *self = g_object_new(VOIP_INPUT_MENU_ITEM_TYPE, NULL); - VoipInputMenuItemPrivate* priv = VOIP_INPUT_MENU_ITEM_GET_PRIVATE (self); - priv->a_sink = sink; - return self; -}
\ No newline at end of file diff --git a/src/voip-input-widget.c b/src/voip-input-widget.c deleted file mode 100644 index 03879e7..0000000 --- a/src/voip-input-widget.c +++ /dev/null @@ -1,284 +0,0 @@ - -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <glib/gi18n-lib.h> -#include <math.h> -#include <glib.h> -#include "voip-input-widget.h" -#include "common-defs.h" -#include <libido/idoscalemenuitem.h> - -typedef struct _VoipInputWidgetPrivate VoipInputWidgetPrivate; - -struct _VoipInputWidgetPrivate -{ - DbusmenuMenuitem* twin_item; - GtkWidget* ido_voip_input_slider; - gboolean grabbed; -}; - -#define VOIP_INPUT_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), VOIP_INPUT_WIDGET_TYPE, VoipInputWidgetPrivate)) - -/* Prototypes */ -static void voip_input_widget_class_init (VoipInputWidgetClass *klass); -static void voip_input_widget_init (VoipInputWidget *self); -static void voip_input_widget_dispose (GObject *object); -static void voip_input_widget_finalize (GObject *object); -static void voip_input_widget_set_twin_item( VoipInputWidget* self, - DbusmenuMenuitem* twin_item); -static void voip_input_widget_property_update( DbusmenuMenuitem* item, gchar* property, - GVariant* value, gpointer userdata ); - -static gboolean voip_input_widget_change_value_cb (GtkRange *range, - GtkScrollType scroll, - gdouble value, - gpointer user_data); -static gboolean voip_input_widget_value_changed_cb(GtkRange *range, gpointer user_data); -static void voip_input_widget_slider_grabbed(GtkWidget *widget, gpointer user_data); -static void voip_input_widget_slider_released(GtkWidget *widget, gpointer user_data); -static void voip_input_widget_parent_changed (GtkWidget *widget, gpointer user_data); - -G_DEFINE_TYPE (VoipInputWidget, voip_input_widget, G_TYPE_OBJECT); - - -static void -voip_input_widget_class_init (VoipInputWidgetClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (VoipInputWidgetPrivate)); - - gobject_class->dispose = voip_input_widget_dispose; - gobject_class->finalize = voip_input_widget_finalize; -} - -static void -voip_input_widget_init (VoipInputWidget *self) -{ - VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(self); - - priv->ido_voip_input_slider = ido_scale_menu_item_new_with_range ("VOLUME", IDO_RANGE_STYLE_DEFAULT, 0, 0, 100, 1); - g_object_ref (priv->ido_voip_input_slider); - ido_scale_menu_item_set_primary_label (IDO_SCALE_MENU_ITEM(priv->ido_voip_input_slider), "VOIP"); - - ido_scale_menu_item_set_style (IDO_SCALE_MENU_ITEM (priv->ido_voip_input_slider), IDO_SCALE_MENU_ITEM_STYLE_IMAGE); - g_object_set(priv->ido_voip_input_slider, "reverse-scroll-events", TRUE, NULL); - - g_signal_connect (priv->ido_voip_input_slider, - "notify::parent", G_CALLBACK (voip_input_widget_parent_changed), - NULL); - - GtkWidget* voip_input_widget = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_voip_input_slider); - - g_signal_connect(voip_input_widget, "change-value", G_CALLBACK(voip_input_widget_change_value_cb), self); - g_signal_connect(voip_input_widget, "value-changed", G_CALLBACK(voip_input_widget_value_changed_cb), self); - g_signal_connect(priv->ido_voip_input_slider, "slider-grabbed", G_CALLBACK(voip_input_widget_slider_grabbed), self); - g_signal_connect(priv->ido_voip_input_slider, "slider-released", G_CALLBACK(voip_input_widget_slider_released), self); - - GtkWidget* primary_image = ido_scale_menu_item_get_primary_image((IdoScaleMenuItem*)priv->ido_voip_input_slider); - GIcon * primary_gicon = g_themed_icon_new_with_default_fallbacks("audio-input-microphone-low-zero-panel"); - gtk_image_set_from_gicon(GTK_IMAGE(primary_image), primary_gicon, GTK_ICON_SIZE_MENU); - g_object_unref(primary_gicon); - - GtkWidget* secondary_image = ido_scale_menu_item_get_secondary_image((IdoScaleMenuItem*)priv->ido_voip_input_slider); - GIcon * secondary_gicon = g_themed_icon_new_with_default_fallbacks("audio-input-microphone-high-panel"); - gtk_image_set_from_gicon(GTK_IMAGE(secondary_image), secondary_gicon, GTK_ICON_SIZE_MENU); - g_object_unref(secondary_gicon); - - GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (voip_input_widget)); - gtk_adjustment_set_step_increment(adj, 4); -} - -static void -voip_input_widget_dispose (GObject *object) -{ - G_OBJECT_CLASS (voip_input_widget_parent_class)->dispose (object); -} - -static void -voip_input_widget_finalize (GObject *object) -{ - G_OBJECT_CLASS (voip_input_widget_parent_class)->finalize (object); -} - -static void -voip_input_widget_property_update (DbusmenuMenuitem* item, gchar* property, - GVariant* value, gpointer userdata) -{ - g_return_if_fail (IS_VOIP_INPUT_WIDGET (userdata)); - VoipInputWidget* mitem = VOIP_INPUT_WIDGET(userdata); - VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(mitem); - if(g_ascii_strcasecmp(DBUSMENU_VOIP_INPUT_MENUITEM_LEVEL, property) == 0){ - g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE)); - if (priv->grabbed == FALSE){ - GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_voip_input_slider); - GtkRange *range = (GtkRange*)slider; - gdouble update = g_variant_get_double (value); - //g_debug("volume-widget - update level with value %f", update); - gtk_range_set_value(range, update); - } - } - if(g_ascii_strcasecmp(DBUSMENU_VOIP_INPUT_MENUITEM_MUTE, property) == 0){ - if(priv->grabbed == FALSE){ - g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_INT32)); - GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_voip_input_slider); - GtkRange *range = (GtkRange*)slider; - gint update = g_variant_get_int32 (value); - gdouble level; - if (update == 1){ - level = 0; - } - else{ - GVariant* variant = dbusmenu_menuitem_property_get_variant (priv->twin_item, - DBUSMENU_VOIP_INPUT_MENUITEM_LEVEL); - g_return_if_fail (g_variant_is_of_type (variant, G_VARIANT_TYPE_DOUBLE)); - level = g_variant_get_double (variant); - } - gtk_range_set_value(range, level); - - g_debug ("voip-item-widget - update mute with value %i", update); - } - } -} - -static void -voip_input_widget_set_twin_item (VoipInputWidget* self, - DbusmenuMenuitem* twin_item) -{ - VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(self); - priv->twin_item = twin_item; - g_object_ref(priv->twin_item); - g_signal_connect(G_OBJECT(twin_item), "property-changed", - G_CALLBACK(voip_input_widget_property_update), self); - gdouble initial_level = g_variant_get_double (dbusmenu_menuitem_property_get_variant(twin_item, - DBUSMENU_VOIP_INPUT_MENUITEM_LEVEL)); - //g_debug("voip_input_widget_set_twin_item initial level = %f", initial_level); - GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_voip_input_slider); - GtkRange *range = (GtkRange*)slider; - gtk_range_set_value(range, initial_level); - - gint mute = g_variant_get_int32 (dbusmenu_menuitem_property_get_variant (priv->twin_item, - DBUSMENU_VOIP_INPUT_MENUITEM_MUTE)); - if (mute == 1){ - gtk_range_set_value (range, 0.0); - } -} - -static gboolean -voip_input_widget_change_value_cb (GtkRange *range, - GtkScrollType scroll, - gdouble new_value, - gpointer user_data) -{ - g_return_val_if_fail (IS_VOIP_INPUT_WIDGET (user_data), FALSE); - VoipInputWidget* mitem = VOIP_INPUT_WIDGET(user_data); - voip_input_widget_update(mitem, new_value); - return FALSE; -} - - -/** - * We only want this callback to catch mouse icon press events which set the - * slider to 0 or 100. Ignore all other events including the new Mute behaviour - * (slider to go to 0 on mute without setting the level to 0 and return to - * previous level on unmute) - **/ -static gboolean -voip_input_widget_value_changed_cb(GtkRange *range, gpointer user_data) -{ - g_return_val_if_fail (IS_VOIP_INPUT_WIDGET (user_data), FALSE); - VoipInputWidget* mitem = VOIP_INPUT_WIDGET(user_data); - VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(mitem); - GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_voip_input_slider); - gdouble current_value = CLAMP(gtk_range_get_value(GTK_RANGE(slider)), 0, 100); - - gint mute = g_variant_get_int32 (dbusmenu_menuitem_property_get_variant (priv->twin_item, - DBUSMENU_VOIP_INPUT_MENUITEM_MUTE)); - if ((current_value == 0 && mute != 1) || current_value == 100 ){ - voip_input_widget_update(mitem, current_value); - } - return FALSE; -} - -void -voip_input_widget_update(VoipInputWidget* self, gdouble update) -{ - VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(self); - gdouble clamped = CLAMP(update, 0, 100); - GVariant* new_volume = g_variant_new_double(clamped); - dbusmenu_menuitem_handle_event (priv->twin_item, "update", new_volume, 0); -} - -GtkWidget* -voip_input_widget_get_ido_slider(VoipInputWidget* self) -{ - VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(self); - return priv->ido_voip_input_slider; -} - -static void -voip_input_widget_parent_changed (GtkWidget *widget, - gpointer user_data) -{ - gtk_widget_set_size_request (widget, 200, -1); - //g_debug("voip_input_widget_parent_changed"); -} - -static void -voip_input_widget_slider_grabbed(GtkWidget *widget, gpointer user_data) -{ - VoipInputWidget* mitem = VOIP_INPUT_WIDGET(user_data); - VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(mitem); - priv->grabbed = TRUE; -} - -static void -voip_input_widget_slider_released(GtkWidget *widget, gpointer user_data) -{ - VoipInputWidget* mitem = VOIP_INPUT_WIDGET(user_data); - VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(mitem); - priv->grabbed = FALSE; -} - -void -voip_input_widget_tidy_up (GtkWidget *widget) -{ - VoipInputWidget* mitem = VOIP_INPUT_WIDGET(widget); - VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(mitem); - gtk_widget_destroy (priv->ido_voip_input_slider); -} - -/** - * voip_input_widget_new: - * @returns: a new #VoipInputWidget. - **/ -GtkWidget* -voip_input_widget_new(DbusmenuMenuitem *item) -{ - GtkWidget* widget = g_object_new(VOIP_INPUT_WIDGET_TYPE, NULL); - voip_input_widget_set_twin_item((VoipInputWidget*)widget, item); - return widget; -} - - diff --git a/src/voip-input-widget.h b/src/voip-input-widget.h deleted file mode 100644 index 72da80c..0000000 --- a/src/voip-input-widget.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#ifndef __VOIP_INPUT_WIDGET_H__ -#define __VOIP_INPUT_WIDGET_H__ - -#include <glib.h> -#include <glib-object.h> -#include <gtk/gtk.h> -#include <libdbusmenu-gtk/menuitem.h> - -G_BEGIN_DECLS - -#define VOIP_INPUT_WIDGET_TYPE (voip_input_widget_get_type ()) -#define VOIP_INPUT_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VOIP_INPUT_WIDGET_TYPE, VoipInputWidget)) -#define VOIP_INPUT_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VOIP_INPUT_WIDGET_TYPE, VoipInputWidgetClass)) -#define IS_VOIP_INPUT_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VOIP_INPUT_WIDGET_TYPE)) -#define IS_VOIP_INPUT_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VOIP_INPUT_WIDGET_TYPE)) -#define VOIP_INPUT_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VOIP_INPUT_WIDGET_TYPE, VoipInputWidgetClass)) - -typedef struct _VoipInputWidget VoipInputWidget; -typedef struct _VoipInputWidgetClass VoipInputWidgetClass; - -struct _VoipInputWidgetClass { - GObjectClass parent_class; -}; - -struct _VoipInputWidget { - GObject parent; -}; - -GType voip_input_widget_get_type (void) G_GNUC_CONST; -GtkWidget* voip_input_widget_new(DbusmenuMenuitem* twin_item); -GtkWidget* voip_input_widget_get_ido_slider(VoipInputWidget* self); -void voip_input_widget_update(VoipInputWidget* self, gdouble update); -void voip_input_widget_tidy_up (GtkWidget *widget); - -G_END_DECLS - -#endif - diff --git a/src/volume-control.vala b/src/volume-control.vala new file mode 100644 index 0000000..9475f53 --- /dev/null +++ b/src/volume-control.vala @@ -0,0 +1,272 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * 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; version 3. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: + * Alberto Ruiz <alberto.ruiz@canonical.com> + */ + +using PulseAudio; + +[CCode(cname="pa_cvolume_set", cheader_filename = "pulse/volume.h")] +extern unowned PulseAudio.CVolume? vol_set (PulseAudio.CVolume? cv, uint channels, PulseAudio.Volume v); + +public class VolumeControl : Object +{ + /* this is static to ensure it being freed after @context (loop does not have ref counting) */ + private static PulseAudio.GLibMainLoop loop; + + private PulseAudio.Context context; + private bool _mute = true; + private double _volume = 0.0; + private double _mic_volume = 0.0; + + public signal void volume_changed (double v); + public signal void mic_volume_changed (double v); + + /** true when connected to the pulse server */ + public bool ready { get; set; } + + /** true when a microphone is active **/ + public bool active_mic { get; private set; default = false; } + + public VolumeControl () + { + if (loop == null) + loop = new PulseAudio.GLibMainLoop (); + + var props = new Proplist (); + props.sets (Proplist.PROP_APPLICATION_NAME, "Ubuntu Audio Settings"); + props.sets (Proplist.PROP_APPLICATION_ID, "com.canonical.settings.sound"); + props.sets (Proplist.PROP_APPLICATION_ICON_NAME, "multimedia-volume-control"); + props.sets (Proplist.PROP_APPLICATION_VERSION, "0.1"); + + context = new PulseAudio.Context (loop.get_api(), null, props); + + context.set_state_callback (context_state_callback); + + if (context.connect(null, Context.Flags.NOFAIL, null) < 0) + { + warning( "pa_context_connect() failed: %s\n", PulseAudio.strerror(context.errno())); + return; + } + } + + /* PulseAudio logic*/ + private void context_events_cb (Context c, Context.SubscriptionEventType t, uint32 index) + { + switch (t & Context.SubscriptionEventType.FACILITY_MASK) + { + case Context.SubscriptionEventType.SINK: + update_sink (); + break; + + case Context.SubscriptionEventType.SOURCE: + update_source (); + break; + + case Context.SubscriptionEventType.SOURCE_OUTPUT: + switch (t & Context.SubscriptionEventType.TYPE_MASK) + { + case Context.SubscriptionEventType.NEW: + c.get_source_output_info (index, source_output_info_cb); + break; + + case Context.SubscriptionEventType.REMOVE: + this.active_mic = false; + break; + } + break; + } + } + + private void sink_info_cb_for_props (Context c, SinkInfo? i, int eol) + { + if (i == null) + return; + + if (_mute != (bool)i.mute) + { + _mute = (bool)i.mute; + this.notify_property ("mute"); + } + + if (_volume != volume_to_double (i.volume.values[0])) + { + _volume = volume_to_double (i.volume.values[0]); + volume_changed (_volume); + } + } + + private void source_info_cb (Context c, SourceInfo? i, int eol) + { + if (i == null) + return; + + if (_mic_volume != volume_to_double (i.volume.values[0])) + { + _mic_volume = volume_to_double (i.volume.values[0]); + mic_volume_changed (_mic_volume); + } + } + + private void server_info_cb_for_props (Context c, ServerInfo? i) + { + if (i == null) + return; + context.get_sink_info_by_name (i.default_sink_name, sink_info_cb_for_props); + } + + private void update_sink () + { + context.get_server_info (server_info_cb_for_props); + } + + private void update_source () + { + context.get_server_info ( (c, i) => { + if (i != null) + context.get_source_info_by_name (i.default_source_name, source_info_cb); + }); + } + + private void source_output_info_cb (Context c, SourceOutputInfo? i, int eol) + { + if (i == null) + return; + + var role = i.proplist.gets (PulseAudio.Proplist.PROP_MEDIA_ROLE); + if (role == "phone" || role == "production") + this.active_mic = true; + } + + private void context_state_callback (Context c) + { + if (c.get_state () == Context.State.READY) + { + c.subscribe (PulseAudio.Context.SubscriptionMask.SINK | + PulseAudio.Context.SubscriptionMask.SOURCE | + PulseAudio.Context.SubscriptionMask.SOURCE_OUTPUT); + c.set_subscribe_callback (context_events_cb); + update_sink (); + update_source (); + this.ready = true; + } + else + this.ready = false; + } + + /* Mute operations */ + public void set_mute (bool mute) + { + return_if_fail (context.get_state () == Context.State.READY); + + context.get_sink_info_list ((context, sink, eol) => { + if (sink != null) + context.set_sink_mute_by_index (sink.index, mute, null); + }); + } + + public void toggle_mute () + { + this.set_mute (!this._mute); + } + + public bool mute + { + get + { + return this._mute; + } + } + + /* Volume operations */ + private static PulseAudio.Volume double_to_volume (double vol) + { + double tmp = (double)(PulseAudio.Volume.NORM - PulseAudio.Volume.MUTED) * vol; + return (PulseAudio.Volume)tmp + PulseAudio.Volume.MUTED; + } + + private static double volume_to_double (PulseAudio.Volume vol) + { + double tmp = (double)(vol - PulseAudio.Volume.MUTED); + return tmp / (double)(PulseAudio.Volume.NORM - PulseAudio.Volume.MUTED); + } + + private void set_volume_success_cb (Context c, int success) + { + if ((bool)success) + volume_changed (_volume); + } + + private void sink_info_set_volume_cb (Context c, SinkInfo? i, int eol) + { + if (i == null) + return; + + unowned CVolume cvol = vol_set (i.volume, 1, double_to_volume (_volume)); + c.set_sink_volume_by_index (i.index, cvol, set_volume_success_cb); + } + + private void server_info_cb_for_set_volume (Context c, ServerInfo? i) + { + if (i == null) + { + warning ("Could not get PulseAudio server info"); + return; + } + + context.get_sink_info_by_name (i.default_sink_name, sink_info_set_volume_cb); + } + + public void set_volume (double volume) + { + return_if_fail (context.get_state () == Context.State.READY); + + _volume = volume; + + context.get_server_info (server_info_cb_for_set_volume); + } + + void set_mic_volume_success_cb (Context c, int success) + { + if ((bool)success) + mic_volume_changed (_mic_volume); + } + + public void set_mic_volume (double volume) + { + return_if_fail (context.get_state () == Context.State.READY); + + _mic_volume = volume; + + context.get_server_info ( (c, i) => { + if (i != null) { + unowned CVolume cvol = CVolume (); + cvol = vol_set (cvol, 1, double_to_volume (_mic_volume)); + c.set_source_volume_by_name (i.default_source_name, cvol, set_mic_volume_success_cb); + } + }); + } + + public double get_volume () + { + return _volume; + } + + public double get_mic_volume () + { + return _mic_volume; + } +} diff --git a/src/volume-widget.c b/src/volume-widget.c deleted file mode 100644 index 1258c20..0000000 --- a/src/volume-widget.c +++ /dev/null @@ -1,338 +0,0 @@ - -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <glib/gi18n-lib.h> -#include <math.h> -#include <glib.h> -#include "volume-widget.h" -#include "common-defs.h" -#include <libido/idoscalemenuitem.h> -#include "indicator-sound.h" - -typedef struct _VolumeWidgetPrivate VolumeWidgetPrivate; - -struct _VolumeWidgetPrivate -{ - DbusmenuMenuitem* twin_item; - GtkWidget* ido_volume_slider; - gboolean grabbed; - IndicatorObject* indicator; -}; - -#define VOLUME_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), VOLUME_WIDGET_TYPE, VolumeWidgetPrivate)) - -/* Prototypes */ -static void volume_widget_class_init (VolumeWidgetClass *klass); -static void volume_widget_init (VolumeWidget *self); -static void volume_widget_dispose (GObject *object); -static void volume_widget_finalize (GObject *object); -static void volume_widget_set_twin_item( VolumeWidget* self, - DbusmenuMenuitem* twin_item); -static void volume_widget_property_update( DbusmenuMenuitem* item, gchar* property, - GVariant* value, gpointer userdata ); - -static gboolean volume_widget_change_value_cb (GtkRange *range, - GtkScrollType scroll, - gdouble value, - gpointer user_data); -static void volume_widget_primary_clicked(GtkWidget *widget, gpointer user_data); -static void volume_widget_secondary_clicked(GtkWidget *widget, gpointer user_data); -static void volume_widget_slider_grabbed(GtkWidget *widget, gpointer user_data); -static void volume_widget_slider_released(GtkWidget *widget, gpointer user_data); -static void volume_widget_parent_changed (GtkWidget *widget, gpointer user_data); - -G_DEFINE_TYPE (VolumeWidget, volume_widget, G_TYPE_OBJECT); - - -static void -volume_widget_class_init (VolumeWidgetClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (VolumeWidgetPrivate)); - - gobject_class->dispose = volume_widget_dispose; - gobject_class->finalize = volume_widget_finalize; -} - -static void -volume_widget_init (VolumeWidget *self) -{ - VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(self); - - priv->ido_volume_slider = ido_scale_menu_item_new_with_range ("VOLUME", IDO_RANGE_STYLE_DEFAULT, 0, 0, 100, 1); - g_object_ref (priv->ido_volume_slider); - ido_scale_menu_item_set_primary_label (IDO_SCALE_MENU_ITEM(priv->ido_volume_slider), "VOLUME"); - ido_scale_menu_item_set_style (IDO_SCALE_MENU_ITEM (priv->ido_volume_slider), IDO_SCALE_MENU_ITEM_STYLE_IMAGE); - g_object_set(priv->ido_volume_slider, "reverse-scroll-events", TRUE, NULL); - - g_signal_connect (priv->ido_volume_slider, - "notify::parent", G_CALLBACK (volume_widget_parent_changed), - NULL); - - GtkWidget* volume_widget = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider); - - g_signal_connect(volume_widget, "change-value", G_CALLBACK(volume_widget_change_value_cb), self); - g_signal_connect(priv->ido_volume_slider, "primary-clicked", G_CALLBACK(volume_widget_primary_clicked), self); - g_signal_connect(priv->ido_volume_slider, "secondary-clicked", G_CALLBACK(volume_widget_secondary_clicked), self); - g_signal_connect(priv->ido_volume_slider, "slider-grabbed", G_CALLBACK(volume_widget_slider_grabbed), self); - g_signal_connect(priv->ido_volume_slider, "slider-released", G_CALLBACK(volume_widget_slider_released), self); - - GtkWidget* primary_image = ido_scale_menu_item_get_primary_image((IdoScaleMenuItem*)priv->ido_volume_slider); - GIcon * primary_gicon = g_themed_icon_new_with_default_fallbacks("audio-volume-low-zero-panel"); - gtk_image_set_from_gicon(GTK_IMAGE(primary_image), primary_gicon, GTK_ICON_SIZE_MENU); - g_object_unref(primary_gicon); - - GtkWidget* secondary_image = ido_scale_menu_item_get_secondary_image((IdoScaleMenuItem*)priv->ido_volume_slider); - GIcon * secondary_gicon = g_themed_icon_new_with_default_fallbacks("audio-volume-high-panel"); - gtk_image_set_from_gicon(GTK_IMAGE(secondary_image), secondary_gicon, GTK_ICON_SIZE_MENU); - g_object_unref(secondary_gicon); - - GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (volume_widget)); - gtk_adjustment_set_step_increment(adj, 4); -} - -static void -volume_widget_dispose (GObject *object) -{ - G_OBJECT_CLASS (volume_widget_parent_class)->dispose (object); -} - -static void -volume_widget_finalize (GObject *object) -{ - G_OBJECT_CLASS (volume_widget_parent_class)->finalize (object); -} - -static void -volume_widget_property_update( DbusmenuMenuitem* item, gchar* property, - GVariant* value, gpointer userdata) -{ - g_return_if_fail (IS_VOLUME_WIDGET(userdata)); - VolumeWidget* mitem = VOLUME_WIDGET(userdata); - VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(mitem); - - if(g_ascii_strcasecmp(DBUSMENU_VOLUME_MENUITEM_LEVEL, property) == 0){ - g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE) ); - gdouble update = g_variant_get_double (value); - - if(priv->grabbed == FALSE){ - GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider); - GtkRange *range = (GtkRange*)slider; - gtk_range_set_value(range, update); -/* - g_debug ("volume-widget::volume_widget_property_update - volume - value %f", update); - AtkObject* atk_object; - atk_object = gtk_widget_get_accessible (priv->ido_volume_slider); - if (atk_object != NULL){ - atk_object_set_name (atk_object, desc); - - }*/ - } - gchar* desc = g_strdup_printf(_("Volume (%'.0f%%)"), - update); - dbusmenu_menuitem_property_set (priv->twin_item, - DBUSMENU_MENUITEM_PROP_ACCESSIBLE_DESC, - desc); - g_free (desc); - update_accessible_desc(priv->indicator); - } - else if(g_ascii_strcasecmp(DBUSMENU_VOLUME_MENUITEM_MUTE, property) == 0){ - g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)); - if(priv->grabbed == FALSE){ - GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider); - GtkRange *range = (GtkRange*)slider; - gboolean update = g_variant_get_boolean (value); - gdouble level; - - if (update == TRUE){ - level = 0; - } - else{ - GVariant* variant = dbusmenu_menuitem_property_get_variant (priv->twin_item, - DBUSMENU_VOLUME_MENUITEM_LEVEL); -/* - g_debug ("variant for the volume - is it null = %i", variant == NULL); -*/ - g_return_if_fail (g_variant_is_of_type (variant, G_VARIANT_TYPE_DOUBLE) ); - - level = g_variant_get_double (variant); - } -/* - g_debug ("volume-widget::volume_widget_property_update - mute - value %i and level = %f", update, level); -*/ - gtk_range_set_value(range, level); - } - } -} - -static void -volume_widget_set_twin_item(VolumeWidget* self, - DbusmenuMenuitem* twin_item) -{ - VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(self); - priv->twin_item = twin_item; - g_object_ref(priv->twin_item); - g_signal_connect(G_OBJECT(twin_item), "property-changed", - G_CALLBACK(volume_widget_property_update), self); - gdouble initial_level = g_variant_get_double (dbusmenu_menuitem_property_get_variant(twin_item, - DBUSMENU_VOLUME_MENUITEM_LEVEL)); - gboolean initial_mute = g_variant_get_boolean (dbusmenu_menuitem_property_get_variant(twin_item, - DBUSMENU_VOLUME_MENUITEM_MUTE)); - - //g_debug("volume_widget_set_twin_item initial level = %f", initial_level); - GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider); - GtkRange *range = (GtkRange*)slider; - if(initial_mute == TRUE){ - initial_level = 0; - } - gtk_range_set_value(range, initial_level); - gchar* desc = g_strdup_printf(_("Volume (%'.0f%%)"), - initial_level); - dbusmenu_menuitem_property_set (priv->twin_item, - DBUSMENU_MENUITEM_PROP_ACCESSIBLE_DESC, - desc); - g_free (desc); - -} - -static gboolean -volume_widget_change_value_cb (GtkRange *range, - GtkScrollType scroll, - gdouble new_value, - gpointer user_data) -{ - g_return_val_if_fail (IS_VOLUME_WIDGET (user_data), FALSE); - VolumeWidget* mitem = VOLUME_WIDGET(user_data); - -/* - g_debug ("changed value %f", new_value); -*/ - - volume_widget_update(mitem, new_value, "change-value"); - return FALSE; -} - -void -volume_widget_update(VolumeWidget* self, gdouble update, gchar* label) -{ - gchar* source = NULL; - source = label; - if (label == NULL){ - source = "v widget update"; - } - VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(self); - gdouble clamped = CLAMP(update, 0, 100); - GVariant* new_volume = g_variant_new_double(clamped); - dbusmenu_menuitem_handle_event (priv->twin_item, source, new_volume, 0); -} - -static void -volume_widget_update_from_scale (VolumeWidget *self) -{ - g_return_if_fail (IS_VOLUME_WIDGET (self)); - - VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(self); - GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider); - const gdouble current_value = CLAMP(gtk_range_get_value(GTK_RANGE(slider)), 0, 100); - g_debug ("%s - setting value to %.0f", G_STRFUNC, current_value); - volume_widget_update (self, current_value, "value-changed"); -} - -static void -volume_widget_primary_clicked (GtkWidget *widget G_GNUC_UNUSED, gpointer user_data) -{ - volume_widget_update_from_scale (VOLUME_WIDGET(user_data)); -} - -static void -volume_widget_secondary_clicked(GtkWidget *widget, gpointer user_data) -{ - volume_widget_update_from_scale (VOLUME_WIDGET(user_data)); -} - -GtkWidget* -volume_widget_get_ido_slider(VolumeWidget* self) -{ - VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(self); - return priv->ido_volume_slider; -} - -static void -volume_widget_parent_changed (GtkWidget *widget, - gpointer user_data) -{ - gtk_widget_set_size_request (widget, 200, -1); - //g_debug("volume_widget_parent_changed"); -} - -static void -volume_widget_slider_grabbed(GtkWidget *widget, gpointer user_data) -{ - VolumeWidget* mitem = VOLUME_WIDGET(user_data); - VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(mitem); - priv->grabbed = TRUE; -} - -static void -volume_widget_slider_released(GtkWidget *widget, gpointer user_data) -{ - VolumeWidget* mitem = VOLUME_WIDGET(user_data); - VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(mitem); - priv->grabbed = FALSE; -} - -void -volume_widget_tidy_up (GtkWidget *widget) -{ - VolumeWidget* mitem = VOLUME_WIDGET(widget); - VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(mitem); - gtk_widget_destroy (priv->ido_volume_slider); -} - -gdouble -volume_widget_get_current_volume ( GtkWidget *widget ) -{ - VolumeWidget* mitem = VOLUME_WIDGET(widget); - VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(mitem); - gdouble vol = g_variant_get_double( dbusmenu_menuitem_property_get_variant( priv->twin_item, - DBUSMENU_VOLUME_MENUITEM_LEVEL)); - return vol; -} - -/** - * volume_widget_new: - * @returns: a new #VolumeWidget. - **/ -GtkWidget* -volume_widget_new(DbusmenuMenuitem *item, IndicatorObject* io) -{ - GtkWidget* widget = g_object_new(VOLUME_WIDGET_TYPE, NULL); - VolumeWidgetPrivate* priv = VOLUME_WIDGET_GET_PRIVATE(VOLUME_WIDGET(widget)); - priv->indicator = io; - volume_widget_set_twin_item((VolumeWidget*)widget, item); - return widget; -} - - diff --git a/src/volume-widget.h b/src/volume-widget.h deleted file mode 100644 index 665f39b..0000000 --- a/src/volume-widget.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#ifndef __VOLUME_WIDGET_H__ -#define __VOLUME_WIDGET_H__ - -#include <glib.h> -#include <glib-object.h> -#include <gtk/gtk.h> -#include <libdbusmenu-gtk/menuitem.h> -#include <libindicator/indicator-object.h> - -G_BEGIN_DECLS - -#define VOLUME_WIDGET_TYPE (volume_widget_get_type ()) -#define VOLUME_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VOLUME_WIDGET_TYPE, VolumeWidget)) -#define VOLUME_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VOLUME_WIDGET_TYPE, VolumeWidgetClass)) -#define IS_VOLUME_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VOLUME_WIDGET_TYPE)) -#define IS_VOLUME_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VOLUME_WIDGET_TYPE)) -#define VOLUME_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VOLUME_WIDGET_TYPE, VolumeWidgetClass)) - -typedef struct _VolumeWidget VolumeWidget; -typedef struct _VolumeWidgetClass VolumeWidgetClass; - -struct _VolumeWidgetClass { - GObjectClass parent_class; -}; - -struct _VolumeWidget { - GObject parent; -}; - -GType volume_widget_get_type (void) G_GNUC_CONST; -GtkWidget* volume_widget_new(DbusmenuMenuitem *item, IndicatorObject* io); -GtkWidget* volume_widget_get_ido_slider(VolumeWidget* self); -void volume_widget_update(VolumeWidget* self, gdouble update, gchar* label); -void volume_widget_tidy_up (GtkWidget *widget); -gdouble volume_widget_get_current_volume ( GtkWidget *widget ); - -G_END_DECLS - -#endif - diff --git a/tests/Makefile.am b/tests/Makefile.am index 574279f..8b13789 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,151 +1 @@ -check_PROGRAMS = \ - test-indicator-sound \ - test-pulse-manager \ - test-indicator-sound-dbus-client \ - test-indicator-sound-dbus-server - -TESTS = \ - test-indicator-sound \ - test-pulse-manager -XTESTS_FAIL = $(TESTS) - -DISTCLEANFILES = $(TESTS) - -noinst_LTLIBRARIES = libmockpulse.la -libmockpulse_la_SOURCES = mockpulse.c mockpulse.h -libmockpulse_la_CFLAGS = $(PULSEAUDIO_CFLAGS) - - -######################################### -## test-indicator-sound -######################################### -test_indicator_sound_SOURCES = \ - test-indicator-sound.c \ - $(top_builddir)/src/indicator-sound.c - -test_indicator_sound_CFLAGS = \ - $(PULSEAUDIO_CFLAGS) \ - $(APPLET_CFLAGS) \ - -Wall -Werror \ - -I$(srcdir) \ - -DTOP_BUILD_DIR="\"${abs_top_builddir}\"" - -test_indicator_sound_LDADD = \ - libmockpulse.la \ - $(PULSEAUDIO_LIBS) \ - $(APPLET_LIBS) \ - ../src/libsoundmenu.la - - -######################################### -## test-pulse-manager -######################################### - -check_PROGRAMS += test-pulse-manager - -test_pulse_manager_SOURCES = \ - test-pulse-manager.c \ - $(top_builddir)/src/dbus-menu-manager.c \ - $(top_builddir)/src/sound-service-dbus.c \ - $(top_builddir)/src/gen-sound-service.xml.h \ - $(top_builddir)/src/gen-sound-service.xml.c \ - $(top_builddir)/src/slider-menu-item.c - -test_pulse_manager_CFLAGS = \ - $(PULSEAUDIO_CFLAGS) \ - $(SOUNDSERVICE_CFLAGS) \ - $(GCONF_CFLAGS) \ - -Wall -Werror \ - -I$(srcdir) \ - -I$(SOUNDSERVICE_CFLAGS) - -test_pulse_manager_LDADD = \ - libmockpulse.la \ - $(PULSEAUDIO_LIBS) \ - $(SOUNDSERVICE_LIBS) \ - $(GCONF_LIBS) \ - $(APPLET_LIBS) - -######################################### -## test-indicator-sound-dbus-client -######################################### -test_indicator_sound_dbus_client_SOURCES = \ - test-defines.h \ - test-indicator-sound-dbus-client.c - -test_indicator_sound_dbus_client_CFLAGS = \ - $(PULSEAUDIO_CFLAGS) \ - $(SOUNDSERVICE_CFLAGS) \ - -Wall -Werror \ - -I$(srcdir) \ - -I$(SOUNDSERVICE_CFLAGS) - -test_indicator_sound_dbus_client_LDADD = \ - $(PULSEAUDIO_LIBS) \ - $(SOUNDSERVICE_LIBS) - -######################################## -# test-indicator-sound-dbus-server -######################################## -test_indicator_sound_dbus_server_SOURCES = \ - test-defines.h \ - test-indicator-sound-dbus-server.c \ - $(top_builddir)/src/sound-service-dbus.c \ - $(top_builddir)/src/pulse-manager.c \ - $(top_builddir)/src/slider-menu-item.c \ - $(top_builddir)/src/dbus-menu-manager.c - -test_indicator_sound_dbus_server_CFLAGS = \ - $(SOUNDSERVICE_CFLAGS) \ - -Wall -Werror \ - -I$(srcdir) - -test_indicator_sound_dbus_server_LDADD = \ - $(SOUNDSERVICE_LIBS) \ - $(PULSEAUDIO_LIBS) - - -######################################### -## Actual tests -######################################### - -XML_REPORT = indicator-sound-check-results.xml -HTML_REPORT = indicator-sound-check-results.html - -indicator-sound-tests: indicator-sound-tests-gtester Makefile.am - @echo "#!/bin/sh" > $@ - @echo $(DBUS_RUNNER) --task ./indicator-sound-tests-gtester >> $@ - @chmod +x $@ - -indicator-sound-tests-gtester: test-indicator-sound Makefile.am - @echo "#!/bin/sh" > $@ - @echo gtester -k --verbose -o=$(XML_REPORT) ./test-indicator-sound >> $@ - @chmod +x $@ - -TESTS += indicator-sound-tests-gtester - -PULSE_XML_REPORT = pulse-manager-check-results.xml - -pulse-manager-tests-gtester: test-pulse-manager Makefile.am - @echo "#!/bin/sh" > $@ - @echo gtester -k --verbose -o=$(PULSE_XML_REPORT) ./test-pulse-manager >> $@ - @chmod +x $@ - -TESTS += pulse-manager-tests-gtester - -DISTCLEANFILES += $(XML_REPORT) $(PULSE_XML_REPORT) $(HTML_REPORT) indicator-sound-tests-gtester - -DBUS_RUNNER=dbus-test-runner --dbus-config /usr/share/dbus-test-runner/session.conf - -test-indicator-sound-dbus: test-indicator-sound-dbus-client test-indicator-sound-dbus-server Makefile.am - @echo "#!/bin/sh" > test-indicator-sound-dbus - @echo $(DBUS_RUNNER) --task ./test-indicator-sound-dbus-server --task-name Server --ignore-return >> test-indicator-sound-dbus --task ./test-indicator-sound-dbus-client --task-name Client - @chmod +x test-indicator-sound-dbus - -TESTS += test-indicator-sound-dbus - - - - - diff --git a/tests/mockpulse.c b/tests/mockpulse.c deleted file mode 100644 index b868e07..0000000 --- a/tests/mockpulse.c +++ /dev/null @@ -1,105 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Robert Collins <robert.collins@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - - -#include <pulse/glib-mainloop.h> -#include <pulse/context.h> -#include <pulse/operation.h> -#include <pulse/introspect.h> -#include "mockpulse.h" - -struct pa_context { - int refcount; - pa_context_notify_cb_t cb; - void *cbdata; - pa_context_state_t state; -}; - -pa_glib_mainloop * -pa_glib_mainloop_new(GMainContext *c) -{ - return NULL; -} - -pa_context * -pa_context_new(pa_mainloop_api *loop, char const *name) { - struct pa_context * result = g_new(pa_context, 1); - result->refcount = 1; - return result; -} - -void -pa_context_unref(pa_context * context) { - context->refcount--; - if (!context->refcount) - g_free(context); -} - -void -pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) -{ - c->cb = cb; - c->cbdata = userdata; -} - -void set_pa_context_get_state_result(pa_context *c, pa_context_state_t state) -{ - c->state = state; -} - -pa_context_state_t -pa_context_get_state(pa_context *c) -{ - return c->state; -} - -struct pa_operation { - int refcount; -}; - - -/*void pa_context_connect(pa_context* c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api)*/ -/*{*/ -/* set_pa_context_get_state_result(c, PA_CONTEXT_CONNECTING);*/ -/*}*/ - -/* Can be made into a list if we need multiple callbacks */ -static pa_sink_info *next_sink_info; - -void -set_pa_context_get_sink_info(pa_sink_info *info) { - next_sink_info = info; -} - -pa_operation * -pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, pa_sink_info_cb_t cb, void * userdata) -{ - pa_operation *result = g_new(pa_operation, 1); - result->refcount = 1; - cb(c, next_sink_info, 0, userdata); - return result; -} - -void -pa_operation_unref(pa_operation * foo) -{ - foo->refcount--; - if (!foo->refcount) - g_free(foo); -} diff --git a/tests/mockpulse.h b/tests/mockpulse.h deleted file mode 100644 index 71cd85b..0000000 --- a/tests/mockpulse.h +++ /dev/null @@ -1,26 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Robert Collins <robert.collins@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -/** - * Control interface for the mocked pa-glib-mainloop test library - */ -#include <pulse/glib-mainloop.h> - -void set_pa_context_get_state_result(pa_context *, pa_context_state_t state); -void set_pa_context_get_sink_info(pa_sink_info *info); diff --git a/tests/run-xvfb.sh b/tests/run-xvfb.sh deleted file mode 100644 index 63b6f0d..0000000 --- a/tests/run-xvfb.sh +++ /dev/null @@ -1,8 +0,0 @@ -if [ "$DISPLAY" == "" ]; then -Xvfb -ac -noreset -screen 0 800x600x16 -help 2>/dev/null 1>&2 -XID=`for id in 101 102 103 104 105 106 107 197 199 211 223 227 293 307 308 309 310 311 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 4703 4721 4723 4729 4733 4751 9973 9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984 9985 9986 9987 9988 9989 9990 9991 9992 9993 9994 9995 9996 9997 9998 9999 ; do test -e /tmp/.X$id-lock || { echo $id; exit 0; }; done; exit 1` -{ Xvfb -ac -noreset -screen 0 800x600x16 :$XID -screen 0 800x600x16 -nolisten tcp -auth /dev/null >/dev/null 2>&1 & trap "kill -15 $! " 0 HUP INT QUIT TRAP USR1 PIPE TERM ; } || { echo "Gtk+Tests:ERROR: Failed to start Xvfb environment for X11 target tests."; exit 1; } -DISPLAY=:$XID -export DISPLAY -echo Setting display: $DISPLAY -fi diff --git a/tests/test-defines.h b/tests/test-defines.h deleted file mode 100644 index 214274e..0000000 --- a/tests/test-defines.h +++ /dev/null @@ -1,25 +0,0 @@ -/* -Testing defines to be shared between various tests. - -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - Ted Gould <ted@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#define TEST_MUTE_VALUE TRUE -#define TEST_VOLUME_VALUE 77.77777 -#define TEST_AVAILABLE_VALUE TRUE diff --git a/tests/test-indicator-sound-dbus-client.c b/tests/test-indicator-sound-dbus-client.c deleted file mode 100644 index eafd03a..0000000 --- a/tests/test-indicator-sound-dbus-client.c +++ /dev/null @@ -1,110 +0,0 @@ -/* -Tests for the libappindicator library that are over DBus. This is -the client side of those tests. - -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - Ted Gould <ted@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - - -#include <glib.h> -#include "../src/dbus-shared-names.h" -#include "test-defines.h" -#include "../src/sound-service-client.h" - -static GMainLoop * mainloop = NULL; -static GDBusProxy * proxy= NULL; - -static void -test_fetch_mute(GDBusProxy * proxy) -{ - GError * error = NULL; - gboolean *fetched_mute_value; - fetched_mute_value = g_new0(gboolean, 1); - org_ayatana_indicator_sound_get_sink_mute(proxy, fetched_mute_value, &error); - if (error != NULL) { - g_warning("test-indicator-sound-dbus-client::test_fetch_mute - Unable to fetch mute: %s", error->message); - g_error_free(error); - g_free(fetched_mute_value); - return; - } - g_assert(TEST_MUTE_VALUE == *fetched_mute_value); - g_free(fetched_mute_value); -} - -static void -test_fetch_availability(DBusGProxy * proxy) -{ - GError * error = NULL; - gboolean * available_input; - available_input = g_new0(gboolean, 1); - org_ayatana_indicator_sound_get_sink_availability(proxy, available_input, &error); - if (error != NULL) { - g_warning("test-indicator-sound-dbus-client::test_fetch_availability - unable to fetch availability %s", error->message); - g_error_free(error); - g_free(available_input); - return; - } - g_assert(TEST_AVAILABLE_VALUE == *available_input); - g_free(available_input); -} - - -gboolean -kill_func (gpointer userdata) -{ - g_free(proxy); - g_main_loop_quit(mainloop); - return FALSE; -} - -gint -main (gint argc, gchar * argv[]) -{ - g_type_init(); - g_test_init(&argc, &argv, NULL); - - g_usleep(500000); - - GError * error = NULL; - DBusGConnection * session_bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error); - if (error != NULL) { - g_error("Unable to get session bus: %s", error->message); - return 1; - } - - DBusGProxy * proxy = dbus_g_proxy_new_for_name_owner(session_bus, - ":1.0", - INDICATOR_SOUND_SERVICE_DBUS_OBJECT, - INDICATOR_SOUND_SERVICE_DBUS_INTERFACE, - &error); - if (error != NULL) { - g_error("Unable to get property proxy: %s", error->message); - return 1; - } - - test_fetch_mute(proxy); - test_fetch_availability(proxy); - - g_timeout_add_seconds(2, kill_func, NULL); - - mainloop = g_main_loop_new(NULL, FALSE); - g_main_loop_run(mainloop); - - return 0; -} diff --git a/tests/test-indicator-sound-dbus-server.c b/tests/test-indicator-sound-dbus-server.c deleted file mode 100644 index b1e3d9c..0000000 --- a/tests/test-indicator-sound-dbus-server.c +++ /dev/null @@ -1,63 +0,0 @@ -/* -Tests for the libappindicator library that are over DBus. This is -the server side of those tests. - -Copyright 2009 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - Ted Gould <ted@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - - -#include <dbus/dbus-glib.h> -#include <dbus/dbus-glib-lowlevel.h> -#include <glib.h> -#include "../src/sound-service-dbus.h" -#include "test-defines.h" - -static GMainLoop * mainloop = NULL; -static SoundServiceDbus *dbus_interface = NULL; - -gboolean -kill_func (gpointer userdata) -{ - g_main_loop_quit(mainloop); - return FALSE; -} - -gint -main (gint argc, gchar * argv[]) -{ - g_type_init(); - - dbus_interface = g_object_new(SOUND_SERVICE_DBUS_TYPE, NULL); - - // Set the mute value - sound_service_dbus_update_sink_mute(dbus_interface, TEST_MUTE_VALUE); - sound_service_dbus_update_sink_availability(dbus_interface, TEST_AVAILABLE_VALUE); - - g_timeout_add_seconds(4, kill_func, NULL); - - // Run the loop - mainloop = g_main_loop_new(NULL, FALSE); - g_main_loop_run(mainloop); - - g_debug("Quiting"); - - return 0; -} - - diff --git a/tests/test-indicator-sound.c b/tests/test-indicator-sound.c deleted file mode 100644 index ae071d0..0000000 --- a/tests/test-indicator-sound.c +++ /dev/null @@ -1,96 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <string.h> -#include <gtk/gtk.h> -#include <libindicator/indicator-object.h> -#include "../src/indicator-sound.h" - -static const gint STATE_MUTED = 0; -static const gint STATE_ZERO = 1; -static const gint STATE_LOW = 2; -static const gint STATE_MEDIUM = 3; -static const gint STATE_HIGH = 4; -static const gint STATE_MUTED_WHILE_INPUT = 5; -static const gint STATE_SINKS_NONE = 6; - -void test_libindicator_sound_init() -{ - IndicatorObject * sound_menu = indicator_object_new_from_file(TOP_BUILD_DIR "/src/.libs/libsoundmenu.so"); - g_assert(sound_menu != NULL); - g_object_unref(G_OBJECT(sound_menu)); -} - -void test_libindicator_determine_state() -{ - IndicatorObject * sound_menu = indicator_object_new_from_file(TOP_BUILD_DIR "/src/.libs/libsoundmenu.so"); - - determine_state_from_volume(40); - g_assert(get_state() == STATE_MEDIUM); - - determine_state_from_volume(0); - g_assert(get_state() == STATE_ZERO); - - determine_state_from_volume(15); - g_assert(get_state() == STATE_LOW); - - determine_state_from_volume(70); - g_assert(get_state() == STATE_HIGH); - - g_object_unref(G_OBJECT(sound_menu)); -} - -void test_libindicator_image_names() -{ - - gchar* muted_name = get_state_image_name(STATE_MUTED); - g_assert(g_ascii_strncasecmp("audio-volume-muted-panel", muted_name, strlen("audio-volume-muted-panel")) == 0); - - gchar* zero_name = get_state_image_name(STATE_ZERO); - g_assert(g_ascii_strncasecmp("audio-volume-low-zero-panel", zero_name, strlen("audio-volume-low-zero-panel")) == 0); - - gchar* low_name = get_state_image_name(STATE_LOW); - g_assert(g_ascii_strncasecmp("audio-volume-low-panel", low_name, strlen("audio-volume-low-panel")) == 0); - - gchar* medium_name = get_state_image_name(STATE_MEDIUM); - g_assert(g_ascii_strncasecmp("audio-volume-medium-panel", medium_name, strlen("audio-volume-medium-panel")) == 0); - - gchar* high_name = get_state_image_name(STATE_HIGH); - g_assert(g_ascii_strncasecmp("audio-volume-high-panel", high_name, strlen("audio-volume-high-panel")) == 0); - - gchar* blocked_name = get_state_image_name(STATE_MUTED_WHILE_INPUT); - g_assert(g_ascii_strncasecmp("audio-volume-muted-blocking-panel", blocked_name, strlen("audio-volume-muted-blocking-panel")) == 0); - - gchar* none_name = get_state_image_name(STATE_SINKS_NONE); - g_assert(g_ascii_strncasecmp("audio-output-none-panel", none_name, strlen("audio-output-none-panel")) == 0); - - //tidy_up_hash(); -} - - -gint main (gint argc, gchar * argv[]) -{ - g_type_init(); - g_test_init(&argc, &argv, NULL); - - //g_test_add_func("/indicator-sound/indicator-sound/image_names", test_libindicator_image_names); - - return g_test_run (); -} - diff --git a/tests/test-pulse-manager.c b/tests/test-pulse-manager.c deleted file mode 100644 index 313f325..0000000 --- a/tests/test-pulse-manager.c +++ /dev/null @@ -1,139 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Robert Collins <robert.collins@canonical.com> - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <string.h> - -/* we intend to test static functions -which are not to be exported -hence the inclusion of the C file*/ -#include "../src/pulse-manager.c" -#include "mockpulse.h" - - -/** -Helper Methods -**/ -static pa_sink_info* -mock_sink_info() -{ - pa_sink_info* mock_sink; - mock_sink = g_new0(pa_sink_info, 1); - mock_sink->index = 8; - mock_sink->name = g_strdup("mock_sink"); - mock_sink->mute = 0; - pa_cvolume volume; // nearly full volume: - pa_cvolume_set(&volume, 1, 30000); - mock_sink->volume = volume; - return mock_sink; -} - - - -/*static void test_pa_context_exit()*/ -/*{*/ -/* pa_context* context = pa_context_new(NULL, "foo");*/ - -/* pa_context_set_state_callback(context, context_state_callback, NULL);*/ -/* // => call context_state_callback(context, NULL);*/ -/* // pa_context_get_state is mocked to return the right FAIL flag.*/ -/* set_pa_context_get_state_result(context, PA_CONTEXT_FAILED);*/ -/* context_state_callback(context, NULL);*/ -/* // Test to ensure context is tidied after failure.*/ -/* g_assert(context == NULL);*/ -/* // 2. then using the same pa_context_get_state we could ensure the manager*/ -/* // is attempting to reconnect to PA. */ -/* //g_assert(PA_CONTEXT_CONNECTING == pa_context_get_state(get_context()));*/ -/* //pa_context_unref(context);*/ -/*}*/ - -static void test_sink_update() -{ - pa_context* context = pa_context_new(NULL, "foo"); - pa_sink_info* mock_sink = mock_sink_info(); - set_pa_context_get_sink_info(mock_sink); - sink_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, destroy_sink_info); - - pa_context_get_sink_info_by_index(context, mock_sink->index, pulse_sink_info_callback, NULL); - - mock_sink->mute = 1; - pa_cvolume volume; // nearly full volume: - pa_cvolume_set(&volume, 1, 10000); - mock_sink->volume = volume; - - set_pa_context_get_sink_info(mock_sink); - - pa_context_get_sink_info_by_index(context, mock_sink->index, update_sink_info, NULL); - - GList *keys = g_hash_table_get_keys(sink_hash); - gint position = g_list_index(keys, GINT_TO_POINTER(mock_sink->index)); - - g_assert(position >= 0); - - sink_info* stored_sink_info = g_hash_table_lookup(sink_hash, GINT_TO_POINTER(mock_sink->index)); - - g_assert(!!mock_sink->mute == stored_sink_info->mute); - g_assert(pa_cvolume_equal(&mock_sink->volume, &stored_sink_info->volume)); - - - g_free(mock_sink); - g_hash_table_destroy(sink_hash); - pa_context_unref(context); -} - - -static void test_sink_cache_population() -{ - pa_context* context = pa_context_new(NULL, "foo"); - pa_sink_info* mock_sink = mock_sink_info(); - set_pa_context_get_sink_info(mock_sink); - sink_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, destroy_sink_info); - - pa_context_get_sink_info_by_index(context, mock_sink->index, pulse_sink_info_callback, NULL); - - GList *keys = g_hash_table_get_keys(sink_hash); - gint position = g_list_index(keys, GINT_TO_POINTER(mock_sink->index)); - - g_assert(position >= 0); - - sink_info* stored_sink_info = g_hash_table_lookup(sink_hash, GINT_TO_POINTER(mock_sink->index)); - - g_assert(g_ascii_strncasecmp(mock_sink->name, stored_sink_info->name, strlen(mock_sink->name)) == 0); - g_assert(!!mock_sink->mute == stored_sink_info->mute); - g_assert(mock_sink->index == stored_sink_info->index); - g_assert(pa_cvolume_equal(&mock_sink->volume, &stored_sink_info->volume)); - - g_free(mock_sink); - g_hash_table_destroy(sink_hash); - pa_context_unref(context); -} - - -gint main (gint argc, gchar * argv[]) -{ - g_type_init(); - g_test_init(&argc, &argv, NULL); - - g_test_add_func("/indicator-sound/pulse-manager/sink-cache-population", test_sink_cache_population); - g_test_add_func("/indicator-sound/pulse-manager/sink-update", test_sink_update); - - //g_test_add_func("/indicator-sound/pulse-manager/pa-context-exit", test_pa_context_exit); - - return g_test_run (); -} diff --git a/vapi/common-defs.vapi b/vapi/common-defs.vapi deleted file mode 100644 index a53d636..0000000 --- a/vapi/common-defs.vapi +++ /dev/null @@ -1,71 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -[CCode (cheader_filename = "common-defs.h")] -namespace DbusmenuMetadata{ - public const string MENUITEM_TYPE; - public const string MENUITEM_ARTIST; - public const string MENUITEM_TITLE; - public const string MENUITEM_ALBUM; - public const string MENUITEM_ARTURL; - public const string MENUITEM_PLAYER_NAME; - public const string MENUITEM_PLAYER_ICON; - public const string MENUITEM_PLAYER_RUNNING; - public const string MENUITEM_HIDE_TRACK_DETAILS; -} - -[CCode (cheader_filename = "common-defs.h")] -namespace DbusmenuTransport{ - public const string MENUITEM_TYPE; - public const string MENUITEM_PLAY_STATE; - public const string MENUITEM_STATE_CHANGE; -} - -[CCode (cheader_filename = "common-defs.h")] -namespace DbusmenuTrackSpecific{ - public const string MENUITEM_TYPE; -} - -[CCode (cheader_filename = "common-defs.h")] -namespace DbusmenuPlaylists{ - public const string MENUITEM_TYPE; - public const string MENUITEM_TITLE; - public const string MENUITEM_PLAYLISTS; -} -[CCode (cheader_filename = "common-defs.h")] -namespace DbusmenuPlaylist{ - public const string MENUITEM_PATH; -} - -[CCode (cprefix ="Transport", cheader_filename = "common-defs.h")] -namespace Transport{ - public enum Action{ - PREVIOUS, - PLAY_PAUSE, - NEXT, - REWIND, - FORWIND, - NO_ACTION - } - public enum State{ - PLAYING, - PAUSED, - LAUNCHING - } -} diff --git a/vapi/config.vapi b/vapi/config.vapi index 4be6d11..15c4c88 100644 --- a/vapi/config.vapi +++ b/vapi/config.vapi @@ -1,7 +1,7 @@ [CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "../config.h")] namespace Config { public const string GETTEXT_PACKAGE; - public const string LOCALEDIR; + public const string GNOMELOCALEDIR; public const string PKGDATADIR; public const string PACKAGE_NAME; public const string PACKAGE_VERSION; |