1 /* gdkdrawable-quartz.c
3 * Copyright (C) 2005, 2006 Imendio AB
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
23 #include <cairo/cairo-quartz.h>
24 #include "gdkprivate-quartz.h"
26 static gpointer parent_class;
29 GdkDrawable *drawable;
33 static cairo_user_data_key_t surface_info_key;
36 surface_info_destroy (void *data)
38 SurfaceInfo *info = data;
40 _gdk_quartz_drawable_release_context (info->drawable, info->context);
45 static cairo_surface_t *
46 gdk_quartz_ref_cairo_surface (GdkDrawable *drawable)
48 GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (drawable);
51 cairo_surface_t *surface;
54 if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable) &&
55 GDK_WINDOW_DESTROYED (impl->wrapper))
58 context = _gdk_quartz_drawable_get_context (drawable, TRUE);
62 gdk_drawable_get_size (drawable, &width, &height);
64 surface = cairo_quartz_surface_create (context, TRUE, width, height);
66 info = g_new (SurfaceInfo, 1);
67 info->drawable = drawable;
68 info->context = context;
70 cairo_surface_set_user_data (surface, &surface_info_key,
71 info, surface_info_destroy);
76 gdk_quartz_set_colormap (GdkDrawable *drawable,
77 GdkColormap *colormap)
79 GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (drawable);
81 if (impl->colormap == colormap)
85 g_object_unref (impl->colormap);
86 impl->colormap = colormap;
88 g_object_ref (impl->colormap);
92 gdk_quartz_get_colormap (GdkDrawable *drawable)
94 return GDK_DRAWABLE_IMPL_QUARTZ (drawable)->colormap;
98 gdk_quartz_get_screen (GdkDrawable *drawable)
104 gdk_quartz_get_visual (GdkDrawable *drawable)
106 return gdk_drawable_get_visual (GDK_DRAWABLE_IMPL_QUARTZ (drawable)->wrapper);
110 gdk_quartz_get_depth (GdkDrawable *drawable)
112 /* This is a bit bogus but I'm not sure the other way is better */
114 return gdk_drawable_get_depth (GDK_DRAWABLE_IMPL_QUARTZ (drawable)->wrapper);
118 gdk_quartz_draw_rectangle (GdkDrawable *drawable,
126 CGContextRef context = _gdk_quartz_drawable_get_context (drawable, FALSE);
127 CGRect rect = CGRectMake (x + 0.5, y + 0.5, width, height);
132 _gdk_quartz_update_context_from_gc (context, gc);
136 _gdk_quartz_set_context_fill_color_from_pixel (context, gdk_drawable_get_colormap (drawable),
137 _gdk_gc_get_fg_pixel (gc));
138 CGContextFillRect (context, rect);
142 _gdk_quartz_set_context_stroke_color_from_pixel (context, gdk_drawable_get_colormap (drawable),
143 _gdk_gc_get_fg_pixel (gc));
144 CGContextStrokeRect (context, rect);
147 _gdk_quartz_drawable_release_context (drawable, context);
151 gdk_quartz_draw_arc (GdkDrawable *drawable,
161 CGContextRef context = _gdk_quartz_drawable_get_context (drawable, FALSE);
162 float start_angle, end_angle;
167 _gdk_quartz_update_context_from_gc (context, gc);
169 CGContextSaveGState (context);
171 CGContextTranslateCTM (context,
173 y + height / 2 + 0.5);
174 CGContextScaleCTM (context, 1.0, (float)height / width);
175 start_angle = (2 - (angle1 / (180.0 * 64.0))) * G_PI;
176 end_angle = start_angle - (angle2 / (180.0 * 64.0)) * G_PI;
180 _gdk_quartz_set_context_fill_color_from_pixel (context, gdk_drawable_get_colormap (drawable),
181 _gdk_gc_get_fg_pixel (gc));
183 CGContextMoveToPoint (context, 0, 0);
184 CGContextAddArc (context, 0, 0, width / 2,
185 start_angle, end_angle,
187 CGContextClosePath (context);
188 CGContextFillPath (context);
192 _gdk_quartz_set_context_stroke_color_from_pixel (context, gdk_drawable_get_colormap (drawable),
193 _gdk_gc_get_fg_pixel (gc));
194 CGContextAddArc (context, 0, 0, width / 2,
195 start_angle, end_angle,
197 CGContextStrokePath (context);
200 CGContextRestoreGState (context);
202 _gdk_quartz_drawable_release_context (drawable, context);
206 gdk_quartz_draw_polygon (GdkDrawable *drawable,
212 CGContextRef context = _gdk_quartz_drawable_get_context (drawable, FALSE);
218 _gdk_quartz_update_context_from_gc (context, gc);
221 _gdk_quartz_set_context_fill_color_from_pixel (context, gdk_drawable_get_colormap (drawable),
222 _gdk_gc_get_fg_pixel (gc));
224 _gdk_quartz_set_context_stroke_color_from_pixel (context, gdk_drawable_get_colormap (drawable),
225 _gdk_gc_get_fg_pixel (gc));
227 CGContextMoveToPoint (context, points[0].x + 0.5, points[0].y + 0.5);
228 for (i = 1; i < npoints; i++)
229 CGContextAddLineToPoint (context, points[i].x + 0.5, points[i].y + 0.5);
231 CGContextClosePath (context);
234 CGContextFillPath (context);
236 CGContextStrokePath (context);
238 _gdk_quartz_drawable_release_context (drawable, context);
242 gdk_quartz_draw_text (GdkDrawable *drawable,
250 /* FIXME: Implement */
254 gdk_quartz_draw_text_wc (GdkDrawable *drawable,
259 const GdkWChar *text,
262 /* FIXME: Implement */
266 gdk_quartz_draw_drawable (GdkDrawable *drawable,
276 int src_depth = gdk_drawable_get_depth (src);
277 int dest_depth = gdk_drawable_get_depth (drawable);
278 GdkDrawableImplQuartz *impl;
279 GdkDrawableImplQuartz *src_impl;
281 impl = GDK_DRAWABLE_IMPL_QUARTZ (drawable);
283 if (GDK_IS_DRAWABLE_IMPL_QUARTZ (src))
284 src_impl = GDK_DRAWABLE_IMPL_QUARTZ (src);
286 src_impl = GDK_DRAWABLE_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (src)->impl);
290 /* FIXME: src depth 1 is not supported yet */
292 else if (dest_depth != 0 && src_depth == dest_depth)
294 CGContextRef context = _gdk_quartz_drawable_get_context (drawable, FALSE);
299 _gdk_quartz_update_context_from_gc (context, gc);
301 CGContextSetBlendMode (context, kCGBlendModeNormal);
303 CGContextClipToRect (context, CGRectMake (xdest, ydest, width, height));
304 CGContextTranslateCTM (context, xdest - xsrc, ydest - ysrc);
305 CGContextDrawImage (context, CGRectMake(0, 0,
306 GDK_PIXMAP_IMPL_QUARTZ (src_impl)->width,
307 GDK_PIXMAP_IMPL_QUARTZ (src_impl)->height),
308 GDK_PIXMAP_IMPL_QUARTZ (src_impl)->image);
310 _gdk_quartz_drawable_release_context (drawable, context);
313 g_warning ("Attempt to draw a drawable with depth %d to a drawable with depth %d",
314 src_depth, dest_depth);
318 gdk_quartz_draw_points (GdkDrawable *drawable,
325 /* Just draw 1x1 rectangles */
326 for (i = 0; i < npoints; i++)
328 gdk_draw_rectangle (drawable, gc, TRUE,
329 points[i].x, points[i].y,
335 gdk_quartz_draw_segments (GdkDrawable *drawable,
340 CGContextRef context = _gdk_quartz_drawable_get_context (drawable, FALSE);
346 _gdk_quartz_update_context_from_gc (context, gc);
347 _gdk_quartz_set_context_stroke_color_from_pixel (context, gdk_drawable_get_colormap (drawable),
348 _gdk_gc_get_fg_pixel (gc));
350 for (i = 0; i < nsegs; i++)
352 CGContextMoveToPoint (context, segs[i].x1 + 0.5, segs[i].y1 + 0.5);
353 CGContextAddLineToPoint (context, segs[i].x2 + 0.5, segs[i].y2 + 0.5);
356 CGContextStrokePath (context);
358 _gdk_quartz_drawable_release_context (drawable, context);
362 gdk_quartz_draw_lines (GdkDrawable *drawable,
367 CGContextRef context = _gdk_quartz_drawable_get_context (drawable, FALSE);
373 _gdk_quartz_update_context_from_gc (context, gc);
374 _gdk_quartz_set_context_stroke_color_from_pixel (context, gdk_drawable_get_colormap (drawable),
375 _gdk_gc_get_fg_pixel (gc));
377 for (i = 1; i < npoints; i++)
379 CGContextMoveToPoint (context, points[i - 1].x + 0.5, points[i - 1].y + 0.5);
380 CGContextAddLineToPoint (context, points[i].x + 0.5, points[i].y + 0.5);
383 CGContextStrokePath (context);
385 _gdk_quartz_drawable_release_context (drawable, context);
389 gdk_quartz_draw_pixbuf (GdkDrawable *drawable,
402 CGContextRef context = _gdk_quartz_drawable_get_context (drawable, FALSE);
403 CGColorSpaceRef colorspace;
404 CGDataProviderRef data_provider;
407 int rowstride, pixbuf_width, pixbuf_height;
413 pixbuf_width = gdk_pixbuf_get_width (pixbuf);
414 pixbuf_height = gdk_pixbuf_get_height (pixbuf);
415 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
416 has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
418 data = gdk_pixbuf_get_pixels (pixbuf);
420 colorspace = CGColorSpaceCreateDeviceRGB ();
421 data_provider = CGDataProviderCreateWithData (NULL, data, pixbuf_height * rowstride, NULL);
423 image = CGImageCreate (pixbuf_width, pixbuf_height, 8,
424 has_alpha ? 32 : 24, rowstride,
426 has_alpha ? kCGImageAlphaLast : 0,
427 data_provider, NULL, FALSE,
428 kCGRenderingIntentDefault);
430 CGDataProviderRelease (data_provider);
431 CGColorSpaceRelease (colorspace);
433 _gdk_quartz_update_context_from_gc (context, gc);
435 CGContextSetBlendMode (context, kCGBlendModeNormal);
437 CGContextClipToRect (context, CGRectMake (dest_x, dest_y, width, height));
438 CGContextTranslateCTM (context, dest_x - src_x, dest_y - src_y + pixbuf_height);
439 CGContextScaleCTM (context, 1, -1);
441 CGContextDrawImage (context, CGRectMake (0, 0, pixbuf_width, pixbuf_height), image);
442 CGImageRelease (image);
444 _gdk_quartz_drawable_release_context (drawable, context);
448 gdk_quartz_draw_image (GdkDrawable *drawable,
458 CGContextRef context = _gdk_quartz_drawable_get_context (drawable, FALSE);
459 CGColorSpaceRef colorspace;
460 CGDataProviderRef data_provider;
466 colorspace = CGColorSpaceCreateDeviceRGB ();
467 data_provider = CGDataProviderCreateWithData (NULL, image->mem, image->height * image->bpl, NULL);
469 /* FIXME: Make sure that this function draws 32-bit images correctly,
470 * also check endianness wrt kCGImageAlphaNoneSkipFirst */
471 cgimage = CGImageCreate (image->width, image->height, 8,
474 kCGImageAlphaNoneSkipFirst,
475 data_provider, NULL, FALSE, kCGRenderingIntentDefault);
477 CGDataProviderRelease (data_provider);
478 CGColorSpaceRelease (colorspace);
480 _gdk_quartz_update_context_from_gc (context, gc);
482 CGContextSetBlendMode (context, kCGBlendModeNormal);
484 CGContextClipToRect (context, CGRectMake (xdest, ydest, width, height));
485 CGContextTranslateCTM (context, xdest - xsrc, ydest - ysrc + image->height);
486 CGContextScaleCTM (context, 1, -1);
488 CGContextDrawImage (context, CGRectMake (0, 0, image->width, image->height), cgimage);
489 CGImageRelease (cgimage);
491 _gdk_quartz_drawable_release_context (drawable, context);
495 gdk_drawable_impl_quartz_finalize (GObject *object)
497 GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (object);
500 g_object_unref (impl->colormap);
502 G_OBJECT_CLASS (parent_class)->finalize (object);
506 gdk_drawable_impl_quartz_class_init (GdkDrawableImplQuartzClass *klass)
508 GObjectClass *object_class = G_OBJECT_CLASS (klass);
509 GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
511 parent_class = g_type_class_peek_parent (klass);
513 object_class->finalize = gdk_drawable_impl_quartz_finalize;
515 drawable_class->create_gc = _gdk_quartz_gc_new;
516 drawable_class->draw_rectangle = gdk_quartz_draw_rectangle;
517 drawable_class->draw_arc = gdk_quartz_draw_arc;
518 drawable_class->draw_polygon = gdk_quartz_draw_polygon;
519 drawable_class->draw_text = gdk_quartz_draw_text;
520 drawable_class->draw_text_wc = gdk_quartz_draw_text_wc;
521 drawable_class->draw_drawable = gdk_quartz_draw_drawable;
522 drawable_class->draw_points = gdk_quartz_draw_points;
523 drawable_class->draw_segments = gdk_quartz_draw_segments;
524 drawable_class->draw_lines = gdk_quartz_draw_lines;
525 drawable_class->draw_image = gdk_quartz_draw_image;
526 drawable_class->draw_pixbuf = gdk_quartz_draw_pixbuf;
528 drawable_class->ref_cairo_surface = gdk_quartz_ref_cairo_surface;
530 drawable_class->set_colormap = gdk_quartz_set_colormap;
531 drawable_class->get_colormap = gdk_quartz_get_colormap;
533 drawable_class->get_depth = gdk_quartz_get_depth;
534 drawable_class->get_screen = gdk_quartz_get_screen;
535 drawable_class->get_visual = gdk_quartz_get_visual;
537 drawable_class->_copy_to_image = _gdk_quartz_copy_to_image;
541 gdk_drawable_impl_quartz_get_type (void)
543 static GType object_type = 0;
547 static const GTypeInfo object_info =
549 sizeof (GdkDrawableImplQuartzClass),
550 (GBaseInitFunc) NULL,
551 (GBaseFinalizeFunc) NULL,
552 (GClassInitFunc) gdk_drawable_impl_quartz_class_init,
553 NULL, /* class_finalize */
554 NULL, /* class_data */
555 sizeof (GdkDrawableImplQuartz),
557 (GInstanceInitFunc) NULL,
560 object_type = g_type_register_static (GDK_TYPE_DRAWABLE,
561 "GdkDrawableImplQuartz",
569 _gdk_quartz_drawable_get_context (GdkDrawable *drawable, gboolean antialias)
571 if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable))
573 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (drawable);
574 CGContextRef context;
576 impl->pool = [[NSAutoreleasePool alloc] init];
578 if (![impl->view lockFocusIfCanDraw])
580 [impl->pool release];
584 context = [[NSGraphicsContext currentContext] graphicsPort];
586 CGContextSaveGState (context);
587 CGContextSetAllowsAntialiasing (context, antialias);
591 else if (GDK_IS_PIXMAP_IMPL_QUARTZ (drawable))
593 GdkPixmapImplQuartz *impl = GDK_PIXMAP_IMPL_QUARTZ (drawable);
594 CGContextRef context;
596 context = CGBitmapContextCreate (impl->data,
597 CGImageGetWidth (impl->image),
598 CGImageGetHeight (impl->image),
599 CGImageGetBitsPerComponent (impl->image),
600 CGImageGetBytesPerRow (impl->image),
601 CGImageGetColorSpace (impl->image),
602 CGImageGetBitmapInfo (impl->image));
603 CGContextSetAllowsAntialiasing (context, antialias);
608 g_assert_not_reached ();
614 _gdk_quartz_drawable_release_context (GdkDrawable *drawable, CGContextRef context)
619 if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable))
621 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (drawable);
623 CGContextRestoreGState (context);
624 CGContextSetAllowsAntialiasing (context, TRUE);
626 [[NSGraphicsContext currentContext] flushGraphics];
627 [impl->view unlockFocus];
628 [impl->pool release];
630 else if (GDK_IS_PIXMAP_IMPL_QUARTZ (drawable))
632 CGContextRelease (context);