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