~kroq-gar78/ubuntu/precise/gnome-control-center/fix-885947

« back to all changes in this revision

Viewing changes to panels/sound/gvc-level-bar.c

  • Committer: Bazaar Package Importer
  • Author(s): Rodrigo Moya
  • Date: 2011-05-17 10:47:27 UTC
  • mfrom: (0.1.11 experimental) (1.1.45 upstream)
  • Revision ID: james.westby@ubuntu.com-20110517104727-lqel6m8vhfw5jby1
Tags: 1:3.0.1.1-1ubuntu1
* Rebase on Debian, remaining Ubuntu changes:
* debian/control:
  - Build-Depend on hardening-wrapper, dpkg-dev and dh-autoreconf
  - Add dependency on ubuntu-system-service
  - Remove dependency on gnome-icon-theme-symbolic
  - Move dependency on apg, gnome-icon-theme-symbolic and accountsservice to
    be a Recommends: until we get them in main
* debian/rules:
  - Use autoreconf
  - Add binary-post-install rule for gnome-control-center-data
  - Run dh-autoreconf
* debian/gnome-control-center.dirs:
* debian/gnome-control-center.links:
  - Add a link to the control center shell for indicators
* debian/patches/00_disable-nm.patch:
  - Temporary patch to disable building with NetworkManager until we get
    the new one in the archive
* debian/patches/01_git_remove_gettext_calls.patch:
  - Remove calls to AM_GNU_GETTEXT, IT_PROG_INTLTOOL should be enough
* debian/patches/01_git_kill_warning.patch:
  - Kill warning
* debian/patches/50_ubuntu_systemwide_prefs.patch:
  - Ubuntu specific proxy preferences
* debian/patches/51_ubuntu_system_keyboard.patch:
  - Implement the global keyboard spec at https://wiki.ubuntu.com/DefaultKeyboardSettings

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
 
2
 *
 
3
 * Copyright (C) 2008 William Jon McCann <william.jon.mccann@gmail.com>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
18
 *
 
19
 */
 
20
 
 
21
#include "config.h"
 
22
 
 
23
#include <stdlib.h>
 
24
#include <stdio.h>
 
25
#include <unistd.h>
 
26
#include <math.h>
 
27
 
 
28
#include <glib.h>
 
29
#include <glib/gi18n-lib.h>
 
30
#include <gtk/gtk.h>
 
31
 
 
32
#include "gvc-level-bar.h"
 
33
 
 
34
#define NUM_BOXES 30
 
35
 
 
36
#define GVC_LEVEL_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_LEVEL_BAR, GvcLevelBarPrivate))
 
37
 
 
38
#define MIN_HORIZONTAL_BAR_WIDTH   150
 
39
#define HORIZONTAL_BAR_HEIGHT      6
 
40
#define VERTICAL_BAR_WIDTH         6
 
41
#define MIN_VERTICAL_BAR_HEIGHT    400
 
42
 
 
43
typedef struct {
 
44
        int          peak_num;
 
45
        int          max_peak_num;
 
46
 
 
47
        GdkRectangle area;
 
48
        int          delta;
 
49
        int          box_width;
 
50
        int          box_height;
 
51
        int          box_radius;
 
52
        double       bg_r;
 
53
        double       bg_g;
 
54
        double       bg_b;
 
55
        double       bdr_r;
 
56
        double       bdr_g;
 
57
        double       bdr_b;
 
58
        double       fl_r;
 
59
        double       fl_g;
 
60
        double       fl_b;
 
61
} LevelBarLayout;
 
62
 
 
63
struct GvcLevelBarPrivate
 
64
{
 
65
        GtkOrientation orientation;
 
66
        GtkAdjustment *peak_adjustment;
 
67
        GtkAdjustment *rms_adjustment;
 
68
        int            scale;
 
69
        gdouble        peak_fraction;
 
70
        gdouble        rms_fraction;
 
71
        gdouble        max_peak;
 
72
        guint          max_peak_id;
 
73
        LevelBarLayout layout;
 
74
};
 
75
 
 
76
enum
 
77
{
 
78
        PROP_0,
 
79
        PROP_PEAK_ADJUSTMENT,
 
80
        PROP_RMS_ADJUSTMENT,
 
81
        PROP_SCALE,
 
82
        PROP_ORIENTATION,
 
83
};
 
