]> Pileus Git - ~andy/gtk/blob - gdk/quartz/gdkcursor-quartz.c
Merge branch 'win32-theme2'
[~andy/gtk] / gdk / quartz / gdkcursor-quartz.c
1 /* gdkcursor-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
23 #include "gdkdisplay.h"
24 #include "gdkcursor.h"
25 #include "gdkcursorprivate.h"
26 #include "gdkquartzcursor.h"
27 #include "gdkprivate-quartz.h"
28
29 #include "xcursors.h"
30
31 struct _GdkQuartzCursor
32 {
33   GdkCursor cursor;
34
35   NSCursor *nscursor;
36 };
37
38 struct _GdkQuartzCursorClass
39 {
40   GdkCursorClass cursor_class;
41 };
42
43
44 static GdkCursor *cached_xcursors[G_N_ELEMENTS (xcursors)];
45
46 static GdkCursor *
47 gdk_quartz_cursor_new_from_nscursor (NSCursor      *nscursor,
48                                      GdkCursorType  cursor_type)
49 {
50   GdkQuartzCursor *private;
51
52   private = g_object_new (GDK_TYPE_QUARTZ_CURSOR,
53                           "cursor-type", cursor_type,
54                           "display", _gdk_display,
55                           NULL);
56   private->nscursor = nscursor;
57
58   return GDK_CURSOR (private);
59 }
60
61 static GdkCursor *
62 create_blank_cursor (void)
63 {
64   NSCursor *nscursor;
65   NSImage *nsimage;
66   NSSize size = { 1.0, 1.0 };
67
68   nsimage = [[NSImage alloc] initWithSize:size];
69   nscursor = [[NSCursor alloc] initWithImage:nsimage
70                                hotSpot:NSMakePoint(0.0, 0.0)];
71   [nsimage release];
72
73   return gdk_quartz_cursor_new_from_nscursor (nscursor, GDK_BLANK_CURSOR);
74 }
75
76 static gboolean
77 get_bit (const guchar *data,
78          gint          width,
79          gint          height,
80          gint          x,
81          gint          y)
82 {
83   gint bytes_per_line;
84   const guchar *src;
85
86   if (x < 0 || y < 0 || x >= width || y >= height)
87     return FALSE;
88
89   bytes_per_line = (width + 7) / 8;
90
91   src = &data[y * bytes_per_line];
92   return ((src[x / 8] >> x % 8) & 1);
93 }
94
95 static GdkCursor *
96 create_builtin_cursor (GdkCursorType cursor_type)
97 {
98   GdkCursor *cursor;
99   NSBitmapImageRep *bitmap_rep;
100   NSInteger mask_width, mask_height;
101   gint src_width, src_height;
102   gint dst_stride;
103   const guchar *mask_start, *src_start;
104   gint dx, dy;
105   gint x, y;
106   NSPoint hotspot;
107   NSImage *image;
108   NSCursor *nscursor;
109
110   if (cursor_type >= G_N_ELEMENTS (xcursors) || cursor_type < 0)
111     return NULL;
112
113   cursor = cached_xcursors[cursor_type];
114   if (cursor)
115     return cursor;
116
117   GDK_QUARTZ_ALLOC_POOL;
118
119   src_width = xcursors[cursor_type].width;
120   src_height = xcursors[cursor_type].height;
121   mask_width = xcursors[cursor_type+1].width;
122   mask_height = xcursors[cursor_type+1].height;
123
124   bitmap_rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
125                 pixelsWide:mask_width pixelsHigh:mask_height
126                 bitsPerSample:8 samplesPerPixel:4
127                 hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace
128                 bytesPerRow:0 bitsPerPixel:0];
129
130   dst_stride = [bitmap_rep bytesPerRow];
131
132   src_start = xcursors[cursor_type].bits;
133   mask_start = xcursors[cursor_type+1].bits;
134
135   dx = xcursors[cursor_type+1].hotx - xcursors[cursor_type].hotx;
136   dy = xcursors[cursor_type+1].hoty - xcursors[cursor_type].hoty;
137
138   for (y = 0; y < mask_height; y++)
139     {
140       guchar *dst = [bitmap_rep bitmapData] + y * dst_stride;
141
142       for (x = 0; x < mask_width; x++)
143         {
144           if (get_bit (mask_start, mask_width, mask_height, x, y))
145             {
146               if (get_bit (src_start, src_width, src_height, x - dx, y - dy))
147                 {
148                   *dst++ = 0;
149                   *dst++ = 0;
150                   *dst++ = 0;
151                 }
152               else
153                 {
154                   *dst++ = 0xff;
155                   *dst++ = 0xff;
156                   *dst++ = 0xff;
157                 }
158
159               *dst++ = 0xff;
160             }
161           else
162             {
163               *dst++ = 0;
164               *dst++ = 0;
165               *dst++ = 0;
166               *dst++ = 0;
167             }
168         }
169     }
170
171   image = [[NSImage alloc] init];
172   [image addRepresentation:bitmap_rep];
173   [bitmap_rep release];
174
175   hotspot = NSMakePoint (xcursors[cursor_type+1].hotx,
176                          xcursors[cursor_type+1].hoty);
177
178   nscursor = [[NSCursor alloc] initWithImage:image hotSpot:hotspot];
179   [image release];
180
181   cursor = gdk_quartz_cursor_new_from_nscursor (nscursor, GDK_CURSOR_IS_PIXMAP);
182
183   cached_xcursors[cursor_type] = gdk_cursor_ref (cursor);
184
185   GDK_QUARTZ_RELEASE_POOL;
186
187   return cursor;
188 }
189
190 GdkCursor*
191 _gdk_quartz_display_get_cursor_for_type (GdkDisplay    *display,
192                                          GdkCursorType  cursor_type)
193 {
194   NSCursor *nscursor;
195
196   g_return_val_if_fail (display == gdk_display_get_default (), NULL);
197
198   switch (cursor_type)
199     {
200     case GDK_XTERM:
201       nscursor = [NSCursor IBeamCursor];
202       break;
203     case GDK_SB_H_DOUBLE_ARROW:
204       nscursor = [NSCursor resizeLeftRightCursor];
205       break;
206     case GDK_SB_V_DOUBLE_ARROW:
207       nscursor = [NSCursor resizeUpDownCursor];
208       break;
209     case GDK_SB_UP_ARROW:
210     case GDK_BASED_ARROW_UP:
211     case GDK_BOTTOM_TEE:
212     case GDK_TOP_SIDE:
213       nscursor = [NSCursor resizeUpCursor];
214       break;
215     case GDK_SB_DOWN_ARROW:
216     case GDK_BASED_ARROW_DOWN:
217     case GDK_TOP_TEE:
218     case GDK_BOTTOM_SIDE:
219       nscursor = [NSCursor resizeDownCursor];
220       break;
221     case GDK_SB_LEFT_ARROW:
222     case GDK_RIGHT_TEE:
223     case GDK_LEFT_SIDE:
224       nscursor = [NSCursor resizeLeftCursor];
225       break;
226     case GDK_SB_RIGHT_ARROW:
227     case GDK_LEFT_TEE:
228     case GDK_RIGHT_SIDE:
229       nscursor = [NSCursor resizeRightCursor];
230       break;
231     case GDK_TCROSS:
232     case GDK_CROSS:
233     case GDK_CROSSHAIR:
234     case GDK_DIAMOND_CROSS:
235       nscursor = [NSCursor crosshairCursor];
236       break;
237     case GDK_HAND1:
238     case GDK_HAND2:
239       nscursor = [NSCursor pointingHandCursor];
240       break;
241     case GDK_CURSOR_IS_PIXMAP:
242       return NULL;
243     case GDK_BLANK_CURSOR:
244       return create_blank_cursor ();
245     default:
246       return gdk_cursor_ref (create_builtin_cursor (cursor_type));
247     }
248
249   [nscursor retain];
250   return gdk_quartz_cursor_new_from_nscursor (nscursor, cursor_type);
251 }
252
253
254 GdkCursor *
255 _gdk_quartz_display_get_cursor_for_pixbuf (GdkDisplay *display,
256                                            GdkPixbuf  *pixbuf,
257                                            gint        x,
258                                            gint        y)
259 {
260   NSImage *image;
261   NSCursor *nscursor;
262   GdkCursor *cursor;
263   gboolean has_alpha;
264
265   GDK_QUARTZ_ALLOC_POOL;
266
267   has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
268
269   image = gdk_quartz_pixbuf_to_ns_image_libgtk_only (pixbuf);
270   nscursor = [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint(x, y)];
271
272   cursor = gdk_quartz_cursor_new_from_nscursor (nscursor, GDK_CURSOR_IS_PIXMAP);
273
274   GDK_QUARTZ_RELEASE_POOL;
275
276   return cursor;
277 }
278
279 GdkCursor*
280 _gdk_quartz_display_get_cursor_for_name (GdkDisplay  *display,
281                                          const gchar *name)
282 {
283   /* FIXME: Implement */
284   return NULL;
285 }
286
287 G_DEFINE_TYPE (GdkQuartzCursor, gdk_quartz_cursor, GDK_TYPE_CURSOR)
288
289 static GdkPixbuf *gdk_quartz_cursor_get_image (GdkCursor *cursor);
290
291 static void
292 gdk_quartz_cursor_finalize (GObject *object)
293 {
294   GdkQuartzCursor *private = GDK_QUARTZ_CURSOR (object);
295
296   if (private->nscursor)
297     [private->nscursor release];
298   private->nscursor = NULL;
299 }
300
301 static void
302 gdk_quartz_cursor_class_init (GdkQuartzCursorClass *quartz_cursor_class)
303 {
304   GdkCursorClass *cursor_class = GDK_CURSOR_CLASS (quartz_cursor_class);
305   GObjectClass *object_class = G_OBJECT_CLASS (quartz_cursor_class);
306
307   object_class->finalize = gdk_quartz_cursor_finalize;
308
309   cursor_class->get_image = gdk_quartz_cursor_get_image;
310 }
311
312 static void
313 gdk_quartz_cursor_init (GdkQuartzCursor *cursor)
314 {
315 }
316
317
318 gboolean
319 _gdk_quartz_display_supports_cursor_alpha (GdkDisplay *display)
320 {
321   return TRUE;
322 }
323
324 gboolean
325 _gdk_quartz_display_supports_cursor_color (GdkDisplay *display)
326 {
327   return TRUE;
328 }
329
330 void
331 _gdk_quartz_display_get_default_cursor_size (GdkDisplay *display,
332                                              guint      *width,
333                                              guint      *height)
334 {
335   /* Mac OS X doesn't have the notion of a default size */
336   *width = 32;
337   *height = 32;
338 }
339
340 void
341 _gdk_quartz_display_get_maximal_cursor_size (GdkDisplay *display,
342                                              guint       *width,
343                                              guint       *height)
344 {
345   /* Cursor sizes in Mac OS X can be arbitrarily large */
346   *width = 65536;
347   *height = 65536;
348 }
349
350 NSCursor *
351 _gdk_quartz_cursor_get_ns_cursor (GdkCursor *cursor)
352 {
353   GdkQuartzCursor *cursor_private;
354
355   if (!cursor)
356     return [NSCursor arrowCursor];
357
358   g_return_val_if_fail (GDK_IS_QUARTZ_CURSOR (cursor), NULL);
359
360   cursor_private = GDK_QUARTZ_CURSOR (cursor);
361
362   return cursor_private->nscursor;
363 }
364
365 static GdkPixbuf *
366 gdk_quartz_cursor_get_image (GdkCursor *cursor)
367 {
368   /* FIXME: Implement */
369   return NULL;
370 }