Merge lp:~cjcurran/indicator-sound/dynamic_sink_switch_smooth_sliding into lp:indicator-sound/0.1

Proposed by Conor Curran
Status: Merged
Merged at revision: not available
Proposed branch: lp:~cjcurran/indicator-sound/dynamic_sink_switch_smooth_sliding
Merge into: lp:indicator-sound/0.1
Diff against target: 417 lines (+134/-86)
3 files modified
src/indicator-sound.c (+36/-55)
src/pulse-manager.c (+89/-22)
src/sound-service.c (+9/-9)
To merge this branch: bzr merge lp:~cjcurran/indicator-sound/dynamic_sink_switch_smooth_sliding
Reviewer Review Type Date Requested Status
Cody Russell (community) Approve
Review via email: mp+19506@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Conor Curran (cjcurran) wrote :

This branch contains fixes to enable dynamic switching of the output devices and change to enable smooth sliding. I had to change some stuff around for this but it should be thoroughly tested .

Revision history for this message
Cody Russell (bratsche) wrote :

It would be nice if you could remove some of the stuff that you're just commenting out, as it's kind of going to clutter up the code for other people reading it. But otherwise, +1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/indicator-sound.c'
2--- src/indicator-sound.c 2010-02-16 16:38:03 +0000
3+++ src/indicator-sound.c 2010-02-17 17:37:14 +0000
4@@ -82,7 +82,7 @@
5 static GtkWidget *volume_slider = NULL;
6 static gboolean new_slider_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
7 static void slider_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GValue * value, GtkWidget *widget);
8-static gboolean user_change_value_event_cb(GtkRange *range, GtkScrollType scroll_type, gdouble input_value, gpointer user_data);
9+/*static gboolean user_change_value_event_cb(GtkRange *range, GtkScrollType scroll_type, gdouble input_value, gpointer user_data);*/
10 static gboolean value_changed_event_cb(GtkRange *range, gpointer user_data);
11 static gboolean key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data);
12
13@@ -148,15 +148,6 @@
14 }
15
16
17-/*static void test_images_hash()*/
18-/*{*/
19-/* g_debug("about to test the images hash"); */
20-/* gchar* current_name = g_hash_table_lookup(volume_states, GINT_TO_POINTER(current_state));*/
21-/* g_debug("start up current image name = %s", current_name); */
22-/* gchar* previous_name = g_hash_table_lookup(volume_states, GINT_TO_POINTER(previous_state));*/
23-/* g_debug("start up previous image name = %s", previous_name); */
24-/*}*/
25-
26 /*
27 Prepare states Array.
28 */
29@@ -264,14 +255,7 @@
30 // DEBUG
31 gdouble current_value = gtk_range_get_value(range);
32 g_debug("SIGNAL- update sink volume - current_value : %f and new value : %f", current_value, volume_percent);
33-
34- // Don't like this solution - too fuzzy
35- // Need the ability to detect if the slider is grabbed
36- if(floor(current_value) != floor(volume_percent))
37- {
38- g_debug("Going to update slider value");
39- gtk_range_set_value(range, volume_percent);
40- }
41+ gtk_range_set_value(range, volume_percent);
42 determine_state_from_volume(volume_percent);
43 }
44
45@@ -337,15 +321,6 @@
46 gtk_image_set_from_icon_name(speaker_image, image_name, GTK_ICON_SIZE_MENU);
47 }
48
49-/*static void revert_state()*/
50-/*{*/
51-
52-/* g_debug("revert state beginning - previous_state = %i", previous_state);*/
53-/* current_state = previous_state;*/
54-/* gchar* image_name = g_hash_table_lookup(volume_states, GINT_TO_POINTER(current_state));*/
55-/* gtk_image_set_from_icon_name(speaker_image, image_name, GTK_ICON_SIZE_MENU);*/
56-/* g_debug("after reverting back to previous state of %i", current_state);*/
57-/*}*/
58
59 static void determine_state_from_volume(gdouble volume_percent)
60 {
61@@ -377,12 +352,16 @@
62 DbusmenuGtkClient *client = dbusmenu_gtkmenu_get_client(menu);
63 dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_SLIDER_MENUITEM_TYPE, new_slider_item);
64
65- // register Key-press listening on the widget
66+ // register Key-press listening on the menu widget as the slider does not allow this.
67 g_signal_connect(menu, "key-press-event", G_CALLBACK(key_press_cb), NULL);
68
69 return GTK_MENU(menu);
70 }
71
72+/**
73+new_slider_item:
74+Create a new dBusMenu Slider item, register the
75+**/
76 static gboolean new_slider_item(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
77 {
78 g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
79@@ -398,7 +377,7 @@
80
81 // register slider changes listening on the range
82 GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)volume_slider);
83- g_signal_connect(slider, "change-value", G_CALLBACK(user_change_value_event_cb), newitem);
84+/* g_signal_connect(slider, "change-value", G_CALLBACK(user_change_value_event_cb), newitem); */
85 g_signal_connect(slider, "value-changed", G_CALLBACK(value_changed_event_cb), newitem);
86
87 // Set images on the ido
88@@ -412,8 +391,10 @@
89 return TRUE;
90 }
91
92-/* Whenever we have a property change on a DbusmenuMenuitem
93- we need to be responsive to that. */
94+/**
95+slider_prop_change_cb:
96+Whenever we have a property change on a DbusmenuMenuitem this will be called.
97+**/
98 static void slider_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GValue * value, GtkWidget *widget)
99 {
100 g_debug("slider_prop_change_cb - dodgy updater ");
101@@ -425,22 +406,21 @@
102 }
103
104 /**
105-This callback will get triggered irregardless of whether its a user change or a programmatic change
106-Our usecase for this particular callback is only interested if the slider is changed by the user hitting either icon
107-which will result in a programmatic value change of 0 or 100 (work around).
108+value_changed_event_cb:
109+This callback will get triggered irregardless of whether its a user change or a programmatic change.
110 **/
111 static gboolean value_changed_event_cb(GtkRange *range, gpointer user_data)
112 {
113- gdouble current_value = gtk_range_get_value(range);
114-/* if(current_value == 0 || current_value == 100)*/
115-/* {*/
116+ gdouble current_value = CLAMP(gtk_range_get_value(range), 0, 100);
117 DbusmenuMenuitem *item = (DbusmenuMenuitem*)user_data;
118 GValue value = {0};
119 g_value_init(&value, G_TYPE_DOUBLE);
120 g_value_set_double(&value, current_value);
121 g_debug("Value changed callback - = %f", current_value);
122- dbusmenu_menuitem_handle_event (item, "slider_change", &value, 0);
123-/* }*/
124+ dbusmenu_menuitem_handle_event (item, "slider_change", &value, 0);
125+ // This is not ideal in that the icon ui will update on ui actions and not on actual service feedback.
126+ // but necessary for now as the server does not send volume update information if the source of change was this ui.
127+ determine_state_from_volume(current_value);
128 return FALSE;
129 }
130
131@@ -450,9 +430,8 @@
132 static gboolean key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data)
133 {
134
135- if(event->length > 0)
136- g_debug("The key event's string is '%s'\n", event->string);
137-
138+/* if(event->length > 0)*/
139+/* g_debug("The key event's string is '%s'\n", event->string);*/
140 GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)volume_slider);
141 GtkRange* range = (GtkRange*)slider;
142 gdouble current_value = gtk_range_get_value(range);
143@@ -502,7 +481,7 @@
144 new_value = CLAMP(new_value, 0, 100);
145 if(new_value != current_value)
146 {
147- g_debug("Attempting to set the range to %f", new_value);
148+ g_debug("Attempting to set the range from the key listener to %f", new_value);
149 gtk_range_set_value(range, new_value);
150 }
151 return FALSE;
152@@ -510,18 +489,20 @@
153
154 /**
155 This callback should only be called when the user actually drags the slider.
156-Turned off for now in favour of the non descriminating call back.
157+Turned off for now in favour of the non descriminating value-changed call back.
158+Once the grabbing listener is implemented on the slider may revert to using this.
159+Its another tool for filtering unwanted volume change updates.
160 **/
161-static gboolean user_change_value_event_cb(GtkRange *range, GtkScrollType scroll_type, gdouble input_value, gpointer user_data)
162-{
163- DbusmenuMenuitem *item = (DbusmenuMenuitem*)user_data;
164- gdouble clamped_input = CLAMP(input_value, 0, 100);
165- GValue value = {0};
166- g_debug("User input on SLIDER - = %f", clamped_input);
167- g_value_init(&value, G_TYPE_DOUBLE);
168- g_value_set_double(&value, clamped_input);
169- dbusmenu_menuitem_handle_event (item, "slider_change", &value, 0);
170- return FALSE;
171-}
172+/*static gboolean user_change_value_event_cb(GtkRange *range, GtkScrollType scroll_type, gdouble input_value, gpointer user_data)*/
173+/*{*/
174+/* DbusmenuMenuitem *item = (DbusmenuMenuitem*)user_data;*/
175+/* gdouble clamped_input = CLAMP(input_value, 0, 100);*/
176+/* GValue value = {0};*/
177+/* g_debug("User input on SLIDER - = %f", clamped_input);*/
178+/* g_value_init(&value, G_TYPE_DOUBLE);*/
179+/* g_value_set_double(&value, clamped_input);*/
180+/* dbusmenu_menuitem_handle_event (item, "slider_change", &value, 0);*/
181+/* return FALSE; */
182+/*} */
183
184
185
186=== modified file 'src/pulse-manager.c'
187--- src/pulse-manager.c 2010-02-17 11:15:00 +0000
188+++ src/pulse-manager.c 2010-02-17 17:37:14 +0000
189@@ -43,10 +43,16 @@
190 static void pulse_sink_input_info_callback(pa_context *c, const pa_sink_input_info *info, int eol, void *userdata);
191 static void pulse_server_info_callback(pa_context *c, const pa_server_info *info, void *userdata);
192 static void update_sink_info(pa_context *c, const pa_sink_info *info, int eol, void *userdata);
193+static void pulse_source_info_callback(pa_context *c, const pa_source_info *i, int eol, void *userdata);
194 static void destroy_sink_info(void *value);
195 static gboolean determine_sink_availability();
196
197
198+/**
199+Refactoring notes
200+Push all UI updates out through update PA state in the service.
201+**/
202+
203 /*
204 Entry point
205 */
206@@ -167,6 +173,13 @@
207 {
208 sink_info *info = (sink_info*)value;
209 pa_operation_unref(pa_context_set_sink_mute_by_index(pulse_context, info->index, GPOINTER_TO_INT(user_data), context_success_callback, NULL));
210+ if(GPOINTER_TO_INT(user_data) == 1){
211+ sound_service_dbus_update_sink_mute(dbus_service, TRUE);
212+ }
213+ else{
214+ sound_service_dbus_update_sink_volume(dbus_service, get_default_sink_volume());
215+ }
216+
217 g_debug("in the pulse manager: mute each sink %i", GPOINTER_TO_INT(user_data));
218 }
219
220@@ -197,8 +210,9 @@
221 g_debug("new volume calculated :%f", (gdouble)new_volume);
222 pa_cvolume dev_vol;
223 pa_cvolume_set(&dev_vol, s->volume.channels, new_volume);
224- // TODO why don't you update the sink_info here with the appropriate pa_cvolume (&dev_vol)
225+ s->volume = dev_vol;
226 pa_operation_unref(pa_context_set_sink_volume_by_index(pulse_context, DEFAULT_SINK_INDEX, &dev_vol, NULL, NULL));
227+
228 }
229
230
231@@ -242,9 +256,9 @@
232 if(device_available == TRUE)
233 {
234 update_pa_state(TRUE, device_available, default_sink_is_muted(), get_default_sink_volume());
235- sound_service_dbus_update_sink_volume(dbus_service, get_default_sink_volume());
236- sound_service_dbus_update_sink_mute(dbus_service, default_sink_is_muted());
237- g_debug("default sink index : %d", DEFAULT_SINK_INDEX);
238+ //sound_service_dbus_update_sink_volume(dbus_service, get_default_sink_volume());
239+ //sound_service_dbus_update_sink_mute(dbus_service, default_sink_is_muted());
240+ //g_debug("default sink index : %d", DEFAULT_SINK_INDEX);
241 }
242 else{
243 //Update the indicator to show PA either is not ready or has no available sink
244@@ -281,7 +295,17 @@
245 else{
246 DEFAULT_SINK_INDEX = info->index;
247 g_debug("Just set the default sink index to %i", DEFAULT_SINK_INDEX);
248- pa_operation_unref(pa_context_get_sink_info_list(c, pulse_sink_info_callback, NULL));
249+ GList *keys = g_hash_table_get_keys(sink_hash);
250+ gint position = g_list_index(keys, GINT_TO_POINTER(info->index));
251+ // Only update sink-list if the index is not in our already fetched list.
252+ if(position < 0)
253+ {
254+ pa_operation_unref(pa_context_get_sink_info_list(c, pulse_sink_info_callback, NULL));
255+ }
256+ else
257+ {
258+ update_pa_state(TRUE, determine_sink_availability(), default_sink_is_muted(), get_default_sink_volume());
259+ }
260 }
261 }
262
263@@ -322,19 +346,22 @@
264 s->description = g_strdup(info->description);
265 s->icon_name = g_strdup(pa_proplist_gets(info->proplist, PA_PROP_DEVICE_ICON_NAME));
266 s->active_port = (info->active_port != NULL);
267- // NASTY!!
268+ s->mute = !!info->mute;
269 gboolean mute_changed = s->mute != !!info->mute;
270- s->mute = !!info->mute;
271+ gboolean volume_changed = (pa_cvolume_equal(&info->volume, &s->volume) == 0);
272 s->volume = info->volume;
273 s->base_volume = info->base_volume;
274 s->channel_map = info->channel_map;
275 if(DEFAULT_SINK_INDEX == s->index)
276 {
277 //update the UI
278- pa_volume_t vol = pa_cvolume_avg(&s->volume);
279- gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM;
280- g_debug("Updating volume from PA manager with volume = %f", volume_percent);
281- sound_service_dbus_update_sink_volume(dbus_service, volume_percent);
282+ if (volume_changed == TRUE)
283+ {
284+ pa_volume_t vol = pa_cvolume_avg(&s->volume);
285+ gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM;
286+ g_debug("Updating volume from PA manager with volume = %f", volume_percent);
287+ sound_service_dbus_update_sink_volume(dbus_service, volume_percent);
288+ }
289 if (mute_changed == TRUE)
290 sound_service_dbus_update_sink_mute(dbus_service, s->mute);
291 update_mute_ui(s->mute);
292@@ -382,24 +409,64 @@
293 pa_operation_unref(operation);
294 }
295
296-static void subscribed_events_callback(pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata){
297- switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
298+static void pulse_source_info_callback(pa_context *c, const pa_source_info *i, int eol, void *userdata)
299+{
300+ g_debug("pulse source info callback");
301+}
302+
303+
304+static void subscribed_events_callback(pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata)
305+{
306+ switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)
307+ {
308 case PA_SUBSCRIPTION_EVENT_SINK:
309- if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
310- //TODO handle the remove event => if its our default sink - grey out the ui with update_pa_state
311- } else {
312+ g_debug("PA_SUBSCRIPTION_EVENT_SINK event triggered");
313+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
314+ {
315+ //TODO handle the remove event => if its our default sink - update date pa state
316+ } else
317+ {
318 pa_operation_unref(pa_context_get_sink_info_by_index(c, index, update_sink_info, userdata));
319 }
320 break;
321 case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
322- // This will be triggered when the sink receives input from a new stream
323- // If a playback client is paused and then resumed this will NOT trigger this event.
324- pa_operation_unref(pa_context_get_sink_input_info(c, index, pulse_sink_input_info_callback, userdata));
325- break;
326+ g_debug("PA_SUBSCRIPTION_EVENT_SINK_INPUT event triggered!!");
327+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
328+ {
329+ //TODO handle the remove event
330+ }
331+ else
332+ {
333+ pa_operation_unref(pa_context_get_sink_input_info(c, index, pulse_sink_input_info_callback, userdata));
334+ }
335+ break;
336+ case PA_SUBSCRIPTION_EVENT_SOURCE:
337+ g_debug("PA_SUBSCRIPTION_EVENT_SOURCE of some description ???");
338+
339+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
340+ {
341+ //TODO handle the remove event
342+ }
343+ else
344+ {
345+ pa_operation *o;
346+ if (!(o = pa_context_get_source_info_by_index(c, index, pulse_source_info_callback, userdata))) {
347+ g_warning("pa_context_get_source_info_by_index() failed");
348+ return;
349+ }
350+ pa_operation_unref(o);
351+ }
352+ break;
353 case PA_SUBSCRIPTION_EVENT_SERVER:
354- if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_SINK ) {
355- g_debug("server change of some sink type ???");
356+ g_debug("PA_SUBSCRIPTION_EVENT_SERVER change of some description ???");
357+ pa_operation *o;
358+ if(!(o = pa_context_get_server_info(c, pulse_server_info_callback, userdata)))
359+ {
360+ g_warning("pa_context_get_server_info() failed");
361+ return;
362 }
363+ pa_operation_unref(o);
364+ break;
365 }
366 }
367
368
369=== modified file 'src/sound-service.c'
370--- src/sound-service.c 2010-02-17 11:15:00 +0000
371+++ src/sound-service.c 2010-02-17 17:37:14 +0000
372@@ -97,6 +97,7 @@
373 {
374 b_all_muted = incoming_mute_value;
375 dbusmenu_menuitem_property_set(mute_all_menuitem, DBUSMENU_MENUITEM_PROP_LABEL, _(b_all_muted == FALSE ? "Mute All" : "Unmute"));
376+ //dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(volume_slider_menuitem), DBUSMENU_MENUITEM_PROP_ENABLED, b_all_muted);
377 }
378
379 static void set_global_mute_from_ui()
380@@ -104,13 +105,7 @@
381 b_all_muted = !b_all_muted;
382 toggle_global_mute(b_all_muted);
383 dbusmenu_menuitem_property_set(mute_all_menuitem, DBUSMENU_MENUITEM_PROP_LABEL, _(b_all_muted == FALSE ? "Mute All" : "Unmute"));
384-
385-/* GValue value = {0};*/
386-/* g_value_init(&value, G_TYPE_DOUBLE);*/
387-/* g_value_set_double(&value, 99.0);*/
388-/* // Testing*/
389-/* g_debug("BUGGY volume update");*/
390-/* dbusmenu_menuitem_property_set_value(DBUSMENU_MENUITEM(volume_slider_menuitem), DBUSMENU_SLIDER_MENUITEM_PROP_VOLUME, &value);*/
391+ //dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(volume_slider_menuitem), DBUSMENU_MENUITEM_PROP_ENABLED, b_all_muted);
392 }
393
394
395@@ -137,7 +132,12 @@
396 b_pulse_ready = pa_state;
397 volume_percent = percent;
398 g_debug("update pa state with state %i, availability of %i, mute value of %i and a volume percent is %f", pa_state, sink_available, sink_muted, volume_percent);
399- rebuild_sound_menu(root_menuitem, dbus_interface);
400+ sound_service_dbus_update_sink_volume(dbus_interface, percent);
401+ sound_service_dbus_update_sink_mute(dbus_interface, sink_muted);
402+
403+ // Only rebuild the menu on start up...
404+ if(volume_slider_menuitem == NULL)
405+ rebuild_sound_menu(root_menuitem, dbus_interface);
406 }
407
408
409@@ -169,7 +169,7 @@
410 dbusmenu_server_set_root(server, root_menuitem);
411 establish_pulse_activities(dbus_interface);
412
413-/* // THIS DOES NOT WORK FROM HERE*/
414+/* // THIS DOES NOT WORK FROM HERE - race condition ?!?*/
415 /* GValue value = {0};*/
416 /* g_value_init(&value, G_TYPE_DOUBLE);*/
417 /* g_value_set_double(&value, volume_percent * 100);*/

Subscribers

People subscribed via source and target branches