84
 
 
85
static void     gvc_level_bar_class_init (GvcLevelBarClass *klass);
 
86
static void     gvc_level_bar_init       (GvcLevelBar      *level_bar);
 
87
static void     gvc_level_bar_finalize   (GObject            *object);
 
88
 
 
89
G_DEFINE_TYPE (GvcLevelBar, gvc_level_bar, GTK_TYPE_WIDGET)
 
90
 
 
91
#define check_rectangle(rectangle1, rectangle2)                          \
 
92
        {                                                                \
 
93
                /* .x and .y are always 0 */                             \
 
94
                if (rectangle1.width  != rectangle2.width)  return TRUE; \
 
95
                if (rectangle1.height != rectangle2.height) return TRUE; \
 
96
        }
 
97
 
 
98
static gboolean
 
99
layout_changed (LevelBarLayout *layout1,
 
100
                LevelBarLayout *layout2)
 
101
{
 
102
        check_rectangle (layout1->area, layout2->area);
 
103
        if (layout1->delta != layout2->delta) return TRUE;
 
104
        if (layout1->peak_num != layout2->peak_num) return TRUE;
 
105
        if (layout1->max_peak_num != layout2->max_peak_num) return TRUE;
 
106
        if (layout1->bg_r != layout2->bg_r
 
107
            || layout1->bg_g != layout2->bg_g
 
108
            || layout1->bg_b != layout2->bg_b)
 
109
                return TRUE;
 
110
        if (layout1->bdr_r != layout2->bdr_r
 
111
            || layout1->bdr_g != layout2->bdr_g
 
112
            || layout1->bdr_b != layout2->bdr_b)
 
113
                return TRUE;
 
114
        if (layout1->fl_r != layout2->fl_r
 
115
            || layout1->fl_g != layout2->fl_g
 
116
            || layout1->fl_b != layout2->fl_b)
 
117
                return TRUE;
 
118
 
 
119
        return FALSE;
 
120
}
 
121
 
 
122
static gdouble
 
123
fraction_from_adjustment (GvcLevelBar   *bar,
 
124
                          GtkAdjustment *adjustment)
 
125
{
 
126
        gdouble level;
 
127
        gdouble fraction;
 
128
        gdouble min;
 
129
        gdouble max;
 
130
 
 
131
        level = gtk_adjustment_get_value (adjustment);
 
132
 
 
133
        min = gtk_adjustment_get_lower (adjustment);
 
134
        max = gtk_adjustment_get_upper (adjustment);
 
135
 
 
136
        switch (bar->priv->scale) {
 
137
        case GVC_LEVEL_SCALE_LINEAR:
 
138
                fraction = (level - min) / (max - min);
 
139
                break;
 
140
        case GVC_LEVEL_SCALE_LOG:
 
141
                fraction = log10 ((level - min + 1) / (max - min + 1));
 
142
                break;
 
143
        default:
 
144
                g_assert_not_reached ();
 
145
        }
 
146
 
 
147
        return fraction;
 
148
}
 
149
 
 
150
static gboolean
 
151
reset_max_peak (GvcLevelBar *bar)
 
152
{
 
153
        gdouble min;
 
154
 
 
155
        min = gtk_adjustment_get_lower (bar->priv->peak_adjustment);
 
156
        bar->priv->max_peak = min;
 
157
        bar->priv->layout.max_peak_num = 0;
 
158
        gtk_widget_queue_draw (GTK_WIDGET (bar));
 
159
        bar->priv->max_peak_id = 0;
 
160
        return FALSE;
 
161
}
 
162
 
 
163
static void
 
164
bar_calc_layout (GvcLevelBar *bar)
 
