~v-geronimos/pama/0.2

« back to all changes in this revision

Viewing changes to src/pama-sink-input-widget.c

  • Committer: Vassili Geronimos
  • Date: 2010-04-22 21:08:38 UTC
  • mfrom: (11.1.31 trunk)
  • Revision ID: v.geronimos@gmail.com-20100422210838-6mvo43j7aj51xfox
Sync with trunk for 0.2.2 release

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
#include "widget-settings.h"
29
29
 
30
30
static void     pama_sink_input_widget_class_init(PamaSinkInputWidgetClass *klass);
31
 
static void     pama_sink_input_widget_init(PamaSinkInputWidget *self);
 
31
static void     pama_sink_input_widget_init(PamaSinkInputWidget *widget);
32
32
static void     pama_sink_input_widget_set_property(GObject *gobject, guint property_id, const GValue *value, GParamSpec *pspec);
33
33
static GObject* pama_sink_input_widget_constructor(GType gtype, guint n_properties, GObjectConstructParam *properties);
34
34
static void     pama_sink_input_widget_dispose(GObject *gobject);
35
35
static void     pama_sink_input_widget_weak_ref_notify(gpointer data, GObject *where_the_object_was);
36
36
 
37
 
static void     pama_sink_input_widget_sink_input_notify(GObject *gobject, GParamSpec *pspec, PamaSinkInputWidget *self);
38
 
 
39
 
static void     pama_sink_input_widget_update_values(PamaSinkInputWidget *self);
40
 
static void     pama_sink_input_widget_mute_toggled(GtkToggleButton *togglebutton, PamaSinkInputWidget *self);
41
 
static void     pama_sink_input_widget_volume_changed(GtkRange *range, PamaSinkInputWidget *self);
42
 
 
43
 
static void     pama_sink_input_widget_sink_button_clicked(GtkButton *button, PamaSinkInputWidget *self);
44
 
static void     pama_sink_input_widget_sink_menu_hidden(GtkWidget *menu_window, PamaSinkInputWidget *self);
45
 
static void     pama_sink_input_widget_sink_menu_item_toggled(GtkCheckMenuItem *item, PamaSinkInputWidget *self);
 
37
static void     pama_sink_input_widget_sink_input_notify(GObject *gobject, GParamSpec *pspec, PamaSinkInputWidget *widget);
 
38
 
 
39
static void     pama_sink_input_widget_update_values(PamaSinkInputWidget *widget);
 
40
static void     pama_sink_input_widget_mute_toggled(GtkToggleButton *togglebutton, PamaSinkInputWidget *widget);
 
41
static void     pama_sink_input_widget_volume_changed(GtkRange *range, PamaSinkInputWidget *widget);
 
42
 
 
43
static void     pama_sink_input_widget_sink_button_clicked(GtkButton *button, PamaSinkInputWidget *widget);
 
44
static void     pama_sink_input_widget_sink_menu_hidden(GtkWidget *menu_window, PamaSinkInputWidget *widget);
 
45
static void     pama_sink_input_widget_sink_menu_item_toggled(GtkCheckMenuItem *item, PamaSinkInputWidget *widget);
 
46
 
 
47
struct _PamaSinkInputWidgetPrivate
 
48
{
 
49
        GtkWidget *icon, *name, *volume, *value, *mute, *sink_button, *sink_menu, *sink_button_image;
 
50
        GtkSizeGroup       *icon_sizegroup;
 
51
        PamaPulseContext   *context;
 
52
        PamaPulseSinkInput *sink_input;
 
53
        gboolean            updating;
 
54
        
 
55
        gulong context_notify_handler_id, sink_input_notify_handler_id;
 
56
};
46
57
 
47
58
G_DEFINE_TYPE(PamaSinkInputWidget, pama_sink_input_widget, GTK_TYPE_HBOX);
48
 
 
 
