forked from AuroraMiddleware/gtk
Add support for composited child windows. (#412882, Ryan Lortie)
2007-06-01 Matthias Clasen <mclasen@redhat.com> Add support for composited child windows. (#412882, Ryan Lortie) * gdk/gdk.symbols: * gdk/gdkdisplay.h: * gdk/gdkinternals.h: * gdk/gdkwindow.[hc]: Add gdk_display_supports_composite() and gdk_window_set_composited(). * gdk/x11/gdkevents-x11.c: * gdk/x11/gdkdisplay-x11.[hc]: * gdk/x11/gdkwindow-x11.[hc]: X11 implementation. * gdk/win32/gdkdisplay-win32.c: * gdk/win32/gdkwindow-win32.c: Dummy win32 implementration. * gdk/quartz/gdkdisplay-quartz.c: * gdk/quartz/gdkwindow-quartz.c: Dummy Quartz implementation. * gdk/directfb/gdkdisplay-directfb.c: * gdk/directfb/gdkwindow-directfb.c: Dummy DirectFB implementation. * tests/testgtk.c: Add a "composited window" test. svn path=/trunk/; revision=18004
This commit is contained in:
parent
62c13f0463
commit
885ba04648
25
ChangeLog
25
ChangeLog
@ -1,3 +1,28 @@
|
||||
2007-06-01 Matthias Clasen <mclasen@redhat.com>
|
||||
|
||||
Add support for composited child windows. (#412882, Ryan Lortie)
|
||||
|
||||
* gdk/gdk.symbols:
|
||||
* gdk/gdkdisplay.h:
|
||||
* gdk/gdkinternals.h:
|
||||
* gdk/gdkwindow.[hc]: Add gdk_display_supports_composite() and
|
||||
gdk_window_set_composited().
|
||||
|
||||
* gdk/x11/gdkevents-x11.c:
|
||||
* gdk/x11/gdkdisplay-x11.[hc]:
|
||||
* gdk/x11/gdkwindow-x11.[hc]: X11 implementation.
|
||||
|
||||
* gdk/win32/gdkdisplay-win32.c:
|
||||
* gdk/win32/gdkwindow-win32.c: Dummy win32 implementration.
|
||||
|
||||
* gdk/quartz/gdkdisplay-quartz.c:
|
||||
* gdk/quartz/gdkwindow-quartz.c: Dummy Quartz implementation.
|
||||
|
||||
* gdk/directfb/gdkdisplay-directfb.c:
|
||||
* gdk/directfb/gdkwindow-directfb.c: Dummy DirectFB implementation.
|
||||
|
||||
* tests/testgtk.c: Add a "composited window" test.
|
||||
|
||||
2007-06-01 Michael Natterer <mitch@imendio.com>
|
||||
|
||||
* gtk/gtkmenuitem.c (gtk_menu_item_position_menu): don't switch
|
||||
|
@ -1,3 +1,8 @@
|
||||
2007-06-01 Matthias Clasen <mclasen@redhat.com>
|
||||
|
||||
* gdk/gdk-sections.txt: Add new composited window api
|
||||
* gdk/tmpl/windows.sgml: Add composited window example
|
||||
|
||||
2007-05-26 Matthias Clasen <mclasen@redhat.com>
|
||||
|
||||
* gtk/migrating*.sgml: Some cleanups
|
||||
|
@ -155,6 +155,7 @@ gdk_display_supports_clipboard_persistence
|
||||
gdk_display_store_clipboard
|
||||
gdk_display_supports_shapes
|
||||
gdk_display_supports_input_shapes
|
||||
gdk_display_supports_composite
|
||||
<SUBSECTION Standard>
|
||||
GDK_DISPLAY_OBJECT
|
||||
GDK_IS_DISPLAY
|
||||
@ -651,6 +652,7 @@ gdk_window_unfullscreen
|
||||
gdk_window_set_keep_above
|
||||
gdk_window_set_keep_below
|
||||
gdk_window_set_opacity
|
||||
gdk_window_set_composited
|
||||
gdk_window_move
|
||||
gdk_window_resize
|
||||
gdk_window_move_resize
|
||||
|
@ -12,6 +12,164 @@ GTK+ level. A #GtkWindow is a toplevel window, the thing a user might think of
|
||||
as a "window" with a titlebar and so on; a #GtkWindow may contain many #GdkWindow.
|
||||
For example, each #GtkButton has a #GdkWindow associated with it.
|
||||
</para>
|
||||
<example id="composited-window-example"><title>Composited windows</title>
|
||||
<programlisting><![CDATA[
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
/* The expose event handler for the event box.
|
||||
*
|
||||
* This function simply draws a transparency onto a widget on the area
|
||||
* for which it receives expose events. This is intended to give the
|
||||
* event box a "transparent" background.
|
||||
*
|
||||
* In order for this to work properly, the widget must have an RGBA
|
||||
* colourmap. The widget should also be set as app-paintable since it
|
||||
* doesn't make sense for GTK+ to draw a background if we are drawing it
|
||||
* (and because GTK+ might actually replace our transparency with its
|
||||
* default background colour).
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/* The expose event handler for the window.
|
||||
*
|
||||
* This function performs the actual compositing of the event box onto
|
||||
* the already-existing background of the window at 50% normal opacity.
|
||||
*
|
||||
* In this case we do not want app-paintable to be set on the widget
|
||||
* since we want it to draw its own (red) background. Because of this,
|
||||
* however, we must ensure that we use g_signal_register_after so that
|
||||
* this handler is called after the red has been drawn. If it was
|
||||
* called before then GTK would just blindly paint over our work.
|
||||
*
|
||||
* Note: if the child window has children, then you need a cairo 1.16
|
||||
* feature to make this work correctly.
|
||||
*/
|
||||
static gboolean
|
||||
window_expose_event (GtkWidget *widget,
|
||||
GdkEventExpose *event)
|
||||
{
|
||||
GdkRegion *region;
|
||||
GtkWidget *child;
|
||||
cairo_t *cr;
|
||||
|
||||
/* get our child (in this case, 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);
|
||||
|
||||
/* the source data is the (composited) event box */
|
||||
gdk_cairo_set_source_pixmap (cr, child->window,
|
||||
child->allocation.x,
|
||||
child->allocation.y);
|
||||
|
||||
/* draw no more than our expose event intersects our child */
|
||||
region = gdk_region_rectangle (&child->allocation);
|
||||
gdk_region_intersect (region, event->region);
|
||||
gdk_cairo_region (cr, region);
|
||||
cairo_clip (cr);
|
||||
|
||||
/* composite, with a 50% opacity */
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_paint_with_alpha (cr, 0.5);
|
||||
|
||||
/* we're done */
|
||||
cairo_destroy (cr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GtkWidget *window, *event, *button;
|
||||
GdkScreen *screen;
|
||||
GdkColormap *rgba;
|
||||
GdkColor red;
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
/* Make the widgets */
|
||||
button = gtk_button_new_with_label ("A Button");
|
||||
event = gtk_event_box_new ();
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
|
||||
/* Put a red background on the window */
|
||||
gdk_color_parse ("red", &red);
|
||||
gtk_widget_modify_bg (window, GTK_STATE_NORMAL, &red);
|
||||
|
||||
/* Set the colourmap for the event box.
|
||||
* Must be done before the event box is realised.
|
||||
*/
|
||||
screen = gtk_widget_get_screen (event);
|
||||
rgba = gdk_screen_get_rgba_colormap (screen);
|
||||
gtk_widget_set_colormap (event, rgba);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Put them inside one another */
|
||||
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
|
||||
gtk_container_add (GTK_CONTAINER (window), event);
|
||||
gtk_container_add (GTK_CONTAINER (event), button);
|
||||
|
||||
/* Realise and show everything */
|
||||
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);
|
||||
|
||||
/* Set up the compositing handler.
|
||||
* Note that we do _after_ so that the normal (red) background is drawn
|
||||
* by gtk before our compositing occurs.
|
||||
*/
|
||||
g_signal_connect_after (window, "expose-event",
|
||||
G_CALLBACK (window_expose_event), NULL);
|
||||
|
||||
gtk_main (<!-- -->);
|
||||
|
||||
return 0;
|
||||
}
|
||||
]]>
|
||||
</programlisting></example>
|
||||
<para>
|
||||
In the example <xref linkend="composited-window-example"/>, a button is
|
||||
placed inside of an event box inside of a window. The event box is
|
||||
set as composited and therefore is no longer automatically drawn to
|
||||
the screen.
|
||||
</para>
|
||||
<para>
|
||||
When the contents of the event box change, an expose event is
|
||||
generated on its parent window (which, in this case, belongs to
|
||||
the toplevel #GtkWindow). The expose handler for this widget is
|
||||
responsible for merging the changes back on the screen in the way
|
||||
that it wishes.
|
||||
</para>
|
||||
<para>
|
||||
In our case, we merge the contents with a 50% transparency. We
|
||||
also set the background colour of the window to red. The effect is
|
||||
that the background shows through the button.
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION See_Also ##### -->
|
||||
<para>
|
||||
@ -465,6 +623,15 @@ Deprecated equivalent of g_object_unref()
|
||||
@opacity:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gdk_window_set_composited ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@window:
|
||||
@composited:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gdk_window_move ##### -->
|
||||
<para>
|
||||
|
||||
|
@ -511,6 +511,13 @@ gdk_notify_startup_complete_with_id (const gchar* startup_id)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
gdk_display_supports_composite (GdkDisplay *display)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#define __GDK_DISPLAY_X11_C__
|
||||
#include "gdkaliasdef.c"
|
||||
|
||||
|
@ -3038,6 +3038,14 @@ gdk_window_set_opacity (GdkWindow *window,
|
||||
cardinal = opacity * 0xff;
|
||||
gdk_directfb_window_set_opacity(window,cardinal);
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_windowing_window_set_composited (GdkWindow *window,
|
||||
gboolean composited)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#define __GDK_WINDOW_X11_C__
|
||||
#include "gdkaliasdef.c"
|
||||
|
||||
|
@ -466,6 +466,7 @@ gdk_display_supports_clipboard_persistence
|
||||
gdk_display_supports_selection_notification
|
||||
gdk_display_supports_shapes
|
||||
gdk_display_supports_input_shapes
|
||||
gdk_display_supports_composite
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -673,6 +674,7 @@ gdk_window_remove_filter
|
||||
gdk_window_set_debug_updates
|
||||
gdk_window_set_user_data
|
||||
gdk_window_thaw_updates
|
||||
gdk_window_set_composited
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -181,6 +181,7 @@ void gdk_display_store_clipboard (GdkDisplay *display,
|
||||
|
||||
gboolean gdk_display_supports_shapes (GdkDisplay *display);
|
||||
gboolean gdk_display_supports_input_shapes (GdkDisplay *display);
|
||||
gboolean gdk_display_supports_composite (GdkDisplay *display);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -337,6 +337,9 @@ void _gdk_windowing_window_destroy_foreign (GdkWindow *window);
|
||||
void _gdk_windowing_display_set_sm_client_id (GdkDisplay *display,
|
||||
const gchar *sm_client_id);
|
||||
|
||||
void _gdk_windowing_window_set_composited (GdkWindow *window,
|
||||
gboolean composited);
|
||||
|
||||
#define GDK_TYPE_PAINTABLE (_gdk_paintable_get_type ())
|
||||
#define GDK_PAINTABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_PAINTABLE, GdkPaintable))
|
||||
#define GDK_IS_PAINTABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_PAINTABLE))
|
||||
|
@ -1042,6 +1042,7 @@ gdk_window_end_paint (GdkWindow *window)
|
||||
{
|
||||
#ifdef USE_BACKING_STORE
|
||||
GdkWindowObject *private = (GdkWindowObject *)window;
|
||||
GdkWindowObject *composited;
|
||||
GdkWindowPaint *paint;
|
||||
GdkGC *tmp_gc;
|
||||
GdkRectangle clip_box;
|
||||
@ -1094,6 +1095,34 @@ gdk_window_end_paint (GdkWindow *window)
|
||||
g_object_unref (paint->pixmap);
|
||||
gdk_region_destroy (paint->region);
|
||||
g_free (paint);
|
||||
|
||||
/* find a composited window in our hierarchy to signal its
|
||||
* parent to redraw, calculating the clip box as we go...
|
||||
*
|
||||
* stop if parent becomes NULL since then we'd have nowhere
|
||||
* to draw (ie: 'composited' will always be non-NULL here).
|
||||
*/
|
||||
for (composited = private;
|
||||
composited->parent;
|
||||
composited = composited->parent)
|
||||
{
|
||||
int width, height;
|
||||
|
||||
gdk_drawable_get_size (GDK_DRAWABLE (composited->parent),
|
||||
&width, &height);
|
||||
|
||||
clip_box.x += composited->x;
|
||||
clip_box.y += composited->y;
|
||||
clip_box.width = MIN (clip_box.width, width - clip_box.x);
|
||||
clip_box.height = MIN (clip_box.height, height - clip_box.y);
|
||||
|
||||
if (composited->composited)
|
||||
{
|
||||
gdk_window_invalidate_rect (GDK_WINDOW (composited->parent),
|
||||
&clip_box, FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* USE_BACKING_STORE */
|
||||
}
|
||||
|
||||
@ -2601,7 +2630,8 @@ gdk_window_invalidate_maybe_recurse (GdkWindow *window,
|
||||
child_region = gdk_region_rectangle (&child_rect);
|
||||
|
||||
/* remove child area from the invalid area of the parent */
|
||||
if (GDK_WINDOW_IS_MAPPED (child) && !child->shaped)
|
||||
if (GDK_WINDOW_IS_MAPPED (child) && !child->shaped &&
|
||||
!child->composited)
|
||||
gdk_region_subtract (visible_region, child_region);
|
||||
|
||||
if (child_func && (*child_func) ((GdkWindow *)child, user_data))
|
||||
@ -3056,5 +3086,64 @@ gdk_window_foreign_new (GdkNativeWindow anid)
|
||||
return gdk_window_foreign_new_for_display (gdk_display_get_default (), anid);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_window_set_composited:
|
||||
* @window: a #GdkWindow
|
||||
*
|
||||
* Sets a #GdkWindow as composited. Composited windows do
|
||||
* not automatically have their contents drawn to the screen.
|
||||
* Drawing is redirected to an offscreen buffer and an expose
|
||||
* event is emitted on the parent of the composited window.
|
||||
* It is the responsibility of the parent's expose handler to
|
||||
* manually merge the off-screen content onto the screen in
|
||||
* whatever way it sees fit. See <xref linkend="composited-window-example"/>
|
||||
* for an example.
|
||||
*
|
||||
* It only makes sense for child windows to be composited; see
|
||||
* gdk_window_set_opacity() if you need translucent toplevel
|
||||
* windows.
|
||||
*
|
||||
* An additional effect of this call is that the area of this
|
||||
* window is no longer clipped from regions marked for
|
||||
* invalidation on its parent. Draws done on the parent
|
||||
* window are also no longer clipped by the child.
|
||||
*
|
||||
* This call is only supported on some systems (currently,
|
||||
* only X11 with new enough Xcomposite and Xdamage extensions).
|
||||
* You must call gdk_display_supports_composite() to check if
|
||||
* setting a window as composited is supported before
|
||||
* attempting to do so.
|
||||
*
|
||||
* Since: 2.12
|
||||
*/
|
||||
void
|
||||
gdk_window_set_composited (GdkWindow *window,
|
||||
gboolean composited)
|
||||
{
|
||||
GdkWindowObject *private = (GdkWindowObject *)window;
|
||||
GdkDisplay *display;
|
||||
|
||||
g_return_if_fail (window != NULL);
|
||||
g_return_if_fail (GDK_IS_WINDOW (window));
|
||||
|
||||
composited = composited != FALSE;
|
||||
|
||||
if (private->composited == composited)
|
||||
return;
|
||||
|
||||
display = gdk_drawable_get_display (GDK_DRAWABLE (window));
|
||||
|
||||
if (!gdk_display_supports_composite (display) && composited)
|
||||
{
|
||||
g_warning ("gdk_window_set_composited called but "
|
||||
"compositing is not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
_gdk_windowing_window_set_composited (window, composited);
|
||||
|
||||
private->composited = composited;
|
||||
}
|
||||
|
||||
#define __GDK_WINDOW_C__
|
||||
#include "gdkaliasdef.c"
|
||||
|
@ -289,6 +289,7 @@ struct _GdkWindowObject
|
||||
guint guffaw_gravity : 1;
|
||||
guint input_only : 1;
|
||||
guint modal_hint : 1;
|
||||
guint composited : 1;
|
||||
|
||||
guint destroyed : 2;
|
||||
|
||||
@ -394,6 +395,9 @@ void gdk_window_shape_combine_region (GdkWindow *window,
|
||||
*/
|
||||
void gdk_window_set_child_shapes (GdkWindow *window);
|
||||
|
||||
void gdk_window_set_composited (GdkWindow *window,
|
||||
gboolean composited);
|
||||
|
||||
/*
|
||||
* This routine allows you to merge (ie ADD) child shapes to your
|
||||
* own window's shape keeping its current shape and ADDING the child
|
||||
|
@ -169,3 +169,11 @@ gdk_display_store_clipboard (GdkDisplay *display,
|
||||
{
|
||||
/* FIXME: Implement */
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
gdk_display_supports_composite (GdkDisplay *display)
|
||||
{
|
||||
/* FIXME: Implement */
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -2155,3 +2155,8 @@ gdk_window_set_opacity (GdkWindow *window,
|
||||
|
||||
[impl->toplevel setAlphaValue: opacity];
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_windowing_window_set_composited (GdkWindow *window, gboolean composited)
|
||||
{
|
||||
}
|
||||
|
@ -389,3 +389,9 @@ gdk_display_supports_input_shapes (GdkDisplay *display)
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_display_supports_composite (GdkDisplay *display)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -3571,3 +3571,8 @@ gdk_window_set_opacity (GdkWindow *window,
|
||||
opacity * 0xff,
|
||||
LWA_ALPHA));
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_windowing_window_set_composited (GdkWindow *window, gboolean composited)
|
||||
{
|
||||
}
|
||||
|
@ -54,6 +54,14 @@
|
||||
#include <X11/extensions/shape.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_XCOMPOSITE
|
||||
#include <X11/extensions/Xcomposite.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_XDAMAGE
|
||||
#include <X11/extensions/Xdamage.h>
|
||||
#endif
|
||||
|
||||
|
||||
static void gdk_display_x11_dispose (GObject *object);
|
||||
static void gdk_display_x11_finalize (GObject *object);
|
||||
@ -206,6 +214,29 @@ gdk_display_open (const gchar *display_name)
|
||||
#endif
|
||||
display_x11->have_xfixes = FALSE;
|
||||
|
||||
#ifdef HAVE_XCOMPOSITE
|
||||
if (XCompositeQueryExtension (display_x11->xdisplay,
|
||||
&ignore, &ignore))
|
||||
display_x11->have_xcomposite = TRUE;
|
||||
else
|
||||
#endif
|
||||
display_x11->have_xcomposite = FALSE;
|
||||
|
||||
#ifdef HAVE_XDAMAGE
|
||||
if (XDamageQueryExtension (display_x11->xdisplay,
|
||||
&display_x11->xdamage_event_base,
|
||||
&ignore))
|
||||
{
|
||||
display_x11->have_xdamage = TRUE;
|
||||
|
||||
gdk_x11_register_standard_event_type (display,
|
||||
display_x11->xdamage_event_base,
|
||||
XDamageNumberEvents);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
display_x11->have_xdamage = FALSE;
|
||||
|
||||
display_x11->have_shapes = FALSE;
|
||||
display_x11->have_input_shapes = FALSE;
|
||||
#ifdef HAVE_SHAPE_EXT
|
||||
@ -1363,5 +1394,30 @@ gdk_x11_display_get_startup_notification_id (GdkDisplay *display)
|
||||
return GDK_DISPLAY_X11 (display)->startup_notification_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_display_supports_composite:
|
||||
* @display: a #GdkDisplay
|
||||
*
|
||||
* Returns %TRUE if gdk_window_set_composited() can be used
|
||||
* to redirect drawing on the window using compositing.
|
||||
*
|
||||
* Currently this only works on X11 with XComposite and
|
||||
* XDamage extensions available.
|
||||
*
|
||||
* Returns: %TRUE if windows may be composited.
|
||||
*
|
||||
* Since: 2.12
|
||||
*/
|
||||
gboolean
|
||||
gdk_display_supports_composite (GdkDisplay *display)
|
||||
{
|
||||
GdkDisplayX11 *x11_display = GDK_DISPLAY_X11 (display);
|
||||
|
||||
return x11_display->have_xcomposite &&
|
||||
x11_display->have_xdamage &&
|
||||
x11_display->have_xfixes;
|
||||
}
|
||||
|
||||
|
||||
#define __GDK_DISPLAY_X11_C__
|
||||
#include "gdkaliasdef.c"
|
||||
|
@ -81,6 +81,10 @@ struct _GdkDisplayX11
|
||||
gboolean have_xfixes;
|
||||
gint xfixes_event_base;
|
||||
|
||||
gboolean have_xcomposite;
|
||||
gboolean have_xdamage;
|
||||
gint xdamage_event_base;
|
||||
|
||||
/* If the SECURITY extension is in place, whether this client holds
|
||||
* a trusted authorization and so is allowed to make various requests
|
||||
* (grabs, properties etc.) Otherwise always TRUE. */
|
||||
|
@ -2101,6 +2101,34 @@ gdk_event_translate (GdkDisplay *display,
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#if defined(HAVE_XCOMPOSITE) && defined (HAVE_XDAMAGE) && defined (HAVE_XFIXES)
|
||||
if (display_x11->have_xdamage && window_private->composited &&
|
||||
xevent->type == display_x11->xdamage_event_base + XDamageNotify)
|
||||
{
|
||||
XDamageNotifyEvent *damage_event = (XDamageNotifyEvent *) xevent;
|
||||
XserverRegion repair;
|
||||
GdkRectangle rect;
|
||||
|
||||
rect.x = window_private->x + damage_event->area.x;
|
||||
rect.y = window_private->y + damage_event->area.y;
|
||||
rect.width = damage_event->area.width;
|
||||
rect.height = damage_event->area.height;
|
||||
|
||||
repair = XFixesCreateRegion (display_x11->xdisplay,
|
||||
&damage_event->area, 1);
|
||||
XDamageSubtract (display_x11->xdisplay,
|
||||
window_impl->damage,
|
||||
repair, None);
|
||||
XFixesDestroyRegion (display_x11->xdisplay, repair);
|
||||
|
||||
if (window_private->parent != NULL)
|
||||
_gdk_window_process_expose (GDK_WINDOW (window_private->parent),
|
||||
damage_event->serial, &rect);
|
||||
|
||||
return_val = TRUE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* something else - (e.g., a Xinput event) */
|
||||
|
||||
|
@ -59,6 +59,18 @@
|
||||
#include <X11/extensions/shape.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_XCOMPOSITE
|
||||
#include <X11/extensions/Xcomposite.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_XFIXES
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_XDAMAGE
|
||||
#include <X11/extensions/Xdamage.h>
|
||||
#endif
|
||||
|
||||
const int _gdk_event_mask_table[21] =
|
||||
{
|
||||
ExposureMask,
|
||||
@ -185,6 +197,14 @@ gdk_window_impl_x11_finalize (GObject *object)
|
||||
|
||||
_gdk_xgrab_check_destroy (GDK_WINDOW (wrapper));
|
||||
|
||||
#if defined(HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES)
|
||||
if (window_impl->damage != None)
|
||||
{
|
||||
XDamageDestroy (GDK_WINDOW_XDISPLAY (object), window_impl->damage);
|
||||
window_impl->damage = None;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!GDK_WINDOW_DESTROYED (wrapper))
|
||||
{
|
||||
GdkDisplay *display = GDK_WINDOW_DISPLAY (wrapper);
|
||||
@ -6413,10 +6433,14 @@ gdk_window_beep (GdkWindow *window)
|
||||
*
|
||||
* Request the windowing system to make @window partially transparent,
|
||||
* with opacity 0 being fully transparent and 1 fully opaque. (Values
|
||||
* of the opacity parameter are clamped to the [0,1] range.) On X11
|
||||
* this works only on X screens with a compositing manager running.
|
||||
* of the opacity parameter are clamped to the [0,1] range.)
|
||||
*
|
||||
* On X11, this works only on X screens with a compositing manager
|
||||
* running.
|
||||
*
|
||||
* For setting up per-pixel alpha, see gdk_screen_get_rgba_colormap().
|
||||
* For making non-toplevel windows translucent, see
|
||||
* gdk_window_set_composited().
|
||||
*
|
||||
* Since: 2.12
|
||||
*/
|
||||
@ -6455,5 +6479,39 @@ gdk_window_set_opacity (GdkWindow *window,
|
||||
(guchar *) cardinal, 1);
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_windowing_window_set_composited (GdkWindow *window,
|
||||
gboolean composited)
|
||||
{
|
||||
#if defined(HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES)
|
||||
GdkWindowObject *private = (GdkWindowObject *) window;
|
||||
GdkDisplayX11 *x11_display;
|
||||
GdkWindowImplX11 *impl;
|
||||
GdkDisplay *display;
|
||||
Display *dpy;
|
||||
Window xid;
|
||||
|
||||
impl = GDK_WINDOW_IMPL_X11 (private->impl);
|
||||
|
||||
display = gdk_screen_get_display (GDK_DRAWABLE_IMPL_X11 (impl)->screen);
|
||||
x11_display = GDK_DISPLAY_X11 (display);
|
||||
dpy = GDK_DISPLAY_XDISPLAY (display);
|
||||
xid = GDK_WINDOW_XWINDOW (private);
|
||||
|
||||
if (composited)
|
||||
{
|
||||
XCompositeRedirectWindow (dpy, xid, CompositeRedirectManual);
|
||||
impl->damage = XDamageCreate (dpy, xid, XDamageReportBoundingBox);
|
||||
}
|
||||
else
|
||||
{
|
||||
XCompositeUnredirectWindow (dpy, xid, CompositeRedirectManual);
|
||||
XDamageDestroy (dpy, impl->damage);
|
||||
impl->damage = None;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#define __GDK_WINDOW_X11_C__
|
||||
#include "gdkaliasdef.c"
|
||||
|
@ -29,6 +29,10 @@
|
||||
|
||||
#include <gdk/x11/gdkdrawable-x11.h>
|
||||
|
||||
#ifdef HAVE_XDAMAGE
|
||||
#include <X11/extensions/Xdamage.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_XSYNC
|
||||
#include <X11/extensions/sync.h>
|
||||
#endif
|
||||
@ -79,6 +83,10 @@ struct _GdkWindowImplX11
|
||||
gint8 toplevel_window_type;
|
||||
guint override_redirect : 1;
|
||||
guint use_synchronized_configure : 1;
|
||||
|
||||
#if defined (HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES)
|
||||
Damage damage;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct _GdkWindowImplX11Class
|
||||
|
141
tests/testgtk.c
141
tests/testgtk.c
@ -420,6 +420,146 @@ create_alpha_window (GtkWidget *widget)
|
||||
gtk_widget_destroy (window);
|
||||
}
|
||||
|
||||
/*
|
||||
* Composited non-toplevel window
|
||||
*/
|
||||
|
||||
/* The expose event handler for the event box.
|
||||
*
|
||||
* This function simply draws a transparency onto a widget on the area
|
||||
* for which it receives expose events. This is intended to give the
|
||||
* event box a "transparent" background.
|
||||
*
|
||||
* In order for this to work properly, the widget must have an RGBA
|
||||
* colourmap. The widget should also be set as app-paintable since it
|
||||
* doesn't make sense for GTK to draw a background if we are drawing it
|
||||
* (and because GTK might actually replace our transparency with its
|
||||
* default background colour).
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/* The expose event handler for the window.
|
||||
*
|
||||
* This function performs the actual compositing of the event box onto
|
||||
* the already-existing background of the window at 50% normal opacity.
|
||||
*
|
||||
* In this case we do not want app-paintable to be set on the widget
|
||||
* since we want it to draw its own (red) background. Because of this,
|
||||
* however, we must ensure that we use g_signal_register_after so that
|
||||
* this handler is called after the red has been drawn. If it was
|
||||
* called before then GTK would just blindly paint over our work.
|
||||
*/
|
||||
static gboolean
|
||||
window_expose_event (GtkWidget *widget,
|
||||
GdkEventExpose *event)
|
||||
{
|
||||
GdkRegion *region;
|
||||
GtkWidget *child;
|
||||
cairo_t *cr;
|
||||
|
||||
/* get our child (in this case, 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);
|
||||
|
||||
/* the source data is the (composited) event box */
|
||||
gdk_cairo_set_source_pixmap (cr, child->window,
|
||||
child->allocation.x,
|
||||
child->allocation.y);
|
||||
|
||||
/* draw no more than our expose event intersects our child */
|
||||
region = gdk_region_rectangle (&child->allocation);
|
||||
gdk_region_intersect (region, event->region);
|
||||
gdk_cairo_region (cr, region);
|
||||
cairo_clip (cr);
|
||||
|
||||
/* composite, with a 50% opacity */
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_paint_with_alpha (cr, 0.5);
|
||||
|
||||
/* we're done */
|
||||
cairo_destroy (cr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
create_composited_window (GtkWidget *widget)
|
||||
{
|
||||
static GtkWidget *window;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *event, *button;
|
||||
GdkScreen *screen;
|
||||
GdkColormap *rgba;
|
||||
GdkColor red;
|
||||
|
||||
/* make the widgets */
|
||||
button = gtk_button_new_with_label ("A Button");
|
||||
event = gtk_event_box_new ();
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
|
||||
/* put a red background on the window */
|
||||
gdk_color_parse ("red", &red);
|
||||
gtk_widget_modify_bg (window, GTK_STATE_NORMAL, &red);
|
||||
|
||||
/* set the colourmap for the event box.
|
||||
* must be done before the event box is realised.
|
||||
*/
|
||||
screen = gtk_widget_get_screen (event);
|
||||
rgba = gdk_screen_get_rgba_colormap (screen);
|
||||
gtk_widget_set_colormap (event, rgba);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* put them inside one another */
|
||||
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
|
||||
gtk_container_add (GTK_CONTAINER (window), event);
|
||||
gtk_container_add (GTK_CONTAINER (event), button);
|
||||
|
||||
/* realise and show everything */
|
||||
gtk_widget_realize (button);
|
||||
|
||||
/* set the event box GdkWindow to be composited.
|
||||
* obviously must be performed after event box is realised.
|
||||
*/
|
||||
gdk_window_set_composited (event->window, TRUE);
|
||||
|
||||
/* set up the compositing handler.
|
||||
* note that we do _after so that the normal (red) background is drawn
|
||||
* by gtk before our compositing occurs.
|
||||
*/
|
||||
g_signal_connect_after (window, "expose-event",
|
||||
G_CALLBACK (window_expose_event), NULL);
|
||||
}
|
||||
|
||||
if (!GTK_WIDGET_VISIBLE (window))
|
||||
gtk_widget_show_all (window);
|
||||
else
|
||||
gtk_widget_destroy (window);
|
||||
}
|
||||
|
||||
/*
|
||||
* Big windows and guffaw scrolling
|
||||
*/
|
||||
@ -13290,6 +13430,7 @@ struct {
|
||||
{ "check buttons", create_check_buttons },
|
||||
{ "clist", create_clist},
|
||||
{ "color selection", create_color_selection },
|
||||
{ "composited window", create_composited_window },
|
||||
{ "ctree", create_ctree },
|
||||
{ "cursors", create_cursors },
|
||||
{ "dialog", create_dialog, TRUE },
|
||||
|
Loading…
Reference in New Issue
Block a user