165
{
 
166
        GdkColor color;
 
167
        int      peak_level;
 
168
        int      max_peak_level;
 
169
        GtkAllocation allocation;
 
170
        GtkStyle *style;
 
171
 
 
172
        gtk_widget_get_allocation (GTK_WIDGET (bar), &allocation);
 
173
        bar->priv->layout.area.width = allocation.width - 2;
 
174
        bar->priv->layout.area.height = allocation.height - 2;
 
175
 
 
176
        style = gtk_widget_get_style (GTK_WIDGET (bar));
 
177
        color = style->bg [GTK_STATE_NORMAL];
 
178
        bar->priv->layout.bg_r = (float)color.red / 65535.0;
 
179
        bar->priv->layout.bg_g = (float)color.green / 65535.0;
 
180
        bar->priv->layout.bg_b = (float)color.blue / 65535.0;
 
181
        color = style->dark [GTK_STATE_NORMAL];
 
182
        bar->priv->layout.bdr_r = (float)color.red / 65535.0;
 
183
        bar->priv->layout.bdr_g = (float)color.green / 65535.0;
 
184
        bar->priv->layout.bdr_b = (float)color.blue / 65535.0;
 
185
        color = style->bg [GTK_STATE_SELECTED];
 
186
        bar->priv->layout.fl_r = (float)color.red / 65535.0;
 
187
        bar->priv->layout.fl_g = (float)color.green / 65535.0;
 
188
        bar->priv->layout.fl_b = (float)color.blue / 65535.0;
 
189
 
 
190
        if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
 
191
                peak_level = bar->priv->peak_fraction * bar->priv->layout.area.height;
 
192
                max_peak_level = bar->priv->max_peak * bar->priv->layout.area.height;
 
193
 
 
194
                bar->priv->layout.delta = bar->priv->layout.area.height / NUM_BOXES;
 
195
                bar->priv->layout.area.x = 0;
 
196
                bar->priv->layout.area.y = 0;
 
197
                bar->priv->layout.box_height = bar->priv->layout.delta / 2;
 
198
                bar->priv->layout.box_width = bar->priv->layout.area.width;
 
199
                bar->priv->layout.box_radius = bar->priv->layout.box_width / 2;
 
200
        } else {
 
201
                peak_level = bar->priv->peak_fraction * bar->priv->layout.area.width;
 
202
                max_peak_level = bar->priv->max_peak * bar->priv->layout.area.width;
 
203
 
 
204
                bar->priv->layout.delta = bar->priv->layout.area.width / NUM_BOXES;
 
205
                bar->priv->layout.area.x = 0;
 
206
                bar->priv->layout.area.y = 0;
 
207
                bar->priv->layout.box_width = bar->priv->layout.delta / 2;
 
208
                bar->priv->layout.box_height = bar->priv->layout.area.height;
 
209
                bar->priv->layout.box_radius = bar->priv->layout.box_height / 2;
 
210
        }
 
211
 
 
212
        /* This can happen if the level bar isn't realized */
 
213
        if (bar->priv->layout.delta == 0)
 
214
                return;
 
215
 
 
216
        bar->priv->layout.peak_num = peak_level / bar->priv->layout.delta;
 
217
        bar->priv->layout.max_peak_num = max_peak_level / bar->priv->layout.delta;
 
218
}
 
219
 
 
220
static void
 
221
update_peak_value (GvcLevelBar *bar)
 
222
{
 
223
        gdouble        val;
 
224
        LevelBarLayout layout;
 
225
 
 
226
        layout = bar->priv->layout;
 
227
 
 
228
        val = fraction_from_adjustment (bar, bar->priv->peak_adjustment);
 
229
        bar->priv->peak_fraction = val;
 
230
 
 
231
        if (val > bar->priv->max_peak) {
 
232
                if (bar->priv->max_peak_id > 0) {
 
233
                        g_source_remove (bar->priv->max_peak_id);
 
234
                }
 
235
                bar->priv->max_peak_id = g_timeout_add_seconds (1, (GSourceFunc)reset_max_peak, bar);
 
236
                bar->priv->max_peak = val;
 
237
        }
 
238
 
 
239
        bar_calc_layout (bar);
 
240
 
 
241
        if (layout_changed (&bar->priv->layout, &layout)) {
 
242
                gtk_widget_queue_draw (GTK_WIDGET (bar));
 
243
        }
 
244
}
 
245
 
 
246
static void
 
247
update_rms_value (GvcLevelBar *bar)
 
248
{
 
249
        gdouble val;
 
250
 
 
251
        val = fraction_from_adjustment (bar, bar->priv->rms_adjustment);
 
252
        bar->priv->rms_fraction = val;
 
253
}
 
254
 
 
255
GtkOrientation
 
256
gvc_level_bar_get_orientation (GvcLevelBar *bar)
 
257
{
 
258
        g_return_val_if_fail (GVC_IS_LEVEL_BAR (bar), 0);
 
259
        return bar->priv->orientation;
 
260
}
 
261
 
 
262
void
 
