2016-05-30 08:44:30 +00:00
|
|
|
/* 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
|
2018-03-20 11:05:26 +00:00
|
|
|
* @Short_description: Drawing context for GDK surfaces
|
2016-05-30 08:44:30 +00:00
|
|
|
*
|
|
|
|
* #GdkDrawingContext is an object that represents the current drawing
|
2018-03-20 10:40:08 +00:00
|
|
|
* state of a #GdkSurface.
|
2016-05-30 08:44:30 +00:00
|
|
|
*
|
2018-03-20 10:40:08 +00:00
|
|
|
* It's possible to use a #GdkDrawingContext to draw on a #GdkSurface
|
2016-05-30 08:44:30 +00:00
|
|
|
* via rendering API like Cairo or OpenGL.
|
|
|
|
*
|
2018-03-20 10:40:08 +00:00
|
|
|
* A #GdkDrawingContext can only be created by calling gdk_surface_begin_draw_frame()
|
|
|
|
* and will be valid until a call to gdk_surface_end_draw_frame().
|
2016-05-30 08:44:30 +00:00
|
|
|
*
|
|
|
|
* #GdkDrawingContext is available since GDK 3.22
|
|
|
|
*/
|
|
|
|
|
2017-12-26 19:39:24 +00:00
|
|
|
/**
|
|
|
|
* GdkDrawingContext:
|
|
|
|
*
|
|
|
|
* The GdkDrawingContext struct contains only private fields and should not
|
|
|
|
* be accessed directly.
|
|
|
|
*/
|
|
|
|
|
2016-05-30 08:44:30 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <cairo-gobject.h>
|
|
|
|
|
|
|
|
#include "gdkdrawingcontextprivate.h"
|
|
|
|
|
|
|
|
#include "gdkrectangle.h"
|
|
|
|
#include "gdkinternals.h"
|
|
|
|
#include "gdkintl.h"
|
2018-03-20 10:46:11 +00:00
|
|
|
#include "gdksurfaceimpl.h"
|
2016-05-30 08:44:30 +00:00
|
|
|
#include "gdkglcontextprivate.h"
|
|
|
|
#include "gdk-private.h"
|
|
|
|
|
2016-11-20 19:24:07 +00:00
|
|
|
typedef struct _GdkDrawingContextPrivate GdkDrawingContextPrivate;
|
|
|
|
|
|
|
|
struct _GdkDrawingContextPrivate {
|
2018-03-20 14:14:10 +00:00
|
|
|
GdkSurface *surface;
|
2016-12-01 00:38:20 +00:00
|
|
|
GdkDrawContext *paint_context;
|
2016-11-20 19:24:07 +00:00
|
|
|
|
|
|
|
cairo_region_t *clip;
|
|
|
|
cairo_t *cr;
|
|
|
|
};
|
|
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (GdkDrawingContext, gdk_drawing_context, G_TYPE_OBJECT)
|
2016-05-30 08:44:30 +00:00
|
|
|
|
|
|
|
enum {
|
|
|
|
PROP_0,
|
|
|
|
|
2018-03-20 14:14:10 +00:00
|
|
|
PROP_SURFACE,
|
2016-05-30 08:44:30 +00:00
|
|
|
PROP_CLIP,
|
2016-11-22 03:12:51 +00:00
|
|
|
PROP_PAINT_CONTEXT,
|
2016-05-30 08:44:30 +00:00
|
|
|
|
|
|
|
N_PROPS
|
|
|
|
};
|
|
|
|
|
|
|
|
static GParamSpec *obj_property[N_PROPS];
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_drawing_context_dispose (GObject *gobject)
|
|
|
|
{
|
|
|
|
GdkDrawingContext *self = GDK_DRAWING_CONTEXT (gobject);
|
2016-11-20 19:24:07 +00:00
|
|
|
GdkDrawingContextPrivate *priv = gdk_drawing_context_get_instance_private (self);
|
2016-05-30 08:44:30 +00:00
|
|
|
|
2016-06-12 17:55:34 +00:00
|
|
|
/* Unset the drawing context, in case somebody is holding
|
|
|
|
* onto the Cairo context
|
|
|
|
*/
|
2016-11-20 19:24:07 +00:00
|
|
|
if (priv->cr != NULL)
|
|
|
|
gdk_cairo_set_drawing_context (priv->cr, NULL);
|
2016-06-12 17:55:34 +00:00
|
|
|
|
2018-03-20 14:14:10 +00:00
|
|
|
g_clear_object (&priv->surface);
|
2016-11-20 19:37:22 +00:00
|
|
|
g_clear_object (&priv->paint_context);
|
2016-11-20 19:24:07 +00:00
|
|
|
g_clear_pointer (&priv->clip, cairo_region_destroy);
|
|
|
|
g_clear_pointer (&priv->cr, cairo_destroy);
|
2016-05-30 08:44:30 +00:00
|
|
|
|
|
|
|
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);
|
2016-11-20 19:24:07 +00:00
|
|
|
GdkDrawingContextPrivate *priv = gdk_drawing_context_get_instance_private (self);
|
2016-05-30 08:44:30 +00:00
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
2018-03-20 14:14:10 +00:00
|
|
|
case PROP_SURFACE:
|
|
|
|
priv->surface = g_value_dup_object (value);
|
|
|
|
if (priv->surface == NULL)
|
2016-11-20 19:37:22 +00:00
|
|
|
{
|
2018-03-20 14:14:10 +00:00
|
|
|
g_critical ("The drawing context of type %s does not have a surface "
|
2016-11-20 19:37:22 +00:00
|
|
|
"associated to it. Drawing contexts can only be created "
|
2018-03-20 10:40:08 +00:00
|
|
|
"using gdk_surface_begin_draw_frame().",
|
2016-11-20 19:37:22 +00:00
|
|
|
G_OBJECT_TYPE_NAME (gobject));
|
|
|
|
return;
|
|
|
|
}
|
2017-03-17 18:00:00 +00:00
|
|
|
break;
|
2016-11-22 03:12:51 +00:00
|
|
|
|
|
|
|
case PROP_PAINT_CONTEXT:
|
|
|
|
priv->paint_context = g_value_dup_object (value);
|
2016-05-30 08:44:30 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_CLIP:
|
2016-11-20 19:24:07 +00:00
|
|
|
priv->clip = g_value_dup_boxed (value);
|
2016-05-30 08:44:30 +00:00
|
|
|
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);
|
2016-11-20 19:24:07 +00:00
|
|
|
GdkDrawingContextPrivate *priv = gdk_drawing_context_get_instance_private (self);
|
2016-05-30 08:44:30 +00:00
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
2018-03-20 14:14:10 +00:00
|
|
|
case PROP_SURFACE:
|
|
|
|
g_value_set_object (value, priv->surface);
|
2016-05-30 08:44:30 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_CLIP:
|
2016-11-20 19:24:07 +00:00
|
|
|
g_value_set_boxed (value, priv->clip);
|
2016-05-30 08:44:30 +00:00
|
|
|
break;
|
|
|
|
|
2016-11-22 03:12:51 +00:00
|
|
|
case PROP_PAINT_CONTEXT:
|
|
|
|
g_value_set_object (value, priv->paint_context);
|
|
|
|
break;
|
|
|
|
|
2016-05-30 08:44:30 +00:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_drawing_context_class_init (GdkDrawingContextClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
/**
|
2018-03-20 14:14:10 +00:00
|
|
|
* GdkDrawingContext:surface:
|
2016-05-30 08:44:30 +00:00
|
|
|
*
|
2018-03-20 10:40:08 +00:00
|
|
|
* The #GdkSurface that created the drawing context.
|
2016-05-30 08:44:30 +00:00
|
|
|
*/
|
2018-03-20 14:14:10 +00:00
|
|
|
obj_property[PROP_SURFACE] =
|
|
|
|
g_param_spec_object ("surface", "Surface", "The surface that created the context",
|
2018-03-20 10:40:08 +00:00
|
|
|
GDK_TYPE_SURFACE,
|
2016-05-30 08:44:30 +00:00
|
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
|
|
G_PARAM_READWRITE |
|
|
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
/**
|
|
|
|
* GdkDrawingContext:clip:
|
|
|
|
*
|
|
|
|
* The clip region applied to the drawing context.
|
|
|
|
*/
|
|
|
|
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);
|
2016-11-22 03:12:51 +00:00
|
|
|
/**
|
|
|
|
* GdkDrawingContext:paint-context:
|
|
|
|
*
|
2016-12-01 00:38:20 +00:00
|
|
|
* The #GdkDrawContext used to draw or %NULL if Cairo is used.
|
2016-11-22 03:12:51 +00:00
|
|
|
*/
|
|
|
|
obj_property[PROP_PAINT_CONTEXT] =
|
|
|
|
g_param_spec_object ("paint-context", "Paint context", "The context used to draw",
|
2016-12-01 00:38:20 +00:00
|
|
|
GDK_TYPE_DRAW_CONTEXT,
|
2016-11-22 03:12:51 +00:00
|
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
|
|
G_PARAM_READWRITE |
|
|
|
|
G_PARAM_STATIC_STRINGS);
|
2016-05-30 08:44:30 +00:00
|
|
|
|
|
|
|
g_object_class_install_properties (gobject_class, N_PROPS, obj_property);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_drawing_context_init (GdkDrawingContext *self)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-06-07 15:34:50 +00:00
|
|
|
static const cairo_user_data_key_t draw_context_key;
|
|
|
|
|
2016-06-10 16:00:29 +00:00
|
|
|
void
|
2016-06-07 15:34:50 +00:00
|
|
|
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
|
|
|
|
*/
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2016-05-30 08:44:30 +00:00
|
|
|
/**
|
|
|
|
* gdk_drawing_context_get_cairo_context:
|
2016-11-23 04:54:50 +00:00
|
|
|
* @context: a #GdkDrawingContext created with a %NULL paint context
|
2016-05-30 08:44:30 +00:00
|
|
|
*
|
2018-03-20 10:40:08 +00:00
|
|
|
* Retrieves a Cairo context to be used to draw on the #GdkSurface
|
2016-11-23 04:54:50 +00:00
|
|
|
* that created the #GdkDrawingContext. The @context must have been
|
2016-12-01 00:38:20 +00:00
|
|
|
* created without a #GdkDrawContext for this function to work. If
|
2016-11-23 04:54:50 +00:00
|
|
|
* gdk_drawing_context_get_paint_context() does not return %NULL,
|
|
|
|
* then this function will.
|
2016-05-30 08:44:30 +00:00
|
|
|
*
|
|
|
|
* The returned context is guaranteed to be valid as long as the
|
|
|
|
* #GdkDrawingContext is valid, that is between a call to
|
2018-03-20 10:40:08 +00:00
|
|
|
* gdk_surface_begin_draw_frame() and gdk_surface_end_draw_frame().
|
2016-05-30 08:44:30 +00:00
|
|
|
*
|
2018-01-08 21:00:57 +00:00
|
|
|
* Returns: (transfer none) (nullable): a Cairo context to be used to draw
|
2018-03-20 10:40:08 +00:00
|
|
|
* the contents of the #GdkSurface. The context is owned by the
|
2016-11-23 04:54:50 +00:00
|
|
|
* #GdkDrawingContext and should not be destroyed. %NULL is
|
|
|
|
* returned when a paint context is in used.
|
2016-05-30 08:44:30 +00:00
|
|
|
*/
|
|
|
|
cairo_t *
|
|
|
|
gdk_drawing_context_get_cairo_context (GdkDrawingContext *context)
|
|
|
|
{
|
2016-11-20 19:24:07 +00:00
|
|
|
GdkDrawingContextPrivate *priv = gdk_drawing_context_get_instance_private (context);
|
|
|
|
|
2016-05-30 08:44:30 +00:00
|
|
|
g_return_val_if_fail (GDK_IS_DRAWING_CONTEXT (context), NULL);
|
2018-03-20 14:14:10 +00:00
|
|
|
g_return_val_if_fail (GDK_IS_SURFACE (priv->surface), NULL);
|
2016-05-30 08:44:30 +00:00
|
|
|
|
2016-11-23 04:54:50 +00:00
|
|
|
if (priv->paint_context != NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2016-11-20 19:24:07 +00:00
|
|
|
if (priv->cr == NULL)
|
2016-05-30 08:44:30 +00:00
|
|
|
{
|
2016-06-07 15:52:50 +00:00
|
|
|
cairo_region_t *region;
|
|
|
|
cairo_surface_t *surface;
|
|
|
|
|
2018-03-20 14:14:10 +00:00
|
|
|
surface = _gdk_surface_ref_cairo_surface (priv->surface);
|
2016-11-20 19:24:07 +00:00
|
|
|
priv->cr = cairo_create (surface);
|
2016-06-07 15:34:50 +00:00
|
|
|
|
2016-11-20 19:24:07 +00:00
|
|
|
gdk_cairo_set_drawing_context (priv->cr, context);
|
2016-06-07 15:34:50 +00:00
|
|
|
|
2018-03-20 14:14:10 +00:00
|
|
|
region = gdk_surface_get_current_paint_region (priv->surface);
|
2016-11-20 19:24:07 +00:00
|
|
|
cairo_region_union (region, priv->clip);
|
|
|
|
gdk_cairo_region (priv->cr, region);
|
|
|
|
cairo_clip (priv->cr);
|
2016-06-07 15:52:50 +00:00
|
|
|
|
|
|
|
cairo_region_destroy (region);
|
|
|
|
cairo_surface_destroy (surface);
|
2016-05-30 08:44:30 +00:00
|
|
|
}
|
|
|
|
|
2016-11-20 19:24:07 +00:00
|
|
|
return priv->cr;
|
2016-05-30 08:44:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-03-20 11:05:26 +00:00
|
|
|
* gdk_drawing_context_get_surface:
|
2016-05-30 08:44:30 +00:00
|
|
|
* @context: a #GdkDrawingContext
|
|
|
|
*
|
2018-03-20 14:14:10 +00:00
|
|
|
* Retrieves the surface that created the drawing @context.
|
2016-05-30 08:44:30 +00:00
|
|
|
*
|
2018-03-20 10:40:08 +00:00
|
|
|
* Returns: (transfer none): a #GdkSurface
|
2016-05-30 08:44:30 +00:00
|
|
|
*/
|
2018-03-20 10:40:08 +00:00
|
|
|
GdkSurface *
|
2018-03-20 11:05:26 +00:00
|
|
|
gdk_drawing_context_get_surface (GdkDrawingContext *context)
|
2016-05-30 08:44:30 +00:00
|
|
|
{
|
2016-11-20 19:24:07 +00:00
|
|
|
GdkDrawingContextPrivate *priv = gdk_drawing_context_get_instance_private (context);
|
|
|
|
|
2016-05-30 08:44:30 +00:00
|
|
|
g_return_val_if_fail (GDK_IS_DRAWING_CONTEXT (context), NULL);
|
|
|
|
|
2018-03-20 14:14:10 +00:00
|
|
|
return priv->surface;
|
2016-05-30 08:44:30 +00:00
|
|
|
}
|
|
|
|
|
2016-11-22 03:12:51 +00:00
|
|
|
/**
|
|
|
|
* gdk_drawing_context_get_paint_context:
|
|
|
|
* @context: a #GdkDrawingContext
|
|
|
|
*
|
|
|
|
* Retrieves the paint context used to draw with.
|
|
|
|
*
|
2016-12-01 00:38:20 +00:00
|
|
|
* Returns: (transfer none): a #GdkDrawContext or %NULL
|
2016-11-22 03:12:51 +00:00
|
|
|
*/
|
2016-12-01 00:38:20 +00:00
|
|
|
GdkDrawContext *
|
2016-11-22 03:12:51 +00:00
|
|
|
gdk_drawing_context_get_paint_context (GdkDrawingContext *context)
|
|
|
|
{
|
|
|
|
GdkDrawingContextPrivate *priv = gdk_drawing_context_get_instance_private (context);
|
|
|
|
|
|
|
|
g_return_val_if_fail (GDK_IS_DRAWING_CONTEXT (context), NULL);
|
|
|
|
|
|
|
|
return priv->paint_context;
|
|
|
|
}
|
|
|
|
|
2016-05-30 08:44:30 +00:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
cairo_region_t *
|
|
|
|
gdk_drawing_context_get_clip (GdkDrawingContext *context)
|
|
|
|
{
|
2016-11-20 19:24:07 +00:00
|
|
|
GdkDrawingContextPrivate *priv = gdk_drawing_context_get_instance_private (context);
|
|
|
|
|
2016-05-30 08:44:30 +00:00
|
|
|
g_return_val_if_fail (GDK_IS_DRAWING_CONTEXT (context), NULL);
|
|
|
|
|
2016-11-20 19:24:07 +00:00
|
|
|
if (priv->clip == NULL)
|
2016-05-30 08:44:30 +00:00
|
|
|
return NULL;
|
|
|
|
|
2016-11-20 19:24:07 +00:00
|
|
|
return cairo_region_copy (priv->clip);
|
2016-05-30 08:44:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gdk_drawing_context_is_valid:
|
|
|
|
* @context: a #GdkDrawingContext
|
|
|
|
*
|
|
|
|
* Checks whether the given #GdkDrawingContext is valid.
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if the context is valid
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gdk_drawing_context_is_valid (GdkDrawingContext *context)
|
|
|
|
{
|
2016-11-20 19:24:07 +00:00
|
|
|
GdkDrawingContextPrivate *priv = gdk_drawing_context_get_instance_private (context);
|
|
|
|
|
2016-05-30 08:44:30 +00:00
|
|
|
g_return_val_if_fail (GDK_IS_DRAWING_CONTEXT (context), FALSE);
|
|
|
|
|
2018-03-20 14:14:10 +00:00
|
|
|
if (priv->surface == NULL)
|
2016-05-30 08:44:30 +00:00
|
|
|
return FALSE;
|
|
|
|
|
2018-03-20 14:14:10 +00:00
|
|
|
if (gdk_surface_get_drawing_context (priv->surface) != context)
|
2016-05-30 08:44:30 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|