~ubuntu-branches/ubuntu/edgy/gnome-media/edgy

« back to all changes in this revision

Viewing changes to gst-mixer/src/volume.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2005-09-05 01:34:20 UTC
  • Revision ID: james.westby@ubuntu.com-20050905013420-p3wd1q9kmdh3tic2
Tags: 2.12.O-0ubuntu1
New upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GNOME Volume Control
 
2
 * Copyright (C) 2003-2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
 
3
 *
 
4
 * volume.c: representation of a track's volume channels
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU Library General Public
 
8
 * License as published by the Free Software Foundation; either
 
9
 * version 2 of the License, or (at your option) any later version.
 
10
 *
 
11
 * This library is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 * Library General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Library General Public
 
17
 * License along with this library; if not, write to the
 
18
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
19
 * Boston, MA 02111-1307, USA.
 
20
 */
 
21
 
 
22
#ifdef HAVE_CONFIG_H
 
23
#include "config.h"
 
24
#endif
 
25
 
 
26
#define _ISOC99_SOURCE
 
27
 
 
28
#include <math.h>
 
29
#include <gnome.h>
 
30
#include <gdk/gdkx.h>
 
31
#include <gtk/gtk.h>
 
32
#include <gst/mixer/mixer.h>
 
33
 
 
34
#include "button.h"
 
35
#include "stock.h"
 
36
#include "volume.h"
 
37
 
 
38
static void     gnome_volume_control_volume_class_init  (GnomeVolumeControlVolumeClass *klass);
 
39
static void     gnome_volume_control_volume_init        (GnomeVolumeControlVolume *el);
 
40
static void     gnome_volume_control_volume_dispose     (GObject   *object);
 
41
 
 
42
static void     gnome_volume_control_volume_size_req    (GtkWidget *widget,
 
43
                                                         GtkRequisition *req);
 
44
static void     gnome_volume_control_volume_size_alloc  (GtkWidget *widget,
 
45
                                                         GtkAllocation *alloc);
 
46
static gboolean gnome_volume_control_volume_expose      (GtkWidget *widget,
 
47
                                                         GdkEventExpose *expose);
 
48
 
 
49
static void     cb_volume_changed                       (GtkAdjustment *adj,
 
50
                                                         gpointer   data);
 
51
static void     cb_lock_toggled                         (GtkToggleButton *button,
 
52
                                                         gpointer   data);
 
53
 
 
54
static gboolean cb_check                                (gpointer   data);
 
55
 
 
56
static GtkFixedClass *parent_class = NULL;
 
57
 
 
58
GType
 
59
gnome_volume_control_volume_get_type (void)
 
60
{
 
61
  static GType gnome_volume_control_volume_type = 0;
 
62
 
 
63
  if (!gnome_volume_control_volume_type) {
 
64
    static const GTypeInfo gnome_volume_control_volume_info = {
 
65
      sizeof (GnomeVolumeControlVolumeClass),
 
66
      NULL,
 
67
      NULL,
 
68
      (GClassInitFunc) gnome_volume_control_volume_class_init,
 
69
      NULL,
 
70
      NULL,
 
71
      sizeof (GnomeVolumeControlVolume),
 
72
      0,
 
73
      (GInstanceInitFunc) gnome_volume_control_volume_init,
 
74
      NULL
 
75
    };
 
76
 
 
77
    gnome_volume_control_volume_type =
 
78
        g_type_register_static (GTK_TYPE_FIXED, 
 
79
                                "GnomeVolumeControlVolume",
 
80
                                &gnome_volume_control_volume_info, 0);
 
81
  }
 
82
 
 
83
  return gnome_volume_control_volume_type;
 
84
}
 
85
 
 
86
static void
 
87
gnome_volume_control_volume_class_init (GnomeVolumeControlVolumeClass *klass)
 
88
{
 
89
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
90
  GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass);
 
