mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-27 06:00:22 +00:00
d7f3ab0569
2007-12-10 Richard Hult <richard@imendio.com> * gdk/quartz/gdkdrawable-quartz.c: (gdk_quartz_drawable_get_context), (gdk_quartz_drawable_release_context): * gdk/quartz/gdkeventloop-quartz.c: (gdk_event_prepare), (gdk_event_check), (gdk_event_dispatch), (poll_func): * gdk/quartz/gdkwindow-quartz.h: Replace the autorelease pools used for each drawing context and in prepare, dispatch and poll with one that exists across each main loop iteration. Fixes leaks on leopard and protects against future leaks introduce when the underlying system changes again (bug #492977). svn path=/trunk/; revision=19149
783 lines
22 KiB
C
783 lines
22 KiB
C
/* gdkdrawable-quartz.c
|
|
*
|
|
* Copyright (C) 2005-2007 Imendio AB
|
|
*
|
|
* 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, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <cairo-quartz.h>
|
|
#include "gdkprivate-quartz.h"
|
|
|
|
static gpointer parent_class;
|
|
|
|
static cairo_user_data_key_t gdk_quartz_cairo_key;
|
|
|
|
typedef struct {
|
|
GdkDrawable *drawable;
|
|
CGContextRef cg_context;
|
|
} GdkQuartzCairoSurfaceData;
|
|
|
|
static void
|
|
gdk_quartz_cairo_surface_destroy (void *data)
|
|
{
|
|
GdkQuartzCairoSurfaceData *surface_data = data;
|
|
GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (surface_data->drawable);
|
|
|
|
gdk_quartz_drawable_release_context (surface_data->drawable,
|
|
surface_data->cg_context);
|
|
|
|
impl->cairo_surface = NULL;
|
|
|
|
g_free (surface_data);
|
|
}
|
|
|
|
static cairo_surface_t *
|
|
gdk_quartz_ref_cairo_surface (GdkDrawable *drawable)
|
|
{
|
|
GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (drawable);
|
|
|
|
if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable) &&
|
|
GDK_WINDOW_DESTROYED (impl->wrapper))
|
|
return NULL;
|
|
|
|
if (!impl->cairo_surface)
|
|
{
|
|
CGContextRef cg_context;
|
|
int width, height;
|
|
GdkQuartzCairoSurfaceData *surface_data;
|
|
|
|
cg_context = gdk_quartz_drawable_get_context (drawable, TRUE);
|
|
if (!cg_context)
|
|
return NULL;
|
|
|
|
gdk_drawable_get_size (drawable, &width, &height);
|
|
|
|
impl->cairo_surface = cairo_quartz_surface_create_for_cg_context (cg_context, width, height);
|
|
|
|
surface_data = g_new (GdkQuartzCairoSurfaceData, 1);
|
|
surface_data->drawable = drawable;
|
|
surface_data->cg_context = cg_context;
|
|
|
|
cairo_surface_set_user_data (impl->cairo_surface, &gdk_quartz_cairo_key,
|
|
surface_data, gdk_quartz_cairo_surface_destroy);
|
|
}
|
|
else
|
|
cairo_surface_reference (impl->cairo_surface);
|
|
|
|
return impl->cairo_surface;
|
|
}
|
|
|
|
static void
|
|
gdk_quartz_set_colormap (GdkDrawable *drawable,
|
|
GdkColormap *colormap)
|
|
{
|
|
GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (drawable);
|
|
|
|
if (impl->colormap == colormap)
|
|
return;
|
|
|
|
if (impl->colormap)
|
|
g_object_unref (impl->colormap);
|
|
impl->colormap = colormap;
|
|
if (impl->colormap)
|
|
g_object_ref (impl->colormap);
|
|
}
|
|
|
|
static GdkColormap*
|
|
gdk_quartz_get_colormap (GdkDrawable *drawable)
|
|
{
|
|
return GDK_DRAWABLE_IMPL_QUARTZ (drawable)->colormap;
|
|
}
|
|
|
|
static GdkScreen*
|
|
gdk_quartz_get_screen (GdkDrawable *drawable)
|
|
{
|
|
return _gdk_screen;
|
|
}
|
|
|
|
static GdkVisual*
|
|
gdk_quartz_get_visual (GdkDrawable *drawable)
|
|
{
|
|
return gdk_drawable_get_visual (GDK_DRAWABLE_IMPL_QUARTZ (drawable)->wrapper);
|
|
}
|
|
|
|
static int
|
|
gdk_quartz_get_depth (GdkDrawable *drawable)
|
|
{
|
|
/* This is a bit bogus but I'm not sure the other way is better */
|
|
|
|
return gdk_drawable_get_depth (GDK_DRAWABLE_IMPL_QUARTZ (drawable)->wrapper);
|
|
}
|
|
|
|
static void
|
|
gdk_quartz_draw_rectangle (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
gboolean filled,
|
|
gint x,
|
|
gint y,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
CGContextRef context = gdk_quartz_drawable_get_context (drawable, FALSE);
|
|
|
|
if (!context)
|
|
return;
|
|
|
|
_gdk_quartz_gc_update_cg_context (gc,
|
|
drawable,
|
|
context,
|
|
filled ?
|
|
GDK_QUARTZ_CONTEXT_FILL :
|
|
GDK_QUARTZ_CONTEXT_STROKE);
|
|
|
|
if (filled)
|
|
{
|
|
CGRect rect = CGRectMake (x, y, width, height);
|
|
|
|
CGContextFillRect (context, rect);
|
|
}
|
|
else
|
|
{
|
|
CGRect rect = CGRectMake (x + 0.5, y + 0.5, width, height);
|
|
|
|
CGContextStrokeRect (context, rect);
|
|
}
|
|
|
|
gdk_quartz_drawable_release_context (drawable, context);
|
|
}
|
|
|
|
static void
|
|
gdk_quartz_draw_arc (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
gboolean filled,
|
|
gint x,
|
|
gint y,
|
|
gint width,
|
|
gint height,
|
|
gint angle1,
|
|
gint angle2)
|
|
{
|
|
CGContextRef context = gdk_quartz_drawable_get_context (drawable, FALSE);
|
|
float start_angle, end_angle;
|
|
gboolean clockwise = FALSE;
|
|
|
|
if (!context)
|
|
return;
|
|
|
|
_gdk_quartz_gc_update_cg_context (gc, drawable, context,
|
|
filled ?
|
|
GDK_QUARTZ_CONTEXT_FILL :
|
|
GDK_QUARTZ_CONTEXT_STROKE);
|
|
|
|
CGContextSaveGState (context);
|
|
|
|
start_angle = angle1 * 2.0 * G_PI / 360.0 / 64.0;
|
|
end_angle = start_angle + angle2 * 2.0 * G_PI / 360.0 / 64.0;
|
|
|
|
/* angle2 is relative to angle1 and can be negative, which switches
|
|
* the drawing direction
|
|
*/
|
|
if (angle2 < 0)
|
|
clockwise = TRUE;
|
|
|
|
/* below, flip the coordinate system back to its original y-diretion
|
|
* so the angles passed to CGContextAddArc() are interpreted as
|
|
* expected
|
|
*
|
|
* FIXME: the implementation below works only for perfect circles
|
|
* (width == height). Any other aspect ratio either scales the
|
|
* line width unevenly or scales away the path entirely for very
|
|
* small line widths (esp. for line_width == 0, which is a hair
|
|
* line on X11 but must be approximated with the thinnest possible
|
|
* line on quartz).
|
|
*/
|
|
|
|
if (filled)
|
|
{
|
|
CGContextTranslateCTM (context,
|
|
x + width / 2.0,
|
|
y + height / 2.0);
|
|
CGContextScaleCTM (context, 1.0, - (double)height / (double)width);
|
|
|
|
CGContextMoveToPoint (context, 0, 0);
|
|
CGContextAddArc (context, 0, 0, width / 2.0,
|
|
start_angle, end_angle,
|
|
clockwise);
|
|
CGContextClosePath (context);
|
|
CGContextFillPath (context);
|
|
}
|
|
else
|
|
{
|
|
CGContextTranslateCTM (context,
|
|
x + width / 2.0 + 0.5,
|
|
y + height / 2.0 + 0.5);
|
|
CGContextScaleCTM (context, 1.0, - (double)height / (double)width);
|
|
|
|
CGContextAddArc (context, 0, 0, width / 2.0,
|
|
start_angle, end_angle,
|
|
clockwise);
|
|
CGContextStrokePath (context);
|
|
}
|
|
|
|
CGContextRestoreGState (context);
|
|
|
|
gdk_quartz_drawable_release_context (drawable, context);
|
|
}
|
|
|
|
static void
|
|
gdk_quartz_draw_polygon (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
gboolean filled,
|
|
GdkPoint *points,
|
|
gint npoints)
|
|
{
|
|
CGContextRef context = gdk_quartz_drawable_get_context (drawable, FALSE);
|
|
int i;
|
|
|
|
if (!context)
|
|
return;
|
|
|
|
_gdk_quartz_gc_update_cg_context (gc, drawable, context,
|
|
filled ?
|
|
GDK_QUARTZ_CONTEXT_FILL :
|
|
GDK_QUARTZ_CONTEXT_STROKE);
|
|
|
|
if (filled)
|
|
{
|
|
CGContextMoveToPoint (context, points[0].x, points[0].y);
|
|
for (i = 1; i < npoints; i++)
|
|
CGContextAddLineToPoint (context, points[i].x, points[i].y);
|
|
|
|
CGContextClosePath (context);
|
|
CGContextFillPath (context);
|
|
}
|
|
else
|
|
{
|
|
CGContextMoveToPoint (context, points[0].x + 0.5, points[0].y + 0.5);
|
|
for (i = 1; i < npoints; i++)
|
|
CGContextAddLineToPoint (context, points[i].x + 0.5, points[i].y + 0.5);
|
|
|
|
CGContextClosePath (context);
|
|
CGContextStrokePath (context);
|
|
}
|
|
|
|
gdk_quartz_drawable_release_context (drawable, context);
|
|
}
|
|
|
|
static void
|
|
gdk_quartz_draw_text (GdkDrawable *drawable,
|
|
GdkFont *font,
|
|
GdkGC *gc,
|
|
gint x,
|
|
gint y,
|
|
const gchar *text,
|
|
gint text_length)
|
|
{
|
|
/* FIXME: Implement */
|
|
}
|
|
|
|
static void
|
|
gdk_quartz_draw_text_wc (GdkDrawable *drawable,
|
|
GdkFont *font,
|
|
GdkGC *gc,
|
|
gint x,
|
|
gint y,
|
|
const GdkWChar *text,
|
|
gint text_length)
|
|
{
|
|
/* FIXME: Implement */
|
|
}
|
|
|
|
static void
|
|
gdk_quartz_draw_drawable (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkPixmap *src,
|
|
gint xsrc,
|
|
gint ysrc,
|
|
gint xdest,
|
|
gint ydest,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
int src_depth = gdk_drawable_get_depth (src);
|
|
int dest_depth = gdk_drawable_get_depth (drawable);
|
|
GdkDrawableImplQuartz *src_impl;
|
|
|
|
if (GDK_IS_DRAWABLE_IMPL_QUARTZ (src))
|
|
src_impl = GDK_DRAWABLE_IMPL_QUARTZ (src);
|
|
else if (GDK_IS_PIXMAP (src))
|
|
src_impl = GDK_DRAWABLE_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (src)->impl);
|
|
else if (GDK_IS_WINDOW (src))
|
|
{
|
|
src_impl = GDK_DRAWABLE_IMPL_QUARTZ (GDK_WINDOW_OBJECT (src)->impl);
|
|
/* FIXME: Implement drawing a window. */
|
|
return;
|
|
}
|
|
else
|
|
g_assert_not_reached ();
|
|
|
|
if (src_depth == 1)
|
|
{
|
|
/* FIXME: src depth 1 is not supported yet */
|
|
}
|
|
else if (dest_depth != 0 && src_depth == dest_depth)
|
|
{
|
|
CGContextRef context = gdk_quartz_drawable_get_context (drawable, FALSE);
|
|
|
|
if (!context)
|
|
return;
|
|
|
|
_gdk_quartz_gc_update_cg_context (gc, drawable, context,
|
|
GDK_QUARTZ_CONTEXT_STROKE);
|
|
|
|
CGContextClipToRect (context, CGRectMake (xdest, ydest, width, height));
|
|
CGContextTranslateCTM (context, xdest - xsrc, ydest - ysrc);
|
|
CGContextDrawImage (context,
|
|
CGRectMake(0, 0,
|
|
GDK_PIXMAP_IMPL_QUARTZ (src_impl)->width,
|
|
GDK_PIXMAP_IMPL_QUARTZ (src_impl)->height),
|
|
GDK_PIXMAP_IMPL_QUARTZ (src_impl)->image);
|
|
|
|
gdk_quartz_drawable_release_context (drawable, context);
|
|
}
|
|
else
|
|
g_warning ("Attempt to draw a drawable with depth %d to a drawable with depth %d",
|
|
src_depth, dest_depth);
|
|
}
|
|
|
|
static void
|
|
gdk_quartz_draw_points (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkPoint *points,
|
|
gint npoints)
|
|
{
|
|
CGContextRef context = gdk_quartz_drawable_get_context (drawable, FALSE);
|
|
int i;
|
|
|
|
if (!context)
|
|
return;
|
|
|
|
_gdk_quartz_gc_update_cg_context (gc, drawable, context,
|
|
GDK_QUARTZ_CONTEXT_STROKE |
|
|
GDK_QUARTZ_CONTEXT_FILL);
|
|
|
|
/* Just draw 1x1 rectangles */
|
|
for (i = 0; i < npoints; i++)
|
|
{
|
|
CGRect rect = CGRectMake (points[i].x, points[i].y, 1, 1);
|
|
CGContextFillRect (context, rect);
|
|
}
|
|
|
|
gdk_quartz_drawable_release_context (drawable, context);
|
|
}
|
|
|
|
static inline void
|
|
gdk_quartz_fix_cap_not_last_line (GdkGCQuartz *private,
|
|
gint x1,
|
|
gint y1,
|
|
gint x2,
|
|
gint y2,
|
|
gint *xfix,
|
|
gint *yfix)
|
|
{
|
|
*xfix = 0;
|
|
*yfix = 0;
|
|
|
|
if (private->cap_style == GDK_CAP_NOT_LAST && private->line_width == 0)
|
|
{
|
|
/* fix only vertical and horizontal lines for now */
|
|
|
|
if (y1 == y2 && x1 != x2)
|
|
{
|
|
*xfix = (x1 < x2) ? -1 : 1;
|
|
}
|
|
else if (x1 == x2 && y1 != y2)
|
|
{
|
|
*yfix = (y1 < y2) ? -1 : 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
gdk_quartz_draw_segments (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkSegment *segs,
|
|
gint nsegs)
|
|
{
|
|
CGContextRef context = gdk_quartz_drawable_get_context (drawable, FALSE);
|
|
GdkGCQuartz *private;
|
|
int i;
|
|
|
|
if (!context)
|
|
return;
|
|
|
|
private = GDK_GC_QUARTZ (gc);
|
|
|
|
_gdk_quartz_gc_update_cg_context (gc, drawable, context,
|
|
GDK_QUARTZ_CONTEXT_STROKE);
|
|
|
|
for (i = 0; i < nsegs; i++)
|
|
{
|
|
gint xfix, yfix;
|
|
|
|
gdk_quartz_fix_cap_not_last_line (private,
|
|
segs[i].x1, segs[i].y1,
|
|
segs[i].x2, segs[i].y2,
|
|
&xfix, &yfix);
|
|
|
|
CGContextMoveToPoint (context, segs[i].x1 + 0.5, segs[i].y1 + 0.5);
|
|
CGContextAddLineToPoint (context, segs[i].x2 + 0.5 + xfix, segs[i].y2 + 0.5 + yfix);
|
|
}
|
|
|
|
CGContextStrokePath (context);
|
|
|
|
gdk_quartz_drawable_release_context (drawable, context);
|
|
}
|
|
|
|
static void
|
|
gdk_quartz_draw_lines (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkPoint *points,
|
|
gint npoints)
|
|
{
|
|
CGContextRef context = gdk_quartz_drawable_get_context (drawable, FALSE);
|
|
GdkGCQuartz *private;
|
|
gint xfix, yfix;
|
|
gint i;
|
|
|
|
if (!context)
|
|
return;
|
|
|
|
private = GDK_GC_QUARTZ (gc);
|
|
|
|
_gdk_quartz_gc_update_cg_context (gc, drawable, context,
|
|
GDK_QUARTZ_CONTEXT_STROKE);
|
|
|
|
CGContextMoveToPoint (context, points[0].x + 0.5, points[0].y + 0.5);
|
|
|
|
for (i = 1; i < npoints - 1; i++)
|
|
CGContextAddLineToPoint (context, points[i].x + 0.5, points[i].y + 0.5);
|
|
|
|
gdk_quartz_fix_cap_not_last_line (private,
|
|
points[npoints - 2].x, points[npoints - 2].y,
|
|
points[npoints - 1].x, points[npoints - 1].y,
|
|
&xfix, &yfix);
|
|
|
|
CGContextAddLineToPoint (context,
|
|
points[npoints - 1].x + 0.5 + xfix,
|
|
points[npoints - 1].y + 0.5 + yfix);
|
|
|
|
CGContextStrokePath (context);
|
|
|
|
gdk_quartz_drawable_release_context (drawable, context);
|
|
}
|
|
|
|
static void
|
|
gdk_quartz_draw_pixbuf (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkPixbuf *pixbuf,
|
|
gint src_x,
|
|
gint src_y,
|
|
gint dest_x,
|
|
gint dest_y,
|
|
gint width,
|
|
gint height,
|
|
GdkRgbDither dither,
|
|
gint x_dither,
|
|
gint y_dither)
|
|
{
|
|
CGContextRef context = gdk_quartz_drawable_get_context (drawable, FALSE);
|
|
CGColorSpaceRef colorspace;
|
|
CGDataProviderRef data_provider;
|
|
CGImageRef image;
|
|
void *data;
|
|
int rowstride, pixbuf_width, pixbuf_height;
|
|
gboolean has_alpha;
|
|
|
|
if (!context)
|
|
return;
|
|
|
|
pixbuf_width = gdk_pixbuf_get_width (pixbuf);
|
|
pixbuf_height = gdk_pixbuf_get_height (pixbuf);
|
|
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
|
|
has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
|
|
|
|
data = gdk_pixbuf_get_pixels (pixbuf);
|
|
|
|
colorspace = CGColorSpaceCreateDeviceRGB ();
|
|
data_provider = CGDataProviderCreateWithData (NULL, data, pixbuf_height * rowstride, NULL);
|
|
|
|
image = CGImageCreate (pixbuf_width, pixbuf_height, 8,
|
|
has_alpha ? 32 : 24, rowstride,
|
|
colorspace,
|
|
has_alpha ? kCGImageAlphaLast : 0,
|
|
data_provider, NULL, FALSE,
|
|
kCGRenderingIntentDefault);
|
|
|
|
CGDataProviderRelease (data_provider);
|
|
CGColorSpaceRelease (colorspace);
|
|
|
|
_gdk_quartz_gc_update_cg_context (gc, drawable, context,
|
|
GDK_QUARTZ_CONTEXT_STROKE);
|
|
|
|
CGContextClipToRect (context, CGRectMake (dest_x, dest_y, width, height));
|
|
CGContextTranslateCTM (context, dest_x - src_x, dest_y - src_y + pixbuf_height);
|
|
CGContextScaleCTM (context, 1, -1);
|
|
|
|
CGContextDrawImage (context, CGRectMake (0, 0, pixbuf_width, pixbuf_height), image);
|
|
CGImageRelease (image);
|
|
|
|
gdk_quartz_drawable_release_context (drawable, context);
|
|
}
|
|
|
|
static void
|
|
gdk_quartz_draw_image (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkImage *image,
|
|
gint xsrc,
|
|
gint ysrc,
|
|
gint xdest,
|
|
gint ydest,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
CGContextRef context = gdk_quartz_drawable_get_context (drawable, FALSE);
|
|
CGColorSpaceRef colorspace;
|
|
CGDataProviderRef data_provider;
|
|
CGImageRef cgimage;
|
|
|
|
if (!context)
|
|
return;
|
|
|
|
colorspace = CGColorSpaceCreateDeviceRGB ();
|
|
data_provider = CGDataProviderCreateWithData (NULL, image->mem, image->height * image->bpl, NULL);
|
|
|
|
/* FIXME: Make sure that this function draws 32-bit images correctly,
|
|
* also check endianness wrt kCGImageAlphaNoneSkipFirst */
|
|
cgimage = CGImageCreate (image->width, image->height, 8,
|
|
32, image->bpl,
|
|
colorspace,
|
|
kCGImageAlphaNoneSkipFirst,
|
|
data_provider, NULL, FALSE, kCGRenderingIntentDefault);
|
|
|
|
CGDataProviderRelease (data_provider);
|
|
CGColorSpaceRelease (colorspace);
|
|
|
|
_gdk_quartz_gc_update_cg_context (gc, drawable, context,
|
|
GDK_QUARTZ_CONTEXT_STROKE);
|
|
|
|
CGContextClipToRect (context, CGRectMake (xdest, ydest, width, height));
|
|
CGContextTranslateCTM (context, xdest - xsrc, ydest - ysrc + image->height);
|
|
CGContextScaleCTM (context, 1, -1);
|
|
|
|
CGContextDrawImage (context, CGRectMake (0, 0, image->width, image->height), cgimage);
|
|
CGImageRelease (cgimage);
|
|
|
|
gdk_quartz_drawable_release_context (drawable, context);
|
|
}
|
|
|
|
static void
|
|
gdk_drawable_impl_quartz_finalize (GObject *object)
|
|
{
|
|
GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (object);
|
|
|
|
if (impl->colormap)
|
|
g_object_unref (impl->colormap);
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gdk_drawable_impl_quartz_class_init (GdkDrawableImplQuartzClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
|
|
|
|
parent_class = g_type_class_peek_parent (klass);
|
|
|
|
object_class->finalize = gdk_drawable_impl_quartz_finalize;
|
|
|
|
drawable_class->create_gc = _gdk_quartz_gc_new;
|
|
drawable_class->draw_rectangle = gdk_quartz_draw_rectangle;
|
|
drawable_class->draw_arc = gdk_quartz_draw_arc;
|
|
drawable_class->draw_polygon = gdk_quartz_draw_polygon;
|
|
drawable_class->draw_text = gdk_quartz_draw_text;
|
|
drawable_class->draw_text_wc = gdk_quartz_draw_text_wc;
|
|
drawable_class->draw_drawable = gdk_quartz_draw_drawable;
|
|
drawable_class->draw_points = gdk_quartz_draw_points;
|
|
drawable_class->draw_segments = gdk_quartz_draw_segments;
|
|
drawable_class->draw_lines = gdk_quartz_draw_lines;
|
|
drawable_class->draw_image = gdk_quartz_draw_image;
|
|
drawable_class->draw_pixbuf = gdk_quartz_draw_pixbuf;
|
|
|
|
drawable_class->ref_cairo_surface = gdk_quartz_ref_cairo_surface;
|
|
|
|
drawable_class->set_colormap = gdk_quartz_set_colormap;
|
|
drawable_class->get_colormap = gdk_quartz_get_colormap;
|
|
|
|
drawable_class->get_depth = gdk_quartz_get_depth;
|
|
drawable_class->get_screen = gdk_quartz_get_screen;
|
|
drawable_class->get_visual = gdk_quartz_get_visual;
|
|
|
|
drawable_class->_copy_to_image = _gdk_quartz_image_copy_to_image;
|
|
}
|
|
|
|
GType
|
|
gdk_drawable_impl_quartz_get_type (void)
|
|
{
|
|
static GType object_type = 0;
|
|
|
|
if (!object_type)
|
|
{
|
|
static const GTypeInfo object_info =
|
|
{
|
|
sizeof (GdkDrawableImplQuartzClass),
|
|
(GBaseInitFunc) NULL,
|
|
(GBaseFinalizeFunc) NULL,
|
|
(GClassInitFunc) gdk_drawable_impl_quartz_class_init,
|
|
NULL, /* class_finalize */
|
|
NULL, /* class_data */
|
|
sizeof (GdkDrawableImplQuartz),
|
|
0, /* n_preallocs */
|
|
(GInstanceInitFunc) NULL,
|
|
};
|
|
|
|
object_type = g_type_register_static (GDK_TYPE_DRAWABLE,
|
|
"GdkDrawableImplQuartz",
|
|
&object_info, 0);
|
|
}
|
|
|
|
return object_type;
|
|
}
|
|
|
|
CGContextRef
|
|
gdk_quartz_drawable_get_context (GdkDrawable *drawable,
|
|
gboolean antialias)
|
|
{
|
|
GdkDrawableImplQuartz *drawable_impl = GDK_DRAWABLE_IMPL_QUARTZ (drawable);
|
|
CGContextRef cg_context;
|
|
|
|
if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable) &&
|
|
GDK_WINDOW_DESTROYED (drawable_impl->wrapper))
|
|
return NULL;
|
|
|
|
if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable))
|
|
{
|
|
GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (drawable);
|
|
|
|
/* Lock focus when not called as part of a drawRect call. This
|
|
* is needed when called from outside "real" expose events, for
|
|
* example for synthesized expose events when realizing windows
|
|
* and for widgets that send fake expose events like the arrow
|
|
* buttons in spinbuttons.
|
|
*/
|
|
if (window_impl->in_paint_rect_count == 0)
|
|
{
|
|
if (![window_impl->view lockFocusIfCanDraw])
|
|
return NULL;
|
|
}
|
|
|
|
cg_context = [[NSGraphicsContext currentContext] graphicsPort];
|
|
CGContextSaveGState (cg_context);
|
|
CGContextSetAllowsAntialiasing (cg_context, antialias);
|
|
|
|
/* We'll emulate the clipping caused by double buffering here */
|
|
if (window_impl->begin_paint_count != 0)
|
|
{
|
|
CGRect rect;
|
|
CGRect *cg_rects;
|
|
GdkRectangle *rects;
|
|
gint n_rects, i;
|
|
|
|
gdk_region_get_rectangles (window_impl->paint_clip_region,
|
|
&rects, &n_rects);
|
|
|
|
if (n_rects == 1)
|
|
cg_rects = ▭
|
|
else
|
|
cg_rects = g_new (CGRect, n_rects);
|
|
|
|
for (i = 0; i < n_rects; i++)
|
|
{
|
|
cg_rects[i].origin.x = rects[i].x;
|
|
cg_rects[i].origin.y = rects[i].y;
|
|
cg_rects[i].size.width = rects[i].width;
|
|
cg_rects[i].size.height = rects[i].height;
|
|
}
|
|
|
|
CGContextClipToRects (cg_context, cg_rects, n_rects);
|
|
|
|
g_free (rects);
|
|
if (cg_rects != &rect)
|
|
g_free (cg_rects);
|
|
}
|
|
}
|
|
else if (GDK_IS_PIXMAP_IMPL_QUARTZ (drawable))
|
|
{
|
|
GdkPixmapImplQuartz *impl = GDK_PIXMAP_IMPL_QUARTZ (drawable);
|
|
|
|
cg_context = CGBitmapContextCreate (impl->data,
|
|
CGImageGetWidth (impl->image),
|
|
CGImageGetHeight (impl->image),
|
|
CGImageGetBitsPerComponent (impl->image),
|
|
CGImageGetBytesPerRow (impl->image),
|
|
CGImageGetColorSpace (impl->image),
|
|
CGImageGetBitmapInfo (impl->image));
|
|
CGContextSetAllowsAntialiasing (cg_context, antialias);
|
|
}
|
|
else
|
|
{
|
|
g_warning ("Tried to create CGContext for something not a quartz window or pixmap");
|
|
cg_context = NULL;
|
|
}
|
|
|
|
return cg_context;
|
|
}
|
|
|
|
void
|
|
gdk_quartz_drawable_release_context (GdkDrawable *drawable,
|
|
CGContextRef cg_context)
|
|
{
|
|
if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable))
|
|
{
|
|
GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (drawable);
|
|
|
|
CGContextRestoreGState (cg_context);
|
|
CGContextSetAllowsAntialiasing (cg_context, TRUE);
|
|
|
|
/* See comment in gdk_quartz_drawable_get_context(). */
|
|
if (window_impl->in_paint_rect_count == 0)
|
|
[window_impl->view unlockFocus];
|
|
}
|
|
else if (GDK_IS_PIXMAP_IMPL_QUARTZ (drawable))
|
|
CGContextRelease (cg_context);
|
|
}
|
|
|
|
void
|
|
_gdk_quartz_drawable_finish (GdkDrawable *drawable)
|
|
{
|
|
GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (drawable);
|
|
|
|
if (impl->cairo_surface)
|
|
{
|
|
cairo_surface_finish (impl->cairo_surface);
|
|
cairo_surface_set_user_data (impl->cairo_surface, &gdk_quartz_cairo_key,
|
|
NULL, NULL);
|
|
impl->cairo_surface = NULL;
|
|
}
|
|
}
|