1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3
* Copyright (C) 2006-2007 William Jon McCann <mccann@jhu.edu>
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2, or (at your option) any later version.
11
* This program is distributed in the hope that it will be
12
* useful, but WITHOUT ANY WARRANTY; without even the implied
13
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14
* PURPOSE. See the GNU Lesser General Public License for more
17
* You should have received a copy of the GNU Lesser General
18
* Public License along with this program; if not, write to the
19
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20
* Boston, MA 02111-1307, USA.
30
#include <glib/gi18n.h>
33
#include "gsd-media-keys-window.h"
35
#define GSD_MEDIA_KEYS_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_MEDIA_KEYS_WINDOW, GsdMediaKeysWindowPrivate))
37
struct GsdMediaKeysWindowPrivate
39
GsdMediaKeysWindowAction action;
43
guint volume_muted : 1;
50
G_DEFINE_TYPE (GsdMediaKeysWindow, gsd_media_keys_window, GSD_TYPE_OSD_WINDOW)
53
volume_controls_set_visible (GsdMediaKeysWindow *window,
56
if (window->priv->progress == NULL)
60
gtk_widget_show (window->priv->progress);
62
gtk_widget_hide (window->priv->progress);
67
window_set_icon_name (GsdMediaKeysWindow *window,
70
if (window->priv->image == NULL)
73
gtk_image_set_from_icon_name (window->priv->image,
74
name, GTK_ICON_SIZE_DIALOG);
78
action_changed (GsdMediaKeysWindow *window)
80
if (!gsd_osd_window_is_composited (GSD_OSD_WINDOW (window))) {
81
switch (window->priv->action) {
82
case GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME:
83
volume_controls_set_visible (window, TRUE);
85
if (window->priv->volume_muted) {
86
window_set_icon_name (window, "audio-volume-muted");
88
window_set_icon_name (window, "audio-volume-high");
92
case GSD_MEDIA_KEYS_WINDOW_ACTION_CUSTOM:
93
volume_controls_set_visible (window, window->priv->show_level);
94
window_set_icon_name (window, window->priv->icon_name);
97
g_assert_not_reached ();
102
gsd_osd_window_update_and_hide (GSD_OSD_WINDOW (window));
106
volume_level_changed (GsdMediaKeysWindow *window)
108
gsd_osd_window_update_and_hide (GSD_OSD_WINDOW (window));
110
if (!gsd_osd_window_is_composited (GSD_OSD_WINDOW (window)) && window->priv->progress != NULL) {
113
fraction = (double) window->priv->volume_level / 100.0;
115
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (window->priv->progress),
121
volume_muted_changed (GsdMediaKeysWindow *window)
123
gsd_osd_window_update_and_hide (GSD_OSD_WINDOW (window));
125
if (!gsd_osd_window_is_composited (GSD_OSD_WINDOW (window))) {
126
if (window->priv->volume_muted) {
127
window_set_icon_name (window, "audio-volume-muted");
129
window_set_icon_name (window, "audio-volume-high");
135
gsd_media_keys_window_set_action (GsdMediaKeysWindow *window,
136
GsdMediaKeysWindowAction action)
138
g_return_if_fail (GSD_IS_MEDIA_KEYS_WINDOW (window));
139
g_return_if_fail (action == GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME);
141
if (window->priv->action != action) {
142
window->priv->action = action;
143
action_changed (window);
145
gsd_osd_window_update_and_hide (GSD_OSD_WINDOW (window));
150
gsd_media_keys_window_set_action_custom (GsdMediaKeysWindow *window,
151
const char *icon_name,
154
g_return_if_fail (GSD_IS_MEDIA_KEYS_WINDOW (window));
155
g_return_if_fail (icon_name != NULL);
157
if (window->priv->action != GSD_MEDIA_KEYS_WINDOW_ACTION_CUSTOM ||
158
g_strcmp0 (window->priv->icon_name, icon_name) != 0 ||
159
window->priv->show_level != show_level) {
160
window->priv->action = GSD_MEDIA_KEYS_WINDOW_ACTION_CUSTOM;
161
g_free (window->priv->icon_name);
162
window->priv->icon_name = g_strdup (icon_name);
163
window->priv->show_level = show_level;
164
action_changed (window);
166
gsd_osd_window_update_and_hide (GSD_OSD_WINDOW (window));
171
gsd_media_keys_window_set_volume_muted (GsdMediaKeysWindow *window,
174
g_return_if_fail (GSD_IS_MEDIA_KEYS_WINDOW (window));
176
if (window->priv->volume_muted != muted) {
177
window->priv->volume_muted = muted;
178
volume_muted_changed (window);
183
gsd_media_keys_window_set_volume_level (GsdMediaKeysWindow *window,
186
g_return_if_fail (GSD_IS_MEDIA_KEYS_WINDOW (window));
188
if (window->priv->volume_level != level) {
189
window->priv->volume_level = level;
190
volume_level_changed (window);
195
load_pixbuf (GsdMediaKeysWindow *window,
202
if (window != NULL && gtk_widget_has_screen (GTK_WIDGET (window))) {
203
theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (window)));
205
theme = gtk_icon_theme_get_default ();
208
pixbuf = gtk_icon_theme_load_icon (theme,
211
GTK_ICON_LOOKUP_FORCE_SIZE,
218
draw_eject (cairo_t *cr,
228
box_height = height * 0.2;
229
separation = box_height / 3;
230
tri_height = height - box_height - separation;
232
cairo_rectangle (cr, _x0, _y0 + height - box_height, width, box_height);
234
cairo_move_to (cr, _x0, _y0 + tri_height);
235
cairo_rel_line_to (cr, width, 0);
236
cairo_rel_line_to (cr, -width / 2, -tri_height);
237
cairo_rel_line_to (cr, -width / 2, tri_height);
238
cairo_close_path (cr);
239
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, GSD_OSD_WINDOW_FG_ALPHA);
240
cairo_fill_preserve (cr);
242
cairo_set_source_rgba (cr, 0.6, 0.6, 0.6, GSD_OSD_WINDOW_FG_ALPHA / 2);
243
cairo_set_line_width (cr, 2);
248
draw_waves (cairo_t *cr,
254
const int n_waves = 3;
258
last_wave = n_waves * volume_level / 100;
260
for (i = 0; i < n_waves; i++) {
271
else if (i > last_wave)
273
else alpha = 0.1 + 0.9 * (n_waves * volume_level % 100) / 100.0;
275
radius = (i + 1) * (max_radius / n_waves);
276
cairo_arc (cr, cx, cy, radius, angle1, angle2);
277
cairo_set_source_rgba (cr, 0.6, 0.6, 0.6, alpha / 2);
278
cairo_set_line_width (cr, 14);
279
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
280
cairo_stroke_preserve (cr);
282
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, alpha);
283
cairo_set_line_width (cr, 10);
284
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
290
draw_cross (cairo_t *cr,
295
cairo_move_to (cr, cx, cy - size/2.0);
296
cairo_rel_line_to (cr, size, size);
298
cairo_move_to (cr, cx, cy + size/2.0);
299
cairo_rel_line_to (cr, size, -size);
301
cairo_set_source_rgba (cr, 0.6, 0.6, 0.6, GSD_OSD_WINDOW_FG_ALPHA / 2);
302
cairo_set_line_width (cr, 14);
303
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
304
cairo_stroke_preserve (cr);
306
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, GSD_OSD_WINDOW_FG_ALPHA);
307
cairo_set_line_width (cr, 10);
308
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
313
draw_speaker (cairo_t *cr,
324
box_width = width / 3;
325
box_height = height / 3;
327
_x0 = cx - (width / 2) + box_width;
328
_y0 = cy - box_height / 2;
330
cairo_move_to (cr, _x0, _y0);
331
cairo_rel_line_to (cr, - box_width, 0);
332
cairo_rel_line_to (cr, 0, box_height);
333
cairo_rel_line_to (cr, box_width, 0);
335
cairo_line_to (cr, cx + box_width, cy + height / 2);
336
cairo_rel_line_to (cr, 0, -height);
337
cairo_line_to (cr, _x0, _y0);
338
cairo_close_path (cr);
340
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, GSD_OSD_WINDOW_FG_ALPHA);
341
cairo_fill_preserve (cr);
343
cairo_set_source_rgba (cr, 0.6, 0.6, 0.6, GSD_OSD_WINDOW_FG_ALPHA / 2);
344
cairo_set_line_width (cr, 2);
349
render_speaker (GsdMediaKeysWindow *window,
359
static const char *icon_names[] = {
360
"audio-volume-muted",
362
"audio-volume-medium",
367
if (window->priv->volume_muted) {
371
n = 3 * window->priv->volume_level / 100 + 1;
379
icon_size = (int)width;
381
pixbuf = load_pixbuf (window, icon_names[n], icon_size);
383
if (pixbuf == NULL) {
387
gdk_cairo_set_source_pixbuf (cr, pixbuf, _x0, _y0);
388
cairo_paint_with_alpha (cr, GSD_OSD_WINDOW_FG_ALPHA);
390
g_object_unref (pixbuf);
395
#define LIGHTNESS_MULT 1.3
396
#define DARKNESS_MULT 0.7
399
draw_volume_boxes (GsdMediaKeysWindow *window,
408
GtkStyleContext *context;
413
height = round (height) - 1;
414
width = round (width) - 1;
415
x1 = round ((width - 1) * percentage);
416
context = gtk_widget_get_style_context (GTK_WIDGET (window));
419
gtk_style_context_get_background_color (context, GTK_STATE_NORMAL, &acolor);
420
gsd_osd_window_color_shade (&acolor, DARKNESS_MULT);
421
gsd_osd_window_color_reverse (&acolor);
422
acolor.alpha = GSD_OSD_WINDOW_FG_ALPHA / 2;
423
gsd_osd_window_draw_rounded_rectangle (cr, 1.0, _x0, _y0, height / 6, width, height);
424
gdk_cairo_set_source_rgba (cr, &acolor);
425
cairo_fill_preserve (cr);
428
gtk_style_context_get_background_color (context, GTK_STATE_NORMAL, &acolor);
429
gsd_osd_window_color_shade (&acolor, LIGHTNESS_MULT);
430
gsd_osd_window_color_reverse (&acolor);
431
acolor.alpha = GSD_OSD_WINDOW_FG_ALPHA / 2;
432
gdk_cairo_set_source_rgba (cr, &acolor);
433
cairo_set_line_width (cr, 1);
437
if (percentage < 0.01)
439
gtk_style_context_get_background_color (context, GTK_STATE_NORMAL, &acolor);
440
acolor.alpha = GSD_OSD_WINDOW_FG_ALPHA;
441
gsd_osd_window_draw_rounded_rectangle (cr, 1.0, _x0 + 0.5, _y0 + 0.5, height / 6 - 0.5, x1, height - 1);
442
gdk_cairo_set_source_rgba (cr, &acolor);
447
draw_action_volume (GsdMediaKeysWindow *window,
452
double icon_box_width;
453
double icon_box_height;
456
double volume_box_x0;
457
double volume_box_y0;
458
double volume_box_width;
459
double volume_box_height;
462
gtk_window_get_size (GTK_WINDOW (window), &window_width, &window_height);
464
icon_box_width = round (window_width * 0.65);
465
icon_box_height = round (window_height * 0.65);
466
volume_box_width = icon_box_width;
467
volume_box_height = round (window_height * 0.05);
469
icon_box_x0 = (window_width - icon_box_width) / 2;
470
icon_box_y0 = (window_height - icon_box_height - volume_box_height) / 2;
471
volume_box_x0 = round (icon_box_x0);
472
volume_box_y0 = round (icon_box_height + icon_box_y0);
475
g_message ("icon box: w=%f h=%f _x0=%f _y0=%f",
480
g_message ("volume box: w=%f h=%f _x0=%f _y0=%f",
487
res = render_speaker (window,
489
icon_box_x0, icon_box_y0,
490
icon_box_width, icon_box_height);
492
double speaker_width;
493
double speaker_height;
497
speaker_width = icon_box_width * 0.5;
498
speaker_height = icon_box_height * 0.75;
499
speaker_cx = icon_box_x0 + speaker_width / 2;
500
speaker_cy = icon_box_y0 + speaker_height / 2;
503
g_message ("speaker box: w=%f h=%f cx=%f cy=%f",
510
/* draw speaker symbol */
511
draw_speaker (cr, speaker_cx, speaker_cy, speaker_width, speaker_height);
513
if (! window->priv->volume_muted) {
514
/* draw sound waves */
519
wave_x0 = window_width / 2;
520
wave_y0 = speaker_cy;
521
wave_radius = icon_box_width / 2;
523
draw_waves (cr, wave_x0, wave_y0, wave_radius, window->priv->volume_level);
525
/* draw 'mute' cross */
530
cross_size = speaker_width * 3 / 4;
531
cross_x0 = icon_box_x0 + icon_box_width - cross_size;
532
cross_y0 = speaker_cy;
534
draw_cross (cr, cross_x0, cross_y0, cross_size);
538
/* draw volume meter */
539
draw_volume_boxes (window,
541
(double)window->priv->volume_level / 100.0,
549
render_custom (GsdMediaKeysWindow *window,
559
icon_size = (int)width;
561
pixbuf = load_pixbuf (window, window->priv->icon_name, icon_size);
563
if (pixbuf == NULL) {
565
if (gtk_widget_get_direction (GTK_WIDGET (window)) == GTK_TEXT_DIR_RTL)
566
name = g_strdup_printf ("%s-rtl", window->priv->icon_name);
568
name = g_strdup_printf ("%s-ltr", window->priv->icon_name);
569
pixbuf = load_pixbuf (window, name, icon_size);
575
gdk_cairo_set_source_pixbuf (cr, pixbuf, _x0, _y0);
576
cairo_paint_with_alpha (cr, GSD_OSD_WINDOW_FG_ALPHA);
578
g_object_unref (pixbuf);
584
draw_action_custom (GsdMediaKeysWindow *window,
589
double icon_box_width;
590
double icon_box_height;
593
double bright_box_x0;
594
double bright_box_y0;
595
double bright_box_width;
596
double bright_box_height;
599
gtk_window_get_size (GTK_WINDOW (window), &window_width, &window_height);
601
icon_box_width = round (window_width * 0.65);
602
icon_box_height = round (window_height * 0.65);
603
bright_box_width = round (icon_box_width);
604
bright_box_height = round (window_height * 0.05);
606
icon_box_x0 = (window_width - icon_box_width) / 2;
607
icon_box_y0 = (window_height - icon_box_height - bright_box_height) / 2;
608
bright_box_x0 = round (icon_box_x0);
609
bright_box_y0 = round (icon_box_height + icon_box_y0);
612
g_message ("icon box: w=%f h=%f _x0=%f _y0=%f",
617
g_message ("brightness box: w=%f h=%f _x0=%f _y0=%f",
624
res = render_custom (window,
626
icon_box_x0, icon_box_y0,
627
icon_box_width, icon_box_height);
628
if (! res && g_strcmp0 (window->priv->icon_name, "media-eject") == 0) {
629
/* draw eject symbol */
631
icon_box_x0, icon_box_y0,
632
icon_box_width, icon_box_height);
635
if (window->priv->show_level != FALSE) {
636
/* draw volume meter */
637
draw_volume_boxes (window,
639
(double)window->priv->volume_level / 100.0,
648
gsd_media_keys_window_draw_when_composited (GsdOsdWindow *osd_window,
651
GsdMediaKeysWindow *window = GSD_MEDIA_KEYS_WINDOW (osd_window);
653
switch (window->priv->action) {
654
case GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME:
655
draw_action_volume (window, cr);
657
case GSD_MEDIA_KEYS_WINDOW_ACTION_CUSTOM:
658
draw_action_custom (window, cr);
666
gsd_media_keys_window_class_init (GsdMediaKeysWindowClass *klass)
668
GsdOsdWindowClass *osd_window_class = GSD_OSD_WINDOW_CLASS (klass);
670
osd_window_class->draw_when_composited = gsd_media_keys_window_draw_when_composited;
672
g_type_class_add_private (klass, sizeof (GsdMediaKeysWindowPrivate));
676
gsd_media_keys_window_init (GsdMediaKeysWindow *window)
678
window->priv = GSD_MEDIA_KEYS_WINDOW_GET_PRIVATE (window);
680
if (!gsd_osd_window_is_composited (GSD_OSD_WINDOW (window))) {
682
const gchar *objects[] = {"acme_box", NULL};
685
builder = gtk_builder_new ();
686
gtk_builder_add_objects_from_file (builder,
687
GTKBUILDERDIR "/acme.ui",
691
window->priv->image = GTK_IMAGE (gtk_builder_get_object (builder, "acme_image"));
692
window->priv->progress = GTK_WIDGET (gtk_builder_get_object (builder, "acme_volume_progressbar"));
693
box = GTK_WIDGET (gtk_builder_get_object (builder, "acme_box"));
696
gtk_container_add (GTK_CONTAINER (window), box);
697
gtk_widget_show_all (box);
700
/* The builder needs to stay alive until the window
701
takes ownership of the box (and its children) */
702
g_object_unref (builder);
707
gsd_media_keys_window_new (void)
709
return g_object_new (GSD_TYPE_MEDIA_KEYS_WINDOW, NULL);