diff options
Diffstat (limited to 'mate-volume-control/src/gvc-applet.c')
-rw-r--r-- | mate-volume-control/src/gvc-applet.c | 350 |
1 files changed, 163 insertions, 187 deletions
diff --git a/mate-volume-control/src/gvc-applet.c b/mate-volume-control/src/gvc-applet.c index b2807f1..4522a8f 100644 --- a/mate-volume-control/src/gvc-applet.c +++ b/mate-volume-control/src/gvc-applet.c @@ -18,28 +18,25 @@ * */ -#include "config.h" +// XXX there are some bugs unrelated to the port, let's see if I can fix them: +// - clicking in the slider makes it disappear +// - drag all the way down to mute, then start dragging up and the change won't +// be reflected until i stop dragging +// - disable the slider if the volume is not changable -#include <stdlib.h> -#include <stdio.h> -#include <fcntl.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> +#include "config.h" #include <glib.h> #include <glib/gi18n.h> #include <gtk/gtk.h> +#include <libmatemixer/matemixer.h> #include "gvc-applet.h" -#include "gvc-mixer-control.h" #include "gvc-stream-status-icon.h" #define GVC_APPLET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_APPLET, GvcAppletPrivate)) -#define SCALE_SIZE 128 - -static const char *output_icon_names[] = { +static const gchar *icon_names_output[] = { "audio-volume-muted", "audio-volume-low", "audio-volume-medium", @@ -47,7 +44,7 @@ static const char *output_icon_names[] = { NULL }; -static const char *input_icon_names[] = { +static const gchar *icon_names_input[] = { "audio-input-microphone-muted", "audio-input-microphone-low", "audio-input-microphone-medium", @@ -55,211 +52,182 @@ static const char *input_icon_names[] = { NULL }; -struct GvcAppletPrivate +struct _GvcAppletPrivate { - GvcStreamStatusIcon *input_status_icon; - GvcStreamStatusIcon *output_status_icon; - GvcMixerControl *control; + GvcStreamStatusIcon *icon_input; + GvcStreamStatusIcon *icon_output; + gboolean running; + MateMixerControl *control; }; -static void gvc_applet_class_init (GvcAppletClass *klass); -static void gvc_applet_init (GvcApplet *applet); -static void gvc_applet_finalize (GObject *object); +static void gvc_applet_class_init (GvcAppletClass *klass); +static void gvc_applet_init (GvcApplet *applet); G_DEFINE_TYPE (GvcApplet, gvc_applet, G_TYPE_OBJECT) static void -maybe_show_status_icons (GvcApplet *applet) +update_icon_input (GvcApplet *applet) { - gboolean show; - GvcMixerStream *stream; - GSList *source_outputs, *l; - - show = TRUE; - stream = gvc_mixer_control_get_default_sink (applet->priv->control); - if (stream == NULL) { - show = FALSE; - } - gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->priv->output_status_icon), show); - - - show = FALSE; - stream = gvc_mixer_control_get_default_source (applet->priv->control); - source_outputs = gvc_mixer_control_get_source_outputs (applet->priv->control); - if (stream != NULL && source_outputs != NULL) { - /* Check that we're not trying to add the peak detector - * as an application doing recording */ - for (l = source_outputs ; l ; l = l->next) { - GvcMixerStream *s = l->data; - const char *id; - - id = gvc_mixer_stream_get_application_id (s); - if (id == NULL) { - show = TRUE; - break; - } + MateMixerStream *stream; + gboolean show = FALSE; - if (!g_str_equal (id, "org.mate.VolumeControl") && - !g_str_equal (id, "org.PulseAudio.pavucontrol")) { - show = TRUE; - break; + /* Enable the input icon in case there is an input stream present and there + * is a non-mixer application using the input */ + stream = mate_mixer_control_get_default_input_stream (applet->priv->control); + if (stream != NULL) { + const gchar *app; + const GList *inputs = + mate_mixer_control_list_streams (applet->priv->control); + + while (inputs) { + MateMixerStream *input = MATE_MIXER_STREAM (inputs->data); + MateMixerStreamFlags flags = mate_mixer_stream_get_flags (input); + + if (flags & MATE_MIXER_STREAM_INPUT && + flags & MATE_MIXER_STREAM_APPLICATION) { + MateMixerClientStream *client = + MATE_MIXER_CLIENT_STREAM (input); + + app = mate_mixer_client_stream_get_app_id (client); + if (app == NULL) { + /* A recording application which has no + * identifier set */ + show = TRUE; + break; + } + + if (!g_str_equal (app, "org.mate.VolumeControl") && + !g_str_equal (app, "org.gnome.VolumeControl") && + !g_str_equal (app, "org.PulseAudio.pavucontrol")) { + show = TRUE; + break; + } } + inputs = inputs->next; } } - gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->priv->input_status_icon), show); - g_slist_free (source_outputs); -} + gvc_stream_status_icon_set_mixer_stream (applet->priv->icon_input, stream); -void -gvc_applet_start (GvcApplet *applet) -{ - g_return_if_fail (GVC_IS_APPLET (applet)); - - maybe_show_status_icons (applet); + gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->priv->icon_input), show); } static void -gvc_applet_dispose (GObject *object) +update_icon_output (GvcApplet *applet) { - GvcApplet *applet = GVC_APPLET (object); + MateMixerStream *stream; - if (applet->priv->control != NULL) { - g_object_unref (applet->priv->control); - applet->priv->control = NULL; - } + stream = mate_mixer_control_get_default_output_stream (applet->priv->control); - G_OBJECT_CLASS (gvc_applet_parent_class)->dispose (object); + gvc_stream_status_icon_set_mixer_stream (applet->priv->icon_output, stream); + + /* Enable the output icon in case there is an output stream present */ + gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->priv->icon_output), + (stream != NULL) ? TRUE : FALSE); } -static void -update_default_source (GvcApplet *applet) +void +gvc_applet_start (GvcApplet *applet) { - GvcMixerStream *stream; + g_return_if_fail (GVC_IS_APPLET (applet)); - stream = gvc_mixer_control_get_default_source (applet->priv->control); - if (stream != NULL) { - gvc_stream_status_icon_set_mixer_stream (applet->priv->input_status_icon, - stream); - maybe_show_status_icons(applet); - } else { - g_debug ("Unable to get default source, or no source available"); - } -} + if (G_UNLIKELY (applet->priv->running)) + return; -static void -update_default_sink (GvcApplet *applet) -{ - GvcMixerStream *stream; + if (mate_mixer_control_open (applet->priv->control) == FALSE) { + /* Normally this should never happen, in the worst case we + * should end up with the Null module */ + g_warning ("Failed to connect to a sound system"); - stream = gvc_mixer_control_get_default_sink (applet->priv->control); - if (stream != NULL) { - gvc_stream_status_icon_set_mixer_stream (applet->priv->output_status_icon, - stream); - maybe_show_status_icons(applet); - } else { - g_warning ("Unable to get default sink"); + gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->priv->icon_output), + FALSE); + gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->priv->icon_input), + FALSE); } -} -static void -on_control_ready (GvcMixerControl *control, - GvcApplet *applet) -{ - update_default_sink (applet); - update_default_source (applet); + applet->priv->running = TRUE; } static void -on_control_connecting (GvcMixerControl *control, - GvcApplet *applet) +on_control_state_notify (MateMixerControl *control, + GParamSpec *pspec, + GvcApplet *applet) { - g_debug ("Connecting.."); + MateMixerState state = mate_mixer_control_get_state (control); + + if (state == MATE_MIXER_STATE_FAILED) + g_warning ("Failed to connect to a sound system"); + + /* Each status change may affect the visibility of the icons */ + update_icon_output (applet); + update_icon_input (applet); } static void -on_control_default_sink_changed (GvcMixerControl *control, - guint id, - GvcApplet *applet) +on_control_default_input_notify (MateMixerControl *control, + GParamSpec *pspec, + GvcApplet *applet) { - update_default_sink (applet); + update_icon_input (applet); } static void -on_control_default_source_changed (GvcMixerControl *control, - guint id, - GvcApplet *applet) +on_control_default_output_notify (MateMixerControl *control, + GParamSpec *pspec, + GvcApplet *applet) { - update_default_source (applet); + update_icon_output (applet); } static void -on_control_stream_removed (GvcMixerControl *control, - guint id, - GvcApplet *applet) +on_control_stream_added (MateMixerControl *control, + const gchar *name, + GvcApplet *applet) { - maybe_show_status_icons (applet); + MateMixerStream *stream; + MateMixerStreamFlags flags; + + stream = mate_mixer_control_get_stream (control, name); + if (G_UNLIKELY (stream == NULL)) + return; + + flags = mate_mixer_stream_get_flags (stream); + + /* Newly added input application stream may cause the input status + * icon to change visibility */ + if (flags & MATE_MIXER_STREAM_INPUT && + flags & MATE_MIXER_STREAM_APPLICATION) + update_icon_input (applet); } static void -on_control_stream_added (GvcMixerControl *control, - guint id, - GvcApplet *applet) +on_control_stream_removed (MateMixerControl *control, + const gchar *name, + GvcApplet *applet) { - maybe_show_status_icons (applet); + /* The removed stream could be an application input, which may cause + * the input status icon to disappear */ + update_icon_input (applet); } -static GObject * -gvc_applet_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_params) +static void +gvc_applet_dispose (GObject *object) { - GObject *object; - GvcApplet *self; - - object = G_OBJECT_CLASS (gvc_applet_parent_class)->constructor (type, n_construct_properties, construct_params); - - self = GVC_APPLET (object); - - self->priv->control = gvc_mixer_control_new ("MATE Volume Control Applet"); - g_signal_connect (self->priv->control, - "ready", - G_CALLBACK (on_control_ready), - self); - g_signal_connect (self->priv->control, - "connecting", - G_CALLBACK (on_control_connecting), - self); - g_signal_connect (self->priv->control, - "default-sink-changed", - G_CALLBACK (on_control_default_sink_changed), - self); - g_signal_connect (self->priv->control, - "default-source-changed", - G_CALLBACK (on_control_default_source_changed), - self); - g_signal_connect (self->priv->control, - "stream-added", - G_CALLBACK (on_control_stream_added), - self); - g_signal_connect (self->priv->control, - "stream-removed", - G_CALLBACK (on_control_stream_removed), - self); + GvcApplet *applet = GVC_APPLET (object); - gvc_mixer_control_open (self->priv->control); + g_clear_object (&applet->priv->control); + g_clear_object (&applet->priv->icon_input); + g_clear_object (&applet->priv->icon_output); - return object; + G_OBJECT_CLASS (gvc_applet_parent_class)->dispose (object); } static void gvc_applet_class_init (GvcAppletClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->finalize = gvc_applet_finalize; object_class->dispose = gvc_applet_dispose; - object_class->constructor = gvc_applet_constructor; g_type_class_add_private (klass, sizeof (GvcAppletPrivate)); } @@ -269,42 +237,50 @@ gvc_applet_init (GvcApplet *applet) { applet->priv = GVC_APPLET_GET_PRIVATE (applet); - applet->priv->output_status_icon = gvc_stream_status_icon_new (NULL, - output_icon_names); - gvc_stream_status_icon_set_display_name (applet->priv->output_status_icon, - _("Output")); - gtk_status_icon_set_title (GTK_STATUS_ICON (applet->priv->output_status_icon), - _("Sound Output Volume")); - applet->priv->input_status_icon = gvc_stream_status_icon_new (NULL, - input_icon_names); - gvc_stream_status_icon_set_display_name (applet->priv->input_status_icon, - _("Input")); - gtk_status_icon_set_title (GTK_STATUS_ICON (applet->priv->input_status_icon), - _("Microphone Volume")); -} - -static void -gvc_applet_finalize (GObject *object) -{ - GvcApplet *applet; + applet->priv->icon_input = gvc_stream_status_icon_new (NULL, icon_names_input); + applet->priv->icon_output = gvc_stream_status_icon_new (NULL, icon_names_output); - g_return_if_fail (object != NULL); - g_return_if_fail (GVC_IS_APPLET (object)); - - applet = GVC_APPLET (object); - - g_return_if_fail (applet->priv != NULL); + gvc_stream_status_icon_set_display_name (applet->priv->icon_input, _("Input")); + gvc_stream_status_icon_set_display_name (applet->priv->icon_output, _("Output")); + gtk_status_icon_set_title (GTK_STATUS_ICON (applet->priv->icon_input), + _("Microphone Volume")); + gtk_status_icon_set_title (GTK_STATUS_ICON (applet->priv->icon_output), + _("Sound Output Volume")); - G_OBJECT_CLASS (gvc_applet_parent_class)->finalize (object); + applet->priv->control = mate_mixer_control_new (); + + mate_mixer_control_set_app_name (applet->priv->control, + _("MATE Volume Control Applet")); + + mate_mixer_control_set_app_id (applet->priv->control, GVC_APPLET_DBUS_NAME); + mate_mixer_control_set_app_version (applet->priv->control, VERSION); + mate_mixer_control_set_app_icon (applet->priv->control, "multimedia-volume-control"); + + g_signal_connect (applet->priv->control, + "notify::state", + G_CALLBACK (on_control_state_notify), + applet); + g_signal_connect (applet->priv->control, + "notify::default-input", + G_CALLBACK (on_control_default_input_notify), + applet); + g_signal_connect (applet->priv->control, + "notify::default-output", + G_CALLBACK (on_control_default_output_notify), + applet); + g_signal_connect (applet->priv->control, + "stream-added", + G_CALLBACK (on_control_stream_added), + applet); + g_signal_connect (applet->priv->control, + "stream-removed", + G_CALLBACK (on_control_stream_removed), + applet); } GvcApplet * gvc_applet_new (void) { - GObject *applet; - - applet = g_object_new (GVC_TYPE_APPLET, NULL); - - return GVC_APPLET (applet); + return g_object_new (GVC_TYPE_APPLET, NULL); } |