[PATCH] example for gtk-demo demonstrating offscreen-rendered widgets with reflection-effect



Greetings gtk+-crowd!

	Here is a patch for gtk-demo adding an example showing off redirected
widget drawing with a reflection effect. The patch applies to gtk+
r19219.

Screenshot:

        http://macslow.thepimp.net/shots/offscreen-widgets-demo.png

Best regards...

Mirco "MacSlow" Müller
diff -Naur gtk-demo.orig/composited_window.c gtk-demo/composited_window.c
--- gtk-demo.orig/composited_window.c	1970-01-01 01:00:00.000000000 +0100
+++ gtk-demo/composited_window.c	2007-12-22 21:04:14.000000000 +0100
@@ -0,0 +1,222 @@
+/* Composited Window
+ *
+ * Offscreen rendered widgets are used to achieve a reflection effect. Only
+ * works under X11!
+ */
+
+#include <gtk/gtk.h>
+
+#ifdef GDK_WINDOWING_X11
+
+static gboolean
+window_expose_event (GtkWidget *widget,
+                     GdkEventExpose *event)
+{
+  GtkWidget *child;
+  cairo_t *cr;
+  gdouble color[3];
+  cairo_matrix_t matrix;
+  cairo_pattern_t *mask;
+  GtkStyle *style;
+
+  /* get our child... here the event-box */ 
+  child = gtk_bin_get_child (GTK_BIN (widget));
+
+  /* create a cairo context to draw to the window */
+  cr = gdk_cairo_create (widget->window);
+
+  /* redirect output for double-buffering */
+  cairo_push_group (cr);
+
+  /* write/paint over everything else */
+  cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+
+  /* set clip-region to windows dimensions */
+  cairo_rectangle (cr,
+                   (gdouble) widget->allocation.x,
+                   (gdouble) widget->allocation.y,
+                   (gdouble) widget->allocation.width,
+                   (gdouble) widget->allocation.height);
+  cairo_clip (cr);
+
+  /* get theme background-color and clear/paint the context with it */
+  style = gtk_widget_get_style (widget);
+  color[0] = (gdouble) style->bg[GTK_STATE_NORMAL].red;
+  color[1] = (gdouble) style->bg[GTK_STATE_NORMAL].green;
+  color[2] = (gdouble) style->bg[GTK_STATE_NORMAL].blue;
+  color[0] /= (gdouble) 0xFFFF;
+  color[1] /= (gdouble) 0xFFFF;
+  color[2] /= (gdouble) 0xFFFF;
+  cairo_set_source_rgb (cr, color[0], color[1], color[2]);
+  cairo_paint (cr);
+
+  /* obtain the the source data... here the composited event-box */
+  cairo_save (cr);
+  gdk_cairo_set_source_pixmap (cr,
+                               child->window,
+                               child->allocation.x,
+                               child->allocation.y);
+
+  /* draw it at its original position */
+  cairo_paint (cr);
+  cairo_restore (cr);
+
+  /* setup transformation-matrix to mirror the source and move it down */
+  cairo_save (cr);
+  cairo_matrix_init_scale (&matrix, 1.0f, -1.0f);
+  cairo_matrix_translate (&matrix,  0.0f, -95.0f);
+  cairo_transform (cr, &matrix);
+
+  /* get the source again */
+  gdk_cairo_set_source_pixmap (cr,
+                               child->window,
+                               child->allocation.x,
+                               child->allocation.y);
+
+  /* create linear gradient as mask-pattern to fade out the source */
+  mask = cairo_pattern_create_linear (0.0f, 0.0f, 0.0f, (gdouble) 68);
+  cairo_pattern_add_color_stop_rgba (mask, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+  cairo_pattern_add_color_stop_rgba (mask, 0.25f, 0.0f, 0.0f, 0.0f, 0.01f);
+  cairo_pattern_add_color_stop_rgba (mask, 0.5f, 0.0f, 0.0f, 0.0f, 0.125f);
+  cairo_pattern_add_color_stop_rgba (mask, 0.75f, 0.0f, 0.0f, 0.0f, 0.5f);
+  cairo_pattern_add_color_stop_rgba (mask, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
+
+  /* apply and draw the current source with the mask-pattern */
+  cairo_mask (cr, mask);
+
+  /* get rid of the mask-pattern again */
+  cairo_pattern_destroy (mask);
+  cairo_restore (cr);
+
+  /* draw the buffered contents */
+  cairo_pop_group_to_source (cr);
+  cairo_paint (cr);
+
+  /* we're done */
+  cairo_destroy (cr);
+
+  return TRUE;
+}
+
+static gboolean
+transparent_expose (GtkWidget *widget,
+                    GdkEventExpose *event)
+{
+  cairo_t *cr;
+
+  cr = gdk_cairo_create (widget->window);
+  cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+  gdk_cairo_region (cr, event->region);
+  cairo_fill (cr);
+  cairo_destroy (cr);
+
+  return FALSE;
+}
+
+GtkWidget *
+do_composited_window (GtkWidget *do_widget)
+{
+  static GtkWidget *window = NULL;
+  GtkWidget *alignment;
+  GtkWidget *vbox;
+  GtkWidget *hbox;
+  GtkWidget *event;
+  GtkWidget *backbutton;
+  GtkWidget *applybutton;
+  GtkWidget *entry;
+  GdkScreen *screen;
+  GdkColormap *colormap;
+
+  if (!window)
+  {
+    /* create the widgets */
+    alignment = gtk_alignment_new (0.5f, 0.0f, 1.0f, 0.0f);
+    gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 34, 0, 0);
+    vbox = gtk_vbox_new (FALSE, 6);
+    hbox = gtk_hbox_new (FALSE, 6);
+    backbutton = gtk_button_new ();
+    gtk_container_add (GTK_CONTAINER (backbutton),
+                       gtk_image_new_from_stock (GTK_STOCK_GO_BACK, 4));
+    entry = gtk_entry_new ();
+    gtk_widget_set_size_request (entry, -1, 34);
+    applybutton = gtk_button_new ();
+    gtk_container_add (GTK_CONTAINER (applybutton),
+                       gtk_image_new_from_stock (GTK_STOCK_APPLY, 4));
+    event = gtk_event_box_new ();
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+    /* if we don't do this, the reflection gets not updated at the right
+     * time */
+    gtk_widget_set_double_buffered (window, FALSE);
+
+    /* set the colormap for the event box... must be done before the event
+     * box is realised. */
+    screen = gtk_widget_get_screen (event);
+    colormap = gdk_screen_get_rgba_colormap (screen);
+    gtk_widget_set_colormap (event, colormap);
+
+    /* set title for the window */
+    gtk_window_set_title (GTK_WINDOW (window), "gtk+ offscreen widgets");
+
+    /* set our event box to have a fully transparent background
+     * drawn on it... currently there is no way to simply tell GTK+
+     * that "transparency" is the background colour for a widget */
+    gtk_widget_set_app_paintable (GTK_WIDGET (event), TRUE);
+    g_signal_connect (event,
+                      "expose-event",
+                      G_CALLBACK (transparent_expose),
+                      NULL);
+
+    /* stuff it all together */
+    gtk_container_set_border_width (GTK_CONTAINER (window), 12);
+    gtk_container_add (GTK_CONTAINER (window), event);
+    gtk_container_add (GTK_CONTAINER (event), alignment);
+    gtk_container_add (GTK_CONTAINER (alignment), hbox);
+    gtk_box_pack_start (GTK_BOX (hbox), backbutton, FALSE, FALSE, 0);
+    gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
+    gtk_box_pack_start (GTK_BOX (hbox), applybutton, FALSE, FALSE, 0);
+
+    /* realize everything */
+    gtk_widget_realize (window);
+
+    /* connect the windows close-button */
+    g_signal_connect (window,
+                      "destroy",
+                      G_CALLBACK (gtk_widget_destroyed),
+                      &window);
+
+    /* connect the compositing handler */
+    g_signal_connect (window,
+                      "expose-event",
+                      G_CALLBACK (window_expose_event),
+                      NULL);
+  }
+
+  if (!GTK_WIDGET_VISIBLE (window))
+  {
+    gtk_widget_show_all (window);
+
+    /* set the event box GdkWindow to be composited.
+     * obviously must be performed after event box is realised.
+     */
+    gdk_window_set_composited (event->window, TRUE);
+  }
+  else
+  {	 
+    gtk_widget_destroy (window);
+    window = NULL;
+  }
+
+  return window;
+}
+
+#elif /* GDK_WINDOWING_X11 */
+
+GtkWidget *
+do_composited_window (GtkWidget *do_widget)
+{
+  return NULL;
+}
+
+#endif /* GDK_WINDOWING_X11 */
+
diff -Naur gtk-demo.orig/Makefile.am gtk-demo/Makefile.am
--- gtk-demo.orig/Makefile.am	2007-12-22 20:36:58.000000000 +0100
+++ gtk-demo/Makefile.am	2007-12-22 21:04:14.000000000 +0100
@@ -14,6 +14,7 @@
 	clipboard.c				\
 	colorsel.c				\
 	combobox.c				\
+	composited_window.c			\
 	dialog.c				\
 	drawingarea.c				\
 	editable_cells.c			\


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