91
 
 
92
  parent_class = g_type_class_ref (GTK_TYPE_FIXED);
 
93
 
 
94
  gobject_class->dispose = gnome_volume_control_volume_dispose;
 
95
  gtkwidget_class->size_allocate = gnome_volume_control_volume_size_alloc;
 
96
  gtkwidget_class->size_request = gnome_volume_control_volume_size_req;
 
97
  gtkwidget_class->expose_event = gnome_volume_control_volume_expose;
 
98
}
 
99
 
 
100
static void
 
101
gnome_volume_control_volume_init (GnomeVolumeControlVolume *vol)
 
102
{
 
103
  gtk_fixed_set_has_window (GTK_FIXED (vol), TRUE);
 
104
 
 
105
  vol->mixer = NULL;
 
106
  vol->track = NULL;
 
107
  vol->padding = 6;
 
108
  vol->scales = NULL;
 
109
  vol->button = NULL;
 
110
  vol->locked = FALSE;
 
111
  vol->appbar = NULL;
 
112
  vol->id = 0;
 
113
}
 
114
 
 
115
static gboolean
 
116
cb_mouseover (GtkScale *scale,
 
117
              GdkEventCrossing *event,
 
118
              gpointer data)
 
119
{
 
120
  GnomeVolumeControlVolume *vol = data;
 
121
  gchar *msg, *chan;
 
122
  GList *items;
 
123
  gint n = 0;
 
124
 
 
125
  for (items = vol->scales; items != NULL; items = items->next, n++)
 
126
    if (items->data == scale)
 
127
      break;
 
128
  g_assert (items != NULL);
 
129
 
 
130
  /* somewhat dirty hack that will suffice for now. 1 chan
 
131
   * means mono, two means stereo (left/right) and > 2 means
 
132
   * alsa, where channel order is front, rear, center, lfe,
 
133
   * side. */
 
134
  if (vol->track->num_channels == 1) {
 
135
    chan = _("mono");
 
136
  } else if (vol->track->num_channels == 2) {
 
137
    chan = (n == 0) ? _("left") : _("right");
 
138
  } else {
 
139
    switch (n) {
 
140
      case 0:  chan = _("front left"); break;
 
141
      case 1:  chan = _("front right"); break;
 
142
      case 2:  chan = _("rear left"); break;
 
143
      case 3:  chan = _("rear right"); break;
 
144
      case 4:  chan = _("front center"); break;
 
145
      /* Translators: This is the name of a surround sound channel. It
 
146
       * stands for "Low-Frequency Effects". If you're not sure that
 
147
       * this has an established and different translation in your
 
148
       * language, leave it unchanged. */
 
149
      case 5:  chan = _("LFE"); break;
 
150
      case 6:  chan = _("side left"); break;
 
151
      case 7:  chan = _("side right"); break;
 
152
      default: chan = _("unknown"); break;
 
153
    }
 
154
  }
 
155
 
 
156
  /* Here, we can actually tell people that this
 
157
   * is a slider that will change channel X. */
 
158
  msg = g_strdup_printf (_("Volume of %s channel on %s"),
 
159
      chan, vol->track->label);
 
160
  gnome_appbar_push (vol->appbar, msg);
 
161
  g_free (msg);
 
162
 
 
163
  return FALSE;
 
164
}
 
165
 
 
166
static gboolean
 
167
cb_mouseout (GtkScale *scale,
 
168
             GdkEventCrossing *event,
 
169
             gpointer data)
 
170
{
 
171
  GnomeVolumeControlVolume *vol = data;
 
172
 
 
173
  gnome_appbar_pop (vol->appbar);
 
174
 
 
175
  return FALSE;
 
176
}
 
177
 
 
178
static GtkWidget *
 
179
get_scale (GnomeVolumeControlVolume *vol,
 
180
           gint num_chan,
 
181
           gint volume)
 
