From d7a33adeda8799ea35eb907b930f271dfcbc5cbb Mon Sep 17 00:00:00 2001 From: Richard Hult Date: Sat, 10 Mar 2007 21:58:49 +0000 Subject: [PATCH] Update for the new quartz cairo surface API (#410442). Don't lock focus 2007-03-10 Richard Hult * 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 --- ChangeLog | 23 ++++ gdk/quartz/gdkdrawable-quartz.c | 186 +++++++++++++++++++------------- gdk/quartz/gdkdrawable-quartz.h | 17 +-- gdk/quartz/gdkpixmap-quartz.c | 2 + gdk/quartz/gdkprivate-quartz.h | 2 + gdk/quartz/gdkwindow-quartz.c | 114 ++++++++++---------- 6 files changed, 208 insertions(+), 136 deletions(-) diff --git a/ChangeLog b/ChangeLog index 73590f45a1..4aa766515e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2007-03-10 Richard Hult + + * 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 * gdk/quartz/gdkprivate-quartz.h: Add missing function signature to fix diff --git a/gdk/quartz/gdkdrawable-quartz.c b/gdk/quartz/gdkdrawable-quartz.c index 030f68362e..5b2a4da195 100644 --- a/gdk/quartz/gdkdrawable-quartz.c +++ b/gdk/quartz/gdkdrawable-quartz.c @@ -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 - #include #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; + } +} diff --git a/gdk/quartz/gdkdrawable-quartz.h b/gdk/quartz/gdkdrawable-quartz.h index 2f2f533d1a..f10441ff8e 100644 --- a/gdk/quartz/gdkdrawable-quartz.h +++ b/gdk/quartz/gdkdrawable-quartz.h @@ -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 diff --git a/gdk/quartz/gdkpixmap-quartz.c b/gdk/quartz/gdkpixmap-quartz.c index 8176e75d15..740321dca6 100644 --- a/gdk/quartz/gdkpixmap-quartz.c +++ b/gdk/quartz/gdkpixmap-quartz.c @@ -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); } diff --git a/gdk/quartz/gdkprivate-quartz.h b/gdk/quartz/gdkprivate-quartz.h index 0b4c3ebee3..4263563db5 100644 --- a/gdk/quartz/gdkprivate-quartz.h +++ b/gdk/quartz/gdkprivate-quartz.h @@ -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__ */ diff --git a/gdk/quartz/gdkwindow-quartz.c b/gdk/quartz/gdkwindow-quartz.c index 0789d0c94b..7e8c31957a 100644 --- a/gdk/quartz/gdkwindow-quartz.c +++ b/gdk/quartz/gdkwindow-quartz.c @@ -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]; } }