263
gvc_level_bar_set_orientation (GvcLevelBar   *bar,
 
264
                               GtkOrientation orientation)
 
265
{
 
266
        g_return_if_fail (GVC_IS_LEVEL_BAR (bar));
 
267
 
 
268
        if (orientation != bar->priv->orientation) {
 
269
                bar->priv->orientation = orientation;
 
270
                gtk_widget_queue_draw (GTK_WIDGET (bar));
 
271
                g_object_notify (G_OBJECT (bar), "orientation");
 
272
        }
 
273
}
 
274
 
 
275
static void
 
276
on_peak_adjustment_value_changed (GtkAdjustment *adjustment,
 
277
                                  GvcLevelBar   *bar)
 
278
{
 
279
        update_peak_value (bar);
 
280
}
 
281
 
 
282
static void
 
283
on_rms_adjustment_value_changed (GtkAdjustment *adjustment,
 
284
                                 GvcLevelBar   *bar)
 
285
{
 
286
        update_rms_value (bar);
 
287
}
 
288
 
 
289
void
 
290
gvc_level_bar_set_peak_adjustment (GvcLevelBar   *bar,
 
291
                                   GtkAdjustment *adjustment)
 
292
{
 
293
        g_return_if_fail (GVC_LEVEL_BAR (bar));
 
294
        g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
 
295
 
 
296
        if (bar->priv->peak_adjustment != NULL) {
 
297
                g_signal_handlers_disconnect_by_func (bar->priv->peak_adjustment,
 
298
                                                      G_CALLBACK (on_peak_adjustment_value_changed),
 
299
                                                      bar);
 
300
                g_object_unref (bar->priv->peak_adjustment);
 
301
        }
 
302
 
 
303
        bar->priv->peak_adjustment = g_object_ref_sink (adjustment);
 
304
 
 
305
        g_signal_connect (bar->priv->peak_adjustment,
 
306
                          "value-changed",
 
307
                          G_CALLBACK (on_peak_adjustment_value_changed),
 
308
                          bar);
 
309
 
 
310
        update_peak_value (bar);
 
311
 
 
312
        g_object_notify (G_OBJECT (bar), "peak-adjustment");
 
313
}
 
314
 
 
315
void
 
316
gvc_level_bar_set_rms_adjustment (GvcLevelBar   *bar,
 
317
                                  GtkAdjustment *adjustment)
 
318
{
 
319
        g_return_if_fail (GVC_LEVEL_BAR (bar));
 
320
        g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
 
321
 
 
322
        if (bar->priv->rms_adjustment != NULL) {
 
323
                g_signal_handlers_disconnect_by_func (bar->priv->peak_adjustment,
 
324
                                                      G_CALLBACK (on_rms_adjustment_value_changed),
 
325
                                                      bar);
 
326
                g_object_unref (bar->priv->rms_adjustment);
 
327
        }
 
328
 
 
329
        bar->priv->rms_adjustment = g_object_ref_sink (adjustment);
 
330
 
 
331
 
 
332
        g_signal_connect (bar->priv->peak_adjustment,
 
333
                          "value-changed",
 
334
                          G_CALLBACK (on_peak_adjustment_value_changed),
 
335
                          bar);
 
336
 
 
337
        update_rms_value (bar);
 
338
 
 
339
        g_object_notify (G_OBJECT (bar), "rms-adjustment");
 
340
}
 
341
 
 
342
GtkAdjustment *
 
343
gvc_level_bar_get_peak_adjustment (GvcLevelBar *bar)
 
344
{
 
345
        g_return_val_if_fail (GVC_IS_LEVEL_BAR (bar), NULL);
 
346
 
 
347
        return bar->priv->peak_adjustment;
 
348
}
 
349
 
 
350
GtkAdjustment *
 
351
gvc_level_bar_get_rms_adjustment (GvcLevelBar *bar)
 
352
{
 
353
        g_return_val_if_fail (GVC_IS_LEVEL_BAR (bar), NULL);
 
354
 
 
355
        return bar->priv->rms_adjustment;
 
356
}
 
357
 
 
358
void
 
359
gvc_level_bar_set_scale (GvcLevelBar  *bar,
 
360
                         GvcLevelScale scale)
 