59
#define PAMA_SINK_INPUT_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PAMA_TYPE_SINK_INPUT_WIDGET, PamaSinkInputWidgetPrivate))
49
60
 
50
61
enum 
51
62
{
52
63
        PROP_0,
53
64
 
54
65
        PROP_SINK_INPUT,
55
 
        PROP_CONTEXT
 
66
        PROP_CONTEXT,
 
67
        PROP_ICON_SIZEGROUP
56
68
};
57
69
enum
58
70
{
84
96
                                    G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
85
97
        g_object_class_install_property(gobject_class, PROP_CONTEXT, pspec);
86
98
 
 
99
        pspec = g_param_spec_object("icon-sizegroup",
 
100
                                    "Icon sizegroup",
 
101
                                    "The GtkSizeGroup to add the sink input's icon to.",
 
102
                                    GTK_TYPE_SIZE_GROUP,
 
103
                                    G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
 
104
        g_object_class_install_property(gobject_class, PROP_ICON_SIZEGROUP, pspec);
 
105
 
87
106
        widget_signals[REORDER_REQUEST_SIGNAL] =
88
107
                g_signal_new("reorder-request",
89
108
                             G_TYPE_FROM_CLASS(gobject_class),
94
113
                             g_cclosure_marshal_VOID__VOID,
95
114
                             G_TYPE_NONE,
96
115
                             0);
 
116
 
 
117
        g_type_class_add_private(klass, sizeof(PamaSinkInputWidgetPrivate));
97
118
}
98
119
 
99
 
static void pama_sink_input_widget_init(PamaSinkInputWidget *self)
 
120
static void pama_sink_input_widget_init(PamaSinkInputWidget *widget)
100
121
{
101
122
}
102
123
 
103
124
static void pama_sink_input_widget_set_property(GObject *gobject, guint property_id, const GValue *value, GParamSpec *pspec)
104
125
{
105
 
        PamaSinkInputWidget *self = PAMA_SINK_INPUT_WIDGET(gobject);
 
126
        PamaSinkInputWidget *widget = PAMA_SINK_INPUT_WIDGET(gobject);
 
127
        PamaSinkInputWidgetPrivate *priv = PAMA_SINK_INPUT_WIDGET_GET_PRIVATE(widget);
106
128
 
107
129
        switch(property_id)
108
130
        {
109
131
                case PROP_SINK_INPUT:
110
 
                        self->sink_input = g_value_get_object(value);
111
 
                        g_object_weak_ref(G_OBJECT(self->sink_input), pama_sink_input_widget_weak_ref_notify, self);
 
132
                        priv->sink_input = g_value_get_object(value);
 
133
                        g_object_weak_ref(G_OBJECT(priv->sink_input), pama_sink_input_widget_weak_ref_notify, widget);
112
134
                        break;
113
135
 
114
136
                case PROP_CONTEXT:
115
 
                        self->context = g_value_get_object(value);
116
 
                        g_object_weak_ref(G_OBJECT(self->context), pama_sink_input_widget_weak_ref_notify, self);
 
137
                        priv->context = g_value_get_object(value);
 
138
                        g_object_weak_ref(G_OBJECT(priv->context), pama_sink_input_widget_weak_ref_notify, widget);
 
139
                        break;
 
140
 
 
141
                case PROP_ICON_SIZEGROUP:
 
142
                        priv->icon_sizegroup = g_value_dup_object(value);
117
143
                        break;
118
144
 
119
145
                default:
127
153
        GtkWidget *inner_box, *volume, *value, *mute, *sink_button, *sink_button_image;
128
154
 
129
155
        GObject *gobject = G_OBJECT_CLASS(pama_sink_input_widget_parent_class)->constructor(gtype, n_properties, properties);
130
 
        PamaSinkInputWidget *self = PAMA_SINK_INPUT_WIDGET(gobject);
 
156
        PamaSinkInputWidget *widget = PAMA_SINK_INPUT_WIDGET(gobject);
 
157
        PamaSinkInputWidgetPrivate *priv = PAMA_SINK_INPUT_WIDGET_GET_PRIVATE(widget);
131
158
 
132
 
        if (NULL == self->sink_input)
 
159
        if (NULL == priv->sink_input)
133
160
                g_error("An attempt was made to create a sink_input widget with no sink_input.");
134
 
        if (NULL == self->context)
 
161
        if (NULL == priv->context)
135
162
                g_error("An attempt was made to create a sink_input widget with no context.");
 
163
        if (NULL == priv->icon_sizegroup)
 
164
                g_error("An attempt was made to create a sink_input widget with no icon sizegroup");
136
165
 
137
166
        alignment = gtk_alignment_new(0, 0.5, 0, 0);
138
167
        gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 0, 6);
139
 
        gtk_box_pack_start(GTK_BOX(self), alignment, FALSE, FALSE, 0);
 
168
        gtk_box_pack_start(GTK_BOX(widget), alignment, FALSE, FALSE, 0);
140
169
 
141
170
        icon = gtk_image_new();
142
171
        gtk_container_add(GTK_CONTAINER(alignment), icon);
143
 
        self->icon = icon;
 
172
        gtk_size_group_add_widget(priv->icon_sizegroup, icon);
 
173
        priv->icon = icon;
144
174
 
145
175
        name = g_object_new(GTK_TYPE_LABEL,
146
176
                            "ellipsize", PANGO_ELLIPSIZE_MIDDLE,
148
178
                            "width-chars", WIDGET_NAME_WIDTH_IN_CHARS,
149
179
                            "xalign", 0.0f,
150
180
                            NULL);
151
 
        gtk_box_pack_start(GTK_BOX(self), name, FALSE, FALSE, 0);
152
 
        self->name = name;
 
181
        gtk_box_pack_start(GTK_BOX(widget), name, FALSE, FALSE, 0);
 
182
        priv->name = name;
153
183
 
154
184
        alignment = gtk_alignment_new(0, 0.5, 0, 0);
155
 
        gtk_box_pack_start(GTK_BOX(self), alignment, FALSE, FALSE, 0);
156
 
 
157
 
        inner_box = gtk_hbox_new(FALSE, 6);
158
 
        gtk_container_add(GTK_CONTAINER(alignment), inner_box);
 
185
        gtk_box_pack_start(GTK_BOX(widget), alignment, FALSE, FALSE, 0);
159
186
 
160
187
        volume = gtk_hscale_new_with_range(0, WIDGET_VOLUME_SLIDER_DB_RANGE, 2.5); /* for scroll steps of 5dB */
161
188
        gtk_scale_set_draw_value   (GTK_SCALE(volume), FALSE);
162
189
        gtk_widget_set_size_request(volume, WIDGET_VOLUME_SLIDER_WIDTH, -1);
163
 
        gtk_box_pack_start(GTK_BOX(inner_box), volume, FALSE, FALSE, 0);
164
 
        self->volume = volume;
 
190
        gtk_container_add(GTK_CONTAINER(alignment), volume);
 
191
        priv->volume = volume;
 
192
 
 
193
        alignment = gtk_alignment_new(0, 0.5, 0, 0);
 
194
        gtk_box_pack_start(GTK_BOX(widget), alignment, FALSE, FALSE, 0);
 
195
 
 
196
        inner_box = gtk_hbox_new(FALSE, 6);
 
197
        gtk_container_add(GTK_CONTAINER(alignment), inner_box);
165
198
 
166
199
        value = g_object_new(GTK_TYPE_LABEL,
167
200
                             "width-chars", WIDGET_VALUE_WIDTH_IN_CHARS,
168
201
                             "xalign", 1.0f,
169
202
                             NULL);
170
203
        gtk_box_pack_start(GTK_BOX(inner_box), value, FALSE, FALSE, 0);
171
 
        self->value = value;
 
204
        priv->value = value;
172
205
 
173
206
        mute = gtk_check_button_new();
174
207
        gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(mute), FALSE);
175
208
        gtk_widget_set_tooltip_text(GTK_WIDGET(mute), _("Mute this application's audio output"));
176
209
        gtk_container_add(GTK_CONTAINER(mute), gtk_image_new_from_icon_name("audio-volume-muted", GTK_ICON_SIZE_MENU));
177
210
        gtk_box_pack_start(GTK_BOX(inner_box), mute, FALSE, FALSE, 0);
178
 
        self->mute = mute;
 
211
        priv->mute = mute;
179
212
 
180
213
        sink_button = gtk_button_new();
181
214
        gtk_widget_set_tooltip_text(GTK_WIDGET(sink_button), _("Select which output device to use for this application"));
182
215
        gtk_box_pack_start(GTK_BOX(inner_box), sink_button, FALSE, FALSE, 0);
183
 
        self->sink_button = sink_button;
 
216
        priv->sink_button = sink_button;
184
217
 
185
218
        sink_button_image = gtk_image_new_from_icon_name("audio-card", GTK_ICON_SIZE_MENU);
186
219
        gtk_container_add(GTK_CONTAINER(sink_button), sink_button_image);
187
 
        self->sink_button_image = sink_button_image;
188
 
 
189
 
        pama_sink_input_widget_update_values(self);
190
 
 
191
 
        g_signal_connect(volume,      "value-changed", G_CALLBACK(pama_sink_input_widget_volume_changed),      self);
192
 
        g_signal_connect(mute,        "toggled",       G_CALLBACK(pama_sink_input_widget_mute_toggled),        self);
193
 
        g_signal_connect(sink_button, "clicked",       G_CALLBACK(pama_sink_input_widget_sink_button_clicked), self);
194
 
 
195
 
        self->sink_input_notify_handler_id = g_signal_connect(self->sink_input, "notify::volume", G_CALLBACK(pama_sink_input_widget_sink_input_notify), self);
 
220
        priv->sink_button_image = sink_button_image;
 
221
 
 
222
        pama_sink_input_widget_update_values(widget);
 
223
 
 
224
        g_signal_connect(volume,      "value-changed", G_CALLBACK(pama_sink_input_widget_volume_changed),      widget);
 
225
        g_signal_connect(mute,        "toggled",       G_CALLBACK(pama_sink_input_widget_mute_toggled),        widget);
 
226
        g_signal_connect(sink_button, "clicked",       G_CALLBACK(pama_sink_input_widget_sink_button_clicked), widget);
 
227
 
 
228
        priv->sink_input_notify_handler_id = g_signal_connect(priv->sink_input, "notify::volume", G_CALLBACK(pama_sink_input_widget_sink_input_notify), widget);
 
229
 
 
230
        /* We no longer need to keep a reference to the icon sizegroup */
 
231
        g_object_unref(priv->icon_sizegroup);
 
232
        priv->icon_sizegroup = NULL;
196
233
 
197
234
        return gobject;
198
235
}
199
236
static void pama_sink_input_widget_dispose(GObject *gobject)
200
237
{
201
 
        PamaSinkInputWidget *self = PAMA_SINK_INPUT_WIDGET(gobject);
 
238
        PamaSinkInputWidget *widget = PAMA_SINK_INPUT_WIDGET(gobject);
 
239
        PamaSinkInputWidgetPrivate *priv = PAMA_SINK_INPUT_WIDGET_GET_PRIVATE(widget);
202
240
 
203
 
        if (self->sink_input)
 
241
        if (priv->sink_input)
204
242
        {
205
 
                if (self->sink_input_notify_handler_id)
 
243
                if (priv->sink_input_notify_handler_id)
206
244
                {
207
 
                        g_signal_handler_disconnect(self->sink_input, self->sink_input_notify_handler_id);
208
 
                        self->sink_input_notify_handler_id = 0;
 
245
                        g_signal_handler_disconnect(priv->sink_input, priv->sink_input_notify_handler_id);
 
246
                        priv->sink_input_notify_handler_id = 0;
209
247
                }
210
248
 
211
 
                g_object_weak_unref(G_OBJECT(self->sink_input), pama_sink_input_widget_weak_ref_notify, self);
212
 
                self->sink_input = NULL;
213
 
        }
214
 
 
215
 
        if (self->context)
216
 
        {
217
 
                g_object_weak_unref(G_OBJECT(self->context), pama_sink_input_widget_weak_ref_notify, self);
218
 
                self->context = NULL;
219
 
        }
220
 
 
221
 
        if (self->sink_menu)
222
 
        {
223
 
                g_object_unref(self->sink_menu);
224
 
                self->sink_menu = NULL;
 
249
                g_object_weak_unref(G_OBJECT(priv->sink_input), pama_sink_input_widget_weak_ref_notify, widget);
 
250
                priv->sink_input = NULL;
 
251
        }
 
252
 
 
253
        if (priv->context)
 
254
        {
 
255
                g_object_weak_unref(G_OBJECT(priv->context), pama_sink_input_widget_weak_ref_notify, widget);
 
256
                priv->context = NULL;
 
257
        }
 
258
 
 
259
        if (priv->sink_menu)
 
260
        {
 
261
                g_object_unref(priv->sink_menu);
 
262
                priv->sink_menu = NULL;
 
263
        }
 
264
 
 
265
        if (priv->icon_sizegroup)
 
266
        {
 
267
                g_object_unref(priv->icon_sizegroup);
 
268
                priv->icon_sizegroup = NULL;
225
269
        }
226
270
 
227
271
        G_OBJECT_CLASS(pama_sink_input_widget_parent_class)->dispose(gobject);
228
272
}
229
273
static void pama_sink_input_widget_weak_ref_notify(gpointer data, GObject *where_the_object_was)
230
274
{
231
 
        PamaSinkInputWidget *self = data;
232
 
 
233
 
        if ((GObject *)self->sink_input == where_the_object_was)
234
 
                self->sink_input = NULL;
235
 
 
236
 
        if ((GObject *)self->context    == where_the_object_was)
237
 
                self->context = NULL;
 
275
        PamaSinkInputWidget *widget = data;
 
276
        PamaSinkInputWidgetPrivate *priv = PAMA_SINK_INPUT_WIDGET_GET_PRIVATE(widget);
 
277
 
 
278
        if ((GObject *)priv->sink_input == where_the_object_was)
 
279
                priv->sink_input = NULL;
 
280
 
 
281
        if ((GObject *)priv->context    == where_the_object_was)
 
282
                priv->context = NULL;
238
283
 
239
284
        /* widget is no longer usable without these items. */
240
 
        gtk_object_destroy(GTK_OBJECT(self));
241
 
}
242
 
 
243
 
 
244
 
