Add a new media keys window that takes advantage of compositing when

2006-12-07  William Jon McCann  <mccann@jhu.edu>

	* gnome-settings-daemon/Makefile.am:
	* gnome-settings-daemon/actions/Makefile.am:
	* gnome-settings-daemon/actions/acme.glade:
	* gnome-settings-daemon/actions/gnome-speakernotes-muted.png:
	* gnome-settings-daemon/actions/gnome-speakernotes.png:
	* gnome-settings-daemon/gnome-settings-multimedia-keys.c:
	(execute), (dialog_init), (unhookup_keysym), (update_kbd_cb),
	(init_kbd), (dialog_show), (do_eject_action), (do_sound_action),
	(gnome_settings_multimedia_keys_load):
	* gnome-settings-daemon/gsd-media-keys-window.c: (hide_timeout),
	(remove_hide_timeout), (add_hide_timeout), (update_window),
	(volume_controls_set_visible), (window_set_icon_name),
	(window_set_icon_file), (action_changed), (volume_level_changed),
	(volume_muted_changed), (gsd_media_keys_window_set_action),
	(gsd_media_keys_window_set_volume_muted),
	(gsd_media_keys_window_set_volume_level), (curved_rectangle),
	(draw_action_eject), (draw_waves), (draw_speaker),
	(draw_volume_boxes), (draw_action_volume), (draw_action),
	(on_expose_event), (gsd_media_keys_window_real_show),
	(gsd_media_keys_window_real_hide),
	(gsd_media_keys_window_class_init), (initialize_alpha_mode),
	(gsd_media_keys_window_init), (gsd_media_keys_window_finalize),
	(gsd_media_keys_window_new):
	* gnome-settings-daemon/gsd-media-keys-window.h:
	Add a new media keys window that takes advantage of
	compositing when available.  Fixes #383066
This commit is contained in:
William Jon McCann 2006-12-07 17:54:56 +00:00 committed by William Jon McCann
parent 514196c62d
commit e7ba3dd216
9 changed files with 835 additions and 150 deletions

View file

@ -1,3 +1,32 @@
2006-12-07 William Jon McCann <mccann@jhu.edu>
* gnome-settings-daemon/Makefile.am:
* gnome-settings-daemon/actions/Makefile.am:
* gnome-settings-daemon/actions/acme.glade:
* gnome-settings-daemon/actions/gnome-speakernotes-muted.png:
* gnome-settings-daemon/actions/gnome-speakernotes.png:
* gnome-settings-daemon/gnome-settings-multimedia-keys.c:
(execute), (dialog_init), (unhookup_keysym), (update_kbd_cb),
(init_kbd), (dialog_show), (do_eject_action), (do_sound_action),
(gnome_settings_multimedia_keys_load):
* gnome-settings-daemon/gsd-media-keys-window.c: (hide_timeout),
(remove_hide_timeout), (add_hide_timeout), (update_window),
(volume_controls_set_visible), (window_set_icon_name),
(window_set_icon_file), (action_changed), (volume_level_changed),
(volume_muted_changed), (gsd_media_keys_window_set_action),
(gsd_media_keys_window_set_volume_muted),
(gsd_media_keys_window_set_volume_level), (curved_rectangle),
(draw_action_eject), (draw_waves), (draw_speaker),
(draw_volume_boxes), (draw_action_volume), (draw_action),
(on_expose_event), (gsd_media_keys_window_real_show),
(gsd_media_keys_window_real_hide),
(gsd_media_keys_window_class_init), (initialize_alpha_mode),
(gsd_media_keys_window_init), (gsd_media_keys_window_finalize),
(gsd_media_keys_window_new):
* gnome-settings-daemon/gsd-media-keys-window.h:
Add a new media keys window that takes advantage of
compositing when available. Fixes #383066
2006-12-04 Rodrigo Moya <rodrigo@novell.com>
* configure.in:

View file

@ -44,6 +44,8 @@ gnome_settings_daemon_SOURCES = \
gnome-settings-dbus.c \
gnome-settings-xrdb.c \
gnome-settings-xrdb.h \
gsd-media-keys-window.c \
gsd-media-keys-window.h \
xsettings-common.c \
xsettings-manager.c \
xsettings-common.h \

View file

@ -32,7 +32,7 @@ Datadir = $(datadir)/control-center-2.0/interfaces/
Data_DATA = acme.glade
pixmapsdir = $(GNOMECC_PIXMAPS_DIR)
pixmaps_DATA = acme-eject.png gnome-speakernotes-muted.png gnome-speakernotes.png
pixmaps_DATA = acme-eject.png
EXTRA_DIST = \
acme-volume-alsa.c acme-volume-alsa.h \

