]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkcursor-x11.c
x11: Make fallback pixbuf-cursor code not use old constructors
[~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   GdkPixmap *pixmap;
161   Pixmap source_pixmap;
162   XColor color;
163   Cursor cursor;
164
165   screen = gdk_display_get_default_screen (display);
166   pixmap = gdk_bitmap_create_from_data (gdk_screen_get_root_window (screen), 
167                                         "\0\0\0\0\0\0\0\0", 1, 1);
168  
169   source_pixmap = GDK_PIXMAP_XID (pixmap);
170
171   color.pixel = 0; 
172   color.red = color.blue = color.green = 0;
173   
174   if (display->closed)
175     cursor = None;
176   else
177     cursor = XCreatePixmapCursor (GDK_DISPLAY_XDISPLAY (display),
178                                   source_pixmap, source_pixmap,
179                                   &color, &color, 1, 1);
180   g_object_unref (pixmap);
181
182   return cursor;
183 }
184
185 /**
186  * gdk_cursor_new_for_display:
187  * @display: the #GdkDisplay for which the cursor will be created
188  * @cursor_type: cursor to create
189  * 
190  * Creates a new cursor from the set of builtin cursors.
191  * Some useful ones are:
192  * <itemizedlist>
193  * <listitem><para>
194  *  <inlinegraphic format="PNG" fileref="right_ptr.png"></inlinegraphic> #GDK_RIGHT_PTR (right-facing arrow)
195  * </para></listitem>
196  * <listitem><para>
197  *  <inlinegraphic format="PNG" fileref="crosshair.png"></inlinegraphic> #GDK_CROSSHAIR (crosshair)
198  * </para></listitem>
199  * <listitem><para>
200  *  <inlinegraphic format="PNG" fileref="xterm.png"></inlinegraphic> #GDK_XTERM (I-beam)
201  * </para></listitem>
202  * <listitem><para>
203  * <inlinegraphic format="PNG" fileref="watch.png"></inlinegraphic> #GDK_WATCH (busy)
204  * </para></listitem>
205  * <listitem><para>
206  * <inlinegraphic format="PNG" fileref="fleur.png"></inlinegraphic> #GDK_FLEUR (for moving objects)
207  * </para></listitem>
208  * <listitem><para>
209  * <inlinegraphic format="PNG" fileref="hand1.png"></inlinegraphic> #GDK_HAND1 (a right-pointing hand)
210  * </para></listitem>
211  * <listitem><para>
212  * <inlinegraphic format="PNG" fileref="hand2.png"></inlinegraphic> #GDK_HAND2 (a left-pointing hand)
213  * </para></listitem>
214  * <listitem><para>
215  * <inlinegraphic format="PNG" fileref="left_side.png"></inlinegraphic> #GDK_LEFT_SIDE (resize left side)
216  * </para></listitem>
217  * <listitem><para>
218  * <inlinegraphic format="PNG" fileref="right_side.png"></inlinegraphic> #GDK_RIGHT_SIDE (resize right side)
219  * </para></listitem>
220  * <listitem><para>
221  * <inlinegraphic format="PNG" fileref="top_left_corner.png"></inlinegraphic> #GDK_TOP_LEFT_CORNER (resize northwest corner)
222  * </para></listitem>
223  * <listitem><para>
224  * <inlinegraphic format="PNG" fileref="top_right_corner.png"></inlinegraphic> #GDK_TOP_RIGHT_CORNER (resize northeast corner)
225  * </para></listitem>
226  * <listitem><para>
227  * <inlinegraphic format="PNG" fileref="bottom_left_corner.png"></inlinegraphic> #GDK_BOTTOM_LEFT_CORNER (resize southwest corner)
228  * </para></listitem>
229  * <listitem><para>
230  * <inlinegraphic format="PNG" fileref="bottom_right_corner.png"></inlinegraphic> #GDK_BOTTOM_RIGHT_CORNER (resize southeast corner)
231  * </para></listitem>
232  * <listitem><para>
233  * <inlinegraphic format="PNG" fileref="top_side.png"></inlinegraphic> #GDK_TOP_SIDE (resize top side)
234  * </para></listitem>
235  * <listitem><para>
236  * <inlinegraphic format="PNG" fileref="bottom_side.png"></inlinegraphic> #GDK_BOTTOM_SIDE (resize bottom side)
237  * </para></listitem>
238  * <listitem><para>
239  * <inlinegraphic format="PNG" fileref="sb_h_double_arrow.png"></inlinegraphic> #GDK_SB_H_DOUBLE_ARROW (move vertical splitter)
240  * </para></listitem>
241  * <listitem><para>
242  * <inlinegraphic format="PNG" fileref="sb_v_double_arrow.png"></inlinegraphic> #GDK_SB_V_DOUBLE_ARROW (move horizontal splitter)
243  * </para></listitem>
244  * <listitem><para>
245  * #GDK_BLANK_CURSOR (Blank cursor). Since 2.16
246  * </para></listitem>
247  * </itemizedlist>
248  *
249  * Return value: a new #GdkCursor
250  *
251  * Since: 2.2
252  **/
253 GdkCursor*
254 gdk_cursor_new_for_display (GdkDisplay    *display,
255                             GdkCursorType  cursor_type)
256 {
257   GdkCursorPrivate *private;
258   GdkCursor *cursor;
259   Cursor xcursor;
260
261   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
262
263   if (display->closed)
264     {
265       xcursor = None;
266     } 
267   else 
268     {
269       private = find_in_cache (display, cursor_type, NULL);
270
271       if (private)
272         {
273           /* Cache had it, add a ref for this user */
274           gdk_cursor_ref ((GdkCursor*) private);
275        
276           return (GdkCursor*) private;
277         } 
278       else 
279         {
280           if (cursor_type != GDK_BLANK_CURSOR)
281             xcursor = XCreateFontCursor (GDK_DISPLAY_XDISPLAY (display),
282                                          cursor_type);
283           else
284             xcursor = get_blank_cursor (display);
285        }
286     }
287   
288   private = g_new (GdkCursorPrivate, 1);
289   private->display = display;
290   private->xcursor = xcursor;
291   private->name = NULL;
292   private->serial = theme_serial;
293
294   cursor = (GdkCursor *) private;
295   cursor->type = cursor_type;
296   cursor->ref_count = 1;
297   
298   if (xcursor != None)
299     add_to_cache (private);
300
301   return cursor;
302 }
303
304 /**
305  * gdk_cursor_new_from_pixmap:
306  * @source: the pixmap specifying the cursor.
307  * @mask: the pixmap specifying the mask, which must be the same size as 
308  *    @source.
309  * @fg: the foreground color, used for the bits in the source which are 1.
310  *    The color does not have to be allocated first. 
311  * @bg: the background color, used for the bits in the source which are 0.
312  *    The color does not have to be allocated first.
313  * @x: the horizontal offset of the 'hotspot' of the cursor. 
314  * @y: the vertical offset of the 'hotspot' of the cursor.
315  * 
316  * Creates a new cursor from a given pixmap and mask. Both the pixmap and mask
317  * must have a depth of 1 (i.e. each pixel has only 2 values - on or off).
318  * The standard cursor size is 16 by 16 pixels. You can create a bitmap 
319  * from inline data as in the below example.
320  * 
321  * <example><title>Creating a custom cursor</title>
322  * <programlisting>
323  * /<!-- -->* This data is in X bitmap format, and can be created with the 'bitmap'
324  *    utility. *<!-- -->/
325  * &num;define cursor1_width 16
326  * &num;define cursor1_height 16
327  * static unsigned char cursor1_bits[] = {
328  *   0x80, 0x01, 0x40, 0x02, 0x20, 0x04, 0x10, 0x08, 0x08, 0x10, 0x04, 0x20,
329  *   0x82, 0x41, 0x41, 0x82, 0x41, 0x82, 0x82, 0x41, 0x04, 0x20, 0x08, 0x10,
330  *   0x10, 0x08, 0x20, 0x04, 0x40, 0x02, 0x80, 0x01};
331  *  
332  * static unsigned char cursor1mask_bits[] = {
333  *   0x80, 0x01, 0xc0, 0x03, 0x60, 0x06, 0x30, 0x0c, 0x18, 0x18, 0x8c, 0x31,
334  *   0xc6, 0x63, 0x63, 0xc6, 0x63, 0xc6, 0xc6, 0x63, 0x8c, 0x31, 0x18, 0x18,
335  *   0x30, 0x0c, 0x60, 0x06, 0xc0, 0x03, 0x80, 0x01};
336  *  
337  *  
338  *  GdkCursor *cursor;
339  *  GdkPixmap *source, *mask;
340  *  GdkColor fg = { 0, 65535, 0, 0 }; /<!-- -->* Red. *<!-- -->/
341  *  GdkColor bg = { 0, 0, 0, 65535 }; /<!-- -->* Blue. *<!-- -->/
342  *  
343  *  
344  *  source = gdk_bitmap_create_from_data (NULL, cursor1_bits,
345  *                                        cursor1_width, cursor1_height);
346  *  mask = gdk_bitmap_create_from_data (NULL, cursor1mask_bits,
347  *                                      cursor1_width, cursor1_height);
348  *  cursor = gdk_cursor_new_from_pixmap (source, mask, &amp;fg, &amp;bg, 8, 8);
349  *  g_object_unref (source);
350  *  g_object_unref (mask);
351  *  
352  *  
353  *  gdk_window_set_cursor (widget->window, cursor);
354  * </programlisting>
355  * </example>
356  *
357  * Return value: a new #GdkCursor.
358  **/
359 GdkCursor*
360 gdk_cursor_new_from_pixmap (GdkPixmap      *source,
361                             GdkPixmap      *mask,
362                             const GdkColor *fg,
363                             const GdkColor *bg,
364                             gint            x,
365                             gint            y)
366 {
367   GdkCursorPrivate *private;
368   GdkCursor *cursor;
369   Pixmap source_pixmap, mask_pixmap;
370   Cursor xcursor;
371   XColor xfg, xbg;
372   GdkDisplay *display;
373
374   g_return_val_if_fail (GDK_IS_PIXMAP (source), NULL);
375   g_return_val_if_fail (GDK_IS_PIXMAP (mask), NULL);
376   g_return_val_if_fail (fg != NULL, NULL);
377   g_return_val_if_fail (bg != NULL, NULL);
378
379   source_pixmap = GDK_PIXMAP_XID (source);
380   mask_pixmap   = GDK_PIXMAP_XID (mask);
381   display = GDK_PIXMAP_DISPLAY (source);
382
383   xfg.pixel = fg->pixel;
384   xfg.red = fg->red;
385   xfg.blue = fg->blue;
386   xfg.green = fg->green;
387   xbg.pixel = bg->pixel;
388   xbg.red = bg->red;
389   xbg.blue = bg->blue;
390   xbg.green = bg->green;
391   
392   if (display->closed)
393     xcursor = None;
394   else
395     xcursor = XCreatePixmapCursor (GDK_DISPLAY_XDISPLAY (display),
396                                    source_pixmap, mask_pixmap, &xfg, &xbg, x, y);
397   private = g_new (GdkCursorPrivate, 1);
398   private->display = display;
399   private->xcursor = xcursor;
400   private->name = NULL;
401   private->serial = theme_serial;
402
403   cursor = (GdkCursor *) private;
404   cursor->type = GDK_CURSOR_IS_PIXMAP;
405   cursor->ref_count = 1;
406   
407   return cursor;
408 }
409
410 void
411 _gdk_cursor_destroy (GdkCursor *cursor)
412 {
413   GdkCursorPrivate *private;
414
415   g_return_if_fail (cursor != NULL);
416   g_return_if_fail (cursor->ref_count == 0);
417
418   private = (GdkCursorPrivate *) cursor;
419   if (!private->display->closed && private->xcursor)
420     XFreeCursor (GDK_DISPLAY_XDISPLAY (private->display), private->xcursor);
421
422   g_free (private->name);
423   g_free (private);
424 }
425
426 /**
427  * gdk_x11_cursor_get_xdisplay:
428  * @cursor: a #GdkCursor.
429  * 
430  * Returns the display of a #GdkCursor.
431  * 
432  * Return value: an Xlib <type>Display*</type>.
433  **/
434 Display *
435 gdk_x11_cursor_get_xdisplay (GdkCursor *cursor)
436 {
437   g_return_val_if_fail (cursor != NULL, NULL);
438
439   return GDK_DISPLAY_XDISPLAY(((GdkCursorPrivate *)cursor)->display);
440 }
441
442 /**
443  * gdk_x11_cursor_get_xcursor:
444  * @cursor: a #GdkCursor.
445  * 
446  * Returns the X cursor belonging to a #GdkCursor.
447  * 
448  * Return value: an Xlib <type>Cursor</type>.
449  **/
450 Cursor
451 gdk_x11_cursor_get_xcursor (GdkCursor *cursor)
452 {
453   g_return_val_if_fail (cursor != NULL, None);
454
455   return ((GdkCursorPrivate *)cursor)->xcursor;
456 }
457
458 /** 
459  * gdk_cursor_get_display:
460  * @cursor: a #GdkCursor.
461  *
462  * Returns the display on which the #GdkCursor is defined.
463  *
464  * Returns: the #GdkDisplay associated to @cursor
465  *
466  * Since: 2.2
467  */
468
469 GdkDisplay *
470 gdk_cursor_get_display (GdkCursor *cursor)
471 {
472   g_return_val_if_fail (cursor != NULL, NULL);
473
474   return ((GdkCursorPrivate *)cursor)->display;
475 }
476
477 #if defined(HAVE_XCURSOR) && defined(HAVE_XFIXES) && XFIXES_MAJOR >= 2
478
479 /**
480  * gdk_cursor_get_image:
481  * @cursor: a #GdkCursor
482  *
483  * Returns a #GdkPixbuf with the image used to display the cursor.
484  *
485  * Note that depending on the capabilities of the windowing system and 
486  * on the cursor, GDK may not be able to obtain the image data. In this 
487  * case, %NULL is returned.
488  *
489  * Returns: a #GdkPixbuf representing @cursor, or %NULL
490  *
491  * Since: 2.8
492  */
493 GdkPixbuf*  
494 gdk_cursor_get_image (GdkCursor *cursor)
495 {
496   Display *xdisplay;
497   GdkCursorPrivate *private;
498   XcursorImages *images = NULL;
499   XcursorImage *image;
500   gint size;
501   gchar buf[32];
502   guchar *data, *p, tmp;
503   GdkPixbuf *pixbuf;
504   gchar *theme;
505   
506   g_return_val_if_fail (cursor != NULL, NULL);
507
508   private = (GdkCursorPrivate *) cursor;
509     
510   xdisplay = GDK_DISPLAY_XDISPLAY (private->display);
511
512   size = XcursorGetDefaultSize (xdisplay);
513   theme = XcursorGetTheme (xdisplay);
514
515   if (cursor->type == GDK_CURSOR_IS_PIXMAP)
516     {
517       if (private->name)
518         images = XcursorLibraryLoadImages (private->name, theme, size);
519     }
520   else 
521     images = XcursorShapeLoadImages (cursor->type, theme, size);
522
523   if (!images)
524     return NULL;
525   
526   image = images->images[0];
527
528   data = g_malloc (4 * image->width * image->height);
529   memcpy (data, image->pixels, 4 * image->width * image->height);
530
531   for (p = data; p < data + (4 * image->width * image->height); p += 4)
532     {
533       tmp = p[0];
534       p[0] = p[2];
535       p[2] = tmp;
536     }
537
538   pixbuf = gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB, TRUE,
539                                      8, image->width, image->height,
540                                      4 * image->width, 
541                                      (GdkPixbufDestroyNotify)g_free, NULL);
542
543   if (private->name)
544     gdk_pixbuf_set_option (pixbuf, "name", private->name);
545   g_snprintf (buf, 32, "%d", image->xhot);
546   gdk_pixbuf_set_option (pixbuf, "x_hot", buf);
547   g_snprintf (buf, 32, "%d", image->yhot);
548   gdk_pixbuf_set_option (pixbuf, "y_hot", buf);
549
550   XcursorImagesDestroy (images);
551
552   return pixbuf;
553 }
554
555 void
556 _gdk_x11_cursor_update_theme (GdkCursor *cursor)
557 {
558   Display *xdisplay;
559   GdkCursorPrivate *private;
560   Cursor new_cursor = None;
561   GdkDisplayX11 *display_x11;
562
563   private = (GdkCursorPrivate *) cursor;
564   xdisplay = GDK_DISPLAY_XDISPLAY (private->display);
565   display_x11 = GDK_DISPLAY_X11 (private->display);
566
567   if (!display_x11->have_xfixes)
568     return;
569
570   if (private->serial == theme_serial)
571     return;
572
573   private->serial = theme_serial;
574
575   if (private->xcursor != None)
576     {
577       if (cursor->type == GDK_BLANK_CURSOR)
578         return;
579
580       if (cursor->type == GDK_CURSOR_IS_PIXMAP)
581         {
582           if (private->name)
583             new_cursor = XcursorLibraryLoadCursor (xdisplay, private->name);
584         }
585       else 
586         new_cursor = XcursorShapeLoadCursor (xdisplay, cursor->type);
587       
588       if (new_cursor != None)
589         {
590           XFixesChangeCursor (xdisplay, new_cursor, private->xcursor);
591           private->xcursor = new_cursor;
592         }
593     }
594 }
595
596 static void
597 update_cursor (gpointer data,
598                gpointer user_data)
599 {
600   GdkCursor *cursor;
601
602   cursor = (GdkCursor*)(data);
603
604   if (!cursor)
605     return;
606   
607   _gdk_x11_cursor_update_theme (cursor);
608 }
609
610 /**
611  * gdk_x11_display_set_cursor_theme:
612  * @display: a #GdkDisplay
613  * @theme: the name of the cursor theme to use, or %NULL to unset
614  *         a previously set value 
615  * @size: the cursor size to use, or 0 to keep the previous size
616  *
617  * Sets the cursor theme from which the images for cursor
618  * should be taken. 
619  * 
620  * If the windowing system supports it, existing cursors created 
621  * with gdk_cursor_new(), gdk_cursor_new_for_display() and 
622  * gdk_cursor_new_for_name() are updated to reflect the theme 
623  * change. Custom cursors constructed with gdk_cursor_new_from_pixmap() 
624  * or gdk_cursor_new_from_pixbuf() will have to be handled
625  * by the application (GTK+ applications can learn about 
626  * cursor theme changes by listening for change notification
627  * for the corresponding #GtkSetting).
628  *
629  * Since: 2.8
630  */
631 void
632 gdk_x11_display_set_cursor_theme (GdkDisplay  *display,
633                                   const gchar *theme,
634                                   const gint   size)
635 {
636   GdkDisplayX11 *display_x11;
637   Display *xdisplay;
638   gchar *old_theme;
639   gint old_size;
640
641   g_return_if_fail (GDK_IS_DISPLAY (display));
642
643   display_x11 = GDK_DISPLAY_X11 (display);
644   xdisplay = GDK_DISPLAY_XDISPLAY (display);
645
646   old_theme = XcursorGetTheme (xdisplay);
647   old_size = XcursorGetDefaultSize (xdisplay);
648
649   if (old_size == size &&
650       (old_theme == theme ||
651        (old_theme && theme && strcmp (old_theme, theme) == 0)))
652     return;
653
654   theme_serial++;
655
656   XcursorSetTheme (xdisplay, theme);
657   if (size > 0)
658     XcursorSetDefaultSize (xdisplay, size);
659     
660   g_slist_foreach (cursor_cache, update_cursor, NULL);
661 }
662
663 #else
664
665 GdkPixbuf*  
666 gdk_cursor_get_image (GdkCursor *cursor)
667 {
668   g_return_val_if_fail (cursor != NULL, NULL);
669   
670   return NULL;
671 }
672
673 void
674 gdk_x11_display_set_cursor_theme (GdkDisplay  *display,
675                                   const gchar *theme,
676                                   const gint   size)
677 {
678   g_return_if_fail (GDK_IS_DISPLAY (display));
679 }
680
681 void
682 _gdk_x11_cursor_update_theme (GdkCursor *cursor)
683 {
684   g_return_if_fail (cursor != NULL);
685 }
686
687 #endif
688
689 #ifdef HAVE_XCURSOR
690
691 static XcursorImage*
692 create_cursor_image (GdkPixbuf *pixbuf,
693                      gint       x,
694                      gint       y)
695 {
696   guint width, height, rowstride, n_channels;
697   guchar *pixels, *src;
698   XcursorImage *xcimage;
699   XcursorPixel *dest;
700
701   width = gdk_pixbuf_get_width (pixbuf);
702   height = gdk_pixbuf_get_height (pixbuf);
703
704   n_channels = gdk_pixbuf_get_n_channels (pixbuf);
705   rowstride = gdk_pixbuf_get_rowstride (pixbuf);
706   pixels = gdk_pixbuf_get_pixels (pixbuf);
707
708   xcimage = XcursorImageCreate (width, height);
709
710   xcimage->xhot = x;
711   xcimage->yhot = y;
712
713   dest = xcimage->pixels;
714
715   if (n_channels == 3)
716     {
717       gint i, j;
718
719       for (j = 0; j < height; j++)
720         {
721           src = pixels + j * rowstride;
722           for (i = 0; i < width; i++)
723             {
724               *dest = (0xff << 24) | (src[0] << 16) | (src[1] << 8) | src[2];
725             }
726
727           src += n_channels;
728           dest++;
729         }
730     }
731   else
732     {
733       _gdk_x11_convert_to_format (pixels, rowstride,
734                                   (guchar *) dest, 4 * width,
735                                   GDK_X11_FORMAT_ARGB,
736                                   (G_BYTE_ORDER == G_BIG_ENDIAN) ?
737                                   GDK_MSB_FIRST : GDK_LSB_FIRST,
738                                   width, height);
739     }
740
741   return xcimage;
742 }
743
744
745 /**
746  * gdk_cursor_new_from_pixbuf:
747  * @display: the #GdkDisplay for which the cursor will be created
748  * @pixbuf: the #GdkPixbuf containing the cursor image
749  * @x: the horizontal offset of the 'hotspot' of the cursor. 
750  * @y: the vertical offset of the 'hotspot' of the cursor.
751  *
752  * Creates a new cursor from a pixbuf. 
753  *
754  * Not all GDK backends support RGBA cursors. If they are not 
755  * supported, a monochrome approximation will be displayed. 
756  * The functions gdk_display_supports_cursor_alpha() and 
757  * gdk_display_supports_cursor_color() can be used to determine
758  * whether RGBA cursors are supported; 
759  * gdk_display_get_default_cursor_size() and 
760  * gdk_display_get_maximal_cursor_size() give information about 
761  * cursor sizes.
762  *
763  * On the X backend, support for RGBA cursors requires a
764  * sufficently new version of the X Render extension. 
765  *
766  * Returns: a new #GdkCursor.
767  * 
768  * Since: 2.4
769  */
770 GdkCursor *
771 gdk_cursor_new_from_pixbuf (GdkDisplay *display, 
772                             GdkPixbuf  *pixbuf,
773                             gint        x,
774                             gint        y)
775 {
776   XcursorImage *xcimage;
777   Cursor xcursor;
778   GdkCursorPrivate *private;
779   GdkCursor *cursor;
780
781   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
782   g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
783   g_return_val_if_fail (0 <= x && x < gdk_pixbuf_get_width (pixbuf), NULL);
784   g_return_val_if_fail (0 <= y && y < gdk_pixbuf_get_height (pixbuf), NULL);
785
786   if (display->closed)
787     xcursor = None;
788   else 
789     {
790       xcimage = create_cursor_image (pixbuf, x, y);
791       xcursor = XcursorImageLoadCursor (GDK_DISPLAY_XDISPLAY (display), xcimage);
792       XcursorImageDestroy (xcimage);
793     }
794
795   private = g_new (GdkCursorPrivate, 1);
796   private->display = display;
797   private->xcursor = xcursor;
798   private->name = NULL;
799   private->serial = theme_serial;
800
801   cursor = (GdkCursor *) private;
802   cursor->type = GDK_CURSOR_IS_PIXMAP;
803   cursor->ref_count = 1;
804   
805   return cursor;
806 }
807
808 /**
809  * gdk_cursor_new_from_name:
810  * @display: the #GdkDisplay for which the cursor will be created
811  * @name: the name of the cursor
812  *
813  * Creates a new cursor by looking up @name in the current cursor
814  * theme. 
815  * 
816  * Returns: a new #GdkCursor, or %NULL if there is no cursor with 
817  *   the given name 
818  *
819  * Since: 2.8
820  */
821 GdkCursor*  
822 gdk_cursor_new_from_name (GdkDisplay  *display,
823                           const gchar *name)
824 {
825   Cursor xcursor;
826   Display *xdisplay;
827   GdkCursorPrivate *private;
828   GdkCursor *cursor;
829
830   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
831
832   if (display->closed)
833     xcursor = None;
834   else 
835     {
836       private = find_in_cache (display, GDK_CURSOR_IS_PIXMAP, name);
837
838       if (private)
839         {
840           /* Cache had it, add a ref for this user */
841           gdk_cursor_ref ((GdkCursor*) private);
842
843           return (GdkCursor*) private;
844         }
845
846       xdisplay = GDK_DISPLAY_XDISPLAY (display);
847       xcursor = XcursorLibraryLoadCursor (xdisplay, name);
848       if (xcursor == None)
849         return NULL;
850     }
851
852   private = g_new (GdkCursorPrivate, 1);
853   private->display = display;
854   private->xcursor = xcursor;
855   private->name = g_strdup (name);
856   private->serial = theme_serial;
857
858   cursor = (GdkCursor *) private;
859   cursor->type = GDK_CURSOR_IS_PIXMAP;
860   cursor->ref_count = 1;
861   add_to_cache (private);
862
863   return cursor;
864 }
865
866 /**
867  * gdk_display_supports_cursor_alpha:
868  * @display: a #GdkDisplay
869  *
870  * Returns %TRUE if cursors can use an 8bit alpha channel 
871  * on @display. Otherwise, cursors are restricted to bilevel 
872  * alpha (i.e. a mask).
873  *
874  * Returns: whether cursors can have alpha channels.
875  *
876  * Since: 2.4
877  */
878 gboolean 
879 gdk_display_supports_cursor_alpha (GdkDisplay *display)
880 {
881   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
882
883   return XcursorSupportsARGB (GDK_DISPLAY_XDISPLAY (display));
884 }
885
886 /**
887  * gdk_display_supports_cursor_color:
888  * @display: a #GdkDisplay
889  *
890  * Returns %TRUE if multicolored cursors are supported
891  * on @display. Otherwise, cursors have only a forground
892  * and a background color.
893  *
894  * Returns: whether cursors can have multiple colors.
895  *
896  * Since: 2.4
897  */
898 gboolean 
899 gdk_display_supports_cursor_color (GdkDisplay *display)
900 {
901   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
902
903   return XcursorSupportsARGB (GDK_DISPLAY_XDISPLAY (display));
904 }
905
906 /**
907  * gdk_display_get_default_cursor_size:
908  * @display: a #GdkDisplay
909  *
910  * Returns the default size to use for cursors on @display.
911  *
912  * Returns: the default cursor size.
913  *
914  * Since: 2.4
915  */
916 guint     
917 gdk_display_get_default_cursor_size (GdkDisplay *display)
918 {
919   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
920
921   return XcursorGetDefaultSize (GDK_DISPLAY_XDISPLAY (display));
922 }
923
924 #else
925
926 GdkCursor *
927 gdk_cursor_new_from_pixbuf (GdkDisplay *display, 
928                             GdkPixbuf  *pixbuf,
929                             gint        x,
930                             gint        y)
931 {
932   GdkCursor *cursor;
933   GdkPixmap *pixmap, *mask;
934   guint width, height, n_channels, rowstride, data_stride, i, j;
935   guint8 *data, *mask_data, *pixels;
936   GdkColor fg = { 0, 0, 0, 0 };
937   GdkColor bg = { 0, 0xffff, 0xffff, 0xffff };
938   GdkScreen *screen;
939   cairo_surface_t *image;
940   cairo_t *cr;
941
942   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
943   g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
944
945   width = gdk_pixbuf_get_width (pixbuf);
946   height = gdk_pixbuf_get_height (pixbuf);
947
948   g_return_val_if_fail (0 <= x && x < width, NULL);
949   g_return_val_if_fail (0 <= y && y < height, NULL);
950
951   n_channels = gdk_pixbuf_get_n_channels (pixbuf);
952   rowstride = gdk_pixbuf_get_rowstride (pixbuf);
953   pixels = gdk_pixbuf_get_pixels (pixbuf);
954
955   data_stride = 4 * ((width + 31) / 32);
956   data = g_new0 (guint8, data_stride * height);
957   mask_data = g_new0 (guint8, data_stride * height);
958
959   for (j = 0; j < height; j++)
960     {
961       guint8 *src = pixels + j * rowstride;
962       guint8 *d = data + data_stride * j;
963       guint8 *md = mask_data + data_stride * j;
964         
965       for (i = 0; i < width; i++)
966         {
967           if (src[1] < 0x80)
968             *d |= 1 << (i % 8);
969           
970           if (n_channels == 3 || src[3] >= 0x80)
971             *md |= 1 << (i % 8);
972           
973           src += n_channels;
974           if (i % 8 == 7)
975             {
976               d++; 
977               md++;
978             }
979         }
980     }
981       
982   screen = gdk_display_get_default_screen (display);
983
984   pixmap = gdk_pixmap_new (gdk_screen_get_root_window (screen), 
985                            width, height, 1);
986   cr = gdk_cairo_create (pixmap);
987   image = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_A1,
988                                                width, height, data_stride);
989   cairo_set_source_surface (cr, image, 0, 0);
990   cairo_surface_destroy (image);
991   cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
992   cairo_paint (cr);
993   cairo_destroy (cr);
994  
995   mask = gdk_pixmap_new (gdk_screen_get_root_window (screen), 
996                          width, height, 1);
997   cr = gdk_cairo_create (mask);
998   image = cairo_image_surface_create_for_data (mask_data, CAIRO_FORMAT_A1,
999                                                width, height, data_stride);
1000   cairo_set_source_surface (cr, image, 0, 0);
1001   cairo_surface_destroy (image);
1002   cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
1003   cairo_paint (cr);
1004   cairo_destroy (cr);
1005  
1006   cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, x, y);
1007    
1008   g_object_unref (pixmap);
1009   g_object_unref (mask);
1010
1011   g_free (data);
1012   g_free (mask_data);
1013   
1014   return cursor;
1015 }
1016
1017 GdkCursor*  
1018 gdk_cursor_new_from_name (GdkDisplay  *display,
1019                           const gchar *name)
1020 {
1021   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
1022
1023   return NULL;
1024 }
1025
1026 gboolean 
1027 gdk_display_supports_cursor_alpha (GdkDisplay    *display)
1028 {
1029   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
1030
1031   return FALSE;
1032 }
1033
1034 gboolean 
1035 gdk_display_supports_cursor_color (GdkDisplay    *display)
1036 {
1037   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
1038
1039   return FALSE;
1040 }
1041
1042 guint     
1043 gdk_display_get_default_cursor_size (GdkDisplay    *display)
1044 {
1045   g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
1046   
1047   /* no idea, really */
1048   return 20; 
1049 }
1050
1051 #endif
1052
1053
1054 /**
1055  * gdk_display_get_maximal_cursor_size:
1056  * @display: a #GdkDisplay
1057  * @width: (out): the return location for the maximal cursor width
1058  * @height: (out): the return location for the maximal cursor height
1059  *
1060  * Gets the maximal size to use for cursors on @display.
1061  *
1062  * Since: 2.4
1063  */
1064 void     
1065 gdk_display_get_maximal_cursor_size (GdkDisplay *display,
1066                                      guint       *width,
1067                                      guint       *height)
1068 {
1069   GdkScreen *screen;
1070   GdkWindow *window;
1071
1072   g_return_if_fail (GDK_IS_DISPLAY (display));
1073   
1074   screen = gdk_display_get_default_screen (display);
1075   window = gdk_screen_get_root_window (screen);
1076   XQueryBestCursor (GDK_DISPLAY_XDISPLAY (display), 
1077                     GDK_WINDOW_XWINDOW (window), 
1078                     128, 128, width, height);
1079 }