diff options
author | Sebastien Bacher <seb128@ubuntu.com> | 2010-07-08 19:31:44 +0200 |
---|---|---|
committer | Sebastien Bacher <seb128@ubuntu.com> | 2010-07-08 19:31:44 +0200 |
commit | cf5205162e421080c511428f54cb18d60cd05568 (patch) | |
tree | f096e69514b8849f40d73beb3f8cf6646a63f5b8 | |
parent | f881060f5a83bea46484083c53ee9b78f01d5d77 (diff) | |
parent | 964106d9c8c140d9c27a22aca8078dfdab57c5e9 (diff) | |
download | ayatana-indicator-sound-cf5205162e421080c511428f54cb18d60cd05568.tar.gz ayatana-indicator-sound-cf5205162e421080c511428f54cb18d60cd05568.tar.bz2 ayatana-indicator-sound-cf5205162e421080c511428f54cb18d60cd05568.zip |
* New upstream release:
-New transport widget integrated
-New title widget integrated which allows the user
to launch familiar app directly from the menu
- UI tidied
- Each player that registers with the menu will be stored in the
cache file allowing the menu to show the application even if it has
not been launched.
33 files changed, 2566 insertions, 571 deletions
@@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.65 for indicator-sound 0.3.4. +# Generated by GNU Autoconf 2.65 for indicator-sound 0.3.5. # # Report bugs to <conor.curran@canonical.com>. # @@ -761,8 +761,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='indicator-sound' PACKAGE_TARNAME='indicator-sound' -PACKAGE_VERSION='0.3.4' -PACKAGE_STRING='indicator-sound 0.3.4' +PACKAGE_VERSION='0.3.5' +PACKAGE_STRING='indicator-sound 0.3.5' PACKAGE_BUGREPORT='conor.curran@canonical.com' PACKAGE_URL='' @@ -1555,7 +1555,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures indicator-sound 0.3.4 to adapt to many kinds of systems. +\`configure' configures indicator-sound 0.3.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1625,7 +1625,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of indicator-sound 0.3.4:";; + short | recursive ) echo "Configuration of indicator-sound 0.3.5:";; esac cat <<\_ACEOF @@ -1752,7 +1752,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -indicator-sound configure 0.3.4 +indicator-sound configure 0.3.5 generated by GNU Autoconf 2.65 Copyright (C) 2009 Free Software Foundation, Inc. @@ -2123,7 +2123,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by indicator-sound $as_me 0.3.4, which was +It was created by indicator-sound $as_me 0.3.5, which was generated by GNU Autoconf 2.65. Invocation command line was $ $0 $@ @@ -2936,7 +2936,7 @@ fi # Define the identity of the package. PACKAGE=indicator-sound - VERSION=0.3.4 + VERSION=0.3.5 cat >>confdefs.h <<_ACEOF @@ -14069,7 +14069,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by indicator-sound $as_me 0.3.4, which was +This file was extended by indicator-sound $as_me 0.3.5, which was generated by GNU Autoconf 2.65. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -14135,7 +14135,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -indicator-sound config.status 0.3.4 +indicator-sound config.status 0.3.5 configured by $0, generated by GNU Autoconf 2.65, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index b6c4fe3..5a6abc4 100644 --- a/configure.ac +++ b/configure.ac @@ -1,10 +1,10 @@ -AC_INIT(indicator-sound, 0.3.4, conor.curran@canonical.com) +AC_INIT(indicator-sound, 0.3.5, conor.curran@canonical.com) AC_PREREQ(2.53) AM_CONFIG_HEADER(config.h) -AM_INIT_AUTOMAKE(indicator-sound, 0.3.4) +AM_INIT_AUTOMAKE(indicator-sound, 0.3.5) AM_MAINTAINER_MODE diff --git a/data/Makefile.am b/data/Makefile.am index 0389576..9fa0c9b 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -1,4 +1,3 @@ - dbus_servicesdir = $(DBUSSERVICEDIR) service_in_files = indicator-sound.service.in dbus_services_DATA = $(service_in_files:.service.in=.service) diff --git a/debian/changelog b/debian/changelog index 0821b8c..aedb8ef 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,16 @@ +indicator-sound (0.3.5-0ubuntu1) UNRELEASED; urgency=low + + * New upstream release: + -New transport widget integrated + -New title widget integrated which allows the user + to launch familiar app directly from the menu + - UI tidied + - Each player that registers with the menu will be stored in the + cache file allowing the menu to show the application even if it has + not been launched. + + -- Sebastien Bacher <seb128@ubuntu.com> Thu, 08 Jul 2010 19:30:26 +0200 + indicator-sound (0.3.4-0ubuntu1) maverick; urgency=low * New upstream version: diff --git a/src/Makefile.am b/src/Makefile.am index b33107d..79ba7d2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,11 +13,15 @@ libsoundmenu_la_SOURCES = \ transport-widget.h \ metadata-widget.c \ metadata-widget.h \ + play-button.c \ + play-button.h \ indicator-sound.c \ + title-widget.c \ + title-widget.h \ dbus-shared-names.h \ sound-service-client.h -libsoundmenu_la_CFLAGS = $(APPLET_CFLAGS) -Wall -Werror -DG_LOG_DOMAIN=\"Indicator-Sound\" +libsoundmenu_la_CFLAGS = $(APPLET_CFLAGS) -Wall -DG_LOG_DOMAIN=\"Indicator-Sound\" libsoundmenu_la_LIBADD = $(APPLET_LIBS) libsoundmenu_la_LDFLAGS = -module -avoid-version @@ -54,6 +58,7 @@ music_bridge_VALASOURCES = \ music-player-bridge.vala \ transport-menu-item.vala \ metadata-menu-item.vala \ + title-menu-item.vala \ player-controller.vala \ mpris-controller-v2.vala \ mpris-controller.vala \ diff --git a/src/Makefile.in b/src/Makefile.in index e3ddfd3..6f0fd0c 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -74,7 +74,9 @@ am__DEPENDENCIES_1 = libsoundmenu_la_DEPENDENCIES = $(am__DEPENDENCIES_1) am_libsoundmenu_la_OBJECTS = libsoundmenu_la-transport-widget.lo \ libsoundmenu_la-metadata-widget.lo \ - libsoundmenu_la-indicator-sound.lo + libsoundmenu_la-play-button.lo \ + libsoundmenu_la-indicator-sound.lo \ + libsoundmenu_la-title-widget.lo libsoundmenu_la_OBJECTS = $(am_libsoundmenu_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) @@ -87,6 +89,7 @@ PROGRAMS = $(libexec_PROGRAMS) am__objects_1 = indicator_sound_service-music-player-bridge.$(OBJEXT) \ indicator_sound_service-transport-menu-item.$(OBJEXT) \ indicator_sound_service-metadata-menu-item.$(OBJEXT) \ + indicator_sound_service-title-menu-item.$(OBJEXT) \ indicator_sound_service-player-controller.$(OBJEXT) \ indicator_sound_service-mpris-controller-v2.$(OBJEXT) \ indicator_sound_service-mpris-controller.$(OBJEXT) \ @@ -307,11 +310,15 @@ libsoundmenu_la_SOURCES = \ transport-widget.h \ metadata-widget.c \ metadata-widget.h \ + play-button.c \ + play-button.h \ indicator-sound.c \ + title-widget.c \ + title-widget.h \ dbus-shared-names.h \ sound-service-client.h -libsoundmenu_la_CFLAGS = $(APPLET_CFLAGS) -Wall -Werror -DG_LOG_DOMAIN=\"Indicator-Sound\" +libsoundmenu_la_CFLAGS = $(APPLET_CFLAGS) -Wall -DG_LOG_DOMAIN=\"Indicator-Sound\" libsoundmenu_la_LIBADD = $(APPLET_LIBS) libsoundmenu_la_LDFLAGS = -module -avoid-version @@ -322,6 +329,7 @@ music_bridge_VALASOURCES = \ music-player-bridge.vala \ transport-menu-item.vala \ metadata-menu-item.vala \ + title-menu-item.vala \ player-controller.vala \ mpris-controller-v2.vala \ mpris-controller.vala \ @@ -522,9 +530,12 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indicator_sound_service-slider-menu-item.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indicator_sound_service-sound-service-dbus.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indicator_sound_service-sound-service.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indicator_sound_service-title-menu-item.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indicator_sound_service-transport-menu-item.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsoundmenu_la-indicator-sound.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsoundmenu_la-metadata-widget.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsoundmenu_la-play-button.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsoundmenu_la-title-widget.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsoundmenu_la-transport-widget.Plo@am__quote@ .c.o: @@ -567,6 +578,14 @@ libsoundmenu_la-metadata-widget.lo: metadata-widget.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsoundmenu_la_CFLAGS) $(CFLAGS) -c -o libsoundmenu_la-metadata-widget.lo `test -f 'metadata-widget.c' || echo '$(srcdir)/'`metadata-widget.c +libsoundmenu_la-play-button.lo: play-button.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsoundmenu_la_CFLAGS) $(CFLAGS) -MT libsoundmenu_la-play-button.lo -MD -MP -MF $(DEPDIR)/libsoundmenu_la-play-button.Tpo -c -o libsoundmenu_la-play-button.lo `test -f 'play-button.c' || echo '$(srcdir)/'`play-button.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsoundmenu_la-play-button.Tpo $(DEPDIR)/libsoundmenu_la-play-button.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='play-button.c' object='libsoundmenu_la-play-button.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsoundmenu_la_CFLAGS) $(CFLAGS) -c -o libsoundmenu_la-play-button.lo `test -f 'play-button.c' || echo '$(srcdir)/'`play-button.c + libsoundmenu_la-indicator-sound.lo: indicator-sound.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsoundmenu_la_CFLAGS) $(CFLAGS) -MT libsoundmenu_la-indicator-sound.lo -MD -MP -MF $(DEPDIR)/libsoundmenu_la-indicator-sound.Tpo -c -o libsoundmenu_la-indicator-sound.lo `test -f 'indicator-sound.c' || echo '$(srcdir)/'`indicator-sound.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsoundmenu_la-indicator-sound.Tpo $(DEPDIR)/libsoundmenu_la-indicator-sound.Plo @@ -575,6 +594,14 @@ libsoundmenu_la-indicator-sound.lo: indicator-sound.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsoundmenu_la_CFLAGS) $(CFLAGS) -c -o libsoundmenu_la-indicator-sound.lo `test -f 'indicator-sound.c' || echo '$(srcdir)/'`indicator-sound.c +libsoundmenu_la-title-widget.lo: title-widget.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsoundmenu_la_CFLAGS) $(CFLAGS) -MT libsoundmenu_la-title-widget.lo -MD -MP -MF $(DEPDIR)/libsoundmenu_la-title-widget.Tpo -c -o libsoundmenu_la-title-widget.lo `test -f 'title-widget.c' || echo '$(srcdir)/'`title-widget.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsoundmenu_la-title-widget.Tpo $(DEPDIR)/libsoundmenu_la-title-widget.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='title-widget.c' object='libsoundmenu_la-title-widget.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsoundmenu_la_CFLAGS) $(CFLAGS) -c -o libsoundmenu_la-title-widget.lo `test -f 'title-widget.c' || echo '$(srcdir)/'`title-widget.c + indicator_sound_service-sound-service.o: sound-service.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(indicator_sound_service_CFLAGS) $(CFLAGS) -MT indicator_sound_service-sound-service.o -MD -MP -MF $(DEPDIR)/indicator_sound_service-sound-service.Tpo -c -o indicator_sound_service-sound-service.o `test -f 'sound-service.c' || echo '$(srcdir)/'`sound-service.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/indicator_sound_service-sound-service.Tpo $(DEPDIR)/indicator_sound_service-sound-service.Po @@ -703,6 +730,22 @@ indicator_sound_service-metadata-menu-item.obj: metadata-menu-item.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(indicator_sound_service_CFLAGS) $(CFLAGS) -c -o indicator_sound_service-metadata-menu-item.obj `if test -f 'metadata-menu-item.c'; then $(CYGPATH_W) 'metadata-menu-item.c'; else $(CYGPATH_W) '$(srcdir)/metadata-menu-item.c'; fi` +indicator_sound_service-title-menu-item.o: title-menu-item.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(indicator_sound_service_CFLAGS) $(CFLAGS) -MT indicator_sound_service-title-menu-item.o -MD -MP -MF $(DEPDIR)/indicator_sound_service-title-menu-item.Tpo -c -o indicator_sound_service-title-menu-item.o `test -f 'title-menu-item.c' || echo '$(srcdir)/'`title-menu-item.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/indicator_sound_service-title-menu-item.Tpo $(DEPDIR)/indicator_sound_service-title-menu-item.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='title-menu-item.c' object='indicator_sound_service-title-menu-item.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(indicator_sound_service_CFLAGS) $(CFLAGS) -c -o indicator_sound_service-title-menu-item.o `test -f 'title-menu-item.c' || echo '$(srcdir)/'`title-menu-item.c + +indicator_sound_service-title-menu-item.obj: title-menu-item.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(indicator_sound_service_CFLAGS) $(CFLAGS) -MT indicator_sound_service-title-menu-item.obj -MD -MP -MF $(DEPDIR)/indicator_sound_service-title-menu-item.Tpo -c -o indicator_sound_service-title-menu-item.obj `if test -f 'title-menu-item.c'; then $(CYGPATH_W) 'title-menu-item.c'; else $(CYGPATH_W) '$(srcdir)/title-menu-item.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/indicator_sound_service-title-menu-item.Tpo $(DEPDIR)/indicator_sound_service-title-menu-item.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='title-menu-item.c' object='indicator_sound_service-title-menu-item.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(indicator_sound_service_CFLAGS) $(CFLAGS) -c -o indicator_sound_service-title-menu-item.obj `if test -f 'title-menu-item.c'; then $(CYGPATH_W) 'title-menu-item.c'; else $(CYGPATH_W) '$(srcdir)/title-menu-item.c'; fi` + indicator_sound_service-player-controller.o: player-controller.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(indicator_sound_service_CFLAGS) $(CFLAGS) -MT indicator_sound_service-player-controller.o -MD -MP -MF $(DEPDIR)/indicator_sound_service-player-controller.Tpo -c -o indicator_sound_service-player-controller.o `test -f 'player-controller.c' || echo '$(srcdir)/'`player-controller.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/indicator_sound_service-player-controller.Tpo $(DEPDIR)/indicator_sound_service-player-controller.Po diff --git a/src/common-defs.h b/src/common-defs.h index dca21cc..9c1fbab 100644 --- a/src/common-defs.h +++ b/src/common-defs.h @@ -34,3 +34,6 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #define DBUSMENU_METADATA_MENUITEM_TEXT_TITLE "x-canonical-metadata-text-title" #define DBUSMENU_METADATA_MENUITEM_TEXT_ALBUM "x-canonical-metadata-text-album" #define DBUSMENU_METADATA_MENUITEM_ARTURL "x-canonical-metadata-arturl" + +#define DBUSMENU_TITLE_MENUITEM_TYPE "x-canonical-sound-menu-player-title-menu-item" +#define DBUSMENU_TITLE_MENUITEM_TEXT_NAME "x-canonical-sound-menu-player-title-name" diff --git a/src/dbus-menu-manager.c b/src/dbus-menu-manager.c index d19bfbb..4cd4a6b 100644 --- a/src/dbus-menu-manager.c +++ b/src/dbus-menu-manager.c @@ -172,7 +172,9 @@ 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", &error)) { + if (!g_spawn_command_line_async("gnome-volume-control", &error) && + !g_spawn_command_line_async("xfce4-mixer", &error)) + { g_warning("Unable to show dialog: %s", error->message); g_error_free(error); } diff --git a/src/familiar-players-db.c b/src/familiar-players-db.c index 152571d..9933d4d 100644 --- a/src/familiar-players-db.c +++ b/src/familiar-players-db.c @@ -139,17 +139,17 @@ static gboolean familiar_players_db_create_key_file (FamiliarPlayersDB* self) { _tmp1_ = g_key_file_load_from_file (self->priv->key_file, self->priv->file_name, G_KEY_FILE_NONE, &_inner_error_); if (_inner_error_ != NULL) { if (_inner_error_->domain == G_FILE_ERROR) { - goto __catch2_g_file_error; + goto __catch3_g_file_error; } - goto __finally2; + goto __finally3; } if (_tmp1_ == TRUE) { result = TRUE; return result; } } - goto __finally2; - __catch2_g_file_error: + goto __finally3; + __catch3_g_file_error: { GError * e; e = _inner_error_; @@ -160,7 +160,7 @@ static gboolean familiar_players_db_create_key_file (FamiliarPlayersDB* self) { _g_error_free0 (e); } } - __finally2: + __finally3: if (_inner_error_ != NULL) { g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); g_clear_error (&_inner_error_); @@ -182,7 +182,7 @@ static gboolean familiar_players_db_check_for_keys (FamiliarPlayersDB* self) { _tmp0_ = g_key_file_has_key (self->priv->key_file, FAMILIAR_PLAYERS_DB_GROUP_NAME, FAMILIAR_PLAYERS_DB_KEY_NAME, &_inner_error_); if (_inner_error_ != NULL) { if (_inner_error_->domain == G_KEY_FILE_ERROR) { - goto __catch3_g_key_file_error; + goto __catch4_g_key_file_error; } g_critical ("file %s: line %d: unexpected error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); g_clear_error (&_inner_error_); @@ -193,8 +193,8 @@ static gboolean familiar_players_db_check_for_keys (FamiliarPlayersDB* self) { return result; } } - goto __finally3; - __catch3_g_key_file_error: + goto __finally4; + __catch4_g_key_file_error: { GError * e; e = _inner_error_; @@ -205,7 +205,7 @@ static gboolean familiar_players_db_check_for_keys (FamiliarPlayersDB* self) { return result; } } - __finally3: + __finally4: if (_inner_error_ != NULL) { g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); g_clear_error (&_inner_error_); @@ -232,9 +232,9 @@ static gboolean familiar_players_db_load_data_from_key_file (FamiliarPlayersDB* desktops = (_tmp1_ = g_key_file_get_string_list (self->priv->key_file, FAMILIAR_PLAYERS_DB_GROUP_NAME, FAMILIAR_PLAYERS_DB_KEY_NAME, &_tmp0_, &_inner_error_), desktops_length1 = _tmp0_, _desktops_size_ = desktops_length1, _tmp1_); if (_inner_error_ != NULL) { if (_inner_error_->domain == G_FILE_ERROR) { - goto __catch4_g_file_error; + goto __catch5_g_file_error; } - goto __finally4; + goto __finally5; } { char** s_collection; @@ -255,8 +255,8 @@ static gboolean familiar_players_db_load_data_from_key_file (FamiliarPlayersDB* desktops = (_vala_array_free (desktops, desktops_length1, (GDestroyNotify) g_free), NULL); return result; } - goto __finally4; - __catch4_g_file_error: + goto __finally5; + __catch5_g_file_error: { GError * _error_; _error_ = _inner_error_; @@ -268,7 +268,7 @@ static gboolean familiar_players_db_load_data_from_key_file (FamiliarPlayersDB* return result; } } - __finally4: + __finally5: { g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); g_clear_error (&_inner_error_); @@ -324,8 +324,8 @@ static gboolean familiar_players_db_write_db (FamiliarPlayersDB* self) { char* _tmp4_; data = (_tmp4_ = g_key_file_to_data (keyfile, &data_length, NULL), _g_free0 (data), _tmp4_); } - goto __finally5; - __catch5_g_error: + goto __finally6; + __catch6_g_error: { GError * e; e = _inner_error_; @@ -340,7 +340,7 @@ static gboolean familiar_players_db_write_db (FamiliarPlayersDB* self) { return result; } } - __finally5: + __finally6: if (_inner_error_ != NULL) { _g_key_file_free0 (keyfile); desktops = (_vala_array_free (desktops, desktops_length1, (GDestroyNotify) g_free), NULL); @@ -362,7 +362,7 @@ static gboolean familiar_players_db_write_db (FamiliarPlayersDB* self) { _tmp5_ = g_file_set_contents (self->priv->file_name, data, (gssize) data_length, &_inner_error_); if (_inner_error_ != NULL) { if (_inner_error_->domain == G_FILE_ERROR) { - goto __catch6_g_file_error; + goto __catch7_g_file_error; } _g_key_file_free0 (keyfile); desktops = (_vala_array_free (desktops, desktops_length1, (GDestroyNotify) g_free), NULL); @@ -375,8 +375,8 @@ static gboolean familiar_players_db_write_db (FamiliarPlayersDB* self) { g_warning ("familiar-players-db.vala:123: Unable to write out file '%s'", self->priv->file_name); } } - goto __finally6; - __catch6_g_file_error: + goto __finally7; + __catch7_g_file_error: { GError * err; err = _inner_error_; @@ -386,7 +386,7 @@ static gboolean familiar_players_db_write_db (FamiliarPlayersDB* self) { _g_error_free0 (err); } } - __finally6: + __finally7: if (_inner_error_ != NULL) { _g_key_file_free0 (keyfile); desktops = (_vala_array_free (desktops, desktops_length1, (GDestroyNotify) g_free), NULL); @@ -426,11 +426,30 @@ void familiar_players_db_insert (FamiliarPlayersDB* self, const char* desktop) { } +static char* bool_to_string (gboolean self) { + char* result = NULL; + if (self) { + result = g_strdup ("true"); + return result; + } else { + result = g_strdup ("false"); + return result; + } +} + + gboolean familiar_players_db_already_familiar (FamiliarPlayersDB* self, const char* desktop) { gboolean result = FALSE; + char* _tmp1_; + GeeSet* _tmp0_; + GeeSet* _tmp2_; + gboolean _tmp3_; g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (desktop != NULL, FALSE); - result = GPOINTER_TO_INT (gee_abstract_map_get ((GeeAbstractMap*) self->priv->players_DB, desktop)); + g_debug ("familiar-players-db.vala:146: playerDB->already_familiar - result %s", _tmp1_ = bool_to_string (gee_collection_contains ((GeeCollection*) (_tmp0_ = gee_map_get_keys ((GeeMap*) self->priv->players_DB)), desktop))); + _g_free0 (_tmp1_); + _g_object_unref0 (_tmp0_); + result = (_tmp3_ = gee_collection_contains ((GeeCollection*) (_tmp2_ = gee_map_get_keys ((GeeMap*) self->priv->players_DB)), desktop), _g_object_unref0 (_tmp2_), _tmp3_); return result; } diff --git a/src/familiar-players-db.vala b/src/familiar-players-db.vala index 88bc01f..b83caa3 100644 --- a/src/familiar-players-db.vala +++ b/src/familiar-players-db.vala @@ -143,7 +143,8 @@ public class FamiliarPlayersDB : GLib.Object public bool already_familiar(string desktop) { - return this.players_DB.get(desktop); + debug("playerDB->already_familiar - result %s", this.players_DB.keys.contains(desktop).to_string()); + return this.players_DB.keys.contains(desktop); } public Gee.Set<string> records() diff --git a/src/indicator-sound.c b/src/indicator-sound.c index 3f0d2d3..8be97b4 100644 --- a/src/indicator-sound.c +++ b/src/indicator-sound.c @@ -40,6 +40,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include "indicator-sound.h" #include "transport-widget.h" #include "metadata-widget.h" +#include "title-widget.h" #include "dbus-shared-names.h" #include "sound-service-client.h" #include "common-defs.h" @@ -96,6 +97,7 @@ static void style_changed_cb(GtkWidget *widget, gpointer user_data); //player widgets related static gboolean new_transport_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client); static gboolean new_metadata_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client); +static gboolean new_title_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client); // DBUS communication static DBusGProxy *sound_dbus_proxy = NULL; @@ -243,7 +245,7 @@ get_menu (IndicatorObject * io) dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_SLIDER_MENUITEM_TYPE, new_slider_item); 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_TITLE_MENUITEM_TYPE, new_title_widget); // register Key-press listening on the menu widget as the slider does not allow this. g_signal_connect(menu, "key-press-event", G_CALLBACK(key_press_cb), NULL); return GTK_MENU(menu); @@ -326,10 +328,9 @@ new_transport_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbus bar = transport_widget_new(newitem); 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); - gtk_widget_show_all(bar); - return TRUE; } @@ -346,16 +347,31 @@ new_metadata_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusm metadata = metadata_widget_new (newitem); 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); - gtk_widget_show_all(metadata); - return TRUE; } -//const gchar* path = dbusmenu_menuitem_property_get(new_item, DBUSMENU_METADATA_MENUITEM_IMAGE_PATH); +static gboolean +new_title_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client) +{ + g_debug("indicator-sound: new_title_widget"); + + GtkWidget* title = NULL; + + g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); + g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); + + title = title_widget_new (newitem); + GtkMenuItem *menu_title_widget = GTK_MENU_ITEM(title); + + dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, menu_title_widget, parent); -//g_debug("New transport bar path = %s", path); + gtk_widget_show_all(title); + + return TRUE; +} static void diff --git a/src/metadata-menu-item.c b/src/metadata-menu-item.c index f33e848..518bad8 100644 --- a/src/metadata-menu-item.c +++ b/src/metadata-menu-item.c @@ -43,16 +43,6 @@ typedef struct _PlayerItem PlayerItem; typedef struct _PlayerItemClass PlayerItemClass; typedef struct _PlayerItemPrivate PlayerItemPrivate; -#define TYPE_MPRIS_CONTROLLER (mpris_controller_get_type ()) -#define MPRIS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_MPRIS_CONTROLLER, MprisController)) -#define MPRIS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_MPRIS_CONTROLLER, MprisControllerClass)) -#define IS_MPRIS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_MPRIS_CONTROLLER)) -#define IS_MPRIS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_MPRIS_CONTROLLER)) -#define MPRIS_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_MPRIS_CONTROLLER, MprisControllerClass)) - -typedef struct _MprisController MprisController; -typedef struct _MprisControllerClass MprisControllerClass; - #define TYPE_METADATA_MENUITEM (metadata_menuitem_get_type ()) #define METADATA_MENUITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_METADATA_MENUITEM, MetadataMenuitem)) #define METADATA_MENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_METADATA_MENUITEM, MetadataMenuitemClass)) @@ -64,17 +54,14 @@ typedef struct _MetadataMenuitem MetadataMenuitem; typedef struct _MetadataMenuitemClass MetadataMenuitemClass; typedef struct _MetadataMenuitemPrivate MetadataMenuitemPrivate; #define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL))) -#define _g_free0(var) (var = (g_free (var), NULL)) struct _PlayerItem { DbusmenuMenuitem parent_instance; PlayerItemPrivate * priv; - MprisController* mpris_adaptor; }; struct _PlayerItemClass { DbusmenuMenuitemClass parent_class; - void (*check_layout) (PlayerItem* self); }; struct _MetadataMenuitem { @@ -90,26 +77,21 @@ struct _MetadataMenuitemClass { static gpointer metadata_menuitem_parent_class = NULL; GType player_item_get_type (void); -GType mpris_controller_get_type (void); GType metadata_menuitem_get_type (void); enum { METADATA_MENUITEM_DUMMY_PROPERTY }; -PlayerItem* player_item_new (void); -PlayerItem* player_item_construct (GType object_type); MetadataMenuitem* metadata_menuitem_new (void); MetadataMenuitem* metadata_menuitem_construct (GType object_type); GeeHashSet* metadata_menuitem_attributes_format (void); gboolean metadata_menuitem_populated (MetadataMenuitem* self); -static void metadata_menuitem_real_check_layout (PlayerItem* base); static int _vala_strcmp0 (const char * str1, const char * str2); MetadataMenuitem* metadata_menuitem_construct (GType object_type) { MetadataMenuitem * self; - self = (MetadataMenuitem*) player_item_construct (object_type); - dbusmenu_menuitem_property_set ((DbusmenuMenuitem*) self, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_METADATA_MENUITEM_TYPE); + self = (MetadataMenuitem*) g_object_new (object_type, "item-type", DBUSMENU_METADATA_MENUITEM_TYPE, NULL); return self; } @@ -132,28 +114,6 @@ GeeHashSet* metadata_menuitem_attributes_format (void) { } -static char* bool_to_string (gboolean self) { - char* result = NULL; - if (self) { - result = g_strdup ("true"); - return result; - } else { - result = g_strdup ("false"); - return result; - } -} - - -static void metadata_menuitem_real_check_layout (PlayerItem* base) { - MetadataMenuitem * self; - char* _tmp0_; - self = (MetadataMenuitem*) base; - dbusmenu_menuitem_property_set_bool ((DbusmenuMenuitem*) self, DBUSMENU_MENUITEM_PROP_VISIBLE, metadata_menuitem_populated (self)); - g_debug ("metadata-menu-item.vala:43: check layout for the metadata = %s", _tmp0_ = bool_to_string (metadata_menuitem_populated (self))); - _g_free0 (_tmp0_); -} - - gboolean metadata_menuitem_populated (MetadataMenuitem* self) { gboolean result = FALSE; gboolean _tmp0_ = FALSE; @@ -170,7 +130,6 @@ gboolean metadata_menuitem_populated (MetadataMenuitem* self) { static void metadata_menuitem_class_init (MetadataMenuitemClass * klass) { metadata_menuitem_parent_class = g_type_class_peek_parent (klass); - PLAYER_ITEM_CLASS (klass)->check_layout = metadata_menuitem_real_check_layout; } diff --git a/src/metadata-menu-item.vala b/src/metadata-menu-item.vala index 541fbf4..cfcb3bc 100644 --- a/src/metadata-menu-item.vala +++ b/src/metadata-menu-item.vala @@ -25,7 +25,7 @@ public class MetadataMenuitem : PlayerItem { public MetadataMenuitem() { - this.property_set(MENUITEM_PROP_TYPE, MENUITEM_TYPE); + Object(item_type: MENUITEM_TYPE); } public static HashSet<string> attributes_format() @@ -37,11 +37,6 @@ public class MetadataMenuitem : PlayerItem attrs.add(MENUITEM_ARTURL); return attrs; } - - public override void check_layout(){ - this.property_set_bool(MENUITEM_PROP_VISIBLE, this.populated()); - debug("check layout for the metadata = %s", this.populated().to_string()); - } public bool populated() { diff --git a/src/metadata-widget.c b/src/metadata-widget.c index ce3bcd1..8235725 100644 --- a/src/metadata-widget.c +++ b/src/metadata-widget.c @@ -47,6 +47,8 @@ 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 gboolean metadata_widget_expose_event(GtkWidget* widget, GdkEventExpose* event); + // keyevent consumers static gboolean metadata_widget_button_press_event (GtkWidget *menuitem, GdkEventButton *event); @@ -74,7 +76,7 @@ metadata_widget_class_init (MetadataWidgetClass *klass) widget_class->button_press_event = metadata_widget_button_press_event; widget_class->button_release_event = metadata_widget_button_release_event; - + widget_class->expose_event = metadata_widget_expose_event; g_type_class_add_private (klass, sizeof (MetadataWidgetPrivate)); gobject_class->dispose = metadata_widget_dispose; @@ -110,8 +112,8 @@ metadata_widget_init (MetadataWidget *self) DBUSMENU_METADATA_MENUITEM_TEXT_ARTIST)); gtk_misc_set_alignment(GTK_MISC(artist), (gfloat)0, (gfloat)0); - gtk_label_set_width_chars(GTK_LABEL(artist), 20); - gtk_label_set_ellipsize(GTK_LABEL(artist), PANGO_ELLIPSIZE_END); + gtk_label_set_width_chars(GTK_LABEL(artist), 15); + gtk_label_set_ellipsize(GTK_LABEL(artist), PANGO_ELLIPSIZE_MIDDLE); priv->artist_label = artist; // Style it up. style_artist_text(self); @@ -121,8 +123,8 @@ metadata_widget_init (MetadataWidget *self) piece = gtk_label_new(dbusmenu_menuitem_property_get(twin_item, DBUSMENU_METADATA_MENUITEM_TEXT_TITLE)); gtk_misc_set_alignment(GTK_MISC(piece), (gfloat)0, (gfloat)0); - gtk_label_set_width_chars(GTK_LABEL(piece), 16); - gtk_label_set_ellipsize(GTK_LABEL(piece), PANGO_ELLIPSIZE_END); + gtk_label_set_width_chars(GTK_LABEL(piece), 12); + gtk_label_set_ellipsize(GTK_LABEL(piece), PANGO_ELLIPSIZE_MIDDLE); priv->piece_label = piece; // Style it up. style_title_text(self); @@ -132,8 +134,8 @@ metadata_widget_init (MetadataWidget *self) container = gtk_label_new(dbusmenu_menuitem_property_get(twin_item, DBUSMENU_METADATA_MENUITEM_TEXT_ALBUM)); gtk_misc_set_alignment(GTK_MISC(container), (gfloat)0, (gfloat)0); - gtk_label_set_width_chars(GTK_LABEL(container), 20); - gtk_label_set_ellipsize(GTK_LABEL(container), PANGO_ELLIPSIZE_END); + gtk_label_set_width_chars(GTK_LABEL(container), 15); + gtk_label_set_ellipsize(GTK_LABEL(container), PANGO_ELLIPSIZE_MIDDLE); priv->container_label = container; // Style it up. style_album_text(self); @@ -152,6 +154,15 @@ metadata_widget_init (MetadataWidget *self) } +static gboolean +metadata_widget_expose_event(GtkWidget* widget, GdkEventExpose* event) +{ + MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(widget); + + gtk_container_propagate_expose(GTK_CONTAINER(widget), priv->hbox, event); + return TRUE; +} + static void metadata_widget_dispose (GObject *object) { diff --git a/src/mpris-controller.c b/src/mpris-controller.c index a9a26b2..7ef0aa3 100644 --- a/src/mpris-controller.c +++ b/src/mpris-controller.c @@ -84,6 +84,8 @@ typedef struct _TransportMenuitem TransportMenuitem; typedef struct _TransportMenuitemClass TransportMenuitemClass; #define _g_hash_table_unref0(var) ((var == NULL) ? NULL : (var = (g_hash_table_unref (var), NULL))) +#define TRANSPORT_MENUITEM_TYPE_ACTION (transport_menuitem_action_get_type ()) + struct _MprisController { GObject parent_instance; MprisControllerPrivate * priv; @@ -101,21 +103,26 @@ struct _MprisControllerPrivate { struct _MprisControllerstatus { gint32 playback; - gint32 shuffle; - gint32 repeat; - gint32 endless; }; struct _PlayerController { GObject parent_instance; PlayerControllerPrivate * priv; + gint current_state; GeeArrayList* custom_items; + MprisController* mpris_adaptor; }; struct _PlayerControllerClass { GObjectClass parent_class; }; +typedef enum { + TRANSPORT_MENUITEM_ACTION_PREVIOUS, + TRANSPORT_MENUITEM_ACTION_PLAY_PAUSE, + TRANSPORT_MENUITEM_ACTION_NEXT +} TransportMenuitemaction; + static gpointer mpris_controller_parent_class = NULL; @@ -146,9 +153,14 @@ GeeHashSet* metadata_menuitem_attributes_format (void); MprisController* mpris_controller_new (const char* name, PlayerController* controller, const char* mpris_interface); MprisController* mpris_controller_construct (GType object_type, const char* name, PlayerController* controller, const char* mpris_interface); void player_item_reset (PlayerItem* self, GeeHashSet* attrs); -static void _dynamic_Play2 (DBusGProxy* self, GError** error); -static void _dynamic_Pause3 (DBusGProxy* self, GError** error); -void mpris_controller_toggle_playback (MprisController* self, gboolean state); +GType transport_menuitem_action_get_type (void); +static void _dynamic_GetStatus2 (DBusGProxy* self, MprisControllerstatus* result, GError** error); +static void _dynamic_Play3 (DBusGProxy* self, GError** error); +static void _dynamic_Pause4 (DBusGProxy* self, GError** error); +static void _dynamic_previous5 (DBusGProxy* self, GError** error); +static void _dynamic_next6 (DBusGProxy* self, GError** error); +void mpris_controller_transport_event (MprisController* self, TransportMenuitemaction command); +gboolean mpris_controller_connected (MprisController* self); static GValue* _g_value_dup (GValue* self); GeeHashSet* transport_menuitem_attributes_format (void); static void mpris_controller_finalize (GObject* obj); @@ -179,22 +191,19 @@ static void _mpris_controller_onStatusChange_dynamic_StatusChange2_ (DBusGProxy* void _dynamic_StatusChange3_connect (gpointer obj, const char * signal_name, GCallback handler, gpointer data) { - dbus_g_object_register_marshaller (g_cclosure_user_marshal_VOID__BOXED, G_TYPE_NONE, dbus_g_type_get_struct ("GValueArray", G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INVALID), G_TYPE_INVALID); - dbus_g_proxy_add_signal (obj, "StatusChange", dbus_g_type_get_struct ("GValueArray", G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INVALID), G_TYPE_INVALID); + dbus_g_object_register_marshaller (g_cclosure_user_marshal_VOID__BOXED, G_TYPE_NONE, dbus_g_type_get_struct ("GValueArray", G_TYPE_INT, G_TYPE_INVALID), G_TYPE_INVALID); + dbus_g_proxy_add_signal (obj, "StatusChange", dbus_g_type_get_struct ("GValueArray", G_TYPE_INT, G_TYPE_INVALID), G_TYPE_INVALID); dbus_g_proxy_connect_signal (obj, signal_name, handler, data, NULL); } static void _dynamic_GetStatus0 (DBusGProxy* self, MprisControllerstatus* result, GError** error) { GValueArray* dbus_result; - dbus_g_proxy_call (self, "GetStatus", error, G_TYPE_INVALID, dbus_g_type_get_struct ("GValueArray", G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INVALID), &dbus_result, G_TYPE_INVALID); + dbus_g_proxy_call (self, "GetStatus", error, G_TYPE_INVALID, dbus_g_type_get_struct ("GValueArray", G_TYPE_INT, G_TYPE_INVALID), &dbus_result, G_TYPE_INVALID); if (*error) { return; } result->playback = g_value_get_int (&dbus_result->values[0]); - result->shuffle = g_value_get_int (&dbus_result->values[1]); - result->repeat = g_value_get_int (&dbus_result->values[2]); - result->endless = g_value_get_int (&dbus_result->values[3]); } @@ -234,12 +243,12 @@ MprisController* mpris_controller_construct (GType object_type, const char* name DBusGConnection* _tmp1_; _tmp0_ = dbus_g_bus_get (DBUS_BUS_SESSION, &_inner_error_); if (_inner_error_ != NULL) { - goto __catch1_g_error; + goto __catch2_g_error; } self->priv->connection = (_tmp1_ = _tmp0_, _dbus_g_connection_unref0 (self->priv->connection), _tmp1_); } - goto __finally1; - __catch1_g_error: + goto __finally2; + __catch2_g_error: { GError * e; e = _inner_error_; @@ -249,7 +258,7 @@ MprisController* mpris_controller_construct (GType object_type, const char* name _g_error_free0 (e); } } - __finally1: + __finally2: if (_inner_error_ != NULL) { g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); g_clear_error (&_inner_error_); @@ -308,7 +317,17 @@ static void mpris_controller_onTrackChange (MprisController* self, DBusGProxy* m } -static void _dynamic_Play2 (DBusGProxy* self, GError** error) { +static void _dynamic_GetStatus2 (DBusGProxy* self, MprisControllerstatus* result, GError** error) { + GValueArray* dbus_result; + dbus_g_proxy_call (self, "GetStatus", error, G_TYPE_INVALID, dbus_g_type_get_struct ("GValueArray", G_TYPE_INT, G_TYPE_INVALID), &dbus_result, G_TYPE_INVALID); + if (*error) { + return; + } + result->playback = g_value_get_int (&dbus_result->values[0]); +} + + +static void _dynamic_Play3 (DBusGProxy* self, GError** error) { dbus_g_proxy_call (self, "Play", error, G_TYPE_INVALID, G_TYPE_INVALID); if (*error) { return; @@ -316,7 +335,7 @@ static void _dynamic_Play2 (DBusGProxy* self, GError** error) { } -static void _dynamic_Pause3 (DBusGProxy* self, GError** error) { +static void _dynamic_Pause4 (DBusGProxy* self, GError** error) { dbus_g_proxy_call (self, "Pause", error, G_TYPE_INVALID, G_TYPE_INVALID); if (*error) { return; @@ -324,30 +343,89 @@ static void _dynamic_Pause3 (DBusGProxy* self, GError** error) { } -void mpris_controller_toggle_playback (MprisController* self, gboolean state) { +static void _dynamic_previous5 (DBusGProxy* self, GError** error) { + dbus_g_proxy_call (self, "Previous", error, G_TYPE_INVALID, G_TYPE_INVALID); + if (*error) { + return; + } +} + + +static void _dynamic_next6 (DBusGProxy* self, GError** error) { + dbus_g_proxy_call (self, "Next", error, G_TYPE_INVALID, G_TYPE_INVALID); + if (*error) { + return; + } +} + + +void mpris_controller_transport_event (MprisController* self, TransportMenuitemaction command) { GError * _inner_error_; g_return_if_fail (self != NULL); _inner_error_ = NULL; - if (state == TRUE) { - g_debug ("mpris-controller.vala:71: about to play"); - _dynamic_Play2 (self->mpris_player, &_inner_error_); + g_debug ("mpris-controller.vala:70: transport_event input = %i", (gint) command); + if (command == TRANSPORT_MENUITEM_ACTION_PLAY_PAUSE) { + MprisControllerstatus _tmp0_ = {0}; + MprisControllerstatus st; + gboolean play_state; + gboolean new_play_state; + st = (_dynamic_GetStatus2 (self->mpris_player, &_tmp0_, &_inner_error_), _tmp0_); if (_inner_error_ != NULL) { g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); g_clear_error (&_inner_error_); return; } + play_state = st.playback == 1; + g_debug ("mpris-controller.vala:74: toggle_playback - initial play state %i", (gint) play_state); + new_play_state = !play_state; + g_debug ("mpris-controller.vala:76: toggle_playback - new play state %i", (gint) new_play_state); + if (new_play_state == TRUE) { + g_debug ("mpris-controller.vala:78: about to play"); + _dynamic_Play3 (self->mpris_player, &_inner_error_); + if (_inner_error_ != NULL) { + g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); + g_clear_error (&_inner_error_); + return; + } + } else { + g_debug ("mpris-controller.vala:82: about to pause"); + _dynamic_Pause4 (self->mpris_player, &_inner_error_); + if (_inner_error_ != NULL) { + g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); + g_clear_error (&_inner_error_); + return; + } + } } else { - g_debug ("mpris-controller.vala:75: about to pause"); - _dynamic_Pause3 (self->mpris_player, &_inner_error_); - if (_inner_error_ != NULL) { - g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); - g_clear_error (&_inner_error_); - return; + if (command == TRANSPORT_MENUITEM_ACTION_PREVIOUS) { + _dynamic_previous5 (self->mpris_player, &_inner_error_); + if (_inner_error_ != NULL) { + g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); + g_clear_error (&_inner_error_); + return; + } + } else { + if (command == TRANSPORT_MENUITEM_ACTION_NEXT) { + _dynamic_next6 (self->mpris_player, &_inner_error_); + if (_inner_error_ != NULL) { + g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); + g_clear_error (&_inner_error_); + return; + } + } } } } +gboolean mpris_controller_connected (MprisController* self) { + gboolean result = FALSE; + g_return_val_if_fail (self != NULL, FALSE); + result = self->mpris_player != NULL; + return result; +} + + static GValue* _g_value_dup (GValue* self) { return g_boxed_copy (G_TYPE_VALUE, self); } @@ -368,11 +446,11 @@ static void mpris_controller_onStatusChange (MprisController* self, DBusGProxy* PlayerItem* _tmp0_; g_return_if_fail (self != NULL); g_return_if_fail (mpris_client != NULL); - g_debug ("mpris-controller.vala:82: onStatusChange - signal received"); + g_debug ("mpris-controller.vala:101: onStatusChange - signal received"); status = st; ar = (GValueArray*) status; play_state = g_value_get_int (g_value_array_get_nth (ar, (guint) 0)); - g_debug ("mpris-controller.vala:86: onStatusChange - play state %i", play_state); + g_debug ("mpris-controller.vala:105: onStatusChange - play state %i", play_state); ht = g_hash_table_new (g_str_hash, g_str_equal); g_value_init (&v, G_TYPE_INT); g_value_set_int (&v, play_state); diff --git a/src/mpris-controller.vala b/src/mpris-controller.vala index beaf02c..2194d44 100644 --- a/src/mpris-controller.vala +++ b/src/mpris-controller.vala @@ -27,9 +27,9 @@ public class MprisController : GLib.Object private PlayerController controller; struct status { public int32 playback; - public int32 shuffle; - public int32 repeat; - public int32 endless; + //public int32 shuffle; // Not used just yet + //public int32 repeat; + //public int32 endless; } public MprisController(string name, PlayerController controller, string mpris_interface="org.freedesktop.MediaPlayer"){ @@ -65,16 +65,35 @@ public class MprisController : GLib.Object * TRUE => Playing * FALSE => Paused **/ - public void toggle_playback(bool state) + public void transport_event(TransportMenuitem.action command) { - if(state == true){ - debug("about to play"); - this.mpris_player.Play(); + debug("transport_event input = %i", (int)command); + if(command == TransportMenuitem.action.PLAY_PAUSE){ + status st = this.mpris_player.GetStatus(); + bool play_state = st.playback == 1; + debug("toggle_playback - initial play state %i", (int)play_state); + bool new_play_state = !play_state; + debug("toggle_playback - new play state %i", (int)new_play_state); + if(new_play_state == true){ + debug("about to play"); + this.mpris_player.Play(); + } + else{ + debug("about to pause"); + this.mpris_player.Pause(); + } } - else{ - debug("about to pause"); - this.mpris_player.Pause(); - } + else if(command == TransportMenuitem.action.PREVIOUS){ + this.mpris_player.previous(); + } + else if(command == TransportMenuitem.action.NEXT){ + this.mpris_player.next(); + } + } + + public bool connected() + { + return (this.mpris_player != null); } private void onStatusChange(dynamic DBus.Object mpris_client, status st) diff --git a/src/music-player-bridge.c b/src/music-player-bridge.c index 250f761..9fd386a 100644 --- a/src/music-player-bridge.c +++ b/src/music-player-bridge.c @@ -70,6 +70,8 @@ typedef struct _FamiliarPlayersDB FamiliarPlayersDB; typedef struct _FamiliarPlayersDBClass FamiliarPlayersDBClass; #define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL))) #define _g_free0(var) (var = (g_free (var), NULL)) + +#define PLAYER_CONTROLLER_TYPE_STATE (player_controller_state_get_type ()) #define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL))) struct _MusicPlayerBridge { @@ -88,6 +90,14 @@ struct _MusicPlayerBridgePrivate { FamiliarPlayersDB* playersDB; }; +typedef enum { + PLAYER_CONTROLLER_STATE_OFFLINE, + PLAYER_CONTROLLER_STATE_INSTANTIATING, + PLAYER_CONTROLLER_STATE_READY, + PLAYER_CONTROLLER_STATE_CONNECTED, + PLAYER_CONTROLLER_STATE_DISCONNECTED +} PlayerControllerstate; + static gpointer music_player_bridge_parent_class = NULL; @@ -115,13 +125,19 @@ static void _music_player_bridge_on_server_count_changed_indicate_listener_serve MusicPlayerBridge* music_player_bridge_new (void); MusicPlayerBridge* music_player_bridge_construct (GType object_type); GeeSet* familiar_players_db_records (FamiliarPlayersDB* self); -PlayerController* player_controller_new (DbusmenuMenuitem* root, const char* client_name, gboolean active); -PlayerController* player_controller_construct (GType object_type, DbusmenuMenuitem* root, const char* client_name, gboolean active); +GType player_controller_state_get_type (void); +PlayerController* player_controller_new (DbusmenuMenuitem* root, const char* client_name, PlayerControllerstate initial_state); +PlayerController* player_controller_construct (GType object_type, DbusmenuMenuitem* root, const char* client_name, PlayerControllerstate initial_state); static void music_player_bridge_try_to_add_inactive_familiar_clients (MusicPlayerBridge* self); static gboolean music_player_bridge_server_is_not_of_interest (MusicPlayerBridge* self, const char* type); +void player_controller_update_state (PlayerController* self, PlayerControllerstate new_state); +void player_controller_activate (PlayerController* self); +GAppInfo* player_controller_get_app_info (PlayerController* self); static void music_player_bridge_desktop_info_callback (MusicPlayerBridge* self, IndicateListenerServer* server, char* path, void* data); void player_controller_vanish (PlayerController* self); +gboolean familiar_players_db_already_familiar (FamiliarPlayersDB* self, const char* desktop); void familiar_players_db_insert (FamiliarPlayersDB* self, const char* desktop); +GAppInfo* music_player_bridge_create_app_info (const char* path); void music_player_bridge_set_root_menu_item (MusicPlayerBridge* self, DbusmenuMenuitem* menu); static void music_player_bridge_finalize (GObject* obj); static void _vala_array_destroy (gpointer array, gint array_length, GDestroyNotify destroy_func); @@ -184,6 +200,22 @@ MusicPlayerBridge* music_player_bridge_new (void) { } +static gpointer _g_object_ref0 (gpointer self) { + return self ? g_object_ref (self) : NULL; +} + + +static char* string_strip (const char* self) { + char* result = NULL; + char* _result_; + g_return_val_if_fail (self != NULL, NULL); + _result_ = g_strdup (self); + g_strstrip (_result_); + result = _result_; + return result; +} + + static void music_player_bridge_try_to_add_inactive_familiar_clients (MusicPlayerBridge* self) { GError * _inner_error_; gint count; @@ -202,34 +234,43 @@ static void music_player_bridge_try_to_add_inactive_familiar_clients (MusicPlaye } app = (char*) gee_iterator_get (_app_it); if (count == 0) { - char** _tmp3_; - gint _bits_size_; - gint bits_length1; - char** _tmp2_; - char** bits; - g_debug ("music-player-bridge.vala:51: we have found %s", app); - bits = (_tmp3_ = _tmp2_ = g_strsplit (app, "/", 0), bits_length1 = _vala_array_length (_tmp2_), _bits_size_ = bits_length1, _tmp3_); + if (app == NULL) { + g_warning ("music-player-bridge.vala:52: App string in keyfile is null therefore m" \ +"oving on to next player"); + _g_free0 (app); + continue; + } { - gint _tmp5__length1; - char** _tmp5_; - char** _tmp4_; - char* _tmp6_; - char* app_name; - PlayerController* ctrl; GDesktopAppInfo* info; - char* desc; - app_name = (_tmp6_ = g_strdup ((_tmp5_ = _tmp4_ = g_strsplit (bits[bits_length1 - 1], ".", 0), _tmp5__length1 = _vala_array_length (_tmp4_), _tmp5_)[0]), _tmp5_ = (_vala_array_free (_tmp5_, _tmp5__length1, (GDestroyNotify) g_free), NULL), _tmp6_); - g_debug ("music-player-bridge.vala:56: we have found %s", app_name); - ctrl = player_controller_new (self->priv->root_menu, app_name, FALSE); - gee_abstract_map_set ((GeeAbstractMap*) self->priv->registered_clients, app_name, ctrl); - info = g_desktop_app_info_new_from_filename (app_name); - desc = g_strdup (g_app_info_get_display_name ((GAppInfo*) info)); - g_debug ("music-player-bridge.vala:63: description from app %s", desc); + GDesktopAppInfo* _tmp2_; + GAppInfo* app_info; + PlayerController* ctrl; + char* _tmp4_; + char* _tmp3_; + char* _tmp6_; + char* _tmp5_; + info = g_desktop_app_info_new_from_filename (app); + if (info == NULL) { + g_warning ("music-player-bridge.vala:58: Could not create a desktopappinfo instanc" \ +"e from app: %s", app); + _g_object_unref0 (info); + _g_free0 (app); + continue; + } + app_info = _g_object_ref0 ((_tmp2_ = info, G_IS_APP_INFO (_tmp2_) ? ((GAppInfo*) _tmp2_) : NULL)); + ctrl = player_controller_new (self->priv->root_menu, g_app_info_get_name (app_info), PLAYER_CONTROLLER_STATE_OFFLINE); + g_object_set ((GObject*) ctrl, "app_info", app_info, NULL); + gee_abstract_map_set ((GeeAbstractMap*) self->priv->registered_clients, _tmp4_ = string_strip (_tmp3_ = g_utf8_strdown (g_app_info_get_name (app_info), -1)), ctrl); + _g_free0 (_tmp4_); + _g_free0 (_tmp3_); + g_debug ("music-player-bridge.vala:67: Created a player controller for %s which " \ +"was found in the cache file", _tmp6_ = string_strip (_tmp5_ = g_utf8_strdown (g_app_info_get_name (app_info), -1))); + _g_free0 (_tmp6_); + _g_free0 (_tmp5_); count = count + 1; - _g_free0 (app_name); - _g_object_unref0 (ctrl); _g_object_unref0 (info); - _g_free0 (desc); + _g_object_unref0 (app_info); + _g_object_unref0 (ctrl); } goto __finally0; __catch0_g_error: @@ -238,21 +279,19 @@ static void music_player_bridge_try_to_add_inactive_familiar_clients (MusicPlaye er = _inner_error_; _inner_error_ = NULL; { - g_warning ("music-player-bridge.vala:67: desktop path in cache is not formatted as" \ + g_warning ("music-player-bridge.vala:71: desktop path in cache is not formatted as" \ " we have anticipated"); _g_error_free0 (er); } } __finally0: if (_inner_error_ != NULL) { - bits = (_vala_array_free (bits, bits_length1, (GDestroyNotify) g_free), NULL); _g_free0 (app); _g_object_unref0 (_app_it); g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); g_clear_error (&_inner_error_); return; } - bits = (_vala_array_free (bits, bits_length1, (GDestroyNotify) g_free), NULL); } _g_free0 (app); break; @@ -271,7 +310,7 @@ void music_player_bridge_on_server_added (MusicPlayerBridge* self, IndicateListe gboolean _tmp3_ = FALSE; g_return_if_fail (self != NULL); g_return_if_fail (type != NULL); - g_debug ("music-player-bridge.vala:76: MusicPlayerBridge -> on_server_added with" \ + g_debug ("music-player-bridge.vala:80: MusicPlayerBridge -> on_server_added with" \ " value %s", type); if (music_player_bridge_server_is_not_of_interest (self, type)) { return; @@ -283,15 +322,32 @@ void music_player_bridge_on_server_added (MusicPlayerBridge* self, IndicateListe _tmp3_ = FALSE; } if (_tmp3_) { - indicate_listener_get_server_property_cb cb; - PlayerController* ctrl; - cb = (indicate_listener_get_server_property_cb) music_player_bridge_desktop_info_callback; - indicate_listener_server_get_desktop (self->priv->listener, object, cb, self); - ctrl = player_controller_new (self->priv->root_menu, client_name, TRUE); - gee_abstract_map_set ((GeeAbstractMap*) self->priv->registered_clients, client_name, ctrl); - g_debug ("music-player-bridge.vala:84: client of name %s has successfully regist" \ -"ered with us", client_name); - _g_object_unref0 (ctrl); + GeeSet* _tmp4_; + gboolean _tmp5_; + PlayerController* _tmp8_; + gboolean _tmp9_; + if ((_tmp5_ = gee_collection_contains ((GeeCollection*) (_tmp4_ = gee_map_get_keys ((GeeMap*) self->priv->registered_clients)), client_name), _g_object_unref0 (_tmp4_), _tmp5_)) { + PlayerController* _tmp6_; + PlayerController* _tmp7_; + g_debug ("music-player-bridge.vala:86: It figured out that it already has an ins" \ +"tance for this player already"); + player_controller_update_state (_tmp6_ = (PlayerController*) gee_abstract_map_get ((GeeAbstractMap*) self->priv->registered_clients, client_name), PLAYER_CONTROLLER_STATE_READY); + _g_object_unref0 (_tmp6_); + player_controller_activate (_tmp7_ = (PlayerController*) gee_abstract_map_get ((GeeAbstractMap*) self->priv->registered_clients, client_name)); + _g_object_unref0 (_tmp7_); + } else { + PlayerController* ctrl; + ctrl = player_controller_new (self->priv->root_menu, client_name, PLAYER_CONTROLLER_STATE_READY); + gee_abstract_map_set ((GeeAbstractMap*) self->priv->registered_clients, client_name, ctrl); + g_debug ("music-player-bridge.vala:94: New Client of name %s has successfully re" \ +"gistered with us", client_name); + _g_object_unref0 (ctrl); + } + if ((_tmp9_ = player_controller_get_app_info (_tmp8_ = (PlayerController*) gee_abstract_map_get ((GeeAbstractMap*) self->priv->registered_clients, client_name)) == NULL, _g_object_unref0 (_tmp8_), _tmp9_)) { + indicate_listener_get_server_property_cb cb; + cb = (indicate_listener_get_server_property_cb) music_player_bridge_desktop_info_callback; + indicate_listener_server_get_desktop (self->priv->listener, object, cb, self); + } } _g_free0 (client_name); } @@ -306,8 +362,8 @@ void music_player_bridge_on_server_removed (MusicPlayerBridge* self, IndicateLis gboolean _tmp3_ = FALSE; g_return_if_fail (self != NULL); g_return_if_fail (type != NULL); - g_debug ("music-player-bridge.vala:90: MusicPlayerBridge -> on_server_removed wi" \ -"th value %s", type); + g_debug ("music-player-bridge.vala:106: MusicPlayerBridge -> on_server_removed w" \ +"ith value %s", type); if (music_player_bridge_server_is_not_of_interest (self, type)) { return; } @@ -322,8 +378,8 @@ void music_player_bridge_on_server_removed (MusicPlayerBridge* self, IndicateLis player_controller_vanish (_tmp4_ = (PlayerController*) gee_abstract_map_get ((GeeAbstractMap*) self->priv->registered_clients, client_name)); _g_object_unref0 (_tmp4_); gee_map_remove ((GeeMap*) self->priv->registered_clients, client_name, NULL); - g_debug ("music-player-bridge.vala:96: Successively removed menu_item for client" \ -" %s from registered_clients", client_name); + g_debug ("music-player-bridge.vala:112: Successively removed menu_item for clien" \ +"t %s from registered_clients", client_name); } _g_free0 (client_name); } @@ -347,7 +403,7 @@ static gboolean music_player_bridge_server_is_not_of_interest (MusicPlayerBridge return result; } if (string_contains (type, "music") == FALSE) { - g_debug ("music-player-bridge.vala:103: server is of no interest, it is not an " \ + g_debug ("music-player-bridge.vala:120: server is of no interest, it is not an " \ "music server"); result = TRUE; return result; @@ -357,19 +413,39 @@ static gboolean music_player_bridge_server_is_not_of_interest (MusicPlayerBridge } -static gpointer _g_object_ref0 (gpointer self) { - return self ? g_object_ref (self) : NULL; -} - - static void music_player_bridge_desktop_info_callback (MusicPlayerBridge* self, IndicateListenerServer* server, char* path, void* data) { void* _tmp0_; MusicPlayerBridge* bridge; + gboolean _tmp1_ = FALSE; g_return_if_fail (self != NULL); g_return_if_fail (path != NULL); - g_debug ("music-player-bridge.vala:112: we got a desktop file path hopefully: %s", path); bridge = _g_object_ref0 ((_tmp0_ = data, IS_MUSIC_PLAYER_BRIDGE (_tmp0_) ? ((MusicPlayerBridge*) _tmp0_) : NULL)); - familiar_players_db_insert (bridge->priv->playersDB, path); + if (string_contains (path, "/")) { + _tmp1_ = familiar_players_db_already_familiar (bridge->priv->playersDB, path) == FALSE; + } else { + _tmp1_ = FALSE; + } + if (_tmp1_) { + GAppInfo* app_info; + g_debug ("music-player-bridge.vala:131: About to store desktop file path: %s", path); + familiar_players_db_insert (bridge->priv->playersDB, path); + app_info = music_player_bridge_create_app_info (path); + if (app_info != NULL) { + char* _tmp3_; + char* _tmp2_; + PlayerController* _tmp4_; + PlayerController* ctrl; + ctrl = (_tmp4_ = (PlayerController*) gee_abstract_map_get ((GeeAbstractMap*) bridge->priv->registered_clients, _tmp3_ = string_strip (_tmp2_ = g_utf8_strdown (g_app_info_get_name (app_info), -1))), _g_free0 (_tmp3_), _g_free0 (_tmp2_), _tmp4_); + g_object_set ((GObject*) ctrl, "app_info", app_info, NULL); + g_debug ("music-player-bridge.vala:137: successfully created appinfo from path a" \ +"nd set it on the respective instance"); + _g_object_unref0 (ctrl); + } + _g_object_unref0 (app_info); + } else { + g_debug ("music-player-bridge.vala:141: Ignoring desktop file path because its e" \ +"ither invalid of the db cache file has it already: %s", path); + } _g_object_unref0 (bridge); _g_free0 (path); } @@ -380,25 +456,26 @@ void music_player_bridge_set_root_menu_item (MusicPlayerBridge* self, DbusmenuMe g_return_if_fail (self != NULL); g_return_if_fail (menu != NULL); self->priv->root_menu = (_tmp0_ = _g_object_ref0 (menu), _g_object_unref0 (self->priv->root_menu), _tmp0_); + music_player_bridge_try_to_add_inactive_familiar_clients (self); } void music_player_bridge_on_server_count_changed (MusicPlayerBridge* self, IndicateListenerServer* object, guint i) { g_return_if_fail (self != NULL); - g_debug ("music-player-bridge.vala:125: MusicPlayerBridge-> on_server_count_chan" \ + g_debug ("music-player-bridge.vala:153: MusicPlayerBridge-> on_server_count_chan" \ "ged with value %u", i); } void music_player_bridge_on_indicator_added (MusicPlayerBridge* self, IndicateListenerServer* object, IndicateListenerIndicator* p0) { g_return_if_fail (self != NULL); - g_debug ("music-player-bridge.vala:129: MusicPlayerBridge-> on_indicator_added"); + g_debug ("music-player-bridge.vala:157: MusicPlayerBridge-> on_indicator_added"); } void music_player_bridge_on_indicator_removed (MusicPlayerBridge* self, IndicateListenerServer* object, IndicateListenerIndicator* p0) { g_return_if_fail (self != NULL); - g_debug ("music-player-bridge.vala:134: MusicPlayerBridge -> on_indicator_remove" \ + g_debug ("music-player-bridge.vala:162: MusicPlayerBridge -> on_indicator_remove" \ "d"); } @@ -406,11 +483,32 @@ void music_player_bridge_on_indicator_removed (MusicPlayerBridge* self, Indicate void music_player_bridge_on_indicator_modified (MusicPlayerBridge* self, IndicateListenerServer* object, IndicateListenerIndicator* p0, const char* s) { g_return_if_fail (self != NULL); g_return_if_fail (s != NULL); - g_debug ("music-player-bridge.vala:139: MusicPlayerBridge -> indicator_modified " \ + g_debug ("music-player-bridge.vala:167: MusicPlayerBridge -> indicator_modified " \ "with vale %s", s); } +GAppInfo* music_player_bridge_create_app_info (const char* path) { + GAppInfo* result = NULL; + GDesktopAppInfo* info; + GDesktopAppInfo* _tmp0_; + GAppInfo* app_info; + g_return_val_if_fail (path != NULL, NULL); + info = g_desktop_app_info_new_from_filename (path); + if (path == NULL) { + g_warning ("music-player-bridge.vala:174: Could not create a desktopappinfo instan" \ +"ce from app: %s", path); + result = NULL; + _g_object_unref0 (info); + return result; + } + app_info = _g_object_ref0 ((_tmp0_ = info, G_IS_APP_INFO (_tmp0_) ? ((GAppInfo*) _tmp0_) : NULL)); + result = app_info; + _g_object_unref0 (info); + return result; +} + + static void music_player_bridge_class_init (MusicPlayerBridgeClass * klass) { music_player_bridge_parent_class = g_type_class_peek_parent (klass); g_type_class_add_private (klass, sizeof (MusicPlayerBridgePrivate)); diff --git a/src/music-player-bridge.h b/src/music-player-bridge.h index 26fe9c3..d2a031e 100644 --- a/src/music-player-bridge.h +++ b/src/music-player-bridge.h @@ -17,6 +17,7 @@ #include <libdbusmenu-glib/menuitem-proxy.h> #include <libdbusmenu-glib/menuitem.h> #include <libdbusmenu-glib/server.h> +#include <gio/gio.h> #include <gee.h> #include <dbus/dbus-glib-lowlevel.h> #include <dbus/dbus-glib.h> @@ -46,16 +47,6 @@ typedef struct _PlayerItem PlayerItem; typedef struct _PlayerItemClass PlayerItemClass; typedef struct _PlayerItemPrivate PlayerItemPrivate; -#define TYPE_MPRIS_CONTROLLER (mpris_controller_get_type ()) -#define MPRIS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_MPRIS_CONTROLLER, MprisController)) -#define MPRIS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_MPRIS_CONTROLLER, MprisControllerClass)) -#define IS_MPRIS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_MPRIS_CONTROLLER)) -#define IS_MPRIS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_MPRIS_CONTROLLER)) -#define MPRIS_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_MPRIS_CONTROLLER, MprisControllerClass)) - -typedef struct _MprisController MprisController; -typedef struct _MprisControllerClass MprisControllerClass; - #define TYPE_TRANSPORT_MENUITEM (transport_menuitem_get_type ()) #define TRANSPORT_MENUITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_TRANSPORT_MENUITEM, TransportMenuitem)) #define TRANSPORT_MENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_TRANSPORT_MENUITEM, TransportMenuitemClass)) @@ -67,6 +58,18 @@ typedef struct _TransportMenuitem TransportMenuitem; typedef struct _TransportMenuitemClass TransportMenuitemClass; typedef struct _TransportMenuitemPrivate TransportMenuitemPrivate; +#define TRANSPORT_MENUITEM_TYPE_ACTION (transport_menuitem_action_get_type ()) + +#define TYPE_PLAYER_CONTROLLER (player_controller_get_type ()) +#define PLAYER_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PLAYER_CONTROLLER, PlayerController)) +#define PLAYER_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PLAYER_CONTROLLER, PlayerControllerClass)) +#define IS_PLAYER_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PLAYER_CONTROLLER)) +#define IS_PLAYER_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PLAYER_CONTROLLER)) +#define PLAYER_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PLAYER_CONTROLLER, PlayerControllerClass)) + +typedef struct _PlayerController PlayerController; +typedef struct _PlayerControllerClass PlayerControllerClass; + #define TYPE_METADATA_MENUITEM (metadata_menuitem_get_type ()) #define METADATA_MENUITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_METADATA_MENUITEM, MetadataMenuitem)) #define METADATA_MENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_METADATA_MENUITEM, MetadataMenuitemClass)) @@ -78,16 +81,29 @@ typedef struct _MetadataMenuitem MetadataMenuitem; typedef struct _MetadataMenuitemClass MetadataMenuitemClass; typedef struct _MetadataMenuitemPrivate MetadataMenuitemPrivate; -#define TYPE_PLAYER_CONTROLLER (player_controller_get_type ()) -#define PLAYER_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PLAYER_CONTROLLER, PlayerController)) -#define PLAYER_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PLAYER_CONTROLLER, PlayerControllerClass)) -#define IS_PLAYER_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PLAYER_CONTROLLER)) -#define IS_PLAYER_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PLAYER_CONTROLLER)) -#define PLAYER_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PLAYER_CONTROLLER, PlayerControllerClass)) +#define TYPE_TITLE_MENUITEM (title_menuitem_get_type ()) +#define TITLE_MENUITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_TITLE_MENUITEM, TitleMenuitem)) +#define TITLE_MENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_TITLE_MENUITEM, TitleMenuitemClass)) +#define IS_TITLE_MENUITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_TITLE_MENUITEM)) +#define IS_TITLE_MENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_TITLE_MENUITEM)) +#define TITLE_MENUITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_TITLE_MENUITEM, TitleMenuitemClass)) -typedef struct _PlayerController PlayerController; -typedef struct _PlayerControllerClass PlayerControllerClass; +typedef struct _TitleMenuitem TitleMenuitem; +typedef struct _TitleMenuitemClass TitleMenuitemClass; +typedef struct _TitleMenuitemPrivate TitleMenuitemPrivate; typedef struct _PlayerControllerPrivate PlayerControllerPrivate; + +#define TYPE_MPRIS_CONTROLLER (mpris_controller_get_type ()) +#define MPRIS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_MPRIS_CONTROLLER, MprisController)) +#define MPRIS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_MPRIS_CONTROLLER, MprisControllerClass)) +#define IS_MPRIS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_MPRIS_CONTROLLER)) +#define IS_MPRIS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_MPRIS_CONTROLLER)) +#define MPRIS_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_MPRIS_CONTROLLER, MprisControllerClass)) + +typedef struct _MprisController MprisController; +typedef struct _MprisControllerClass MprisControllerClass; + +#define PLAYER_CONTROLLER_TYPE_STATE (player_controller_state_get_type ()) typedef struct _MprisControllerPrivate MprisControllerPrivate; #define TYPE_MPRIS_CONTROLLER_V2 (mpris_controller_v2_get_type ()) @@ -124,12 +140,10 @@ struct _MusicPlayerBridgeClass { struct _PlayerItem { DbusmenuMenuitem parent_instance; PlayerItemPrivate * priv; - MprisController* mpris_adaptor; }; struct _PlayerItemClass { DbusmenuMenuitemClass parent_class; - void (*check_layout) (PlayerItem* self); }; struct _TransportMenuitem { @@ -141,6 +155,12 @@ struct _TransportMenuitemClass { PlayerItemClass parent_class; }; +typedef enum { + TRANSPORT_MENUITEM_ACTION_PREVIOUS, + TRANSPORT_MENUITEM_ACTION_PLAY_PAUSE, + TRANSPORT_MENUITEM_ACTION_NEXT +} TransportMenuitemaction; + struct _MetadataMenuitem { PlayerItem parent_instance; MetadataMenuitemPrivate * priv; @@ -150,16 +170,35 @@ struct _MetadataMenuitemClass { PlayerItemClass parent_class; }; +struct _TitleMenuitem { + PlayerItem parent_instance; + TitleMenuitemPrivate * priv; +}; + +struct _TitleMenuitemClass { + PlayerItemClass parent_class; +}; + struct _PlayerController { GObject parent_instance; PlayerControllerPrivate * priv; + gint current_state; GeeArrayList* custom_items; + MprisController* mpris_adaptor; }; struct _PlayerControllerClass { GObjectClass parent_class; }; +typedef enum { + PLAYER_CONTROLLER_STATE_OFFLINE, + PLAYER_CONTROLLER_STATE_INSTANTIATING, + PLAYER_CONTROLLER_STATE_READY, + PLAYER_CONTROLLER_STATE_CONNECTED, + PLAYER_CONTROLLER_STATE_DISCONNECTED +} PlayerControllerstate; + struct _MprisController { GObject parent_instance; MprisControllerPrivate * priv; @@ -199,11 +238,13 @@ void music_player_bridge_on_server_count_changed (MusicPlayerBridge* self, Indic void music_player_bridge_on_indicator_added (MusicPlayerBridge* self, IndicateListenerServer* object, IndicateListenerIndicator* p0); void music_player_bridge_on_indicator_removed (MusicPlayerBridge* self, IndicateListenerServer* object, IndicateListenerIndicator* p0); void music_player_bridge_on_indicator_modified (MusicPlayerBridge* self, IndicateListenerServer* object, IndicateListenerIndicator* p0, const char* s); +GAppInfo* music_player_bridge_create_app_info (const char* path); GType player_item_get_type (void); -GType mpris_controller_get_type (void); GType transport_menuitem_get_type (void); -TransportMenuitem* transport_menuitem_new (void); -TransportMenuitem* transport_menuitem_construct (GType object_type); +GType transport_menuitem_action_get_type (void); +GType player_controller_get_type (void); +TransportMenuitem* transport_menuitem_new (PlayerController* parent); +TransportMenuitem* transport_menuitem_construct (GType object_type, PlayerController* parent); void transport_menuitem_change_play_state (TransportMenuitem* self, gint state); GeeHashSet* transport_menuitem_attributes_format (void); GType metadata_menuitem_get_type (void); @@ -211,26 +252,37 @@ MetadataMenuitem* metadata_menuitem_new (void); MetadataMenuitem* metadata_menuitem_construct (GType object_type); GeeHashSet* metadata_menuitem_attributes_format (void); gboolean metadata_menuitem_populated (MetadataMenuitem* self); -GType player_controller_get_type (void); +GType title_menuitem_get_type (void); +TitleMenuitem* title_menuitem_new (PlayerController* parent, const char* name); +TitleMenuitem* title_menuitem_construct (GType object_type, PlayerController* parent, const char* name); +GeeHashSet* title_menuitem_attributes_format (void); +GType mpris_controller_get_type (void); +GType player_controller_state_get_type (void); #define PLAYER_CONTROLLER_METADATA 2 -PlayerController* player_controller_new (DbusmenuMenuitem* root, const char* client_name, gboolean active); -PlayerController* player_controller_construct (GType object_type, DbusmenuMenuitem* root, const char* client_name, gboolean active); +PlayerController* player_controller_new (DbusmenuMenuitem* root, const char* client_name, PlayerControllerstate initial_state); +PlayerController* player_controller_construct (GType object_type, DbusmenuMenuitem* root, const char* client_name, PlayerControllerstate initial_state); +void player_controller_update_state (PlayerController* self, PlayerControllerstate new_state); +void player_controller_activate (PlayerController* self); +void player_controller_instantiate (PlayerController* self); void player_controller_vanish (PlayerController* self); +const char* player_controller_get_name (PlayerController* self); +void player_controller_set_name (PlayerController* self, const char* value); +GAppInfo* player_controller_get_app_info (PlayerController* self); +void player_controller_set_app_info (PlayerController* self, GAppInfo* value); GType mpris_controller_v2_get_type (void); MprisControllerV2* mpris_controller_v2_new (const char* name, PlayerController* controller); MprisControllerV2* mpris_controller_v2_construct (GType object_type, const char* name, PlayerController* controller); MprisController* mpris_controller_new (const char* name, PlayerController* controller, const char* mpris_interface); MprisController* mpris_controller_construct (GType object_type, const char* name, PlayerController* controller, const char* mpris_interface); -void mpris_controller_toggle_playback (MprisController* self, gboolean state); -PlayerItem* player_item_new (void); -PlayerItem* player_item_construct (GType object_type); +void mpris_controller_transport_event (MprisController* self, TransportMenuitemaction command); +gboolean mpris_controller_connected (MprisController* self); +PlayerItem* player_item_new (const char* type); +PlayerItem* player_item_construct (GType object_type, const char* type); void player_item_reset (PlayerItem* self, GeeHashSet* attrs); void player_item_update (PlayerItem* self, GHashTable* data, GeeHashSet* attributes); -void player_item_set_adaptor (PlayerItem* self, MprisController* adaptor); char* player_item_sanitize_string (const char* st); -PlayerItem* player_item_new_title_item (const char* name); -PlayerItem* player_item_new_separator_item (void); -void player_item_check_layout (PlayerItem* self); +PlayerController* player_item_get_owner (PlayerItem* self); +const char* player_item_get_item_type (PlayerItem* self); GType familiar_players_db_get_type (void); FamiliarPlayersDB* familiar_players_db_new (void); FamiliarPlayersDB* familiar_players_db_construct (GType object_type); diff --git a/src/music-player-bridge.vala b/src/music-player-bridge.vala index 6fc9032..d771192 100644 --- a/src/music-player-bridge.vala +++ b/src/music-player-bridge.vala @@ -42,25 +42,29 @@ public class MusicPlayerBridge : GLib.Object listener.server_removed.connect(on_server_removed); listener.server_count_changed.connect(on_server_count_changed); } - // Alpha 2 not in use ... yet. + private void try_to_add_inactive_familiar_clients(){ - // for now just use one of the entries. + // TODO handle multple players - just working with one right now int count = 0; foreach(string app in this.playersDB.records()){ if(count == 0){ - debug("we have found %s", app); - string[] bits = app.split("/"); - + if(app == null){ + warning("App string in keyfile is null therefore moving on to next player"); + continue; + } try{ - string app_name = bits[bits.length -1].split(".")[0]; - debug("we have found %s", app_name); + DesktopAppInfo info = new DesktopAppInfo.from_filename(app); + if(info == null){ + warning("Could not create a desktopappinfo instance from app: %s", app); + continue; + } + GLib.AppInfo app_info = info as GLib.AppInfo; PlayerController ctrl = new PlayerController(this.root_menu, - app_name, - false); - this.registered_clients.set(app_name, ctrl); - DesktopAppInfo info = new DesktopAppInfo.from_filename(app_name); - string desc = info.get_display_name(); - debug("description from app %s", desc); + app_info.get_name(), + PlayerController.state.OFFLINE); + ctrl.set("app_info", app_info); + this.registered_clients.set(app_info.get_name().down().strip(), ctrl); + debug("Created a player controller for %s which was found in the cache file", app_info.get_name().down().strip()); count += 1; } catch(Error er){ @@ -75,13 +79,25 @@ public class MusicPlayerBridge : GLib.Object { debug("MusicPlayerBridge -> on_server_added with value %s", type); if(server_is_not_of_interest(type)) return; - string client_name = type.split(".")[1]; + string client_name = type.split(".")[1]; if (root_menu != null && client_name != null){ - listener_get_server_property_cb cb = (listener_get_server_property_cb)desktop_info_callback; - this.listener.server_get_desktop(object, cb, this); - PlayerController ctrl = new PlayerController(root_menu, client_name, true); - registered_clients.set(client_name, ctrl); - debug("client of name %s has successfully registered with us", client_name); + // If we have an instance already for this player, ensure it is switched to active + if(this.registered_clients.keys.contains(client_name)){ + debug("It figured out that it already has an instance for this player already"); + this.registered_clients[client_name].update_state(PlayerController.state.READY); + this.registered_clients[client_name].activate(); + } + //else init a new one + else{ + PlayerController ctrl = new PlayerController(root_menu, client_name, PlayerController.state.READY); + registered_clients.set(client_name, ctrl); + debug("New Client of name %s has successfully registered with us", client_name); + } + // irregardless check that it has a desktop file if not kick off a request for it + if(this.registered_clients[client_name].app_info == null){ + listener_get_server_property_cb cb = (listener_get_server_property_cb)desktop_info_callback; + this.listener.server_get_desktop(object, cb, this); + } } } @@ -93,7 +109,8 @@ public class MusicPlayerBridge : GLib.Object if (root_menu != null && client_name != null){ registered_clients[client_name].vanish(); registered_clients.remove(client_name); - debug("Successively removed menu_item for client %s from registered_clients", client_name); + debug("Successively removed menu_item for client %s from registered_clients", + client_name); } } @@ -109,15 +126,26 @@ public class MusicPlayerBridge : GLib.Object private void desktop_info_callback(Indicate.ListenerServer server, owned string path, void* data) { - debug("we got a desktop file path hopefully: %s", path); MusicPlayerBridge bridge = data as MusicPlayerBridge; - bridge.playersDB.insert(path); + if(path.contains("/") && bridge.playersDB.already_familiar(path) == false){ + debug("About to store desktop file path: %s", path); + bridge.playersDB.insert(path); + AppInfo? app_info = create_app_info(path); + if(app_info != null){ + PlayerController ctrl = bridge.registered_clients[app_info.get_name().down().strip()]; + ctrl.set("app_info", app_info); + debug("successfully created appinfo from path and set it on the respective instance"); + } + } + else{ + debug("Ignoring desktop file path because its either invalid of the db cache file has it already: %s", path); + } } public void set_root_menu_item(Dbusmenu.Menuitem menu) { this.root_menu = menu; - //try_to_add_inactive_familiar_clients(); + try_to_add_inactive_familiar_clients(); } public void on_server_count_changed(Indicate.ListenerServer object, uint i) @@ -139,6 +167,17 @@ public class MusicPlayerBridge : GLib.Object debug("MusicPlayerBridge -> indicator_modified with vale %s", s ); } + public static AppInfo? create_app_info(string path) + { + DesktopAppInfo info = new DesktopAppInfo.from_filename(path); + if(path == null){ + warning("Could not create a desktopappinfo instance from app: %s", path); + return null; + } + GLib.AppInfo app_info = info as GLib.AppInfo; + return app_info; + } + } diff --git a/src/play-button.c b/src/play-button.c new file mode 100644 index 0000000..2fddbcf --- /dev/null +++ b/src/play-button.c @@ -0,0 +1,800 @@ +/* +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/>. + +Uses code from ctk +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <math.h> +#include "play-button.h" + +#define RECT_WIDTH 130.0f +#define Y 15.0f +#define X 22.0f +#define INNER_RADIUS 12.5 +#define MIDDLE_RADIUS 13.5f +#define OUTER_RADIUS 14.5f +#define CIRCLE_RADIUS 19.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 20.0f +#define PREV_Y 21.0f +#define NEXT_X 98.0f +#define NEXT_Y 21.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 62.0f +#define PAUSE_Y 15.0f + +// Transport events +enum { + PREVIOUS, + PLAY_PAUSE, + NEXT +}; + +typedef struct _PlayButtonPrivate PlayButtonPrivate; + +struct _PlayButtonPrivate +{ + GdkColor background_colour_fg; + GdkColor background_colour_bg_dark; + GdkColor background_colour_bg_light; + GdkColor foreground_colour_fg; + GdkColor foreground_colour_bg; +}; + +#define PLAY_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PLAY_BUTTON_TYPE, PlayButtonPrivate)) + +/* Gobject boiler plate */ +static void play_button_class_init (PlayButtonClass *klass); +static void play_button_init (PlayButton *self); +static void play_button_dispose (GObject *object); +static void play_button_finalize (GObject *object); + +static gboolean play_button_expose (GtkWidget *button, GdkEventExpose *event); +static void draw (GtkWidget* button, cairo_t *cr); + +G_DEFINE_TYPE (PlayButton, play_button, GTK_TYPE_DRAWING_AREA); + +/// internal helper functions ////////////////////////////////////////////////// + +static double +_align (double val) +{ + double fract = val - (int) val; + + if (fract != 0.5f) + return (double) ((int) val + 0.5f); + else + return val; +} + +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); +} + +/// GObject functions ////////////////////////////////////////////////////////// + +static void +play_button_class_init (PlayButtonClass *klass) +{ + + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass); + + g_type_class_add_private (klass, sizeof (PlayButtonPrivate)); + + widget_class->expose_event = play_button_expose; + + gobject_class->dispose = play_button_dispose; + gobject_class->finalize = play_button_finalize; +} + +static void +play_button_init (PlayButton *self) +{ + gtk_widget_set_size_request(GTK_WIDGET(self), 200, 80); +} + +static void +play_button_dispose (GObject *object) +{ + G_OBJECT_CLASS (play_button_parent_class)->dispose (object); +} + +static void +play_button_finalize (GObject *object) +{ + G_OBJECT_CLASS (play_button_parent_class)->finalize (object); +} + +static gboolean +play_button_expose (GtkWidget *button, GdkEventExpose *event) +{ + cairo_t *cr; + cr = gdk_cairo_create (button->window); + + 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; +} + + +gint +determine_button_event(GtkWidget* button, GdkEventButton* event) +{ + g_debug("event x coordinate = %f", event->x); + g_debug("event y coordinate = %f", event->y); + gint result = 0; + // For now very simple rectangular collision detection + if(event->x > 40 && event->x < 80 + && event->y > 22 && event->y < 46){ + result = PREVIOUS; + } + else if(event->x > 86 && event->x < 118 + && event->y > 20 && event->y < 47){ + result = PLAY_PAUSE; + } + else if(event->x > 122 && event->x < 164 + && event->y > 22 && event->y < 46){ + result = NEXT; + } + + return result; +} + +void +play_button_set_style(GtkWidget* button, GtkStyle* style) +{ + PlayButtonPrivate* priv = PLAY_BUTTON_GET_PRIVATE(button); + priv->background_colour_fg = style->fg[GTK_STATE_NORMAL]; + priv->background_colour_bg_dark = style->bg[GTK_STATE_NORMAL]; + priv->background_colour_bg_light = style->base[GTK_STATE_NORMAL]; + priv->foreground_colour_fg = style->fg[GTK_STATE_PRELIGHT]; + priv->foreground_colour_bg = style->bg[GTK_STATE_NORMAL]; +} + +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 +_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 +draw (GtkWidget* button, cairo_t *cr) +{ + cairo_surface_t* surf = NULL; + cairo_t* cr_surf = NULL; + + double INNER_START[] = {229.0f/255.0f, 223.0f/255.0f, 215.0f/255.0f, 1.0f}; + double INNER_END[] = {183.0f / 255.0f, 178.0f / 255.0f, 172.0f / 255.0f, 1.0f}; + double MIDDLE_START[] = {61.0f / 255.0f, 60.0f / 255.0f, 57.0f / 255.0f, 1.0f}; + double MIDDLE_END[] = {94.0f / 255.0f,93.0f / 255.0f, 90.0f / 255.0f,1.0f}; + double OUTER_START[] = {36.0f / 255.0f, 35.0f / 255.0f, 33.0f / 255.0f, 1.0f}; + double OUTER_END[] = {123.0f / 255.0f, 123.0f / 255.0f, 120.0f / 255.0f, 1.0f}; + double BUTTON_START[] = {252.0f / 255.0f, 251.0f / 255.0f, 251.0f / 255.0f,1.0f}; + double BUTTON_END[] = {186.0f / 255.0f,180.0f / 255.0f, 170.0f / 255.0f, 1.0f}; + double BUTTON_SHADOW[] = {0.0f / 255.0f, 0.0f / 255.0f, 0.0f / 255.0f, 0.75f}; + + + // prev/next-background + 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, + INNER_RADIUS, + INNER_START, + INNER_END); + + // play/pause-background + draw_circle (cr, + X + RECT_WIDTH / 2.0f - 2.0f * OUTER_RADIUS - 4.5f, + Y - ((CIRCLE_RADIUS - OUTER_RADIUS)), + CIRCLE_RADIUS, + OUTER_START, + OUTER_END); + draw_circle (cr, + X + RECT_WIDTH / 2.0f - 2.0f * OUTER_RADIUS - 4.5f + 1.0f, + Y - ((CIRCLE_RADIUS - OUTER_RADIUS)) + 1.0f, + CIRCLE_RADIUS - 1, + MIDDLE_START, + MIDDLE_END); + draw_circle (cr, + X + RECT_WIDTH / 2.0f - 2.0f * OUTER_RADIUS - 4.5f + 2.0f, + Y - ((CIRCLE_RADIUS - OUTER_RADIUS)) + 2.0f, + CIRCLE_RADIUS - 2.0f, + INNER_START, + INNER_END); + + // draw previous-button drop-shadow + _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 + _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 + _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); +} + + +/** +* play_button_new: +* @returns: a new #PlayButton. +**/ +GtkWidget* +play_button_new() +{ + + GtkWidget* widget = g_object_new(PLAY_BUTTON_TYPE, NULL); + gtk_widget_set_app_paintable (widget, TRUE); + return widget; +} + diff --git a/src/play-button.h b/src/play-button.h new file mode 100644 index 0000000..3eaabcc --- /dev/null +++ b/src/play-button.h @@ -0,0 +1,53 @@ +/* +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 __PLAY_BUTTON_H__ +#define __PLAY_BUTTON_H__ + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define PLAY_BUTTON_TYPE (play_button_get_type ()) +#define PLAY_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLAY_BUTTON_TYPE, PlayButton)) +#define PLAY_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PLAY_BUTTON_TYPE, PlayButtonClass)) +#define IS_PLAY_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLAY_BUTTON_TYPE)) +#define IS_PLAY_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PLAY_BUTTON_TYPE)) +#define PLAY_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PLAY_BUTTON_TYPE, PlayButtonClass)) + +typedef struct _PlayButton PlayButton; +typedef struct _PlayButtonClass PlayButtonClass; + +struct _PlayButtonClass { + GtkDrawingAreaClass parent_class; +}; + +struct _PlayButton { + GtkDrawingArea parent; +}; + +GType play_button_get_type (void); +void play_button_set_style(GtkWidget* button, GtkStyle* style); +gint determine_button_event(GtkWidget* button, GdkEventButton* event); + +GtkWidget* play_button_new(); + +G_END_DECLS + +#endif + diff --git a/src/player-controller.c b/src/player-controller.c index 5c4e0cc..bbdbcbf 100644 --- a/src/player-controller.c +++ b/src/player-controller.c @@ -30,6 +30,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <libdbusmenu-glib/server.h> #include <stdlib.h> #include <string.h> +#include <gio/gio.h> #define TYPE_PLAYER_CONTROLLER (player_controller_get_type ()) @@ -62,8 +63,11 @@ typedef struct _PlayerItemClass PlayerItemClass; typedef struct _MprisController MprisController; typedef struct _MprisControllerClass MprisControllerClass; + +#define PLAYER_CONTROLLER_TYPE_STATE (player_controller_state_get_type ()) #define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL))) #define _g_free0(var) (var = (g_free (var), NULL)) +#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL))) #define TYPE_MPRIS_CONTROLLER_V2 (mpris_controller_v2_get_type ()) #define MPRIS_CONTROLLER_V2(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_MPRIS_CONTROLLER_V2, MprisControllerV2)) @@ -75,6 +79,16 @@ typedef struct _MprisControllerClass MprisControllerClass; typedef struct _MprisControllerV2 MprisControllerV2; typedef struct _MprisControllerV2Class MprisControllerV2Class; +#define TYPE_TITLE_MENUITEM (title_menuitem_get_type ()) +#define TITLE_MENUITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_TITLE_MENUITEM, TitleMenuitem)) +#define TITLE_MENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_TITLE_MENUITEM, TitleMenuitemClass)) +#define IS_TITLE_MENUITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_TITLE_MENUITEM)) +#define IS_TITLE_MENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_TITLE_MENUITEM)) +#define TITLE_MENUITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_TITLE_MENUITEM, TitleMenuitemClass)) + +typedef struct _TitleMenuitem TitleMenuitem; +typedef struct _TitleMenuitemClass TitleMenuitemClass; + #define TYPE_METADATA_MENUITEM (metadata_menuitem_get_type ()) #define METADATA_MENUITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_METADATA_MENUITEM, MetadataMenuitem)) #define METADATA_MENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_METADATA_MENUITEM, MetadataMenuitemClass)) @@ -98,7 +112,9 @@ typedef struct _TransportMenuitemClass TransportMenuitemClass; struct _PlayerController { GObject parent_instance; PlayerControllerPrivate * priv; + gint current_state; GeeArrayList* custom_items; + MprisController* mpris_adaptor; }; struct _PlayerControllerClass { @@ -107,12 +123,18 @@ struct _PlayerControllerClass { struct _PlayerControllerPrivate { DbusmenuMenuitem* root_menu; - char* name; - gboolean is_active; - MprisController* mpris_adaptor; - char* desktop_path; + char* _name; + GAppInfo* _app_info; }; +typedef enum { + PLAYER_CONTROLLER_STATE_OFFLINE, + PLAYER_CONTROLLER_STATE_INSTANTIATING, + PLAYER_CONTROLLER_STATE_READY, + PLAYER_CONTROLLER_STATE_CONNECTED, + PLAYER_CONTROLLER_STATE_DISCONNECTED +} PlayerControllerstate; + static gpointer player_controller_parent_class = NULL; @@ -121,34 +143,63 @@ GType player_item_get_type (void); GType mpris_controller_get_type (void); #define PLAYER_CONTROLLER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_PLAYER_CONTROLLER, PlayerControllerPrivate)) enum { - PLAYER_CONTROLLER_DUMMY_PROPERTY + PLAYER_CONTROLLER_DUMMY_PROPERTY, + PLAYER_CONTROLLER_NAME, + PLAYER_CONTROLLER_APP_INFO }; +GType player_controller_state_get_type (void); #define PLAYER_CONTROLLER_METADATA 2 #define PLAYER_CONTROLLER_TRANSPORT 3 static char* player_controller_format_client_name (const char* client_name); -static gboolean player_controller_self_construct (PlayerController* self); +void player_controller_set_name (PlayerController* self, const char* value); +void player_controller_update_state (PlayerController* self, PlayerControllerstate new_state); +static void player_controller_construct_widgets (PlayerController* self); +static void player_controller_establish_mpris_connection (PlayerController* self); +static void player_controller_update_layout (PlayerController* self); +PlayerController* player_controller_new (DbusmenuMenuitem* root, const char* client_name, PlayerControllerstate initial_state); +PlayerController* player_controller_construct (GType object_type, DbusmenuMenuitem* root, const char* client_name, PlayerControllerstate initial_state); +void player_controller_activate (PlayerController* self); +GAppInfo* player_controller_get_app_info (PlayerController* self); +const char* player_controller_get_name (PlayerController* self); +void player_controller_instantiate (PlayerController* self); MprisControllerV2* mpris_controller_v2_new (const char* name, PlayerController* controller); MprisControllerV2* mpris_controller_v2_construct (GType object_type, const char* name, PlayerController* controller); GType mpris_controller_v2_get_type (void); MprisController* mpris_controller_new (const char* name, PlayerController* controller, const char* mpris_interface); MprisController* mpris_controller_construct (GType object_type, const char* name, PlayerController* controller, const char* mpris_interface); -void player_item_set_adaptor (PlayerItem* self, MprisController* adaptor); -PlayerController* player_controller_new (DbusmenuMenuitem* root, const char* client_name, gboolean active); -PlayerController* player_controller_construct (GType object_type, DbusmenuMenuitem* root, const char* client_name, gboolean active); +gboolean mpris_controller_connected (MprisController* self); void player_controller_vanish (PlayerController* self); -PlayerItem* player_item_new_separator_item (void); -PlayerItem* player_item_new_title_item (const char* name); +PlayerItem* player_item_new (const char* type); +PlayerItem* player_item_construct (GType object_type, const char* type); +TitleMenuitem* title_menuitem_new (PlayerController* parent, const char* name); +TitleMenuitem* title_menuitem_construct (GType object_type, PlayerController* parent, const char* name); +GType title_menuitem_get_type (void); MetadataMenuitem* metadata_menuitem_new (void); MetadataMenuitem* metadata_menuitem_construct (GType object_type); GType metadata_menuitem_get_type (void); -TransportMenuitem* transport_menuitem_new (void); -TransportMenuitem* transport_menuitem_construct (GType object_type); +TransportMenuitem* transport_menuitem_new (PlayerController* parent); +TransportMenuitem* transport_menuitem_construct (GType object_type, PlayerController* parent); GType transport_menuitem_get_type (void); +void player_controller_set_app_info (PlayerController* self, GAppInfo* value); static void player_controller_finalize (GObject* obj); +static void player_controller_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec); +static void player_controller_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec); static int _vala_strcmp0 (const char * str1, const char * str2); +GType player_controller_state_get_type (void) { + static volatile gsize player_controller_state_type_id__volatile = 0; + if (g_once_init_enter (&player_controller_state_type_id__volatile)) { + static const GEnumValue values[] = {{PLAYER_CONTROLLER_STATE_OFFLINE, "PLAYER_CONTROLLER_STATE_OFFLINE", "offline"}, {PLAYER_CONTROLLER_STATE_INSTANTIATING, "PLAYER_CONTROLLER_STATE_INSTANTIATING", "instantiating"}, {PLAYER_CONTROLLER_STATE_READY, "PLAYER_CONTROLLER_STATE_READY", "ready"}, {PLAYER_CONTROLLER_STATE_CONNECTED, "PLAYER_CONTROLLER_STATE_CONNECTED", "connected"}, {PLAYER_CONTROLLER_STATE_DISCONNECTED, "PLAYER_CONTROLLER_STATE_DISCONNECTED", "disconnected"}, {0, NULL, NULL}}; + GType player_controller_state_type_id; + player_controller_state_type_id = g_enum_register_static ("PlayerControllerstate", values); + g_once_init_leave (&player_controller_state_type_id__volatile, player_controller_state_type_id); + } + return player_controller_state_type_id__volatile; +} + + static gpointer _g_object_ref0 (gpointer self) { return self ? g_object_ref (self) : NULL; } @@ -165,37 +216,101 @@ static char* string_strip (const char* self) { } -PlayerController* player_controller_construct (GType object_type, DbusmenuMenuitem* root, const char* client_name, gboolean active) { +PlayerController* player_controller_construct (GType object_type, DbusmenuMenuitem* root, const char* client_name, PlayerControllerstate initial_state) { PlayerController * self; DbusmenuMenuitem* _tmp0_; char* _tmp2_; char* _tmp1_; GeeArrayList* _tmp3_; - PlayerItem* _tmp6_; g_return_val_if_fail (root != NULL, NULL); g_return_val_if_fail (client_name != NULL, NULL); self = (PlayerController*) g_object_new (object_type, NULL); self->priv->root_menu = (_tmp0_ = _g_object_ref0 (root), _g_object_unref0 (self->priv->root_menu), _tmp0_); - self->priv->name = (_tmp2_ = player_controller_format_client_name (_tmp1_ = string_strip (client_name)), _g_free0 (self->priv->name), _tmp2_); + player_controller_set_name (self, _tmp2_ = player_controller_format_client_name (_tmp1_ = string_strip (client_name))); + _g_free0 (_tmp2_); _g_free0 (_tmp1_); - self->priv->is_active = active; self->custom_items = (_tmp3_ = gee_array_list_new (TYPE_PLAYER_ITEM, (GBoxedCopyFunc) g_object_ref, g_object_unref, NULL), _g_object_unref0 (self->custom_items), _tmp3_); - player_controller_self_construct (self); - if (_vala_strcmp0 (self->priv->name, "Vlc") == 0) { - MprisController* _tmp4_; - self->priv->mpris_adaptor = (_tmp4_ = (MprisController*) mpris_controller_v2_new (self->priv->name, self), _g_object_unref0 (self->priv->mpris_adaptor), _tmp4_); - } else { - MprisController* _tmp5_; - self->priv->mpris_adaptor = (_tmp5_ = mpris_controller_new (self->priv->name, self, "org.freedesktop.MediaPlayer"), _g_object_unref0 (self->priv->mpris_adaptor), _tmp5_); - } - player_item_set_adaptor (_tmp6_ = (PlayerItem*) gee_abstract_list_get ((GeeAbstractList*) self->custom_items, PLAYER_CONTROLLER_TRANSPORT), self->priv->mpris_adaptor); - _g_object_unref0 (_tmp6_); + player_controller_update_state (self, initial_state); + player_controller_construct_widgets (self); + player_controller_establish_mpris_connection (self); + player_controller_update_layout (self); return self; } -PlayerController* player_controller_new (DbusmenuMenuitem* root, const char* client_name, gboolean active) { - return player_controller_construct (TYPE_PLAYER_CONTROLLER, root, client_name, active); +PlayerController* player_controller_new (DbusmenuMenuitem* root, const char* client_name, PlayerControllerstate initial_state) { + return player_controller_construct (TYPE_PLAYER_CONTROLLER, root, client_name, initial_state); +} + + +void player_controller_update_state (PlayerController* self, PlayerControllerstate new_state) { + g_return_if_fail (self != NULL); + g_debug ("player-controller.vala:59: update_state : new state %i", (gint) new_state); + self->current_state = (gint) new_state; +} + + +void player_controller_activate (PlayerController* self) { + PlayerItem* _tmp0_; + g_return_if_fail (self != NULL); + player_controller_establish_mpris_connection (self); + dbusmenu_menuitem_property_set_bool ((DbusmenuMenuitem*) (_tmp0_ = (PlayerItem*) gee_abstract_list_get ((GeeAbstractList*) self->custom_items, PLAYER_CONTROLLER_METADATA)), DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); + _g_object_unref0 (_tmp0_); +} + + +void player_controller_instantiate (PlayerController* self) { + GError * _inner_error_; + g_return_if_fail (self != NULL); + _inner_error_ = NULL; + { + g_app_info_launch (self->priv->_app_info, NULL, NULL, &_inner_error_); + if (_inner_error_ != NULL) { + goto __catch1_g_error; + } + player_controller_update_state (self, PLAYER_CONTROLLER_STATE_INSTANTIATING); + } + goto __finally1; + __catch1_g_error: + { + GError * _error_; + _error_ = _inner_error_; + _inner_error_ = NULL; + { + g_warning ("player-controller.vala:82: Failed to launch app %s with error message:" \ +" %s", self->priv->_name, _error_->message); + _g_error_free0 (_error_); + } + } + __finally1: + if (_inner_error_ != NULL) { + g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); + g_clear_error (&_inner_error_); + return; + } +} + + +static void player_controller_establish_mpris_connection (PlayerController* self) { + g_return_if_fail (self != NULL); + if (self->current_state != PLAYER_CONTROLLER_STATE_READY) { + g_debug ("player-controller.vala:89: establish_mpris_connection - Not ready to c" \ +"onnect"); + return; + } + if (_vala_strcmp0 (self->priv->_name, "Vlc") == 0) { + MprisController* _tmp0_; + self->mpris_adaptor = (_tmp0_ = (MprisController*) mpris_controller_v2_new (self->priv->_name, self), _g_object_unref0 (self->mpris_adaptor), _tmp0_); + } else { + MprisController* _tmp1_; + self->mpris_adaptor = (_tmp1_ = mpris_controller_new (self->priv->_name, self, "org.freedesktop.MediaPlayer"), _g_object_unref0 (self->mpris_adaptor), _tmp1_); + } + if (mpris_controller_connected (self->mpris_adaptor) == TRUE) { + player_controller_update_state (self, PLAYER_CONTROLLER_STATE_CONNECTED); + } else { + player_controller_update_state (self, PLAYER_CONTROLLER_STATE_DISCONNECTED); + } + player_controller_update_layout (self); } @@ -218,21 +333,52 @@ void player_controller_vanish (PlayerController* self) { } -static gboolean player_controller_self_construct (PlayerController* self) { - gboolean result = FALSE; - PlayerItem* _tmp0_; +static char* bool_to_string (gboolean self) { + char* result = NULL; + if (self) { + result = g_strdup ("true"); + return result; + } else { + result = g_strdup ("false"); + return result; + } +} + + +static void player_controller_update_layout (PlayerController* self) { + gboolean visibility; + char* _tmp0_; PlayerItem* _tmp1_; + PlayerItem* _tmp2_; + g_return_if_fail (self != NULL); + visibility = TRUE; + if (self->current_state != PLAYER_CONTROLLER_STATE_CONNECTED) { + visibility = FALSE; + } + g_debug ("player-controller.vala:120: about the set the visibility on both the t" \ +"ransport and metadata widget to %s", _tmp0_ = bool_to_string (visibility)); + _g_free0 (_tmp0_); + dbusmenu_menuitem_property_set_bool ((DbusmenuMenuitem*) (_tmp1_ = (PlayerItem*) gee_abstract_list_get ((GeeAbstractList*) self->custom_items, PLAYER_CONTROLLER_TRANSPORT)), DBUSMENU_MENUITEM_PROP_VISIBLE, visibility); + _g_object_unref0 (_tmp1_); + dbusmenu_menuitem_property_set_bool ((DbusmenuMenuitem*) (_tmp2_ = (PlayerItem*) gee_abstract_list_get ((GeeAbstractList*) self->custom_items, PLAYER_CONTROLLER_METADATA)), DBUSMENU_MENUITEM_PROP_VISIBLE, visibility); + _g_object_unref0 (_tmp2_); +} + + +static void player_controller_construct_widgets (PlayerController* self) { + PlayerItem* _tmp0_; + TitleMenuitem* title_menu_item; MetadataMenuitem* metadata_item; TransportMenuitem* transport_item; gint offset; - g_return_val_if_fail (self != NULL, FALSE); - gee_abstract_collection_add ((GeeAbstractCollection*) self->custom_items, _tmp0_ = player_item_new_separator_item ()); + g_return_if_fail (self != NULL); + gee_abstract_collection_add ((GeeAbstractCollection*) self->custom_items, _tmp0_ = player_item_new (DBUSMENU_CLIENT_TYPES_SEPARATOR)); _g_object_unref0 (_tmp0_); - gee_abstract_collection_add ((GeeAbstractCollection*) self->custom_items, _tmp1_ = player_item_new_title_item (self->priv->name)); - _g_object_unref0 (_tmp1_); + title_menu_item = title_menuitem_new (self, self->priv->_name); + gee_abstract_collection_add ((GeeAbstractCollection*) self->custom_items, (PlayerItem*) title_menu_item); metadata_item = metadata_menuitem_new (); gee_abstract_collection_add ((GeeAbstractCollection*) self->custom_items, (PlayerItem*) metadata_item); - transport_item = transport_menuitem_new (); + transport_item = transport_menuitem_new (self); gee_abstract_collection_add ((GeeAbstractCollection*) self->custom_items, (PlayerItem*) transport_item); offset = 2; { @@ -249,10 +395,9 @@ static gboolean player_controller_self_construct (PlayerController* self) { } _g_object_unref0 (_item_it); } - result = TRUE; + _g_object_unref0 (title_menu_item); _g_object_unref0 (metadata_item); _g_object_unref0 (transport_item); - return result; } @@ -301,22 +446,60 @@ static char* player_controller_format_client_name (const char* client_name) { formatted = (_tmp2_ = g_strconcat (_tmp0_ = g_utf8_strup (client_name, (gssize) 1), _tmp1_ = string_slice (client_name, (glong) 1, g_utf8_strlen (client_name, -1)), NULL), _g_free0 (formatted), _tmp2_); _g_free0 (_tmp1_); _g_free0 (_tmp0_); - g_debug ("player-controller.vala:93: PlayerController->format_client_name - : %s", formatted); + g_debug ("player-controller.vala:154: PlayerController->format_client_name - : %" \ +"s", formatted); } result = formatted; return result; } +const char* player_controller_get_name (PlayerController* self) { + const char* result; + g_return_val_if_fail (self != NULL, NULL); + result = self->priv->_name; + return result; +} + + +void player_controller_set_name (PlayerController* self, const char* value) { + char* _tmp0_; + g_return_if_fail (self != NULL); + self->priv->_name = (_tmp0_ = g_strdup (value), _g_free0 (self->priv->_name), _tmp0_); + g_object_notify ((GObject *) self, "name"); +} + + +GAppInfo* player_controller_get_app_info (PlayerController* self) { + GAppInfo* result; + g_return_val_if_fail (self != NULL, NULL); + result = self->priv->_app_info; + return result; +} + + +void player_controller_set_app_info (PlayerController* self, GAppInfo* value) { + GAppInfo* _tmp0_; + g_return_if_fail (self != NULL); + self->priv->_app_info = (_tmp0_ = _g_object_ref0 (value), _g_object_unref0 (self->priv->_app_info), _tmp0_); + g_object_notify ((GObject *) self, "app-info"); +} + + static void player_controller_class_init (PlayerControllerClass * klass) { player_controller_parent_class = g_type_class_peek_parent (klass); g_type_class_add_private (klass, sizeof (PlayerControllerPrivate)); + G_OBJECT_CLASS (klass)->get_property = player_controller_get_property; + G_OBJECT_CLASS (klass)->set_property = player_controller_set_property; G_OBJECT_CLASS (klass)->finalize = player_controller_finalize; + g_object_class_install_property (G_OBJECT_CLASS (klass), PLAYER_CONTROLLER_NAME, g_param_spec_string ("name", "name", "name", NULL, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PLAYER_CONTROLLER_APP_INFO, g_param_spec_object ("app-info", "app-info", "app-info", G_TYPE_APP_INFO, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE)); } static void player_controller_instance_init (PlayerController * self) { self->priv = PLAYER_CONTROLLER_GET_PRIVATE (self); + self->current_state = (gint) PLAYER_CONTROLLER_STATE_OFFLINE; } @@ -324,10 +507,10 @@ static void player_controller_finalize (GObject* obj) { PlayerController * self; self = PLAYER_CONTROLLER (obj); _g_object_unref0 (self->priv->root_menu); - _g_free0 (self->priv->name); + _g_free0 (self->priv->_name); _g_object_unref0 (self->custom_items); - _g_object_unref0 (self->priv->mpris_adaptor); - _g_free0 (self->priv->desktop_path); + _g_object_unref0 (self->mpris_adaptor); + _g_object_unref0 (self->priv->_app_info); G_OBJECT_CLASS (player_controller_parent_class)->finalize (obj); } @@ -344,6 +527,40 @@ GType player_controller_get_type (void) { } +static void player_controller_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) { + PlayerController * self; + self = PLAYER_CONTROLLER (object); + switch (property_id) { + case PLAYER_CONTROLLER_NAME: + g_value_set_string (value, player_controller_get_name (self)); + break; + case PLAYER_CONTROLLER_APP_INFO: + g_value_set_object (value, player_controller_get_app_info (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void player_controller_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec) { + PlayerController * self; + self = PLAYER_CONTROLLER (object); + switch (property_id) { + case PLAYER_CONTROLLER_NAME: + player_controller_set_name (self, g_value_get_string (value)); + break; + case PLAYER_CONTROLLER_APP_INFO: + player_controller_set_app_info (self, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + static int _vala_strcmp0 (const char * str1, const char * str2) { if (str1 == NULL) { return -(str1 != str2); diff --git a/src/player-controller.vala b/src/player-controller.vala index 0d8dc01..3fb4750 100644 --- a/src/player-controller.vala +++ b/src/player-controller.vala @@ -25,66 +25,127 @@ public class PlayerController : GLib.Object { public const int METADATA = 2; private const int TRANSPORT = 3; + + public enum state{ + OFFLINE, + INSTANTIATING, + READY, + CONNECTED, + DISCONNECTED + } + + public int current_state = state.OFFLINE; + private Dbusmenu.Menuitem root_menu; - private string name; - private bool is_active; + public string name { get; set;} public ArrayList<PlayerItem> custom_items; - private MprisController mpris_adaptor; - private string desktop_path; - - public PlayerController(Dbusmenu.Menuitem root, string client_name, bool active) + public MprisController mpris_adaptor; + public AppInfo? app_info { get; set;} + + public PlayerController(Dbusmenu.Menuitem root, string client_name, state initial_state) { this.root_menu = root; this.name = format_client_name(client_name.strip()); - this.is_active = active; this.custom_items = new ArrayList<PlayerItem>(); - self_construct(); - - // Temporary scenario to handle both v1 and v2 of MPRIS. + this.update_state(initial_state); + construct_widgets(); + establish_mpris_connection(); + update_layout(); + } + + public void update_state(state new_state) + { + debug("update_state : new state %i", new_state); + this.current_state = new_state; + } + + public void activate() + { + this.establish_mpris_connection(); + this.custom_items[METADATA].property_set_bool(MENUITEM_PROP_VISIBLE, true); + } + + /* + 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() + { + try{ + this.app_info.launch(null, null); + this.update_state(state.INSTANTIATING); + } + catch(GLib.Error error){ + warning("Failed to launch app %s with error message: %s", this.name, error.message); + } + } + + private void establish_mpris_connection() + { + if(this.current_state != state.READY){ + debug("establish_mpris_connection - Not ready to connect"); + return; + } if(this.name == "Vlc"){ this.mpris_adaptor = new MprisControllerV2(this.name, this); } else{ this.mpris_adaptor = new MprisController(this.name, this); - } - this.custom_items[TRANSPORT].set_adaptor(this.mpris_adaptor); - - // At start up if there is no metadata then hide the item. - // TODO: NOT working -> dbus menu bug ? - //((MetadataMenuitem)this.custom_items[METADATA]).check_layout(); + } + if(this.mpris_adaptor.connected() == true){ + this.update_state(state.CONNECTED); + } + else{ + this.update_state(state.DISCONNECTED); + } + this.update_layout(); } - + public void vanish() { foreach(Dbusmenu.Menuitem item in this.custom_items){ root_menu.child_delete(item); } } + + private void update_layout() + { + bool visibility = true; + if(this.current_state != state.CONNECTED){ + visibility = false; + } + debug("about the set the visibility on both the transport and metadata widget to %s", visibility.to_string()); + this.custom_items[TRANSPORT].property_set_bool(MENUITEM_PROP_VISIBLE, visibility); + this.custom_items[METADATA].property_set_bool(MENUITEM_PROP_VISIBLE, visibility); + } + - private bool self_construct() + private void construct_widgets() { // Separator item - this.custom_items.add(PlayerItem.new_separator_item()); + this.custom_items.add(new PlayerItem(CLIENT_TYPES_SEPARATOR)); // Title item - this.custom_items.add(PlayerItem.new_title_item(this.name)); + TitleMenuitem title_menu_item = new TitleMenuitem(this, this.name); + this.custom_items.add(title_menu_item); // Metadata item MetadataMenuitem metadata_item = new MetadataMenuitem(); this.custom_items.add(metadata_item); // Transport item - TransportMenuitem transport_item = new TransportMenuitem(); + TransportMenuitem transport_item = new TransportMenuitem(this); this.custom_items.add(transport_item); int offset = 2; foreach(PlayerItem item in this.custom_items){ root_menu.child_add_position(item, offset + this.custom_items.index_of(item)); } - return true; } - + private static string format_client_name(string client_name) { string formatted = client_name; @@ -94,5 +155,5 @@ public class PlayerController : GLib.Object } return formatted; } - + }
\ No newline at end of file diff --git a/src/player-item.c b/src/player-item.c index bd9d78c..6152703 100644 --- a/src/player-item.c +++ b/src/player-item.c @@ -26,9 +26,9 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <libdbusmenu-glib/menuitem-proxy.h> #include <libdbusmenu-glib/menuitem.h> #include <libdbusmenu-glib/server.h> -#include <gee.h> #include <stdlib.h> #include <string.h> +#include <gee.h> #define TYPE_PLAYER_ITEM (player_item_get_type ()) @@ -42,65 +42,74 @@ typedef struct _PlayerItem PlayerItem; typedef struct _PlayerItemClass PlayerItemClass; typedef struct _PlayerItemPrivate PlayerItemPrivate; -#define TYPE_MPRIS_CONTROLLER (mpris_controller_get_type ()) -#define MPRIS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_MPRIS_CONTROLLER, MprisController)) -#define MPRIS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_MPRIS_CONTROLLER, MprisControllerClass)) -#define IS_MPRIS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_MPRIS_CONTROLLER)) -#define IS_MPRIS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_MPRIS_CONTROLLER)) -#define MPRIS_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_MPRIS_CONTROLLER, MprisControllerClass)) +#define TYPE_PLAYER_CONTROLLER (player_controller_get_type ()) +#define PLAYER_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PLAYER_CONTROLLER, PlayerController)) +#define PLAYER_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PLAYER_CONTROLLER, PlayerControllerClass)) +#define IS_PLAYER_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PLAYER_CONTROLLER)) +#define IS_PLAYER_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PLAYER_CONTROLLER)) +#define PLAYER_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PLAYER_CONTROLLER, PlayerControllerClass)) -typedef struct _MprisController MprisController; -typedef struct _MprisControllerClass MprisControllerClass; +typedef struct _PlayerController PlayerController; +typedef struct _PlayerControllerClass PlayerControllerClass; #define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL))) #define _g_free0(var) (var = (g_free (var), NULL)) struct _PlayerItem { DbusmenuMenuitem parent_instance; PlayerItemPrivate * priv; - MprisController* mpris_adaptor; }; struct _PlayerItemClass { DbusmenuMenuitemClass parent_class; - void (*check_layout) (PlayerItem* self); +}; + +struct _PlayerItemPrivate { + PlayerController* _owner; + char* _item_type; }; static gpointer player_item_parent_class = NULL; GType player_item_get_type (void); -GType mpris_controller_get_type (void); +GType player_controller_get_type (void); +#define PLAYER_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_PLAYER_ITEM, PlayerItemPrivate)) enum { - PLAYER_ITEM_DUMMY_PROPERTY + PLAYER_ITEM_DUMMY_PROPERTY, + PLAYER_ITEM_OWNER, + PLAYER_ITEM_ITEM_TYPE }; -PlayerItem* player_item_new (void); -PlayerItem* player_item_construct (GType object_type); +PlayerItem* player_item_new (const char* type); +PlayerItem* player_item_construct (GType object_type, const char* type); void player_item_reset (PlayerItem* self, GeeHashSet* attrs); static gboolean player_item_ensure_valid_updates (GHashTable* data, GeeHashSet* attributes); static GValue* _g_value_dup (GValue* self); char* player_item_sanitize_string (const char* st); void player_item_update (PlayerItem* self, GHashTable* data, GeeHashSet* attributes); -void player_item_set_adaptor (PlayerItem* self, MprisController* adaptor); -PlayerItem* player_item_new_title_item (const char* name); -PlayerItem* player_item_new_separator_item (void); -void player_item_check_layout (PlayerItem* self); -static void player_item_real_check_layout (PlayerItem* self); +PlayerController* player_item_get_owner (PlayerItem* self); +static void player_item_set_owner (PlayerItem* self, PlayerController* value); +const char* player_item_get_item_type (PlayerItem* self); +static void player_item_set_item_type (PlayerItem* self, const char* value); +static GObject * player_item_constructor (GType type, guint n_construct_properties, GObjectConstructParam * construct_properties); static void player_item_finalize (GObject* obj); +static void player_item_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec); +static void player_item_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec); static void _vala_array_destroy (gpointer array, gint array_length, GDestroyNotify destroy_func); static void _vala_array_free (gpointer array, gint array_length, GDestroyNotify destroy_func); static gint _vala_array_length (gpointer array); -PlayerItem* player_item_construct (GType object_type) { +PlayerItem* player_item_construct (GType object_type, const char* type) { PlayerItem * self; - self = g_object_newv (object_type, 0, NULL); + g_return_val_if_fail (type != NULL, NULL); + self = (PlayerItem*) g_object_new (object_type, "item-type", type, NULL); return self; } -PlayerItem* player_item_new (void) { - return player_item_construct (TYPE_PLAYER_ITEM); +PlayerItem* player_item_new (const char* type) { + return player_item_construct (TYPE_PLAYER_ITEM, type); } @@ -116,7 +125,7 @@ void player_item_reset (PlayerItem* self, GeeHashSet* attrs) { break; } s = (char*) gee_iterator_get (_s_it); - g_debug ("player-item.vala:33: attempting to set prop %s to null", s); + g_debug ("player-item.vala:39: attempting to set prop %s to null", s); dbusmenu_menuitem_property_set ((DbusmenuMenuitem*) self, s, NULL); _g_free0 (s); } @@ -139,9 +148,9 @@ void player_item_update (PlayerItem* self, GHashTable* data, GeeHashSet* attribu g_return_if_fail (self != NULL); g_return_if_fail (data != NULL); g_return_if_fail (attributes != NULL); - g_debug ("player-item.vala:40: PlayerItem::update()"); + g_debug ("player-item.vala:46: PlayerItem::update()"); if (player_item_ensure_valid_updates (data, attributes) == FALSE) { - g_debug ("player-item.vala:42: PlayerItem::Update -> The hashtable update does n" \ + g_debug ("player-item.vala:48: PlayerItem::Update -> The hashtable update does n" \ "ot contain what we were expecting - just leave it!"); return; } @@ -165,16 +174,16 @@ void player_item_update (PlayerItem* self, GHashTable* data, GeeHashSet* attribu property = (char*) gee_iterator_get (_property_it); input_keys = (_tmp1_ = _tmp0_ = g_strsplit (property, "-", 0), input_keys_length1 = _vala_array_length (_tmp0_), _input_keys_size_ = input_keys_length1, _tmp1_); search_key = g_strdup ((_tmp3_ = input_keys + (input_keys_length1 - 1), _tmp2_ = input_keys_length1 - (input_keys_length1 - 1), _tmp3_)[0]); - g_debug ("player-item.vala:48: search key = %s", search_key); + g_debug ("player-item.vala:54: search key = %s", search_key); v = __g_value_dup0 ((GValue*) g_hash_table_lookup (data, search_key)); if (G_VALUE_HOLDS (v, G_TYPE_STRING)) { char* _tmp4_; - g_debug ("player-item.vala:52: with value : %s", g_value_get_string (v)); + g_debug ("player-item.vala:58: with value : %s", g_value_get_string (v)); dbusmenu_menuitem_property_set ((DbusmenuMenuitem*) self, property, _tmp4_ = player_item_sanitize_string (g_value_get_string (v))); _g_free0 (_tmp4_); } else { if (G_VALUE_HOLDS (v, G_TYPE_INT)) { - g_debug ("player-item.vala:56: with value : %i", g_value_get_int (v)); + g_debug ("player-item.vala:62: with value : %i", g_value_get_int (v)); dbusmenu_menuitem_property_set_int ((DbusmenuMenuitem*) self, property, g_value_get_int (v)); } else { if (G_VALUE_HOLDS (v, G_TYPE_BOOLEAN)) { @@ -192,19 +201,6 @@ void player_item_update (PlayerItem* self, GHashTable* data, GeeHashSet* attribu } -static gpointer _g_object_ref0 (gpointer self) { - return self ? g_object_ref (self) : NULL; -} - - -void player_item_set_adaptor (PlayerItem* self, MprisController* adaptor) { - MprisController* _tmp0_; - g_return_if_fail (self != NULL); - g_return_if_fail (adaptor != NULL); - self->mpris_adaptor = (_tmp0_ = _g_object_ref0 (adaptor), _g_object_unref0 (self->mpris_adaptor), _tmp0_); -} - - static gboolean player_item_ensure_valid_updates (GHashTable* data, GeeHashSet* attributes) { gboolean result = FALSE; g_return_val_if_fail (data != NULL, FALSE); @@ -214,7 +210,7 @@ static gboolean player_item_ensure_valid_updates (GHashTable* data, GeeHashSet* return result; } if (g_hash_table_size (data) < gee_collection_get_size ((GeeCollection*) attributes)) { - g_warning ("player-item.vala:78: update hash was too small for the target"); + g_warning ("player-item.vala:77: update hash was too small for the target"); result = FALSE; return result; } @@ -276,60 +272,85 @@ char* player_item_sanitize_string (const char* st) { char* _tmp0_; _result_ = (_tmp0_ = string_slice (_result_, (glong) 7, g_utf8_strlen (_result_, -1)), _g_free0 (_result_), _tmp0_); } - g_debug ("player-item.vala:90: Sanitize string - result = %s", _result_); + g_debug ("player-item.vala:89: Sanitize string - result = %s", _result_); result = _result_; return result; } -PlayerItem* player_item_new_title_item (const char* name) { - PlayerItem* result = NULL; - PlayerItem* item; - g_return_val_if_fail (name != NULL, NULL); - item = player_item_new (); - dbusmenu_menuitem_property_set ((DbusmenuMenuitem*) item, DBUSMENU_MENUITEM_PROP_LABEL, name); - dbusmenu_menuitem_property_set ((DbusmenuMenuitem*) item, DBUSMENU_MENUITEM_PROP_ICON_NAME, "applications-multimedia"); - result = item; +PlayerController* player_item_get_owner (PlayerItem* self) { + PlayerController* result; + g_return_val_if_fail (self != NULL, NULL); + result = self->priv->_owner; return result; } -PlayerItem* player_item_new_separator_item (void) { - PlayerItem* result = NULL; - PlayerItem* separator; - separator = player_item_new (); - dbusmenu_menuitem_property_set ((DbusmenuMenuitem*) separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); - result = separator; +static gpointer _g_object_ref0 (gpointer self) { + return self ? g_object_ref (self) : NULL; +} + + +static void player_item_set_owner (PlayerItem* self, PlayerController* value) { + PlayerController* _tmp0_; + g_return_if_fail (self != NULL); + self->priv->_owner = (_tmp0_ = _g_object_ref0 (value), _g_object_unref0 (self->priv->_owner), _tmp0_); + g_object_notify ((GObject *) self, "owner"); +} + + +const char* player_item_get_item_type (PlayerItem* self) { + const char* result; + g_return_val_if_fail (self != NULL, NULL); + result = self->priv->_item_type; return result; } -static void player_item_real_check_layout (PlayerItem* self) { +static void player_item_set_item_type (PlayerItem* self, const char* value) { + char* _tmp0_; g_return_if_fail (self != NULL); - g_warning ("player-item.vala:114: this should not be hit"); + self->priv->_item_type = (_tmp0_ = g_strdup (value), _g_free0 (self->priv->_item_type), _tmp0_); + g_object_notify ((GObject *) self, "item-type"); } -void player_item_check_layout (PlayerItem* self) { - PLAYER_ITEM_GET_CLASS (self)->check_layout (self); +static GObject * player_item_constructor (GType type, guint n_construct_properties, GObjectConstructParam * construct_properties) { + GObject * obj; + GObjectClass * parent_class; + PlayerItem * self; + parent_class = G_OBJECT_CLASS (player_item_parent_class); + obj = parent_class->constructor (type, n_construct_properties, construct_properties); + self = PLAYER_ITEM (obj); + { + dbusmenu_menuitem_property_set ((DbusmenuMenuitem*) self, DBUSMENU_MENUITEM_PROP_TYPE, self->priv->_item_type); + } + return obj; } static void player_item_class_init (PlayerItemClass * klass) { player_item_parent_class = g_type_class_peek_parent (klass); - PLAYER_ITEM_CLASS (klass)->check_layout = player_item_real_check_layout; + g_type_class_add_private (klass, sizeof (PlayerItemPrivate)); + G_OBJECT_CLASS (klass)->get_property = player_item_get_property; + G_OBJECT_CLASS (klass)->set_property = player_item_set_property; + G_OBJECT_CLASS (klass)->constructor = player_item_constructor; G_OBJECT_CLASS (klass)->finalize = player_item_finalize; + g_object_class_install_property (G_OBJECT_CLASS (klass), PLAYER_ITEM_OWNER, g_param_spec_object ("owner", "owner", "owner", TYPE_PLAYER_CONTROLLER, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PLAYER_ITEM_ITEM_TYPE, g_param_spec_string ("item-type", "item-type", "item-type", NULL, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); } static void player_item_instance_init (PlayerItem * self) { + self->priv = PLAYER_ITEM_GET_PRIVATE (self); } static void player_item_finalize (GObject* obj) { PlayerItem * self; self = PLAYER_ITEM (obj); - _g_object_unref0 (self->mpris_adaptor); + _g_object_unref0 (self->priv->_owner); + _g_free0 (self->priv->_item_type); G_OBJECT_CLASS (player_item_parent_class)->finalize (obj); } @@ -346,6 +367,40 @@ GType player_item_get_type (void) { } +static void player_item_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) { + PlayerItem * self; + self = PLAYER_ITEM (object); + switch (property_id) { + case PLAYER_ITEM_OWNER: + g_value_set_object (value, player_item_get_owner (self)); + break; + case PLAYER_ITEM_ITEM_TYPE: + g_value_set_string (value, player_item_get_item_type (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void player_item_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec) { + PlayerItem * self; + self = PLAYER_ITEM (object); + switch (property_id) { + case PLAYER_ITEM_OWNER: + player_item_set_owner (self, g_value_get_object (value)); + break; + case PLAYER_ITEM_ITEM_TYPE: + player_item_set_item_type (self, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + static void _vala_array_destroy (gpointer array, gint array_length, GDestroyNotify destroy_func) { if ((array != NULL) && (destroy_func != NULL)) { int i; diff --git a/src/player-item.vala b/src/player-item.vala index a5c5512..171c140 100644 --- a/src/player-item.vala +++ b/src/player-item.vala @@ -22,10 +22,16 @@ using Gee; public class PlayerItem : Dbusmenu.Menuitem { - public MprisController mpris_adaptor; - - public PlayerItem() + public PlayerController owner {get; construct;} + public string item_type { get; construct; } + + public PlayerItem(string type) { + Object(item_type: type); + } + + construct { + this.property_set(MENUITEM_PROP_TYPE, item_type); } public void reset(HashSet<string> attrs){ @@ -60,15 +66,8 @@ public class PlayerItem : Dbusmenu.Menuitem this.property_set_bool(property, v.get_boolean()); } } - // TODO: not working - //this.check_layout(); } - public void set_adaptor(MprisController adaptor) - { - this.mpris_adaptor = adaptor; - } - private static bool ensure_valid_updates(HashTable<string, Value?> data, HashSet<string> attributes) { if(data == null){ @@ -91,27 +90,5 @@ public class PlayerItem : Dbusmenu.Menuitem return result; } - - //----- Custom constructors for player items ----------------// - // Title item - public static PlayerItem new_title_item(dynamic string name) - { - PlayerItem item = new PlayerItem(); - item.property_set(MENUITEM_PROP_LABEL, name); - item.property_set(MENUITEM_PROP_ICON_NAME, "applications-multimedia"); - return item; - } - - // Separator item - public static PlayerItem new_separator_item() - { - PlayerItem separator = new PlayerItem(); - separator.property_set(MENUITEM_PROP_TYPE, CLIENT_TYPES_SEPARATOR); - return separator; - } - - public virtual void check_layout(){ - warning("this should not be hit"); - } } diff --git a/src/title-menu-item.c b/src/title-menu-item.c new file mode 100644 index 0000000..0bf7db1 --- /dev/null +++ b/src/title-menu-item.c @@ -0,0 +1,213 @@ +/* title-menu-item.c generated by valac, the Vala compiler + * generated from title-menu-item.vala, do not modify */ + +/* +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 <glib.h> +#include <glib-object.h> +#include <libdbusmenu-glib/client.h> +#include <libdbusmenu-glib/menuitem-proxy.h> +#include <libdbusmenu-glib/menuitem.h> +#include <libdbusmenu-glib/server.h> +#include <common-defs.h> +#include <stdlib.h> +#include <string.h> +#include <gee.h> + + +#define TYPE_PLAYER_ITEM (player_item_get_type ()) +#define PLAYER_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PLAYER_ITEM, PlayerItem)) +#define PLAYER_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PLAYER_ITEM, PlayerItemClass)) +#define IS_PLAYER_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PLAYER_ITEM)) +#define IS_PLAYER_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PLAYER_ITEM)) +#define PLAYER_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PLAYER_ITEM, PlayerItemClass)) + +typedef struct _PlayerItem PlayerItem; +typedef struct _PlayerItemClass PlayerItemClass; +typedef struct _PlayerItemPrivate PlayerItemPrivate; + +#define TYPE_TITLE_MENUITEM (title_menuitem_get_type ()) +#define TITLE_MENUITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_TITLE_MENUITEM, TitleMenuitem)) +#define TITLE_MENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_TITLE_MENUITEM, TitleMenuitemClass)) +#define IS_TITLE_MENUITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_TITLE_MENUITEM)) +#define IS_TITLE_MENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_TITLE_MENUITEM)) +#define TITLE_MENUITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_TITLE_MENUITEM, TitleMenuitemClass)) + +typedef struct _TitleMenuitem TitleMenuitem; +typedef struct _TitleMenuitemClass TitleMenuitemClass; +typedef struct _TitleMenuitemPrivate TitleMenuitemPrivate; + +#define TYPE_PLAYER_CONTROLLER (player_controller_get_type ()) +#define PLAYER_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PLAYER_CONTROLLER, PlayerController)) +#define PLAYER_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PLAYER_CONTROLLER, PlayerControllerClass)) +#define IS_PLAYER_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PLAYER_CONTROLLER)) +#define IS_PLAYER_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PLAYER_CONTROLLER)) +#define PLAYER_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PLAYER_CONTROLLER, PlayerControllerClass)) + +typedef struct _PlayerController PlayerController; +typedef struct _PlayerControllerClass PlayerControllerClass; +#define _g_free0(var) (var = (g_free (var), NULL)) +typedef struct _PlayerControllerPrivate PlayerControllerPrivate; + +#define TYPE_MPRIS_CONTROLLER (mpris_controller_get_type ()) +#define MPRIS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_MPRIS_CONTROLLER, MprisController)) +#define MPRIS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_MPRIS_CONTROLLER, MprisControllerClass)) +#define IS_MPRIS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_MPRIS_CONTROLLER)) +#define IS_MPRIS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_MPRIS_CONTROLLER)) +#define MPRIS_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_MPRIS_CONTROLLER, MprisControllerClass)) + +typedef struct _MprisController MprisController; +typedef struct _MprisControllerClass MprisControllerClass; + +#define PLAYER_CONTROLLER_TYPE_STATE (player_controller_state_get_type ()) +#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL))) + +struct _PlayerItem { + DbusmenuMenuitem parent_instance; + PlayerItemPrivate * priv; +}; + +struct _PlayerItemClass { + DbusmenuMenuitemClass parent_class; +}; + +struct _TitleMenuitem { + PlayerItem parent_instance; + TitleMenuitemPrivate * priv; +}; + +struct _TitleMenuitemClass { + PlayerItemClass parent_class; +}; + +struct _PlayerController { + GObject parent_instance; + PlayerControllerPrivate * priv; + gint current_state; + GeeArrayList* custom_items; + MprisController* mpris_adaptor; +}; + +struct _PlayerControllerClass { + GObjectClass parent_class; +}; + +typedef enum { + PLAYER_CONTROLLER_STATE_OFFLINE, + PLAYER_CONTROLLER_STATE_INSTANTIATING, + PLAYER_CONTROLLER_STATE_READY, + PLAYER_CONTROLLER_STATE_CONNECTED, + PLAYER_CONTROLLER_STATE_DISCONNECTED +} PlayerControllerstate; + + +static gpointer title_menuitem_parent_class = NULL; + +GType player_item_get_type (void); +GType title_menuitem_get_type (void); +enum { + TITLE_MENUITEM_DUMMY_PROPERTY +}; +GType player_controller_get_type (void); +TitleMenuitem* title_menuitem_new (PlayerController* parent, const char* name); +TitleMenuitem* title_menuitem_construct (GType object_type, PlayerController* parent, const char* name); +PlayerController* player_item_get_owner (PlayerItem* self); +GType mpris_controller_get_type (void); +GType player_controller_state_get_type (void); +void player_controller_instantiate (PlayerController* self); +static void title_menuitem_real_handle_event (DbusmenuMenuitem* base, const char* name, GValue* input_value, guint timestamp); +GeeHashSet* title_menuitem_attributes_format (void); + + + +TitleMenuitem* title_menuitem_construct (GType object_type, PlayerController* parent, const char* name) { + TitleMenuitem * self; + g_return_val_if_fail (parent != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + self = (TitleMenuitem*) g_object_new (object_type, "item-type", DBUSMENU_TITLE_MENUITEM_TYPE, "owner", parent, NULL); + dbusmenu_menuitem_property_set ((DbusmenuMenuitem*) self, DBUSMENU_TITLE_MENUITEM_TEXT_NAME, name); + return self; +} + + +TitleMenuitem* title_menuitem_new (PlayerController* parent, const char* name) { + return title_menuitem_construct (TYPE_TITLE_MENUITEM, parent, name); +} + + +static char* bool_to_string (gboolean self) { + char* result = NULL; + if (self) { + result = g_strdup ("true"); + return result; + } else { + result = g_strdup ("false"); + return result; + } +} + + +static void title_menuitem_real_handle_event (DbusmenuMenuitem* base, const char* name, GValue* input_value, guint timestamp) { + TitleMenuitem * self; + char* _tmp0_; + self = (TitleMenuitem*) base; + g_return_if_fail (name != NULL); + g_debug ("title-menu-item.vala:34: handle_event with bool value %s", _tmp0_ = bool_to_string (g_value_get_boolean (input_value))); + _g_free0 (_tmp0_); + if (player_item_get_owner ((PlayerItem*) self)->current_state == PLAYER_CONTROLLER_STATE_OFFLINE) { + player_controller_instantiate (player_item_get_owner ((PlayerItem*) self)); + } +} + + +GeeHashSet* title_menuitem_attributes_format (void) { + GeeHashSet* result = NULL; + GeeHashSet* attrs; + attrs = gee_hash_set_new (G_TYPE_STRING, (GBoxedCopyFunc) g_strdup, g_free, NULL, NULL); + gee_abstract_collection_add ((GeeAbstractCollection*) attrs, DBUSMENU_TITLE_MENUITEM_TEXT_NAME); + result = attrs; + return result; +} + + +static void title_menuitem_class_init (TitleMenuitemClass * klass) { + title_menuitem_parent_class = g_type_class_peek_parent (klass); + DBUSMENU_MENUITEM_CLASS (klass)->handle_event = title_menuitem_real_handle_event; +} + + +static void title_menuitem_instance_init (TitleMenuitem * self) { +} + + +GType title_menuitem_get_type (void) { + static volatile gsize title_menuitem_type_id__volatile = 0; + if (g_once_init_enter (&title_menuitem_type_id__volatile)) { + static const GTypeInfo g_define_type_info = { sizeof (TitleMenuitemClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) title_menuitem_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (TitleMenuitem), 0, (GInstanceInitFunc) title_menuitem_instance_init, NULL }; + GType title_menuitem_type_id; + title_menuitem_type_id = g_type_register_static (TYPE_PLAYER_ITEM, "TitleMenuitem", &g_define_type_info, 0); + g_once_init_leave (&title_menuitem_type_id__volatile, title_menuitem_type_id); + } + return title_menuitem_type_id__volatile; +} + + + + diff --git a/src/title-menu-item.vala b/src/title-menu-item.vala new file mode 100644 index 0000000..612d279 --- /dev/null +++ b/src/title-menu-item.vala @@ -0,0 +1,48 @@ +/* +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 DbusmenuTitle; +using Gee; + +public class TitleMenuitem : PlayerItem +{ + public TitleMenuitem(PlayerController parent, string name) + { + Object(item_type: MENUITEM_TYPE, owner: parent); + this.property_set(MENUITEM_TEXT_NAME, name); + } + + public override void handle_event(string name, GLib.Value input_value, uint timestamp) + { + debug("handle_event with bool value %s", input_value.get_boolean().to_string()); + if(this.owner.current_state == PlayerController.state.OFFLINE) + { + this.owner.instantiate(); + } + } + + + public static HashSet<string> attributes_format() + { + HashSet<string> attrs = new HashSet<string>(); + attrs.add(MENUITEM_TEXT_NAME); + return attrs; + } +}
\ No newline at end of file diff --git a/src/title-widget.c b/src/title-widget.c new file mode 100644 index 0000000..1b57fe9 --- /dev/null +++ b/src/title-widget.c @@ -0,0 +1,192 @@ +/* +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 "title-widget.h" +#include "common-defs.h" +#include <gtk/gtk.h> +#include <libindicator/indicator-image-helper.h> + +static DbusmenuMenuitem* twin_item; + +typedef struct _TitleWidgetPrivate TitleWidgetPrivate; + +struct _TitleWidgetPrivate +{ + GtkWidget* hbox; + GtkWidget* name; + GtkWidget* player_icon; +}; + +#define TITLE_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TITLE_WIDGET_TYPE, TitleWidgetPrivate)) + +/* Prototypes */ +static void title_widget_class_init (TitleWidgetClass *klass); +static void title_widget_init (TitleWidget *self); +static void title_widget_dispose (GObject *object); +static void title_widget_finalize (GObject *object); + +// keyevent consumers +static gboolean title_widget_button_press_event (GtkWidget *menuitem, + GdkEventButton *event); +static gboolean title_widget_button_release_event (GtkWidget *menuitem, + GdkEventButton *event); +static gboolean title_widget_expose_event(GtkWidget* widget, + GdkEventExpose* event); + +// Dbusmenuitem properties update callback +static void title_widget_property_update(DbusmenuMenuitem* item, gchar* property, + GValue* value, gpointer userdata); +static void style_name_text(TitleWidget* self); +G_DEFINE_TYPE (TitleWidget, title_widget, GTK_TYPE_MENU_ITEM); + + + +static void +title_widget_class_init (TitleWidgetClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + widget_class->button_press_event = title_widget_button_press_event; + widget_class->button_release_event = title_widget_button_release_event; + widget_class->expose_event = title_widget_expose_event; + + g_type_class_add_private (klass, sizeof (TitleWidgetPrivate)); + + gobject_class->dispose = title_widget_dispose; + gobject_class->finalize = title_widget_finalize; + +} + +static void +title_widget_init (TitleWidget *self) +{ + g_debug("TitleWidget::title_widget_init"); + + TitleWidgetPrivate * priv = TITLE_WIDGET_GET_PRIVATE(self); + + GtkWidget *hbox; + + hbox = gtk_hbox_new(FALSE, 0); + priv->hbox = hbox; + g_signal_connect(G_OBJECT(twin_item), "property-changed", + G_CALLBACK(title_widget_property_update), self); + + priv->player_icon = indicator_image_helper("sound_icon"); + gtk_box_pack_start(GTK_BOX (priv->hbox), priv->player_icon, FALSE, FALSE, 0); + + priv->name = gtk_label_new(dbusmenu_menuitem_property_get(twin_item, + DBUSMENU_TITLE_MENUITEM_TEXT_NAME)); + gtk_misc_set_padding(GTK_MISC(priv->name), 10, 0); + gtk_box_pack_start (GTK_BOX (priv->hbox), priv->name, FALSE, FALSE, 0); + + style_name_text(self); + + gtk_widget_show_all (priv->hbox); + gtk_container_add (GTK_CONTAINER (self), hbox); + +} + +static void +title_widget_dispose (GObject *object) +{ + G_OBJECT_CLASS (title_widget_parent_class)->dispose (object); +} + +static void +title_widget_finalize (GObject *object) +{ + G_OBJECT_CLASS (title_widget_parent_class)->finalize (object); +} + +/* Suppress/consume keyevents */ +static gboolean +title_widget_button_press_event (GtkWidget *menuitem, + GdkEventButton *event) +{ + g_debug("TitleWidget::menu_press_event"); + + GValue value = {0}; + g_value_init(&value, G_TYPE_BOOLEAN); + + g_value_set_boolean(&value, TRUE); + dbusmenu_menuitem_handle_event (twin_item, "Title menu event", &value, 0); + + return TRUE; +} + +static gboolean +title_widget_button_release_event (GtkWidget *menuitem, + GdkEventButton *event) +{ + g_debug("TitleWidget::menu_release_event"); + return TRUE; +} + +static gboolean +title_widget_expose_event(GtkWidget* widget, GdkEventExpose* event) +{ + TitleWidgetPrivate * priv = TITLE_WIDGET_GET_PRIVATE(widget); + + gtk_container_propagate_expose(GTK_CONTAINER(widget), priv->hbox, event); + return TRUE; +} + +static void +title_widget_property_update(DbusmenuMenuitem* item, gchar* property, + GValue* value, gpointer userdata) +{ + g_return_if_fail (IS_TITLE_WIDGET (userdata)); + TitleWidget* mitem = TITLE_WIDGET(userdata); + TitleWidgetPrivate * priv = TITLE_WIDGET_GET_PRIVATE(mitem); + + if(g_ascii_strcasecmp(DBUSMENU_TITLE_MENUITEM_TEXT_NAME, property) == 0){ + gtk_label_set_text(GTK_LABEL(priv->name), g_value_get_string(value)); + style_name_text(mitem); + } +} + +static void +style_name_text(TitleWidget* self) +{ + TitleWidgetPrivate * priv = TITLE_WIDGET_GET_PRIVATE(self); + + char* markup; + markup = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>", + gtk_label_get_text(GTK_LABEL(priv->name))); + gtk_label_set_markup (GTK_LABEL (priv->name), markup); + g_free(markup); +} + + /** + * transport_new: + * @returns: a new #TitleWidget. + **/ +GtkWidget* +title_widget_new(DbusmenuMenuitem *item) +{ + twin_item = item; + return g_object_new(TITLE_WIDGET_TYPE, NULL); +} + diff --git a/src/title-widget.h b/src/title-widget.h new file mode 100644 index 0000000..efc0c78 --- /dev/null +++ b/src/title-widget.h @@ -0,0 +1,51 @@ +/* +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 __TITLE_WIDGET_H__ +#define __TITLE_WIDGET_H__ + +#include <gtk/gtkmenuitem.h> +#include <libdbusmenu-gtk/menu.h> + +G_BEGIN_DECLS + +#define TITLE_WIDGET_TYPE (title_widget_get_type ()) +#define TITLE_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TITLE_WIDGET_TYPE, TitleWidget)) +#define TITLE_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TITLE_WIDGET_TYPE, TitleWidgetClass)) +#define IS_TITLE_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TITLE_WIDGET_TYPE)) +#define IS_TITLE_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TITLE_WIDGET_TYPE)) +#define TITLE_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TITLE_WIDGET_TYPE, TitleWidgetClass)) + +typedef struct _TitleWidget TitleWidget; +typedef struct _TitleWidgetClass TitleWidgetClass; + +struct _TitleWidgetClass { + GtkMenuItemClass parent_class; +}; + +struct _TitleWidget { + GtkMenuItem parent; +}; + +GType title_widget_get_type (void); +GtkWidget* title_widget_new(DbusmenuMenuitem *twin_item); + +G_END_DECLS + +#endif + diff --git a/src/transport-menu-item.c b/src/transport-menu-item.c index 96d3576..48c437a 100644 --- a/src/transport-menu-item.c +++ b/src/transport-menu-item.c @@ -27,9 +27,9 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <libdbusmenu-glib/menuitem.h> #include <libdbusmenu-glib/server.h> #include <common-defs.h> +#include <gee.h> #include <stdlib.h> #include <string.h> -#include <gee.h> #define TYPE_PLAYER_ITEM (player_item_get_type ()) @@ -43,16 +43,6 @@ typedef struct _PlayerItem PlayerItem; typedef struct _PlayerItemClass PlayerItemClass; typedef struct _PlayerItemPrivate PlayerItemPrivate; -#define TYPE_MPRIS_CONTROLLER (mpris_controller_get_type ()) -#define MPRIS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_MPRIS_CONTROLLER, MprisController)) -#define MPRIS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_MPRIS_CONTROLLER, MprisControllerClass)) -#define IS_MPRIS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_MPRIS_CONTROLLER)) -#define IS_MPRIS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_MPRIS_CONTROLLER)) -#define MPRIS_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_MPRIS_CONTROLLER, MprisControllerClass)) - -typedef struct _MprisController MprisController; -typedef struct _MprisControllerClass MprisControllerClass; - #define TYPE_TRANSPORT_MENUITEM (transport_menuitem_get_type ()) #define TRANSPORT_MENUITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_TRANSPORT_MENUITEM, TransportMenuitem)) #define TRANSPORT_MENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_TRANSPORT_MENUITEM, TransportMenuitemClass)) @@ -63,18 +53,39 @@ typedef struct _MprisControllerClass MprisControllerClass; typedef struct _TransportMenuitem TransportMenuitem; typedef struct _TransportMenuitemClass TransportMenuitemClass; typedef struct _TransportMenuitemPrivate TransportMenuitemPrivate; + +#define TRANSPORT_MENUITEM_TYPE_ACTION (transport_menuitem_action_get_type ()) + +#define TYPE_PLAYER_CONTROLLER (player_controller_get_type ()) +#define PLAYER_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PLAYER_CONTROLLER, PlayerController)) +#define PLAYER_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PLAYER_CONTROLLER, PlayerControllerClass)) +#define IS_PLAYER_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PLAYER_CONTROLLER)) +#define IS_PLAYER_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PLAYER_CONTROLLER)) +#define PLAYER_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PLAYER_CONTROLLER, PlayerControllerClass)) + +typedef struct _PlayerController PlayerController; +typedef struct _PlayerControllerClass PlayerControllerClass; #define _g_free0(var) (var = (g_free (var), NULL)) +typedef struct _PlayerControllerPrivate PlayerControllerPrivate; + +#define TYPE_MPRIS_CONTROLLER (mpris_controller_get_type ()) +#define MPRIS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_MPRIS_CONTROLLER, MprisController)) +#define MPRIS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_MPRIS_CONTROLLER, MprisControllerClass)) +#define IS_MPRIS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_MPRIS_CONTROLLER)) +#define IS_MPRIS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_MPRIS_CONTROLLER)) +#define MPRIS_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_MPRIS_CONTROLLER, MprisControllerClass)) + +typedef struct _MprisController MprisController; +typedef struct _MprisControllerClass MprisControllerClass; #define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL))) struct _PlayerItem { DbusmenuMenuitem parent_instance; PlayerItemPrivate * priv; - MprisController* mpris_adaptor; }; struct _PlayerItemClass { DbusmenuMenuitemClass parent_class; - void (*check_layout) (PlayerItem* self); }; struct _TransportMenuitem { @@ -86,38 +97,67 @@ struct _TransportMenuitemClass { PlayerItemClass parent_class; }; +typedef enum { + TRANSPORT_MENUITEM_ACTION_PREVIOUS, + TRANSPORT_MENUITEM_ACTION_PLAY_PAUSE, + TRANSPORT_MENUITEM_ACTION_NEXT +} TransportMenuitemaction; + +struct _PlayerController { + GObject parent_instance; + PlayerControllerPrivate * priv; + gint current_state; + GeeArrayList* custom_items; + MprisController* mpris_adaptor; +}; + +struct _PlayerControllerClass { + GObjectClass parent_class; +}; + static gpointer transport_menuitem_parent_class = NULL; GType player_item_get_type (void); -GType mpris_controller_get_type (void); GType transport_menuitem_get_type (void); enum { TRANSPORT_MENUITEM_DUMMY_PROPERTY }; -PlayerItem* player_item_new (void); -PlayerItem* player_item_construct (GType object_type); -TransportMenuitem* transport_menuitem_new (void); -TransportMenuitem* transport_menuitem_construct (GType object_type); +GType transport_menuitem_action_get_type (void); +GType player_controller_get_type (void); +TransportMenuitem* transport_menuitem_new (PlayerController* parent); +TransportMenuitem* transport_menuitem_construct (GType object_type, PlayerController* parent); void transport_menuitem_change_play_state (TransportMenuitem* self, gint state); -void mpris_controller_toggle_playback (MprisController* self, gboolean state); +PlayerController* player_item_get_owner (PlayerItem* self); +GType mpris_controller_get_type (void); +void mpris_controller_transport_event (MprisController* self, TransportMenuitemaction command); static void transport_menuitem_real_handle_event (DbusmenuMenuitem* base, const char* name, GValue* input_value, guint timestamp); -static void transport_menuitem_real_check_layout (PlayerItem* base); GeeHashSet* transport_menuitem_attributes_format (void); -TransportMenuitem* transport_menuitem_construct (GType object_type) { +GType transport_menuitem_action_get_type (void) { + static volatile gsize transport_menuitem_action_type_id__volatile = 0; + if (g_once_init_enter (&transport_menuitem_action_type_id__volatile)) { + static const GEnumValue values[] = {{TRANSPORT_MENUITEM_ACTION_PREVIOUS, "TRANSPORT_MENUITEM_ACTION_PREVIOUS", "previous"}, {TRANSPORT_MENUITEM_ACTION_PLAY_PAUSE, "TRANSPORT_MENUITEM_ACTION_PLAY_PAUSE", "play-pause"}, {TRANSPORT_MENUITEM_ACTION_NEXT, "TRANSPORT_MENUITEM_ACTION_NEXT", "next"}, {0, NULL, NULL}}; + GType transport_menuitem_action_type_id; + transport_menuitem_action_type_id = g_enum_register_static ("TransportMenuitemaction", values); + g_once_init_leave (&transport_menuitem_action_type_id__volatile, transport_menuitem_action_type_id); + } + return transport_menuitem_action_type_id__volatile; +} + + +TransportMenuitem* transport_menuitem_construct (GType object_type, PlayerController* parent) { TransportMenuitem * self; - self = (TransportMenuitem*) player_item_construct (object_type); - dbusmenu_menuitem_property_set ((DbusmenuMenuitem*) self, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_TRANSPORT_MENUITEM_TYPE); - g_debug ("transport-menu-item.vala:30: transport on the vala side"); + g_return_val_if_fail (parent != NULL, NULL); + self = (TransportMenuitem*) g_object_new (object_type, "item-type", DBUSMENU_TRANSPORT_MENUITEM_TYPE, "owner", parent, NULL); return self; } -TransportMenuitem* transport_menuitem_new (void) { - return transport_menuitem_construct (TYPE_TRANSPORT_MENUITEM); +TransportMenuitem* transport_menuitem_new (PlayerController* parent) { + return transport_menuitem_construct (TYPE_TRANSPORT_MENUITEM, parent); } @@ -127,32 +167,16 @@ void transport_menuitem_change_play_state (TransportMenuitem* self, gint state) } -static char* bool_to_string (gboolean self) { - char* result = NULL; - if (self) { - result = g_strdup ("true"); - return result; - } else { - result = g_strdup ("false"); - return result; - } -} - - static void transport_menuitem_real_handle_event (DbusmenuMenuitem* base, const char* name, GValue* input_value, guint timestamp) { TransportMenuitem * self; + gint input; char* _tmp0_; self = (TransportMenuitem*) base; g_return_if_fail (name != NULL); - g_debug ("transport-menu-item.vala:40: handle_event with bool value %s", _tmp0_ = bool_to_string (g_value_get_boolean (input_value))); + input = g_value_get_int (input_value); + g_debug ("transport-menu-item.vala:45: handle_event with value %s", _tmp0_ = g_strdup_printf ("%i", input)); _g_free0 (_tmp0_); - mpris_controller_toggle_playback (((PlayerItem*) self)->mpris_adaptor, g_value_get_boolean (input_value)); -} - - -static void transport_menuitem_real_check_layout (PlayerItem* base) { - TransportMenuitem * self; - self = (TransportMenuitem*) base; + mpris_controller_transport_event (player_item_get_owner ((PlayerItem*) self)->mpris_adaptor, (TransportMenuitemaction) input); } @@ -169,7 +193,6 @@ GeeHashSet* transport_menuitem_attributes_format (void) { static void transport_menuitem_class_init (TransportMenuitemClass * klass) { transport_menuitem_parent_class = g_type_class_peek_parent (klass); DBUSMENU_MENUITEM_CLASS (klass)->handle_event = transport_menuitem_real_handle_event; - PLAYER_ITEM_CLASS (klass)->check_layout = transport_menuitem_real_check_layout; } diff --git a/src/transport-menu-item.vala b/src/transport-menu-item.vala index 264e153..e0710a8 100644 --- a/src/transport-menu-item.vala +++ b/src/transport-menu-item.vala @@ -23,11 +23,15 @@ using DbusmenuTransport; public class TransportMenuitem : PlayerItem { + public enum action{ + PREVIOUS, + PLAY_PAUSE, + NEXT + } - public TransportMenuitem() + public TransportMenuitem(PlayerController parent) { - this.property_set(MENUITEM_PROP_TYPE, MENUITEM_TYPE); - debug("transport on the vala side"); + Object(item_type: MENUITEM_TYPE, owner: parent); } public void change_play_state(int state) @@ -37,14 +41,11 @@ public class TransportMenuitem : PlayerItem public override void handle_event(string name, GLib.Value input_value, uint timestamp) { - debug("handle_event with bool value %s", input_value.get_boolean().to_string()); - this.mpris_adaptor.toggle_playback(input_value.get_boolean()); - } - - public override void check_layout(){ - // nothing to be done for this item - always active - } - + int input = input_value.get_int(); + debug("handle_event with value %s", input.to_string()); + // Fire and forgot - the widget would not have sent it over it didn't think it was relevant. + this.owner.mpris_adaptor.transport_event((action)input); + } public static HashSet<string> attributes_format() { diff --git a/src/transport-widget.c b/src/transport-widget.c index bc9df53..9852b50 100644 --- a/src/transport-widget.c +++ b/src/transport-widget.c @@ -25,8 +25,8 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include "transport-widget.h" #include "common-defs.h" #include <gtk/gtk.h> +#include "play-button.h" -// TODO: think about leakage: ted ! static DbusmenuMenuitem* twin_item; @@ -38,16 +38,6 @@ struct _TransportWidgetPrivate GtkWidget* play_button; }; -enum { - PLAY, - PAUSE, - NEXT, - PREVIOUS, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - #define TRANSPORT_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRANSPORT_WIDGET_TYPE, TransportWidgetPrivate)) /* Gobject boiler plate */ @@ -55,26 +45,20 @@ 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); +static gboolean transport_widget_expose_event(GtkWidget* widget, GdkEventExpose* event); /* 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 void transport_widget_play_clicked (GtkWidget* button, - TransportWidget* self); - + GdkEventButton *event); static void transport_widget_property_update(DbusmenuMenuitem* item, - gchar * property, - GValue * value, - gpointer userdata); -// utility methods -static gchar* transport_widget_toggle_play_label(gint state); + gchar * property, + GValue * value, + gpointer userdata); G_DEFINE_TYPE (TransportWidget, transport_widget, GTK_TYPE_MENU_ITEM); - - static void transport_widget_class_init (TransportWidgetClass *klass) { @@ -84,45 +68,12 @@ transport_widget_class_init (TransportWidgetClass *klass) menu_item_class->hide_on_activate = FALSE; widget_class->button_press_event = transport_widget_button_press_event; - widget_class->button_release_event = transport_widget_button_release_event; - + widget_class->button_release_event = transport_widget_button_release_event; + widget_class->expose_event = transport_widget_expose_event; g_type_class_add_private (klass, sizeof (TransportWidgetPrivate)); gobject_class->dispose = transport_widget_dispose; gobject_class->finalize = transport_widget_finalize; - - signals[PLAY] = g_signal_new ("play", - G_OBJECT_CLASS_TYPE (gobject_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[PAUSE] = g_signal_new ("pause", - G_OBJECT_CLASS_TYPE (gobject_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - - signals[NEXT] = g_signal_new ("next", - G_OBJECT_CLASS_TYPE (gobject_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[PREVIOUS] = g_signal_new ("previous", - G_OBJECT_CLASS_TYPE (gobject_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); } static void @@ -131,19 +82,19 @@ transport_widget_init (TransportWidget *self) g_debug("TransportWidget::transport_widget_init"); TransportWidgetPrivate * priv = TRANSPORT_WIDGET_GET_PRIVATE(self); - GtkWidget *hbox; + GtkWidget* hbox; hbox = gtk_hbox_new(TRUE, 2); - gchar* symbol = transport_widget_toggle_play_label(dbusmenu_menuitem_property_get_int(twin_item, DBUSMENU_TRANSPORT_MENUITEM_PLAY_STATE)); - priv->play_button = gtk_button_new_with_label(symbol); - //g_free(symbol); - gtk_box_pack_start (GTK_BOX (hbox), priv->play_button, FALSE, TRUE, 0); + GtkStyle* style = gtk_rc_get_style(GTK_WIDGET(self)); + priv->hbox = hbox; + priv->play_button = play_button_new(); + play_button_set_style(priv->play_button, style); + + gtk_box_pack_start (GTK_BOX (priv->hbox), priv->play_button, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(twin_item), "property-changed", G_CALLBACK(transport_widget_property_update), self); - - g_signal_connect(priv->play_button, "clicked", G_CALLBACK(transport_widget_play_clicked), self); gtk_container_add (GTK_CONTAINER (self), priv->hbox); @@ -162,6 +113,15 @@ transport_widget_finalize (GObject *object) G_OBJECT_CLASS (transport_widget_parent_class)->finalize (object); } +static gboolean +transport_widget_expose_event(GtkWidget* widget, GdkEventExpose* event) +{ + //TransportWidgetPrivate * priv = TRANSPORT_WIDGET_GET_PRIVATE(widget); + //gtk_container_propagate_expose(GTK_CONTAINER(widget),priv->play_button, event); + return TRUE; +} + + /* keyevents */ static gboolean transport_widget_button_press_event (GtkWidget *menuitem, @@ -174,26 +134,26 @@ transport_widget_button_press_event (GtkWidget *menuitem, TransportWidgetPrivate * priv = TRANSPORT_WIDGET_GET_PRIVATE(TRANSPORT_WIDGET(menuitem)); - gtk_widget_event (priv->hbox, (GdkEvent*)event); - gboolean state = g_ascii_strcasecmp(gtk_button_get_label(GTK_BUTTON(priv->play_button)), ">") == 0; + GtkWidget *parent; - gtk_button_set_label(GTK_BUTTON(priv->play_button), transport_widget_toggle_play_label((gint)state)); - GValue value = {0}; - g_value_init(&value, G_TYPE_BOOLEAN); - g_debug("TransportWidget::menu_press_event - going to send value %i", state); + // can we block emissions of "grab-notify" on parent?? + parent = gtk_widget_get_parent (GTK_WIDGET (menuitem)); + gint result = determine_button_event(priv->play_button, event); + + //GTK_OBJECT_FLAGS (scale) |= GTK_HAS_GRAB; + //gtk_widget_event (scale, + //((GdkEvent *)(void*)(event))); + //GTK_OBJECT_FLAGS (scale) &= ~(GTK_HAS_GRAB); - g_value_set_boolean(&value, state); + GValue value = {0}; + g_value_init(&value, G_TYPE_INT); + g_debug("TransportWidget::menu_press_event - going to send value %i", result); + g_value_set_int(&value, result); dbusmenu_menuitem_handle_event (twin_item, "Transport state change", &value, 0); return TRUE; } -static void -transport_widget_play_clicked(GtkWidget* button, - TransportWidget* self) -{ - g_debug("Transport_widget_play_clicked"); -} static gboolean transport_widget_button_release_event (GtkWidget *menuitem, @@ -203,9 +163,6 @@ transport_widget_button_release_event (GtkWidget *menuitem, if(IS_TRANSPORT_WIDGET(menuitem) == FALSE){ return FALSE; } - - TransportWidgetPrivate * priv = TRANSPORT_WIDGET_GET_PRIVATE(TRANSPORT_WIDGET(menuitem)); - gtk_widget_event (priv->hbox, (GdkEvent*)event); return TRUE; } @@ -219,23 +176,12 @@ transport_widget_property_update(DbusmenuMenuitem* item, gchar* property, GValue* value, gpointer userdata) { g_debug("transport_widget_update_state - with property %s", property); - int update_value = g_value_get_int(value); - g_debug("transport_widget_update_state - with value %i", update_value); + //int update_value = g_value_get_int(value); + //g_debug("transport_widget_update_state - with value %i", update_value); - TransportWidget* bar = (TransportWidget*)userdata; - TransportWidgetPrivate *priv = TRANSPORT_WIDGET_GET_PRIVATE(bar); + //TransportWidget* bar = (TransportWidget*)userdata; + //TransportWidgetPrivate *priv = TRANSPORT_WIDGET_GET_PRIVATE(bar); - gtk_button_set_label(GTK_BUTTON(priv->play_button), transport_widget_toggle_play_label(update_value)); -} - -// will be needed for image swapping -static gchar* transport_widget_toggle_play_label(int play_state) -{ - gchar* label = ">"; - if(play_state == 1){ - label = "||"; - } - return label; } /** diff --git a/vapi/common-defs.vapi b/vapi/common-defs.vapi index 222fb67..6649b26 100644 --- a/vapi/common-defs.vapi +++ b/vapi/common-defs.vapi @@ -30,4 +30,10 @@ namespace DbusmenuMetadata{ namespace DbusmenuTransport{ public const string MENUITEM_TYPE; public const string MENUITEM_PLAY_STATE; +} + +[CCode (cheader_filename = "common-defs.h")] +namespace DbusmenuTitle{ + public const string MENUITEM_TYPE; + public const string MENUITEM_TEXT_NAME; }
\ No newline at end of file |