static void pama_sink_input_widget_sink_input_notify(GObject *gobject, GParamSpec *pspec, PamaSinkInputWidget *self)
245
 
{
246
 
        pama_sink_input_widget_update_values(self);
247
 
        g_signal_emit(self, widget_signals[REORDER_REQUEST_SIGNAL], 0);
248
 
}
249
 
 
250
 
static void pama_sink_input_widget_update_values(PamaSinkInputWidget *self)
251
 
{
 
285
        gtk_object_destroy(GTK_OBJECT(widget));
 
286
}
 
287
 
 
288
 
 
289
static void pama_sink_input_widget_sink_input_notify(GObject *gobject, GParamSpec *pspec, PamaSinkInputWidget *widget)
 
290
{
 
291
        pama_sink_input_widget_update_values(widget);
 
292
        g_signal_emit(widget, widget_signals[REORDER_REQUEST_SIGNAL], 0);
 
293
}
 
294
 
 
295
static void pama_sink_input_widget_update_values(PamaSinkInputWidget *widget)
 
296
{
 
297
        PamaSinkInputWidgetPrivate *priv = PAMA_SINK_INPUT_WIDGET_GET_PRIVATE(widget);
252
298
        gchar           *temp;
253
299
        gchar           *stream_name, *client_name;
254
300
        gchar           *hostname, *application_id;
262
308
 
263
309
        double volume_dB;
264
310
 
265
 
        self->updating = TRUE;
 
311
        priv->updating = TRUE;
266
312
 
267
 
        g_object_get(self->sink_input,
 
313
        g_object_get(priv->sink_input,
268
314
                     "volume",    &volume,
269
315
                     "mute",      &mute,
270
316
                     "client",    &client,
279
325
                     "application-id", &application_id,
280
326
                     NULL);
281
327
 
282
 
        icon = pama_pulse_sink_input_build_gicon(self->sink_input);
283
 
        g_object_set(self->icon,
 
328
        icon = pama_pulse_sink_input_build_gicon(priv->sink_input);
 
329
        g_object_set(priv->icon,
284
330
                     "gicon", icon,
285
331
                     "pixel-size", 32,
286
332
                     NULL);
290
336
                temp = g_markup_printf_escaped("<b>%s</b>\n%s", client_name, stream_name);
291
337
        else
292
338
                temp = g_markup_printf_escaped("<b>%s</b> (on %s)\n%s", client_name, hostname, stream_name);
293
 
        gtk_label_set_markup(GTK_LABEL(self->name), temp);
294
 
        gtk_widget_set_tooltip_markup(GTK_WIDGET(self->name), temp);
 
339
        gtk_label_set_markup(GTK_LABEL(priv->name), temp);
 
340
        gtk_widget_set_tooltip_markup(GTK_WIDGET(priv->name), temp);
295
341
        g_free(temp);
296
342
        g_free(stream_name);
297
343
        g_free(client_name);
298
344
 
299
345
        volume_dB = pa_sw_volume_to_dB(volume);
300
346
        if (isinf(volume_dB))
301
 
                gtk_label_set_text(GTK_LABEL(self->value), "-∞dB");
 
347
                gtk_label_set_text(GTK_LABEL(priv->value), "-∞dB");
302
348
        else
303
349
        {
304
350
                temp = g_strdup_printf("%+.1fdB", volume_dB);
305
 
                gtk_label_set_text(GTK_LABEL(self->value), temp);
 
351
                gtk_label_set_text(GTK_LABEL(priv->value), temp);
306
352
                g_free(temp);
307
353
        }
308
354
 
309
 
        gtk_range_set_value(GTK_RANGE(self->volume), volume_dB + WIDGET_VOLUME_SLIDER_DB_RANGE);
310
 
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->mute), mute);
 
355
        gtk_range_set_value(GTK_RANGE(priv->volume), volume_dB + WIDGET_VOLUME_SLIDER_DB_RANGE);
 
356
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->mute), mute);
311
357
 