View file

@ -10,24 +10,26 @@
<property name="modal">False</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
<property name="decorated">True</property>
<property name="skip_taskbar_hint">False</property>
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="focus_on_map">True</property>
<property name="urgency_hint">False</property>
<child>
<widget class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="label_yalign">0.5</property>
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
<child>
<widget class="GtkVBox" id="vbox2">
<property name="border_width">5</property>
<widget class="GtkVBox" id="acme_vbox">
<property name="border_width">12</property>
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<property name="spacing">6</property>
<child>
<widget class="GtkImage" id="image1">
<widget class="GtkImage" id="acme_image">
<property name="visible">True</property>
<property name="icon_size">6</property>
<property name="icon_name">stock_volume-max</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
@ -41,15 +43,12 @@
</child>
<child>
<widget class="GtkProgressBar" id="progressbar">
<widget class="GtkProgressBar" id="acme_volume_progressbar">
<property name="visible">True</property>
<property name="orientation">GTK_PROGRESS_LEFT_TO_RIGHT</property>
<property name="fraction">0</property>
<property name="pulse_step">0.1</property>
<property name="activity_mode">False</property>
<property name="show_text">False</property>
<property name="text_xalign">0.5</property>
<property name="text_yalign">0.5</property>
<property name="pulse_step">0.10000000149</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
</widget>
<packing>
<property name="padding">0</property>
@ -59,8 +58,6 @@
</child>
</widget>
</child>
</widget>
</child>
</widget>
</glade-interface>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

View file