182
{
 
183
  GtkWidget *slider;
 
184
  GtkObject *adj;
 
185
  AtkObject *accessible;
 
186
  gchar *accessible_name;
 
187
 
 
188
  adj = gtk_adjustment_new (volume,
 
189
                            vol->track->min_volume,
 
190
                            vol->track->max_volume,
 
191
                            1.0, 1.0, 0.0);
 
192
  g_signal_connect (adj, "value_changed",
 
193
                    G_CALLBACK (cb_volume_changed), vol);
 
194
  slider = gtk_vscale_new (GTK_ADJUSTMENT (adj));
 
195
  gtk_scale_set_draw_value (GTK_SCALE (slider), FALSE);
 
196
  gtk_range_set_inverted (GTK_RANGE (slider), TRUE);
 
197
  g_signal_connect (slider, "enter-notify-event",
 
198
                    G_CALLBACK (cb_mouseover), vol);
 
199
  g_signal_connect (slider, "leave-notify-event",
 
200
                    G_CALLBACK (cb_mouseout), vol);
 
201
 
 
202
  /* a11y */
 
203
  accessible = gtk_widget_get_accessible (slider);
 
204
  if (GTK_IS_ACCESSIBLE (accessible)) {
 
205
    if (vol->track->num_channels == 1) {
 
206
      accessible_name = g_strdup_printf (_("Track %s"),
 
207
                                         vol->track->label);
 
208
    } else {
 
209
      gchar *accessible_desc = g_strdup_printf (_("Channel %d of track %s"),
 
210
                                                num_chan + 1,
 
211
                                                vol->track->label);
 
212
      accessible_name = g_strdup_printf (_("Track %s, channel %d"),
 
213
                                         vol->track->label, num_chan + 1);
 
214
      atk_object_set_description (accessible, accessible_desc); 
 
215
      g_free (accessible_desc);
 
216
    }
 
217
    atk_object_set_name (accessible, accessible_name);
 
218
    g_free (accessible_name);
 
219
  }
 
220
 
 
221
  return slider;
 
222
}
 
223
 
 
224
static void
 
225
get_button (GnomeVolumeControlVolume *vol,
 
226
            gint *volumes)
 
227
{
 
228
  AtkObject *accessible;
 
229
  gchar *accessible_name, *msg;
 
230
  gint n;
 
231
 
 
232
  msg = g_strdup_printf (("Lock channels for %s together"), vol->track->label);
 
233
  vol->button = gnome_volume_control_button_new ("chain.png",
 
234
                                                 "chain-broken.png",
 
235
                                                 vol->appbar, msg);
 
236
  g_free (msg);
 
237
  g_signal_connect (vol->button, "clicked",
 
238
                    G_CALLBACK (cb_lock_toggled), vol);
 
239
  for (n = 1; n < vol->track->num_channels; n++) {
 
240
    /* default, unlocked */
 
241
    if (volumes[n] != volumes[0])
 
242
      break;
 
243
  }
 
244
  gnome_volume_control_button_set_active (GNOME_VOLUME_CONTROL_BUTTON (vol->button),
 
245
                                          n == vol->track->num_channels);
 
246
 
 
247
  /* a11y */
 
248
  accessible = gtk_widget_get_accessible (vol->button);
 
249
  if (GTK_IS_ACCESSIBLE (accessible)) {
 
250
    accessible_name = g_strdup_printf (_("Track %s: lock channels together"),
 
251
                                       vol->track->label);
 
252
    atk_object_set_name (accessible, accessible_name);
 
253
    g_free (accessible_name);
 
254
  }
 
255
}
 
256
 
 
257
GtkWidget *
 
258
gnome_volume_control_volume_new (GstMixer *mixer,
 
259
                                 GstMixerTrack *track,
 
260
                                 gint      padding,
 
261
                                 GnomeAppBar *appbar)
 
