]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkcursor-x11.c
Don't export gdk_x11_cursor_finalize
[~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           gdk_cursor_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", GDK_CURSOR_IS_PIXMAP,
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: a #GdkCursor.
290  * 
291  * Returns the display of a #GdkCursor.
292  * 
293  * Return value: 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: 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: 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   GdkX11Display *display_x11;
463   Display *xdisplay;
464   gchar *old_theme;
465   gint old_size;
466
467   g_return_if_fail (GDK_IS_DISPLAY (display));
468
469   display_x11 = GDK_X11_DISPLAY (display);
470   xdisplay = GDK_DISPLAY_XDISPLAY (display);
471
472   old_theme = XcursorGetTheme (xdisplay);
473   old_size = XcursorGetDefaultSize (xdisplay);
474
475   if (old_size == size &&
476       (old_theme == theme ||
477        (old_theme && theme && strcmp (old_theme, theme) == 0)))
478     return;
479
480   theme_serial++;
481
482   XcursorSetTheme (xdisplay, theme);
483   if (size > 0)
484     XcursorSetDefaultSize (xdisplay, size);
485     
486   g_slist_foreach (cursor_cache, update_cursor, NULL);
487 }
488
489 #else
490
491 static GdkPixbuf*  
492 gdk_x11_cursor_get_image (GdkCursor *cursor)
493 {
494   return NULL;
495 }
496
497 void
498 gdk_x11_display_set_cursor_theme (GdkDisplay  *display,
499                                   const gchar *theme,
500                                   const gint   size)
501 {
502   g_return_if_fail (GDK_IS_DISPLAY (display));
503 }
504
505 void
506 _gdk_x11_cursor_update_theme (GdkCursor *cursor)
507 {
508   g_return_if_fail (cursor != NULL);
509 }
510
511 #endif
512
513 #ifdef HAVE_XCURSOR
514
515 static XcursorImage*
516 create_cursor_image (GdkPixbuf *pixbuf,
517                      gint       x,
518                      gint       y)
519 {
520   guint width, height;
521   XcursorImage *xcimage;
522   cairo_surface_t *surface;
523   cairo_t *cr;
524
525   width = gdk_pixbuf_get_width (pixbuf);
526   height = gdk_pixbuf_get_height (pixbuf);
527
528   xcimage = XcursorImageCreate (width, height);
529
530   xcimage->xhot = x;
531   xcimage->yhot = y;
532
533   surface = cairo_image_surface_create_for_data ((guchar *) xcimage->pixels,
534                                                  CAIRO_FORMAT_ARGB32,
535                                                  width,
536                                                  height,
537                                                  width * 4);
538
539   cr = cairo_create (surface);
540   cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
541   gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
542   cairo_paint (cr);
543   cairo_destroy (cr);
544
545   cairo_surface_destroy (surface);
546
547   return xcimage;
548 }
549
550 GdkCursor *
551 _gdk_x11_display_get_cursor_for_pixbuf (GdkDisplay *display,
552                                         GdkPixbuf  *pixbuf,
553                                         gint        x,
554                                         gint        y)
555 {
556   XcursorImage *xcimage;
557   Cursor xcursor;
558   GdkX11Cursor *private;
559   const char *option;
560   char *end;
561   gint64 value;
562
563   if (x == -1 && (option = gdk_pixbuf_get_option (pixbuf, "x_hot")))
564     {
565       errno = 0;
566       end = NULL;
567       value = g_ascii_strtoll (option, &end, 10);
568       if (errno == 0 &&
569           end != option &&
570           value >= 0 && value < G_MAXINT)
571         x = (gint) value;
572     }
573   if (y == -1 && (option = gdk_pixbuf_get_option (pixbuf, "y_hot")))
574     {
575       errno = 0;
576       end = NULL;
577       value = g_ascii_strtoll (option, &end, 10);
578       if (errno == 0 &&
579           end != option &&
580           value >= 0 && value < G_MAXINT)
581         y = (gint) value;
582     }
583
584   g_return_val_if_fail (0 <= x && x < gdk_pixbuf_get_width (pixbuf), NULL);
585   g_return_val_if_fail (0 <= y && y < gdk_pixbuf_get_height (pixbuf), NULL);
586
587   if (gdk_display_is_closed (display))
588     {
589       xcursor = None;
590     }
591   else
592     {
593       xcimage = create_cursor_image (pixbuf, x, y);
594       xcursor = XcursorImageLoadCursor (GDK_DISPLAY_XDISPLAY (display), xcimage);
595       XcursorImageDestroy (xcimage);
596     }
597
598   private = g_object_new (GDK_TYPE_X11_CURSOR, 
599                           "cursor-type", GDK_CURSOR_IS_PIXMAP,
600                           "display", display,
601                           NULL);
602   private->xcursor = xcursor;
603   private->name = NULL;
604   private->serial = theme_serial;
605
606   return GDK_CURSOR (private);
607 }
608
609 GdkCursor*
610 _gdk_x11_display_get_cursor_for_name (GdkDisplay  *display,
611                                       const gchar *name)
612 {
613   Cursor xcursor;
614   Display *xdisplay;
615   GdkX11Cursor *private;
616
617   if (gdk_display_is_closed (display))
618     {
619       xcursor = None;
620     }
621   else
622     {
623       private = find_in_cache (display, GDK_CURSOR_IS_PIXMAP, name);
624
625       if (private)
626         {
627           /* Cache had it, add a ref for this user */
628           g_object_ref (private);
629
630           return (GdkCursor*) private;
631         }
632
633       xdisplay = GDK_DISPLAY_XDISPLAY (display);
634       xcursor = XcursorLibraryLoadCursor (xdisplay, name);
635       if (xcursor == None)
636         return NULL;
637     }
638
639   private = g_object_new (GDK_TYPE_X11_CURSOR,
640                           "cursor-type", GDK_CURSOR_IS_PIXMAP,
641                           "display", display,
642                           NULL);
643   private->xcursor = xcursor;
644   private->name = g_strdup (name);
645   private->serial = theme_serial;
646
647   add_to_cache (private);
648
649   return GDK_CURSOR (private);
650 }
651
652 gboolean
653 _gdk_x11_display_supports_cursor_alpha (GdkDisplay *display)
654 {
655   return XcursorSupportsARGB (GDK_DISPLAY_XDISPLAY (display));
656 }
657
658 gboolean
659 _gdk_x11_display_supports_cursor_color (GdkDisplay *display)
660 {
661   return XcursorSupportsARGB (GDK_DISPLAY_XDISPLAY (display));
662 }
663
664 void
665 _gdk_x11_display_get_default_cursor_size (GdkDisplay *display,
666                                           guint      *width,
667                                           guint      *height)
668 {
669   *width = *height = XcursorGetDefaultSize (GDK_DISPLAY_XDISPLAY (display));
670 }
671
672 #else
673
674 static GdkCursor*
675 gdk_cursor_new_from_pixmap (GdkDisplay     *display,
676                             Pixmap          source_pixmap,
677                             Pixmap          mask_pixmap,
678                             const GdkColor *fg,
679                             const GdkColor *bg,
680                             gint            x,
681                             gint            y)
682 {
683   GdkX11Cursor *private;
684   Cursor xcursor;
685   XColor xfg, xbg;
686
687   g_return_val_if_fail (fg != NULL, NULL);
688   g_return_val_if_fail (bg != NULL, NULL);
689
690   xfg.pixel = fg->pixel;
691   xfg.red = fg->red;
692   xfg.blue = fg->blue;
693   xfg.green = fg->green;
694   xbg.pixel = bg->pixel;
695   xbg.red = bg->red;
696   xbg.blue = bg->blue;
697   xbg.green = bg->green;
698   
699   if (gdk_display_is_closed (display->closed))
700     xcursor = None;
701   else
702     xcursor = XCreatePixmapCursor (GDK_DISPLAY_XDISPLAY (display),
703                                    source_pixmap, mask_pixmap, &xfg, &xbg, x, y);
704   private = g_object_new (GDK_TYPE_X11_CURSOR,
705                           "cursor-type", GDK_CURSOR_IS_PIXMAP,
706                           "display", display,
707                           NULL);
708   private->xcursor = xcursor;
709   private->name = NULL;
710   private->serial = theme_serial;
711
712   return GDK_CURSOR (private);
713 }
714
715 GdkCursor *
716 _gdk_x11_display_get_cursor_for_pixbuf (GdkDisplay *display,
717                                         GdkPixbuf  *pixbuf,
718                                         gint        x,
719                                         gint        y)
720 {
721   GdkCursor *cursor;
722   cairo_surface_t *pixmap, *mask;
723   guint width, height, n_channels, rowstride, data_stride, i, j;
724   guint8 *data, *mask_data, *pixels;
725   GdkColor fg = { 0, 0, 0, 0 };
726   GdkColor bg = { 0, 0xffff, 0xffff, 0xffff };
727   GdkScreen *screen;
728   cairo_surface_t *image;
729   cairo_t *cr;
730
731   width = gdk_pixbuf_get_width (pixbuf);
732   height = gdk_pixbuf_get_height (pixbuf);
733
734   g_return_val_if_fail (0 <= x && x < width, NULL);
735   g_return_val_if_fail (0 <= y && y < height, NULL);
736
737   n_channels = gdk_pixbuf_get_n_channels (pixbuf);
738   rowstride = gdk_pixbuf_get_rowstride (pixbuf);
739   pixels = gdk_pixbuf_get_pixels (pixbuf);
740
741   data_stride = 4 * ((width + 31) / 32);
742   data = g_new0 (guint8, data_stride * height);
743   mask_data = g_new0 (guint8, data_stride * height);
744
745   for (j = 0; j < height; j++)
746     {
747       guint8 *src = pixels + j * rowstride;
748       guint8 *d = data + data_stride * j;
749       guint8 *md = mask_data + data_stride * j;
750
751       for (i = 0; i < width; i++)
752         {
753           if (src[1] < 0x80)
754             *d |= 1 << (i % 8);
755
756           if (n_channels == 3 || src[3] >= 0x80)
757             *md |= 1 << (i % 8);
758
759           src += n_channels;
760           if (i % 8 == 7)
761             {
762               d++;
763               md++;
764             }
765         }
766     }
767
768   screen = gdk_display_get_default_screen (display);
769
770   pixmap = _gdk_x11_window_create_bitmap_surface (gdk_screen_get_root_window (screen),
771                                                   width, height);
772   cr = cairo_create (pixmap);
773   image = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_A1,
774                                                width, height, data_stride);
775   cairo_set_source_surface (cr, image, 0, 0);
776   cairo_surface_destroy (image);
777   cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
778   cairo_paint (cr);
779   cairo_destroy (cr);
780
781   mask = _gdk_x11_window_create_bitmap_surface (gdk_screen_get_root_window (screen),
782                                                 width, height);
783   cr = cairo_create (mask);
784   image = cairo_image_surface_create_for_data (mask_data, CAIRO_FORMAT_A1,
785                                                width, height, data_stride);
786   cairo_set_source_surface (cr, image, 0, 0);
787   cairo_surface_destroy (image);
788   cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
789   cairo_paint (cr);
790   cairo_destroy (cr);
791
792   cursor = gdk_cursor_new_from_pixmap (display,
793                                        cairo_xlib_surface_get_drawable (pixmap),
794                                        cairo_xlib_surface_get_drawable (mask),
795                                        &fg, &bg,
796                                        x, y);
797
798   cairo_surface_destroy (pixmap);
799   cairo_surface_destroy (mask);
800
801   g_free (data);
802   g_free (mask_data);
803
804   return cursor;
805 }
806
807 GdkCursor*
808 _gdk_x11_display_get_cursor_for_name (GdkDisplay  *display,
809                                       const gchar *name)
810 {
811   return NULL;
812 }
813
814 gboolean
815 _gdk_x11_display_supports_cursor_alpha (GdkDisplay *display)
816 {
817   return FALSE;
818 }
819
820 gboolean
821 _gdk_x11_display_supports_cursor_color (GdkDisplay *display)
822 {
823   return FALSE;
824 }
825
826 void
827 _gdk_x11_display_get_default_cursor_size (GdkDisplay *display)
828 {
829   /* no idea, really */
830   return 20;
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 }