[gnome-settings-daemon] media-keys: Make drawing code usable outside the widget



commit 70fc5e988e6d34bf86afd0a930c832a670fbcfc3
Author: Bastien Nocera <hadess hadess net>
Date:   Tue Apr 17 14:29:32 2012 +0100

    media-keys: Make drawing code usable outside the widget
    
    Making it possible to reimplement the OSD in clutter. See
    test-media-window-clutter.c for an example of how to do so.

 plugins/media-keys/Makefile.am                 |    1 +
 plugins/media-keys/gsd-osd-window-private.h    |   67 +++++++++
 plugins/media-keys/gsd-osd-window.c            |  183 +++++++++++++-----------
 plugins/media-keys/test-media-window-clutter.c |   95 ++++++++++++
 4 files changed, 260 insertions(+), 86 deletions(-)
---
diff --git a/plugins/media-keys/Makefile.am b/plugins/media-keys/Makefile.am
index bdc924b..d1d0132 100644
--- a/plugins/media-keys/Makefile.am
+++ b/plugins/media-keys/Makefile.am
@@ -131,6 +131,7 @@ test_media_keys_LDADD = \
 EXTRA_DIST = 				\
 	gsd-marshal.list		\
 	README.media-keys-API		\
+	test-media-window-clutter.c	\
 	$(plugin_in_files)
 
 CLEANFILES = 			\
diff --git a/plugins/media-keys/gsd-osd-window-private.h b/plugins/media-keys/gsd-osd-window-private.h
new file mode 100644
index 0000000..de3b2af
--- /dev/null
+++ b/plugins/media-keys/gsd-osd-window-private.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8; tab-width: 8 -*-
+ *
+ * On-screen-display (OSD) window for gnome-settings-daemon's plugins
+ *
+ * Copyright (C) 2006 William Jon McCann <mccann jhu edu> 
+ * Copyright (C) 2009 Novell, Inc
+ *
+ * Authors:
+ *   William Jon McCann <mccann jhu edu>
+ *   Federico Mena-Quintero <federico novell com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2, 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 Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ *
+ */
+
+/* GsdOsdWindow is an "on-screen-display" window (OSD).  It is the cute,
+ * semi-transparent, curved popup that appears when you press a hotkey global to
+ * the desktop, such as to change the volume, switch your monitor's parameters,
+ * etc.
+ *
+ * You can create a GsdOsdWindow and use it as a normal GtkWindow.  It will
+ * automatically center itself, figure out if it needs to be composited, etc.
+ * Just pack your widgets in it, sit back, and enjoy the ride.
+ */
+
+#ifndef GSD_OSD_WINDOW_PRIVATE_H
+#define GSD_OSD_WINDOW_PRIVATE_H
+
+#include <glib-object.h>
+#include <cairo.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct {
+        int                 size;
+        GtkStyleContext    *style;
+        GtkTextDirection    direction;
+
+        GsdOsdWindowAction  action;
+        GtkIconTheme       *theme;
+        const char         *icon_name;
+
+        gboolean            show_level;
+        int                 volume_level;
+        guint               volume_muted : 1;
+} GsdOsdDrawContext;
+
+void gsd_osd_window_draw (GsdOsdDrawContext *ctx, cairo_t *cr);
+
+G_END_DECLS
+
+#endif
diff --git a/plugins/media-keys/gsd-osd-window.c b/plugins/media-keys/gsd-osd-window.c
index 5e1b3ab..10f6eed 100644
--- a/plugins/media-keys/gsd-osd-window.c
+++ b/plugins/media-keys/gsd-osd-window.c
@@ -38,13 +38,13 @@
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
 #include "gsd-osd-window.h"
+#include "gsd-osd-window-private.h"
 
 #define DIALOG_TIMEOUT 2000       /* dialog timeout in ms */
 #define DIALOG_FADE_TIMEOUT 1500  /* timeout before fade starts */
 #define FADE_TIMEOUT 10           /* timeout in ms between each frame of the fade */
-#define ICON_SCALE 0.50           /* The size of the icon compared to the whole OSD */
-
-#define BG_ALPHA 0.75
+#define ICON_SCALE 0.50           /* size of the icon compared to the whole OSD */
+#define BG_ALPHA 0.75             /* background transparency */
 
 #define GSD_OSD_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_OSD_WINDOW, GsdOsdWindowPrivate))
 
