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