262
{
 
263
  GnomeVolumeControlVolume *vol;
 
264
  gint *volumes, n;
 
265
 
 
266
  /* volume */
 
267
  vol = g_object_new (GNOME_VOLUME_CONTROL_TYPE_VOLUME, NULL);
 
268
  gst_object_ref (GST_OBJECT (mixer));
 
269
  vol->mixer = mixer;
 
270
  vol->track = g_object_ref (G_OBJECT (track));
 
271
  vol->appbar = appbar;
 
272
  if (padding >= 0)
 
273
    vol->padding = padding;
 
274
 
 
275
  /* sliders */
 
276
  volumes = g_new0 (gint, track->num_channels);
 
277
  gst_mixer_get_volume (mixer, track, volumes);
 
278
  for (n = 0; n < track->num_channels; n++) {
 
279
    GtkWidget *slider;
 
280
 
 
281
    /* we will reposition the widget once we're drawing up */
 
282
    slider = get_scale (vol, n, volumes[n]);
 
283
    gtk_fixed_put (GTK_FIXED (vol), slider, 0, 0);
 
284
    gtk_widget_show (slider);
 
285
    vol->scales = g_list_append (vol->scales, slider);
 
286
  }
 
287
 
 
288
  /* chainbutton */
 
289
  get_button (vol, volumes);
 
290
  if (track->num_channels > 1) {
 
291
    gtk_fixed_put (GTK_FIXED (vol), vol->button, 0, 0);
 
292
    gtk_widget_show (vol->button);
 
293
  }
 
294
 
 
295
  g_free (volumes);
 
296
 
 
297
  /* GStreamer signals */
 
298
  vol->id = g_timeout_add (100, cb_check, vol);
 
299
 
 
300
  return GTK_WIDGET (vol);
 
301
}
 
302
 
 
303
static void
 
304
gnome_volume_control_volume_dispose (GObject *object)
 
305
{
 
306
  GnomeVolumeControlVolume *vol = GNOME_VOLUME_CONTROL_VOLUME (object);
 
307
 
 
308
  if (vol->id != 0) {
 
309
    g_source_remove (vol->id);
 
310
    vol->id = 0;
 
311
  }
 
312
 
 
313
  if (vol->track) {
 
314
    g_object_unref (G_OBJECT (vol->track));
 
315
    vol->track = NULL;
 
316
  }
 
317
 
 
318
  if (vol->mixer) {
 
319
    gst_object_unref (GST_OBJECT (vol->mixer));
 
320
    vol->mixer = NULL;
 
321
  }
 
322
 
 
323
  if (vol->scales) {
 
324
    g_list_free (vol->scales);
 
325
    vol->scales = NULL;
 
326
  }
 
327
 
 
328
  G_OBJECT_CLASS (parent_class)->dispose (object);
 
329
}
 
330
 
 
331
/*
 
332
 * Gtk/GDK virtual functions for size negotiation.
 
333
 */
 
334
 
 
335
static void
 
336
gnome_volume_control_volume_size_req (GtkWidget *widget,
 
337
                                      GtkRequisition *req)
 
338
{
 
339
  GnomeVolumeControlVolume *vol = GNOME_VOLUME_CONTROL_VOLUME (widget);
 
340
  GtkRequisition but_req, scale_req;
 
341
  gint w,h;
 
342
 
 
343
  /* request size of kids */
 
344
  GTK_WIDGET_GET_CLASS (vol->button)->size_request (vol->button, &but_req);
 
345
  GTK_WIDGET_GET_CLASS (vol->scales->data)->size_request (vol->scales->data,
 
346
                                                          &scale_req);
 
347
  if (scale_req.height < 100)
 
348
    scale_req.height = 100;
 
349
 
 
350
  /* calculate our own size from that */
 
351
  req->width = scale_req.width * vol->track->num_channels +
 
352
      vol->padding * (vol->track->num_channels - 1);
 
353
  req->height = scale_req.height + but_req.height /*+ vol->padding*/;
 
354
}
 
