diff options
32 files changed, 2553 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/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 |