diff options
-rw-r--r-- | .pc/.version | 1 | ||||
-rw-r--r-- | .pc/applied-patches | 3 | ||||
-rw-r--r-- | .pc/dbusmenu_05_90.patch/configure.ac | 191 | ||||
-rw-r--r-- | .pc/dbusmenu_05_90.patch/src/indicator-sound.c | 772 | ||||
-rw-r--r-- | .pc/dbusmenu_05_90.patch/src/metadata-widget.h | 55 | ||||
-rw-r--r-- | .pc/dbusmenu_05_90.patch/src/mute-widget.h | 67 | ||||
-rw-r--r-- | .pc/dbusmenu_05_90.patch/src/transport-widget.h | 71 | ||||
-rw-r--r-- | .pc/dbusmenu_05_90.patch/src/voip-input-widget.h | 60 | ||||
-rw-r--r-- | .pc/dbusmenu_05_90.patch/src/volume-widget.h | 62 | ||||
-rw-r--r-- | .pc/lazy_init.patch/src/sound-state-manager.c | 473 | ||||
-rw-r--r-- | .pc/sound_nua.patch/src/sound-service-dbus.c | 480 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/indicator-sound.c | 4 | ||||
-rw-r--r-- | src/metadata-widget.h | 4 | ||||
-rw-r--r-- | src/mute-widget.h | 4 | ||||
-rw-r--r-- | src/sound-service-dbus.c | 2 | ||||
-rw-r--r-- | src/sound-state-manager.c | 11 | ||||
-rw-r--r-- | src/transport-widget.h | 4 | ||||
-rw-r--r-- | src/voip-input-widget.h | 4 | ||||
-rw-r--r-- | src/volume-widget.h | 4 |
20 files changed, 2246 insertions, 28 deletions
diff --git a/.pc/.version b/.pc/.version new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/.pc/applied-patches b/.pc/applied-patches new file mode 100644 index 0000000..424fc6e --- /dev/null +++ b/.pc/applied-patches @@ -0,0 +1,3 @@ +lazy_init.patch +sound_nua.patch +dbusmenu_05_90.patch diff --git a/.pc/dbusmenu_05_90.patch/configure.ac b/.pc/dbusmenu_05_90.patch/configure.ac new file mode 100644 index 0000000..0e88562 --- /dev/null +++ b/.pc/dbusmenu_05_90.patch/configure.ac @@ -0,0 +1,191 @@ + +AC_INIT(indicator-sound, 0.8.0.0, conor.curran@canonical.com) + +AC_PREREQ(2.53) + +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(indicator-sound, 0.8.0.0) + +AM_MAINTAINER_MODE + +IT_PROG_INTLTOOL([0.35.0]) +AM_PROG_VALAC([0.11.2]) +AS_IF([test -z "$VALAC"], [AC_MSG_ERROR(["No valac compiler found."])]) + +AC_ISC_POSIX +AC_PROG_CC +AM_PROG_CC_C_O +AC_STDC_HEADERS +AC_PROG_LIBTOOL + +AC_SUBST(VERSION) +AC_CONFIG_MACRO_DIR([m4]) + +m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) + +AC_PATH_PROG([GLIB_GENMARSHAL], [glib-genmarshal]) + +########################### +# GTK+ version option +########################### + +AC_ARG_WITH([gtk], + [AS_HELP_STRING([--with-gtk], + [Which version of gtk to use for the indicator @<:@default=3@:>@])], + [], + [with_gtk=3]) + +########################### +# Dependencies +########################### + +GTK_REQUIRED_VERSION=2.22 +GTK3_REQUIRED_VERSION=3.0 +INDICATOR_REQUIRED_VERSION=0.3.19 +DBUSMENUGTK_REQUIRED_VERSION=0.3.101 +POLKIT_REQUIRED_VERSION=0.92 +PULSE_AUDIO_REQUIRED_VERSION=0.9.19 +INDICATOR_DISPLAY_OBJECTS=0.1.11 +DBUSMENUGLIB_REQUIRED_VERSION=0.3.101 +GIO_2_0_REQUIRED_VERSION=2.25.13 +LIBNOTIFY_REQUIRED_VERSION=0.7.0 + +PKG_CHECK_MODULES(PULSEAUDIO, libpulse-mainloop-glib >= $PULSE_AUDIO_REQUIRED_VERSION + gio-unix-2.0) +AC_SUBST(PULSEAUDIO_CFLAGS) +AC_SUBST(PULSEAUDIO_LIBS) + +AS_IF([test "x$with_gtk" = x3], + [PKG_CHECK_MODULES(APPLET, gtk+-3.0 >= $GTK3_REQUIRED_VERSION + indicator3-0.4 >= $INDICATOR_REQUIRED_VERSION + dbusmenu-gtk3-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION + libido3-0.1 >= $INDICATOR_DISPLAY_OBJECTS + libnotify >= $LIBNOTIFY_REQUIRED_VERSION) + + PKG_CHECK_MODULES(SOUNDSERVICE, dbusmenu-glib-0.4 >= $DBUSMENUGLIB_REQUIRED_VERSION + indicator3-0.4 + gee-1.0 + gio-unix-2.0 + libxml-2.0) + ], + [test "x$with_gtk" = x2], + [PKG_CHECK_MODULES(APPLET, gtk+-2.0 >= $GTK_REQUIRED_VERSION + indicator-0.4 >= $INDICATOR_REQUIRED_VERSION + dbusmenu-gtk-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION + libido-0.1 >= $INDICATOR_DISPLAY_OBJECTS + libnotify >= $LIBNOTIFY_REQUIRED_VERSION) + + PKG_CHECK_MODULES(SOUNDSERVICE, dbusmenu-glib-0.4 >= $DBUSMENUGLIB_REQUIRED_VERSION + indicator-0.4 + gee-1.0 + gio-unix-2.0 + libxml-2.0) + ], + [AC_MSG_FAILURE([Value for --with-gtk was neither 2 nor 3])] +) +AC_SUBST(APPLET_CFLAGS) +AC_SUBST(APPLET_LIBS) + +AC_SUBST(SOUNDSERVICE_CFLAGS) +AC_SUBST(SOUNDSERVICE_LIBS) + +########################### +# Check to see if we're local +########################### + +with_localinstall="no" +AC_ARG_ENABLE(localinstall, AS_HELP_STRING([--enable-localinstall], [install all of the files localy instead of system directories (for distcheck)]), with_localinstall=$enableval, with_localinstall=no) + +########################### +# Indicator Info +########################### + +AS_IF([test "x$with_localinstall" = "xyes"], + [ + INDICATORDIR="${libdir}/indicators/2/" + INDICATORICONSDIR="${datadir}/indicator-sound/icons/" + ], + [AS_IF([test "x$with_gtk" = "x2"], + [ + INDICATORDIR=`$PKG_CONFIG --variable=indicatordir indicator-0.4` + INDICATORICONSDIR=`$PKG_CONFIG --variable=iconsdir indicator-0.4` + ], + [ + INDICATORDIR=`$PKG_CONFIG --variable=indicatordir indicator3-0.4` + INDICATORICONSDIR=`$PKG_CONFIG --variable=iconsdir indicator3-0.4` + ])]) +AC_SUBST(INDICATORDIR) +AC_SUBST(INDICATORICONSDIR) + +########################### +# Grab the GSettings Macros +########################### + +GLIB_GSETTINGS +GLIB_GENMARSHAL + +########################### +# DBus Service Info +########################### + +if test "x$with_localinstall" = "xyes"; then + DBUSSERVICEDIR="${datadir}/dbus-1/services/" +else + DBUSSERVICEDIR=`$PKG_CONFIG --variable=session_bus_services_dir dbus-1` +fi +AC_SUBST(DBUSSERVICEDIR) + +############################## +# Custom Junk +############################## + +AC_DEFUN([AC_DEFINE_PATH], [ + test "x$prefix" = xNONE && prefix="$ac_default_prefix" + test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + ac_define_path=`eval echo [$]$2` + ac_define_path=`eval echo [$]ac_define_path` + $1="$ac_define_path" + AC_SUBST($1) + ifelse($3, , + AC_DEFINE_UNQUOTED($1, "$ac_define_path"), + AC_DEFINE_UNQUOTED($1, "$ac_define_path", $3)) +]) + +########################### +# Internationalization +########################### + +GETTEXT_PACKAGE=indicator-sound +AC_SUBST(GETTEXT_PACKAGE) +AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Name of the default get text domain]) +AC_DEFINE_PATH(GNOMELOCALEDIR, "${datadir}/locale", [locale directory]) + +AM_GLIB_GNU_GETTEXT + +########################### +# Files +########################### + +AC_OUTPUT([ +Makefile +src/Makefile +data/Makefile +data/icons/Makefile +data/icons/16x16/Makefile +data/icons/16x16/status/Makefile +data/icons/scalable/Makefile +data/icons/scalable/status/Makefile +po/Makefile.in +]) + +########################### +# Results +########################### + +AC_MSG_NOTICE([ + +SUS Indicator Configuration: + + Prefix: $prefix + GTK+: $with_gtk +]) diff --git a/.pc/dbusmenu_05_90.patch/src/indicator-sound.c b/.pc/dbusmenu_05_90.patch/src/indicator-sound.c new file mode 100644 index 0000000..b953449 --- /dev/null +++ b/.pc/dbusmenu_05_90.patch/src/indicator-sound.c @@ -0,0 +1,772 @@ +/* +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 <math.h> +#include <glib.h> +#include <glib-object.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> +#if GTK_CHECK_VERSION(3, 0, 0) +#include <libdbusmenu-gtk3/menu.h> +#else +#include <libdbusmenu-gtk/menu.h> +#endif +#include <libido/idoscalemenuitem.h> + +#include <gio/gio.h> + +#include "indicator-sound.h" +#include "transport-widget.h" +#include "metadata-widget.h" +#include "volume-widget.h" +#include "voip-input-widget.h" +#include "dbus-shared-names.h" +#include "sound-state-manager.h" +#include "mute-widget.h" + +#include "gen-sound-service.xml.h" +#include "common-defs.h" + +typedef struct _IndicatorSoundPrivate IndicatorSoundPrivate; + +struct _IndicatorSoundPrivate +{ + GtkWidget* volume_widget; + GtkWidget* voip_widget; + MuteWidget *mute_widget; + GList* transport_widgets_list; + GDBusProxy *dbus_proxy; + SoundStateManager* state_manager; + gchar *accessible_desc; +}; + +#define INDICATOR_SOUND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_SOUND_TYPE, IndicatorSoundPrivate)) + +// GObject Boiler plate +INDICATOR_SET_VERSION +INDICATOR_SET_TYPE(INDICATOR_SOUND_TYPE) + +// GObject Boiler plate +static void indicator_sound_class_init (IndicatorSoundClass *klass); +static void indicator_sound_init (IndicatorSound *self); +static void indicator_sound_dispose (GObject *object); +static void indicator_sound_finalize (GObject *object); +G_DEFINE_TYPE (IndicatorSound, indicator_sound, INDICATOR_OBJECT_TYPE); + +//GTK+ items +static GtkLabel * get_label (IndicatorObject * io); +static GtkImage * get_icon (IndicatorObject * io); +static GtkMenu * get_menu (IndicatorObject * io); +static const gchar * get_accessible_desc (IndicatorObject * io); +static const gchar * get_name_hint (IndicatorObject * io); +static void indicator_sound_scroll (IndicatorObject * io, + IndicatorObjectEntry * entry, gint delta, + IndicatorScrollDirection direction); +static void indicator_sound_middle_click (IndicatorObject * io, + IndicatorObjectEntry * entry, + guint time, gpointer data); + +//key/moust event handlers +static gboolean key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data); +static gboolean key_release_cb(GtkWidget* widget, GdkEventKey* event, gpointer data); + +//custom widget realisation methods +static gboolean new_volume_slider_widget (DbusmenuMenuitem * newitem, + DbusmenuMenuitem * parent, + DbusmenuClient * client, + gpointer user_data); +static gboolean new_voip_slider_widget (DbusmenuMenuitem * newitem, + DbusmenuMenuitem * parent, + DbusmenuClient * client, + gpointer user_data); +static gboolean new_transport_widget (DbusmenuMenuitem * newitem, + DbusmenuMenuitem * parent, + DbusmenuClient * client, + gpointer user_data); +static gboolean new_metadata_widget (DbusmenuMenuitem * newitem, + DbusmenuMenuitem * parent, + DbusmenuClient * client, + gpointer user_data); +static gboolean new_mute_widget (DbusmenuMenuitem * newitem, + DbusmenuMenuitem * parent, + DbusmenuClient * client, + gpointer user_data); + +// DBUS communication +static GDBusNodeInfo *node_info = NULL; +static GDBusInterfaceInfo *interface_info = NULL; +static void create_connection_to_service (GObject *source_object, + GAsyncResult *res, + gpointer user_data); +static void connection_changed (IndicatorServiceManager * sm, + gboolean connected, + gpointer userdata); + +static void +indicator_sound_class_init (IndicatorSoundClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = indicator_sound_dispose; + object_class->finalize = indicator_sound_finalize; + + IndicatorObjectClass *io_class = INDICATOR_OBJECT_CLASS(klass); + + g_type_class_add_private (klass, sizeof (IndicatorSoundPrivate)); + + io_class->get_label = get_label; + io_class->get_image = get_icon; + io_class->get_menu = get_menu; + io_class->get_accessible_desc = get_accessible_desc; + io_class->get_name_hint = get_name_hint; + io_class->entry_scrolled = indicator_sound_scroll; + io_class->secondary_activate = indicator_sound_middle_click; +} + +static void +indicator_sound_init (IndicatorSound *self) +{ + self->service = NULL; + self->service = indicator_service_manager_new_version(INDICATOR_SOUND_DBUS_NAME, + INDICATOR_SOUND_DBUS_VERSION); + + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self); + priv->volume_widget = NULL; + priv->voip_widget = NULL; + priv->mute_widget = NULL; + priv->dbus_proxy = NULL; + GList* t_list = NULL; + priv->transport_widgets_list = t_list; + priv->state_manager = g_object_new (SOUND_TYPE_STATE_MANAGER, NULL); + priv->accessible_desc = NULL; + + g_signal_connect ( G_OBJECT(self->service), + INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, + G_CALLBACK(connection_changed), self ); +} + +static void +indicator_sound_dispose (GObject *object) +{ + IndicatorSound * self = INDICATOR_SOUND(object); + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self); + + if (self->service != NULL) { + g_object_unref(G_OBJECT(self->service)); + self->service = NULL; + } + g_list_free (priv->transport_widgets_list); + + G_OBJECT_CLASS (indicator_sound_parent_class)->dispose (object); +} + +static void +indicator_sound_finalize (GObject *object) +{ + IndicatorSound * self = INDICATOR_SOUND(object); + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self); + + if (priv->accessible_desc) { + g_free (priv->accessible_desc); + priv->accessible_desc = NULL; + } + + G_OBJECT_CLASS (indicator_sound_parent_class)->finalize (object); +} + +static GtkLabel * +get_label (IndicatorObject * io) +{ + return NULL; +} + +static GtkImage * +get_icon (IndicatorObject * io) +{ + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io)); + gtk_widget_show( GTK_WIDGET(sound_state_manager_get_current_icon (priv->state_manager)) ); + return sound_state_manager_get_current_icon (priv->state_manager); +} + +/* Indicator based function to get the menu for the whole + applet. This starts up asking for the parts of the menu + from the various services. */ +static GtkMenu * +get_menu (IndicatorObject * io) +{ + DbusmenuGtkMenu* menu = dbusmenu_gtkmenu_new(INDICATOR_SOUND_DBUS_NAME, + INDICATOR_SOUND_MENU_DBUS_OBJECT_PATH); + + DbusmenuGtkClient *client = dbusmenu_gtkmenu_get_client(menu); + g_object_set_data (G_OBJECT (client), "indicator", io); + dbusmenu_client_add_type_handler (DBUSMENU_CLIENT(client), + DBUSMENU_VOLUME_MENUITEM_TYPE, + new_volume_slider_widget); + dbusmenu_client_add_type_handler (DBUSMENU_CLIENT(client), + DBUSMENU_VOIP_INPUT_MENUITEM_TYPE, + new_voip_slider_widget); + dbusmenu_client_add_type_handler (DBUSMENU_CLIENT(client), + DBUSMENU_TRANSPORT_MENUITEM_TYPE, + new_transport_widget); + dbusmenu_client_add_type_handler (DBUSMENU_CLIENT(client), + DBUSMENU_METADATA_MENUITEM_TYPE, + new_metadata_widget); + dbusmenu_client_add_type_handler (DBUSMENU_CLIENT(client), + DBUSMENU_MUTE_MENUITEM_TYPE, + new_mute_widget); + // Note: Not ideal but all key handling needs to be managed here and then + // delegated to the appropriate widget. + g_signal_connect (menu, "key-press-event", G_CALLBACK(key_press_cb), io); + g_signal_connect (menu, "key-release-event", G_CALLBACK(key_release_cb), io); + + return GTK_MENU(menu); +} + +static const gchar * +get_accessible_desc (IndicatorObject * io) +{ + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(io); + return priv->accessible_desc; +} + +static const gchar *get_name_hint (IndicatorObject * io) +{ + return PACKAGE_NAME; +} + +static void +connection_changed (IndicatorServiceManager * sm, + gboolean connected, + gpointer user_data) +{ + IndicatorSound* indicator = INDICATOR_SOUND(user_data); + g_return_if_fail ( IS_INDICATOR_SOUND (indicator) ); + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE (indicator); + GError *error = NULL; + + if (connected == FALSE){ + sound_state_manager_deal_with_disconnect (priv->state_manager); + return; + //TODO: Gracefully handle disconnection + // do a timeout to wait for reconnection + // for 5 seconds and then if no connection message + // is received put the state at 'sink not available' + } + // If the proxy is not null and connected is true => its a reconnect, + // we don't need to anything, gdbus takes care of the rest - bless. + // just fetch the state. + if (priv->dbus_proxy != NULL){ + g_dbus_proxy_call ( priv->dbus_proxy, + "GetSoundState", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback)sound_state_manager_get_state_cb, + priv->state_manager); + return; + } + + if ( node_info == NULL ){ + node_info = g_dbus_node_info_new_for_xml ( _sound_service, + &error ); + if (error != NULL) { + g_warning( "Failed to get create interface info from xml: %s", + error->message ); + g_error_free(error); + return; + } + } + + if (interface_info == NULL) { + interface_info = g_dbus_node_info_lookup_interface (node_info, + INDICATOR_SOUND_DBUS_INTERFACE); + if (interface_info == NULL) { + g_error("Unable to find interface '" INDICATOR_SOUND_DBUS_INTERFACE "'"); + } + } + + g_dbus_proxy_new_for_bus( G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + interface_info, + INDICATOR_SOUND_DBUS_NAME, + INDICATOR_SOUND_SERVICE_DBUS_OBJECT_PATH, + INDICATOR_SOUND_DBUS_INTERFACE, + NULL, + create_connection_to_service, + indicator ); +} + +static void create_connection_to_service (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + IndicatorSound *self = INDICATOR_SOUND(user_data); + GError *error = NULL; + + g_return_if_fail( IS_INDICATOR_SOUND(self) ); + + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self); + + priv->dbus_proxy = g_dbus_proxy_new_finish(res, &error); + + if (error != NULL) { + g_warning("Failed to get dbus proxy: %s", error->message); + g_error_free(error); + return; + } + sound_state_manager_connect_to_dbus (priv->state_manager, + priv->dbus_proxy); + +} + +static gboolean +new_transport_widget (DbusmenuMenuitem * newitem, + DbusmenuMenuitem * parent, + DbusmenuClient * client, + gpointer user_data) +{ + g_debug("indicator-sound: new_transport_bar() called "); + + GtkWidget* bar = NULL; + IndicatorObject *io = NULL; + + g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); + g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); + + bar = transport_widget_new(newitem); + io = g_object_get_data (G_OBJECT (client), "indicator"); + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io)); + priv->transport_widgets_list = g_list_append ( priv->transport_widgets_list, bar ); + + GtkMenuItem *menu_transport_bar = GTK_MENU_ITEM(bar); + + gtk_widget_show_all(bar); + dbusmenu_gtkclient_newitem_base (DBUSMENU_GTKCLIENT(client), + newitem, + menu_transport_bar, + parent); + return TRUE; +} + +static gboolean +new_metadata_widget (DbusmenuMenuitem * newitem, + DbusmenuMenuitem * parent, + DbusmenuClient * client, + gpointer user_data) +{ + g_debug("indicator-sound: new_metadata_widget"); + + GtkWidget* metadata = NULL; + + g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); + g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); + + + metadata = metadata_widget_new (newitem); + + g_debug ("%s (\"%s\")", __func__, + dbusmenu_menuitem_property_get(newitem, DBUSMENU_METADATA_MENUITEM_PLAYER_NAME)); + + GtkMenuItem *menu_metadata_widget = GTK_MENU_ITEM(metadata); + + gtk_widget_show_all(metadata); + dbusmenu_gtkclient_newitem_base (DBUSMENU_GTKCLIENT(client), + newitem, + menu_metadata_widget, + parent); + return TRUE; +} + +static gboolean +new_volume_slider_widget(DbusmenuMenuitem * newitem, + DbusmenuMenuitem * parent, + DbusmenuClient * client, + gpointer user_data) +{ + g_debug("indicator-sound: new_volume_slider_widget"); + + GtkWidget* volume_widget = NULL; + IndicatorObject *io = NULL; + + g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); + g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); + + io = g_object_get_data (G_OBJECT (client), "indicator"); + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io)); + + if (priv->volume_widget != NULL){ + volume_widget_tidy_up (priv->volume_widget); + gtk_widget_destroy (priv->volume_widget); + priv->volume_widget = NULL; + } + volume_widget = volume_widget_new (newitem, io); + priv->volume_widget = volume_widget; + // Don't forget to set the accessible desc. + update_accessible_desc (io); + + + GtkWidget* ido_slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget)); + + gtk_widget_show_all(ido_slider_widget); + // register the style callback on this widget with state manager's style change + // handler (needs to remake the blocking animation for each style). + g_signal_connect (ido_slider_widget, "style-set", + G_CALLBACK(sound_state_manager_style_changed_cb), + priv->state_manager); + + GtkMenuItem *menu_volume_item = GTK_MENU_ITEM(ido_slider_widget); + dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), + newitem, + menu_volume_item, + parent); + return TRUE; +} +/** + * new_voip_slider_widget + * Create the voip menu item widget, must of the time this widget will be hidden. + * @param newitem + * @param parent + * @param client + * @param user_data + * @return + */ +static gboolean +new_voip_slider_widget (DbusmenuMenuitem * newitem, + DbusmenuMenuitem * parent, + DbusmenuClient * client, + gpointer user_data) +{ + g_debug("indicator-sound: new_voip_slider_widget"); + GtkWidget* voip_widget = NULL; + IndicatorObject *io = NULL; + + g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); + g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); + + io = g_object_get_data (G_OBJECT (client), "indicator"); + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io)); + + if (priv->voip_widget != NULL){ + voip_input_widget_tidy_up (priv->voip_widget); + gtk_widget_destroy (priv->voip_widget); + priv->voip_widget = NULL; + } + + voip_widget = voip_input_widget_new (newitem); + priv->voip_widget = voip_widget; + + GtkWidget* ido_slider_widget = voip_input_widget_get_ido_slider(VOIP_INPUT_WIDGET(voip_widget)); + + gtk_widget_show_all(ido_slider_widget); + + GtkMenuItem *menu_volume_item = GTK_MENU_ITEM(ido_slider_widget); + dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), + newitem, + menu_volume_item, + parent); + return TRUE; +} + +static gboolean +new_mute_widget(DbusmenuMenuitem * newitem, + DbusmenuMenuitem * parent, + DbusmenuClient * client, + gpointer user_data) +{ + IndicatorObject *io = NULL; + + g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); + g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); + + io = g_object_get_data (G_OBJECT (client), "indicator"); + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io)); + + if (priv->mute_widget != NULL){ + g_object_unref (priv->mute_widget); + priv->mute_widget = NULL; + } + + priv->mute_widget = mute_widget_new(newitem); + GtkMenuItem *item = mute_widget_get_menu_item (priv->mute_widget); + + dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), + newitem, + item, + parent); + + return TRUE; +} + +/*******************************************************************/ +//UI callbacks +/******************************************************************/ + +static GtkWidget * +get_current_item (GtkContainer * container) +{ + GList *children = gtk_container_get_children (container); + GList *iter; + GtkWidget *rv = NULL; + + /* Suprisingly, GTK+ doesn't really let us query "what is the currently + selected item?". But it does note it internally by prelighting the + widget, so we watch for that. */ + for (iter = children; iter; iter = iter->next) { + if (gtk_widget_get_state (GTK_WIDGET (iter->data)) & GTK_STATE_PRELIGHT) { + rv = GTK_WIDGET (iter->data); + break; + } + } + + return rv; +} + +/** +key_press_cb: +**/ +static gboolean +key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + gboolean digested = FALSE; + + g_return_val_if_fail(IS_INDICATOR_SOUND(data), FALSE); + + IndicatorSound *indicator = INDICATOR_SOUND (data); + + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(indicator); + GtkWidget *menuitem; + menuitem = get_current_item (GTK_CONTAINER (widget)); + + if (IDO_IS_SCALE_MENU_ITEM(menuitem) == TRUE){ + gdouble current_value = 0; + gdouble new_value = 0; + const gdouble five_percent = 5; + gboolean is_voip_slider = FALSE; + + if (g_ascii_strcasecmp (ido_scale_menu_item_get_primary_label (IDO_SCALE_MENU_ITEM(menuitem)), "VOLUME") == 0) { + g_debug ("vOLUME SLIDER KEY PRESS"); + GtkWidget* slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget)); + GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)slider_widget); + GtkRange* range = (GtkRange*)slider; + g_return_val_if_fail(GTK_IS_RANGE(range), FALSE); + current_value = gtk_range_get_value(range); + new_value = current_value; + } + else if (g_ascii_strcasecmp (ido_scale_menu_item_get_primary_label (IDO_SCALE_MENU_ITEM(menuitem)), "VOIP") == 0) { + g_debug ("VOIP SLIDER KEY PRESS"); + GtkWidget* slider_widget = voip_input_widget_get_ido_slider(VOIP_INPUT_WIDGET(priv->voip_widget)); + GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)slider_widget); + GtkRange* range = (GtkRange*)slider; + g_return_val_if_fail(GTK_IS_RANGE(range), FALSE); + current_value = gtk_range_get_value(range); + new_value = current_value; + is_voip_slider = TRUE; + } + + switch (event->keyval) { + case GDK_KEY_Right: + digested = TRUE; + new_value = current_value + five_percent; + break; + case GDK_KEY_Left: + digested = TRUE; + new_value = current_value - five_percent; + break; + case GDK_KEY_plus: + digested = TRUE; + new_value = current_value + five_percent; + break; + case GDK_KEY_minus: + digested = TRUE; + new_value = current_value - five_percent; + break; + default: + break; + } + new_value = CLAMP(new_value, 0, 100); + if (new_value != current_value){ + if (is_voip_slider == TRUE){ + voip_input_widget_update (VOIP_INPUT_WIDGET(priv->voip_widget), new_value); + } + else{ + volume_widget_update (VOLUME_WIDGET(priv->volume_widget), new_value, "keypress-update"); + } + } + } + else if (IS_TRANSPORT_WIDGET(menuitem) == TRUE) { + TransportWidget* transport_widget = NULL; + GList* elem; + + for ( elem = priv->transport_widgets_list; elem; elem = elem->next ) { + transport_widget = TRANSPORT_WIDGET ( elem->data ); + if ( transport_widget_is_selected( transport_widget ) ) + break; + } + + switch (event->keyval) { + case GDK_KEY_Right: + transport_widget_react_to_key_press_event ( transport_widget, + TRANSPORT_ACTION_NEXT ); + digested = TRUE; + break; + case GDK_KEY_Left: + transport_widget_react_to_key_press_event ( transport_widget, + TRANSPORT_ACTION_PREVIOUS ); + digested = TRUE; + break; + case GDK_KEY_space: + transport_widget_react_to_key_press_event ( transport_widget, + TRANSPORT_ACTION_PLAY_PAUSE ); + digested = TRUE; + break; + case GDK_KEY_Up: + case GDK_KEY_Down: + digested = FALSE; + break; + default: + break; + } + } + return digested; +} + + +/** +key_release_cb: +**/ +static gboolean +key_release_cb(GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + gboolean digested = FALSE; + + g_return_val_if_fail(IS_INDICATOR_SOUND(data), FALSE); + + IndicatorSound *indicator = INDICATOR_SOUND (data); + + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(indicator); + + GtkWidget *menuitem; + + menuitem = get_current_item (GTK_CONTAINER (widget)); + if (IS_TRANSPORT_WIDGET(menuitem) == TRUE) { + TransportWidget* transport_widget = NULL; + GList* elem; + + for(elem = priv->transport_widgets_list; elem; elem = elem->next) { + transport_widget = TRANSPORT_WIDGET (elem->data); + if ( transport_widget_is_selected( transport_widget ) ) + break; + } + + switch (event->keyval) { + case GDK_KEY_Right: + transport_widget_react_to_key_release_event ( transport_widget, + TRANSPORT_ACTION_NEXT ); + digested = TRUE; + break; + case GDK_KEY_Left: + transport_widget_react_to_key_release_event ( transport_widget, + TRANSPORT_ACTION_PREVIOUS ); + digested = TRUE; + break; + case GDK_KEY_space: + transport_widget_react_to_key_release_event ( transport_widget, + TRANSPORT_ACTION_PLAY_PAUSE ); + digested = TRUE; + break; + case GDK_KEY_Up: + case GDK_KEY_Down: + digested = FALSE; + break; + default: + break; + } + } + return digested; +} + +static void +indicator_sound_scroll (IndicatorObject * io, IndicatorObjectEntry * entry, + gint delta, IndicatorScrollDirection direction) +{ + //g_debug("indicator-sound-scroll - current slider value"); + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io)); + SoundState current_state = sound_state_manager_get_current_state (priv->state_manager); + + if (current_state == UNAVAILABLE || current_state == MUTED) + return; + + GtkWidget* slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget)); + GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)slider_widget); + GtkRange* range = (GtkRange*)slider; + g_return_if_fail(GTK_IS_RANGE(range)); + + gdouble value = gtk_range_get_value(range); + GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (slider)); + //g_debug("indicator-sound-scroll - current slider value %f", value); + if (direction == INDICATOR_OBJECT_SCROLL_UP) { + value += gtk_adjustment_get_step_increment (adj); + } else { + value -= gtk_adjustment_get_step_increment (adj); + } + //g_debug("indicator-sound-scroll - update slider with value %f", value); + volume_widget_update(VOLUME_WIDGET(priv->volume_widget), value, "scroll updates"); + + if (!gtk_widget_get_mapped(GTK_WIDGET (entry->menu))) + sound_state_manager_show_notification (priv->state_manager, value); +} + +static void +indicator_sound_middle_click (IndicatorObject * io, IndicatorObjectEntry * entry, + guint time, gpointer data) +{ + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(io); + g_return_if_fail (priv); + + mute_widget_toggle(priv->mute_widget); +} + +void +update_accessible_desc (IndicatorObject * io) +{ + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(io); + GList *entries = indicator_object_get_entries(io); + IndicatorObjectEntry * entry = (IndicatorObjectEntry *)entries->data; + + gchar *old_desc = priv->accessible_desc; + + if (priv->volume_widget) { + priv->accessible_desc = g_strdup_printf(_("Volume (%'.0f%%)"), + volume_widget_get_current_volume (priv->volume_widget)); + } + else { + priv->accessible_desc = NULL; + } + + entry->accessible_desc = priv->accessible_desc; + g_free (old_desc); + g_signal_emit(G_OBJECT(io), + INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE_ID, + 0, + entry, + TRUE); + g_list_free(entries); +} diff --git a/.pc/dbusmenu_05_90.patch/src/metadata-widget.h b/.pc/dbusmenu_05_90.patch/src/metadata-widget.h new file mode 100644 index 0000000..b0123a3 --- /dev/null +++ b/.pc/dbusmenu_05_90.patch/src/metadata-widget.h @@ -0,0 +1,55 @@ +/* +Copyright 2010 Canonical Ltd. + +Authors: + Conor Curran <conor.curran@canonical.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#ifndef __METADATA_WIDGET_H__ +#define __METADATA_WIDGET_H__ + +#include <gtk/gtk.h> +#if GTK_CHECK_VERSION(3, 0, 0) +#include <libdbusmenu-gtk3/menuitem.h> +#else +#include <libdbusmenu-gtk/menuitem.h> +#endif + +G_BEGIN_DECLS + +#define METADATA_WIDGET_TYPE (metadata_widget_get_type ()) +#define METADATA_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), METADATA_WIDGET_TYPE, MetadataWidget)) +#define METADATA_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), METADATA_WIDGET_TYPE, MetadataWidgetClass)) +#define IS_METADATA_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), METADATA_WIDGET_TYPE)) +#define IS_METADATA_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), METADATA_WIDGET_TYPE)) +#define METADATA_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), METADATA_WIDGET_TYPE, MetadataWidgetClass)) + +typedef struct _MetadataWidget MetadataWidget; +typedef struct _MetadataWidgetClass MetadataWidgetClass; + +struct _MetadataWidgetClass { + GtkMenuItemClass parent_class; +}; + +struct _MetadataWidget { + GtkMenuItem parent; +}; + +GType metadata_widget_get_type (void); +GtkWidget* metadata_widget_new(DbusmenuMenuitem *twin_item); + +G_END_DECLS + +#endif + diff --git a/.pc/dbusmenu_05_90.patch/src/mute-widget.h b/.pc/dbusmenu_05_90.patch/src/mute-widget.h new file mode 100644 index 0000000..95130a1 --- /dev/null +++ b/.pc/dbusmenu_05_90.patch/src/mute-widget.h @@ -0,0 +1,67 @@ +/* +Copyright 2011 Canonical Ltd. + +Authors: + Marco Trevisan (Treviño) <mail@3v1n0.net> + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#ifndef __MUTE_WIDGET_H__ +#define __MUTE_WIDGET_H__ + +#include <glib.h> +#include <glib-object.h> +#include <gtk/gtk.h> +#if GTK_CHECK_VERSION(3, 0, 0) +#include <libdbusmenu-gtk3/menuitem.h> +#else +#include <libdbusmenu-gtk/menuitem.h> +#endif +#include <libindicator/indicator-object.h> + +G_BEGIN_DECLS + +#define MUTE_WIDGET_TYPE (mute_widget_get_type ()) +#define MUTE_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MUTE_WIDGET_TYPE, MuteWidget)) +#define MUTE_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MUTE_WIDGET_TYPE, MuteWidgetClass)) +#define IS_MUTE_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MUTE_WIDGET_TYPE)) +#define IS_MUTE_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MUTE_WIDGET_TYPE)) +#define MUTE_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MUTE_WIDGET_TYPE, MuteWidgetClass)) + +typedef struct _MuteWidget MuteWidget; +typedef struct _MuteWidgetClass MuteWidgetClass; + +struct _MuteWidgetClass { + GObjectClass parent_class; +}; + +struct _MuteWidget { + GObject parent; +}; + +typedef enum { + MUTE_STATUS_UNAVAILABLE, + MUTE_STATUS_MUTED, + MUTE_STATUS_UNMUTED +} MuteStatus; + +GType mute_widget_get_type (void) G_GNUC_CONST; +MuteWidget* mute_widget_new (DbusmenuMenuitem *item); +MuteStatus mute_widget_get_status (MuteWidget *self); +void mute_widget_toggle (MuteWidget *self); +GtkMenuItem *mute_widget_get_menu_item (MuteWidget *self); + +G_END_DECLS + +#endif + diff --git a/.pc/dbusmenu_05_90.patch/src/transport-widget.h b/.pc/dbusmenu_05_90.patch/src/transport-widget.h new file mode 100644 index 0000000..8c2ce48 --- /dev/null +++ b/.pc/dbusmenu_05_90.patch/src/transport-widget.h @@ -0,0 +1,71 @@ +/* +Copyright 2010 Canonical Ltd. + +Authors: + Conor Curran <conor.curran@canonical.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#ifndef __TRANSPORT_WIDGET_H__ +#define __TRANSPORT_WIDGET_H__ + +#include <gtk/gtk.h> +#if GTK_CHECK_VERSION(3, 0, 0) +#include <libdbusmenu-gtk3/menuitem.h> +#else +#include <libdbusmenu-gtk/menuitem.h> +#endif + +#include "common-defs.h" + +G_BEGIN_DECLS + +#define TRANSPORT_WIDGET_TYPE (transport_widget_get_type ()) +#define TRANSPORT_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TRANSPORT_WIDGET_TYPE, TransportWidget)) +#define TRANSPORT_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TRANSPORT_WIDGET_TYPE, TransportWidgetClass)) +#define IS_TRANSPORT_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TRANSPORT_WIDGET_TYPE)) +#define IS_TRANSPORT_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TRANSPORT_WIDGET_TYPE)) +#define TRANSPORT_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TRANSPORT_WIDGET_TYPE, TransportWidgetClass)) + +typedef struct _TransportWidget TransportWidget; +typedef struct _TransportWidgetClass TransportWidgetClass; + + +struct _TransportWidgetClass { + GtkMenuItemClass parent_class; +}; + +struct _TransportWidget { + GtkMenuItem parent; +}; + +typedef struct +{ + double r; + double g; + double b; +} CairoColorRGB; + + +void _color_shade (const CairoColorRGB *a, float k, CairoColorRGB *b); +GType transport_widget_get_type (void); +GtkWidget* transport_widget_new (DbusmenuMenuitem *item); +void transport_widget_react_to_key_press_event (TransportWidget* widget, + TransportAction transport_event); +void transport_widget_react_to_key_release_event (TransportWidget* widget, + TransportAction transport_event); +gboolean transport_widget_is_selected (TransportWidget* widget); +G_END_DECLS + +#endif + diff --git a/.pc/dbusmenu_05_90.patch/src/voip-input-widget.h b/.pc/dbusmenu_05_90.patch/src/voip-input-widget.h new file mode 100644 index 0000000..0e90665 --- /dev/null +++ b/.pc/dbusmenu_05_90.patch/src/voip-input-widget.h @@ -0,0 +1,60 @@ +/* +Copyright 2011 Canonical Ltd. + +Authors: + Conor Curran <conor.curran@canonical.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#ifndef __VOIP_INPUT_WIDGET_H__ +#define __VOIP_INPUT_WIDGET_H__ + +#include <glib.h> +#include <glib-object.h> +#include <gtk/gtk.h> +#if GTK_CHECK_VERSION(3, 0, 0) +#include <libdbusmenu-gtk3/menuitem.h> +#else +#include <libdbusmenu-gtk/menuitem.h> +#endif + +G_BEGIN_DECLS + +#define VOIP_INPUT_WIDGET_TYPE (voip_input_widget_get_type ()) +#define VOIP_INPUT_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VOIP_INPUT_WIDGET_TYPE, VoipInputWidget)) +#define VOIP_INPUT_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VOIP_INPUT_WIDGET_TYPE, VoipInputWidgetClass)) +#define IS_VOIP_INPUT_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VOIP_INPUT_WIDGET_TYPE)) +#define IS_VOIP_INPUT_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VOIP_INPUT_WIDGET_TYPE)) +#define VOIP_INPUT_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VOIP_INPUT_WIDGET_TYPE, VoipInputWidgetClass)) + +typedef struct _VoipInputWidget VoipInputWidget; +typedef struct _VoipInputWidgetClass VoipInputWidgetClass; + +struct _VoipInputWidgetClass { + GObjectClass parent_class; +}; + +struct _VoipInputWidget { + GObject parent; +}; + +GType voip_input_widget_get_type (void) G_GNUC_CONST; +GtkWidget* voip_input_widget_new(DbusmenuMenuitem* twin_item); +GtkWidget* voip_input_widget_get_ido_slider(VoipInputWidget* self); +void voip_input_widget_update(VoipInputWidget* self, gdouble update); +void voip_input_widget_tidy_up (GtkWidget *widget); + +G_END_DECLS + +#endif + diff --git a/.pc/dbusmenu_05_90.patch/src/volume-widget.h b/.pc/dbusmenu_05_90.patch/src/volume-widget.h new file mode 100644 index 0000000..3deb99c --- /dev/null +++ b/.pc/dbusmenu_05_90.patch/src/volume-widget.h @@ -0,0 +1,62 @@ +/* +Copyright 2010 Canonical Ltd. + +Authors: + Conor Curran <conor.curran@canonical.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#ifndef __VOLUME_WIDGET_H__ +#define __VOLUME_WIDGET_H__ + +#include <glib.h> +#include <glib-object.h> +#include <gtk/gtk.h> +#if GTK_CHECK_VERSION(3, 0, 0) +#include <libdbusmenu-gtk3/menuitem.h> +#else +#include <libdbusmenu-gtk/menuitem.h> +#endif +#include <libindicator/indicator-object.h> + +G_BEGIN_DECLS + +#define VOLUME_WIDGET_TYPE (volume_widget_get_type ()) +#define VOLUME_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VOLUME_WIDGET_TYPE, VolumeWidget)) +#define VOLUME_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VOLUME_WIDGET_TYPE, VolumeWidgetClass)) +#define IS_VOLUME_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VOLUME_WIDGET_TYPE)) +#define IS_VOLUME_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VOLUME_WIDGET_TYPE)) +#define VOLUME_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VOLUME_WIDGET_TYPE, VolumeWidgetClass)) + +typedef struct _VolumeWidget VolumeWidget; +typedef struct _VolumeWidgetClass VolumeWidgetClass; + +struct _VolumeWidgetClass { + GObjectClass parent_class; +}; + +struct _VolumeWidget { + GObject parent; +}; + +GType volume_widget_get_type (void) G_GNUC_CONST; +GtkWidget* volume_widget_new(DbusmenuMenuitem *item, IndicatorObject* io); +GtkWidget* volume_widget_get_ido_slider(VolumeWidget* self); +void volume_widget_update(VolumeWidget* self, gdouble update, gchar* label); +void volume_widget_tidy_up (GtkWidget *widget); +gdouble volume_widget_get_current_volume ( GtkWidget *widget ); + +G_END_DECLS + +#endif + diff --git a/.pc/lazy_init.patch/src/sound-state-manager.c b/.pc/lazy_init.patch/src/sound-state-manager.c new file mode 100644 index 0000000..c851407 --- /dev/null +++ b/.pc/lazy_init.patch/src/sound-state-manager.c @@ -0,0 +1,473 @@ +/* +Copyright 2011 Canonical Ltd. + +Authors: + Conor Curran <conor.curran@canonical.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <libindicator/indicator-image-helper.h> +#include <libnotify/notify.h> + +#include "config.h" + +#include "sound-state-manager.h" +#include "dbus-shared-names.h" +#include "sound-state.h" + +typedef struct _SoundStateManagerPrivate SoundStateManagerPrivate; + +struct _SoundStateManagerPrivate +{ + GDBusProxy* dbus_proxy; + GHashTable* volume_states; + GList* blocked_animation_list; + SoundState current_state; + GtkImage* speaker_image; + NotifyNotification* notification; + GSettings *settings_manager; +}; + +#define SOUND_STATE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUND_TYPE_STATE_MANAGER, SoundStateManagerPrivate)) +G_DEFINE_TYPE (SoundStateManager, sound_state_manager, G_TYPE_OBJECT); + +static GtkIconSize design_team_size; +static gint blocked_id; +static gint animation_id; +static GList* blocked_iter = NULL; +static gboolean can_animate = FALSE; + +//Notifications +static void sound_state_manager_notification_init (SoundStateManager* self); + +//Animation/State related +static void sound_state_manager_prepare_blocked_animation (SoundStateManager* self); +static gboolean sound_state_manager_start_animation (gpointer user_data); +static gboolean sound_state_manager_fade_back_to_mute_image (gpointer user_data); +static void sound_state_manager_reset_mute_blocking_animation (SoundStateManager* self); +static void sound_state_manager_free_the_animation_list (SoundStateManager* self); +static void sound_state_manager_prepare_state_image_names (SoundStateManager* self); +static void sound_state_signal_cb ( GDBusProxy* proxy, + gchar* sender_name, + gchar* signal_name, + GVariant* parameters, + gpointer user_data ); +static gboolean sound_state_manager_can_proceed_with_blocking_animation (SoundStateManager* self); + + +static void +sound_state_manager_init (SoundStateManager* self) +{ + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + + priv->dbus_proxy = NULL; + priv->volume_states = NULL; + priv->speaker_image = NULL; + priv->blocked_animation_list = NULL; + priv->notification = NULL; + priv->settings_manager = NULL; + + priv->settings_manager = g_settings_new("com.canonical.indicators.sound"); + + sound_state_manager_notification_init (self); + + sound_state_manager_prepare_state_image_names (self); + sound_state_manager_prepare_blocked_animation (self); + + priv->current_state = UNAVAILABLE; + priv->speaker_image = indicator_image_helper (g_hash_table_lookup (priv->volume_states, + GINT_TO_POINTER(priv->current_state))); +} + +static void +sound_state_manager_finalize (GObject *object) +{ + /* TODO: Add deinitalization code here */ + + G_OBJECT_CLASS (sound_state_manager_parent_class)->finalize (object); +} + +static void +sound_state_manager_dispose (GObject *object) +{ + SoundStateManager* self = SOUND_STATE_MANAGER (object); + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + + g_hash_table_destroy (priv->volume_states); + + sound_state_manager_free_the_animation_list (self); + + if (priv->notification) { + notify_uninit(); + } + + g_object_unref(priv->settings_manager); + + G_OBJECT_CLASS (sound_state_manager_parent_class)->dispose (object); +} + + +static void +sound_state_manager_class_init (SoundStateManagerClass *klass) +{ + GObjectClass* object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = sound_state_manager_finalize; + object_class->dispose = sound_state_manager_dispose; + + g_type_class_add_private (klass, sizeof (SoundStateManagerPrivate)); + + design_team_size = gtk_icon_size_register("design-team-size", 22, 22); +} + +static void +sound_state_manager_notification_init (SoundStateManager* self) +{ + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + + if (!notify_init(PACKAGE_NAME)) + return; + + GList* caps = notify_get_server_caps(); + gboolean has_notify_osd = FALSE; + + if (caps) { + if (g_list_find_custom(caps, "x-canonical-private-synchronous", + (GCompareFunc) g_strcmp0)) { + has_notify_osd = TRUE; + } + g_list_foreach(caps, (GFunc) g_free, NULL); + g_list_free(caps); + } + + if (has_notify_osd) { + priv->notification = notify_notification_new(PACKAGE_NAME, NULL, NULL); + notify_notification_set_hint_string(priv->notification, + "x-canonical-private-synchronous", PACKAGE_NAME); + } +} + +void +sound_state_manager_show_notification (SoundStateManager *self, + double value) +{ + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + + if (priv->notification == NULL || + g_settings_get_boolean (priv->settings_manager, "show-notify-osd-on-scroll") == FALSE){ + return; + } + + char *icon; + const int notify_value = CLAMP((int)value, -1, 101); + + SoundState state = sound_state_get_from_volume ((int)value); + + if (state == ZERO_LEVEL) { + // Not available for all the themes + icon = "notification-audio-volume-off"; + } else if (state == LOW_LEVEL) { + icon = "notification-audio-volume-low"; + } else if (state == MEDIUM_LEVEL) { + icon = "notification-audio-volume-medium"; + } else if (state == HIGH_LEVEL) { + icon = "notification-audio-volume-high"; + } else { + icon = "notification-audio-volume-muted"; + } + + notify_notification_update(priv->notification, PACKAGE_NAME, NULL, icon); + notify_notification_set_hint_int32(priv->notification, "value", notify_value); + notify_notification_show(priv->notification, NULL); +} + + +/* +Prepare states versus images names hash. +*/ +static void +sound_state_manager_prepare_state_image_names (SoundStateManager* self) +{ + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + priv->volume_states = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); + + g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(MUTED), g_strdup("audio-volume-muted-panel")); + g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(ZERO_LEVEL), g_strdup("audio-volume-low-zero-panel")); + g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(LOW_LEVEL), g_strdup("audio-volume-low-panel")); + g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(MEDIUM_LEVEL), g_strdup("audio-volume-medium-panel")); + g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(HIGH_LEVEL), g_strdup("audio-volume-high-panel")); + g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(BLOCKED), g_strdup("audio-volume-muted-blocking-panel")); + g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(UNAVAILABLE), g_strdup("audio-output-none-panel")); +} + +/* +prepare_blocked_animation: +Prepares the array of images to be used in the blocked animation. +Only called at startup. +*/ +static void +sound_state_manager_prepare_blocked_animation (SoundStateManager* self) +{ + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + + gchar* blocked_name = g_hash_table_lookup(priv->volume_states, + GINT_TO_POINTER(BLOCKED)); + gchar* muted_name = g_hash_table_lookup(priv->volume_states, + GINT_TO_POINTER(MUTED)); + + GtkImage* temp_image = indicator_image_helper(muted_name); + GdkPixbuf* mute_buf = gtk_image_get_pixbuf(temp_image); + + temp_image = indicator_image_helper(blocked_name); + GdkPixbuf* blocked_buf = gtk_image_get_pixbuf(temp_image); + + if (mute_buf == NULL || blocked_buf == NULL) { + //g_debug("Don bother with the animation, the theme aint got the goods !"); + return; + } + + int i; + + // sample 51 snapshots - range : 0-256 + for (i = 0; i < 51; i++) { + gdk_pixbuf_composite(mute_buf, blocked_buf, 0, 0, + gdk_pixbuf_get_width(mute_buf), + gdk_pixbuf_get_height(mute_buf), + 0, 0, 1, 1, GDK_INTERP_BILINEAR, MIN(255, i * 5)); + priv->blocked_animation_list = g_list_append(priv->blocked_animation_list, + gdk_pixbuf_copy(blocked_buf)); + } + can_animate = TRUE; + g_object_ref_sink(mute_buf); + g_object_unref(mute_buf); + g_object_ref_sink(blocked_buf); + g_object_unref(blocked_buf); +} + + +GtkImage* +sound_state_manager_get_current_icon (SoundStateManager* self) +{ + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + return priv->speaker_image; +} + +SoundState +sound_state_manager_get_current_state (SoundStateManager* self) +{ + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + return priv->current_state; +} + +/** + * sound_state_manager_connect_to_dbus: + * @returns: void + * When ready the indicator-sound calls this method to enable state communication + * between the indicator and the service. + **/ +void +sound_state_manager_connect_to_dbus (SoundStateManager* self, GDBusProxy* proxy) +{ + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + priv->dbus_proxy = proxy; + g_signal_connect (priv->dbus_proxy, "g-signal", + G_CALLBACK (sound_state_signal_cb), self); + + g_dbus_proxy_call ( priv->dbus_proxy, + "GetSoundState", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback)sound_state_manager_get_state_cb, + self); +} + +void +sound_state_manager_get_state_cb (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + g_return_if_fail (SOUND_IS_STATE_MANAGER (user_data)); + SoundStateManager* self = SOUND_STATE_MANAGER (user_data); + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + + GVariant *result, *value; + GError *error = NULL; + result = g_dbus_proxy_call_finish ( priv->dbus_proxy, + res, + &error ); + + if (error != NULL) { + g_warning("get_sound_state call failed: %s", error->message); + g_error_free(error); + return; + } + + value = g_variant_get_child_value(result, 0); + priv->current_state = (SoundState)g_variant_get_int32(value); + + gchar* image_name = g_hash_table_lookup (priv->volume_states, + GINT_TO_POINTER(priv->current_state) ); + indicator_image_helper_update (priv->speaker_image, image_name); + + g_variant_unref(value); + g_variant_unref(result); +} + +void +sound_state_manager_deal_with_disconnect (SoundStateManager* self) +{ + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + priv->current_state = UNAVAILABLE; + + gchar* image_name = g_hash_table_lookup (priv->volume_states, + GINT_TO_POINTER(priv->current_state) ); + indicator_image_helper_update (priv->speaker_image, image_name); +} + +static void +sound_state_signal_cb ( GDBusProxy* proxy, + gchar* sender_name, + gchar* signal_name, + GVariant* parameters, + gpointer user_data) +{ + //g_debug ( "!!! sound state manager signal_cb" ); + + g_return_if_fail (SOUND_IS_STATE_MANAGER (user_data)); + SoundStateManager* self = SOUND_STATE_MANAGER (user_data); + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + + g_variant_ref (parameters); + GVariant *value = g_variant_get_child_value (parameters, 0); + gint update = g_variant_get_int32 (value); + + //g_debug ( "!!! signal_cb with value %i", update); + + priv->current_state = (SoundState)update; + + g_variant_unref (parameters); + + if (g_strcmp0(signal_name, INDICATOR_SOUND_SIGNAL_STATE_UPDATE) == 0){ + + gchar* image_name = g_hash_table_lookup (priv->volume_states, + GINT_TO_POINTER(priv->current_state) ); + if (priv->current_state == BLOCKED && + sound_state_manager_can_proceed_with_blocking_animation (self) == TRUE) { + blocked_id = g_timeout_add_seconds (4, + sound_state_manager_start_animation, + self); + indicator_image_helper_update (priv->speaker_image, image_name); + } + else{ + indicator_image_helper_update (priv->speaker_image, image_name); + } + } + else { + g_warning ("sorry don't know what signal this is - %s", signal_name); + } +} + +void +sound_state_manager_style_changed_cb (GtkWidget *widget, + GtkStyle *previous_style, + gpointer user_data) +{ + g_debug("Just caught a style change event"); + g_return_if_fail (SOUND_IS_STATE_MANAGER (user_data)); + SoundStateManager* self = SOUND_STATE_MANAGER (user_data); + sound_state_manager_reset_mute_blocking_animation (self); + sound_state_manager_free_the_animation_list (self); + sound_state_manager_prepare_blocked_animation (self); +} + +static void +sound_state_manager_reset_mute_blocking_animation (SoundStateManager* self) +{ + if (animation_id != 0) { + //g_debug("about to remove the animation_id callback from the mainloop!!**"); + g_source_remove(animation_id); + animation_id = 0; + } + if (blocked_id != 0) { + //g_debug("about to remove the blocked_id callback from the mainloop!!**"); + g_source_remove(blocked_id); + blocked_id = 0; + } +} + +static void +sound_state_manager_free_the_animation_list (SoundStateManager* self) +{ + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + + if (priv->blocked_animation_list != NULL) { + g_list_foreach (priv->blocked_animation_list, (GFunc)g_object_unref, NULL); + g_list_free (priv->blocked_animation_list); + priv->blocked_animation_list = NULL; + } +} + + +static gboolean +sound_state_manager_start_animation (gpointer userdata) +{ + g_return_val_if_fail (SOUND_IS_STATE_MANAGER (userdata), FALSE); + SoundStateManager* self = SOUND_STATE_MANAGER (userdata); + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + + blocked_iter = priv->blocked_animation_list; + blocked_id = 0; + animation_id = g_timeout_add (50, + sound_state_manager_fade_back_to_mute_image, + self); + return FALSE; +} + +static gboolean +sound_state_manager_fade_back_to_mute_image (gpointer user_data) +{ + g_return_val_if_fail (SOUND_IS_STATE_MANAGER (user_data), FALSE); + SoundStateManager* self = SOUND_STATE_MANAGER (user_data); + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE (self); + + if (blocked_iter != NULL) { + gtk_image_set_from_pixbuf (priv->speaker_image, blocked_iter->data); + blocked_iter = blocked_iter->next; + return TRUE; + } else { + animation_id = 0; + //g_debug("exit from animation now\n"); + g_dbus_proxy_call ( priv->dbus_proxy, + "GetSoundState", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback)sound_state_manager_get_state_cb, + self); + + return FALSE; + } +} + + +// Simple static helper to determine if the coast is clear to animate +static +gboolean sound_state_manager_can_proceed_with_blocking_animation (SoundStateManager* self) +{ + return (can_animate && blocked_id == 0 && animation_id == 0 ); +} + diff --git a/.pc/sound_nua.patch/src/sound-service-dbus.c b/.pc/sound_nua.patch/src/sound-service-dbus.c new file mode 100644 index 0000000..b69f081 --- /dev/null +++ b/.pc/sound_nua.patch/src/sound-service-dbus.c @@ -0,0 +1,480 @@ +/* + * Copyright 2010 Canonical Ltd. + * + * Authors: + * Conor Curran <conor.curran@canonical.com> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gio/gio.h> +#include <unistd.h> +#include <glib/gi18n.h> +#include <libindicator/indicator-service.h> +#include <libdbusmenu-glib/server.h> +#include <libdbusmenu-glib/client.h> + +#include "sound-service-dbus.h" +#include "device.h" +#include "gen-sound-service.xml.h" +#include "dbus-shared-names.h" +#include "sound-service-marshal.h" + +// DBUS methods +static void bus_method_call (GDBusConnection * connection, + const gchar * sender, + const gchar * path, + const gchar * interface, + const gchar * method, + GVariant * params, + GDBusMethodInvocation * invocation, + gpointer user_data); + +static GDBusInterfaceVTable interface_table = { + method_call: bus_method_call, + get_property: NULL, /* No properties */ + set_property: NULL /* No properties */ +}; + + +typedef struct _SoundServiceDbusPrivate SoundServiceDbusPrivate; + +struct _SoundServiceDbusPrivate { + GDBusConnection* connection; + DbusmenuMenuitem* root_menuitem; + Device* device; + gboolean greeter_mode; +}; + +enum { + TRACK_SPECIFIC_ITEM, + PLAYER_SPECIFIC_ITEM, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static GDBusNodeInfo * node_info = NULL; +static GDBusInterfaceInfo * interface_info = NULL; + +#define SOUND_SERVICE_DBUS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUND_SERVICE_DBUS_TYPE, SoundServiceDbusPrivate)) + +static void sound_service_dbus_class_init (SoundServiceDbusClass *klass); +static void sound_service_dbus_init (SoundServiceDbus *self); +static void sound_service_dbus_dispose (GObject *object); +static void sound_service_dbus_finalize (GObject *object); + +static void show_sound_settings_dialog (DbusmenuMenuitem *mi, + gpointer user_data); +static gboolean sound_service_dbus_blacklist_player (SoundServiceDbus* self, + gchar* player_name, + gboolean blacklist); + +static gboolean sound_service_dbus_is_blacklisted (SoundServiceDbus* self, + gchar* player_name); + +G_DEFINE_TYPE (SoundServiceDbus, sound_service_dbus, G_TYPE_OBJECT); + +static void +sound_service_dbus_class_init (SoundServiceDbusClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (object_class, sizeof(SoundServiceDbusPrivate)); + + object_class->dispose = sound_service_dbus_dispose; + object_class->finalize = sound_service_dbus_finalize; + + g_assert(klass != NULL); + + if (node_info == NULL) { + GError * error = NULL; + + node_info = g_dbus_node_info_new_for_xml(_sound_service, &error); + if (error != NULL) { + g_error("Unable to parse Indicator Service Interface description: %s", + error->message); + g_error_free(error); + } + } + + if (interface_info == NULL) { + interface_info = g_dbus_node_info_lookup_interface (node_info, + INDICATOR_SOUND_DBUS_INTERFACE); + + if (interface_info == NULL) { + g_error("Unable to find interface '" INDICATOR_SOUND_DBUS_INTERFACE "'"); + } + } + signals[TRACK_SPECIFIC_ITEM] = g_signal_new("track-specific-item-requested", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + _sound_service_marshal_VOID__STRING_STRING, + G_TYPE_NONE, 2, G_TYPE_STRING, + G_TYPE_STRING); + signals[PLAYER_SPECIFIC_ITEM] = g_signal_new("player-specific-item-requested", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + _sound_service_marshal_VOID__STRING_STRING, + G_TYPE_NONE, 2, G_TYPE_STRING, + G_TYPE_STRING); +} + +static void +sound_service_dbus_init (SoundServiceDbus *self) +{ + GError *error = NULL; + SoundServiceDbusPrivate * priv = SOUND_SERVICE_DBUS_GET_PRIVATE(self); + + priv->connection = NULL; + + /* Fetch the session bus */ + priv->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); + + if (error != NULL) { + g_error("sound-service-dbus:Unable to connect to the session bus when creating indicator sound service : %s", error->message); + g_error_free(error); + return; + } + /* register the service on it */ + g_dbus_connection_register_object (priv->connection, + INDICATOR_SOUND_SERVICE_DBUS_OBJECT_PATH, + interface_info, + &interface_table, + self, + NULL, + &error); + if (error != NULL) { + g_error("Unable to register the object to DBus: %s", error->message); + g_error_free(error); + return; + } +} + +DbusmenuMenuitem* +sound_service_dbus_create_root_item (SoundServiceDbus* self, gboolean greeter_mode) +{ + SoundServiceDbusPrivate * priv = SOUND_SERVICE_DBUS_GET_PRIVATE(self); + priv->greeter_mode = greeter_mode; + priv->root_menuitem = dbusmenu_menuitem_new(); + DbusmenuServer *server = dbusmenu_server_new (INDICATOR_SOUND_MENU_DBUS_OBJECT_PATH); + dbusmenu_server_set_root (server, priv->root_menuitem); + g_object_unref (priv->root_menuitem); + priv->device = device_new (self); + return priv->root_menuitem; +} + +void +sound_service_dbus_build_sound_menu ( SoundServiceDbus* self, + DbusmenuMenuitem* mute_item, + DbusmenuMenuitem* slider_item, + DbusmenuMenuitem* voip_input_menu_item) +{ + SoundServiceDbusPrivate * priv = SOUND_SERVICE_DBUS_GET_PRIVATE(self); + + // Mute, Volume and Voip widgets + dbusmenu_menuitem_child_add_position (priv->root_menuitem, mute_item, 0); + dbusmenu_menuitem_child_add_position (priv->root_menuitem, slider_item, 1); + dbusmenu_menuitem_child_add_position (priv->root_menuitem, voip_input_menu_item, 2); + + if (!priv->greeter_mode) { + // Separator + DbusmenuMenuitem* separator = dbusmenu_menuitem_new(); + + dbusmenu_menuitem_property_set (separator, + DBUSMENU_MENUITEM_PROP_TYPE, + DBUSMENU_CLIENT_TYPES_SEPARATOR); + dbusmenu_menuitem_child_add_position (priv->root_menuitem, separator, 3); + g_object_unref (separator); + + // Sound preferences dialog + DbusmenuMenuitem* settings_mi = dbusmenu_menuitem_new(); + + dbusmenu_menuitem_property_set( settings_mi, + DBUSMENU_MENUITEM_PROP_LABEL, + _("Sound Settings...")); + dbusmenu_menuitem_child_append(priv->root_menuitem, settings_mi); + g_object_unref (settings_mi); + g_signal_connect(G_OBJECT(settings_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK(show_sound_settings_dialog), NULL); + } +} + +/** +show_sound_settings_dialog: +Bring up the gnome volume preferences dialog +**/ +static void +show_sound_settings_dialog (DbusmenuMenuitem *mi, + gpointer user_data) +{ + GError * error = NULL; + if (!g_spawn_command_line_async("gnome-volume-control --page=applications", &error) && + !g_spawn_command_line_async("gnome-control-center sound", &error) && + !g_spawn_command_line_async("xfce4-mixer", &error)) + { + g_warning("Unable to show dialog: %s", error->message); + g_error_free(error); + } +} + +static void +sound_service_dbus_dispose (GObject *object) +{ + G_OBJECT_CLASS (sound_service_dbus_parent_class)->dispose (object); + //TODO dispose of the active sink instance ! + return; +} + +static void +sound_service_dbus_finalize (GObject *object) +{ + G_OBJECT_CLASS (sound_service_dbus_parent_class)->finalize (object); + return; +} + + +// EMIT STATE SIGNAL +void +sound_service_dbus_update_sound_state (SoundServiceDbus* self, + SoundState new_state) +{ + SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (self); + + GVariant* v_output = g_variant_new("(i)", (int)new_state); + + GError * error = NULL; + + if (priv->connection == NULL || + g_dbus_connection_is_closed (priv->connection) == TRUE){ + g_critical ("sound_service_dbus_update_sound_state - connection is %s !!", + priv->connection == NULL? "NULL" : "closed"); + return; + } + + g_debug ("emitting state signal with value %i", (int)new_state); + g_dbus_connection_emit_signal( priv->connection, + NULL, + INDICATOR_SOUND_SERVICE_DBUS_OBJECT_PATH, + INDICATOR_SOUND_DBUS_INTERFACE, + INDICATOR_SOUND_SIGNAL_STATE_UPDATE, + v_output, + &error ); + if (error != NULL) { + g_critical ("Unable to emit signal because : %s", error->message); + g_error_free(error); + } +} + +//HANDLE DBUS METHOD CALLS +static void +bus_method_call (GDBusConnection * connection, + const gchar * sender, + const gchar * path, + const gchar * interface, + const gchar * method, + GVariant * params, + GDBusMethodInvocation * invocation, + gpointer user_data) +{ + SoundServiceDbus* service = SOUND_SERVICE_DBUS(user_data); + g_return_if_fail ( IS_SOUND_SERVICE_DBUS(service) ); + GVariant * retval = NULL; + SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (service); + + if (g_strcmp0(method, "GetSoundState") == 0) { + g_debug("Get state - %i", device_get_state (priv->device)); + retval = g_variant_new ( "(i)", device_get_state (priv->device)); + } + else if (g_strcmp0(method, "BlacklistMediaPlayer") == 0) { + gboolean blacklist; + gchar* player_name; + g_variant_get (params, "(sb)", &player_name, &blacklist); + + g_debug ("BlacklistMediaPlayer - bool %i", blacklist); + g_debug ("BlacklistMediaPlayer - name %s", player_name); + gboolean result = sound_service_dbus_blacklist_player (service, + player_name, + blacklist); + retval = g_variant_new ("(b)", result); + } + else if (g_strcmp0(method, "IsBlacklisted") == 0) { + gchar* player_name; + g_variant_get (params, "(s)", &player_name); + + g_debug ("IsBlacklisted - name %s", player_name); + gboolean result = sound_service_dbus_is_blacklisted (service, + player_name); + retval = g_variant_new ("(b)", result); + } + else if (g_strcmp0(method, "EnableTrackSpecificItems") == 0) { + g_debug ("EnableTrackSpecificItems"); + gchar* player_object_path; + gchar* player_id; + g_variant_get (params, "(os)", &player_object_path, &player_id); + //g_debug ("object path = %s and id = %s", player_object_path, player_id); + g_signal_emit (service, + signals[TRACK_SPECIFIC_ITEM], + 0, + player_object_path, + player_id); + g_free (player_object_path); + g_free (player_id); + + } + else if (g_strcmp0(method, "EnablePlayerSpecificItems") == 0) { + gchar* player_object_path; + gchar* player_id; + g_variant_get (params, "(os)", &player_object_path, &player_id); + g_debug ("PLayer specific item - object path = %s and id = %s", + player_object_path, + player_id); + g_signal_emit (service, + signals[PLAYER_SPECIFIC_ITEM], + 0, + player_object_path, + player_id); + g_free (player_object_path); + g_free (player_id); + } + else { + g_warning("Calling method '%s' on the sound service but it's unknown", method); + } + g_dbus_method_invocation_return_value (invocation, retval); +} + +/** + TODO - Works nicely but refactor into at least two different methods +**/ +static gboolean sound_service_dbus_blacklist_player (SoundServiceDbus* self, + gchar* player_name, + gboolean blacklist) +{ + g_return_val_if_fail (player_name != NULL, FALSE); + g_return_val_if_fail (IS_SOUND_SERVICE_DBUS (self), FALSE); + + GVariant* the_black_list; + gboolean result = FALSE; + GSettings* our_settings; + GVariantIter iter; + gchar *str; + GVariantBuilder builder; + + our_settings = g_settings_new ("com.canonical.indicators.sound"); + the_black_list = g_settings_get_value (our_settings, + "blacklisted-media-players"); + g_variant_iter_init (&iter, the_black_list); + g_variant_builder_init(&builder, G_VARIANT_TYPE_STRING_ARRAY); + + while (g_variant_iter_loop (&iter, "s", &str)){ + g_variant_builder_add (&builder, "s", str); + } + g_variant_iter_init (&iter, the_black_list); + + if (blacklist == TRUE){ + while (g_variant_iter_loop (&iter, "s", &str)){ + g_print ("first pass to check if %s is present\n", str); + if (g_strcmp0 (player_name, str) == 0){ + // Return if its already there + g_debug ("we have this already blacklisted, no need to do anything"); + g_variant_builder_clear (&builder); + g_object_unref (our_settings); + g_variant_unref (the_black_list); + return result; + } + } + // Otherwise blacklist it ! + g_debug ("about to blacklist %s", player_name); + g_variant_builder_add (&builder, "s", player_name); + } + else{ + gboolean present = FALSE; + g_variant_iter_init (&iter, the_black_list); + g_debug ("attempting to UN-blacklist %s", player_name); + + while (g_variant_iter_loop (&iter, "s", &str)){ + if (g_strcmp0 (player_name, str) == 0){ + present = TRUE; + } + } + // It was not there anyway, return false + if (present == FALSE){ + g_debug ("it was not blacklisted ?, no need to do anything"); + g_variant_builder_clear (&builder); + g_object_unref (our_settings); + g_variant_unref (the_black_list); + return result; + } + + // Otherwise free the builder and reconstruct ensuring no duplicates. + g_variant_builder_clear (&builder); + g_variant_builder_init (&builder, G_VARIANT_TYPE_STRING_ARRAY); + + g_variant_iter_init (&iter, the_black_list); + + while (g_variant_iter_loop (&iter, "s", &str)){ + if (g_strcmp0 (player_name, str) != 0){ + g_variant_builder_add (&builder, "s", str); + } + } + } + GVariant* value = g_variant_builder_end (&builder); + result = g_settings_set_value (our_settings, + "blacklisted-media-players", + value); + + g_object_unref (our_settings); + g_variant_unref (the_black_list); + + return result; +} + +static gboolean sound_service_dbus_is_blacklisted (SoundServiceDbus *self, + gchar *player_name) +{ + GSettings *our_settings; + GVariant *the_black_list; + GVariantIter iter; + gchar *str; + gboolean result = FALSE; + + g_return_val_if_fail (player_name != NULL, FALSE); + g_return_val_if_fail (IS_SOUND_SERVICE_DBUS (self), FALSE); + + our_settings = g_settings_new ("com.canonical.indicators.sound"); + the_black_list = g_settings_get_value (our_settings, + "blacklisted-media-players"); + g_variant_iter_init (&iter, the_black_list); + while (g_variant_iter_next (&iter, "s", &str)){ + if (g_strcmp0 (player_name, str) == 0) { + result = TRUE; + g_free (str); + break; + } + g_free (str); + } + + g_object_unref (our_settings); + g_variant_unref (the_black_list); + + return result; +} + diff --git a/configure.ac b/configure.ac index 0e88562..01e1ae4 100644 --- a/configure.ac +++ b/configure.ac @@ -42,7 +42,7 @@ AC_ARG_WITH([gtk], GTK_REQUIRED_VERSION=2.22 GTK3_REQUIRED_VERSION=3.0 INDICATOR_REQUIRED_VERSION=0.3.19 -DBUSMENUGTK_REQUIRED_VERSION=0.3.101 +DBUSMENUGTK_REQUIRED_VERSION=0.5.90 POLKIT_REQUIRED_VERSION=0.92 PULSE_AUDIO_REQUIRED_VERSION=0.9.19 INDICATOR_DISPLAY_OBJECTS=0.1.11 diff --git a/src/indicator-sound.c b/src/indicator-sound.c index b953449..9c8cff7 100644 --- a/src/indicator-sound.c +++ b/src/indicator-sound.c @@ -23,11 +23,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <glib/gi18n.h> #include <gtk/gtk.h> #include <gdk/gdkkeysyms.h> -#if GTK_CHECK_VERSION(3, 0, 0) -#include <libdbusmenu-gtk3/menu.h> -#else #include <libdbusmenu-gtk/menu.h> -#endif #include <libido/idoscalemenuitem.h> #include <gio/gio.h> diff --git a/src/metadata-widget.h b/src/metadata-widget.h index b0123a3..fc6944e 100644 --- a/src/metadata-widget.h +++ b/src/metadata-widget.h @@ -20,11 +20,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #define __METADATA_WIDGET_H__ #include <gtk/gtk.h> -#if GTK_CHECK_VERSION(3, 0, 0) -#include <libdbusmenu-gtk3/menuitem.h> -#else #include <libdbusmenu-gtk/menuitem.h> -#endif G_BEGIN_DECLS diff --git a/src/mute-widget.h b/src/mute-widget.h index 95130a1..88ddd41 100644 --- a/src/mute-widget.h +++ b/src/mute-widget.h @@ -22,11 +22,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <glib.h> #include <glib-object.h> #include <gtk/gtk.h> -#if GTK_CHECK_VERSION(3, 0, 0) -#include <libdbusmenu-gtk3/menuitem.h> -#else #include <libdbusmenu-gtk/menuitem.h> -#endif #include <libindicator/indicator-object.h> G_BEGIN_DECLS diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c index b69f081..899fee8 100644 --- a/src/sound-service-dbus.c +++ b/src/sound-service-dbus.c @@ -228,7 +228,7 @@ show_sound_settings_dialog (DbusmenuMenuitem *mi, { GError * error = NULL; if (!g_spawn_command_line_async("gnome-volume-control --page=applications", &error) && - !g_spawn_command_line_async("gnome-control-center sound", &error) && + !g_spawn_command_line_async("gnome-control-center sound-nua", &error) && !g_spawn_command_line_async("xfce4-mixer", &error)) { g_warning("Unable to show dialog: %s", error->message); diff --git a/src/sound-state-manager.c b/src/sound-state-manager.c index c851407..ac03add 100644 --- a/src/sound-state-manager.c +++ b/src/sound-state-manager.c @@ -80,8 +80,6 @@ sound_state_manager_init (SoundStateManager* self) priv->settings_manager = g_settings_new("com.canonical.indicators.sound"); - sound_state_manager_notification_init (self); - sound_state_manager_prepare_state_image_names (self); sound_state_manager_prepare_blocked_animation (self); @@ -134,6 +132,13 @@ sound_state_manager_class_init (SoundStateManagerClass *klass) static void sound_state_manager_notification_init (SoundStateManager* self) { + static gboolean initialized = FALSE; + + /* one-time lazy initialization */ + if (initialized) + return; + initialized = TRUE; + SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); if (!notify_init(PACKAGE_NAME)) @@ -164,6 +169,8 @@ sound_state_manager_show_notification (SoundStateManager *self, { SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self); + sound_state_manager_notification_init (self); + if (priv->notification == NULL || g_settings_get_boolean (priv->settings_manager, "show-notify-osd-on-scroll") == FALSE){ return; diff --git a/src/transport-widget.h b/src/transport-widget.h index 8c2ce48..b68845f 100644 --- a/src/transport-widget.h +++ b/src/transport-widget.h @@ -20,11 +20,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #define __TRANSPORT_WIDGET_H__ #include <gtk/gtk.h> -#if GTK_CHECK_VERSION(3, 0, 0) -#include <libdbusmenu-gtk3/menuitem.h> -#else #include <libdbusmenu-gtk/menuitem.h> -#endif #include "common-defs.h" diff --git a/src/voip-input-widget.h b/src/voip-input-widget.h index 0e90665..72da80c 100644 --- a/src/voip-input-widget.h +++ b/src/voip-input-widget.h @@ -22,11 +22,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <glib.h> #include <glib-object.h> #include <gtk/gtk.h> -#if GTK_CHECK_VERSION(3, 0, 0) -#include <libdbusmenu-gtk3/menuitem.h> -#else #include <libdbusmenu-gtk/menuitem.h> -#endif G_BEGIN_DECLS diff --git a/src/volume-widget.h b/src/volume-widget.h index 3deb99c..665f39b 100644 --- a/src/volume-widget.h +++ b/src/volume-widget.h @@ -22,11 +22,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <glib.h> #include <glib-object.h> #include <gtk/gtk.h> -#if GTK_CHECK_VERSION(3, 0, 0) -#include <libdbusmenu-gtk3/menuitem.h> -#else #include <libdbusmenu-gtk/menuitem.h> -#endif #include <libindicator/indicator-object.h> G_BEGIN_DECLS |