Compare commits

...

8 Commits

Author SHA1 Message Date
Emmanuele Bassi
3611fc9ab4 gdk: Deprecate gdk_cairo_create()
We have GdkDrawingContext, now, which is in charge of creating Cairo
contexts for drawing on a GdkWindow.

https://bugzilla.gnome.org/show_bug.cgi?id=766675
2016-06-08 14:40:08 +01:00
Emmanuele Bassi
59bf3a08ed gdk: Explicitly create a cairo context inside GdkDrawingContext
Instead of using gdk_cairo_create(), which we'll soon deprecate.

https://bugzilla.gnome.org/show_bug.cgi?id=766675
2016-06-08 14:40:08 +01:00
Emmanuele Bassi
b1b0a25164 Deprecate the gdk_window_begin/end_paint family of functions
They are replaced by the more appropriate gdk_window_begin_draw_frame()
and gdk_window_end_draw_frame() functions.

https://bugzilla.gnome.org/show_bug.cgi?id=766675
2016-06-08 14:40:08 +01:00
Emmanuele Bassi
bfb4fe771c Associate the drawing context to the Cairo context
Instead of associating the GdkWindow that created the GdkDrawingContext
we can directly bind the Cairo context to the GDK drawing context.

Cairo contexts created via gdk_cairo_create() go back to not having a
GdkWindow associated to them, like they did before we introduced the
gdk_window_begin_draw_frame() API.

https://bugzilla.gnome.org/show_bug.cgi?id=766675
2016-06-08 14:40:08 +01:00
Emmanuele Bassi
af6f9773ec docs: Add GdkDrawingContext to the GDK API reference
https://bugzilla.gnome.org/show_bug.cgi?id=766675
2016-06-08 14:40:08 +01:00
Emmanuele Bassi
7510615893 Add GdkDrawingContext
Instead of giving out Cairo contexts, GdkWindow should provide a
"drawing context", which can then create Cairo contexts on demand; this
allows us to future proof the API for when we're going to use a
different rendering pipeline, like OpenGL.

https://bugzilla.gnome.org/show_bug.cgi?id=766675
2016-06-08 14:40:08 +01:00
Emmanuele Bassi
45d33f2e3a Simplify the widget rendering entry point
Now that GDK has the appropriate API, we can simplify the widget drawing
code into a single function.

https://bugzilla.gnome.org/show_bug.cgi?id=766675
2016-06-08 14:40:08 +01:00
Emmanuele Bassi
f0fa8e780b Add frame drawing API to GdkWindow
Existing code drawing on a GDK window has to handle the direct drawing
and the buffered drawing by itself, by checking the window type and
whether or not the window is backed by a native windowing surface. After
that, the calling code has to create a Cairo context from the window and
keep an association between the context and the window itself.

This is completely unnecessary: GDK can determine whether or not it
should use a backing store to draw on a GdkWindow as well as create a
Cairo context, and keep track of it.

This allows to simplify the calling code, and enforce some of the
drawing behavior we want to guarantee to users.

https://bugzilla.gnome.org/show_bug.cgi?id=766675
2016-06-08 14:40:08 +01:00
18 changed files with 904 additions and 244 deletions

View File

@@ -33,6 +33,7 @@
<xi:include href="xml/windows.xml" />
<xi:include href="xml/gdkframeclock.xml" />
<xi:include href="xml/gdkframetimings.xml" />
<xi:include href="xml/gdkdrawingcontext.xml" />
<xi:include href="xml/gdkglcontext.xml" />
<xi:include href="xml/events.xml" />
<xi:include href="xml/event_structs.xml" />

View File

@@ -412,6 +412,9 @@ gdk_window_get_clip_region
gdk_window_begin_paint_rect
gdk_window_begin_paint_region
gdk_window_end_paint
gdk_window_begin_draw_frame
gdk_window_end_draw_fram
gdk_window_should_draw
gdk_window_get_visible_region
GdkWindowInvalidateHandlerFunc
gdk_window_set_invalidate_handler
@@ -622,6 +625,7 @@ gdk_window_create_similar_surface
gdk_window_create_similar_image_surface
gdk_cairo_create
gdk_cairo_get_clip_rectangle
gdk_cairo_get_drawing_context
gdk_cairo_set_source_color
gdk_cairo_set_source_rgba
gdk_cairo_set_source_pixbuf
@@ -1409,3 +1413,19 @@ GDK_TYPE_MONITOR
GDK_MONITOR
GDK_IS_MONITOR
</SECTION>
<SECTION>
<FILE>gdkdrawingcontext</FILE>
GdkDrawingContext
gdk_drawing_context_get_window
gdk_drawing_context_get_clip
gdk_drawing_context_get_cairo_context
gdk_drawing_context_is_valid
<SUBSECTION Standard>
gdk_drawing_context_get_type
GdkDrawingContextClass
GDK_TYPE_DRAWING_CONTEXT
GDK_DRAWING_CONTEXT
GDK_IS_DRAWING_CONTEXT
</SECTION>

View File

@@ -7,6 +7,7 @@ gdk_device_manager_get_type
gdk_display_get_type
gdk_display_manager_get_type
gdk_drag_context_get_type
gdk_drawing_context_get_type
gdk_frame_clock_get_type
gdk_gl_context_get_type
gdk_keymap_get_type

View File

@@ -75,6 +75,7 @@ gdk_public_h_sources = \
gdkdisplay.h \
gdkdisplaymanager.h \
gdkdnd.h \
gdkdrawingcontext.h \
gdkevents.h \
gdkframetimings.h \
gdkglcontext.h \
@@ -116,6 +117,7 @@ gdk_private_headers = \
gdkdisplaymanagerprivate.h \
gdkdisplayprivate.h \
gdkdndprivate.h \
gdkdrawingcontextprivate.h \
gdkframeclockidle.h \
gdkframeclockprivate.h \
gdkglcontextprivate.h \
@@ -146,6 +148,7 @@ gdk_c_sources = \
gdkdisplay.c \
gdkdisplaymanager.c \
gdkdnd.c \
gdkdrawingcontext.c \
gdkevents.c \
gdkframetimings.c \
gdkgl.c \

View File

