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, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23 */
24
25#include "config.h"
26
27#define GDK_PIXBUF_ENABLE_BACKEND
28#include <gdk-pixbuf/gdk-pixbuf.h>
29
30#include "gdkcursor.h"
31#include "gdkcursorprivate.h"
32#include "gdkdisplayprivate.h"
33#include "gdkintl.h"
34#include "gdkinternals.h"
35
36#include <math.h>
37#include <errno.h>
38
39/**
40 * SECTION:cursors
41 * @Short_description: Standard and pixmap cursors
42 * @Title: Cursors
43 *
44 * These functions are used to create and destroy cursors.
45 * There is a number of standard cursors, but it is also
46 * possible to construct new cursors from pixbufs. There
47 * may be limitations as to what kinds of cursors can be
48 * constructed on a given display, see
49 * gdk_display_supports_cursor_alpha(),
50 * gdk_display_supports_cursor_color(),
51 * gdk_display_get_default_cursor_size() and
52 * gdk_display_get_maximal_cursor_size().
53 *
54 * Cursors by themselves are not very interesting, they must be be
55 * bound to a window for users to see them. This is done with
56 * gdk_window_set_cursor() or by setting the cursor member of the
57 * #GdkWindowAttr passed to gdk_window_new().
58 */
59
60/**
61 * GdkCursor:
62 *
63 * A #GdkCursor represents a cursor. Its contents are private.
64 */
65
66enum {
67 PROP_0,
68 PROP_CURSOR_TYPE,
69 PROP_DISPLAY
70};
71
72G_DEFINE_ABSTRACT_TYPE (GdkCursor, gdk_cursor, G_TYPE_OBJECT)
73
74static void
75gdk_cursor_get_property (GObject *object,
76 guint prop_id,
77 GValue *value,
78 GParamSpec *pspec)
79{
80 GdkCursor *cursor = GDK_CURSOR (object);
81
82 switch (prop_id)
83 {
84 case PROP_CURSOR_TYPE:
85 g_value_set_enum (value, cursor->type);
86 break;
87 case PROP_DISPLAY:
88 g_value_set_object (value, cursor->display);
89 break;
90 default:
91 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
92 break;
93 }
94}
95
96static void
97gdk_cursor_set_property (GObject *object,
98 guint prop_id,
99 const GValue *value,
100 GParamSpec *pspec)
101{
102 GdkCursor *cursor = GDK_CURSOR (object);
103
104 switch (prop_id)
105 {
106 case PROP_CURSOR_TYPE:
107 cursor->type = g_value_get_enum (value);
108 break;
109 case PROP_DISPLAY:
110 cursor->display = g_value_get_object (value);
111 /* check that implementations actually provide the display when constructing */
112 g_assert (cursor->display != NULL);
113 break;
114 default:
115 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
116 break;
117 }
118}
119
120static void
121gdk_cursor_class_init (GdkCursorClass *cursor_class)
122{
123 GObjectClass *object_class = G_OBJECT_CLASS (cursor_class);
124
125 object_class->get_property = gdk_cursor_get_property;
126 object_class->set_property = gdk_cursor_set_property;
127
128 g_object_class_install_property (object_class,
129 PROP_CURSOR_TYPE,
130 g_param_spec_enum ("cursor-type",
131 P_("Cursor type"),
132 P_("Standard cursor type"),
133 GDK_TYPE_CURSOR_TYPE, GDK_X_CURSOR,
134 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
135
136 g_object_class_install_property (object_class,
137 PROP_DISPLAY,
138 g_param_spec_object ("display",
139 P_("Display"),
140 P_("Display of this cursor"),
141 GDK_TYPE_DISPLAY,
142 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
143}
144
145static void
146gdk_cursor_init (GdkCursor *cursor)
147{
148}
149
150/**
151 * gdk_cursor_ref:
152 * @cursor: a #GdkCursor
153 *
154 * Adds a reference to @cursor.
155 *
156 * Returns: (transfer full): Same @cursor that was passed in
157 *
158 * Deprecated: 3.0: Use g_object_ref() instead
159 */
160GdkCursor*
161gdk_cursor_ref (GdkCursor *cursor)
162{
163 g_return_val_if_fail (cursor != NULL, NULL);
164
165 return g_object_ref (cursor);
166}
167
168/**
169 * gdk_cursor_unref:
170 * @cursor: a #GdkCursor
171 *
172 * Removes a reference from @cursor, deallocating the cursor
173 * if no references remain.
174 *
175 * Deprecated: 3.0: Use g_object_unref() instead
176 */
177void
178gdk_cursor_unref (GdkCursor *cursor)
179{
180 g_return_if_fail (cursor != NULL);
181
182 g_object_unref (cursor);
183}
184
185/**
186 * gdk_cursor_new:
187 * @cursor_type: cursor to create
188 *
189 * Creates a new cursor from the set of builtin cursors for the default display.
190 * See gdk_cursor_new_for_display().
191 *
192 * To make the cursor invisible, use %GDK_BLANK_CURSOR.
193 *
194 * Returns: a new #GdkCursor
195 *
196 * Deprecated: 3.16: Use gdk_cursor_new_for_display() instead.
197 */
198GdkCursor*
199gdk_cursor_new (GdkCursorType cursor_type)
200{
201 return gdk_cursor_new_for_display (gdk_display_get_default (), cursor_type);
202}
203
204/**
205 * gdk_cursor_get_cursor_type:
206 * @cursor: a #GdkCursor
207 *
208 * Returns the cursor type for this cursor.
209 *
210 * Returns: a #GdkCursorType
211 *
212 * Since: 2.22
213 **/
214GdkCursorType
215gdk_cursor_get_cursor_type (GdkCursor *cursor)
216{
217 g_return_val_if_fail (cursor != NULL, GDK_BLANK_CURSOR);
218
219 return cursor->type;
220}
221
222/**
223 * gdk_cursor_new_for_display:
224 * @display: the #GdkDisplay for which the cursor will be created
225 * @cursor_type: cursor to create
226 *
227 * Creates a new cursor from the set of builtin cursors.
228 *
229 * Returns: a new #GdkCursor
230 *
231 * Since: 2.2
232 **/
233GdkCursor*
234gdk_cursor_new_for_display (GdkDisplay *display,
235 GdkCursorType cursor_type)
236{
237 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
238
239 return GDK_DISPLAY_GET_CLASS (display)->get_cursor_for_type (display, cursor_type);
240}
241
242/**
243 * gdk_cursor_new_from_name:
244 * @display: the #GdkDisplay for which the cursor will be created
245 * @name: the name of the cursor
246 *
247 * Creates a new cursor by looking up @name in the current cursor
248 * theme.
249 *
250 * A recommended set of cursor names that will work across different
251 * platforms can be found in the CSS specification:
252 * - "none"
253 * - ![](default_cursor.png) "default"
254 * - ![](help_cursor.png) "help"
255 * - ![](pointer_cursor.png) "pointer"
256 * - ![](context_menu_cursor.png) "context-menu"
257 * - ![](progress_cursor.png) "progress"
258 * - ![](wait_cursor.png) "wait"
259 * - ![](cell_cursor.png) "cell"
260 * - ![](crosshair_cursor.png) "crosshair"
261 * - ![](text_cursor.png) "text"
262 * - ![](vertical_text_cursor.png) "vertical-text"
263 * - ![](alias_cursor.png) "alias"
264 * - ![](copy_cursor.png) "copy"
265 * - ![](no_drop_cursor.png) "no-drop"
266 * - ![](move_cursor.png) "move"
267 * - ![](not_allowed_cursor.png) "not-allowed"
268 * - ![](grab_cursor.png) "grab"
269 * - ![](grabbing_cursor.png) "grabbing"
270 * - ![](all_scroll_cursor.png) "all-scroll"
271 * - ![](col_resize_cursor.png) "col-resize"
272 * - ![](row_resize_cursor.png) "row-resize"
273 * - ![](n_resize_cursor.png) "n-resize"
274 * - ![](e_resize_cursor.png) "e-resize"
275 * - ![](s_resize_cursor.png) "s-resize"
276 * - ![](w_resize_cursor.png) "w-resize"
277 * - ![](ne_resize_cursor.png) "ne-resize"
278 * - ![](nw_resize_cursor.png) "nw-resize"
279 * - ![](sw_resize_cursor.png) "sw-resize"
280 * - ![](se_resize_cursor.png) "se-resize"
281 * - ![](ew_resize_cursor.png) "ew-resize"
282 * - ![](ns_resize_cursor.png) "ns-resize"
283 * - ![](nesw_resize_cursor.png) "nesw-resize"
284 * - ![](nwse_resize_cursor.png) "nwse-resize"
285 * - ![](zoom_in_cursor.png) "zoom-in"
286 * - ![](zoom_out_cursor.png) "zoom-out"
287 *
288 *
289 * Returns: (nullable): a new #GdkCursor, or %NULL if there is no
290 * cursor with the given name
291 *
292 * Since: 2.8
293 */
294GdkCursor*
295gdk_cursor_new_from_name (GdkDisplay *display,
296 const gchar *name)
297{
298 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
299
300 return GDK_DISPLAY_GET_CLASS (display)->get_cursor_for_name (display, name);
301}
302
303/**
304 * gdk_cursor_new_from_pixbuf:
305 * @display: the #GdkDisplay for which the cursor will be created
306 * @pixbuf: the #GdkPixbuf containing the cursor image
307 * @x: the horizontal offset of the “hotspot” of the cursor.
308 * @y: the vertical offset of the “hotspot” of the cursor.
309 *
310 * Creates a new cursor from a pixbuf.
311 *
312 * Not all GDK backends support RGBA cursors. If they are not
313 * supported, a monochrome approximation will be displayed.
314 * The functions gdk_display_supports_cursor_alpha() and
315 * gdk_display_supports_cursor_color() can be used to determine
316 * whether RGBA cursors are supported;
317 * gdk_display_get_default_cursor_size() and
318 * gdk_display_get_maximal_cursor_size() give information about
319 * cursor sizes.
320 *
321 * If @x or @y are `-1`, the pixbuf must have
322 * options named “x_hot” and “y_hot”, resp., containing
323 * integer values between `0` and the width resp. height of
324 * the pixbuf. (Since: 3.0)
325 *
326 * On the X backend, support for RGBA cursors requires a
327 * sufficently new version of the X Render extension.
328 *
329 * Returns: a new #GdkCursor.
330 *
331 * Since: 2.4
332 */
333GdkCursor *
334gdk_cursor_new_from_pixbuf (GdkDisplay *display,
335 GdkPixbuf *pixbuf,
336 gint x,
337 gint y)
338{
339 cairo_surface_t *surface;
340 const char *option;
341 char *end;
342 gint64 value;
343 GdkCursor *cursor;
344
345 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
346 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
347
348 if (x == -1 && (option = gdk_pixbuf_get_option (pixbuf, "x_hot")))
349 {
350 errno = 0;
351 end = NULL;
352 value = g_ascii_strtoll (option, &end, 10);
353 if (errno == 0 &&
354 end != option &&
355 value >= 0 && value < G_MAXINT)
356 x = (gint) value;
357 }
358
359 if (y == -1 && (option = gdk_pixbuf_get_option (pixbuf, "y_hot")))
360 {
361 errno = 0;
362 end = NULL;
363 value = g_ascii_strtoll (option, &end, 10);
364 if (errno == 0 &&
365 end != option &&
366 value >= 0 && value < G_MAXINT)
367 y = (gint) value;
368 }
369
370 surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, NULL);
371
372 cursor = GDK_DISPLAY_GET_CLASS (display)->get_cursor_for_surface (display, surface, x, y);
373
374 cairo_surface_destroy (surface);
375
376 return cursor;
377}
378
379/**
380 * gdk_cursor_new_from_surface:
381 * @display: the #GdkDisplay for which the cursor will be created
382 * @surface: the cairo image surface containing the cursor pixel data
383 * @x: the horizontal offset of the “hotspot” of the cursor
384 * @y: the vertical offset of the “hotspot” of the cursor
385 *
386 * Creates a new cursor from a cairo image surface.
387 *
388 * Not all GDK backends support RGBA cursors. If they are not
389 * supported, a monochrome approximation will be displayed.
390 * The functions gdk_display_supports_cursor_alpha() and
391 * gdk_display_supports_cursor_color() can be used to determine
392 * whether RGBA cursors are supported;
393 * gdk_display_get_default_cursor_size() and
394 * gdk_display_get_maximal_cursor_size() give information about
395 * cursor sizes.
396 *
397 * On the X backend, support for RGBA cursors requires a
398 * sufficently new version of the X Render extension.
399 *
400 * Returns: a new #GdkCursor.
401 *
402 * Since: 3.10
403 */
404GdkCursor *
405gdk_cursor_new_from_surface (GdkDisplay *display,
406 cairo_surface_t *surface,
407 gdouble x,
408 gdouble y)
409{
410 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
411 g_return_val_if_fail (surface != NULL, NULL);
412 g_return_val_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE, NULL);
413 g_return_val_if_fail (0 <= x && x < cairo_image_surface_get_width (surface), NULL);
414 g_return_val_if_fail (0 <= y && y < cairo_image_surface_get_height (surface), NULL);
415
416 return GDK_DISPLAY_GET_CLASS (display)->get_cursor_for_surface (display,
417 surface, x, y);
418}
419/**
420 * gdk_cursor_get_display:
421 * @cursor: a #GdkCursor.
422 *
423 * Returns the display on which the #GdkCursor is defined.
424 *
425 * Returns: (transfer none): the #GdkDisplay associated to @cursor
426 *
427 * Since: 2.2
428 */
429
430GdkDisplay *
431gdk_cursor_get_display (GdkCursor *cursor)
432{
433 g_return_val_if_fail (GDK_IS_CURSOR (cursor), NULL);
434
435 return cursor->display;
436}
437
438/**
439 * gdk_cursor_get_image:
440 * @cursor: a #GdkCursor
441 *
442 * Returns a #GdkPixbuf with the image used to display the cursor.
443 *
444 * Note that depending on the capabilities of the windowing system and
445 * on the cursor, GDK may not be able to obtain the image data. In this
446 * case, %NULL is returned.
447 *
448 * Returns: (nullable) (transfer full): a #GdkPixbuf representing
449 * @cursor, or %NULL
450 *
451 * Since: 2.8
452 */
453GdkPixbuf*
454gdk_cursor_get_image (GdkCursor *cursor)
455{
456 int w, h;
457 cairo_surface_t *surface;
458 GdkPixbuf *pixbuf;
459 gchar buf[32];
460 double x_hot, y_hot;
461 double x_scale, y_scale;
462
463 g_return_val_if_fail (GDK_IS_CURSOR (cursor), NULL);
464
465 surface = gdk_cursor_get_surface (cursor, &x_hot, &y_hot);
466 if (surface == NULL)
467 return NULL;
468
469 w = cairo_image_surface_get_width (surface);
470 h = cairo_image_surface_get_height (surface);
471
472 x_scale = y_scale = 1;
473 cairo_surface_get_device_scale (surface, &x_scale, &y_scale);
474
475 pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, w, h);
476 cairo_surface_destroy (surface);
477
478 if (x_scale != 1)
479 {
480 GdkPixbuf *old;
481
482 old = pixbuf;
483 pixbuf = gdk_pixbuf_scale_simple (old,
484 w / x_scale, h / y_scale,
485 GDK_INTERP_HYPER);
486 g_object_unref (old);
487 }
488
489
490 g_snprintf (buf, 32, "%d", (int)x_hot);
491 gdk_pixbuf_set_option (pixbuf, "x_hot", buf);
492
493 g_snprintf (buf, 32, "%d", (int)y_hot);
494 gdk_pixbuf_set_option (pixbuf, "y_hot", buf);
495
496 return pixbuf;
497}
498
499/**
500 * gdk_cursor_get_surface:
501 * @cursor: a #GdkCursor
502 * @x_hot: (optional) (out): Location to store the hotspot x position,
503 * or %NULL
504 * @y_hot: (optional) (out): Location to store the hotspot y position,
505 * or %NULL
506 *
507 * Returns a cairo image surface with the image used to display the cursor.
508 *
509 * Note that depending on the capabilities of the windowing system and
510 * on the cursor, GDK may not be able to obtain the image data. In this
511 * case, %NULL is returned.
512 *
513 * Returns: (nullable) (transfer full): a #cairo_surface_t
514 * representing @cursor, or %NULL
515 *
516 * Since: 3.10
517 */
518cairo_surface_t *
519gdk_cursor_get_surface (GdkCursor *cursor,
520 gdouble *x_hot,
521 gdouble *y_hot)
522{
523 g_return_val_if_fail (GDK_IS_CURSOR (cursor), NULL);
524
525 return GDK_CURSOR_GET_CLASS (cursor)->get_surface (cursor, x_hot, y_hot);
526}
527