@@ -404,7 +404,7 @@ add_hide_timeout (GsdOsdWindow *window)
 
 static const char *
 get_image_name_for_volume (gboolean muted,
-			   int volume)
+                           int volume)
 {
         static const char *icon_names[] = {
                 "audio-volume-muted-symbolic",
@@ -509,25 +509,16 @@ gsd_osd_window_set_volume_level (GsdOsdWindow *window,
 }
 
 static GdkPixbuf *
-load_pixbuf (GsdOsdWindow *window,
-             const char   *name,
-             int           icon_size)
+load_pixbuf (GsdOsdDrawContext *ctx,
+             const char        *name,
+             int                icon_size)
 {
-        GtkIconTheme    *theme;
         GtkIconInfo     *info;
         GdkPixbuf       *pixbuf;
-        GtkStyleContext *context;
         GdkRGBA          color;
 
-        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 ();
-        }
-
-        context = gtk_widget_get_style_context (GTK_WIDGET (window));
-        gtk_style_context_get_background_color (context, GTK_STATE_NORMAL, &color);
-        info = gtk_icon_theme_lookup_icon (theme,
+        gtk_style_context_get_background_color (ctx->style, GTK_STATE_NORMAL, &color);
+        info = gtk_icon_theme_lookup_icon (ctx->theme,
                                            name,
                                            icon_size,
                                            GTK_ICON_LOOKUP_FORCE_SIZE | GTK_ICON_LOOKUP_GENERIC_FALLBACK);
@@ -681,23 +672,23 @@ draw_speaker (cairo_t *cr,
 }
 
 static gboolean
-render_speaker (GsdOsdWindow *window,
-                cairo_t      *cr,
-                double        _x0,
-                double        _y0,
-                double        width,
-                double        height)
+render_speaker (GsdOsdDrawContext *ctx,
+                cairo_t           *cr,
+                double             _x0,
+                double             _y0,
+                double             width,
+                double             height)
 {
         GdkPixbuf         *pixbuf;
         const char        *icon_name;
         int                icon_size;
 
-	icon_name = get_image_name_for_volume (window->priv->volume_muted,
-					       window->priv->volume_level);
+        icon_name = get_image_name_for_volume (ctx->volume_muted,
+                                               ctx->volume_level);
 
-        icon_size = (int)width;
+        icon_size = (int) width;
 
-        pixbuf = load_pixbuf (window, icon_name, icon_size);
+        pixbuf = load_pixbuf (ctx, icon_name, icon_size);
 
         if (pixbuf == NULL) {
                 return FALSE;
@@ -715,25 +706,23 @@ render_speaker (GsdOsdWindow *window,
 #define DARKNESS_MULT   0.7
 
 static void
-draw_volume_boxes (GsdOsdWindow *window,
-                   cairo_t      *cr,
-                   double        percentage,
-                   double        _x0,
-                   double        _y0,
-                   double        width,
-                   double        height)
+draw_volume_boxes (GsdOsdDrawContext *ctx,
+                   cairo_t           *cr,
+                   double             percentage,
+                   double             _x0,
+                   double             _y0,
+                   double             width,
+                   double             height)
 {
         gdouble   x1;
-        GtkStyleContext *context;
         GdkRGBA  acolor;
 
         height = round (height) - 1;
         width = round (width) - 1;
         x1 = round ((width - 1) * percentage);
-        context = gtk_widget_get_style_context (GTK_WIDGET (window));
 
         /* bar background */
-        gtk_style_context_get_background_color (context, GTK_STATE_NORMAL, &acolor);
+        gtk_style_context_get_background_color (ctx->style, GTK_STATE_NORMAL, &acolor);
         gsd_osd_window_color_shade (&acolor, DARKNESS_MULT);
         gsd_osd_window_color_reverse (&acolor);
         acolor.alpha = GSD_OSD_WINDOW_FG_ALPHA / 2;
@@ -744,7 +733,7 @@ draw_volume_boxes (GsdOsdWindow *window,
         /* bar progress */
         if (percentage < 0.01)
                 return;
-        gtk_style_context_get_background_color (context, GTK_STATE_NORMAL, &acolor);
+        gtk_style_context_get_background_color (ctx->style, GTK_STATE_NORMAL, &acolor);
         acolor.alpha = GSD_OSD_WINDOW_FG_ALPHA;
         gsd_osd_window_draw_rounded_rectangle (cr, 1.0, _x0, _y0, height / 6, x1, height);
         gdk_cairo_set_source_rgba (cr, &acolor);
@@ -752,8 +741,8 @@ draw_volume_boxes (GsdOsdWindow *window,
 }
 
 static void
-draw_action_volume (GsdOsdWindow *window,
-                    cairo_t      *cr)
+draw_action_volume (GsdOsdDrawContext *ctx,
+                    cairo_t           *cr)
 {
         int window_width;
         int window_height;
@@ -767,7 +756,7 @@ draw_action_volume (GsdOsdWindow *window,
         double volume_box_height;
         gboolean res;
 
-	window_width = window_height = window->priv->size;
+	window_width = window_height = ctx->size;
 
         icon_box_width = round (window_width * ICON_SCALE);
         icon_box_height = round (window_height * ICON_SCALE);
@@ -792,7 +781,7 @@ draw_action_volume (GsdOsdWindow *window,
                    volume_box_y0);
 #endif
 
-        res = render_speaker (window,
+        res = render_speaker (ctx,
                               cr,
                               icon_box_x0, icon_box_y0,
                               icon_box_width, icon_box_height);
@@ -818,7 +807,7 @@ draw_action_volume (GsdOsdWindow *window,
                 /* draw speaker symbol */
                 draw_speaker (cr, speaker_cx, speaker_cy, speaker_width, speaker_height);
 
-                if (! window->priv->volume_muted) {
+                if (!ctx->volume_muted) {
                         /* draw sound waves */
                         double wave_x0;
                         double wave_y0;
@@ -828,7 +817,7 @@ draw_action_volume (GsdOsdWindow *window,
                         wave_y0 = speaker_cy;
                         wave_radius = icon_box_width / 2;
 
-                        draw_waves (cr, wave_x0, wave_y0, wave_radius, window->priv->volume_level);
+                        draw_waves (cr, wave_x0, wave_y0, wave_radius, ctx->volume_level);
                 } else {
                         /* draw 'mute' cross */
                         double cross_x0;
@@ -844,9 +833,9 @@ draw_action_volume (GsdOsdWindow *window,
         }
 
         /* draw volume meter */
-        draw_volume_boxes (window,
+        draw_volume_boxes (ctx,
                            cr,
-                           (double)window->priv->volume_level / 100.0,
+                           (double) ctx->volume_level / 100.0,
                            volume_box_x0,
                            volume_box_y0,
                            volume_box_width,
@@ -854,7 +843,7 @@ draw_action_volume (GsdOsdWindow *window,
 }
 
 static gboolean
-render_custom (GsdOsdWindow *window,
+render_custom (GsdOsdDrawContext  *ctx,
                cairo_t            *cr,
                double              _x0,
                double              _y0,
@@ -866,15 +855,15 @@ render_custom (GsdOsdWindow *window,
 
         icon_size = (int)width;
 
-        pixbuf = load_pixbuf (window, window->priv->icon_name, icon_size);
+        pixbuf = load_pixbuf (ctx, ctx->icon_name, icon_size);
 
         if (pixbuf == NULL) {
                 char *name;
-                if (gtk_widget_get_direction (GTK_WIDGET (window)) == GTK_TEXT_DIR_RTL)
-                        name = g_strdup_printf ("%s-rtl", window->priv->icon_name);
+                if (ctx->direction == GTK_TEXT_DIR_RTL)
+                        name = g_strdup_printf ("%s-rtl", ctx->icon_name);
                 else
-                        name = g_strdup_printf ("%s-ltr", window->priv->icon_name);
-                pixbuf = load_pixbuf (window, name, icon_size);
+                        name = g_strdup_printf ("%s-ltr", ctx->icon_name);
+                pixbuf = load_pixbuf (ctx, name, icon_size);
                 g_free (name);
                 if (pixbuf == NULL)
                         return FALSE;
@@ -889,7 +878,7 @@ render_custom (GsdOsdWindow *window,
 }
 
 static void
-draw_action_custom (GsdOsdWindow *window,
+draw_action_custom (GsdOsdDrawContext  *ctx,
                     cairo_t            *cr)
 {
         int window_width;
@@ -904,7 +893,7 @@ draw_action_custom (GsdOsdWindow *window,
         double bright_box_height;
         gboolean res;
 
-        gtk_window_get_size (GTK_WINDOW (window), &window_width, &window_height);
+	window_width = window_height = ctx->size;
 
         icon_box_width = round (window_width * ICON_SCALE);
         icon_box_height = round (window_height * ICON_SCALE);
@@ -929,22 +918,22 @@ draw_action_custom (GsdOsdWindow *window,
                    bright_box_y0);
 #endif
 
-        res = render_custom (window,
+        res = render_custom (ctx,
                              cr,
                              icon_box_x0, icon_box_y0,
                              icon_box_width, icon_box_height);
-        if (! res && g_str_has_prefix (window->priv->icon_name, "media-eject")) {
+        if (!res && g_str_has_prefix (ctx->icon_name, "media-eject")) {
                 /* draw eject symbol */
                 draw_eject (cr,
                             icon_box_x0, icon_box_y0,
                             icon_box_width, icon_box_height);
         }
 
-        if (window->priv->show_level != FALSE) {
+        if (ctx->show_level != FALSE) {
                 /* draw volume meter */
-                draw_volume_boxes (window,
+                draw_volume_boxes (ctx,
                                    cr,
-                                   (double)window->priv->volume_level / 100.0,
+                                   (double) ctx->volume_level / 100.0,
                                    bright_box_x0,
                                    bright_box_y0,
                                    bright_box_width,
@@ -952,16 +941,43 @@ draw_action_custom (GsdOsdWindow *window,
         }
 }
 
+void
+gsd_osd_window_draw (GsdOsdDrawContext *ctx,
+                     cairo_t           *cr)
+{
+        gdouble          corner_radius;
+        GdkRGBA          acolor;
+
+        /* draw a box */
+        corner_radius = ctx->size / 10;
+        gsd_osd_window_draw_rounded_rectangle (cr, 1.0, 0.0, 0.0, corner_radius, ctx->size - 1, ctx->size - 1);
+        gtk_style_context_get_background_color (ctx->style, GTK_STATE_NORMAL, &acolor);
+        gsd_osd_window_color_reverse (&acolor);
+        acolor.alpha = BG_ALPHA;
+        gdk_cairo_set_source_rgba (cr, &acolor);
+        cairo_fill (cr);
+
+        switch (ctx->action) {
+        case GSD_OSD_WINDOW_ACTION_VOLUME:
+                draw_action_volume (ctx, cr);
+                break;
+        case GSD_OSD_WINDOW_ACTION_CUSTOM:
+                draw_action_custom (ctx, cr);
+                break;
+        default:
+                break;
+        }
+}
+
 static gboolean
-gsd_osd_window_draw (GtkWidget *widget,
+gsd_osd_window_obj_draw (GtkWidget *widget,
                      cairo_t   *orig_cr)
 {
-        GsdOsdWindow    *window;
-        cairo_t         *cr;
-        cairo_surface_t *surface;
-        GtkStyleContext *context;
-        GdkRGBA          acolor;
-        gdouble          corner_radius;
+        GsdOsdWindow      *window;
+        cairo_t           *cr;
+        cairo_surface_t   *surface;
+        GtkStyleContext   *context;
+        GsdOsdDrawContext  ctx;
 
         window = GSD_OSD_WINDOW (widget);
 
@@ -985,25 +1001,20 @@ gsd_osd_window_draw (GtkWidget *widget,
         cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
         cairo_paint (cr);
 
-        /* draw a box */
-	corner_radius = window->priv->size / 10;
-        gsd_osd_window_draw_rounded_rectangle (cr, 1.0, 0.0, 0.0, corner_radius, window->priv->size - 1, window->priv->size - 1);
-        gtk_style_context_get_background_color (context, GTK_STATE_NORMAL, &acolor);
-        gsd_osd_window_color_reverse (&acolor);
-        acolor.alpha = BG_ALPHA;
-        gdk_cairo_set_source_rgba (cr, &acolor);
-        cairo_fill (cr);
-
-        switch (window->priv->action) {
-        case GSD_OSD_WINDOW_ACTION_VOLUME:
-                draw_action_volume (window, cr);
-                break;
-        case GSD_OSD_WINDOW_ACTION_CUSTOM:
-                draw_action_custom (window, cr);
-                break;
-        default:
-                break;
+        ctx.size = window->priv->size;
+        ctx.style = context;
+        ctx.volume_level = window->priv->volume_level;
+        ctx.volume_muted = window->priv->volume_muted;
+        ctx.icon_name = window->priv->icon_name;
+        ctx.direction = gtk_widget_get_direction (GTK_WIDGET (window));
+        ctx.show_level = window->priv->show_level;
+        ctx.action = window->priv->action;
+        if (window != NULL && gtk_widget_has_screen (GTK_WIDGET (window))) {
+                ctx.theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (window)));
+        } else {
+                ctx.theme = gtk_icon_theme_get_default ();
         }
+        gsd_osd_window_draw (&ctx, cr);
 
         cairo_destroy (cr);
 
@@ -1128,7 +1139,7 @@ gsd_osd_window_class_init (GsdOsdWindowClass *klass)
         widget_class->show = gsd_osd_window_real_show;
         widget_class->hide = gsd_osd_window_real_hide;
         widget_class->realize = gsd_osd_window_real_realize;
-        widget_class->draw = gsd_osd_window_draw;
+        widget_class->draw = gsd_osd_window_obj_draw;
 
         g_type_class_add_private (klass, sizeof (GsdOsdWindowPrivate));
 }
diff --git a/plugins/media-keys/test-media-window-clutter.c b/plugins/media-keys/test-media-window-clutter.c
new file mode 100644
index 0000000..ee2e2f9
--- /dev/null
+++ b/plugins/media-keys/test-media-window-clutter.c
@@ -0,0 +1,95 @@
+// gcc -o test-media-window-clutter `pkg-config --libs --cflags clutter-1.0 gtk+-3.0 cairo` -I../../ -lm test-media-window-clutter.c gsd-osd-window.c
+
+#include <stdlib.h>
+
+#include <gtk/gtk.h>
+#include <clutter/clutter.h>
+
+#include "gsd-osd-window.h"
+#include "gsd-osd-window-private.h"
+
+static gboolean
+draw_box (ClutterCanvas     *canvas,
+          cairo_t           *cr,
+          int                width,
+          int                height,
+          GsdOsdDrawContext *ctx)
+{
+	cairo_save (cr);
+	cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+	cairo_paint (cr);
+
+	cairo_restore (cr);
+	cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+
+	ctx->size = MIN(width, height);
+
+	ctx->action = GSD_OSD_WINDOW_ACTION_CUSTOM;
+	ctx->icon_name = "touchpad-disabled-symbolic";
+
+	gsd_osd_window_draw (ctx, cr);
+
+	return FALSE;
+}
+
+static void
+test_window (void)
+{
+  GsdOsdDrawContext ctx;
+  ClutterActor *stage, *actor;
+  ClutterContent *canvas;
+  GtkWidget *widget;
+
+  /* create a resizable stage */
+  stage = clutter_stage_new ();
+  clutter_stage_set_title (CLUTTER_STAGE (stage), "OSD Test");
+  clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
+  clutter_actor_set_background_color (stage, CLUTTER_COLOR_Red);
+  clutter_actor_set_size (stage, 300, 300);
+  clutter_actor_show (stage);
+
+  /* box canvas */
+  canvas = clutter_canvas_new ();
+  clutter_canvas_set_size (CLUTTER_CANVAS (canvas), 300, 300);
+
+  actor = clutter_actor_new ();
+  clutter_actor_add_constraint (actor, clutter_bind_constraint_new (stage, CLUTTER_BIND_SIZE, 0));
+  clutter_actor_set_content (actor, canvas);
+  clutter_content_invalidate (canvas);
+  g_object_unref (canvas);
+
+  clutter_actor_add_child (stage, actor);
+
+  memset (&ctx, 0, sizeof(ctx));
+  widget = gsd_osd_window_new ();
+  ctx.style = gtk_widget_get_style_context (widget);
+  ctx.direction = gtk_widget_get_direction (GTK_WIDGET (widget));;
+  ctx.theme = gtk_icon_theme_get_default ();
+
+  g_signal_connect (canvas, "draw", G_CALLBACK (draw_box), &ctx);
+
+  g_signal_connect (stage, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+  clutter_content_invalidate (canvas);
+}
+
+int
+main (int    argc,
+      char **argv)
+{
+        GError *error = NULL;
+
+        if (! gtk_init_with_args (&argc, &argv, NULL, NULL, NULL, &error)) {
+                fprintf (stderr, "%s", error->message);
+                g_error_free (error);
+                exit (1);
+        }
+	if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
+		return EXIT_FAILURE;
+
+        test_window ();
+
+        gtk_main ();
+
+        return 0;
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]