2007-03-26 Jens Granseuer <jensgr@gmx.net> * gnome-settings-multimedia-keys.c: (dialog_init): * gsd-media-keys-window.c: (gsd_media_keys_window_is_valid), (initialize_alpha_mode): * gsd-media-keys-window.h: rebuild the media window if the state of composite has changed (fixes bug #408035) svn path=/trunk/; revision=7425
899 lines
21 KiB
C
899 lines
21 KiB
C
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
|
*
|
|
* Copyright (C) 2006-2007 William Jon McCann <mccann@jhu.edu>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <glib.h>
|
|
#include <glib/gi18n.h>
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <glade/glade.h>
|
|
|
|
#include "gsd-media-keys-window.h"
|
|
|
|
#define DIALOG_TIMEOUT 2000 /* dialog timeout in ms */
|
|
|
|
#define BG_ALPHA 0.50
|
|
#define FG_ALPHA 1.00
|
|
|
|
static void gsd_media_keys_window_class_init (GsdMediaKeysWindowClass *klass);
|
|
static void gsd_media_keys_window_init (GsdMediaKeysWindow *fade);
|
|
static void gsd_media_keys_window_finalize (GObject *object);
|
|
|
|
#define GSD_MEDIA_KEYS_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_MEDIA_KEYS_WINDOW, GsdMediaKeysWindowPrivate))
|
|
|
|
struct GsdMediaKeysWindowPrivate
|
|
{
|
|
guint is_composited : 1;
|
|
guint hide_timeout_id;
|
|
GsdMediaKeysWindowAction action;
|
|
|
|
guint volume_muted : 1;
|
|
int volume_level;
|
|
|
|
GladeXML *xml;
|
|
};
|
|
|
|
G_DEFINE_TYPE (GsdMediaKeysWindow, gsd_media_keys_window, GTK_TYPE_WINDOW)
|
|
|
|
static gboolean
|
|
hide_timeout (GsdMediaKeysWindow *window)
|
|
{
|
|
gtk_widget_hide (GTK_WIDGET (window));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
remove_hide_timeout (GsdMediaKeysWindow *window)
|
|
{
|
|
if (window->priv->hide_timeout_id != 0) {
|
|
g_source_remove (window->priv->hide_timeout_id);
|
|
window->priv->hide_timeout_id = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
add_hide_timeout (GsdMediaKeysWindow *window)
|
|
{
|
|
window->priv->hide_timeout_id = g_timeout_add (DIALOG_TIMEOUT,
|
|
(GSourceFunc)hide_timeout,
|
|
window);
|
|
}
|
|
|
|
static void
|
|
update_window (GsdMediaKeysWindow *window)
|
|
{
|
|
remove_hide_timeout (window);
|
|
add_hide_timeout (window);
|
|
|
|
if (window->priv->is_composited) {
|
|
gtk_widget_queue_draw (GTK_WIDGET (window));
|
|
}
|
|
}
|
|
|
|
static void
|
|
volume_controls_set_visible (GsdMediaKeysWindow *window,
|
|
gboolean visible)
|
|
{
|
|
GtkWidget *progress;
|
|
|
|
if (window->priv->xml == NULL) {
|
|
return;
|
|
}
|
|
|
|
progress = glade_xml_get_widget (window->priv->xml, "acme_volume_progressbar");
|
|
if (progress == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (visible) {
|
|
gtk_widget_show (progress);
|
|
} else {
|
|
gtk_widget_hide (progress);
|
|
}
|
|
}
|
|
|
|
static void
|
|
window_set_icon_name (GsdMediaKeysWindow *window,
|
|
const char *name)
|
|
{
|
|
GtkWidget *image;
|
|
|
|
if (window->priv->xml == NULL) {
|
|
return;
|
|
}
|
|
|
|
image = glade_xml_get_widget (window->priv->xml, "acme_image");
|
|
if (image == NULL) {
|
|
return;
|
|
}
|
|
|
|
gtk_image_set_from_icon_name (GTK_IMAGE (image), name, GTK_ICON_SIZE_DIALOG);
|
|
}
|
|
|
|
static void
|
|
window_set_icon_file (GsdMediaKeysWindow *window,
|
|
const char *path)
|
|
{
|
|
GtkWidget *image;
|
|
|
|
if (window->priv->xml == NULL) {
|
|
return;
|
|
}
|
|
|
|
image = glade_xml_get_widget (window->priv->xml, "acme_image");
|
|
if (image == NULL) {
|
|
return;
|
|
}
|
|
|
|
gtk_image_set_from_file (GTK_IMAGE (image), path);
|
|
}
|
|
|
|
static void
|
|
action_changed (GsdMediaKeysWindow *window)
|
|
{
|
|
if (! window->priv->is_composited) {
|
|
switch (window->priv->action) {
|
|
case GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME:
|
|
volume_controls_set_visible (window, TRUE);
|
|
|
|
if (window->priv->volume_muted) {
|
|
window_set_icon_name (window, "audio-volume-muted");
|
|
} else {
|
|
window_set_icon_name (window, "audio-volume-high");
|
|
}
|
|
|
|
break;
|
|
case GSD_MEDIA_KEYS_WINDOW_ACTION_EJECT:
|
|
volume_controls_set_visible (window, FALSE);
|
|
window_set_icon_file (window, GNOMECC_PIXMAPS_DIR "/acme-eject.png");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
update_window (window);
|
|
}
|
|
|
|
static void
|
|
volume_level_changed (GsdMediaKeysWindow *window)
|
|
{
|
|
update_window (window);
|
|
|
|
if (! window->priv->is_composited) {
|
|
GtkWidget *progress;
|
|
double fraction;
|
|
|
|
if (window->priv->xml != NULL) {
|
|
fraction = (double)window->priv->volume_level / 100.0;
|
|
|
|
progress = glade_xml_get_widget (window->priv->xml, "acme_volume_progressbar");
|
|
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress), fraction);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
volume_muted_changed (GsdMediaKeysWindow *window)
|
|
{
|
|
update_window (window);
|
|
|
|
if (! window->priv->is_composited) {
|
|
if (window->priv->volume_muted) {
|
|
window_set_icon_name (window, "audio-volume-muted");
|
|
} else {
|
|
window_set_icon_name (window, "audio-volume-high");
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
gsd_media_keys_window_set_action (GsdMediaKeysWindow *window,
|
|
GsdMediaKeysWindowAction action)
|
|
{
|
|
g_return_if_fail (GSD_IS_MEDIA_KEYS_WINDOW (window));
|
|
|
|
if (window->priv->action != action) {
|
|
window->priv->action = action;
|
|
action_changed (window);
|
|
}
|
|
}
|
|
|
|
void
|
|
gsd_media_keys_window_set_volume_muted (GsdMediaKeysWindow *window,
|
|
gboolean muted)
|
|
{
|
|
g_return_if_fail (GSD_IS_MEDIA_KEYS_WINDOW (window));
|
|
|
|
if (window->priv->volume_muted != muted) {
|
|
window->priv->volume_muted = muted;
|
|
volume_muted_changed (window);
|
|
}
|
|
}
|
|
|
|
void
|
|
gsd_media_keys_window_set_volume_level (GsdMediaKeysWindow *window,
|
|
int level)
|
|
{
|
|
g_return_if_fail (GSD_IS_MEDIA_KEYS_WINDOW (window));
|
|
|
|
if (window->priv->volume_level != level) {
|
|
window->priv->volume_level = level;
|
|
volume_level_changed (window);
|
|
}
|
|
}
|
|
|
|
static void
|
|
curved_rectangle (cairo_t *cr,
|
|
double x0,
|
|
double y0,
|
|
double width,
|
|
double height,
|
|
double radius)
|
|
{
|
|
double x1;
|
|
double y1;
|
|
|
|
x1 = x0 + width;
|
|
y1 = y0 + height;
|
|
|
|
if (!width || !height) {
|
|
return;
|
|
}
|
|
|
|
if (width / 2 < radius) {
|
|
if (height / 2 < radius) {
|
|
cairo_move_to (cr, x0, (y0 + y1) / 2);
|
|
cairo_curve_to (cr, x0 ,y0, x0, y0, (x0 + x1) / 2, y0);
|
|
cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2);
|
|
cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1);
|
|
cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2);
|
|
} else {
|
|
cairo_move_to (cr, x0, y0 + radius);
|
|
cairo_curve_to (cr, x0, y0, x0, y0, (x0 + x1) / 2, y0);
|
|
cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
|
|
cairo_line_to (cr, x1, y1 - radius);
|
|
cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1);
|
|
cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
|
|
}
|
|
} else {
|
|
if (height / 2 < radius) {
|
|
cairo_move_to (cr, x0, (y0 + y1) / 2);
|
|
cairo_curve_to (cr, x0, y0, x0 , y0, x0 + radius, y0);
|
|
cairo_line_to (cr, x1 - radius, y0);
|
|
cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2);
|
|
cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
|
|
cairo_line_to (cr, x0 + radius, y1);
|
|
cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2);
|
|
} else {
|
|
cairo_move_to (cr, x0, y0 + radius);
|
|
cairo_curve_to (cr, x0 , y0, x0 , y0, x0 + radius, y0);
|
|
cairo_line_to (cr, x1 - radius, y0);
|
|
cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
|
|
cairo_line_to (cr, x1, y1 - radius);
|
|
cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
|
|
cairo_line_to (cr, x0 + radius, y1);
|
|
cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
|
|
}
|
|
}
|
|
|
|
cairo_close_path (cr);
|
|
}
|
|
|
|
static GdkPixbuf *
|
|
load_pixbuf (GsdMediaKeysWindow *window,
|
|
const char *name,
|
|
int icon_size)
|
|
{
|
|
GtkIconTheme *theme;
|
|
GdkPixbuf *pixbuf;
|
|
|
|
if (window != NULL && gtk_widget_has_screen (GTK_WIDGET (window))) {
|
|
theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (window)));
|
|
} else {
|
|
theme = gtk_icon_theme_get_default ();
|
|
}
|
|
|
|
pixbuf = gtk_icon_theme_load_icon (theme,
|
|
name,
|
|
icon_size,
|
|
GTK_ICON_LOOKUP_FORCE_SVG,
|
|
NULL);
|
|
|
|
/* make sure the pixbuf is close to the requested size
|
|
* this is necessary because GTK_ICON_LOOKUP_FORCE_SVG
|
|
* seems to be broken */
|
|
if (pixbuf != NULL) {
|
|
int width;
|
|
|
|
width = gdk_pixbuf_get_width (pixbuf);
|
|
if (width < (float)icon_size * 0.75) {
|
|
g_object_unref (pixbuf);
|
|
pixbuf = NULL;
|
|
}
|
|
}
|
|
|
|
return pixbuf;
|
|
}
|
|
|
|
static gboolean
|
|
render_eject (GsdMediaKeysWindow *window,
|
|
cairo_t *cr,
|
|
double x0,
|
|
double y0,
|
|
double width,
|
|
double height)
|
|
{
|
|
GdkPixbuf *pixbuf;
|
|
int icon_size;
|
|
const char *icon_name;
|
|
|
|
icon_name = "media-eject";
|
|
|
|
icon_size = (int)width;
|
|
|
|
pixbuf = load_pixbuf (window, icon_name, icon_size);
|
|
|
|
if (pixbuf == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
gdk_cairo_set_source_pixbuf (cr, pixbuf, x0, y0);
|
|
cairo_paint_with_alpha (cr, FG_ALPHA);
|
|
|
|
g_object_unref (pixbuf);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
draw_eject (cairo_t *cr,
|
|
double x0,
|
|
double y0,
|
|
double width,
|
|
double height)
|
|
{
|
|
int box_height;
|
|
int tri_height;
|
|
int separation;
|
|
|
|
box_height = height * 0.2;
|
|
separation = box_height / 3;
|
|
tri_height = height - box_height - separation;
|
|
|
|
cairo_rectangle (cr, x0, y0 + height - box_height, width, box_height);
|
|
|
|
cairo_move_to (cr, x0, y0 + tri_height);
|
|
cairo_rel_line_to (cr, width, 0);
|
|
cairo_rel_line_to (cr, -width / 2, -tri_height);
|
|
cairo_rel_line_to (cr, -width / 2, tri_height);
|
|
cairo_close_path (cr);
|
|
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, FG_ALPHA);
|
|
cairo_fill_preserve (cr);
|
|
|
|
cairo_set_source_rgba (cr, 0.6, 0.6, 0.6, FG_ALPHA / 2);
|
|
cairo_set_line_width (cr, 2);
|
|
cairo_stroke (cr);
|
|
}
|
|
|
|
static void
|
|
draw_action_eject (GsdMediaKeysWindow *window,
|
|
cairo_t *cr)
|
|
{
|
|
int window_width;
|
|
int window_height;
|
|
double width;
|
|
double height;
|
|
double x0;
|
|
double y0;
|
|
gboolean res;
|
|
|
|
gtk_window_get_size (GTK_WINDOW (window), &window_width, &window_height);
|
|
|
|
width = window_width * 0.65;
|
|
height = window_height * 0.65;
|
|
x0 = (window_width - width) / 2;
|
|
y0 = (window_height - height) / 2;
|
|
|
|
#if 0
|
|
g_message ("eject box: w=%f h=%f x0=%f y0=%f",
|
|
width,
|
|
height,
|
|
x0,
|
|
y0);
|
|
#endif
|
|
|
|
res = render_eject (window,
|
|
cr,
|
|
x0, y0,
|
|
width, height);
|
|
if (! res) {
|
|
/* draw eject symbol */
|
|
draw_eject (cr, x0, y0, width, height);
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_waves (cairo_t *cr,
|
|
double cx,
|
|
double cy,
|
|
double max_radius)
|
|
{
|
|
int n_waves;
|
|
int i;
|
|
|
|
n_waves = 3;
|
|
|
|
for (i = 0; i < n_waves; i++) {
|
|
double angle1;
|
|
double angle2;
|
|
double radius;
|
|
|
|
angle1 = -M_PI / 4;
|
|
angle2 = M_PI / 4;
|
|
|
|
radius = (i + 1) * (max_radius / n_waves);
|
|
cairo_arc (cr, cx, cy, radius, angle1, angle2);
|
|
cairo_set_source_rgba (cr, 0.6, 0.6, 0.6, FG_ALPHA / 2);
|
|
cairo_set_line_width (cr, 14);
|
|
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
|
|
cairo_stroke_preserve (cr);
|
|
|
|
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, FG_ALPHA);
|
|
cairo_set_line_width (cr, 10);
|
|
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
|
|
cairo_stroke (cr);
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_speaker (cairo_t *cr,
|
|
double cx,
|
|
double cy,
|
|
double width,
|
|
double height)
|
|
{
|
|
double box_width;
|
|
double box_height;
|
|
double x0;
|
|
double y0;
|
|
|
|
box_width = width / 3;
|
|
box_height = height / 3;
|
|
|
|
x0 = cx - (width / 2) + box_width;
|
|
y0 = cy - box_height / 2;
|
|
|
|
cairo_move_to (cr, x0, y0);
|
|
cairo_rel_line_to (cr, - box_width, 0);
|
|
cairo_rel_line_to (cr, 0, box_height);
|
|
cairo_rel_line_to (cr, box_width, 0);
|
|
|
|
cairo_line_to (cr, cx + box_width, cy + height / 2);
|
|
cairo_rel_line_to (cr, 0, -height);
|
|
cairo_line_to (cr, x0, y0);
|
|
cairo_close_path (cr);
|
|
|
|
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, FG_ALPHA);
|
|
cairo_fill_preserve (cr);
|
|
|
|
cairo_set_source_rgba (cr, 0.6, 0.6, 0.6, FG_ALPHA / 2);
|
|
cairo_set_line_width (cr, 2);
|
|
cairo_stroke (cr);
|
|
}
|
|
|
|
static gboolean
|
|
render_speaker (GsdMediaKeysWindow *window,
|
|
cairo_t *cr,
|
|
double x0,
|
|
double y0,
|
|
double width,
|
|
double height)
|
|
{
|
|
GdkPixbuf *pixbuf;
|
|
int icon_size;
|
|
int n;
|
|
static const char *icon_names[] = {
|
|
"audio-volume-muted",
|
|
"audio-volume-low",
|
|
"audio-volume-medium",
|
|
"audio-volume-high",
|
|
NULL
|
|
};
|
|
|
|
if (window->priv->volume_muted) {
|
|
n = 0;
|
|
} else {
|
|
/* select image */
|
|
n = 3 * window->priv->volume_level / 100 + 1;
|
|
if (n < 1) {
|
|
n = 1;
|
|
} else if (n > 3) {
|
|
n = 3;
|
|
}
|
|
}
|
|
|
|
icon_size = (int)width;
|
|
|
|
pixbuf = load_pixbuf (window, icon_names[n], icon_size);
|
|
|
|
if (pixbuf == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
gdk_cairo_set_source_pixbuf (cr, pixbuf, x0, y0);
|
|
cairo_paint_with_alpha (cr, FG_ALPHA);
|
|
|
|
g_object_unref (pixbuf);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
draw_volume_boxes (GsdMediaKeysWindow *window,
|
|
cairo_t *cr,
|
|
double percentage,
|
|
double x0,
|
|
double y0,
|
|
double width,
|
|
double height)
|
|
{
|
|
gdouble x1;
|
|
GdkColor color;
|
|
double r, g, b;
|
|
|
|
x1 = width * percentage;
|
|
|
|
/* bar background */
|
|
color = GTK_WIDGET (window)->style->dark [GTK_STATE_NORMAL];
|
|
r = (float)color.red / 65535.0;
|
|
g = (float)color.green / 65535.0;
|
|
b = (float)color.blue / 65535.0;
|
|
cairo_rectangle (cr, x0, y0, width, height);
|
|
cairo_set_source_rgba (cr, r, g, b, FG_ALPHA);
|
|
cairo_fill (cr);
|
|
|
|
/* bar border */
|
|
color = GTK_WIDGET (window)->style->dark [GTK_STATE_SELECTED];
|
|
r = (float)color.red / 65535.0;
|
|
g = (float)color.green / 65535.0;
|
|
b = (float)color.blue / 65535.0;
|
|
cairo_rectangle (cr, x0, y0, width, height);
|
|
cairo_set_source_rgba (cr, r, g, b, FG_ALPHA);
|
|
cairo_set_line_width (cr, 1);
|
|
cairo_stroke (cr);
|
|
|
|
/* bar progress */
|
|
color = GTK_WIDGET (window)->style->bg [GTK_STATE_SELECTED];
|
|
r = (float)color.red / 65535.0;
|
|
g = (float)color.green / 65535.0;
|
|
b = (float)color.blue / 65535.0;
|
|
cairo_rectangle (cr, x0, y0, x1, height);
|
|
cairo_set_source_rgba (cr, r, g, b, FG_ALPHA);
|
|
cairo_fill (cr);
|
|
}
|
|
|
|
static void
|
|
draw_action_volume (GsdMediaKeysWindow *window,
|
|
cairo_t *cr)
|
|
{
|
|
int window_width;
|
|
int window_height;
|
|
double icon_box_width;
|
|
double icon_box_height;
|
|
double icon_box_x0;
|
|
double icon_box_y0;
|
|
double volume_box_x0;
|
|
double volume_box_y0;
|
|
double volume_box_width;
|
|
double volume_box_height;
|
|
gboolean res;
|
|
|
|
gtk_window_get_size (GTK_WINDOW (window), &window_width, &window_height);
|
|
|
|
icon_box_width = window_width * 0.65;
|
|
icon_box_height = window_height * 0.65;
|
|
volume_box_width = icon_box_width;
|
|
volume_box_height = window_height * 0.05;
|
|
|
|
icon_box_x0 = (window_width - icon_box_width) / 2;
|
|
icon_box_y0 = (window_height - icon_box_height - volume_box_height) / 2;
|
|
volume_box_x0 = icon_box_x0;
|
|
volume_box_y0 = icon_box_height + icon_box_y0;
|
|
|
|
#if 0
|
|
g_message ("icon box: w=%f h=%f x0=%f y0=%f",
|
|
icon_box_width,
|
|
icon_box_height,
|
|
icon_box_x0,
|
|
icon_box_y0);
|
|
g_message ("volume box: w=%f h=%f x0=%f y0=%f",
|
|
volume_box_width,
|
|
volume_box_height,
|
|
volume_box_x0,
|
|
volume_box_y0);
|
|
#endif
|
|
|
|
res = render_speaker (window,
|
|
cr,
|
|
icon_box_x0, icon_box_y0,
|
|
icon_box_width, icon_box_height);
|
|
if (! res) {
|
|
double speaker_width;
|
|
double speaker_height;
|
|
double speaker_cx;
|
|
double speaker_cy;
|
|
double wave_x0;
|
|
double wave_y0;
|
|
double wave_radius;
|
|
|
|
speaker_width = icon_box_width * 0.5;
|
|
speaker_height = icon_box_height * 0.75;
|
|
speaker_cx = icon_box_x0 + speaker_width / 2;
|
|
speaker_cy = icon_box_y0 + speaker_height / 2;
|
|
|
|
wave_x0 = window_width / 2;
|
|
wave_y0 = speaker_cy;
|
|
wave_radius = icon_box_width / 2;
|
|
|
|
#if 0
|
|
g_message ("speaker box: w=%f h=%f cx=%f cy=%f",
|
|
speaker_width,
|
|
speaker_height,
|
|
speaker_cx,
|
|
speaker_cy);
|
|
#endif
|
|
|
|
/* draw speaker symbol */
|
|
draw_speaker (cr, speaker_cx, speaker_cy, speaker_width, speaker_height);
|
|
/* draw sound waves */
|
|
if (! window->priv->volume_muted) {
|
|
draw_waves (cr, wave_x0, wave_y0, wave_radius);
|
|
}
|
|
}
|
|
|
|
/* draw volume meter */
|
|
draw_volume_boxes (window,
|
|
cr,
|
|
(double)window->priv->volume_level / 100.0,
|
|
volume_box_x0,
|
|
volume_box_y0,
|
|
volume_box_width,
|
|
volume_box_height);
|
|
}
|
|
|
|
static void
|
|
draw_action (GsdMediaKeysWindow *window,
|
|
cairo_t *cr)
|
|
{
|
|
switch (window->priv->action) {
|
|
case GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME:
|
|
draw_action_volume (window, cr);
|
|
break;
|
|
case GSD_MEDIA_KEYS_WINDOW_ACTION_EJECT:
|
|
draw_action_eject (window, cr);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
on_expose_event (GtkWidget *widget,
|
|
GdkEventExpose *event,
|
|
GsdMediaKeysWindow *window)
|
|
{
|
|
cairo_t *context;
|
|
cairo_t *cr;
|
|
cairo_surface_t *surface;
|
|
int width;
|
|
int height;
|
|
GdkColor color;
|
|
double r, g, b;
|
|
|
|
context = gdk_cairo_create (GTK_WIDGET (window)->window);
|
|
|
|
cairo_set_operator (context, CAIRO_OPERATOR_SOURCE);
|
|
gtk_window_get_size (GTK_WINDOW (widget), &width, &height);
|
|
|
|
surface = cairo_surface_create_similar (cairo_get_target (context),
|
|
CAIRO_CONTENT_COLOR_ALPHA,
|
|
width,
|
|
height);
|
|
|
|
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
|
|
goto done;
|
|
}
|
|
|
|
cr = cairo_create (surface);
|
|
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) {
|
|
goto done;
|
|
}
|
|
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0);
|
|
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
|
cairo_paint (cr);
|
|
|
|
/* draw a box */
|
|
curved_rectangle (cr, 0, 0, width, height, height / 10);
|
|
color = GTK_WIDGET (window)->style->bg [GTK_STATE_NORMAL];
|
|
r = (float)color.red / 65535.0;
|
|
g = (float)color.green / 65535.0;
|
|
b = (float)color.blue / 65535.0;
|
|
cairo_set_source_rgba (cr, r, g, b, BG_ALPHA);
|
|
cairo_fill_preserve (cr);
|
|
|
|
color = GTK_WIDGET (window)->style->fg [GTK_STATE_NORMAL];
|
|
r = (float)color.red / 65535.0;
|
|
g = (float)color.green / 65535.0;
|
|
b = (float)color.blue / 65535.0;
|
|
cairo_set_source_rgba (cr, r, g, b, BG_ALPHA);
|
|
cairo_set_line_width (cr, 1);
|
|
cairo_stroke (cr);
|
|
|
|
/* draw action */
|
|
draw_action (window, cr);
|
|
|
|
cairo_destroy (cr);
|
|
|
|
cairo_set_source_surface (context, surface, 0, 0);
|
|
cairo_paint (context);
|
|
|
|
done:
|
|
if (surface != NULL) {
|
|
cairo_surface_destroy (surface);
|
|
}
|
|
cairo_destroy (context);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gsd_media_keys_window_real_show (GtkWidget *widget)
|
|
{
|
|
GsdMediaKeysWindow *window;
|
|
|
|
if (GTK_WIDGET_CLASS (gsd_media_keys_window_parent_class)->show) {
|
|
GTK_WIDGET_CLASS (gsd_media_keys_window_parent_class)->show (widget);
|
|
}
|
|
|
|
window = GSD_MEDIA_KEYS_WINDOW (widget);
|
|
remove_hide_timeout (window);
|
|
add_hide_timeout (window);
|
|
}
|
|
|
|
static void
|
|
gsd_media_keys_window_real_hide (GtkWidget *widget)
|
|
{
|
|
GsdMediaKeysWindow *window;
|
|
|
|
if (GTK_WIDGET_CLASS (gsd_media_keys_window_parent_class)->hide) {
|
|
GTK_WIDGET_CLASS (gsd_media_keys_window_parent_class)->hide (widget);
|
|
}
|
|
|
|
window = GSD_MEDIA_KEYS_WINDOW (widget);
|
|
remove_hide_timeout (window);
|
|
}
|
|
|
|
static void
|
|
gsd_media_keys_window_class_init (GsdMediaKeysWindowClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
GtkWidgetClass *widget_class;
|
|
|
|
widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
object_class->finalize = gsd_media_keys_window_finalize;
|
|
|
|
widget_class->show = gsd_media_keys_window_real_show;
|
|
widget_class->hide = gsd_media_keys_window_real_hide;
|
|
|
|
g_type_class_add_private (klass, sizeof (GsdMediaKeysWindowPrivate));
|
|
}
|
|
|
|
gboolean
|
|
gsd_media_keys_window_is_valid (GsdMediaKeysWindow *window)
|
|
{
|
|
GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (window));
|
|
return gdk_screen_is_composited (screen) == window->priv->is_composited;
|
|
}
|
|
|
|
static void
|
|
initialize_alpha_mode (GsdMediaKeysWindow *window)
|
|
{
|
|
GdkScreen *screen;
|
|
GdkColormap *colormap = NULL;
|
|
|
|
screen = gtk_widget_get_screen (GTK_WIDGET (window));
|
|
if (gdk_screen_is_composited (screen)) {
|
|
colormap = gdk_screen_get_rgba_colormap (screen);
|
|
}
|
|
|
|
if (colormap != NULL) {
|
|
gtk_widget_set_colormap (GTK_WIDGET (window), colormap);
|
|
window->priv->is_composited = TRUE;
|
|
} else {
|
|
window->priv->is_composited = FALSE;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gsd_media_keys_window_init (GsdMediaKeysWindow *window)
|
|
{
|
|
window->priv = GSD_MEDIA_KEYS_WINDOW_GET_PRIVATE (window);
|
|
|
|
initialize_alpha_mode (window);
|
|
|
|
if (window->priv->is_composited) {
|
|
gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
|
|
gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
|
|
|
|
gtk_window_set_default_size (GTK_WINDOW (window), 300, 300);
|
|
g_signal_connect (window, "expose-event", G_CALLBACK (on_expose_event), window);
|
|
} else {
|
|
GtkWidget *vbox;
|
|
|
|
window->priv->xml = glade_xml_new (GNOMECC_GLADE_DIR "/acme.glade", "acme_vbox", NULL);
|
|
|
|
vbox = glade_xml_get_widget (window->priv->xml, "acme_vbox");
|
|
if (vbox != NULL) {
|
|
gtk_container_add (GTK_CONTAINER (window), vbox);
|
|
gtk_widget_show_all (vbox);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
gsd_media_keys_window_finalize (GObject *object)
|
|
{
|
|
GsdMediaKeysWindow *window;
|
|
|
|
g_return_if_fail (object != NULL);
|
|
g_return_if_fail (GSD_IS_MEDIA_KEYS_WINDOW (object));
|
|
|
|
window = GSD_MEDIA_KEYS_WINDOW (object);
|
|
|
|
g_return_if_fail (window->priv != NULL);
|
|
|
|
if (window->priv->xml != NULL) {
|
|
g_object_unref (window->priv->xml);
|
|
}
|
|
|
|
G_OBJECT_CLASS (gsd_media_keys_window_parent_class)->finalize (object);
|
|
}
|
|
|
|
GtkWidget *
|
|
gsd_media_keys_window_new (void)
|
|
{
|
|
GObject *object;
|
|
|
|
object = g_object_new (GSD_TYPE_MEDIA_KEYS_WINDOW,
|
|
"type", GTK_WINDOW_POPUP,
|
|
"skip-taskbar-hint", TRUE,
|
|
"skip-pager-hint", TRUE,
|
|
"focus-on-map", FALSE,
|
|
NULL);
|
|
|
|
return GTK_WIDGET (object);
|
|
}
|