Update for the new quartz cairo surface API (#410442). Don't lock focus

2007-03-10  Richard Hult  <richard@imendio.com>

	* gdk/quartz/gdkdrawable-quartz.c:
	(gdk_quartz_drawable_get_context): Update for the new quartz cairo 
	surface API (#410442). Don't lock focus unless called outside of an 
	expose event.
	(gdk_quartz_drawable_release_context): Only flush the CG context and 
	unlock focus if called outside of expose.
	(gdk_quartz_ref_cairo_surface): Reuse the surface during its lifetime.
	(_gdk_quartz_drawable_finish): New function, used to free the cached
	cairo surface.

	* gdk/quartz/gdkwindow-quartz.c:
	(gdk_window_impl_quartz_begin_paint_region): A few small style changes.
	(gdk_window_quartz_process_all_updates): Move the autorelease pool
	allocation and freeing outside the loop.
	(_gdk_windowing_window_destroy): Finish the drawable.
	(move_resize_window_internal): Small cleanup and remove comment.
	(_gdk_window_impl_quartz_get_type): No need to make the type info
	static.

	* gdk/quartz/gdkpixmap-quartz.c: Finish the drawable.

svn path=/trunk/; revision=17463
This commit is contained in:
Richard Hult 2007-03-10 21:58:49 +00:00 committed by Richard Hult
parent 9493e135c7
commit d7a33adeda
6 changed files with 208 additions and 136 deletions

View File

@ -1,3 +1,26 @@
2007-03-10 Richard Hult <richard@imendio.com>
* gdk/quartz/gdkdrawable-quartz.c:
(gdk_quartz_ref_cairo_surface): Reuse the surface during its lifetime.
(gdk_quartz_drawable_get_context): Update for the new quartz cairo
surface API (#410442). Don't lock focus unless called outside of an
expose event.
(gdk_quartz_drawable_release_context): Only flush the CG context and
unlock focus if called outside of expose.
(_gdk_quartz_drawable_finish): New function, used to free the cached
cairo surface.
* gdk/quartz/gdkwindow-quartz.c:
(gdk_window_impl_quartz_begin_paint_region): A few small style changes.
(_gdk_window_impl_quartz_get_type): No need to make the type info
static.
(gdk_window_quartz_process_all_updates): Move the autorelease pool
allocation and freeing outside the loop.
(_gdk_windowing_window_destroy): Finish the drawable.
(move_resize_window_internal): Small cleanup and remove comment.
* gdk/quartz/gdkpixmap-quartz.c: Finish the drawable.
2007-03-10 Richard Hult <richard@imendio.com>
* gdk/quartz/gdkprivate-quartz.h: Add missing function signature to fix

View File

@ -1,6 +1,6 @@
/* gdkdrawable-quartz.c
*
* Copyright (C) 2005, 2006 Imendio AB
* 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
@ -19,57 +19,66 @@
*/
#include <config.h>
#include <cairo-quartz.h>
#include "gdkprivate-quartz.h"
static gpointer parent_class;
typedef struct {
GdkDrawable *drawable;
CGContextRef context;
} SurfaceInfo;
static cairo_user_data_key_t gdk_quartz_cairo_key;
static cairo_user_data_key_t surface_info_key;
typedef struct {
GdkDrawable *drawable;
CGContextRef cg_context;
} GdkQuartzCairoSurfaceData;
static void
surface_info_destroy (void *data)
gdk_quartz_cairo_surface_destroy (void *data)
{
SurfaceInfo *info = data;
GdkQuartzCairoSurfaceData *surface_data = data;
GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (surface_data->drawable);
gdk_quartz_drawable_release_context (info->drawable, info->context);
gdk_quartz_drawable_release_context (surface_data->drawable,
surface_data->cg_context);
g_free (info);
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);
CGContextRef context;
int width, height;
cairo_surface_t *surface;
SurfaceInfo *info;
if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable) &&
GDK_WINDOW_DESTROYED (impl->wrapper))
return NULL;
context = gdk_quartz_drawable_get_context (drawable, TRUE);
if (!context)
return NULL;
if (!impl->cairo_surface)
{
CGContextRef cg_context;
int width, height;
GdkQuartzCairoSurfaceData *surface_data;
gdk_drawable_get_size (drawable, &width, &height);
cg_context = gdk_quartz_drawable_get_context (drawable, TRUE);
if (!cg_context)
return NULL;
surface = cairo_quartz_surface_create (context, width, height, TRUE);
gdk_drawable_get_size (drawable, &width, &height);
info = g_new (SurfaceInfo, 1);
info->drawable = drawable;
info->context = context;
impl->cairo_surface = cairo_quartz_surface_create_for_cg_context (cg_context, width, height);
cairo_surface_set_user_data (surface, &surface_info_key,
info, surface_info_destroy);
return surface;
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
@ -588,33 +597,47 @@ CGContextRef
gdk_quartz_drawable_get_context (GdkDrawable *drawable,
gboolean antialias)
{
GdkDrawableImplQuartz *drawable_impl = GDK_DRAWABLE_IMPL_QUARTZ (drawable);
if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable) &&
GDK_WINDOW_DESTROYED (drawable_impl->wrapper))
return NULL;
CGContextRef cg_context;
if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable))
{
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (drawable);
CGContextRef context;
impl->pool = [[NSAutoreleasePool alloc] init];
if (![impl->view lockFocusIfCanDraw])
GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (drawable);
/* Lock focus when not called as part of begin/end paint cycle.
* This is needed to allow broken apps that draw outside of expose
* to still work (somewhat).
*/
if (window_impl->begin_paint_count == 0)
{
[impl->pool release];
return NULL;
window_impl->pool = [[NSAutoreleasePool alloc] init];
if (![window_impl->view lockFocusIfCanDraw])
{
[window_impl->pool release];
window_impl->pool = NULL;
return NULL;
}
}
context = [[NSGraphicsContext currentContext] graphicsPort];
CGContextSaveGState (context);
CGContextSetAllowsAntialiasing (context, antialias);
cg_context = [[NSGraphicsContext currentContext] graphicsPort];
CGContextSaveGState (cg_context);
CGContextSetAllowsAntialiasing (cg_context, antialias);
/* We'll emulate the clipping caused by double buffering here */
if (impl->begin_paint_count != 0)
if (window_impl->begin_paint_count != 0)
{
CGRect rect;
CGRect *cg_rects;
GdkRectangle *rects;
gint n_rects, i;
gdk_region_get_rectangles (impl->paint_clip_region,
gdk_region_get_rectangles (window_impl->paint_clip_region,
&rects, &n_rects);
if (n_rects == 1)
@ -630,60 +653,75 @@ gdk_quartz_drawable_get_context (GdkDrawable *drawable,
cg_rects[i].size.height = rects[i].height;
}
CGContextClipToRects (context, cg_rects, n_rects);
CGContextClipToRects (cg_context, cg_rects, n_rects);
g_free (rects);
if (cg_rects != &rect)
g_free (cg_rects);
}
return context;
}
else if (GDK_IS_PIXMAP_IMPL_QUARTZ (drawable))
{
GdkPixmapImplQuartz *impl = GDK_PIXMAP_IMPL_QUARTZ (drawable);
CGContextRef context;
context = CGBitmapContextCreate (impl->data,
CGImageGetWidth (impl->image),
CGImageGetHeight (impl->image),
CGImageGetBitsPerComponent (impl->image),
CGImageGetBytesPerRow (impl->image),
CGImageGetColorSpace (impl->image),
CGImageGetBitmapInfo (impl->image));
CGContextSetAllowsAntialiasing (context, antialias);
return context;
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;
}
g_assert_not_reached ();
return NULL;
return cg_context;
}
void
gdk_quartz_drawable_release_context (GdkDrawable *drawable,
CGContextRef context)
gdk_quartz_drawable_release_context (GdkDrawable *drawable,
CGContextRef cg_context)
{
if (!context)
return;
if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable))
{
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (drawable);
GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (drawable);
CGContextRestoreGState (context);
CGContextSetAllowsAntialiasing (context, TRUE);
CGContextRestoreGState (cg_context);
CGContextSetAllowsAntialiasing (cg_context, TRUE);
if (impl->in_paint_rect_count == 0 &&
impl->begin_paint_count == 0)
CGContextFlush (context);
/* Only flush and unlock if called outside the expose, since it's
* already handled for otherwise.
*/
if (window_impl->in_paint_rect_count == 0 && window_impl->begin_paint_count == 0)
{
CGContextFlush (cg_context);
[window_impl->view unlockFocus];
}
[impl->view unlockFocus];
[impl->pool release];
if (window_impl->pool)
{
[window_impl->pool release];
window_impl->pool = NULL;
}
}
else if (GDK_IS_PIXMAP_IMPL_QUARTZ (drawable))
{
CGContextRelease (context);
}
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;
}
}

