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
This commit is contained in:
@ -412,6 +412,9 @@ gdk_window_get_clip_region
|
|||||||
gdk_window_begin_paint_rect
|
gdk_window_begin_paint_rect
|
||||||
gdk_window_begin_paint_region
|
gdk_window_begin_paint_region
|
||||||
gdk_window_end_paint
|
gdk_window_end_paint
|
||||||
|
gdk_window_begin_draw_frame
|
||||||
|
gdk_window_end_draw_fram
|
||||||
|
gdk_window_should_draw
|
||||||
gdk_window_get_visible_region
|
gdk_window_get_visible_region
|
||||||
GdkWindowInvalidateHandlerFunc
|
GdkWindowInvalidateHandlerFunc
|
||||||
gdk_window_set_invalidate_handler
|
gdk_window_set_invalidate_handler
|
||||||
@ -622,6 +625,7 @@ gdk_window_create_similar_surface
|
|||||||
gdk_window_create_similar_image_surface
|
gdk_window_create_similar_image_surface
|
||||||
gdk_cairo_create
|
gdk_cairo_create
|
||||||
gdk_cairo_get_clip_rectangle
|
gdk_cairo_get_clip_rectangle
|
||||||
|
gdk_cairo_get_window
|
||||||
gdk_cairo_set_source_color
|
gdk_cairo_set_source_color
|
||||||
gdk_cairo_set_source_rgba
|
gdk_cairo_set_source_rgba
|
||||||
gdk_cairo_set_source_pixbuf
|
gdk_cairo_set_source_pixbuf
|
||||||
|
|||||||
@ -32,6 +32,8 @@ G_BEGIN_DECLS
|
|||||||
|
|
||||||
GDK_AVAILABLE_IN_ALL
|
GDK_AVAILABLE_IN_ALL
|
||||||
cairo_t * gdk_cairo_create (GdkWindow *window);
|
cairo_t * gdk_cairo_create (GdkWindow *window);
|
||||||
|
GDK_AVAILABLE_IN_3_22
|
||||||
|
GdkWindow * gdk_cairo_get_window (cairo_t *cr);
|
||||||
GDK_AVAILABLE_IN_ALL
|
GDK_AVAILABLE_IN_ALL
|
||||||
gboolean gdk_cairo_get_clip_rectangle (cairo_t *cr,
|
gboolean gdk_cairo_get_clip_rectangle (cairo_t *cr,
|
||||||
GdkRectangle *rect);
|
GdkRectangle *rect);
|
||||||
|
|||||||
448
gdk/gdkwindow.c
448
gdk/gdkwindow.c
@ -2841,76 +2841,8 @@ gdk_window_create_gl_context (GdkWindow *window,
|
|||||||
error);
|
error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void
|
||||||
* gdk_window_begin_paint_rect:
|
gdk_window_begin_paint_internal (GdkWindow *window,
|
||||||
* @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 you’re 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)
|
const cairo_region_t *region)
|
||||||
{
|
{
|
||||||
GdkRectangle clip_box;
|
GdkRectangle clip_box;
|
||||||
@ -2919,16 +2851,14 @@ gdk_window_begin_paint_region (GdkWindow *window,
|
|||||||
gboolean needs_surface;
|
gboolean needs_surface;
|
||||||
cairo_content_t surface_content;
|
cairo_content_t surface_content;
|
||||||
|
|
||||||
g_return_if_fail (GDK_IS_WINDOW (window));
|
|
||||||
|
|
||||||
if (GDK_WINDOW_DESTROYED (window) ||
|
if (GDK_WINDOW_DESTROYED (window) ||
|
||||||
!gdk_window_has_impl (window))
|
!gdk_window_has_impl (window))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (window->current_paint.surface != NULL)
|
if (window->current_paint.surface != NULL)
|
||||||
{
|
{
|
||||||
g_warning ("gdk_window_begin_paint_region called while a paint was "
|
g_warning ("A paint operation on the window is alredy in progress. "
|
||||||
"alredy in progress. This is not allowed.");
|
"This is not allowed.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3004,99 +2934,14 @@ gdk_window_begin_paint_region (GdkWindow *window,
|
|||||||
gdk_window_clear_backing_region (window);
|
gdk_window_clear_backing_region (window);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void
|
||||||
* gdk_window_mark_paint_from_clip:
|
gdk_window_end_paint_internal (GdkWindow *window)
|
||||||
* @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)
|
|
||||||
{
|
{
|
||||||
GdkWindow *composited;
|
GdkWindow *composited;
|
||||||
GdkWindowImplClass *impl_class;
|
GdkWindowImplClass *impl_class;
|
||||||
GdkRectangle clip_box = { 0, };
|
GdkRectangle clip_box = { 0, };
|
||||||
cairo_t *cr;
|
cairo_t *cr;
|
||||||
|
|
||||||
g_return_if_fail (GDK_IS_WINDOW (window));
|
|
||||||
|
|
||||||
if (GDK_WINDOW_DESTROYED (window) ||
|
if (GDK_WINDOW_DESTROYED (window) ||
|
||||||
!gdk_window_has_impl (window))
|
!gdk_window_has_impl (window))
|
||||||
return;
|
return;
|
||||||
@ -3188,6 +3033,285 @@ 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.
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
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 you’re 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)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GDK_IS_WINDOW (window));
|
||||||
|
|
||||||
|
gdk_window_begin_paint_internal (window, region);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const cairo_user_data_key_t draw_context_window_key;
|
||||||
|
|
||||||
|
static void
|
||||||
|
gdk_cairo_set_window (cairo_t *cr,
|
||||||
|
GdkWindow *window)
|
||||||
|
{
|
||||||
|
cairo_set_user_data (cr, &draw_context_window_key, window, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gdk_cairo_get_window:
|
||||||
|
* @cr: a Cairo context created by gdk_window_begin_draw_frame()
|
||||||
|
*
|
||||||
|
* Retrieves the #GdkWindow that created the Cairo context @cr.
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer none): a #GdkWindow
|
||||||
|
*
|
||||||
|
* Since: 3.22
|
||||||
|
*/
|
||||||
|
GdkWindow *
|
||||||
|
gdk_cairo_get_window (cairo_t *cr)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (cr != NULL, NULL);
|
||||||
|
|
||||||
|
return cairo_get_user_data (cr, &draw_context_window_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 Cairo context for drawing.
|
||||||
|
*
|
||||||
|
* 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 you’re
|
||||||
|
* 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 Cairo context that should be used to
|
||||||
|
* draw the contents of the window; the returned context is owned
|
||||||
|
* by GDK and should not be destroyed directly
|
||||||
|
*
|
||||||
|
* Since: 3.22
|
||||||
|
*/
|
||||||
|
cairo_t *
|
||||||
|
gdk_window_begin_draw_frame (GdkWindow *window,
|
||||||
|
const cairo_region_t *region)
|
||||||
|
{
|
||||||
|
cairo_t *retval;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
|
||||||
|
|
||||||
|
if (gdk_window_has_native (window) && gdk_window_is_toplevel (window))
|
||||||
|
gdk_window_begin_paint_internal (window, region);
|
||||||
|
|
||||||
|
retval = gdk_cairo_create (window);
|
||||||
|
|
||||||
|
gdk_cairo_region (retval, region);
|
||||||
|
cairo_clip (retval);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gdk_window_end_draw_frame:
|
||||||
|
* @window: a #GdkWindow
|
||||||
|
* @cr: the Cairo context 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 Cairo context.
|
||||||
|
*
|
||||||
|
* 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,
|
||||||
|
cairo_t *cr)
|
||||||
|
{
|
||||||
|
if (gdk_window_has_native (window) && gdk_window_is_toplevel (window))
|
||||||
|
gdk_window_end_paint_internal (window);
|
||||||
|
|
||||||
|
gdk_cairo_set_window (cr, NULL);
|
||||||
|
cairo_destroy (cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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:
|
* gdk_window_flush:
|
||||||
* @window: a #GdkWindow
|
* @window: a #GdkWindow
|
||||||
@ -3358,6 +3482,8 @@ gdk_cairo_create (GdkWindow *window)
|
|||||||
|
|
||||||
cr = cairo_create (surface);
|
cr = cairo_create (surface);
|
||||||
|
|
||||||
|
gdk_cairo_set_window (cr, window);
|
||||||
|
|
||||||
if (window->impl_window->current_paint.region != NULL)
|
if (window->impl_window->current_paint.region != NULL)
|
||||||
{
|
{
|
||||||
region = cairo_region_copy (window->impl_window->current_paint.region);
|
region = cairo_region_copy (window->impl_window->current_paint.region);
|
||||||
|
|||||||
@ -704,6 +704,14 @@ void gdk_window_begin_paint_region (GdkWindow *window,
|
|||||||
const cairo_region_t *region);
|
const cairo_region_t *region);
|
||||||
GDK_AVAILABLE_IN_ALL
|
GDK_AVAILABLE_IN_ALL
|
||||||
void gdk_window_end_paint (GdkWindow *window);
|
void gdk_window_end_paint (GdkWindow *window);
|
||||||
|
|
||||||
|
GDK_AVAILABLE_IN_3_22
|
||||||
|
cairo_t * 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,
|
||||||
|
cairo_t *cr);
|
||||||
|
|
||||||
GDK_DEPRECATED_IN_3_14
|
GDK_DEPRECATED_IN_3_14
|
||||||
void gdk_window_flush (GdkWindow *window);
|
void gdk_window_flush (GdkWindow *window);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user