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> 2007-03-10 Richard Hult <richard@imendio.com>
* gdk/quartz/gdkprivate-quartz.h: Add missing function signature to fix * gdk/quartz/gdkprivate-quartz.h: Add missing function signature to fix

View File

@ -1,6 +1,6 @@
/* gdkdrawable-quartz.c /* 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -19,57 +19,66 @@
*/ */
#include <config.h> #include <config.h>
#include <cairo-quartz.h> #include <cairo-quartz.h>
#include "gdkprivate-quartz.h" #include "gdkprivate-quartz.h"
static gpointer parent_class; static gpointer parent_class;
typedef struct { static cairo_user_data_key_t gdk_quartz_cairo_key;
GdkDrawable *drawable;
CGContextRef context;
} SurfaceInfo;
static cairo_user_data_key_t surface_info_key; typedef struct {
GdkDrawable *drawable;
CGContextRef cg_context;
} GdkQuartzCairoSurfaceData;
static void 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 * static cairo_surface_t *
gdk_quartz_ref_cairo_surface (GdkDrawable *drawable) gdk_quartz_ref_cairo_surface (GdkDrawable *drawable)
{ {
GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (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) && if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable) &&
GDK_WINDOW_DESTROYED (impl->wrapper)) GDK_WINDOW_DESTROYED (impl->wrapper))
return NULL; return NULL;
context = gdk_quartz_drawable_get_context (drawable, TRUE); if (!impl->cairo_surface)
if (!context) {
return NULL; 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); impl->cairo_surface = cairo_quartz_surface_create_for_cg_context (cg_context, width, height);
info->drawable = drawable;
info->context = context;
cairo_surface_set_user_data (surface, &surface_info_key, surface_data = g_new (GdkQuartzCairoSurfaceData, 1);
info, surface_info_destroy); surface_data->drawable = drawable;
return surface; 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 static void
@ -588,33 +597,47 @@ CGContextRef
gdk_quartz_drawable_get_context (GdkDrawable *drawable, gdk_quartz_drawable_get_context (GdkDrawable *drawable,
gboolean antialias) 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)) if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable))
{ {
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (drawable); GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (drawable);
CGContextRef context;
impl->pool = [[NSAutoreleasePool alloc] init]; /* Lock focus when not called as part of begin/end paint cycle.
* This is needed to allow broken apps that draw outside of expose
if (![impl->view lockFocusIfCanDraw]) * to still work (somewhat).
*/
if (window_impl->begin_paint_count == 0)
{ {
[impl->pool release]; window_impl->pool = [[NSAutoreleasePool alloc] init];
return NULL; if (![window_impl->view lockFocusIfCanDraw])
{
[window_impl->pool release];
window_impl->pool = NULL;
return NULL;
}
} }
context = [[NSGraphicsContext currentContext] graphicsPort]; cg_context = [[NSGraphicsContext currentContext] graphicsPort];
CGContextSaveGState (cg_context);
CGContextSaveGState (context); CGContextSetAllowsAntialiasing (cg_context, antialias);
CGContextSetAllowsAntialiasing (context, antialias);
/* We'll emulate the clipping caused by double buffering here */ /* 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 rect;
CGRect *cg_rects; CGRect *cg_rects;
GdkRectangle *rects; GdkRectangle *rects;
gint n_rects, i; gint n_rects, i;
gdk_region_get_rectangles (impl->paint_clip_region, gdk_region_get_rectangles (window_impl->paint_clip_region,
&rects, &n_rects); &rects, &n_rects);
if (n_rects == 1) if (n_rects == 1)
@ -630,60 +653,75 @@ gdk_quartz_drawable_get_context (GdkDrawable *drawable,
cg_rects[i].size.height = rects[i].height; cg_rects[i].size.height = rects[i].height;
} }
CGContextClipToRects (context, cg_rects, n_rects); CGContextClipToRects (cg_context, cg_rects, n_rects);
g_free (rects); g_free (rects);
if (cg_rects != &rect) if (cg_rects != &rect)
g_free (cg_rects); g_free (cg_rects);
} }
return context;
} }
else if (GDK_IS_PIXMAP_IMPL_QUARTZ (drawable)) else if (GDK_IS_PIXMAP_IMPL_QUARTZ (drawable))
{ {
GdkPixmapImplQuartz *impl = GDK_PIXMAP_IMPL_QUARTZ (drawable); GdkPixmapImplQuartz *impl = GDK_PIXMAP_IMPL_QUARTZ (drawable);
CGContextRef context;
context = CGBitmapContextCreate (impl->data, cg_context = CGBitmapContextCreate (impl->data,
CGImageGetWidth (impl->image), CGImageGetWidth (impl->image),
CGImageGetHeight (impl->image), CGImageGetHeight (impl->image),
CGImageGetBitsPerComponent (impl->image), CGImageGetBitsPerComponent (impl->image),
CGImageGetBytesPerRow (impl->image), CGImageGetBytesPerRow (impl->image),
CGImageGetColorSpace (impl->image), CGImageGetColorSpace (impl->image),
CGImageGetBitmapInfo (impl->image)); CGImageGetBitmapInfo (impl->image));
CGContextSetAllowsAntialiasing (context, antialias); CGContextSetAllowsAntialiasing (cg_context, antialias);
}
return context; else
{
g_warning ("Tried to create CGContext for something not a quartz window or pixmap");
cg_context = NULL;
} }
g_assert_not_reached (); return cg_context;
return NULL;
} }
void void
gdk_quartz_drawable_release_context (GdkDrawable *drawable, gdk_quartz_drawable_release_context (GdkDrawable *drawable,
CGContextRef context) CGContextRef cg_context)
{ {
if (!context)
return;
if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable)) if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable))
{ {
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (drawable); GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (drawable);
CGContextRestoreGState (context); CGContextRestoreGState (cg_context);
CGContextSetAllowsAntialiasing (context, TRUE); CGContextSetAllowsAntialiasing (cg_context, TRUE);
if (impl->in_paint_rect_count == 0 && /* Only flush and unlock if called outside the expose, since it's
impl->begin_paint_count == 0) * already handled for otherwise.
CGContextFlush (context); */
if (window_impl->in_paint_rect_count == 0 && window_impl->begin_paint_count == 0)
{
CGContextFlush (cg_context);
[window_impl->view unlockFocus];
}
[impl->view unlockFocus]; if (window_impl->pool)
[impl->pool release]; {
[window_impl->pool release];
window_impl->pool = NULL;
}
} }
else if (GDK_IS_PIXMAP_IMPL_QUARTZ (drawable)) 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)
{ {
CGContextRelease (context); 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 struct _GdkDrawableImplQuartz
{ {
GdkDrawable parent_instance; GdkDrawable parent_instance;
GdkDrawable *wrapper; GdkDrawable *wrapper;
GdkColormap *colormap; GdkColormap *colormap;
cairo_surface_t *cairo_surface;
}; };
struct _GdkDrawableImplQuartzClass struct _GdkDrawableImplQuartzClass
@ -52,10 +54,11 @@ struct _GdkDrawableImplQuartzClass
GdkDrawableClass parent_class; GdkDrawableClass parent_class;
}; };
GType gdk_drawable_impl_quartz_get_type (void); GType gdk_drawable_impl_quartz_get_type (void);
CGContextRef gdk_quartz_drawable_get_context (GdkDrawable *drawable,
CGContextRef gdk_quartz_drawable_get_context (GdkDrawable *drawable, gboolean antialias); gboolean antialias);
void gdk_quartz_drawable_release_context (GdkDrawable *drawable, CGContextRef context); void gdk_quartz_drawable_release_context (GdkDrawable *drawable,
CGContextRef context);
G_END_DECLS G_END_DECLS