@ -1,5 +1,7 @@
/*
* Copyright (C) 2001,2002,2003 Bastien Nocera <hadess@hadess.net>
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2001-2003 Bastien Nocera <hadess@hadess.net>
* Copyright (C) 2006 William Jon McCann <mccann@jhu.edu>
*
* gnome-settings-multimedia-keys.c
*
@ -30,15 +32,14 @@
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#include <glade/glade.h>
#include <gconf/gconf-client.h>
#include "eggaccelerators.h"
#include "actions/acme.h"
#include "actions/acme-volume.h"
#include "gsd-media-keys-window.h"
#define DIALOG_TIMEOUT 1000 /* dialog timeout in ms */
#define VOLUME_STEP 6 /* percents for one volume button press */
/* we exclude shift, GDK_CONTROL_MASK and GDK_MOD1_MASK since we know what
@ -52,22 +53,14 @@
typedef struct {
AcmeVolume *volobj;
GladeXML *xml;
GtkWidget *dialog;
GConfClient *conf_client;
guint dialog_timeout;
/* Multihead stuff */
GdkScreen *current_screen;
GSList *screens;
} Acme;
enum {
ICON_MUTED,
ICON_LOUD,
ICON_EJECT,
};
static void
acme_error (char * msg)
{
@ -137,40 +130,11 @@ do_sleep_action (char *cmd1, char *cmd2)
}
}
static char *images[] = {
PIXMAPSDIR "/gnome-speakernotes-muted.png",
PIXMAPSDIR "/gnome-speakernotes.png",
PIXMAPSDIR "/acme-eject.png",
};
static void
acme_image_set (Acme *acme, int icon)
{
GtkWidget *image;
image = glade_xml_get_widget (acme->xml, "image1");
g_return_if_fail (image != NULL);
if (icon > ICON_EJECT)
g_assert_not_reached ();
gtk_image_set_from_file (GTK_IMAGE(image), images[icon]);
}
static void
dialog_init (Acme *acme)
{
if (acme->xml == NULL) {
glade_gnome_init ();
acme->xml = glade_xml_new (DATADIR "/control-center-2.0/interfaces/acme.glade", NULL, NULL);
if (acme->xml == NULL) {
acme_error (_("Couldn't load the Glade file.\n"
"Make sure that this daemon is properly installed."));
return;
}
acme->dialog = glade_xml_get_widget (acme->xml, "dialog");
acme_image_set (acme, ICON_LOUD);
if (acme->dialog == NULL) {
acme->dialog = gsd_media_keys_window_new ();
}
}
@ -496,14 +460,6 @@ init_kbd (Acme *acme)
}
}
static gboolean
dialog_hide (Acme *acme)
{
gtk_widget_hide (acme->dialog);
acme->dialog_timeout = 0;
return FALSE;
}
static void
dialog_show (Acme *acme)
{
@ -550,9 +506,6 @@ dialog_show (Acme *acme)
gtk_widget_show (acme->dialog);
gdk_display_sync (gdk_screen_get_display (acme->current_screen));
acme->dialog_timeout = gtk_timeout_add (DIALOG_TIMEOUT,
(GtkFunction) dialog_hide, acme);
}
static void
@ -655,40 +608,26 @@ do_exit_action (Acme *acme)
static void
do_eject_action (Acme *acme)
{
GtkWidget *progress;
char *command;
if (acme->dialog_timeout != 0)
{
gtk_timeout_remove (acme->dialog_timeout);
acme->dialog_timeout = 0;
}
dialog_init (acme);
progress = glade_xml_get_widget (acme->xml, "progressbar");
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress),
(double) 0);
gtk_widget_set_sensitive (progress, FALSE);
acme_image_set (acme, ICON_EJECT);
gsd_media_keys_window_set_action (GSD_MEDIA_KEYS_WINDOW (acme->dialog),
GSD_MEDIA_KEYS_WINDOW_ACTION_EJECT);
dialog_show (acme);
command = gconf_client_get_string (acme->conf_client,
GCONF_MISC_DIR "/eject_command", NULL);
if ((command != NULL) && (strcmp (command, "") != 0))
execute (command, TRUE);
execute (command, FALSE);
else
execute ("eject", TRUE);
execute ("eject", FALSE);
g_free (command);
gtk_widget_set_sensitive (progress, TRUE);
}
static void
do_sound_action (Acme *acme, int type)
{
GtkWidget *progress;
gboolean muted;
int vol;
int vol_step;
@ -702,18 +641,13 @@ do_sound_action (Acme *acme, int type)
if (vol_step == 0)
vol_step = VOLUME_STEP;
if (acme->dialog_timeout != 0)
{
gtk_timeout_remove (acme->dialog_timeout);
acme->dialog_timeout = 0;
}
/* FIXME: this is racy */
vol = acme_volume_get_volume (acme->volobj);
muted = acme_volume_get_mute (acme->volobj);
switch (type) {
case MUTE_KEY:
acme_volume_mute_toggle(acme->volobj);
acme_volume_mute_toggle (acme->volobj);
break;
case VOLUME_DOWN_KEY:
if (muted)
@ -733,16 +667,18 @@ do_sound_action (Acme *acme, int type)
break;
}
muted = acme_volume_get_mute(acme->volobj);
dialog_init (acme);
acme_image_set (acme, muted ? ICON_MUTED : ICON_LOUD);
muted = acme_volume_get_mute (acme->volobj);
vol = acme_volume_get_volume (acme->volobj);
progress = glade_xml_get_widget (acme->xml, "progressbar");
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress),
(double) vol / 100);
/* FIXME: AcmeVolume should probably emit signals
instead of doing it like this */
dialog_init (acme);
gsd_media_keys_window_set_volume_muted (GSD_MEDIA_KEYS_WINDOW (acme->dialog),
muted);
gsd_media_keys_window_set_volume_level (GSD_MEDIA_KEYS_WINDOW (acme->dialog),
vol);
gsd_media_keys_window_set_action (GSD_MEDIA_KEYS_WINDOW (acme->dialog),
GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME);
dialog_show (acme);
}
@ -863,15 +799,14 @@ void
gnome_settings_multimedia_keys_init (GConfClient *client)
{
}
void
gnome_settings_multimedia_keys_load (GConfClient *client)
{
GSList *l;
Acme *acme;
GError *err = NULL;
acme = g_new0 (Acme, 1);
acme->xml = NULL;
acme->conf_client = client;
gconf_client_add_dir (acme->conf_client,
@ -881,7 +816,6 @@ gnome_settings_multimedia_keys_load (GConfClient *client)
init_screens (acme);
init_kbd (acme);
acme->dialog_timeout = 0;
/* initialise Volume handler */
acme->volobj = acme_volume_new();

View file

@ -0,0 +1,656 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2006 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 */
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, PIXMAPSDIR "/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 void
draw_action_eject (GsdMediaKeysWindow *window,
cairo_t *cr)
{
int window_width;
int window_height;
int width;
int height;
int x0;
int y0;
int box_height;
int tri_height;
int separation;
gtk_window_get_size (GTK_WINDOW (window), &window_width, &window_height);
width = window_width * 0.5;
height = window_height * 0.5;
x0 = (window_width - width) / 2;
y0 = (window_height - height) / 2;
box_height = height * 0.2;
separation = box_height / 3;
tri_height = height - box_height - separation;
/* draw eject symbol */
cairo_rectangle (cr, x0, y0 + height - box_height, width, box_height);
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
cairo_fill (cr);
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, 1.0);
cairo_fill (cr);
}
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 / 3;
angle2 = M_PI / 3;
radius = (i + 1) * (max_radius / n_waves);
cairo_arc (cr, cx, cy, radius, angle1, angle2);
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
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;
box_width = width / 3;
box_height = height / 3;
cairo_rectangle (cr, cx - box_width / 2, cy - box_height / 2, box_width, box_height);
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
cairo_fill (cr);
cairo_move_to (cr, cx, cy);
cairo_rel_line_to (cr, width / 2, -height / 2);
cairo_rel_line_to (cr, 0, height);
cairo_rel_line_to (cr, -width / 2, -height / 2);
cairo_close_path (cr);
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
cairo_fill (cr);
}
static void
draw_volume_boxes (cairo_t *cr,
double percentage,
double x0,
double y0,
double width,
double height)
{
gdouble x1;
x1 = width * percentage;
cairo_rectangle (cr, x0, y0, width, height);
cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 1.0);
cairo_fill (cr);
cairo_rectangle (cr, x0, y0, x1, height);
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
cairo_fill (cr);
}
static void
draw_action_volume (GsdMediaKeysWindow *window,
cairo_t *cr)
{
int window_width;
int window_height;
int width;
int height;
double speaker_width;
double speaker_height;
double speaker_cx;
double speaker_cy;
double wave_x0;
double wave_y0;
double wave_radius;
double box_x0;
double box_y0;
double box_width;
double box_height;
gtk_window_get_size (GTK_WINDOW (window), &window_width, &window_height);
width = window_width * 0.5;
height = window_height * 0.5;
speaker_width = width * 0.75;
speaker_height = height * 0.75;
speaker_cx = window_width / 4;
speaker_cy = window_height / 3;
wave_x0 = window_width / 2;
wave_y0 = speaker_cy;
wave_radius = width / 2;
box_x0 = (window_width - width) / 2;
box_y0 = window_width - (window_width - width) / 2;
box_width = width;
box_height = height * 0.1;
/* 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 (cr,
(double)window->priv->volume_level / 100.0,
box_x0,
box_y0,
box_width,
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;
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, 50);
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.5);
cairo_fill (cr);
/* draw action */
draw_action (window, cr);
cairo_destroy (cr);
cairo_set_source_surface (context, surface, 0, 0);
cairo_paint (context);
done:
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));
}
static void
initialize_alpha_mode (GsdMediaKeysWindow *window)
{
GdkScreen *screen;
GdkColormap *colormap;
screen = gtk_widget_get_screen (GTK_WIDGET (window));
colormap = gdk_screen_get_rgba_colormap (screen);
if (colormap != NULL && gdk_screen_is_composited (screen)) {
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 (DATADIR "/control-center-2.0/interfaces/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,
"set-focus-on-map", FALSE,
NULL);
return GTK_WIDGET (object);
}

View file

@ -0,0 +1,67 @@
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
*
* Copyright (C) 2006 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.
*
*/
#ifndef GSD_MEDIA_KEYS_WINDOW_H
#define GSD_MEDIA_KEYS_WINDOW_H
#include <glib-object.h>
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GSD_TYPE_MEDIA_KEYS_WINDOW (gsd_media_keys_window_get_type ())
#define GSD_MEDIA_KEYS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSD_TYPE_MEDIA_KEYS_WINDOW, GsdMediaKeysWindow))
#define GSD_MEDIA_KEYS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSD_TYPE_MEDIA_KEYS_WINDOW, GsdMediaKeysWindowClass))
#define GSD_IS_MEDIA_KEYS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSD_TYPE_MEDIA_KEYS_WINDOW))
#define GSD_IS_MEDIA_KEYS_WINDOW_CLASS(klass) (G_TYPE_INSTANCE_GET_CLASS ((klass), GSD_TYPE_MEDIA_KEYS_WINDOW))
typedef struct GsdMediaKeysWindow GsdMediaKeysWindow;
typedef struct GsdMediaKeysWindowClass GsdMediaKeysWindowClass;
typedef struct GsdMediaKeysWindowPrivate GsdMediaKeysWindowPrivate;
struct GsdMediaKeysWindow {
GtkWindow parent;
GsdMediaKeysWindowPrivate *priv;
};
struct GsdMediaKeysWindowClass {
GtkWindowClass parent_class;
};
typedef enum {
GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME,
GSD_MEDIA_KEYS_WINDOW_ACTION_EJECT
} GsdMediaKeysWindowAction;
GType gsd_media_keys_window_get_type (void);
GtkWidget * gsd_media_keys_window_new (void);
void gsd_media_keys_window_set_action (GsdMediaKeysWindow *window,
GsdMediaKeysWindowAction action);
void gsd_media_keys_window_set_volume_muted (GsdMediaKeysWindow *window,
gboolean muted);
void gsd_media_keys_window_set_volume_level (GsdMediaKeysWindow *window,
int level);
G_END_DECLS
#endif