@@ -38,6 +38,7 @@
#include <gdk/gdkdisplay.h>
#include <gdk/gdkdisplaymanager.h>
#include <gdk/gdkdnd.h>
#include <gdk/gdkdrawingcontext.h>
#include <gdk/gdkenumtypes.h>
#include <gdk/gdkevents.h>
#include <gdk/gdkframeclock.h>

View File

@@ -25,13 +25,15 @@
#include <gdk/gdkversionmacros.h>
#include <gdk/deprecated/gdkcolor.h>
#include <gdk/gdkrgba.h>
#include <gdk/gdkdrawingcontext.h>
#include <gdk/gdkpixbuf.h>
#include <pango/pangocairo.h>
G_BEGIN_DECLS
GDK_AVAILABLE_IN_ALL
GDK_DEPRECATED_IN_3_22_FOR(gdk_window_begin_draw_frame() and gdk_drawing_context_get_cairo_context())
cairo_t * gdk_cairo_create (GdkWindow *window);
GDK_AVAILABLE_IN_ALL
gboolean gdk_cairo_get_clip_rectangle (cairo_t *cr,
GdkRectangle *rect);
@@ -81,6 +83,8 @@ void gdk_cairo_draw_from_gl (cairo_t *cr,
int width,
int height);
GDK_AVAILABLE_IN_3_22
GdkDrawingContext * gdk_cairo_get_drawing_context (cairo_t *cr);
G_END_DECLS

315
gdk/gdkdrawingcontext.c Normal file
View File