View File

@ -40,11 +40,13 @@ typedef struct _GdkDrawableImplQuartzClass GdkDrawableImplQuartzClass;
struct _GdkDrawableImplQuartz
{
GdkDrawable parent_instance;
GdkDrawable parent_instance;
GdkDrawable *wrapper;
GdkDrawable *wrapper;
GdkColormap *colormap;
GdkColormap *colormap;
cairo_surface_t *cairo_surface;
};
struct _GdkDrawableImplQuartzClass
@ -52,10 +54,11 @@ struct _GdkDrawableImplQuartzClass
GdkDrawableClass parent_class;
};
GType gdk_drawable_impl_quartz_get_type (void);
CGContextRef gdk_quartz_drawable_get_context (GdkDrawable *drawable, gboolean antialias);
void gdk_quartz_drawable_release_context (GdkDrawable *drawable, CGContextRef context);
GType gdk_drawable_impl_quartz_get_type (void);
CGContextRef gdk_quartz_drawable_get_context (GdkDrawable *drawable,
gboolean antialias);
void gdk_quartz_drawable_release_context (GdkDrawable *drawable,
CGContextRef context);
G_END_DECLS

View File

@ -48,6 +48,8 @@ gdk_pixmap_impl_quartz_finalize (GObject *object)
CGImageRelease (impl->image);
_gdk_quartz_drawable_finish (GDK_DRAWABLE (impl));
G_OBJECT_CLASS (parent_class)->finalize (object);
}