361
{
 
362
        g_return_if_fail (GVC_IS_LEVEL_BAR (bar));
 
363
 
 
364
        if (scale != bar->priv->scale) {
 
365
                bar->priv->scale = scale;
 
366
 
 
367
                update_peak_value (bar);
 
368
                update_rms_value (bar);
 
369
 
 
370
                g_object_notify (G_OBJECT (bar), "scale");
 
371
        }
 
372
}
 
373
 
 
374
static void
 
375
gvc_level_bar_set_property (GObject       *object,
 
376
                              guint          prop_id,
 
377
                              const GValue  *value,
 
378
                              GParamSpec    *pspec)
 
379
{
 
380
        GvcLevelBar *self = GVC_LEVEL_BAR (object);
 
381
 
 
382
        switch (prop_id) {
 
383
        case PROP_SCALE:
 
384
                gvc_level_bar_set_scale (self, g_value_get_int (value));
 
385
                break;
 
386
        case PROP_ORIENTATION:
 
387
                gvc_level_bar_set_orientation (self, g_value_get_enum (value));
 
388
                break;
 
389
        case PROP_PEAK_ADJUSTMENT:
 
390
                gvc_level_bar_set_peak_adjustment (self, g_value_get_object (value));
 
391
                break;
 
392
        case PROP_RMS_ADJUSTMENT:
 
393
                gvc_level_bar_set_rms_adjustment (self, g_value_get_object (value));
 
394
                break;
 
395
        default:
 
396
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
397
                break;
 
398
        }
 
399
}
 
400
 
 
401
static void
 
402
gvc_level_bar_get_property (GObject     *object,
 
403
                              guint        prop_id,
 
404
                              GValue      *value,
 
405
                              GParamSpec  *pspec)
 
406
{
 
407
        GvcLevelBar *self = GVC_LEVEL_BAR (object);
 
408
 
 
409
        switch (prop_id) {
 
410
        case PROP_SCALE:
 
411
                g_value_set_int (value, self->priv->scale);
 
412
                break;
 
413
        case PROP_ORIENTATION:
 
414
                g_value_set_enum (value, self->priv->orientation);
 
415
                break;
 
416
        case PROP_PEAK_ADJUSTMENT:
 
417
                g_value_set_object (value, self->priv->peak_adjustment);
 
418
                break;
 
419
        case PROP_RMS_ADJUSTMENT:
 
420
                g_value_set_object (value, self->priv->rms_adjustment);
 
421
                break;
 
422
        default:
 
423
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
424
                break;
 
425
        }
 
426
}
 
427
 
 
428
static GObject *
 
429
gvc_level_bar_constructor (GType                  type,
 
430
                           guint                  n_construct_properties,
 
431
                           GObjectConstructParam *construct_params)
 
432
{
 
433
        return G_OBJECT_CLASS (gvc_level_bar_parent_class)->constructor (type, n_construct_properties, construct_params);
 
434
}
 
435
 
 
436
static void
 
437
gvc_level_bar_size_request (GtkWidget      *widget,
 
438
                            GtkRequisition *requisition)
 
439
{
 
440
        GvcLevelBar *bar = GVC_LEVEL_BAR (widget);
 
441
 
 
442
        switch (bar->priv->orientation) {
 
443
        case GTK_ORIENTATION_VERTICAL:
 
444
                requisition->width = VERTICAL_BAR_WIDTH;
 
445
                requisition->height = MIN_VERTICAL_BAR_HEIGHT;
 
446
                break;
 
447
        case GTK_ORIENTATION_HORIZONTAL:
 
448
                requisition->width = MIN_HORIZONTAL_BAR_WIDTH;
 
449
                requisition->height = HORIZONTAL_BAR_HEIGHT;
 
450
                break;
 
451
        default:
 
452
                g_assert_not_reached ();
 
453
                break;
 
454
        }
 
455
}
 
456
 
 
457
static void
 
458
gvc_level_bar_get_preferred_width (GtkWidget *widget,
 
459
                                   gint      *minimum,
 
460
                                   gint      *natural)
 
461
{
 
462
        GtkRequisition requisition;
 
463
 
 
464
        gvc_level_bar_size_request (widget, &requisition);
 
465
 
 
466
        if (minimum != NULL) {
 
467
                *minimum = requisition.width;
 
468
        }
 
469
        if (natural != NULL) {
 
470
                *natural = requisition.width;
 
471
        }
 
472
}
 
473
 
 
474
static void
 