355
 
 
356
static void
 
357
gnome_volume_control_volume_size_alloc (GtkWidget *widget,
 
358
                                        GtkAllocation *alloc)
 
359
{
 
360
  GnomeVolumeControlVolume *vol = GNOME_VOLUME_CONTROL_VOLUME (widget);
 
361
  GtkRequisition but_req, scale_req;
 
362
  GtkAllocation but_all, scale_all;
 
363
  gint x_offset, but_deco_y_offset, but_x_offset, but_deco_width, n = 0;
 
364
  GList *scales;
 
365
 
 
366
  /* loop? */
 
367
  if (alloc->x == widget->allocation.x &&
 
368
      alloc->y == widget->allocation.y &&
 
369
      alloc->width == widget->allocation.width &&
 
370
      alloc->height == widget->allocation.height)
 
371
    return;
 
372
 
 
373
  /* request size of kids */
 
374
  GTK_WIDGET_GET_CLASS (vol->button)->size_request (vol->button, &but_req);
 
375
  GTK_WIDGET_GET_CLASS (vol->scales->data)->size_request (vol->scales->data,
 
376
                                                          &scale_req);
 
377
 
 
378
  /* calculate */
 
379
  x_offset = (alloc->width - ((vol->track->num_channels * scale_req.width) +
 
380
      (vol->track->num_channels - 1) * vol->padding)) / 2;
 
381
  scale_all.width = scale_req.width;
 
382
  scale_all.height = alloc->height - but_req.height;
 
383
  scale_all.y = 0;
 
384
  but_deco_width = alloc->width - (2 * x_offset);
 
385
  but_all.width = but_req.width;
 
386
  but_all.height = but_req.height;
 
387
  but_all.x = x_offset + (but_deco_width - but_req.width) / 2;
 
388
  but_all.y = alloc->height - but_req.height;
 
389
 
 
390
  /* tell sliders */
 
391
  for (scales = vol->scales; scales != NULL; scales = scales->next, n++) {
 
392
    scale_all.x = x_offset + n * (scale_req.width + vol->padding);
 
393
    gtk_fixed_move (GTK_FIXED (vol), scales->data, scale_all.x, scale_all.y);
 
394
    gtk_widget_set_size_request (scales->data, scale_all.width, scale_all.height);
 
395
  }
 
396
 
 
397
  /* tell button */
 
398
  if (vol->track->num_channels > 1) {
 
399
    gtk_fixed_move (GTK_FIXED (vol), vol->button, but_all.x, but_all.y);
 
400
    gtk_widget_set_size_request (vol->button, but_all.width, but_all.height);
 
401
  }
 
402
 
 
403
  /* parent will resize window */
 
404
  GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, alloc);
 
405
}
 
406
 
 
407
static gboolean
 
408
gnome_volume_control_volume_expose (GtkWidget *widget,
 
409
                                    GdkEventExpose *expose)
 