View File

@ -48,6 +48,8 @@ gdk_pixmap_impl_quartz_finalize (GObject *object)
CGImageRelease (impl->image); CGImageRelease (impl->image);
_gdk_quartz_drawable_finish (GDK_DRAWABLE (impl));
G_OBJECT_CLASS (parent_class)->finalize (object); 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); NSEvent *_gdk_quartz_event_loop_get_current (void);
void _gdk_quartz_event_loop_release_current (void); void _gdk_quartz_event_loop_release_current (void);
void _gdk_quartz_drawable_finish (GdkDrawable *drawable);
#endif /* __GDK_PRIVATE_QUARTZ_H__ */ #endif /* __GDK_PRIVATE_QUARTZ_H__ */

View File

@ -1,7 +1,7 @@
/* gdkwindow-quartz.c /* gdkwindow-quartz.c
* *
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -145,19 +145,21 @@ gdk_window_impl_quartz_begin_paint_region (GdkPaintable *paintable,
GdkRegion *region) GdkRegion *region)
{ {
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (paintable); GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (paintable);
GdkDrawableImplQuartz *drawable_impl;
int n_rects; int n_rects;
GdkRectangle *rects; GdkRectangle *rects;
GdkPixmap *bg_pixmap; GdkPixmap *bg_pixmap;
GdkWindow *window; 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) if (impl->begin_paint_count == 0)
impl->paint_clip_region = gdk_region_copy (region); impl->paint_clip_region = gdk_region_copy (region);
else else
gdk_region_union (impl->paint_clip_region, region); gdk_region_union (impl->paint_clip_region, region);
impl->begin_paint_count ++; impl->begin_paint_count++;
if (bg_pixmap == GDK_NO_BG) if (bg_pixmap == GDK_NO_BG)
return; return;
@ -166,24 +168,24 @@ gdk_window_impl_quartz_begin_paint_region (GdkPaintable *paintable,
if (bg_pixmap == NULL) 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; 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++) for (i = 0; i < n_rects; i++)
{ {
gfloat r, g, b, a; CGContextSetRGBFillColor (cg_context, r, g, b, a);
CGContextFillRect (cg_context,
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,
CGRectMake (rects[i].x, rects[i].y, CGRectMake (rects[i].x, rects[i].y,
rects[i].width, rects[i].height)); 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 else
{ {
@ -194,7 +196,7 @@ gdk_window_impl_quartz_begin_paint_region (GdkPaintable *paintable,
x_offset = y_offset = 0; 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) while (window && ((GdkWindowObject *) window)->bg_pixmap == GDK_PARENT_RELATIVE_BG)
{ {
/* If this window should have the same background as the parent, /* If this window should have the same background as the parent,
@ -230,7 +232,7 @@ gdk_window_impl_quartz_begin_paint_region (GdkPaintable *paintable,
x += width; x += width;
} }
g_object_unref (G_OBJECT (gc)); g_object_unref (gc);
} }
g_free (rects); g_free (rects);
@ -241,7 +243,7 @@ gdk_window_impl_quartz_end_paint (GdkPaintable *paintable)
{ {
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (paintable); GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (paintable);
impl->begin_paint_count --; impl->begin_paint_count--;
if (impl->begin_paint_count == 0) 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); g_slist_foreach (old_update_windows, (GFunc) g_object_ref, NULL);
GDK_QUARTZ_ALLOC_POOL;
while (tmp_list) while (tmp_list)
{ {
GdkWindowObject *private = tmp_list->data; GdkWindowObject *private = tmp_list->data;
@ -275,18 +279,14 @@ gdk_window_quartz_process_all_updates (void)
gdk_region_destroy (private->update_area); gdk_region_destroy (private->update_area);
private->update_area = NULL; private->update_area = NULL;
GDK_QUARTZ_ALLOC_POOL;
for (i = 0; i < n_rects; i++) for (i = 0; i < n_rects; i++)
{ {
[impl->view setNeedsDisplayInRect:NSMakeRect (rects[i].x, rects[i].y, [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]; [impl->view displayIfNeeded];
GDK_QUARTZ_RELEASE_POOL;
g_free (rects); g_free (rects);
} }
@ -294,6 +294,8 @@ gdk_window_quartz_process_all_updates (void)
tmp_list = tmp_list->next; tmp_list = tmp_list->next;
} }
GDK_QUARTZ_RELEASE_POOL;
g_slist_free (old_update_windows); g_slist_free (old_update_windows);
} }
@ -373,25 +375,25 @@ _gdk_window_impl_quartz_get_type (void)
if (!object_type) if (!object_type)
{ {
static const GTypeInfo object_info = const GTypeInfo object_info =
{ {
sizeof (GdkWindowImplQuartzClass), sizeof (GdkWindowImplQuartzClass),
(GBaseInitFunc) NULL, (GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL, (GBaseFinalizeFunc) NULL,
(GClassInitFunc) gdk_window_impl_quartz_class_init, (GClassInitFunc) gdk_window_impl_quartz_class_init,
NULL, /* class_finalize */ NULL, /* class_finalize */
NULL, /* class_data */ NULL, /* class_data */
sizeof (GdkWindowImplQuartz), sizeof (GdkWindowImplQuartz),
0, /* n_preallocs */ 0, /* n_preallocs */
(GInstanceInitFunc) gdk_window_impl_quartz_init, (GInstanceInitFunc) gdk_window_impl_quartz_init,
}; };
static const GInterfaceInfo paintable_info = const GInterfaceInfo paintable_info =
{ {
(GInterfaceInitFunc) gdk_window_impl_quartz_paintable_init, (GInterfaceInitFunc) gdk_window_impl_quartz_paintable_init,
NULL, NULL,
NULL NULL
}; };
object_type = g_type_register_static (GDK_TYPE_DRAWABLE_IMPL_QUARTZ, object_type = g_type_register_static (GDK_TYPE_DRAWABLE_IMPL_QUARTZ,
"GdkWindowImplQuartz", "GdkWindowImplQuartz",
@ -737,6 +739,8 @@ _gdk_windowing_window_destroy (GdkWindow *window,
GDK_QUARTZ_ALLOC_POOL; GDK_QUARTZ_ALLOC_POOL;
_gdk_quartz_drawable_finish (GDK_DRAWABLE (impl));
if (impl->toplevel) if (impl->toplevel)
[impl->toplevel close]; [impl->toplevel close];
else if (impl->view) else if (impl->view)
@ -908,10 +912,10 @@ move_resize_window_internal (GdkWindow *window,
{ {
if (!private->input_only) if (!private->input_only)
{ {
[impl->view setFrame:NSMakeRect (private->x, private->y, NSRect nsrect;
impl->width, impl->height)];
/* 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]; [impl->view setNeedsDisplay:YES];
} }
} }