@@ -0,0 +1,315 @@
/* GDK - The GIMP Drawing Kit
* Copyright 2016 Endless
*
* This library 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 of the License, or (at your option) any later version.
*
* This library 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 library. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* SECTION:gdkdrawingcontext
* @Title: GdkDrawingContext
* @Short_description: Drawing context for GDK windows
*
* #GdkDrawingContext is an object that represents the current drawing
* state of a #GdkWindow.
*
* It's possible to use a #GdkDrawingContext to draw on a #GdkWindow
* via rendering API like Cairo or OpenGL.
*
* A #GdkDrawingContext can only be created by calling gdk_window_begin_draw_frame()
* and will be valid until a call to gdk_window_end_draw_frame().
*
* #GdkDrawingContext is available since GDK 3.22
*/
#include "config.h"
#include <cairo-gobject.h>
#include "gdkdrawingcontextprivate.h"
#include "gdkrectangle.h"
#include "gdkinternals.h"
#include "gdkintl.h"
#include "gdkframeclockidle.h"
#include "gdkwindowimpl.h"
#include "gdkglcontextprivate.h"
#include "gdk-private.h"
G_DEFINE_TYPE (GdkDrawingContext, gdk_drawing_context, G_TYPE_OBJECT)
enum {
PROP_0,
PROP_WINDOW,
PROP_CLIP,
N_PROPS
};
static GParamSpec *obj_property[N_PROPS];
static void
gdk_drawing_context_dispose (GObject *gobject)
{
GdkDrawingContext *self = GDK_DRAWING_CONTEXT (gobject);
g_clear_object (&self->window);
g_clear_pointer (&self->clip, cairo_region_destroy);
g_clear_pointer (&self->cr, cairo_destroy);
G_OBJECT_CLASS (gdk_drawing_context_parent_class)->dispose (gobject);
}
static void
gdk_drawing_context_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdkDrawingContext *self = GDK_DRAWING_CONTEXT (gobject);
switch (prop_id)
{
case PROP_WINDOW:
self->window = g_value_dup_object (value);
break;
case PROP_CLIP:
self->clip = g_value_dup_boxed (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
}
}
static void
gdk_drawing_context_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdkDrawingContext *self = GDK_DRAWING_CONTEXT (gobject);
switch (prop_id)
{
case PROP_WINDOW:
g_value_set_object (value, self->window);
break;
case PROP_CLIP:
g_value_set_boxed (value, self->clip);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
}
}
static void
gdk_drawing_context_constructed (GObject *gobject)
{
GdkDrawingContext *self = GDK_DRAWING_CONTEXT (gobject);
if (self->window == NULL)
{
g_critical ("The drawing context of type %s does not have a window "
"associated to it. Drawing contexts can only be created "
"using gdk_window_begin_draw_frame().",
G_OBJECT_TYPE_NAME (gobject));
}
G_OBJECT_CLASS (gdk_drawing_context_parent_class)->constructed (gobject);
}
static void
gdk_drawing_context_class_init (GdkDrawingContextClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->constructed = gdk_drawing_context_constructed;
gobject_class->set_property = gdk_drawing_context_set_property;
gobject_class->get_property = gdk_drawing_context_get_property;
gobject_class->dispose = gdk_drawing_context_dispose;
/**
* GdkDrawingContext:window:
*
* The #GdkWindow that created the drawing context.
*
* Since: 3.22
*/
obj_property[PROP_WINDOW] =
g_param_spec_object ("window", "Window", "The window that created the context",
GDK_TYPE_WINDOW,
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
/**
* GdkDrawingContext:clip:
*
* The clip region applied to the drawing context.
*
* Since: 3.22
*/
obj_property[PROP_CLIP] =
g_param_spec_boxed ("clip", "Clip", "The clip region of the context",
CAIRO_GOBJECT_TYPE_REGION,
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, obj_property);
}
static void
gdk_drawing_context_init (GdkDrawingContext *self)
{
}
static const cairo_user_data_key_t draw_context_key;
static void
gdk_cairo_set_drawing_context (cairo_t *cr,
GdkDrawingContext *context)
{
cairo_set_user_data (cr, &draw_context_key, context, NULL);
}
/**
* gdk_cairo_get_drawing_context:
* @cr: a Cairo context
*
* Retrieves the #GdkDrawingContext that created the Cairo
* context @cr.
*
* Returns: (transfer none) (nullable): a #GdkDrawingContext, if any is set
*
* Since: 3.22
*/
GdkDrawingContext *
gdk_cairo_get_drawing_context (cairo_t *cr)
{
g_return_val_if_fail (cr != NULL, NULL);
return cairo_get_user_data (cr, &draw_context_key);
}
/**
* gdk_drawing_context_get_cairo_context:
* @context:
*
* Retrieves a Cairo context to be used to draw on the #GdkWindow
* that created the #GdkDrawingContext.
*
* The returned context is guaranteed to be valid as long as the
* #GdkDrawingContext is valid, that is between a call to
* gdk_window_begin_draw_frame() and gdk_window_end_draw_frame().
*
* Returns: (transfer none): a Cairo context to be used to draw
* the contents of the #GdkWindow. The context is owned by the
* #GdkDrawingContext and should not be destroyed
*
* Since: 3.22
*/
cairo_t *
gdk_drawing_context_get_cairo_context (GdkDrawingContext *context)
{
g_return_val_if_fail (GDK_IS_DRAWING_CONTEXT (context), NULL);
g_return_val_if_fail (GDK_IS_WINDOW (context->window), NULL);
if (context->cr == NULL)
{
cairo_region_t *region;
cairo_surface_t *surface;
surface = _gdk_window_ref_cairo_surface (context->window);
context->cr = cairo_create (surface);
gdk_cairo_set_drawing_context (context->cr, context);
region = gdk_window_get_current_paint_region (context->window);
cairo_region_union (region, context->clip);
gdk_cairo_region (context->cr, region);
cairo_clip (context->cr);
cairo_region_destroy (region);
cairo_surface_destroy (surface);
}
return context->cr;
}
/**
* gdk_drawing_context_get_window:
* @context: a #GdkDrawingContext
*
* Retrieves the window that created the drawing @context.
*
* Returns: (transfer none): a #GdkWindow
*
* Since: 3.22
*/
GdkWindow *
gdk_drawing_context_get_window (GdkDrawingContext *context)
{
g_return_val_if_fail (GDK_IS_DRAWING_CONTEXT (context), NULL);
return context->window;
}
/**
* gdk_drawing_context_get_clip:
* @context: a #GdkDrawingContext
*
* Retrieves a copy of the clip region used when creating the @context.
*
* Returns: (transfer full) (nullable): a Cairo region
*
* Since: 3.22
*/
cairo_region_t *
gdk_drawing_context_get_clip (GdkDrawingContext *context)
{
g_return_val_if_fail (GDK_IS_DRAWING_CONTEXT (context), NULL);
if (context->clip == NULL)
return NULL;
return cairo_region_copy (context->clip);
}
/**
* gdk_drawing_context_is_valid:
* @context: a #GdkDrawingContext
*
* Checks whether the given #GdkDrawingContext is valid.
*
* Returns: %TRUE if the context is valid
*
* Since: 3.22
*/
gboolean
gdk_drawing_context_is_valid (GdkDrawingContext *context)
{
g_return_val_if_fail (GDK_IS_DRAWING_CONTEXT (context), FALSE);
if (context->window == NULL)
return FALSE;
if (gdk_window_get_drawing_context (context->window) != context)
return FALSE;
return TRUE;
}

53
gdk/gdkdrawingcontext.h Normal file
View File

@@ -0,0 +1,53 @@
/* GDK - The GIMP Drawing Kit
*
* This library 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 of the License, or (at your option) any later version.
*
* This library 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 library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_DRAWING_CONTEXT_H__
#define __GDK_DRAWING_CONTEXT_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
#include <gdk/gdkversionmacros.h>
#include <gdk/gdktypes.h>
G_BEGIN_DECLS
#define GDK_TYPE_DRAWING_CONTEXT (gdk_drawing_context_get_type ())
#define GDK_DRAWING_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_DRAWING_CONTEXT, GdkDrawingContext))
#define GDK_IS_DRAWING_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_DRAWING_CONTEXT))
typedef struct _GdkDrawingContext GdkDrawingContext;
typedef struct _GdkDrawingContextClass GdkDrawingContextClass;
GDK_AVAILABLE_IN_3_22
GType gdk_drawing_context_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_22
GdkWindow * gdk_drawing_context_get_window (GdkDrawingContext *context);
GDK_AVAILABLE_IN_3_22
cairo_region_t *gdk_drawing_context_get_clip (GdkDrawingContext *context);
GDK_AVAILABLE_IN_3_22
gboolean gdk_drawing_context_is_valid (GdkDrawingContext *context);
GDK_AVAILABLE_IN_3_22
cairo_t * gdk_drawing_context_get_cairo_context (GdkDrawingContext *context);
G_END_DECLS
#endif /* __GDK_DRAWING_CONTEXT_H__ */

View File

@@ -0,0 +1,29 @@
#ifndef __GDK_DRAWING_CONTEXT_PRIVATE_H__
#define __GDK_DRAWING_CONTEXT_PRIVATE_H__
#include "gdkdrawingcontext.h"
G_BEGIN_DECLS
#define GDK_DRAWING_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_DRAWING_CONTEXT, GdkDrawingContextClass))
#define GDK_IS_DRAWING_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_DRAWING_CONTEXT))
#define GDK_DRAWING_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_DRAWING_CONTEXT, GdkDrawingContextClass))
struct _GdkDrawingContext
{
GObject parent_instance;
GdkWindow *window;
cairo_region_t *clip;
cairo_t *cr;
};
struct _GdkDrawingContextClass
{
GObjectClass parent_instance;
};
G_END_DECLS
#endif /* __GDK_DRAWING_CONTEXT_PRIVATE_H__ */

View File

@@ -379,6 +379,8 @@ struct _GdkWindow
GdkFrameClock *frame_clock; /* NULL to use from parent or default */
GdkWindowInvalidateHandlerFunc invalidate_handler;
GdkDrawingContext *drawing_context;
};
#define GDK_WINDOW_TYPE(d) ((((GdkWindow *)(d)))->window_type)
@@ -468,6 +470,10 @@ void gdk_window_get_unscaled_size (GdkWindow *window,
int *unscaled_width,
int *unscaled_height);
GdkDrawingContext *gdk_window_get_drawing_context (GdkWindow *window);
cairo_region_t *gdk_window_get_current_paint_region (GdkWindow *window);
void _gdk_window_process_updates_recurse (GdkWindow *window,
cairo_region_t *expose_region);

View File