410
{
 
411
  GnomeVolumeControlVolume *vol = GNOME_VOLUME_CONTROL_VOLUME (widget);
 
412
 
 
413
  /* clear background */
 
414
  gdk_window_clear_area (widget->window, 0, 0,
 
415
                         widget->allocation.width,
 
416
                         widget->allocation.height);
 
417
 
 
418
  if (vol->track->num_channels > 1) {
 
419
    gint x_offset, y_offset, height, width;
 
420
    GtkRequisition scale_req, but_req;
 
421
    GdkPoint points[3];
 
422
 
 
423
    /* request size of kids */
 
424
    GTK_WIDGET_GET_CLASS (vol->button)->size_request (vol->button, &but_req);
 
425
    GTK_WIDGET_GET_CLASS (vol->scales->data)->size_request (vol->scales->data,
 
426
                                                            &scale_req);
 
427
 
 
428
    /* calculate */
 
429
    x_offset = (widget->allocation.width -
 
430
        ((vol->track->num_channels * scale_req.width) +
 
431
        (vol->track->num_channels - 1) * vol->padding)) / 2;
 
432
    y_offset = widget->allocation.height - but_req.height;
 
433
    width = widget->allocation.width - (2 * x_offset + but_req.width);
 
434
    height = but_req.height / 2;
 
435
    points[0].y = y_offset + 3;
 
436
    points[1].y = points[2].y = points[0].y + height - 3;
 
437
 
 
438
    /* draw chainbutton decorations */
 
439
    points[0].x = points[1].x = x_offset + 3;
 
440
    points[2].x = points[0].x + width - 6;
 
441
    gtk_paint_polygon (widget->style, widget->window,
 
442
                       GTK_WIDGET_STATE (widget),
 
443
                       GTK_SHADOW_ETCHED_IN,
 
444
                       &expose->area, widget, "hseparator",
 
445
                       points, 3, FALSE);
 
446
 
 
447
    points[0].x = points[1].x = widget->allocation.width - x_offset - 3;
 
448
    points[2].x = points[0].x - width + 6;
 
449
    gtk_paint_polygon (widget->style, widget->window,
 
450
                       GTK_WIDGET_STATE (widget),
 
451
                       GTK_SHADOW_ETCHED_IN,
 
452
                       &expose->area, widget, "hseparator",
 
453
                       points, 3, FALSE);
 
454
  }
 
455
 
 
456
  /* take care of redrawing the kids */
 
457
  return GTK_WIDGET_CLASS (parent_class)->expose_event (widget, expose);
 
458
}
 
459
 
 
460
/*
 
461
 * Signals handlers.
 
462
 */
 
463
 
 
464
static void
 
465
cb_volume_changed (GtkAdjustment *_adj,
 
466
                   gpointer       data)
 
467
{
 
468
  GnomeVolumeControlVolume *vol = data;
 
469
  gint *volumes, i = 0;
 
470
  GList *scales;
 
471
 
 
472
  if (vol->locked)
 
473
    return;
 
474
  vol->locked = TRUE;
 
475
  volumes = g_new (gint, vol->track->num_channels);
 
476
 
 
477
  for (scales = vol->scales; scales != NULL; scales = scales->next) {
 
478
    GtkAdjustment *adj = gtk_range_get_adjustment (scales->data);
 
479
 
 
480
    if (gnome_volume_control_button_get_active (
 
481
            GNOME_VOLUME_CONTROL_BUTTON (vol->button))) {
 
482
      gtk_adjustment_set_value (adj, gtk_adjustment_get_value (_adj));
 
483
      volumes[i++] = rint (gtk_adjustment_get_value (_adj));
 
484
    } else {
 
485
      volumes[i++] = rint (gtk_adjustment_get_value (adj));
 
486
    }
 
487
  }
 
488
 
 
489
  gst_mixer_set_volume (vol->mixer, vol->track, volumes);
 
490
 
 
491
  g_free (volumes);
 
492
  vol->locked = FALSE;
 
493
}
 
494
 
 
495
/*
 
496
 * To be called after unmuting.
 
497
 */
 
498
 
 
499
void
 
500
gnome_volume_control_volume_sync (GnomeVolumeControlVolume * vol)
 
501
{
 
502
  cb_volume_changed (gtk_range_get_adjustment (vol->scales->data), vol);
 
503
}
 
504
 
 
505
static void
 
506
cb_lock_toggled (GtkToggleButton *button,
 
507
                 gpointer         data)
 
