]> Pileus Git - ~andy/gtk/blob - gdk/quartz/gdkdrawable-quartz.c
gdk: Remove gdk_windowing_create_cairo_surface()
[~andy/gtk] / gdk / quartz / gdkdrawable-quartz.c
1 /* gdkdrawable-quartz.c
2  *
3  * Copyright (C) 2005-2007 Imendio AB
4  *
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.
9  *
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.
14  *
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.
19  */
20
21 #include "config.h"
22 #include <sys/time.h>
23 #include <cairo-quartz.h>
24 #include "gdkprivate-quartz.h"
25
26 static gpointer parent_class;
27
28 static cairo_user_data_key_t gdk_quartz_cairo_key;
29
30 typedef struct {
31   GdkDrawable  *drawable;
32   CGContextRef  cg_context;
33 } GdkQuartzCairoSurfaceData;
34
35 gboolean
36 _gdk_windowing_set_cairo_surface_size (cairo_surface_t *surface,
37                                        int              width,
38                                        int              height)
39 {
40   /* This is not supported with quartz surfaces. */
41   return FALSE;
42 }
43
44 static void
45 gdk_quartz_cairo_surface_destroy (void *data)
46 {
47   GdkQuartzCairoSurfaceData *surface_data = data;
48   GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (surface_data->drawable);
49
50   impl->cairo_surface = NULL;
51
52   gdk_quartz_drawable_release_context (surface_data->drawable,
53                                        surface_data->cg_context);
54
55   g_free (surface_data);
56 }
57
58 static cairo_surface_t *
59 gdk_quartz_create_cairo_surface (GdkDrawable *drawable,
60                                  int          width,
61                                  int          height)
62 {
63   CGContextRef cg_context;
64   GdkQuartzCairoSurfaceData *surface_data;
65   cairo_surface_t *surface;
66
67   cg_context = gdk_quartz_drawable_get_context (drawable, TRUE);
68
69   if (!cg_context)
70     return NULL;
71
72   surface_data = g_new (GdkQuartzCairoSurfaceData, 1);
73   surface_data->drawable = drawable;
74   surface_data->cg_context = cg_context;
75
76   surface = cairo_quartz_surface_create_for_cg_context (cg_context,
77                                                         width, height);
78
79   cairo_surface_set_user_data (surface, &gdk_quartz_cairo_key,
80                                surface_data,
81                                gdk_quartz_cairo_surface_destroy);
82
83   return surface;
84 }
85
86 static cairo_surface_t *
87 gdk_quartz_ref_cairo_surface (GdkDrawable *drawable)
88 {
89   GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (drawable);
90
91   if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable) &&
92       GDK_WINDOW_DESTROYED (impl->wrapper))
93     return NULL;
94
95   if (!impl->cairo_surface)
96     {
97       int width, height;
98
99       gdk_drawable_get_size (drawable, &width, &height);
100       impl->cairo_surface = gdk_quartz_create_cairo_surface (drawable,
101                                                              width, height);
102     }
103   else
104     cairo_surface_reference (impl->cairo_surface);
105
106   return impl->cairo_surface;
107 }
108
109 static void
110 gdk_quartz_set_colormap (GdkDrawable *drawable,
111                          GdkColormap *colormap)
112 {
113   GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (drawable);
114
115   if (impl->colormap == colormap)
116     return;
117   
118   if (impl->colormap)
119     g_object_unref (impl->colormap);
120   impl->colormap = colormap;
121   if (impl->colormap)
122     g_object_ref (impl->colormap);
123 }
124
125 static GdkColormap*
126 gdk_quartz_get_colormap (GdkDrawable *drawable)
127 {
128   return GDK_DRAWABLE_IMPL_QUARTZ (drawable)->colormap;
129 }
130
131 static GdkScreen*
132 gdk_quartz_get_screen (GdkDrawable *drawable)
133 {
134   return _gdk_screen;
135 }
136
137 static GdkVisual*
138 gdk_quartz_get_visual (GdkDrawable *drawable)
139 {
140   return gdk_drawable_get_visual (GDK_DRAWABLE_IMPL_QUARTZ (drawable)->wrapper);
141 }
142
143 static int
144 gdk_quartz_get_depth (GdkDrawable *drawable)
145 {
146   /* This is a bit bogus but I'm not sure the other way is better */
147
148   return gdk_drawable_get_depth (GDK_DRAWABLE_IMPL_QUARTZ (drawable)->wrapper);
149 }
150
151 static void
152 gdk_drawable_impl_quartz_finalize (GObject *object)
153 {
154   GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (object);
155
156   if (impl->colormap)
157     g_object_unref (impl->colormap);
158
159   G_OBJECT_CLASS (parent_class)->finalize (object);
160 }
161
162 static void
163 gdk_drawable_impl_quartz_class_init (GdkDrawableImplQuartzClass *klass)
164 {
165   GObjectClass *object_class = G_OBJECT_CLASS (klass);
166   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
167
168   parent_class = g_type_class_peek_parent (klass);
169
170   object_class->finalize = gdk_drawable_impl_quartz_finalize;
171
172   drawable_class->ref_cairo_surface = gdk_quartz_ref_cairo_surface;
173   drawable_class->create_cairo_surface = gdk_quartz_create_cairo_surface;
174
175   drawable_class->set_colormap = gdk_quartz_set_colormap;
176   drawable_class->get_colormap = gdk_quartz_get_colormap;
177
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;
181 }
182
183 GType
184 gdk_drawable_impl_quartz_get_type (void)
185 {
186   static GType object_type = 0;
187
188   if (!object_type)
189     {
190       const GTypeInfo object_info =
191       {
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),
199         0,              /* n_preallocs */
200         (GInstanceInitFunc) NULL,
201       };
202       
203       object_type = g_type_register_static (GDK_TYPE_DRAWABLE,
204                                             "GdkDrawableImplQuartz",
205                                             &object_info, 0);
206     }
207   
208   return object_type;
209 }
210
211 CGContextRef
212 gdk_quartz_drawable_get_context (GdkDrawable *drawable,
213                                  gboolean     antialias)
214 {
215   if (!GDK_DRAWABLE_IMPL_QUARTZ_GET_CLASS (drawable)->get_context)
216     {
217       g_warning ("%s doesn't implement GdkDrawableImplQuartzClass::get_context()",
218                  G_OBJECT_TYPE_NAME (drawable));
219       return NULL;
220     }
221
222   return GDK_DRAWABLE_IMPL_QUARTZ_GET_CLASS (drawable)->get_context (drawable, antialias);
223 }
224
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.
232  *
233  * If drawable NULL, no flushing is done, only registering that a flush was
234  * done externally.
235  */
236 void
237 _gdk_quartz_drawable_flush (GdkDrawable *drawable)
238 {
239   static struct timeval prev_tv;
240   static gint intervals[4];
241   static gint index;
242   struct timeval tv;
243   gint ms;
244
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;
248
249   if (drawable)
250     {
251       ms = intervals[0] + intervals[1] + intervals[2] + intervals[3];
252
253       /* ~25Hz on average. */
254       if (ms > 4*40)
255         {
256           if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable))
257             {
258               GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (drawable);
259
260               [window_impl->toplevel flushWindow];
261             }
262
263           prev_tv = tv;
264         }
265     }
266   else
267     prev_tv = tv;
268 }
269
270 void
271 gdk_quartz_drawable_release_context (GdkDrawable  *drawable, 
272                                      CGContextRef  cg_context)
273 {
274   if (GDK_IS_WINDOW_IMPL_QUARTZ (drawable))
275     {
276       GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (drawable);
277
278       CGContextRestoreGState (cg_context);
279       CGContextSetAllowsAntialiasing (cg_context, TRUE);
280
281       /* See comment in gdk_quartz_drawable_get_context(). */
282       if (window_impl->in_paint_rect_count == 0)
283         {
284           _gdk_quartz_drawable_flush (drawable);
285           [window_impl->view unlockFocus];
286         }
287     }
288   else if (GDK_IS_PIXMAP_IMPL_QUARTZ (drawable))
289     CGContextRelease (cg_context);
290 }
291
292 void
293 _gdk_quartz_drawable_finish (GdkDrawable *drawable)
294 {
295   GdkDrawableImplQuartz *impl = GDK_DRAWABLE_IMPL_QUARTZ (drawable);
296
297   if (impl->cairo_surface)
298     {
299       cairo_surface_finish (impl->cairo_surface);
300       cairo_surface_set_user_data (impl->cairo_surface, &gdk_quartz_cairo_key,
301                                    NULL, NULL);
302       impl->cairo_surface = NULL;
303     }
304 }