312
 
        gtk_widget_set_sensitive(self->volume, !mute);
313
 
        gtk_widget_set_sensitive(self->value,  !mute);
 
358
        gtk_widget_set_sensitive(priv->volume, !mute);
 
359
        gtk_widget_set_sensitive(priv->value,  !mute);
314
360
 
315
361
        // Ideally, this would be done by checking the sink input's flags for
316
362
        // PA_STREAM_DONT_MOVE, but we don't have that information
317
363
        is_pulseaudio = 0 == strcmp(application_id, "org.PulseAudio.PulseAudio");
318
 
        gtk_widget_set_sensitive(self->sink_button, !is_pulseaudio);
 
364
        gtk_widget_set_sensitive(priv->sink_button, !is_pulseaudio);
319
365
 
320
 
        g_object_set(self->sink_button_image,
 
366
        g_object_set(priv->sink_button_image,
321
367
                     "gicon", pama_pulse_sink_build_gicon(sink),
322
368
                     NULL);
323
369
 
324
370
        g_object_unref(client);
325
371
        g_object_unref(sink);
326
372
 
327
 
        self->updating = FALSE;
328
 
}
329
 
 
330
 
static void pama_sink_input_widget_mute_toggled   (GtkToggleButton *togglebutton, PamaSinkInputWidget *self)
331
 
