Index: applet.c =================================================================== --- applet.c (revision 10461) +++ applet.c (working copy) @@ -79,7 +79,12 @@ PanelAppletOrient orient); static void gnome_volume_applet_refresh (GnomeVolumeApplet *applet, - gboolean force_refresh); + gboolean force_refresh, + gdouble volume, + gint mute); + +static void cb_notify_message (GstBus *bus, GstMessage *message, gpointer data); + static gboolean cb_check (gpointer data); static void cb_volume (GtkAdjustment *adj, @@ -242,6 +247,12 @@ /* i18n */ ao = gtk_widget_get_accessible (GTK_WIDGET (applet)); atk_object_set_name (ao, _("Volume Control")); + + /* Bus for notifications */ + applet->bus = gst_bus_new (); + gst_bus_add_signal_watch (applet->bus); + g_signal_connect (G_OBJECT (applet->bus), "message::element", + (GCallback) cb_notify_message, applet); } /* Parse the list of tracks that are stored in GConf */ @@ -368,12 +379,33 @@ return FALSE; applet->mixer = g_object_ref (active_element); + gst_element_set_bus (GST_ELEMENT (applet->mixer), applet->bus); applet->tracks = active_tracks; g_list_foreach (applet->tracks, (GFunc) g_object_ref, NULL); return TRUE; } +static void +gnome_volume_applet_setup_timeout (GnomeVolumeApplet *applet) +{ + gboolean need_timeout = TRUE; + need_timeout = ((gst_mixer_get_mixer_flags (GST_MIXER (applet->mixer)) & + GST_MIXER_FLAG_AUTO_NOTIFICATIONS) == 0); + + if (need_timeout) { + if (applet->timeout == 0) { + applet->timeout = g_timeout_add (100, cb_check, applet); + } + } + else { + if (applet->timeout != 0) { + g_source_remove (applet->timeout); + applet->timeout = 0; + } + } +} + gboolean gnome_volume_applet_setup (GnomeVolumeApplet *applet, GList *elements) @@ -435,10 +467,9 @@ component = panel_applet_get_popup_component (PANEL_APPLET (applet)); g_signal_connect (component, "ui-event", G_CALLBACK (cb_ui_event), applet); - gnome_volume_applet_refresh (applet, TRUE); - if (res) { - applet->timeout = g_timeout_add (100, cb_check, applet); - } + gnome_volume_applet_refresh (applet, TRUE, -1, -1); + if (res) + gnome_volume_applet_setup_timeout (applet); if (res) { /* gconf */ @@ -479,6 +510,11 @@ g_list_free (applet->elements); applet->elements = NULL; } + gst_bus_remove_signal_watch (applet->bus); + if (applet->bus) { + gst_object_unref (applet->bus); + applet->bus = NULL; + } if (applet->tracks) { g_list_foreach (applet->tracks, (GFunc) g_object_unref, NULL); @@ -673,11 +709,11 @@ component = panel_applet_get_popup_component (PANEL_APPLET (applet)); bonobo_ui_component_set_prop (component, "/commands/Mute", - "state", mute ? "1" : "0", NULL); + "state", !mute ? "1" : "0", NULL); /* update graphic - this should happen automagically after the next * idle call, but apparently doesn't for some people... */ - gnome_volume_applet_refresh (applet, TRUE); + gnome_volume_applet_refresh (applet, TRUE, -1, !mute); } /* @@ -940,7 +976,7 @@ } init_pixbufs (applet); - gnome_volume_applet_refresh (applet, TRUE); + gnome_volume_applet_refresh (applet, TRUE, -1, -1); } static void @@ -990,15 +1026,23 @@ { int range = track->max_volume - track->min_volume; gdouble scale = ((gdouble) range) / 100; - int *volumes, n; + int *volumes, n, volint; - volume *= scale; - volume += track->min_volume; + if (volume == 1.0) { + volint = track->max_volume; + } else if (volume == 0.0) { + volint = track->min_volume; + } else { + volume *= scale; + volume += track->min_volume; + volint = lrint (volume); + } volumes = g_new (gint, track->num_channels); for (n = 0; n < track->num_channels; n++) - volumes[n] = lrint (volume); + volumes[n] = volint; gst_mixer_set_volume (mixer, track, volumes); + g_free (volumes); } @@ -1049,6 +1093,8 @@ applet->lock = FALSE; applet->force_next_update = TRUE; + + gnome_volume_applet_refresh (GNOME_VOLUME_APPLET (data), FALSE, v, -1); } /* @@ -1059,31 +1105,40 @@ static void gnome_volume_applet_refresh (GnomeVolumeApplet *applet, - gboolean force_refresh) + gboolean force_refresh, + gdouble volume, + gint mute) { BonoboUIComponent *component; GdkPixbuf *pixbuf; gint n; - gdouble volume; - gboolean mute, did_change; + gboolean show_mute, did_change; gchar *tooltip_str; GstMixerTrack *first_track; GString *track_names; GList *iter; + show_mute = 0; + if (!applet->mixer) { n = 0; - mute = FALSE; + show_mute = 1; + mute = 0; } else if (!applet->tracks) { return; } else { - /* only first track */ first_track = g_list_first (applet->tracks)->data; - volume = gnome_volume_applet_get_volume (applet->mixer, first_track); - mute = GST_MIXER_TRACK_HAS_FLAG (first_track, - GST_MIXER_TRACK_MUTE); - if (volume <= 0) { - mute = TRUE; + + if (volume == -1) { + /* only first track */ + volume = gnome_volume_applet_get_volume (applet->mixer, first_track); + } + if (mute == -1) { + mute = GST_MIXER_TRACK_HAS_FLAG (first_track, + GST_MIXER_TRACK_MUTE) ? 1 : 0; + } + if (volume <= 0 || mute) { + show_mute = 1; n = 0; } else { @@ -1101,7 +1156,7 @@ applet->force_next_update = FALSE; if (did_change) { - if (mute) { + if (show_mute) { pixbuf = applet->pix[0]; } else { pixbuf = applet->pix[n]; @@ -1125,7 +1180,7 @@ track_names = g_string_append (track_names, track->label); } - if (mute) { + if (show_mute) { tooltip_str = g_strdup_printf (_("%s: muted"), track_names->str); } else { /* Translator comment: I'm not all too sure if this makes sense @@ -1152,10 +1207,56 @@ "state", mute ? "1" : "0", NULL); } +static void +cb_notify_message (GstBus *bus, GstMessage *message, gpointer data) +{ + GnomeVolumeApplet *applet = GNOME_VOLUME_APPLET (data); + GstMixerMessageType type; + GstMixerTrack *first_track; + GstMixerTrack *track = NULL; + gint mute; + gdouble volume; + + if (applet->tracks == NULL || + GST_MESSAGE_SRC (message) != GST_OBJECT (applet->mixer)) { + /* No tracks, or not from our mixer - can't update anything anyway */ + return; + } + + volume = mute = -1; + + first_track = g_list_first (applet->tracks)->data; + + /* This code only calls refresh if the first_track changes, because the + * refresh code only retrieves the current value from that track anyway */ + type = gst_mixer_message_get_type (message); + if (type == GST_MIXER_MESSAGE_MUTE_TOGGLED) { + gboolean muted; + gst_mixer_message_parse_mute_toggled (message, &track, &muted); + mute = muted ? 1 : 0; + } + else if (type == GST_MIXER_MESSAGE_VOLUME_CHANGED) { + gint n, num_channels, *vols; + volume = 0.0; + + gst_mixer_message_parse_volume_changed (message, &track, &vols, &num_channels); + for (n = 0; n < num_channels; n++) + volume += vols[n]; + volume /= track->num_channels; + volume = 100 * volume / (track->max_volume - track->min_volume); + } else + { + return; + } + + if (first_track == track) + gnome_volume_applet_refresh (GNOME_VOLUME_APPLET (data), FALSE, volume, mute); +} + static gboolean cb_check (gpointer data) { - gnome_volume_applet_refresh (GNOME_VOLUME_APPLET (data), FALSE); + gnome_volume_applet_refresh (GNOME_VOLUME_APPLET (data), FALSE, -1, -1); return TRUE; } @@ -1214,6 +1315,8 @@ /* save */ gst_object_replace ((GstObject **) &applet->mixer, item->data); gst_element_set_state (old_element, GST_STATE_NULL); + + gnome_volume_applet_setup_timeout (applet); newdevice = TRUE; } break; @@ -1374,7 +1477,7 @@ GnomeVolumeApplet *applet = GNOME_VOLUME_APPLET (data); init_pixbufs (applet); - gnome_volume_applet_refresh (applet, TRUE); + gnome_volume_applet_refresh (applet, TRUE, -1, -1); } /* Index: applet.h =================================================================== --- applet.h (revision 10461) +++ applet.h (working copy) @@ -71,6 +71,7 @@ /* element */ GstMixer *mixer; + GstBus *bus; gboolean lock; gint state; GList *tracks;