View File

@ -168,4 +168,6 @@ void _gdk_quartz_event_loop_init (void);
NSEvent *_gdk_quartz_event_loop_get_current (void);
void _gdk_quartz_event_loop_release_current (void);
void _gdk_quartz_drawable_finish (GdkDrawable *drawable);
#endif /* __GDK_PRIVATE_QUARTZ_H__ */

View File

@ -1,7 +1,7 @@
/* gdkwindow-quartz.c
*
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
* Copyright (C) 2005 Imendio AB
* 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
@ -145,45 +145,47 @@ gdk_window_impl_quartz_begin_paint_region (GdkPaintable *paintable,
GdkRegion *region)
{
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (paintable);
GdkDrawableImplQuartz *drawable_impl;
int n_rects;
GdkRectangle *rects;
GdkPixmap *bg_pixmap;
GdkWindow *window;
bg_pixmap = GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_QUARTZ (impl)->wrapper)->bg_pixmap;
drawable_impl = GDK_DRAWABLE_IMPL_QUARTZ (impl);
bg_pixmap = GDK_WINDOW_OBJECT (drawable_impl->wrapper)->bg_pixmap;
if (impl->begin_paint_count == 0)
impl->paint_clip_region = gdk_region_copy (region);
else
gdk_region_union (impl->paint_clip_region, region);
impl->begin_paint_count ++;
impl->begin_paint_count++;
if (bg_pixmap == GDK_NO_BG)
return;
gdk_region_get_rectangles (region, &rects, &n_rects);
if (bg_pixmap == NULL)
{
CGContextRef context = gdk_quartz_drawable_get_context (GDK_DRAWABLE (impl), FALSE);
CGContextRef cg_context;
gfloat r, g, b, a;
gint i;
cg_context = gdk_quartz_drawable_get_context (GDK_DRAWABLE (impl), FALSE);
gdk_quartz_get_rgba_from_pixel (gdk_drawable_get_colormap (drawable_impl->wrapper),
GDK_WINDOW_OBJECT (drawable_impl->wrapper)->bg_color.pixel,
&r, &g, &b, &a);
for (i = 0; i < n_rects; i++)
{
gfloat r, g, b, a;
gdk_quartz_get_rgba_from_pixel (gdk_drawable_get_colormap (GDK_DRAWABLE_IMPL_QUARTZ (impl)->wrapper),
GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_QUARTZ (impl)->wrapper)->bg_color.pixel,
&r, &g, &b, &a);
CGContextSetRGBFillColor (context, r, g, b, a);
CGContextFillRect (context,
CGContextSetRGBFillColor (cg_context, r, g, b, a);
CGContextFillRect (cg_context,
CGRectMake (rects[i].x, rects[i].y,
rects[i].width, rects[i].height));
}
gdk_quartz_drawable_release_context (GDK_DRAWABLE (impl), context);
gdk_quartz_drawable_release_context (GDK_DRAWABLE (impl), cg_context);
}
else
{
@ -191,10 +193,10 @@ gdk_window_impl_quartz_begin_paint_region (GdkPaintable *paintable,
int x_offset, y_offset;
int width, height;
GdkGC *gc;
x_offset = y_offset = 0;
window = GDK_WINDOW (GDK_DRAWABLE_IMPL_QUARTZ (impl)->wrapper);
window = GDK_WINDOW (drawable_impl->wrapper);
while (window && ((GdkWindowObject *) window)->bg_pixmap == GDK_PARENT_RELATIVE_BG)
{
/* If this window should have the same background as the parent,
@ -210,9 +212,9 @@ gdk_window_impl_quartz_begin_paint_region (GdkPaintable *paintable,
* want to look into that for this.
*/
gc = gdk_gc_new (GDK_DRAWABLE (impl));
gdk_drawable_get_size (GDK_DRAWABLE (bg_pixmap), &width, &height);
x = -x_offset;
while (x < (rects[0].x + rects[0].width))
{
@ -229,10 +231,10 @@ gdk_window_impl_quartz_begin_paint_region (GdkPaintable *paintable,
}
x += width;
}
g_object_unref (G_OBJECT (gc));
g_object_unref (gc);
}
g_free (rects);
}
@ -241,7 +243,7 @@ gdk_window_impl_quartz_end_paint (GdkPaintable *paintable)
{
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (paintable);
impl->begin_paint_count --;
impl->begin_paint_count--;
if (impl->begin_paint_count == 0)
{
@ -261,6 +263,8 @@ gdk_window_quartz_process_all_updates (void)
g_slist_foreach (old_update_windows, (GFunc) g_object_ref, NULL);
GDK_QUARTZ_ALLOC_POOL;
while (tmp_list)
{
GdkWindowObject *private = tmp_list->data;
@ -275,18 +279,14 @@ gdk_window_quartz_process_all_updates (void)
gdk_region_destroy (private->update_area);
private->update_area = NULL;
GDK_QUARTZ_ALLOC_POOL;
for (i = 0; i < n_rects; i++)
{
[impl->view setNeedsDisplayInRect:NSMakeRect (rects[i].x, rects[i].y,
rects[i].width, rects[i].height)];
rects[i].width, rects[i].height)];
}
[impl->view displayIfNeeded];
GDK_QUARTZ_RELEASE_POOL;
g_free (rects);
}
@ -294,6 +294,8 @@ gdk_window_quartz_process_all_updates (void)
tmp_list = tmp_list->next;
}
GDK_QUARTZ_RELEASE_POOL;
g_slist_free (old_update_windows);
}
@ -373,25 +375,25 @@ _gdk_window_impl_quartz_get_type (void)
if (!object_type)
{
static const GTypeInfo object_info =
{
sizeof (GdkWindowImplQuartzClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gdk_window_impl_quartz_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GdkWindowImplQuartz),
0, /* n_preallocs */
(GInstanceInitFunc) gdk_window_impl_quartz_init,
};
static const GInterfaceInfo paintable_info =
{
(GInterfaceInitFunc) gdk_window_impl_quartz_paintable_init,
NULL,
NULL
};
const GTypeInfo object_info =
{
sizeof (GdkWindowImplQuartzClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gdk_window_impl_quartz_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GdkWindowImplQuartz),
0, /* n_preallocs */
(GInstanceInitFunc) gdk_window_impl_quartz_init,
};
const GInterfaceInfo paintable_info =
{
(GInterfaceInitFunc) gdk_window_impl_quartz_paintable_init,
NULL,
NULL
};
object_type = g_type_register_static (GDK_TYPE_DRAWABLE_IMPL_QUARTZ,
"GdkWindowImplQuartz",
@ -400,7 +402,7 @@ _gdk_window_impl_quartz_get_type (void)
GDK_TYPE_PAINTABLE,
&paintable_info);
}
return object_type;
}
@ -737,6 +739,8 @@ _gdk_windowing_window_destroy (GdkWindow *window,
GDK_QUARTZ_ALLOC_POOL;
_gdk_quartz_drawable_finish (GDK_DRAWABLE (impl));
if (impl->toplevel)
[impl->toplevel close];
else if (impl->view)
@ -908,10 +912,10 @@ move_resize_window_internal (GdkWindow *window,
{
if (!private->input_only)
{
[impl->view setFrame:NSMakeRect (private->x, private->y,
impl->width, impl->height)];
NSRect nsrect;
/* FIXME: Maybe we should use setNeedsDisplayInRect instead */
nsrect = NSMakeRect (private->x, private->y, impl->width, impl->height);
[impl->view setFrame: nsrect];
[impl->view setNeedsDisplay:YES];
}
}