{
332
 
        if (self->updating)
333
 
                return;
334
 
 
335
 
        pama_pulse_sink_input_set_mute(self->sink_input, gtk_toggle_button_get_active(togglebutton));
336
 
}
337
 
static void pama_sink_input_widget_volume_changed (GtkRange *range, PamaSinkInputWidget *self)
338
 
{
339
 
        if (self->updating)
340
 
                return;
341
 
 
342
 
        pama_pulse_sink_input_set_volume(self->sink_input, pa_sw_volume_from_dB(gtk_range_get_value(range) - WIDGET_VOLUME_SLIDER_DB_RANGE));
 
373
        priv->updating = FALSE;
 
374
}
 
375
 
 
376
static void pama_sink_input_widget_mute_toggled   (GtkToggleButton *togglebutton, PamaSinkInputWidget *widget)
 
377
{
 
378
        PamaSinkInputWidgetPrivate *priv = PAMA_SINK_INPUT_WIDGET_GET_PRIVATE(widget);
 
379
        if (priv->updating)
 
380
                return;
 
381
 
 
382
        pama_pulse_sink_input_set_mute(priv->sink_input, gtk_toggle_button_get_active(togglebutton));
 
383
}
 
384
static void pama_sink_input_widget_volume_changed (GtkRange *range, PamaSinkInputWidget *widget)
 
