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