@@ -40,6 +40,7 @@
#include "gdkframeclockidle.h"
#include "gdkwindowimpl.h"
#include "gdkglcontextprivate.h"
#include "gdkdrawingcontextprivate.h"
#include "gdk-private.h"
#include <math.h>
@@ -2841,77 +2842,9 @@ gdk_window_create_gl_context (GdkWindow *window,
error);
}
/**
* gdk_window_begin_paint_rect:
* @window: a #GdkWindow
* @rectangle: rectangle you intend to draw to
*
* A convenience wrapper around gdk_window_begin_paint_region() which
* creates a rectangular region for you. See
* gdk_window_begin_paint_region() for details.
*
**/
void
gdk_window_begin_paint_rect (GdkWindow *window,
const GdkRectangle *rectangle)
{
cairo_region_t *region;
g_return_if_fail (GDK_IS_WINDOW (window));
region = cairo_region_create_rectangle (rectangle);
gdk_window_begin_paint_region (window, region);
cairo_region_destroy (region);
}
/**
* gdk_window_begin_paint_region:
* @window: a #GdkWindow
* @region: region you intend to draw to
*
* Indicates that you are beginning the process of redrawing @region.
* A backing store (offscreen buffer) large enough to contain @region
* will be created. The backing store will be initialized with the
* background color or background surface for @window. Then, all
* drawing operations performed on @window will be diverted to the
* backing store. When you call gdk_window_end_paint(), the backing
* store will be copied to @window, making it visible onscreen. Only
* the part of @window contained in @region will be modified; that is,
* drawing operations are clipped to @region.
*
* The net result of all this is to remove flicker, because the user
* sees the finished product appear all at once when you call
* gdk_window_end_paint(). If you draw to @window directly without
* calling gdk_window_begin_paint_region(), the user may see flicker
* as individual drawing operations are performed in sequence. The
* clipping and background-initializing features of
* gdk_window_begin_paint_region() are conveniences for the
* programmer, so you can avoid doing that work yourself.
*
* When using GTK+, the widget system automatically places calls to
* gdk_window_begin_paint_region() and gdk_window_end_paint() around
* emissions of the expose_event signal. That is, if youre writing an
* expose event handler, you can assume that the exposed area in
* #GdkEventExpose has already been cleared to the window background,
* is already set as the clip region, and already has a backing store.
* Therefore in most cases, application code need not call
* gdk_window_begin_paint_region(). (You can disable the automatic
* calls around expose events on a widget-by-widget basis by calling
* gtk_widget_set_double_buffered().)
*
* If you call this function multiple times before calling the
* matching gdk_window_end_paint(), the backing stores are pushed onto
* a stack. gdk_window_end_paint() copies the topmost backing store
* onscreen, subtracts the topmost region from all other regions in
* the stack, and pops the stack. All drawing operations affect only
* the topmost backing store in the stack. One matching call to
* gdk_window_end_paint() is required for each call to
* gdk_window_begin_paint_region().
*
**/
void
gdk_window_begin_paint_region (GdkWindow *window,
const cairo_region_t *region)
static void
gdk_window_begin_paint_internal (GdkWindow *window,
const cairo_region_t *region)
{
GdkRectangle clip_box;
GdkWindowImplClass *impl_class;
@@ -2919,16 +2852,14 @@ gdk_window_begin_paint_region (GdkWindow *window,
gboolean needs_surface;
cairo_content_t surface_content;
g_return_if_fail (GDK_IS_WINDOW (window));
if (GDK_WINDOW_DESTROYED (window) ||
!gdk_window_has_impl (window))
return;
if (window->current_paint.surface != NULL)
{
g_warning ("gdk_window_begin_paint_region called while a paint was "
"alredy in progress. This is not allowed.");
g_warning ("A paint operation on the window is alredy in progress. "
"This is not allowed.");
return;
}
@@ -3004,106 +2935,21 @@ gdk_window_begin_paint_region (GdkWindow *window,
gdk_window_clear_backing_region (window);
}
/**
* gdk_window_mark_paint_from_clip:
* @window: a #GdkWindow
* @cr: a #cairo_t
*
* If you call this during a paint (e.g. between gdk_window_begin_paint_region()
* and gdk_window_end_paint() then GDK will mark the current clip region of the
* window as being drawn. This is required when mixing GL rendering via
* gdk_cairo_draw_from_gl() and cairo rendering, as otherwise GDK has no way
* of knowing when something paints over the GL-drawn regions.
*
* This is typically called automatically by GTK+ and you don't need
* to care about this.
*
* Since: 3.16
**/
void
gdk_window_mark_paint_from_clip (GdkWindow *window,
cairo_t *cr)
{
cairo_region_t *clip_region;
GdkWindow *impl_window = window->impl_window;
if (impl_window->current_paint.surface == NULL ||
cairo_get_target (cr) != impl_window->current_paint.surface)
return;
if (cairo_region_is_empty (impl_window->current_paint.flushed_region))
return;
/* This here seems a bit weird, but basically, we're taking the current
clip and applying also the flushed region, and the result is that the
new clip is the intersection of these. This is the area where the newly
drawn region overlaps a previosly flushed area, which is an area of the
double buffer surface that need to be blended OVER the back buffer rather
than SRCed. */
cairo_save (cr);
/* We set the identity matrix here so we get and apply regions in native
window coordinates. */
cairo_identity_matrix (cr);
gdk_cairo_region (cr, impl_window->current_paint.flushed_region);
cairo_clip (cr);
clip_region = gdk_cairo_region_from_clip (cr);
if (clip_region == NULL)
{
/* Failed to represent clip as region, mark all as requiring
blend */
cairo_region_union (impl_window->current_paint.need_blend_region,
impl_window->current_paint.flushed_region);
cairo_region_destroy (impl_window->current_paint.flushed_region);
impl_window->current_paint.flushed_region = cairo_region_create ();
}
else
{
cairo_region_subtract (impl_window->current_paint.flushed_region, clip_region);
cairo_region_union (impl_window->current_paint.need_blend_region, clip_region);
}
cairo_region_destroy (clip_region);
/* Clear the area on the double buffer surface to transparent so we
can start drawing from scratch the area "above" the flushed
region */
cairo_set_source_rgba (cr, 0, 0, 0, 0);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
cairo_restore (cr);
}
/**
* gdk_window_end_paint:
* @window: a #GdkWindow
*
* Indicates that the backing store created by the most recent call
* to gdk_window_begin_paint_region() should be copied onscreen and
* deleted, leaving the next-most-recent backing store or no backing
* store at all as the active paint region. See
* gdk_window_begin_paint_region() for full details.
*
* It is an error to call this function without a matching
* gdk_window_begin_paint_region() first.
**/
void
gdk_window_end_paint (GdkWindow *window)
static void
gdk_window_end_paint_internal (GdkWindow *window)
{
GdkWindow *composited;
GdkWindowImplClass *impl_class;
GdkRectangle clip_box = { 0, };
cairo_t *cr;
g_return_if_fail (GDK_IS_WINDOW (window));
if (GDK_WINDOW_DESTROYED (window) ||
!gdk_window_has_impl (window))
return;
if (window->current_paint.surface == NULL)
{
g_warning (G_STRLOC": no preceding call to gdk_window_begin_paint_region(), see documentation");
g_warning (G_STRLOC": no preceding call to gdk_window_begin_draw_frame(), see documentation");
return;
}
@@ -3188,6 +3034,344 @@ gdk_window_end_paint (GdkWindow *window)
}
}
/**
* gdk_window_begin_paint_rect:
* @window: a #GdkWindow
* @rectangle: rectangle you intend to draw to
*
* A convenience wrapper around gdk_window_begin_paint_region() which
* creates a rectangular region for you. See
* gdk_window_begin_paint_region() for details.
*
* Deprecated: 3.22: Use gdk_window_begin_draw_frame() instead
*/
void
gdk_window_begin_paint_rect (GdkWindow *window,
const GdkRectangle *rectangle)
{
cairo_region_t *region;
g_return_if_fail (GDK_IS_WINDOW (window));
region = cairo_region_create_rectangle (rectangle);
gdk_window_begin_paint_internal (window, region);
cairo_region_destroy (region);
}
/**
* gdk_window_begin_paint_region:
* @window: a #GdkWindow
* @region: region you intend to draw to
*
* Indicates that you are beginning the process of redrawing @region.
* A backing store (offscreen buffer) large enough to contain @region
* will be created. The backing store will be initialized with the
* background color or background surface for @window. Then, all
* drawing operations performed on @window will be diverted to the
* backing store. When you call gdk_window_end_paint(), the backing
* store will be copied to @window, making it visible onscreen. Only
* the part of @window contained in @region will be modified; that is,
* drawing operations are clipped to @region.
*
* The net result of all this is to remove flicker, because the user
* sees the finished product appear all at once when you call
* gdk_window_end_paint(). If you draw to @window directly without
* calling gdk_window_begin_paint_region(), the user may see flicker
* as individual drawing operations are performed in sequence. The
* clipping and background-initializing features of
* gdk_window_begin_paint_region() are conveniences for the
* programmer, so you can avoid doing that work yourself.
*
* When using GTK+, the widget system automatically places calls to
* gdk_window_begin_paint_region() and gdk_window_end_paint() around
* emissions of the expose_event signal. That is, if youre writing an
* expose event handler, you can assume that the exposed area in
* #GdkEventExpose has already been cleared to the window background,
* is already set as the clip region, and already has a backing store.
* Therefore in most cases, application code need not call
* gdk_window_begin_paint_region(). (You can disable the automatic
* calls around expose events on a widget-by-widget basis by calling
* gtk_widget_set_double_buffered().)
*
* If you call this function multiple times before calling the
* matching gdk_window_end_paint(), the backing stores are pushed onto
* a stack. gdk_window_end_paint() copies the topmost backing store
* onscreen, subtracts the topmost region from all other regions in
* the stack, and pops the stack. All drawing operations affect only
* the topmost backing store in the stack. One matching call to
* gdk_window_end_paint() is required for each call to
* gdk_window_begin_paint_region().
*
* Deprecated: 3.22: Use gdk_window_begin_draw_frame() instead
*/
void
gdk_window_begin_paint_region (GdkWindow *window,
const cairo_region_t *region)
{
g_return_if_fail (GDK_IS_WINDOW (window));
gdk_window_begin_paint_internal (window, region);
}
/**
* gdk_window_begin_draw_frame:
* @window: a #GdkWindow
* @region: a Cairo region
*
* Indicates that you are beginning the process of redrawing @region
* on @window, and provides you with a #GdkDrawingContext.
*
* If @window is a top level #GdkWindow, backed by a native window
* implementation, a backing store (offscreen buffer) large enough to
* contain @region will be created. The backing store will be initialized
* with the background color or background surface for @window. Then, all
* drawing operations performed on @window will be diverted to the
* backing store. When you call gdk_window_end_frame(), the contents of
* the backing store will be copied to @window, making it visible
* on screen. Only the part of @window contained in @region will be
* modified; that is, drawing operations are clipped to @region.
*
* The net result of all this is to remove flicker, because the user
* sees the finished product appear all at once when you call
* gdk_window_end_draw_frame(). If you draw to @window directly without
* calling gdk_window_begin_draw_frame(), the user may see flicker
* as individual drawing operations are performed in sequence.
*
* When using GTK+, the widget system automatically places calls to
* gdk_window_begin_draw_frame() and gdk_window_end_draw_frame() around
* emissions of the `GtkWidget::draw` signal. That is, if youre
* drawing the contents of the widget yourself, you can assume that the
* widget has a cleared background, is already set as the clip region,
* and already has a backing store. Therefore in most cases, application
* code in GTK does not need to call gdk_window_begin_draw_frame()
* explicitly.
*
* Returns: (transfer none): a #GdkDrawingContext context that should be
* used to draw the contents of the window; the returned context is owned
* by GDK.
*
* Since: 3.22
*/
GdkDrawingContext *
gdk_window_begin_draw_frame (GdkWindow *window,
const cairo_region_t *region)
{
GdkDrawingContext *context;
GdkWindowImplClass *impl_class;
g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
if (window->drawing_context != NULL)
{
g_critical ("The window %p already has a drawing context. You cannot "
"call gdk_window_begin_draw_frame() without calling "
"gdk_window_end_draw_frame() first.", window);
return NULL;
}
if (gdk_window_has_native (window) && gdk_window_is_toplevel (window))
gdk_window_begin_paint_internal (window, region);
impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
if (impl_class->create_draw_context != NULL)
{
context = impl_class->create_draw_context (window, region);
}
else
{
context = g_object_new (GDK_TYPE_DRAWING_CONTEXT,
"window", window,
"clip", region,
NULL);
}
/* Do not take a reference, to avoid creating cycles */
window->drawing_context = context;
return context;
}
/**
* gdk_window_end_draw_frame:
* @window: a #GdkWindow
* @context: the #GdkDrawingContext created by gdk_window_begin_draw_frame()
*
* Indicates that the drawing of the contents of @window started with
* gdk_window_begin_frame() has been completed.
*
* This function will take care of destroying the #GdkDrawingContext.
*
* It is an error to call this function without a matching
* gdk_window_begin_frame() first.
*
* Since: 3.22
*/
void
gdk_window_end_draw_frame (GdkWindow *window,
GdkDrawingContext *context)
{
GdkWindowImplClass *impl_class;
g_return_if_fail (GDK_IS_WINDOW (window));
g_return_if_fail (GDK_IS_DRAWING_CONTEXT (context));
if (window->drawing_context == NULL)
{
g_critical ("The window %p has no drawing context. You must call "
"gdk_window_begin_draw_frame() before calling "
"gdk_window_end_draw_frame().", window);
return;
}
if (gdk_window_has_native (window) && gdk_window_is_toplevel (window))
gdk_window_end_paint_internal (window);
impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
if (impl_class->destroy_draw_context != NULL)
impl_class->destroy_draw_context (window, context);
else
g_object_unref (context);
window->drawing_context = NULL;
}
/*< private >
* gdk_window_get_current_paint_region:
* @window: a #GdkWindow
*
* Retrieves a copy of the current paint region.
*
* Returns: (transfer full): a Cairo region
*/
cairo_region_t *
gdk_window_get_current_paint_region (GdkWindow *window)
{
cairo_region_t *region;
if (window->impl_window->current_paint.region != NULL)
{
region = cairo_region_copy (window->impl_window->current_paint.region);
cairo_region_translate (region, -window->abs_x, -window->abs_y);
}
else
{
region = cairo_region_copy (window->clip_region);
}
return region;
}
/*< private >
* gdk_window_get_drawing_context:
* @window: a #GdkWindow
*
* Retrieves the #GdkDrawingContext associated to @window by
* gdk_window_begin_draw_frame().
*
* Returns: (transfer none) (nullable): a #GdkDrawingContext, if any is set
*/
GdkDrawingContext *
gdk_window_get_drawing_context (GdkWindow *window)
{
g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
if (GDK_WINDOW_DESTROYED (window))
return NULL;
return window->drawing_context;
}
/**
* gdk_window_mark_paint_from_clip:
* @window: a #GdkWindow
* @cr: a #cairo_t
*
* If you call this during a paint (e.g. between gdk_window_begin_paint_region()
* and gdk_window_end_paint() then GDK will mark the current clip region of the
* window as being drawn. This is required when mixing GL rendering via
* gdk_cairo_draw_from_gl() and cairo rendering, as otherwise GDK has no way
* of knowing when something paints over the GL-drawn regions.
*
* This is typically called automatically by GTK+ and you don't need
* to care about this.
*
* Since: 3.16
**/
void
gdk_window_mark_paint_from_clip (GdkWindow *window,
cairo_t *cr)
{
cairo_region_t *clip_region;
GdkWindow *impl_window = window->impl_window;
if (impl_window->current_paint.surface == NULL ||
cairo_get_target (cr) != impl_window->current_paint.surface)
return;
if (cairo_region_is_empty (impl_window->current_paint.flushed_region))
return;
/* This here seems a bit weird, but basically, we're taking the current
clip and applying also the flushed region, and the result is that the
new clip is the intersection of these. This is the area where the newly
drawn region overlaps a previosly flushed area, which is an area of the
double buffer surface that need to be blended OVER the back buffer rather
than SRCed. */
cairo_save (cr);
/* We set the identity matrix here so we get and apply regions in native
window coordinates. */
cairo_identity_matrix (cr);
gdk_cairo_region (cr, impl_window->current_paint.flushed_region);
cairo_clip (cr);
clip_region = gdk_cairo_region_from_clip (cr);
if (clip_region == NULL)
{
/* Failed to represent clip as region, mark all as requiring
blend */
cairo_region_union (impl_window->current_paint.need_blend_region,
impl_window->current_paint.flushed_region);
cairo_region_destroy (impl_window->current_paint.flushed_region);
impl_window->current_paint.flushed_region = cairo_region_create ();
}
else
{
cairo_region_subtract (impl_window->current_paint.flushed_region, clip_region);
cairo_region_union (impl_window->current_paint.need_blend_region, clip_region);
}
cairo_region_destroy (clip_region);
/* Clear the area on the double buffer surface to transparent so we
can start drawing from scratch the area "above" the flushed
region */
cairo_set_source_rgba (cr, 0, 0, 0, 0);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
cairo_restore (cr);
}
/**
* gdk_window_end_paint:
* @window: a #GdkWindow
*
* Indicates that the backing store created by the most recent call
* to gdk_window_begin_paint_region() should be copied onscreen and
* deleted, leaving the next-most-recent backing store or no backing
* store at all as the active paint region. See
* gdk_window_begin_paint_region() for full details.
*
* It is an error to call this function without a matching
* gdk_window_begin_paint_region() first.
**/
void
gdk_window_end_paint (GdkWindow *window)
{
g_return_if_fail (GDK_IS_WINDOW (window));
gdk_window_end_paint_internal (window);
}
/**
* gdk_window_flush:
* @window: a #GdkWindow
@@ -3340,10 +3524,21 @@ _gdk_window_ref_cairo_surface (GdkWindow *window)
* Note that calling cairo_reset_clip() on the resulting #cairo_t will
* produce undefined results, so avoid it at all costs.
*
* Typically, this function is used to draw on a #GdkWindow out of the paint
* cycle of the toolkit; this should be avoided, as it breaks various assumptions
* and optimizations.
*
* If you are drawing a native #GdkWindow in response to a %GDK_EXPOSE event
* you should use gdk_window_begin_draw_frame() and gdk_drawing_context_get_cairo_context()
* instead. GTK will automatically do this for you when drawing a widget.
*
* Returns: A newly created Cairo context. Free with
* cairo_destroy() when you are done drawing.
*
* Since: 2.8
*
* Deprecated: 3.22: Use gdk_window_begin_draw_frame() and
* gdk_drawing_context_get_cairo_context() instead
**/
cairo_t *
gdk_cairo_create (GdkWindow *window)

View File

@@ -31,6 +31,7 @@
#include <gdk/gdkversionmacros.h>
#include <gdk/gdktypes.h>
#include <gdk/gdkdrawingcontext.h>
#include <gdk/gdkevents.h>
#include <gdk/gdkframeclock.h>
@@ -693,17 +694,25 @@ GDK_AVAILABLE_IN_ALL
cairo_region_t *gdk_window_get_visible_region(GdkWindow *window);
GDK_AVAILABLE_IN_ALL
GDK_DEPRECATED_IN_3_22_FOR(gdk_window_begin_draw_frame)
void gdk_window_begin_paint_rect (GdkWindow *window,
const GdkRectangle *rectangle);
GDK_AVAILABLE_IN_3_16
void gdk_window_mark_paint_from_clip (GdkWindow *window,
cairo_t *cr);
GDK_AVAILABLE_IN_ALL
GDK_DEPRECATED_IN_3_22_FOR(gdk_window_begin_draw_frame)
void gdk_window_begin_paint_region (GdkWindow *window,
const cairo_region_t *region);
GDK_AVAILABLE_IN_ALL
GDK_DEPRECATED_IN_3_22_FOR(gdk_window_end_draw_frame)
void gdk_window_end_paint (GdkWindow *window);
GDK_AVAILABLE_IN_3_22
GdkDrawingContext *gdk_window_begin_draw_frame (GdkWindow *window,
const cairo_region_t *region);
GDK_AVAILABLE_IN_3_22
void gdk_window_end_draw_frame (GdkWindow *window,
GdkDrawingContext *context);
GDK_DEPRECATED_IN_3_14
void gdk_window_flush (GdkWindow *window);

View File

@@ -303,6 +303,11 @@ struct _GdkWindowImplClass
GError **error);
void (*invalidate_for_new_frame)(GdkWindow *window,
cairo_region_t *update_area);
GdkDrawingContext *(* create_draw_context) (GdkWindow *window,
const cairo_region_t *region);
void (* destroy_draw_context) (GdkWindow *window,
GdkDrawingContext *context);
};
/* Interface Functions */

