]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkcursor-x11.c
6a7b3335c949f97123f902515efdbe1e00edec40
[~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 #include <X11/Xlib.h>
29 #include <X11/cursorfont.h>
30 #ifdef HAVE_XCURSOR
31 #include <X11/Xcursor/Xcursor.h>
32 #endif
33
34 #include "gdkprivate-x11.h"
35 #include "gdkcursor.h"
36 #include "gdkpixmap-x11.h"
37 #include "gdkx.h"
38 #include <gdk/gdkpixmap.h>
39 #include <gdk-pixbuf/gdk-pixbuf.h>
40 #include "gdkalias.h"
41
42
43 /**
44  * gdk_cursor_new_for_display:
45  * @display: the #GdkDisplay for which the cursor will be created
46  * @cursor_type: cursor to create
47  * 
48  * Creates a new cursor from the set of builtin cursors.
49  * Some useful ones are:
50  * <itemizedlist>
51  * <listitem><para>
52  *  <inlinegraphic format="PNG" fileref="right_ptr.png"></inlinegraphic> #GDK_RIGHT_PTR (right-facing arrow)
53  * </para></listitem>
54  * <listitem><para>
55  *  <inlinegraphic format="PNG" fileref="crosshair.png"></inlinegraphic> #GDK_CROSSHAIR (crosshair)
56  * </para></listitem>
57  * <listitem><para>
58  *  <inlinegraphic format="PNG" fileref="xterm.png"></inlinegraphic> #GDK_XTERM (I-beam)
59  * </para></listitem>
60  * <listitem><para>
61  * <inlinegraphic format="PNG" fileref="watch.png"></inlinegraphic> #GDK_WATCH (busy)
62  * </para></listitem>
63  * <listitem><para>
64  * <inlinegraphic format="PNG" fileref="fleur.png"></inlinegraphic> #GDK_FLEUR (for moving objects)
65  * </para></listitem>
66  * <listitem><para>
67  * <inlinegraphic format="PNG" fileref="hand1.png"></inlinegraphic> #GDK_HAND1 (a right-pointing hand)
68  * </para></listitem>
69  * <listitem><para>
70  * <inlinegraphic format="PNG" fileref="hand2.png"></inlinegraphic> #GDK_HAND2 (a left-pointing hand)
71  * </para></listitem>
72  * <listitem><para>
73  * <inlinegraphic format="PNG" fileref="left_side.png"></inlinegraphic> #GDK_LEFT_SIDE (resize left side)
74  * </para></listitem>
75  * <listitem><para>
76  * <inlinegraphic format="PNG" fileref="right_side.png"></inlinegraphic> #GDK_RIGHT_SIDE (resize right side)
77  * </para></listitem>
78  * <listitem><para>
79  * <inlinegraphic format="PNG" fileref="top_left_corner.png"></inlinegraphic> #GDK_TOP_LEFT_CORNER (resize northwest corner)
80  * </para></listitem>
81  * <listitem><para>
82  * <inlinegraphic format="PNG" fileref="top_right_corner.png"></inlinegraphic> #GDK_TOP_RIGHT_CORNER (resize northeast corner)
83  * </para></listitem>
84  * <listitem><para>
85  * <inlinegraphic format="PNG" fileref="bottom_left_corner.png"></inlinegraphic> #GDK_BOTTOM_LEFT_CORNER (resize southwest corner)
86  * </para></listitem>
87  * <listitem><para>
88  * <inlinegraphic format="PNG" fileref="bottom_right_corner.png"></inlinegraphic> #GDK_BOTTOM_RIGHT_CORNER (resize southeast corner)
89  * </para></listitem>
90  * <listitem><para>
91  * <inlinegraphic format="PNG" fileref="top_side.png"></inlinegraphic> #GDK_TOP_SIDE (resize top side)
92  * </para></listitem>
93  * <listitem><para>
94  * <inlinegraphic format="PNG" fileref="bottom_side.png"></inlinegraphic> #GDK_BOTTOM_SIDE (resize bottom side)
95  * </para></listitem>
96  * <listitem><para>
97  * <inlinegraphic format="PNG" fileref="sb_h_double_arrow.png"></inlinegraphic> #GDK_SB_H_DOUBLE_ARROW (move vertical splitter)
98  * </para></listitem>
99  * <listitem><para>
100  * <inlinegraphic format="PNG" fileref="sb_v_double_arrow.png"></inlinegraphic> #GDK_SB_V_DOUBLE_ARROW (move horizontal splitter)
101  * </para></listitem>
102  * </itemizedlist>
103  *
104  * To make the cursor invisible, use gdk_cursor_new_from_pixmap() to create
105  * a cursor with no pixels in it.
106  * 
107  * Return value: a new #GdkCursor
108  *
109  * Since: 2.2
110  **/
111 GdkCursor*
112 gdk_cursor_new_for_display (GdkDisplay    *display,
113                             GdkCursorType  cursor_type)
114 {
115   GdkCursorPrivate *private;
116   GdkCursor *cursor;
117   Cursor xcursor;
118
119   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
120
121   if (display->closed)
122     xcursor = None;
123   else
124     xcursor = XCreateFontCursor (GDK_DISPLAY_XDISPLAY (display), cursor_type);
125   
126   private = g_new (GdkCursorPrivate, 1);
127   private->display = display;
128   private->xcursor = xcursor;
129   cursor = (GdkCursor *) private;
130   cursor->type = cursor_type;
131   cursor->ref_count = 1;
132   
133   return cursor;
134 }
135
136 /**
137  * gdk_cursor_new_from_pixmap:
138  * @source: the pixmap specifying the cursor.
139  * @mask: the pixmap specifying the mask, which must be the same size as 
140  *    @source.
141  * @fg: the foreground color, used for the bits in the source which are 1.
142  *    The color does not have to be allocated first. 
143  * @bg: the background color, used for the bits in the source which are 0.
144  *    The color does not have to be allocated first.
145  * @x: the horizontal offset of the 'hotspot' of the cursor. 
146  * @y: the vertical offset of the 'hotspot' of the cursor.
147  * 
148  * Creates a new cursor from a given pixmap and mask. Both the pixmap and mask
149  * must have a depth of 1 (i.e. each pixel has only 2 values - on or off).
150  * The standard cursor size is 16 by 16 pixels. You can create a bitmap 
151  * from inline data as in the below example.
152  * 
153  * <example><title>Creating a custom cursor</title>
154  * <programlisting>
155  * /<!-- -->* This data is in X bitmap format, and can be created with the 'bitmap'
156  *    utility. *<!-- -->/
157  * &num;define cursor1_width 16
158  * &num;define cursor1_height 16
159  * static unsigned char cursor1_bits[] = {
160  *   0x80, 0x01, 0x40, 0x02, 0x20, 0x04, 0x10, 0x08, 0x08, 0x10, 0x04, 0x20,
161  *   0x82, 0x41, 0x41, 0x82, 0x41, 0x82, 0x82, 0x41, 0x04, 0x20, 0x08, 0x10,
162  *   0x10, 0x08, 0x20, 0x04, 0x40, 0x02, 0x80, 0x01};
163  *  
164  * static unsigned char cursor1mask_bits[] = {
165  *   0x80, 0x01, 0xc0, 0x03, 0x60, 0x06, 0x30, 0x0c, 0x18, 0x18, 0x8c, 0x31,
166  *   0xc6, 0x63, 0x63, 0xc6, 0x63, 0xc6, 0xc6, 0x63, 0x8c, 0x31, 0x18, 0x18,
167  *   0x30, 0x0c, 0x60, 0x06, 0xc0, 0x03, 0x80, 0x01};
168  *  
169  *  
170  *  GdkCursor *cursor;
171  *  GdkPixmap *source, *mask;
172  *  GdkColor fg = { 0, 65535, 0, 0 }; /<!-- -->* Red. *<!-- -->/
173  *  GdkColor bg = { 0, 0, 0, 65535 }; /<!-- -->* Blue. *<!-- -->/
174  *  
175  *  
176  *  source = gdk_bitmap_create_from_data (NULL, cursor1_bits,
177  *                                        cursor1_width, cursor1_height);
178  *  mask = gdk_bitmap_create_from_data (NULL, cursor1mask_bits,
179  *                                      cursor1_width, cursor1_height);
180  *  cursor = gdk_cursor_new_from_pixmap (source, mask, &amp;fg, &amp;bg, 8, 8);
181  *  gdk_pixmap_unref (source);
182  *  gdk_pixmap_unref (mask);
183  *  
184  *  
185  *  gdk_window_set_cursor (widget->window, cursor);
186  * </programlisting>
187  * </example>
188  *
189  * Return value: a new #GdkCursor.
190  **/
191 GdkCursor*
192 gdk_cursor_new_from_pixmap (GdkPixmap      *source,
193                             GdkPixmap      *mask,
194                             const GdkColor *fg,
195                             const GdkColor *bg,
196                             gint            x,
197                             gint            y)
198 {
199   GdkCursorPrivate *private;
200   GdkCursor *cursor;
201   Pixmap source_pixmap, mask_pixmap;
202   Cursor xcursor;
203   XColor xfg, xbg;
204   GdkDisplay *display;
205
206   g_return_val_if_fail (GDK_IS_PIXMAP (source), NULL);
207   g_return_val_if_fail (GDK_IS_PIXMAP (mask), NULL);
208   g_return_val_if_fail (fg != NULL, NULL);
209   g_return_val_if_fail (bg != NULL, NULL);
210
211   source_pixmap = GDK_PIXMAP_XID (source);
212   mask_pixmap   = GDK_PIXMAP_XID (mask);
213   display = GDK_PIXMAP_DISPLAY (source);
214
215   xfg.pixel = fg->pixel;
216   xfg.red = fg->red;
217   xfg.blue = fg->blue;
218   xfg.green = fg->green;
219   xbg.pixel = bg->pixel;
220   xbg.red = bg->red;
221   xbg.blue = bg->blue;
222   xbg.green = bg->green;
223   
224   if (display->closed)
225     xcursor = None;
226   else
227     xcursor = XCreatePixmapCursor (GDK_DISPLAY_XDISPLAY (display),
228                                    source_pixmap, mask_pixmap, &xfg, &xbg, x, y);
229   private = g_new (GdkCursorPrivate, 1);
230   private->display = display;
231   private->xcursor = xcursor;
232   cursor = (GdkCursor *) private;
233   cursor->type = GDK_CURSOR_IS_PIXMAP;
234   cursor->ref_count = 1;
235   
236   return cursor;
237 }
238
239 void
240 _gdk_cursor_destroy (GdkCursor *cursor)
241 {
242   GdkCursorPrivate *private;
243
244   g_return_if_fail (cursor != NULL);
245   g_return_if_fail (cursor->ref_count == 0);
246
247   private = (GdkCursorPrivate *) cursor;
248   if (!private->display->closed && private->xcursor)
249     XFreeCursor (GDK_DISPLAY_XDISPLAY (private->display), private->xcursor);
250
251   g_free (private);
252 }
253
254 /**
255  * gdk_x11_cursor_get_xdisplay:
256  * @cursor: a #GdkCursor.
257  * 
258  * Returns the display of a #GdkCursor.
259  * 
260  * Return value: an Xlib <type>Display*</type>.
261  **/
262 Display *
263 gdk_x11_cursor_get_xdisplay (GdkCursor *cursor)
264 {
265   g_return_val_if_fail (cursor != NULL, NULL);
266
267   return GDK_DISPLAY_XDISPLAY(((GdkCursorPrivate *)cursor)->display);
268 }
269
270 /**
271  * gdk_x11_cursor_get_xcursor:
272  * @cursor: a #GdkCursor.
273  * 
274  * Returns the X cursor belonging to a #GdkCursor.
275  * 
276  * Return value: an Xlib <type>Cursor</type>.
277  **/
278 Cursor
279 gdk_x11_cursor_get_xcursor (GdkCursor *cursor)
280 {
281   g_return_val_if_fail (cursor != NULL, None);
282
283   return ((GdkCursorPrivate *)cursor)->xcursor;
284 }
285
286 /** 
287  * gdk_cursor_get_display:
288  * @cursor: a #GdkCursor.
289  *
290  * Returns the display on which the #GdkCursor is defined.
291  *
292  * Returns: the #GdkDisplay associated to @cursor
293  *
294  * Since: 2.2
295  */
296
297 GdkDisplay *
298 gdk_cursor_get_display (GdkCursor *cursor)
299 {
300   g_return_val_if_fail (cursor != NULL, NULL);
301
302   return ((GdkCursorPrivate *)cursor)->display;
303 }
304
305
306 #ifdef HAVE_XCURSOR
307
308 static XcursorImage*
309 create_cursor_image (GdkPixbuf *pixbuf,
310                      gint       x,
311                      gint       y)
312 {
313   guint width, height, rowstride, n_channels;
314   guchar *pixels, *src;
315   XcursorImage *xcimage;
316   XcursorPixel *dest;
317
318   width = gdk_pixbuf_get_width (pixbuf);
319   height = gdk_pixbuf_get_height (pixbuf);
320
321   n_channels = gdk_pixbuf_get_n_channels (pixbuf);
322   rowstride = gdk_pixbuf_get_rowstride (pixbuf);
323   pixels = gdk_pixbuf_get_pixels (pixbuf);
324
325   xcimage = XcursorImageCreate (width, height);
326
327   xcimage->xhot = x;
328   xcimage->yhot = y;
329
330   dest = xcimage->pixels;
331
332   if (n_channels == 3)
333     {
334       gint i, j;
335
336       for (j = 0; j < height; j++)
337         {
338           src = pixels + j * rowstride;
339           for (i = 0; i < width; i++)
340             {
341               *dest = (0xff << 24) | (src[0] << 16) | (src[1] << 8) | src[2];
342             }
343
344           src += n_channels;
345           dest++;
346         }
347     }
348   else
349     {
350       _gdk_x11_convert_to_format (pixels, rowstride,
351                                   (guchar *) dest, 4 * width,
352                                   GDK_X11_FORMAT_ARGB,
353                                   (G_BYTE_ORDER == G_BIG_ENDIAN) ?
354                                   GDK_MSB_FIRST : GDK_LSB_FIRST,
355                                   width, height);
356     }
357
358   return xcimage;
359 }
360
361
362 /**
363  * gdk_cursor_new_from_pixbuf:
364  * @display: the #GdkDisplay for which the cursor will be created
365  * @pixbuf: the #GdkPixbuf containing the cursor image
366  * @x: the horizontal offset of the 'hotspot' of the cursor. 
367  * @y: the vertical offset of the 'hotspot' of the cursor.
368  *
369  * Creates a new cursor from a pixbuf. 
370  *
371  * Not all GDK backends support RGBA cursors. If they are not 
372  * supported, a monochrome approximation will be displayed. 
373  * The functions gdk_display_supports_cursor_alpha() and 
374  * gdk_display_supports_cursor_color() can be used to determine
375  * whether RGBA cursors are supported; 
376  * gdk_display_get_default_cursor_size() and 
377  * gdk_display_get_maximal_cursor_size() give information about 
378  * cursor sizes.
379  *
380  * On the X backend, support for RGBA cursors requires a
381  * sufficently new version of the X Render extension. 
382  *
383  * Returns: a new #GdkCursor.
384  * 
385  * Since: 2.4
386  */
387 GdkCursor *
388 gdk_cursor_new_from_pixbuf (GdkDisplay *display, 
389                             GdkPixbuf  *pixbuf,
390                             gint        x,
391                             gint        y)
392 {
393   XcursorImage *xcimage;
394   Cursor xcursor;
395   GdkCursorPrivate *private;
396   GdkCursor *cursor;
397
398   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
399   g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
400   g_return_val_if_fail (0 <= x && x < gdk_pixbuf_get_width (pixbuf), NULL);
401   g_return_val_if_fail (0 <= y && y < gdk_pixbuf_get_height (pixbuf), NULL);
402
403   if (display->closed)
404     xcursor = None;
405   else 
406     {
407       xcimage = create_cursor_image (pixbuf, x, y);
408       xcursor = XcursorImageLoadCursor (GDK_DISPLAY_XDISPLAY (display), xcimage);
409       XcursorImageDestroy (xcimage);
410     }
411
412   private = g_new (GdkCursorPrivate, 1);
413   private->display = display;
414   private->xcursor = xcursor;
415   cursor = (GdkCursor *) private;
416   cursor->type = GDK_CURSOR_IS_PIXMAP;
417   cursor->ref_count = 1;
418   
419   return cursor;
420 }
421
422 /**
423  * gdk_display_supports_cursor_alpha:
424  * @display: a #GdkDisplay
425  *
426  * Returns %TRUE if cursors can use an 8bit alpha channel 
427  * on @display. Otherwise, cursors are restricted to bilevel 
428  * alpha (i.e. a mask).
429  *
430  * Returns: whether cursors can have alpha channels.
431  *
432  * Since: 2.4
433  */
434 gboolean 
435 gdk_display_supports_cursor_alpha (GdkDisplay *display)
436 {
437   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
438
439   return XcursorSupportsARGB (GDK_DISPLAY_XDISPLAY (display));
440 }
441
442 /**
443  * gdk_display_supports_cursor_color:
444  * @display: a #GdkDisplay
445  *
446  * Returns %TRUE if multicolored cursors are supported
447  * on @display. Otherwise, cursors have only a forground
448  * and a background color.
449  *
450  * Returns: whether cursors can have multiple colors.
451  *
452  * Since: 2.4
453  */
454 gboolean 
455 gdk_display_supports_cursor_color (GdkDisplay *display)
456 {
457   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
458
459   return XcursorSupportsARGB (GDK_DISPLAY_XDISPLAY (display));
460 }
461
462 /**
463  * gdk_display_get_default_cursor_size:
464  * @display: a #GdkDisplay
465  *
466  * Returns the default size to use for cursors on @display.
467  *
468  * Returns: the default cursor size.
469  *
470  * Since: 2.4
471  */
472 guint     
473 gdk_display_get_default_cursor_size (GdkDisplay *display)
474 {
475   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
476
477   return XcursorGetDefaultSize (GDK_DISPLAY_XDISPLAY (display));
478 }
479
480 #else
481
482 GdkCursor *
483 gdk_cursor_new_from_pixbuf (GdkDisplay *display, 
484                             GdkPixbuf  *pixbuf,
485                             gint        x,
486                             gint        y)
487 {
488   GdkCursor *cursor;
489   GdkPixmap *pixmap, *mask;
490   guint width, height, n_channels, rowstride, i, j;
491   guint8 *data, *mask_data, *pixels;
492   GdkColor fg = { 0, 0, 0, 0 };
493   GdkColor bg = { 0, 0xffff, 0xffff, 0xffff };
494   GdkScreen *screen;
495
496   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
497   g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
498
499   width = gdk_pixbuf_get_width (pixbuf);
500   height = gdk_pixbuf_get_height (pixbuf);
501
502   g_return_val_if_fail (0 <= x && x < width, NULL);
503   g_return_val_if_fail (0 <= y && y < height, NULL);
504
505   n_channels = gdk_pixbuf_get_n_channels (pixbuf);
506   rowstride = gdk_pixbuf_get_rowstride (pixbuf);
507   pixels = gdk_pixbuf_get_pixels (pixbuf);
508
509   data = g_new0 (guint8, (width + 7) / 8 * height);
510   mask_data = g_new0 (guint8, (width + 7) / 8 * height);
511
512   for (j = 0; j < height; j++)
513     {
514       guint8 *src = pixels + j * rowstride;
515       guint8 *d = data + (width + 7) / 8 * j;
516       guint8 *md = mask_data + (width + 7) / 8 * j;
517         
518       for (i = 0; i < width; i++)
519         {
520           if (src[1] < 0x80)
521             *d |= 1 << (i % 8);
522           
523           if (n_channels == 3 || src[3] >= 0x80)
524             *md |= 1 << (i % 8);
525           
526           src += n_channels;
527           if (i % 8 == 7)
528             {
529               d++; 
530               md++;
531             }
532         }
533     }
534       
535   screen = gdk_display_get_default_screen (display);
536   pixmap = gdk_bitmap_create_from_data (gdk_screen_get_root_window (screen), 
537                                         data, width, height);
538  
539   mask = gdk_bitmap_create_from_data (gdk_screen_get_root_window (screen),
540                                       mask_data, width, height);
541    
542   cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, x, y);
543    
544   g_object_unref (pixmap);
545   g_object_unref (mask);
546
547   g_free (data);
548   g_free (mask_data);
549   
550   return cursor;
551 }
552
553 gboolean 
554 gdk_display_supports_cursor_alpha (GdkDisplay    *display)
555 {
556   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
557
558   return FALSE;
559 }
560
561 gboolean 
562 gdk_display_supports_cursor_color (GdkDisplay    *display)
563 {
564   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
565
566   return FALSE;
567 }
568
569 guint     
570 gdk_display_get_default_cursor_size (GdkDisplay    *display)
571 {
572   g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
573   
574   /* no idea, really */
575   return 20; 
576 }
577
578 #endif
579
580
581 /**
582  * gdk_display_get_maximal_cursor_size:
583  * @display: a #GdkDisplay
584  * @width: the return location for the maximal cursor width
585  * @height: the return location for the maximal cursor height
586  *
587  * Gets the maximal size to use for cursors on @display.
588  *
589  * Since: 2.4
590  */
591 void     
592 gdk_display_get_maximal_cursor_size (GdkDisplay *display,
593                                      guint       *width,
594                                      guint       *height)
595 {
596   GdkScreen *screen;
597   GdkWindow *window;
598
599   g_return_if_fail (GDK_IS_DISPLAY (display));
600   
601   screen = gdk_display_get_default_screen (display);
602   window = gdk_screen_get_root_window (screen);
603   XQueryBestCursor (GDK_DISPLAY_XDISPLAY (display), 
604                     GDK_WINDOW_XWINDOW (window), 
605                     128, 128, width, height);
606 }
607
608 #define __GDK_CURSOR_X11_C__
609 #include "gdkaliasdef.c"