385
{
 
386
        PamaSinkInputWidgetPrivate *priv = PAMA_SINK_INPUT_WIDGET_GET_PRIVATE(widget);
 
387
        if (priv->updating)
 
388
                return;
 
389
 
 
390
        pama_pulse_sink_input_set_volume(priv->sink_input, pa_sw_volume_from_dB(gtk_range_get_value(range) - WIDGET_VOLUME_SLIDER_DB_RANGE));
343
391
}
344
392
 
345
393
static gint _sink_menu_sort_function(gconstpointer a, gconstpointer b) 
346
394
{
347
 
        gint result;
348
 
 
349
 
        if (result = pama_pulse_sink_compare_by_hostname(a, b))
 
395
        gint result = pama_pulse_sink_compare_by_hostname(a, b);
 
396
        if (result)
350
397
                return result;
351
398
 
352
399
        return pama_pulse_sink_compare_by_description(a, b);
353
400
}
354
 
static void pama_sink_input_widget_sink_button_clicked(GtkButton *button, PamaSinkInputWidget *self)
 
401
static void pama_sink_input_widget_sink_button_clicked(GtkButton *button, PamaSinkInputWidget *widget)
355
402
{
 
403
        PamaSinkInputWidgetPrivate *priv = PAMA_SINK_INPUT_WIDGET_GET_PRIVATE(widget);
356
404
        GtkWidget *item, *last = NULL;
357
405
        GtkWidget *label;
358
406
        GSList *sinks, *iter;
361
409
        gboolean network;
362
410
        gchar *text;
363
411
 
364
 
        if (!self->sink_menu)
 
412
        if (!priv->sink_menu)
365
413
        {
366
 
                self->sink_menu = gtk_menu_new();
367
 
                g_object_ref_sink(self->sink_menu);
368
 
                g_signal_connect(gtk_widget_get_toplevel(self->sink_menu), "hide", G_CALLBACK(pama_sink_input_widget_sink_menu_hidden), self);
 
414
                priv->sink_menu = gtk_menu_new();
 
415
                g_object_ref_sink(priv->sink_menu);
 
416
                g_signal_connect(gtk_widget_get_toplevel(priv->sink_menu), "hide", G_CALLBACK(pama_sink_input_widget_sink_menu_hidden), widget);
369
417
 
370
 
                sinks = g_slist_copy(pama_pulse_context_get_sinks(self->context));
 
418
                sinks = g_slist_copy(pama_pulse_context_get_sinks(priv->context));
371
419
                sinks = g_slist_sort(sinks, _sink_menu_sort_function);
372
420
 
373
 
                g_object_get(self->sink_input, "sink", &current_sink, NULL);
 
421
                g_object_get(priv->sink_input, "sink", &current_sink, NULL);
374
422
 
375
423
                for (iter = sinks; iter; iter = iter->next)
376
424
                {
408
456
                        g_free(hostname);
409
457
                        g_free(text);
410
458
 
411
 
                        g_signal_connect(item, "toggled", G_CALLBACK(pama_sink_input_widget_sink_menu_item_toggled), self);
412
 
                        gtk_menu_shell_append(GTK_MENU_SHELL(self->sink_menu), item);
 
459
                        g_signal_connect(item, "toggled", G_CALLBACK(pama_sink_input_widget_sink_menu_item_toggled), widget);
 
460
                        gtk_menu_shell_append(GTK_MENU_SHELL(priv->sink_menu), item);
413
461
                        gtk_widget_show_all(item);
414
462
                }
415
463
 
416
464
                g_slist_free(sinks);
417
465
                g_object_unref(current_sink);
418
466
 
419
 
                gtk_menu_popup(GTK_MENU(self->sink_menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
 
467
                gtk_menu_popup(GTK_MENU(priv->sink_menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
420
468
        }
421
469
}
422
 
static void pama_sink_input_widget_sink_menu_hidden(GtkWidget *menu_window, PamaSinkInputWidget *self)
 
470
static void pama_sink_input_widget_sink_menu_hidden(GtkWidget *menu_window, PamaSinkInputWidget *widget)
423
471
{
424
 
        g_object_unref(self->sink_menu);
425
 
        self->sink_menu = NULL;
 
472
        PamaSinkInputWidgetPrivate *priv = PAMA_SINK_INPUT_WIDGET_GET_PRIVATE(widget);
 
473
        g_object_unref(priv->sink_menu);
 
474
        priv->sink_menu = NULL;
426
475
}
427
 
static void pama_sink_input_widget_sink_menu_item_toggled(GtkCheckMenuItem *item, PamaSinkInputWidget *self)
 
476
static void pama_sink_input_widget_sink_menu_item_toggled(GtkCheckMenuItem *item, PamaSinkInputWidget *widget)
428
477
{
 
478
        PamaSinkInputWidgetPrivate *priv = PAMA_SINK_INPUT_WIDGET_GET_PRIVATE(widget);
429
479
        PamaPulseSink *sink;
430
480
 
431
481
        if (!gtk_check_menu_item_get_active(item))
433
483
 
434
484
        g_object_get(item, "user-data", &sink, NULL);
435
485
 
436
 
        pama_pulse_sink_input_set_sink(self->sink_input, sink);
 
486
        pama_pulse_sink_input_set_sink(priv->sink_input, sink);
437
487
}
438
488
 
439
489
gint pama_sink_input_widget_compare(gconstpointer a, gconstpointer b)
440
490
{
441
 
        PamaSinkInputWidget *A = PAMA_SINK_INPUT_WIDGET(a);
442
 
        PamaSinkInputWidget *B = PAMA_SINK_INPUT_WIDGET(b);
 
491
        PamaSinkInputWidgetPrivate *A = PAMA_SINK_INPUT_WIDGET_GET_PRIVATE(a);
 
492
        PamaSinkInputWidgetPrivate *B = PAMA_SINK_INPUT_WIDGET_GET_PRIVATE(b);
443
493
 
444
494
        PamaPulseClient *Ac, *Bc;
445
495