1 /* gdkdrawable-quartz.c
3 * Copyright (C) 2005-2007 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-quartz.h>
24 #include "gdkprivate-quartz.h"
26 static gpointer parent_class;
28 static cairo_user_data_key_t gdk_quartz_cairo_key;
31 GdkDrawable *drawable;
32 CGContextRef cg_context;
33 } GdkQuartzCairoSurfaceData;
36 _gdk_windowing_set_cairo_surface_size (cairo_surface_t *surface,
40 /* This is not supported with quartz surfaces. */
45 gdk_quartz_cairo_surface_destroy (void *data)
47 GdkQuartzCairoSurfaceData *surface_data = data;
48 GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (surface_data->drawable);
50 impl->cairo_surface = NULL;
52 gdk_quartz_drawable_release_context (surface_data->drawable,
53 surface_data->cg_context);
55 g_free (surface_data);
58 static cairo_surface_t *
59 gdk_quartz_create_cairo_surface (GdkDrawable *drawable,
63 CGContextRef cg_context;
64 GdkQuartzCairoSurfaceData *surface_data;
65 cairo_surface_t *surface;
67 cg_context = gdk_quartz_drawable_get_context (drawable, TRUE);
72 surface_data = g_new (GdkQuartzCairoSurfaceData, 1);
73 surface_data->drawable = drawable;
74 surface_data->cg_context = cg_context;
76 surface = cairo_quartz_surface_create_for_cg_context (cg_context,
79 cairo_surface_set_user_data (surface, &gdk_quartz_cairo_key,
81 gdk_quartz_cairo_surface_destroy);
86 static cairo_surface_t *
87 gdk_quartz_ref_cairo_surface (GdkDrawable *drawable)
89 GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (drawable);
91 if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable) &&
92 GDK_WINDOW_DESTROYED (impl->wrapper))
95 if (!impl->cairo_surface)
99 gdk_drawable_get_size (drawable, &width, &height);
100 impl->cairo_surface = gdk_quartz_create_cairo_surface (drawable,
104 cairo_surface_reference (impl->cairo_surface);
106 return impl->cairo_surface;
110 gdk_quartz_set_colormap (GdkDrawable *drawable,
111 GdkColormap *colormap)
113 GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (drawable);
115 if (impl->colormap == colormap)
119 g_object_unref (impl->colormap);
120 impl->colormap = colormap;
122 g_object_ref (impl->colormap);
126 gdk_quartz_get_colormap (GdkDrawable *drawable)
128 return GDK_DRAWABLE_IMPL_QUARTZ (drawable)->colormap;
132 gdk_quartz_get_screen (GdkDrawable *drawable)
138 gdk_quartz_get_visual (GdkDrawable *drawable)
140 return gdk_drawable_get_visual (GDK_DRAWABLE_IMPL_QUARTZ (drawable)->wrapper);
144 gdk_quartz_get_depth (GdkDrawable *drawable)
146 /* This is a bit bogus but I'm not sure the other way is better */
148 return gdk_drawable_get_depth (GDK_DRAWABLE_IMPL_QUARTZ (drawable)->wrapper);
152 gdk_drawable_impl_quartz_finalize (GObject *object)
154 GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (object);
157 g_object_unref (impl->colormap);
159 G_OBJECT_CLASS (parent_class)->finalize (object);
163 gdk_drawable_impl_quartz_class_init (GdkDrawableImplQuartzClass *klass)
165 GObjectClass *object_class = G_OBJECT_CLASS (klass);
166 GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
168 parent_class = g_type_class_peek_parent (klass);
170 object_class->finalize = gdk_drawable_impl_quartz_finalize;
172 drawable_class->ref_cairo_surface = gdk_quartz_ref_cairo_surface;
173 drawable_class->create_cairo_surface = gdk_quartz_create_cairo_surface;
175 drawable_class->set_colormap = gdk_quartz_set_colormap;
176 drawable_class->get_colormap = gdk_quartz_get_colormap;
178 drawable_class->get_depth = gdk_quartz_get_depth;
179 drawable_class->get_screen = gdk_quartz_get_screen;
180 drawable_class->get_visual = gdk_quartz_get_visual;
184 gdk_drawable_impl_quartz_get_type (void)
186 static GType object_type = 0;
190 const GTypeInfo object_info =
192 sizeof (GdkDrawableImplQuartzClass),
193 (GBaseInitFunc) NULL,
194 (GBaseFinalizeFunc) NULL,
195 (GClassInitFunc) gdk_drawable_impl_quartz_class_init,
196 NULL, /* class_finalize */
197 NULL, /* class_data */
198 sizeof (GdkDrawableImplQuartz),
200 (GInstanceInitFunc) NULL,
203 object_type = g_type_register_static (GDK_TYPE_DRAWABLE,
204 "GdkDrawableImplQuartz",
212 gdk_quartz_drawable_get_context (GdkDrawable *drawable,
215 if (!GDK_DRAWABLE_IMPL_QUARTZ_GET_CLASS (drawable)->get_context)
217 g_warning ("%s doesn't implement GdkDrawableImplQuartzClass::get_context()",
218 G_OBJECT_TYPE_NAME (drawable));
222 return GDK_DRAWABLE_IMPL_QUARTZ_GET_CLASS (drawable)->get_context (drawable, antialias);
225 /* Help preventing "beam sync penalty" where CG makes all graphics code
226 * block until the next vsync if we try to flush (including call display on
227 * a view) too often. We do this by limiting the manual flushing done
228 * outside of expose calls to less than some frequency when measured over
229 * the last 4 flushes. This is a bit arbitray, but seems to make it possible
230 * for some quick manual flushes (such as gtkruler or gimp's marching ants)
231 * without hitting the max flush frequency.
233 * If drawable NULL, no flushing is done, only registering that a flush was
237 _gdk_quartz_drawable_flush (GdkDrawable *drawable)
239 static struct timeval prev_tv;
240 static gint intervals[4];
245 gettimeofday (&tv, NULL);
246 ms = (tv.tv_sec - prev_tv.tv_sec) * 1000 + (tv.tv_usec - prev_tv.tv_usec) / 1000;
247 intervals[index++ % 4] = ms;
251 ms = intervals[0] + intervals[1] + intervals[2] + intervals[3];
253 /* ~25Hz on average. */
256 if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable))
258 GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (drawable);
260 [window_impl->toplevel flushWindow];
271 gdk_quartz_drawable_release_context (GdkDrawable *drawable,
272 CGContextRef cg_context)
274 if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable))
276 GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (drawable);
278 CGContextRestoreGState (cg_context);
279 CGContextSetAllowsAntialiasing (cg_context, TRUE);
281 /* See comment in gdk_quartz_drawable_get_context(). */
282 if (window_impl->in_paint_rect_count == 0)
284 _gdk_quartz_drawable_flush (drawable);
285 [window_impl->view unlockFocus];
288 else if (GDK_IS_PIXMAP_IMPL_QUARTZ (drawable))
289 CGContextRelease (cg_context);
293 _gdk_quartz_drawable_finish (GdkDrawable *drawable)
295 GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (drawable);
297 if (impl->cairo_surface)
299 cairo_surface_finish (impl->cairo_surface);
300 cairo_surface_set_user_data (impl->cairo_surface, &gdk_quartz_cairo_key,
302 impl->cairo_surface = NULL;