View File

@@ -1804,32 +1804,7 @@ gtk_main_do_event (GdkEvent *event)
case GDK_EXPOSE:
if (event->any.window)
{
gboolean is_double_buffered;
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
is_double_buffered = gtk_widget_get_double_buffered (event_widget);
G_GNUC_END_IGNORE_DEPRECATIONS;
if (is_double_buffered)
{
/* We handle exposes only on native windows, relying on the
* draw() handler to propagate down to non-native windows.
* This is ok now that child windows are always considered
* (semi)transparent.
*/
if (gdk_window_has_native (event->expose.window))
{
gdk_window_begin_paint_region (event->any.window, event->expose.region);
gtk_widget_send_expose (event_widget, event);
gdk_window_end_paint (event->any.window);
}
}
else
{
gtk_widget_send_expose (event_widget, event);
}
}
gtk_widget_render (event_widget, event->any.window, event->expose.region);
break;
case GDK_PROPERTY_NOTIFY:

View File

@@ -6883,21 +6883,22 @@ gtk_widget_real_mnemonic_activate (GtkWidget *widget,
return TRUE;
}
static const cairo_user_data_key_t event_window_key;
static const cairo_user_data_key_t mark_for_draw_key;
static GdkWindow *
gtk_cairo_get_event_window (cairo_t *cr)
static gboolean
gtk_cairo_is_marked_for_draw (cairo_t *cr)
{
g_return_val_if_fail (cr != NULL, NULL);
return cairo_get_user_data (cr, &event_window_key);
return cairo_get_user_data (cr, &mark_for_draw_key) != NULL;
}
static void
gtk_cairo_set_event_window (cairo_t *cr,
GdkWindow *event_window)
gtk_cairo_set_marked_for_draw (cairo_t *cr,
gboolean marked)
{
cairo_set_user_data (cr, &event_window_key, event_window, NULL);
if (marked)
cairo_set_user_data (cr, &mark_for_draw_key, GINT_TO_POINTER (1), NULL);
else
cairo_set_user_data (cr, &mark_for_draw_key, NULL, NULL);
}
/**
@@ -6919,25 +6920,32 @@ gtk_cairo_set_event_window (cairo_t *cr,
* Returns: %TRUE if @window should be drawn
*
* Since: 3.0
**/
*/
gboolean
gtk_cairo_should_draw_window (cairo_t *cr,
gtk_cairo_should_draw_window (cairo_t *cr,
GdkWindow *window)
{
GdkWindow *event_window;
GdkDrawingContext *context;
GdkWindow *tmp;
g_return_val_if_fail (cr != NULL, FALSE);
g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
event_window = gtk_cairo_get_event_window (cr);
if (gtk_cairo_is_marked_for_draw (cr))
return TRUE;
if (event_window == NULL)
context = gdk_cairo_get_drawing_context (cr);
if (context == NULL)
return TRUE;
tmp = gdk_drawing_context_get_window (context);
if (tmp == NULL)
return TRUE;
while (!gdk_window_has_native (window))
window = gdk_window_get_parent (window);
return event_window == window;
return tmp == window;
}
void
@@ -6960,13 +6968,26 @@ gtk_widget_draw_internal (GtkWidget *widget,
if (gdk_cairo_get_clip_rectangle (cr, NULL))
{
GdkWindow *event_window;
GdkWindow *event_window = NULL;
gboolean result;
gboolean push_group;
event_window = gtk_cairo_get_event_window (cr);
if (event_window)
gdk_window_mark_paint_from_clip (event_window, cr);
/* If this was a cairo_t passed via gtk_widget_draw() then we don't
* require a window; otherwise we check for the window associated
* to the drawing context and mark it using the clip region of the
* Cairo context.
*/
if (!gtk_cairo_is_marked_for_draw (cr))
{
GdkDrawingContext *context = gdk_cairo_get_drawing_context (cr);
if (context != NULL)
{
event_window = gdk_drawing_context_get_window (context);
if (event_window != NULL)
gdk_window_mark_paint_from_clip (event_window, cr);
}
}
push_group =
widget->priv->alpha != 255 &&
@@ -7077,7 +7098,7 @@ void
gtk_widget_draw (GtkWidget *widget,
cairo_t *cr)
{
GdkWindow *tmp_event_window;
gboolean was_marked;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (!widget->priv->alloc_needed);
@@ -7086,17 +7107,18 @@ gtk_widget_draw (GtkWidget *widget,
cairo_save (cr);
/* We have to reset the event here so that draw functions can call
* gtk_widget_draw() on random other widgets and get the desired
* effect: Drawing all contents, not just the current window.
was_marked = gtk_cairo_is_marked_for_draw (cr);
/* We mark the window so that gtk_cairo_should_draw_window()
* will always return TRUE, and all GdkWindows get drawn
*/
tmp_event_window = gtk_cairo_get_event_window (cr);
gtk_cairo_set_event_window (cr, NULL);
gtk_cairo_set_marked_for_draw (cr, TRUE);
gtk_widget_draw_internal (widget, cr, TRUE);
gtk_cairo_set_marked_for_draw (cr, was_marked);
cairo_restore (cr);
gtk_cairo_set_event_window (cr, tmp_event_window);
}
static gboolean
@@ -7506,32 +7528,12 @@ gint
gtk_widget_send_expose (GtkWidget *widget,
GdkEvent *event)
{
cairo_t *cr;
int x, y;
gboolean do_clip;
g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE);
g_return_val_if_fail (gtk_widget_get_realized (widget), TRUE);
g_return_val_if_fail (event != NULL, TRUE);
g_return_val_if_fail (event->type == GDK_EXPOSE, TRUE);
cr = gdk_cairo_create (event->expose.window);
gtk_cairo_set_event_window (cr, event->expose.window);
gdk_cairo_region (cr, event->expose.region);
cairo_clip (cr);
do_clip = _gtk_widget_get_translation_to_window (widget,
event->expose.window,
&x, &y);
cairo_translate (cr, -x, -y);
gtk_widget_draw_internal (widget, cr, do_clip);
/* unset here, so if someone keeps a reference to cr we
* don't leak the window. */
gtk_cairo_set_event_window (cr, NULL);
cairo_destroy (cr);
gtk_widget_render (widget, event->any.window, event->expose.region);
return FALSE;
}
@@ -9292,10 +9294,10 @@ gtk_widget_get_app_paintable (GtkWidget *widget)
*
* Widgets are double buffered by default; you can use this function
* to turn off the buffering. “Double buffered” simply means that
* gdk_window_begin_paint_region() and gdk_window_end_paint() are called
* gdk_window_begin_draw_frame() and gdk_window_end_draw_frame() are called
* automatically around expose events sent to the
* widget. gdk_window_begin_paint_region() diverts all drawing to a widget's
* window to an offscreen buffer, and gdk_window_end_paint() draws the
* widget. gdk_window_begin_draw_frame() diverts all drawing to a widget's
* window to an offscreen buffer, and gdk_window_end_draw_frame() draws the
* buffer to the screen. The result is that users see the window
* update in one smooth step, and dont see individual graphics
* primitives being rendered.
@@ -9307,7 +9309,7 @@ gtk_widget_get_app_paintable (GtkWidget *widget)
* Note: if you turn off double-buffering, you have to handle
* expose events, since even the clearing to the background color or
* pixmap will not happen automatically (as it is done in
* gdk_window_begin_paint_region()).
* gdk_window_begin_draw_frame()).
*
* In 3.10 GTK and GDK have been restructured for translucent drawing. Since
* then expose events for double-buffered widgets are culled into a single
@@ -17439,3 +17441,32 @@ gtk_widget_reset_controllers (GtkWidget *widget)
gtk_event_controller_reset (controller_data->controller);
}
}
void
gtk_widget_render (GtkWidget *widget,
GdkWindow *window,
const cairo_region_t *region)
{
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
GdkDrawingContext *context;
gboolean do_clip;
cairo_t *cr;
int x, y;
if (priv->double_buffered)
{
/* We only render double buffered on native windows */
if (!gdk_window_has_native (window))
return;
}
context = gdk_window_begin_draw_frame (window, region);
cr = gdk_drawing_context_get_cairo_context (context);
do_clip = _gtk_widget_get_translation_to_window (widget, window, &x, &y);
cairo_translate (cr, -x, -y);
gtk_widget_draw_internal (widget, cr, do_clip);
gdk_window_end_draw_frame (window, context);
}