475
gvc_level_bar_get_preferred_height (GtkWidget *widget,
 
476
                                    gint      *minimum,
 
477
                                    gint      *natural)
 
478
{
 
479
        GtkRequisition requisition;
 
480
 
 
481
        gvc_level_bar_size_request (widget, &requisition);
 
482
 
 
483
        if (minimum != NULL) {
 
484
                *minimum = requisition.height;
 
485
        }
 
486
        if (natural != NULL) {
 
487
                *natural = requisition.height;
 
488
        }
 
489
}
 
490
 
 
491
static void
 
492
gvc_level_bar_size_allocate (GtkWidget     *widget,
 
493
                             GtkAllocation *allocation)
 
494
{
 
495
        GvcLevelBar *bar;
 
496
 
 
497
        g_return_if_fail (GVC_IS_LEVEL_BAR (widget));
 
498
        g_return_if_fail (allocation != NULL);
 
499
 
 
500
        bar = GVC_LEVEL_BAR (widget);
 
501
 
 
502
        /* FIXME: add height property, labels, etc */
 
503
        GTK_WIDGET_CLASS (gvc_level_bar_parent_class)->size_allocate (widget, allocation);
 
504
 
 
505
        gtk_widget_set_allocation (widget, allocation);
 
506
        gtk_widget_get_allocation (widget, allocation);
 
507
 
 
508
        if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
 
509
                allocation->height = MIN (allocation->height, MIN_VERTICAL_BAR_HEIGHT);
 
510
                allocation->width = MAX (allocation->width, VERTICAL_BAR_WIDTH);
 
511
        } else {
 
512
                allocation->width = MIN (allocation->width, MIN_HORIZONTAL_BAR_WIDTH);
 
513
                allocation->height = MAX (allocation->height, HORIZONTAL_BAR_HEIGHT);
 
514
        }
 
515
 
 
516
        bar_calc_layout (bar);
 
517
}
 
518
 
 
519
static void
 
520
curved_rectangle (cairo_t *cr,
 
521
                  double   x0,
 
522
                  double   y0,
 
523
                  double   width,
 
524
                  double   height,
 
525
                  double   radius)
 
526
{
 
527
        double x1;
 
528
        double y1;
 
529
 
 
530
        x1 = x0 + width;
 
531
        y1 = y0 + height;
 
532
 
 
533
        if (!width || !height) {
 
534
                return;
 
535
        }
 
536
 
 
537
        if (width / 2 < radius) {
 
538
                if (height / 2 < radius) {
 
539
                        cairo_move_to  (cr, x0, (y0 + y1) / 2);
 
540
                        cairo_curve_to (cr, x0 ,y0, x0, y0, (x0 + x1) / 2, y0);
 
541
                        cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2);
 
542
                        cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1);
 
543
                        cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2);
 
544
                } else {
 
545
                        cairo_move_to  (cr, x0, y0 + radius);
 
546
                        cairo_curve_to (cr, x0, y0, x0, y0, (x0 + x1) / 2, y0);
 
547
                        cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
 
548
                        cairo_line_to (cr, x1, y1 - radius);
 
549
                        cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1);
 
550
                        cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
 
551
                }
 
552
        } else {
 
553
                if (height / 2 < radius) {
 
554
                        cairo_move_to  (cr, x0, (y0 + y1) / 2);
 
555
                        cairo_curve_to (cr, x0, y0, x0 , y0, x0 + radius, y0);
 
556
                        cairo_line_to (cr, x1 - radius, y0);
 
557
                        cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2);
 
558
                        cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
 
559
                        cairo_line_to (cr, x0 + radius, y1);
 
560
                        cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2);
 
561
                } else {
 
562
                        cairo_move_to  (cr, x0, y0 + radius);
 
563
                        cairo_curve_to (cr, x0 , y0, x0 , y0, x0 + radius, y0);
 
564
                        cairo_line_to (cr, x1 - radius, y0);
 
565
                        cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
 
566
                        cairo_line_to (cr, x1, y1 - radius);
 
567
                        cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
 
568
                        cairo_line_to (cr, x0 + radius, y1);
 
569
                        cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
 
570
                }
 
571
        }
 
572
 
 
573
        cairo_close_path (cr);
 
574
}
 
575
 
 
576
static int
 
577
gvc_level_bar_draw (GtkWidget *widget,
 
578
                    cairo_t   *cr)
 
