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