]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkcursor-x11.c
Take cursor hotspot from pixbuf if available
[~andy/gtk] / gdk / x11 / gdkcursor-x11.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28
29 #include "gdkcursor.h"
30
31 #include "gdkprivate-x11.h"
32 #include "gdkdisplay-x11.h"
33 #include "gdkx.h"
34
35 #define GDK_PIXBUF_ENABLE_BACKEND
36 #include <gdk-pixbuf/gdk-pixbuf.h>
37
38 #include <X11/Xlib.h>
39 #include <X11/cursorfont.h>
40 #ifdef HAVE_XCURSOR
41 #include <X11/Xcursor/Xcursor.h>
42 #endif
43 #ifdef HAVE_XFIXES
44 #include <X11/extensions/Xfixes.h>
45 #endif
46 #include <string.h>
47 #include <errno.h>
48
49
50 static guint theme_serial = 0;
51
52 /* cursor_cache holds a cache of non-pixmap cursors to avoid expensive 
53  * libXcursor searches, cursors are added to it but only removed when
54  * their display is closed. We make the assumption that since there are 
55  * a small number of display's and a small number of cursor's that this 
56  * list will stay small enough not to be a problem.
57  */
58 static GSList* cursor_cache = NULL;
59
60 struct cursor_cache_key
61 {
62   GdkDisplay* display;
63   GdkCursorType type;
64   const char* name;
65 };
66
67 /* Caller should check if there is already a match first.
68  * Cursor MUST be either a typed cursor or a pixmap with 
69  * a non-NULL name.
70  */
71 static void
72 add_to_cache (GdkCursorPrivate* cursor)
73 {
74   cursor_cache = g_slist_prepend (cursor_cache, cursor);
75
76   /* Take a ref so that if the caller frees it we still have it */
77   gdk_cursor_ref ((GdkCursor*) cursor);
78 }
79
80 /* Returns 0 on a match
81  */
82 static gint
83 cache_compare_func (gconstpointer listelem, 
84                     gconstpointer target)
85 {
86   GdkCursorPrivate* cursor = (GdkCursorPrivate*)listelem;
87   struct cursor_cache_key* key = (struct cursor_cache_key*)target;
88
89   if ((cursor->cursor.type != key->type) ||
90       (cursor->display != key->display))
91     return 1; /* No match */
92   
93   /* Elements marked as pixmap must be named cursors 
94    * (since we don't store normal pixmap cursors 
95    */
96   if (key->type == GDK_CURSOR_IS_PIXMAP)
97     return strcmp (key->name, cursor->name);
98
99   return 0; /* Match */
100 }
101
102 /* Returns the cursor if there is a match, NULL if not
103  * For named cursors type shall be GDK_CURSOR_IS_PIXMAP
104  * For unnamed, typed cursors, name shall be NULL
105  */
106 static GdkCursorPrivate*
107 find_in_cache (GdkDisplay    *display, 
108                GdkCursorType  type,
109                const char    *name)
110 {
111   GSList* res;
112   struct cursor_cache_key key;
113
114   key.display = display;
115   key.type = type;
116   key.name = name;
117
118   res = g_slist_find_custom (cursor_cache, &key, cache_compare_func);
119
120   if (res)
121     return (GdkCursorPrivate *) res->data;
122
123   return NULL;
124 }
125
126 /* Called by gdk_display_x11_finalize to flush any cached cursors
127  * for a dead display.
128  */
129 void 
130 _gdk_x11_cursor_display_finalize (GdkDisplay *display)
131 {
132   GSList* item;
133   GSList** itemp; /* Pointer to the thing to fix when we delete an item */
134   item = cursor_cache;
135   itemp = &cursor_cache;
136   while (item)
137     {
138       GdkCursorPrivate* cursor = (GdkCursorPrivate*)(item->data);
139       if (cursor->display == display)
140         {
141           GSList* olditem;
142           gdk_cursor_unref ((GdkCursor*) cursor);
143           /* Remove this item from the list */
144           *(itemp) = item->next;
145           olditem = item;
146           item = g_slist_next (item);
147           g_slist_free_1 (olditem);
148         } 
149       else 
150         {
151           itemp = &(item->next);
152           item = g_slist_next (item);
153         }
154     }
155 }
156
157 static Cursor
158 get_blank_cursor (GdkDisplay *display)
159 {
160   GdkScreen *screen;
161   Pixmap pixmap;
162   XColor color;
163   Cursor cursor;
164   cairo_surface_t *surface;
165   cairo_t *cr;
166
167   screen = gdk_display_get_default_screen (display);
168   surface = _gdk_x11_window_create_bitmap_surface (gdk_screen_get_root_window (screen), 1, 1);
169   /* Clear surface */
170   cr = cairo_create (surface);
171   cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
172   cairo_paint (cr);
173   cairo_destroy (cr);
174  
175   pixmap = cairo_xlib_surface_get_drawable (surface);
176
177   color.pixel = 0; 
178   color.red = color.blue = color.green = 0;
179   
180   if (display->closed)
181     cursor = None;
182   else
183     cursor = XCreatePixmapCursor (GDK_DISPLAY_XDISPLAY (display),
184                                   pixmap, pixmap,
185                                   &color, &color, 1, 1);
186   cairo_surface_destroy (surface);
187
188   return cursor;
189 }
190
191 /**
192  * gdk_cursor_new_for_display:
193  * @display: the #GdkDisplay for which the cursor will be created
194  * @cursor_type: cursor to create
195  * 
196  * Creates a new cursor from the set of builtin cursors.
197  * Some useful ones are:
198  * <itemizedlist>
199  * <listitem><para>
200  *  <inlinegraphic format="PNG" fileref="right_ptr.png"></inlinegraphic> #GDK_RIGHT_PTR (right-facing arrow)
201  * </para></listitem>
202  * <listitem><para>
203  *  <inlinegraphic format="PNG" fileref="crosshair.png"></inlinegraphic> #GDK_CROSSHAIR (crosshair)
204  * </para></listitem>
205  * <listitem><para>
206  *  <inlinegraphic format="PNG" fileref="xterm.png"></inlinegraphic> #GDK_XTERM (I-beam)
207  * </para></listitem>
208  * <listitem><para>
209  * <inlinegraphic format="PNG" fileref="watch.png"></inlinegraphic> #GDK_WATCH (busy)
210  * </para></listitem>
211  * <listitem><para>
212  * <inlinegraphic format="PNG" fileref="fleur.png"></inlinegraphic> #GDK_FLEUR (for moving objects)
213  * </para></listitem>
214  * <listitem><para>
215  * <inlinegraphic format="PNG" fileref="hand1.png"></inlinegraphic> #GDK_HAND1 (a right-pointing hand)
216  * </para></listitem>
217  * <listitem><para>
218  * <inlinegraphic format="PNG" fileref="hand2.png"></inlinegraphic> #GDK_HAND2 (a left-pointing hand)
219  * </para></listitem>
220  * <listitem><para>
221  * <inlinegraphic format="PNG" fileref="left_side.png"></inlinegraphic> #GDK_LEFT_SIDE (resize left side)
222  * </para></listitem>
223  * <listitem><para>
224  * <inlinegraphic format="PNG" fileref="right_side.png"></inlinegraphic> #GDK_RIGHT_SIDE (resize right side)
225  * </para></listitem>
226  * <listitem><para>
227  * <inlinegraphic format="PNG" fileref="top_left_corner.png"></inlinegraphic> #GDK_TOP_LEFT_CORNER (resize northwest corner)
228  * </para></listitem>
229  * <listitem><para>
230  * <inlinegraphic format="PNG" fileref="top_right_corner.png"></inlinegraphic> #GDK_TOP_RIGHT_CORNER (resize northeast corner)
231  * </para></listitem>
232  * <listitem><para>
233  * <inlinegraphic format="PNG" fileref="bottom_left_corner.png"></inlinegraphic> #GDK_BOTTOM_LEFT_CORNER (resize southwest corner)
234  * </para></listitem>
235  * <listitem><para>
236  * <inlinegraphic format="PNG" fileref="bottom_right_corner.png"></inlinegraphic> #GDK_BOTTOM_RIGHT_CORNER (resize southeast corner)
237  * </para></listitem>
238  * <listitem><para>
239  * <inlinegraphic format="PNG" fileref="top_side.png"></inlinegraphic> #GDK_TOP_SIDE (resize top side)
240  * </para></listitem>
241  * <listitem><para>
242  * <inlinegraphic format="PNG" fileref="bottom_side.png"></inlinegraphic> #GDK_BOTTOM_SIDE (resize bottom side)
243  * </para></listitem>
244  * <listitem><para>
245  * <inlinegraphic format="PNG" fileref="sb_h_double_arrow.png"></inlinegraphic> #GDK_SB_H_DOUBLE_ARROW (move vertical splitter)
246  * </para></listitem>
247  * <listitem><para>
248  * <inlinegraphic format="PNG" fileref="sb_v_double_arrow.png"></inlinegraphic> #GDK_SB_V_DOUBLE_ARROW (move horizontal splitter)
249  * </para></listitem>
250  * <listitem><para>
251  * #GDK_BLANK_CURSOR (Blank cursor). Since 2.16
252  * </para></listitem>
253  * </itemizedlist>
254  *
255  * Return value: a new #GdkCursor
256  *
257  * Since: 2.2
258  **/
259 GdkCursor*
260 gdk_cursor_new_for_display (GdkDisplay    *display,
261                             GdkCursorType  cursor_type)
262 {
263   GdkCursorPrivate *private;
264   GdkCursor *cursor;
265   Cursor xcursor;
266
267   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
268
269   if (display->closed)
270     {
271       xcursor = None;
272     } 
273   else 
274     {
275       private = find_in_cache (display, cursor_type, NULL);
276
277       if (private)
278         {
279           /* Cache had it, add a ref for this user */
280           gdk_cursor_ref ((GdkCursor*) private);
281        
282           return (GdkCursor*) private;
283         } 
284       else 
285         {
286           if (cursor_type != GDK_BLANK_CURSOR)
287             xcursor = XCreateFontCursor (GDK_DISPLAY_XDISPLAY (display),
288                                          cursor_type);
289           else
290             xcursor = get_blank_cursor (display);
291        }
292     }
293   
294   private = g_new (GdkCursorPrivate, 1);
295   private->display = display;
296   private->xcursor = xcursor;
297   private->name = NULL;
298   private->serial = theme_serial;
299
300   cursor = (GdkCursor *) private;
301   cursor->type = cursor_type;
302   cursor->ref_count = 1;
303   
304   if (xcursor != None)
305     add_to_cache (private);
306
307   return cursor;
308 }
309
310 void
311 _gdk_cursor_destroy (GdkCursor *cursor)
312 {
313   GdkCursorPrivate *private;
314
315   g_return_if_fail (cursor != NULL);
316   g_return_if_fail (cursor->ref_count == 0);
317
318   private = (GdkCursorPrivate *) cursor;
319   if (!private->display->closed && private->xcursor)
320     XFreeCursor (GDK_DISPLAY_XDISPLAY (private->display), private->xcursor);
321
322   g_free (private->name);
323   g_free (private);
324 }
325
326 /**
327  * gdk_x11_cursor_get_xdisplay:
328  * @cursor: a #GdkCursor.
329  * 
330  * Returns the display of a #GdkCursor.
331  * 
332  * Return value: an Xlib <type>Display*</type>.
333  **/
334 Display *
335 gdk_x11_cursor_get_xdisplay (GdkCursor *cursor)
336 {
337   g_return_val_if_fail (cursor != NULL, NULL);
338
339   return GDK_DISPLAY_XDISPLAY(((GdkCursorPrivate *)cursor)->display);
340 }
341
342 /**
343  * gdk_x11_cursor_get_xcursor:
344  * @cursor: a #GdkCursor.
345  * 
346  * Returns the X cursor belonging to a #GdkCursor.
347  * 
348  * Return value: an Xlib <type>Cursor</type>.
349  **/
350 Cursor
351 gdk_x11_cursor_get_xcursor (GdkCursor *cursor)
352 {
353   g_return_val_if_fail (cursor != NULL, None);
354
355   return ((GdkCursorPrivate *)cursor)->xcursor;
356 }
357
358 /** 
359  * gdk_cursor_get_display:
360  * @cursor: a #GdkCursor.
361  *
362  * Returns the display on which the #GdkCursor is defined.
363  *
364  * Returns: the #GdkDisplay associated to @cursor
365  *
366  * Since: 2.2
367  */
368
369 GdkDisplay *
370 gdk_cursor_get_display (GdkCursor *cursor)
371 {
372   g_return_val_if_fail (cursor != NULL, NULL);
373
374   return ((GdkCursorPrivate *)cursor)->display;
375 }
376
377 #if defined(HAVE_XCURSOR) && defined(HAVE_XFIXES) && XFIXES_MAJOR >= 2
378
379 /**
380  * gdk_cursor_get_image:
381  * @cursor: a #GdkCursor
382  *
383  * Returns a #GdkPixbuf with the image used to display the cursor.
384  *
385  * Note that depending on the capabilities of the windowing system and 
386  * on the cursor, GDK may not be able to obtain the image data. In this 
387  * case, %NULL is returned.
388  *
389  * Returns: a #GdkPixbuf representing @cursor, or %NULL
390  *
391  * Since: 2.8
392  */
393 GdkPixbuf*  
394 gdk_cursor_get_image (GdkCursor *cursor)
395 {
396   Display *xdisplay;
397   GdkCursorPrivate *private;
398   XcursorImages *images = NULL;
399   XcursorImage *image;
400   gint size;
401   gchar buf[32];
402   guchar *data, *p, tmp;
403   GdkPixbuf *pixbuf;
404   gchar *theme;
405   
406   g_return_val_if_fail (cursor != NULL, NULL);
407
408   private = (GdkCursorPrivate *) cursor;
409     
410   xdisplay = GDK_DISPLAY_XDISPLAY (private->display);
411
412   size = XcursorGetDefaultSize (xdisplay);
413   theme = XcursorGetTheme (xdisplay);
414
415   if (cursor->type == GDK_CURSOR_IS_PIXMAP)
416     {
417       if (private->name)
418         images = XcursorLibraryLoadImages (private->name, theme, size);
419     }
420   else 
421     images = XcursorShapeLoadImages (cursor->type, theme, size);
422
423   if (!images)
424     return NULL;
425   
426   image = images->images[0];
427
428   data = g_malloc (4 * image->width * image->height);
429   memcpy (data, image->pixels, 4 * image->width * image->height);
430
431   for (p = data; p < data + (4 * image->width * image->height); p += 4)
432     {
433       tmp = p[0];
434       p[0] = p[2];
435       p[2] = tmp;
436     }
437
438   pixbuf = gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB, TRUE,
439                                      8, image->width, image->height,
440                                      4 * image->width, 
441                                      (GdkPixbufDestroyNotify)g_free, NULL);
442
443   if (private->name)
444     gdk_pixbuf_set_option (pixbuf, "name", private->name);
445   g_snprintf (buf, 32, "%d", image->xhot);
446   gdk_pixbuf_set_option (pixbuf, "x_hot", buf);
447   g_snprintf (buf, 32, "%d", image->yhot);
448   gdk_pixbuf_set_option (pixbuf, "y_hot", buf);
449
450   XcursorImagesDestroy (images);
451
452   return pixbuf;
453 }
454
455 void
456 _gdk_x11_cursor_update_theme (GdkCursor *cursor)
457 {
458   Display *xdisplay;
459   GdkCursorPrivate *private;
460   Cursor new_cursor = None;
461   GdkDisplayX11 *display_x11;
462
463   private = (GdkCursorPrivate *) cursor;
464   xdisplay = GDK_DISPLAY_XDISPLAY (private->display);
465   display_x11 = GDK_DISPLAY_X11 (private->display);
466
467   if (!display_x11->have_xfixes)
468     return;
469
470   if (private->serial == theme_serial)
471     return;
472
473   private->serial = theme_serial;
474
475   if (private->xcursor != None)
476     {
477       if (cursor->type == GDK_BLANK_CURSOR)
478         return;
479
480       if (cursor->type == GDK_CURSOR_IS_PIXMAP)
481         {
482           if (private->name)
483             new_cursor = XcursorLibraryLoadCursor (xdisplay, private->name);
484         }
485       else 
486         new_cursor = XcursorShapeLoadCursor (xdisplay, cursor->type);
487       
488       if (new_cursor != None)
489         {
490           XFixesChangeCursor (xdisplay, new_cursor, private->xcursor);
491           private->xcursor = new_cursor;
492         }
493     }
494 }
495
496 static void
497 update_cursor (gpointer data,
498                gpointer user_data)
499 {
500   GdkCursor *cursor;
501
502   cursor = (GdkCursor*)(data);
503
504   if (!cursor)
505     return;
506   
507   _gdk_x11_cursor_update_theme (cursor);
508 }
509
510 /**
511  * gdk_x11_display_set_cursor_theme:
512  * @display: a #GdkDisplay
513  * @theme: the name of the cursor theme to use, or %NULL to unset
514  *         a previously set value 
515  * @size: the cursor size to use, or 0 to keep the previous size
516  *
517  * Sets the cursor theme from which the images for cursor
518  * should be taken. 
519  * 
520  * If the windowing system supports it, existing cursors created 
521  * with gdk_cursor_new(), gdk_cursor_new_for_display() and 
522  * gdk_cursor_new_for_name() are updated to reflect the theme 
523  * change. Custom cursors constructed with
524  * gdk_cursor_new_from_pixbuf() will have to be handled
525  * by the application (GTK+ applications can learn about 
526  * cursor theme changes by listening for change notification
527  * for the corresponding #GtkSetting).
528  *
529  * Since: 2.8
530  */
531 void
532 gdk_x11_display_set_cursor_theme (GdkDisplay  *display,
533                                   const gchar *theme,
534                                   const gint   size)
535 {
536   GdkDisplayX11 *display_x11;
537   Display *xdisplay;
538   gchar *old_theme;
539   gint old_size;
540
541   g_return_if_fail (GDK_IS_DISPLAY (display));
542
543   display_x11 = GDK_DISPLAY_X11 (display);
544   xdisplay = GDK_DISPLAY_XDISPLAY (display);
545
546   old_theme = XcursorGetTheme (xdisplay);
547   old_size = XcursorGetDefaultSize (xdisplay);
548
549   if (old_size == size &&
550       (old_theme == theme ||
551        (old_theme && theme && strcmp (old_theme, theme) == 0)))
552     return;
553
554   theme_serial++;
555
556   XcursorSetTheme (xdisplay, theme);
557   if (size > 0)
558     XcursorSetDefaultSize (xdisplay, size);
559     
560   g_slist_foreach (cursor_cache, update_cursor, NULL);
561 }
562
563 #else
564
565 GdkPixbuf*  
566 gdk_cursor_get_image (GdkCursor *cursor)
567 {
568   g_return_val_if_fail (cursor != NULL, NULL);
569   
570   return NULL;
571 }
572
573 void
574 gdk_x11_display_set_cursor_theme (GdkDisplay  *display,
575                                   const gchar *theme,
576                                   const gint   size)
577 {
578   g_return_if_fail (GDK_IS_DISPLAY (display));
579 }
580
581 void
582 _gdk_x11_cursor_update_theme (GdkCursor *cursor)
583 {
584   g_return_if_fail (cursor != NULL);
585 }
586
587 #endif
588
589 #ifdef HAVE_XCURSOR
590
591 static XcursorImage*
592 create_cursor_image (GdkPixbuf *pixbuf,
593                      gint       x,
594                      gint       y)
595 {
596   guint width, height;
597   XcursorImage *xcimage;
598   cairo_surface_t *surface;
599   cairo_t *cr;
600
601   width = gdk_pixbuf_get_width (pixbuf);
602   height = gdk_pixbuf_get_height (pixbuf);
603
604   xcimage = XcursorImageCreate (width, height);
605
606   xcimage->xhot = x;
607   xcimage->yhot = y;
608
609   surface = cairo_image_surface_create_for_data ((guchar *) xcimage->pixels,
610                                                  CAIRO_FORMAT_ARGB32,
611                                                  width,
612                                                  height,
613                                                  width * 4);
614
615   cr = cairo_create (surface);
616   cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
617   gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
618   cairo_paint (cr);
619   cairo_destroy (cr);
620
621   cairo_surface_destroy (surface);
622
623   return xcimage;
624 }
625
626
627 /**
628  * gdk_cursor_new_from_pixbuf:
629  * @display: the #GdkDisplay for which the cursor will be created
630  * @pixbuf: the #GdkPixbuf containing the cursor image
631  * @x: the horizontal offset of the 'hotspot' of the cursor. 
632  * @y: the vertical offset of the 'hotspot' of the cursor.
633  *
634  * Creates a new cursor from a pixbuf. 
635  *
636  * Not all GDK backends support RGBA cursors. If they are not 
637  * supported, a monochrome approximation will be displayed. 
638  * The functions gdk_display_supports_cursor_alpha() and 
639  * gdk_display_supports_cursor_color() can be used to determine
640  * whether RGBA cursors are supported; 
641  * gdk_display_get_default_cursor_size() and 
642  * gdk_display_get_maximal_cursor_size() give information about 
643  * cursor sizes.
644  *
645  * If @x or @y are <literal>-1</literal>, the pixbuf must have
646  * options named "x_hot" and "y_hot", resp., containing
647  * integer values between %0 and the width resp. height of
648  * the pixbuf. (Since: 3.0)
649  *
650  * On the X backend, support for RGBA cursors requires a
651  * sufficently new version of the X Render extension. 
652  *
653  * Returns: a new #GdkCursor.
654  * 
655  * Since: 2.4
656  */
657 GdkCursor *
658 gdk_cursor_new_from_pixbuf (GdkDisplay *display, 
659                             GdkPixbuf  *pixbuf,
660                             gint        x,
661                             gint        y)
662 {
663   XcursorImage *xcimage;
664   Cursor xcursor;
665   GdkCursorPrivate *private;
666   GdkCursor *cursor;
667   const char *option;
668   char *end;
669   gint64 value;
670
671   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
672   g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
673
674   if (x == -1 && (option = gdk_pixbuf_get_option (pixbuf, "x_hot")))
675     {
676       errno = 0;
677       end = NULL;
678       value = g_ascii_strtoll (option, &end, 10);
679       if (errno == 0 &&
680           end != option &&
681           value >= 0 && value < G_MAXINT)
682         x = (gint) value;
683     }
684   if (y == -1 && (option = gdk_pixbuf_get_option (pixbuf, "y_hot")))
685     {
686       errno = 0;
687       end = NULL;
688       value = g_ascii_strtoll (option, &end, 10);
689       if (errno == 0 &&
690           end != option &&
691           value >= 0 && value < G_MAXINT)
692         y = (gint) value;
693     }
694
695   g_return_val_if_fail (0 <= x && x < gdk_pixbuf_get_width (pixbuf), NULL);
696   g_return_val_if_fail (0 <= y && y < gdk_pixbuf_get_height (pixbuf), NULL);
697
698   if (display->closed)
699     xcursor = None;
700   else 
701     {
702       xcimage = create_cursor_image (pixbuf, x, y);
703       xcursor = XcursorImageLoadCursor (GDK_DISPLAY_XDISPLAY (display), xcimage);
704       XcursorImageDestroy (xcimage);
705     }
706
707   private = g_new (GdkCursorPrivate, 1);
708   private->display = display;
709   private->xcursor = xcursor;
710   private->name = NULL;
711   private->serial = theme_serial;
712
713   cursor = (GdkCursor *) private;
714   cursor->type = GDK_CURSOR_IS_PIXMAP;
715   cursor->ref_count = 1;
716   
717   return cursor;
718 }
719
720 /**
721  * gdk_cursor_new_from_name:
722  * @display: the #GdkDisplay for which the cursor will be created
723  * @name: the name of the cursor
724  *
725  * Creates a new cursor by looking up @name in the current cursor
726  * theme. 
727  * 
728  * Returns: a new #GdkCursor, or %NULL if there is no cursor with 
729  *   the given name 
730  *
731  * Since: 2.8
732  */
733 GdkCursor*  
734 gdk_cursor_new_from_name (GdkDisplay  *display,
735                           const gchar *name)
736 {
737   Cursor xcursor;
738   Display *xdisplay;
739   GdkCursorPrivate *private;
740   GdkCursor *cursor;
741
742   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
743
744   if (display->closed)
745     xcursor = None;
746   else 
747     {
748       private = find_in_cache (display, GDK_CURSOR_IS_PIXMAP, name);
749
750       if (private)
751         {
752           /* Cache had it, add a ref for this user */
753           gdk_cursor_ref ((GdkCursor*) private);
754
755           return (GdkCursor*) private;
756         }
757
758       xdisplay = GDK_DISPLAY_XDISPLAY (display);
759       xcursor = XcursorLibraryLoadCursor (xdisplay, name);
760       if (xcursor == None)
761         return NULL;
762     }
763
764   private = g_new (GdkCursorPrivate, 1);
765   private->display = display;
766   private->xcursor = xcursor;
767   private->name = g_strdup (name);
768   private->serial = theme_serial;
769
770   cursor = (GdkCursor *) private;
771   cursor->type = GDK_CURSOR_IS_PIXMAP;
772   cursor->ref_count = 1;
773   add_to_cache (private);
774
775   return cursor;
776 }
777
778 /**
779  * gdk_display_supports_cursor_alpha:
780  * @display: a #GdkDisplay
781  *
782  * Returns %TRUE if cursors can use an 8bit alpha channel 
783  * on @display. Otherwise, cursors are restricted to bilevel 
784  * alpha (i.e. a mask).
785  *
786  * Returns: whether cursors can have alpha channels.
787  *
788  * Since: 2.4
789  */
790 gboolean 
791 gdk_display_supports_cursor_alpha (GdkDisplay *display)
792 {
793   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
794
795   return XcursorSupportsARGB (GDK_DISPLAY_XDISPLAY (display));
796 }
797
798 /**
799  * gdk_display_supports_cursor_color:
800  * @display: a #GdkDisplay
801  *
802  * Returns %TRUE if multicolored cursors are supported
803  * on @display. Otherwise, cursors have only a forground
804  * and a background color.
805  *
806  * Returns: whether cursors can have multiple colors.
807  *
808  * Since: 2.4
809  */
810 gboolean 
811 gdk_display_supports_cursor_color (GdkDisplay *display)
812 {
813   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
814
815   return XcursorSupportsARGB (GDK_DISPLAY_XDISPLAY (display));
816 }
817
818 /**
819  * gdk_display_get_default_cursor_size:
820  * @display: a #GdkDisplay
821  *
822  * Returns the default size to use for cursors on @display.
823  *
824  * Returns: the default cursor size.
825  *
826  * Since: 2.4
827  */
828 guint     
829 gdk_display_get_default_cursor_size (GdkDisplay *display)
830 {
831   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
832
833   return XcursorGetDefaultSize (GDK_DISPLAY_XDISPLAY (display));
834 }
835
836 #else
837
838 static GdkCursor*
839 gdk_cursor_new_from_pixmap (GdkDisplay     *display,
840                             Pixmap          source_pixmap,
841                             Pixmap          mask_pixmap,
842                             const GdkColor *fg,
843                             const GdkColor *bg,
844                             gint            x,
845                             gint            y)
846 {
847   GdkCursorPrivate *private;
848   GdkCursor *cursor;
849   Cursor xcursor;
850   XColor xfg, xbg;
851
852   g_return_val_if_fail (fg != NULL, NULL);
853   g_return_val_if_fail (bg != NULL, NULL);
854
855   xfg.pixel = fg->pixel;
856   xfg.red = fg->red;
857   xfg.blue = fg->blue;
858   xfg.green = fg->green;
859   xbg.pixel = bg->pixel;
860   xbg.red = bg->red;
861   xbg.blue = bg->blue;
862   xbg.green = bg->green;
863   
864   if (display->closed)
865     xcursor = None;
866   else
867     xcursor = XCreatePixmapCursor (GDK_DISPLAY_XDISPLAY (display),
868                                    source_pixmap, mask_pixmap, &xfg, &xbg, x, y);
869   private = g_new (GdkCursorPrivate, 1);
870   private->display = display;
871   private->xcursor = xcursor;
872   private->name = NULL;
873   private->serial = theme_serial;
874
875   cursor = (GdkCursor *) private;
876   cursor->type = GDK_CURSOR_IS_PIXMAP;
877   cursor->ref_count = 1;
878   
879   return cursor;
880 }
881
882 GdkCursor *
883 gdk_cursor_new_from_pixbuf (GdkDisplay *display, 
884                             GdkPixbuf  *pixbuf,
885                             gint        x,
886                             gint        y)
887 {
888   GdkCursor *cursor;
889   cairo_surface_t *pixmap, *mask;
890   guint width, height, n_channels, rowstride, data_stride, i, j;
891   guint8 *data, *mask_data, *pixels;
892   GdkColor fg = { 0, 0, 0, 0 };
893   GdkColor bg = { 0, 0xffff, 0xffff, 0xffff };
894   GdkScreen *screen;
895   cairo_surface_t *image;
896   cairo_t *cr;
897
898   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
899   g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
900
901   width = gdk_pixbuf_get_width (pixbuf);
902   height = gdk_pixbuf_get_height (pixbuf);
903
904   g_return_val_if_fail (0 <= x && x < width, NULL);
905   g_return_val_if_fail (0 <= y && y < height, NULL);
906
907   n_channels = gdk_pixbuf_get_n_channels (pixbuf);
908   rowstride = gdk_pixbuf_get_rowstride (pixbuf);
909   pixels = gdk_pixbuf_get_pixels (pixbuf);
910
911   data_stride = 4 * ((width + 31) / 32);
912   data = g_new0 (guint8, data_stride * height);
913   mask_data = g_new0 (guint8, data_stride * height);
914
915   for (j = 0; j < height; j++)
916     {
917       guint8 *src = pixels + j * rowstride;
918       guint8 *d = data + data_stride * j;
919       guint8 *md = mask_data + data_stride * j;
920         
921       for (i = 0; i < width; i++)
922         {
923           if (src[1] < 0x80)
924             *d |= 1 << (i % 8);
925           
926           if (n_channels == 3 || src[3] >= 0x80)
927             *md |= 1 << (i % 8);
928           
929           src += n_channels;
930           if (i % 8 == 7)
931             {
932               d++; 
933               md++;
934             }
935         }
936     }
937       
938   screen = gdk_display_get_default_screen (display);
939
940   pixmap = _gdk_x11_window_create_bitmap_surface (gdk_screen_get_root_window (screen), 
941                                                   width, height);
942   cr = cairo_create (pixmap);
943   image = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_A1,
944                                                width, height, data_stride);
945   cairo_set_source_surface (cr, image, 0, 0);
946   cairo_surface_destroy (image);
947   cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
948   cairo_paint (cr);
949   cairo_destroy (cr);
950  
951   mask = _gdk_x11_window_create_bitmap_surface (gdk_screen_get_root_window (screen), 
952                                                 width, height);
953   cr = cairo_create (mask);
954   image = cairo_image_surface_create_for_data (mask_data, CAIRO_FORMAT_A1,
955                                                width, height, data_stride);
956   cairo_set_source_surface (cr, image, 0, 0);
957   cairo_surface_destroy (image);
958   cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
959   cairo_paint (cr);
960   cairo_destroy (cr);
961  
962   cursor = gdk_cursor_new_from_pixmap (display,
963                                        cairo_xlib_surface_get_drawable (pixmap),
964                                        cairo_xlib_surface_get_drawable (mask),
965                                        &fg, &bg,
966                                        x, y);
967    
968   cairo_surface_destroy (pixmap);
969   cairo_surface_destroy (mask);
970
971   g_free (data);
972   g_free (mask_data);
973   
974   return cursor;
975 }
976
977 GdkCursor*  
978 gdk_cursor_new_from_name (GdkDisplay  *display,
979                           const gchar *name)
980 {
981   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
982
983   return NULL;
984 }
985
986 gboolean 
987 gdk_display_supports_cursor_alpha (GdkDisplay    *display)
988 {
989   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
990
991   return FALSE;
992 }
993
994 gboolean 
995 gdk_display_supports_cursor_color (GdkDisplay    *display)
996 {
997   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
998
999   return FALSE;
1000 }
1001
1002 guint     
1003 gdk_display_get_default_cursor_size (GdkDisplay    *display)
1004 {
1005   g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
1006   
1007   /* no idea, really */
1008   return 20; 
1009 }
1010
1011 #endif
1012
1013
1014 /**
1015  * gdk_display_get_maximal_cursor_size:
1016  * @display: a #GdkDisplay
1017  * @width: (out): the return location for the maximal cursor width
1018  * @height: (out): the return location for the maximal cursor height
1019  *
1020  * Gets the maximal size to use for cursors on @display.
1021  *
1022  * Since: 2.4
1023  */
1024 void     
1025 gdk_display_get_maximal_cursor_size (GdkDisplay *display,
1026                                      guint       *width,
1027                                      guint       *height)
1028 {
1029   GdkScreen *screen;
1030   GdkWindow *window;
1031
1032   g_return_if_fail (GDK_IS_DISPLAY (display));
1033   
1034   screen = gdk_display_get_default_screen (display);
1035   window = gdk_screen_get_root_window (screen);
1036   XQueryBestCursor (GDK_DISPLAY_XDISPLAY (display), 
1037                     GDK_WINDOW_XWINDOW (window), 
1038                     128, 128, width, height);
1039 }