579
{
 
580
        GvcLevelBar     *bar;
 
581
 
 
582
        g_return_val_if_fail (GVC_IS_LEVEL_BAR (widget), FALSE);
 
583
 
 
584
        bar = GVC_LEVEL_BAR (widget);
 
585
 
 
586
        if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
 
587
                int i;
 
588
                int by;
 
589
 
 
590
                for (i = 0; i < NUM_BOXES; i++) {
 
591
                        by = i * bar->priv->layout.delta;
 
592
                        curved_rectangle (cr,
 
593
                                          bar->priv->layout.area.x + 0.5,
 
594
                                          by + 0.5,
 
595
                                          bar->priv->layout.box_width - 1,
 
596
                                          bar->priv->layout.box_height - 1,
 
597
                                          bar->priv->layout.box_radius);
 
598
                        if ((bar->priv->layout.max_peak_num - 1) == i) {
 
599
                                /* fill peak foreground */
 
600
                                cairo_set_source_rgb (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b);
 
601
                                cairo_fill_preserve (cr);
 
602
                        } else if ((bar->priv->layout.peak_num - 1) >= i) {
 
603
                                /* fill background */
 
604
                                cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b);
 
605
                                cairo_fill_preserve (cr);
 
606
                                /* fill foreground */
 
607
                                cairo_set_source_rgba (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b, 0.5);
 
608
                                cairo_fill_preserve (cr);
 
609
                        } else {
 
610
                                /* fill background */
 
611
                                cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b);
 
612
                                cairo_fill_preserve (cr);
 
613
                        }
 
614
 
 
615
                        /* stroke border */
 
616
                        cairo_set_source_rgb (cr, bar->priv->layout.bdr_r, bar->priv->layout.bdr_g, bar->priv->layout.bdr_b);
 
617
                        cairo_set_line_width (cr, 1);
 
618
                        cairo_stroke (cr);
 
619
                }
 
620
 
 
621
        } else {
 
622
                int i;
 
623
                int bx;
 
624
 
 
625
                for (i = 0; i < NUM_BOXES; i++) {
 
626
                        bx = i * bar->priv->layout.delta;
 
627
                        curved_rectangle (cr,
 
628
                                          bx + 0.5,
 
629
                                          bar->priv->layout.area.y + 0.5,
 
630
                                          bar->priv->layout.box_width - 1,
 
631
                                          bar->priv->layout.box_height - 1,
 
632
                                          bar->priv->layout.box_radius);
 
633
 
 
634
                        if ((bar->priv->layout.max_peak_num - 1) == i) {
 
635
                                /* fill peak foreground */
 
636
                                cairo_set_source_rgb (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b);
 
637
                                cairo_fill_preserve (cr);
 
638
                        } else if ((bar->priv->layout.peak_num - 1) >= i) {
 
639
                                /* fill background */
 
640
                                cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b);
 
641
                                cairo_fill_preserve (cr);
 
642
                                /* fill foreground */
 
643
                                cairo_set_source_rgba (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b, 0.5);
 
644
                                cairo_fill_preserve (cr);
 
645
                        } else {
 
646
                                /* fill background */
 
647
                                cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b);
 
648
                                cairo_fill_preserve (cr);
 
649
                        }
 
650
 
 
651
                        /* stroke border */
 
652
                        cairo_set_source_rgb (cr, bar->priv->layout.bdr_r, bar->priv->layout.bdr_g, bar->priv->layout.bdr_b);
 
653
                        cairo_set_line_width (cr, 1);
 
654
                        cairo_stroke (cr);
 
655
                }
 
656
        }
 
657
 
 
658
        return FALSE;
 
659
}
 
660
 
 
661
static void
 
662
gvc_level_bar_class_init (GvcLevelBarClass *klass)
 