View File

@@ -302,6 +302,11 @@ gboolean gtk_widget_query_tooltip (GtkWidget *widget,
gboolean keyboard_mode,
GtkTooltip *tooltip);
void gtk_widget_render (GtkWidget *widget,
GdkWindow *window,
const cairo_region_t *region);
/* inline getters */
static inline gboolean

View File

@@ -423,7 +423,9 @@ preview_got_page_size (GtkPrintOperationPreview *preview,
w = gtk_paper_size_get_width (paper_size, GTK_UNIT_INCH);
h = gtk_paper_size_get_height (paper_size, GTK_UNIT_INCH);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
cr = gdk_cairo_create (gtk_widget_get_window (pop->area));
G_GNUC_END_IGNORE_DEPRECATIONS
gtk_widget_get_allocation (pop->area, &allocation);
dpi_x = allocation.width/w;
@@ -500,7 +502,10 @@ preview_cb (GtkPrintOperation *op,
gtk_widget_realize (da);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
cr = gdk_cairo_create (gtk_widget_get_window (da));
G_GNUC_END_IGNORE_DEPRECATIONS
/* TODO: What dpi to use here? This will be used for pagination.. */
gtk_print_context_set_cairo_context (context, cr, 72, 72);
cairo_destroy (cr);

View File

@@ -52,7 +52,9 @@ update_cursor (GtkWidget *widget, gdouble x, gdouble y)
if (surface != NULL)
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (widget));
G_GNUC_END_IGNORE_DEPRECATIONS
if (cursor_present && (cursor_present != state ||
x != cursor_x || y != cursor_y))