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