663
{
 
664
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
 
665
        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
666
 
 
667
        object_class->constructor = gvc_level_bar_constructor;
 
668
        object_class->finalize = gvc_level_bar_finalize;
 
669
        object_class->set_property = gvc_level_bar_set_property;
 
670
        object_class->get_property = gvc_level_bar_get_property;
 
671
 
 
672
        widget_class->draw = gvc_level_bar_draw;
 
673
        widget_class->get_preferred_width = gvc_level_bar_get_preferred_width;
 
674
        widget_class->get_preferred_height = gvc_level_bar_get_preferred_height;
 
675
        widget_class->size_allocate = gvc_level_bar_size_allocate;
 
676
 
 
677
        g_object_class_install_property (object_class,
 
678
                                         PROP_ORIENTATION,
 
679
                                         g_param_spec_enum ("orientation",
 
680
                                                            "Orientation",
 
681
                                                            "The orientation of the bar",
 
682
                                                            GTK_TYPE_ORIENTATION,
 
683
                                                            GTK_ORIENTATION_HORIZONTAL,
 
684
                                                            G_PARAM_READWRITE));
 
685
        g_object_class_install_property (object_class,
 
686
                                         PROP_PEAK_ADJUSTMENT,
 
687
                                         g_param_spec_object ("peak-adjustment",
 
688
                                                              "Peak Adjustment",
 
689
                                                              "The GtkAdjustment that contains the current peak value",
 
690
                                                              GTK_TYPE_ADJUSTMENT,
 
691
                                                              G_PARAM_READWRITE));
 
692
        g_object_class_install_property (object_class,
 
693
                                         PROP_RMS_ADJUSTMENT,
 
694
                                         g_param_spec_object ("rms-adjustment",
 
695
                                                              "RMS Adjustment",
 
696
                                                              "The GtkAdjustment that contains the current rms value",
 
697
                                                              GTK_TYPE_ADJUSTMENT,
 
698
                                                              G_PARAM_READWRITE));
 
699
        g_object_class_install_property (object_class,
 
700
                                         PROP_SCALE,
 
701
                                         g_param_spec_int ("scale",
 
702
                                                           "Scale",
 
703
                                                           "Scale",
 
704
                                                           0,
 
705
                                                           G_MAXINT,
 
706
                                                           GVC_LEVEL_SCALE_LINEAR,
 
707
                                                           G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
708
 
 
709
        g_type_class_add_private (klass, sizeof (GvcLevelBarPrivate));
 
710
}
 
711
 
 
712
static void
 
713
gvc_level_bar_init (GvcLevelBar *bar)
 
714
{
 
715
        bar->priv = GVC_LEVEL_BAR_GET_PRIVATE (bar);
 
716
 
 
717
        bar->priv->peak_adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
 
718
                                                                         0.0,
 
719
                                                                         1.0,
 
720
                                                                         0.05,
 
721
                                                                         0.1,
 
722
                                                                         0.1));
 
723
        g_object_ref_sink (bar->priv->peak_adjustment);
 
724
        g_signal_connect (bar->priv->peak_adjustment,
 
725
                          "value-changed",
 
726
                          G_CALLBACK (on_peak_adjustment_value_changed),
 
727
                          bar);
 
728
 
 
729
        bar->priv->rms_adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
 
730
                                                                        0.0,
 
731
                                                                        1.0,
 
732
                                                                        0.05,
 
733
                                                                        0.1,
 
734
                                                                        0.1));
 
735
        g_object_ref_sink (bar->priv->rms_adjustment);
 
736
        g_signal_connect (bar->priv->rms_adjustment,
 
737
                          "value-changed",
 
738
                          G_CALLBACK (on_rms_adjustment_value_changed),
 
739
                          bar);
 
740
 
 
741
        gtk_widget_set_has_window (GTK_WIDGET (bar), FALSE);
 
742
}
 
743
 
 
744
static void
 
745
gvc_level_bar_finalize (GObject *object)
 
746
{
 
747
        GvcLevelBar *bar;
 
748
 
 
749
        g_return_if_fail (object != NULL);
 
750
        g_return_if_fail (GVC_IS_LEVEL_BAR (object));
 
751
 
 
752
        bar = GVC_LEVEL_BAR (object);
 
753
 
 
754
        if (bar->priv->max_peak_id > 0) {
 
755
                g_source_remove (bar->priv->max_peak_id);
 
756
        }
 
757
 
 
758
        g_return_if_fail (bar->priv != NULL);
 
759
 
 
760
        G_OBJECT_CLASS (gvc_level_bar_parent_class)->finalize (object);
 
761
}
 
762
 
 
763
GtkWidget *
 
764
gvc_level_bar_new (void)
 
765
{
 
766
        GObject *bar;
 
767
        bar = g_object_new (GVC_TYPE_LEVEL_BAR,
 
768
                            NULL);
 
769
        return GTK_WIDGET (bar);
 
770
}