Compare commits
8 Commits
use-gles3-
...
wip/ebassi
Author | SHA1 | Date | |
---|---|---|---|
|
3611fc9ab4 | ||
|
59bf3a08ed | ||
|
b1b0a25164 | ||
|
bfb4fe771c | ||
|
af6f9773ec | ||
|
7510615893 | ||
|
45d33f2e3a | ||
|
f0fa8e780b |
@@ -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" />
|
||||
|
@@ -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>
|
||||
|
@@ -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
|
||||
|
@@ -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 \
|
||||
|
@@ -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>
|
||||
|
@@ -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
315
gdk/gdkdrawingcontext.c
Normal 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
53
gdk/gdkdrawingcontext.h
Normal 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__ */
|
29
gdk/gdkdrawingcontextprivate.h
Normal file
29
gdk/gdkdrawingcontextprivate.h
Normal 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__ */
|
@@ -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);
|
||||
|
||||
|
521
gdk/gdkwindow.c
521
gdk/gdkwindow.c
@@ -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 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)
|
||||
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 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().
|
||||
*
|
||||
* 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 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 #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)
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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 */
|
||||
|
@@ -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:
|
||||
|
133
gtk/gtkwidget.c
133
gtk/gtkwidget.c
@@ -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 don’t 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);
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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))
|
||||
|
Reference in New Issue
Block a user