508
{
 
509
  GnomeVolumeControlVolume *vol = data;
 
510
 
 
511
  if (gnome_volume_control_button_get_active (
 
512
          GNOME_VOLUME_CONTROL_BUTTON (vol->button))) {
 
513
    /* get the mean value, and set it on the first adjustment.
 
514
     * the cb_volume_changed () callback will take care of the
 
515
     * rest. */
 
516
    gint volume = 0, num = 0;
 
517
    GList *scales;
 
518
 
 
519
    for (scales = vol->scales ; scales != NULL; scales = scales->next) {
 
520
      GtkAdjustment *adj = gtk_range_get_adjustment (scales->data);
 
521
 
 
522
      num++;
 
523
      volume += gtk_adjustment_get_value (adj);
 
524
    }
 
525
 
 
526
    /* safety check */
 
527
    if (vol->scales != NULL) {
 
528
      gtk_adjustment_set_value (gtk_range_get_adjustment (vol->scales->data),
 
529
                                volume / num);
 
530
    }
 
531
  }
 
532
}
 
533
 
 
534
/*
 
535
 * See if our volume is zero.
 
536
 */
 
537
 
 
538
void
 
539
gnome_volume_control_volume_ask (GnomeVolumeControlVolume * vol,
 
540
    gboolean *real_zero, gboolean *slider_zero)
 
541
{
 
542
  GList *scales;
 
543
  gint *volumes, n, tot = 0;
 
544
 
 
545
  volumes = g_new (gint, vol->track->num_channels);
 
546
  gst_mixer_get_volume (vol->mixer, vol->track, volumes);
 
547
  for (n = 0; n < vol->track->num_channels; n++)
 
548
    tot += volumes[n];
 
549
  g_free (volumes);
 
550
  *real_zero = (tot == 0);
 
551
 
 
552
  *slider_zero = TRUE;
 
553
  for (n = 0, scales = vol->scales;
 
554
       scales != NULL; scales = scales->next, n++) {
 
555
    GtkAdjustment *adj = gtk_range_get_adjustment (scales->data);
 
556
                                                                                
 
557
    if (rint (gtk_adjustment_get_value (adj)) != 0) {
 
558
      *slider_zero = FALSE;
 
559
      break;
 
560
    }
 
561
  }
 
562
}
 
563
 
 
564
/*
 
565
 * Timeout to check for volume changes.
 
566
 */
 
567
 
 
568
static gboolean
 
569
cb_check (gpointer data)
 
570
{
 
571
  GnomeVolumeControlVolume *vol = data;
 
572
  gint *volumes, n;
 
573
  gboolean real_zero, slider_zero;
 
574
  GList *scales;
 
575
 
 
576
  /* don't do callbacks */
 
577
  if (vol->locked)
 
578
    return TRUE;
 
579
  vol->locked = TRUE;
 
580
 
 
581
  volumes = g_new (gint, vol->track->num_channels);
 
582
  gst_mixer_get_volume (vol->mixer, vol->track, volumes);
 
583
  gnome_volume_control_volume_ask (vol, &real_zero, &slider_zero);
 
584
  if (real_zero || GST_MIXER_TRACK_HAS_FLAG (vol->track,
 
585
                                             GST_MIXER_TRACK_MUTE)) {
 
586
    g_free (volumes);
 
587
    vol->locked = FALSE;
 
588
    return TRUE;
 
589
  }
 
590
 
 
591
  /* did we change? */
 
592
  for (n = 0, scales = vol->scales;
 
593
       scales != NULL; scales = scales->next, n++) {
 
594
    GtkAdjustment *adj = gtk_range_get_adjustment (scales->data);
 
595
 
 
596
    if ((gint) gtk_adjustment_get_value (adj) != volumes[n]) {
 
597
      gtk_range_set_value (scales->data, volumes[n]);
 
598
    }
 
599
 
 
600
    /* should we release lock? */
 
601
    if (volumes[n] != volumes[0]) {
 
602
      gnome_volume_control_button_set_active (
 
603
          GNOME_VOLUME_CONTROL_BUTTON (vol->button), FALSE);
 
604
    }
 
605
  }
 
606
 
 
607
  g_free (volumes);
 
608
  vol->locked = FALSE;
 
609
 
 
610
  return TRUE;
 
611
}