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