1/* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-2007 Peter Mattis, Spencer Kimball,
3 * Josh MacDonald, Ryan Lortie
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
21 * file for a list of people on the GTK+ Team. See the ChangeLog
22 * files for a list of changes. These files are distributed with
23 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
24 */
25
26#include "config.h"
27
28#include <cairo-gobject.h>
29
30#include "gdksurface.h"
31
32#include "gdk-private.h"
33#include "gdkcontentprovider.h"
34#include "gdkdeviceprivate.h"
35#include "gdkdisplayprivate.h"
36#include "gdkdragsurfaceprivate.h"
37#include "gdkeventsprivate.h"
38#include "gdkframeclockidleprivate.h"
39#include "gdkglcontextprivate.h"
40#include "gdkintl.h"
41#include "gdkmarshalers.h"
42#include "gdkpopupprivate.h"
43#include "gdkrectangle.h"
44#include "gdktoplevelprivate.h"
45#include "gdkvulkancontext.h"
46
47#include <math.h>
48
49#ifdef HAVE_EGL
50#include <epoxy/egl.h>
51#endif
52
53/**
54 * GdkSurface:
55 *
56 * A `GdkSurface` is a rectangular region on the screen.
57 *
58 * It’s a low-level object, used to implement high-level objects
59 * such as [class@Gtk.Window] or [class@Gtk.Dialog] in GTK.
60 *
61 * The surfaces you see in practice are either [iface@Gdk.Toplevel] or
62 * [iface@Gdk.Popup], and those interfaces provide much of the required
63 * API to interact with these surfaces. Other, more specialized surface
64 * types exist, but you will rarely interact with them directly.
65 */
66
67typedef struct _GdkSurfacePrivate GdkSurfacePrivate;
68
69struct _GdkSurfacePrivate
70{
71 gpointer egl_native_window;
72#ifdef HAVE_EGL
73 EGLSurface egl_surface;
74 gboolean egl_surface_high_depth;
75#endif
76
77 gpointer widget;
78};
79
80enum {
81 LAYOUT,
82 RENDER,
83 EVENT,
84 ENTER_MONITOR,
85 LEAVE_MONITOR,
86 LAST_SIGNAL
87};
88
89enum {
90 PROP_0,
91 PROP_CURSOR,
92 PROP_DISPLAY,
93 PROP_FRAME_CLOCK,
94 PROP_MAPPED,
95 PROP_WIDTH,
96 PROP_HEIGHT,
97 PROP_SCALE_FACTOR,
98 LAST_PROP
99};
100
101/* Global info */
102
103static void gdk_surface_finalize (GObject *object);
104
105static void gdk_surface_set_property (GObject *object,
106 guint prop_id,
107 const GValue *value,
108 GParamSpec *pspec);
109static void gdk_surface_get_property (GObject *object,
110 guint prop_id,
111 GValue *value,
112 GParamSpec *pspec);
113
114static void update_cursor (GdkDisplay *display,
115 GdkDevice *device);
116
117static void gdk_surface_set_frame_clock (GdkSurface *surface,
118 GdkFrameClock *clock);
119
120static void gdk_surface_queue_set_is_mapped (GdkSurface *surface,
121 gboolean is_mapped);
122
123
124static guint signals[LAST_SIGNAL] = { 0 };
125static GParamSpec *properties[LAST_PROP] = { NULL, };
126
127G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GdkSurface, gdk_surface, G_TYPE_OBJECT)
128
129static gboolean
130gdk_surface_real_beep (GdkSurface *surface)
131{
132 return FALSE;
133}
134
135static GdkDisplay *
136get_display_for_surface (GdkSurface *primary,
137 GdkSurface *secondary)
138{
139 GdkDisplay *display = primary->display;
140
141 if (display)
142 return display;
143
144 display = secondary->display;
145
146 if (display)
147 return display;
148
149 g_warning ("no display for surface, using default");
150 return gdk_display_get_default ();
151}
152
153static GdkMonitor *
154get_monitor_for_rect (GdkDisplay *display,
155 const GdkRectangle *rect,
156 void (*get_bounds) (GdkMonitor *monitor,
157 GdkRectangle *bounds))
158{
159 int biggest_area = G_MININT;
160 GdkMonitor *best_monitor = NULL;
161 GdkMonitor *monitor;
162 GdkRectangle workarea;
163 GdkRectangle intersection;
164 GListModel *monitors;
165 guint i;
166
167 monitors = gdk_display_get_monitors (self: display);
168 for (i = 0; i < g_list_model_get_n_items (list: monitors); i++)
169 {
170 monitor = g_list_model_get_item (list: monitors, position: i);
171 get_bounds (monitor, &workarea);
172
173 if (gdk_rectangle_intersect (src1: &workarea, src2: rect, dest: &intersection))
174 {
175 if (intersection.width * intersection.height > biggest_area)
176 {
177 biggest_area = intersection.width * intersection.height;
178 best_monitor = monitor;
179 }
180 }
181 g_object_unref (object: monitor);
182 }
183
184 return best_monitor;
185}
186
187static int
188get_anchor_x_sign (GdkGravity anchor)
189{
190 switch (anchor)
191 {
192 case GDK_GRAVITY_STATIC:
193 case GDK_GRAVITY_NORTH_WEST:
194 case GDK_GRAVITY_WEST:
195 case GDK_GRAVITY_SOUTH_WEST:
196 return -1;
197
198 default:
199 case GDK_GRAVITY_NORTH:
200 case GDK_GRAVITY_CENTER:
201 case GDK_GRAVITY_SOUTH:
202 return 0;
203
204 case GDK_GRAVITY_NORTH_EAST:
205 case GDK_GRAVITY_EAST:
206 case GDK_GRAVITY_SOUTH_EAST:
207 return 1;
208 }
209}
210
211static int
212get_anchor_y_sign (GdkGravity anchor)
213{
214 switch (anchor)
215 {
216 case GDK_GRAVITY_STATIC:
217 case GDK_GRAVITY_NORTH_WEST:
218 case GDK_GRAVITY_NORTH:
219 case GDK_GRAVITY_NORTH_EAST:
220 return -1;
221
222 default:
223 case GDK_GRAVITY_WEST:
224 case GDK_GRAVITY_CENTER:
225 case GDK_GRAVITY_EAST:
226 return 0;
227
228 case GDK_GRAVITY_SOUTH_WEST:
229 case GDK_GRAVITY_SOUTH:
230 case GDK_GRAVITY_SOUTH_EAST:
231 return 1;
232 }
233}
234
235static int
236maybe_flip_position (int bounds_pos,
237 int bounds_size,
238 int rect_pos,
239 int rect_size,
240 int surface_size,
241 int rect_sign,
242 int surface_sign,
243 int offset,
244 gboolean flip,
245 gboolean *flipped)
246{
247 int primary;
248 int secondary;
249
250 *flipped = FALSE;
251 primary = rect_pos + (1 + rect_sign) * rect_size / 2 + offset - (1 + surface_sign) * surface_size / 2;
252
253 if (!flip || (primary >= bounds_pos && primary + surface_size <= bounds_pos + bounds_size))
254 return primary;
255
256 *flipped = TRUE;
257 secondary = rect_pos + (1 - rect_sign) * rect_size / 2 - offset - (1 - surface_sign) * surface_size / 2;
258
259 if (secondary >= bounds_pos && secondary + surface_size <= bounds_pos + bounds_size)
260 return secondary;
261
262 *flipped = FALSE;
263 return primary;
264}
265
266GdkMonitor *
267gdk_surface_get_layout_monitor (GdkSurface *surface,
268 GdkPopupLayout *layout,
269 void (*get_bounds) (GdkMonitor *monitor,
270 GdkRectangle *bounds))
271{
272 GdkDisplay *display;
273 GdkRectangle root_rect;
274
275 root_rect = *gdk_popup_layout_get_anchor_rect (layout);
276 gdk_surface_get_root_coords (surface: surface->parent,
277 x: root_rect.x,
278 y: root_rect.y,
279 root_x: &root_rect.x,
280 root_y: &root_rect.y);
281
282 root_rect.width = MAX (1, root_rect.width);
283 root_rect.height = MAX (1, root_rect.height);
284
285 display = get_display_for_surface (primary: surface, secondary: surface->transient_for);
286 return get_monitor_for_rect (display, rect: &root_rect, get_bounds);
287}
288
289void
290gdk_surface_layout_popup_helper (GdkSurface *surface,
291 int width,
292 int height,
293 int shadow_left,
294 int shadow_right,
295 int shadow_top,
296 int shadow_bottom,
297 GdkMonitor *monitor,
298 GdkRectangle *bounds,
299 GdkPopupLayout *layout,
300 GdkRectangle *out_final_rect)
301{
302 GdkRectangle root_rect;
303 GdkGravity rect_anchor;
304 GdkGravity surface_anchor;
305 int rect_anchor_dx;
306 int rect_anchor_dy;
307 GdkAnchorHints anchor_hints;
308 GdkRectangle final_rect;
309 gboolean flipped_x;
310 gboolean flipped_y;
311 int x, y;
312
313 g_return_if_fail (GDK_IS_POPUP (surface));
314
315 root_rect = *gdk_popup_layout_get_anchor_rect (layout);
316 gdk_surface_get_root_coords (surface: surface->parent,
317 x: root_rect.x,
318 y: root_rect.y,
319 root_x: &root_rect.x,
320 root_y: &root_rect.y);
321
322 rect_anchor = gdk_popup_layout_get_rect_anchor (layout);
323 surface_anchor = gdk_popup_layout_get_surface_anchor (layout);
324 gdk_popup_layout_get_offset (layout, dx: &rect_anchor_dx, dy: &rect_anchor_dy);
325 anchor_hints = gdk_popup_layout_get_anchor_hints (layout);
326
327 final_rect.width = width - shadow_left - shadow_right;
328 final_rect.height = height - shadow_top - shadow_bottom;
329 final_rect.x = maybe_flip_position (bounds_pos: bounds->x,
330 bounds_size: bounds->width,
331 rect_pos: root_rect.x,
332 rect_size: root_rect.width,
333 surface_size: final_rect.width,
334 rect_sign: get_anchor_x_sign (anchor: rect_anchor),
335 surface_sign: get_anchor_x_sign (anchor: surface_anchor),
336 offset: rect_anchor_dx,
337 flip: anchor_hints & GDK_ANCHOR_FLIP_X,
338 flipped: &flipped_x);
339 final_rect.y = maybe_flip_position (bounds_pos: bounds->y,
340 bounds_size: bounds->height,
341 rect_pos: root_rect.y,
342 rect_size: root_rect.height,
343 surface_size: final_rect.height,
344 rect_sign: get_anchor_y_sign (anchor: rect_anchor),
345 surface_sign: get_anchor_y_sign (anchor: surface_anchor),
346 offset: rect_anchor_dy,
347 flip: anchor_hints & GDK_ANCHOR_FLIP_Y,
348 flipped: &flipped_y);
349
350 if (anchor_hints & GDK_ANCHOR_SLIDE_X)
351 {
352 if (final_rect.x + final_rect.width > bounds->x + bounds->width)
353 final_rect.x = bounds->x + bounds->width - final_rect.width;
354
355 if (final_rect.x < bounds->x)
356 final_rect.x = bounds->x;
357 }
358
359 if (anchor_hints & GDK_ANCHOR_SLIDE_Y)
360 {
361 if (final_rect.y + final_rect.height > bounds->y + bounds->height)
362 final_rect.y = bounds->y + bounds->height - final_rect.height;
363
364 if (final_rect.y < bounds->y)
365 final_rect.y = bounds->y;
366 }
367
368 if (anchor_hints & GDK_ANCHOR_RESIZE_X)
369 {
370 if (final_rect.x < bounds->x)
371 {
372 final_rect.width -= bounds->x - final_rect.x;
373 final_rect.x = bounds->x;
374 }
375
376 if (final_rect.x + final_rect.width > bounds->x + bounds->width)
377 final_rect.width = bounds->x + bounds->width - final_rect.x;
378 }
379
380 if (anchor_hints & GDK_ANCHOR_RESIZE_Y)
381 {
382 if (final_rect.y < bounds->y)
383 {
384 final_rect.height -= bounds->y - final_rect.y;
385 final_rect.y = bounds->y;
386 }
387
388 if (final_rect.y + final_rect.height > bounds->y + bounds->height)
389 final_rect.height = bounds->y + bounds->height - final_rect.y;
390 }
391
392 final_rect.x -= shadow_left;
393 final_rect.y -= shadow_top;
394 final_rect.width += shadow_left + shadow_right;
395 final_rect.height += shadow_top + shadow_bottom;
396
397 gdk_surface_get_origin (surface: surface->parent, x: &x, y: &y);
398 final_rect.x -= x;
399 final_rect.y -= y;
400
401 if (flipped_x)
402 {
403 rect_anchor = gdk_gravity_flip_horizontally (anchor: rect_anchor);
404 surface_anchor = gdk_gravity_flip_horizontally (anchor: surface_anchor);
405 }
406 if (flipped_y)
407 {
408 rect_anchor = gdk_gravity_flip_vertically (anchor: rect_anchor);
409 surface_anchor = gdk_gravity_flip_vertically (anchor: surface_anchor);
410 }
411
412 surface->popup.rect_anchor = rect_anchor;
413 surface->popup.surface_anchor = surface_anchor;
414
415 *out_final_rect = final_rect;
416}
417
418/* Since GdkEvent is a GTypeInstance, GValue can only store it as a pointer,
419 * and GClosure does not know how to handle its memory management. To avoid
420 * the event going away in the middle of the signal emission, we provide a
421 * marshaller that keeps the event alive for the duration of the closure.
422 */
423static void
424gdk_surface_event_marshaller (GClosure *closure,
425 GValue *return_value,
426 guint n_param_values,
427 const GValue *param_values,
428 gpointer invocation_hint,
429 gpointer marshal_data)
430{
431 GdkEvent *event = g_value_get_pointer (value: &param_values[1]);
432
433 gdk_event_ref (event);
434
435 _gdk_marshal_BOOLEAN__POINTER (closure,
436 return_value,
437 n_param_values,
438 param_values,
439 invocation_hint,
440 marshal_data);
441
442
443 gdk_event_unref (event);
444}
445
446static void
447gdk_surface_event_marshallerv (GClosure *closure,
448 GValue *return_value,
449 gpointer instance,
450 va_list args,
451 gpointer marshal_data,
452 int n_params,
453 GType *param_types)
454{
455 va_list args_copy;
456 GdkEvent *event;
457
458 G_VA_COPY (args_copy, args);
459 event = va_arg (args_copy, gpointer);
460
461 gdk_event_ref (event);
462
463 _gdk_marshal_BOOLEAN__POINTERv (closure,
464 return_value,
465 instance,
466 args,
467 marshal_data,
468 n_params,
469 param_types);
470
471 gdk_event_unref (event);
472
473 va_end (args_copy);
474}
475
476static void
477gdk_surface_init (GdkSurface *surface)
478{
479 /* 0-initialization is good for all other fields. */
480
481 surface->state = 0;
482 surface->fullscreen_mode = GDK_FULLSCREEN_ON_CURRENT_MONITOR;
483 surface->width = 1;
484 surface->height = 1;
485
486 surface->alpha = 255;
487
488 surface->device_cursor = g_hash_table_new_full (NULL, NULL,
489 NULL, value_destroy_func: g_object_unref);
490}
491
492static void
493gdk_surface_class_init (GdkSurfaceClass *klass)
494{
495 GObjectClass *object_class = G_OBJECT_CLASS (klass);
496
497 object_class->finalize = gdk_surface_finalize;
498 object_class->set_property = gdk_surface_set_property;
499 object_class->get_property = gdk_surface_get_property;
500
501 klass->beep = gdk_surface_real_beep;
502
503 /**
504 * GdkSurface:cursor: (attributes org.gtk.Property.get=gdk_surface_get_cursor org.gtk.Property.set=gdk_surface_set_cursor)
505 *
506 * The mouse pointer for the `GdkSurface`.
507 */
508 properties[PROP_CURSOR] =
509 g_param_spec_object (name: "cursor",
510 P_("Cursor"),
511 P_("Cursor"),
512 GDK_TYPE_CURSOR,
513 flags: G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
514
515 /**
516 * GdkSurface:display: (attributes org.gtk.Property.get=gdk_surface_get_display)
517 *
518 * The `GdkDisplay` connection of the surface.
519 */
520 properties[PROP_DISPLAY] =
521 g_param_spec_object (name: "display",
522 P_("Display"),
523 P_("Display"),
524 GDK_TYPE_DISPLAY,
525 flags: G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
526
527 /**
528 * GdkSurface:frame-clock: (attributes org.gtk.Property.get=gdk_surface_get_frame_clock)
529 *
530 * The `GdkFrameClock` of the surface.
531 */
532 properties[PROP_FRAME_CLOCK] =
533 g_param_spec_object (name: "frame-clock",
534 P_("Frame Clock"),
535 P_("Frame Clock"),
536 GDK_TYPE_FRAME_CLOCK,
537 flags: G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
538
539 /**
540 * GdkSurface:mapped: (attributes org.gtk.Property.get=gdk_surface_get_mapped)
541 *
542 * Whether the surface is mapped.
543 */
544 properties[PROP_MAPPED] =
545 g_param_spec_boolean (name: "mapped",
546 P_("Mapped"),
547 P_("Mapped"),
548 FALSE,
549 flags: G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
550
551 /**
552 * GdkSurface:width: (attributes org.gtk.Property.get=gdk_surface_get_width)
553 *
554 * The width of the surface in pixels.
555 */
556 properties[PROP_WIDTH] =
557 g_param_spec_int (name: "width",
558 P_("Width"),
559 P_("Width"),
560 minimum: 0, G_MAXINT, default_value: 0,
561 flags: G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
562
563 /**
564 * GdkSurface:height: (attributes org.gtk.Property.get=gdk_surface_get_height)
565 *
566 * The height of the surface, in pixels.
567 */
568 properties[PROP_HEIGHT] =
569 g_param_spec_int (name: "height",
570 P_("Height"),
571 P_("Height"),
572 minimum: 0, G_MAXINT, default_value: 0,
573 flags: G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
574
575 /**
576 * GdkSurface:scale-factor: (attributes org.gtk.Property.get=gdk_surface_get_scale_factor)
577 *
578 * The scale factor of the surface.
579 */
580 properties[PROP_SCALE_FACTOR] =
581 g_param_spec_int (name: "scale-factor",
582 P_("Scale factor"),
583 P_("Scale factor"),
584 minimum: 1, G_MAXINT, default_value: 1,
585 flags: G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
586
587 g_object_class_install_properties (oclass: object_class, n_pspecs: LAST_PROP, pspecs: properties);
588
589 /**
590 * GdkSurface::layout:
591 * @surface: the `GdkSurface`
592 * @width: the current width
593 * @height: the current height
594 *
595 * Emitted when the size of @surface is changed, or when relayout should
596 * be performed.
597 *
598 * Surface size is reported in ”application pixels”, not
599 * ”device pixels” (see gdk_surface_get_scale_factor()).
600 */
601 signals[LAYOUT] =
602 g_signal_new (signal_name: g_intern_static_string (string: "layout"),
603 G_OBJECT_CLASS_TYPE (object_class),
604 signal_flags: G_SIGNAL_RUN_FIRST,
605 class_offset: 0,
606 NULL,
607 NULL,
608 c_marshaller: _gdk_marshal_VOID__INT_INT,
609 G_TYPE_NONE,
610 n_params: 2,
611 G_TYPE_INT,
612 G_TYPE_INT);
613 g_signal_set_va_marshaller (signal_id: signals[LAYOUT],
614 G_OBJECT_CLASS_TYPE (object_class),
615 va_marshaller: _gdk_marshal_VOID__INT_INTv);
616
617 /**
618 * GdkSurface::render:
619 * @surface: the `GdkSurface`
620 * @region: the region that needs to be redrawn
621 *
622 * Emitted when part of the surface needs to be redrawn.
623 *
624 * Returns: %TRUE to indicate that the signal has been handled
625 */
626 signals[RENDER] =
627 g_signal_new (signal_name: g_intern_static_string (string: "render"),
628 G_OBJECT_CLASS_TYPE (object_class),
629 signal_flags: G_SIGNAL_RUN_LAST,
630 class_offset: 0,
631 accumulator: g_signal_accumulator_true_handled,
632 NULL,
633 c_marshaller: _gdk_marshal_BOOLEAN__BOXED,
634 G_TYPE_BOOLEAN,
635 n_params: 1,
636 CAIRO_GOBJECT_TYPE_REGION);
637 g_signal_set_va_marshaller (signal_id: signals[RENDER],
638 G_OBJECT_CLASS_TYPE (object_class),
639 va_marshaller: _gdk_marshal_BOOLEAN__BOXEDv);
640
641 /**
642 * GdkSurface::event:
643 * @surface: the `GdkSurface`
644 * @event: (type Gdk.Event): an input event
645 *
646 * Emitted when GDK receives an input event for @surface.
647 *
648 * Returns: %TRUE to indicate that the event has been handled
649 */
650 signals[EVENT] =
651 g_signal_new (signal_name: g_intern_static_string (string: "event"),
652 G_OBJECT_CLASS_TYPE (object_class),
653 signal_flags: G_SIGNAL_RUN_LAST,
654 class_offset: 0,
655 accumulator: g_signal_accumulator_true_handled,
656 NULL,
657 c_marshaller: gdk_surface_event_marshaller,
658 G_TYPE_BOOLEAN,
659 n_params: 1,
660 G_TYPE_POINTER);
661 g_signal_set_va_marshaller (signal_id: signals[EVENT],
662 G_OBJECT_CLASS_TYPE (object_class),
663 va_marshaller: gdk_surface_event_marshallerv);
664
665 /**
666 * GdkSurface::enter-monitor:
667 * @surface: the `GdkSurface`
668 * @monitor: the monitor
669 *
670 * Emitted when @surface starts being present on the monitor.
671 */
672 signals[ENTER_MONITOR] =
673 g_signal_new (signal_name: g_intern_static_string (string: "enter-monitor"),
674 G_OBJECT_CLASS_TYPE (object_class),
675 signal_flags: G_SIGNAL_RUN_FIRST,
676 class_offset: 0,
677 NULL,
678 NULL,
679 NULL,
680 G_TYPE_NONE,
681 n_params: 1,
682 GDK_TYPE_MONITOR);
683
684 /**
685 * GdkSurface::leave-monitor:
686 * @surface: the `GdkSurface`
687 * @monitor: the monitor
688 *
689 * Emitted when @surface stops being present on the monitor.
690 */
691 signals[LEAVE_MONITOR] =
692 g_signal_new (signal_name: g_intern_static_string (string: "leave-monitor"),
693 G_OBJECT_CLASS_TYPE (object_class),
694 signal_flags: G_SIGNAL_RUN_FIRST,
695 class_offset: 0,
696 NULL,
697 NULL,
698 NULL,
699 G_TYPE_NONE,
700 n_params: 1,
701 GDK_TYPE_MONITOR);
702}
703
704static void
705seat_removed_cb (GdkDisplay *display,
706 GdkSeat *seat,
707 GdkSurface *surface)
708{
709 GdkDevice *device = gdk_seat_get_pointer (seat);
710
711 surface->devices_inside = g_list_remove (list: surface->devices_inside, data: device);
712 g_hash_table_remove (hash_table: surface->device_cursor, key: device);
713}
714
715static void
716gdk_surface_finalize (GObject *object)
717{
718 GdkSurface *surface = GDK_SURFACE (object);
719
720 g_clear_handle_id (&surface->request_motion_id, g_source_remove);
721
722 g_signal_handlers_disconnect_by_func (surface->display,
723 seat_removed_cb, surface);
724
725 if (!GDK_SURFACE_DESTROYED (surface))
726 {
727 g_warning ("losing last reference to undestroyed surface");
728 _gdk_surface_destroy (surface, FALSE);
729 }
730
731 g_clear_pointer (&surface->input_region, cairo_region_destroy);
732 g_clear_object (&surface->cursor);
733 g_clear_pointer (&surface->device_cursor, g_hash_table_destroy);
734 g_clear_pointer (&surface->devices_inside, g_list_free);
735
736 g_clear_object (&surface->display);
737
738 g_clear_pointer (&surface->opaque_region, cairo_region_destroy);
739
740 if (surface->parent)
741 surface->parent->children = g_list_remove (list: surface->parent->children, data: surface);
742
743 G_OBJECT_CLASS (gdk_surface_parent_class)->finalize (object);
744}
745
746static void
747gdk_surface_set_property (GObject *object,
748 guint prop_id,
749 const GValue *value,
750 GParamSpec *pspec)
751{
752 GdkSurface *surface = GDK_SURFACE (object);
753
754 switch (prop_id)
755 {
756 case PROP_CURSOR:
757 gdk_surface_set_cursor (surface, cursor: g_value_get_object (value));
758 break;
759
760 case PROP_DISPLAY:
761 surface->display = g_value_dup_object (value);
762 g_assert (surface->display != NULL);
763 g_signal_connect (surface->display, "seat-removed",
764 G_CALLBACK (seat_removed_cb), surface);
765 break;
766
767 case PROP_FRAME_CLOCK:
768 gdk_surface_set_frame_clock (surface, GDK_FRAME_CLOCK (g_value_get_object (value)));
769 break;
770
771 default:
772 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
773 break;
774 }
775}
776
777#define GDK_SURFACE_IS_STICKY(surface) (((surface)->state & GDK_TOPLEVEL_STATE_STICKY))
778
779static void
780gdk_surface_get_property (GObject *object,
781 guint prop_id,
782 GValue *value,
783 GParamSpec *pspec)
784{
785 GdkSurface *surface = GDK_SURFACE (object);
786
787 switch (prop_id)
788 {
789 case PROP_CURSOR:
790 g_value_set_object (value, v_object: gdk_surface_get_cursor (surface));
791 break;
792
793 case PROP_DISPLAY:
794 g_value_set_object (value, v_object: surface->display);
795 break;
796
797 case PROP_FRAME_CLOCK:
798 g_value_set_object (value, v_object: surface->frame_clock);
799 break;
800
801 case PROP_MAPPED:
802 g_value_set_boolean (value, GDK_SURFACE_IS_MAPPED (surface));
803 break;
804
805 case PROP_WIDTH:
806 g_value_set_int (value, v_int: surface->width);
807 break;
808
809 case PROP_HEIGHT:
810 g_value_set_int (value, v_int: surface->height);
811 break;
812
813 case PROP_SCALE_FACTOR:
814 g_value_set_int (value, v_int: gdk_surface_get_scale_factor (surface));
815 break;
816
817 default:
818 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
819 break;
820 }
821}
822
823void
824_gdk_surface_update_size (GdkSurface *surface)
825{
826 GSList *l;
827
828 for (l = surface->draw_contexts; l; l = l->next)
829 gdk_draw_context_surface_resized (context: l->data);
830
831 g_object_notify (G_OBJECT (surface), property_name: "width");
832 g_object_notify (G_OBJECT (surface), property_name: "height");
833}
834
835static GdkSurface *
836gdk_surface_new (GdkDisplay *display,
837 GdkSurfaceType surface_type,
838 GdkSurface *parent,
839 int x,
840 int y,
841 int width,
842 int height)
843{
844 return gdk_display_create_surface (display,
845 surface_type,
846 parent,
847 x, y, width, height);
848}
849
850/**
851 * gdk_surface_new_toplevel: (constructor)
852 * @display: the display to create the surface on
853 *
854 * Creates a new toplevel surface.
855 *
856 * Returns: (transfer full): the new `GdkSurface`
857 */
858GdkSurface *
859gdk_surface_new_toplevel (GdkDisplay *display)
860{
861 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
862
863 return gdk_surface_new (display, surface_type: GDK_SURFACE_TOPLEVEL,
864 NULL, x: 0, y: 0, width: 1, height: 1);
865}
866
867/**
868 * gdk_surface_new_popup: (constructor)
869 * @parent: the parent surface to attach the surface to
870 * @autohide: whether to hide the surface on outside clicks
871 *
872 * Create a new popup surface.
873 *
874 * The surface will be attached to @parent and can be positioned
875 * relative to it using [method@Gdk.Popup.present].
876 *
877 * Returns: (transfer full): a new `GdkSurface`
878 */
879GdkSurface *
880gdk_surface_new_popup (GdkSurface *parent,
881 gboolean autohide)
882{
883 GdkSurface *surface;
884
885 g_return_val_if_fail (GDK_IS_SURFACE (parent), NULL);
886
887 surface = gdk_surface_new (display: parent->display, surface_type: GDK_SURFACE_POPUP,
888 parent, x: 0, y: 0, width: 100, height: 100);
889
890 surface->autohide = autohide;
891
892 return surface;
893}
894
895static void
896update_pointer_info_foreach (GdkDisplay *display,
897 GdkDevice *device,
898 GdkPointerSurfaceInfo *pointer_info,
899 gpointer user_data)
900{
901 GdkSurface *surface = user_data;
902
903 if (pointer_info->surface_under_pointer == surface)
904 {
905 g_object_unref (object: pointer_info->surface_under_pointer);
906 pointer_info->surface_under_pointer = NULL;
907 }
908}
909
910static void
911surface_remove_from_pointer_info (GdkSurface *surface,
912 GdkDisplay *display)
913{
914 _gdk_display_pointer_info_foreach (display,
915 func: update_pointer_info_foreach,
916 user_data: surface);
917}
918
919/**
920 * _gdk_surface_destroy_hierarchy:
921 * @surface: a `GdkSurface`
922 * @recursing_native: If %TRUE, then this is being called because a native
923 * parent was destroyed. This generally means that the call to the windowing
924 * system to destroy the surface can be omitted, since it will be destroyed
925 * as a result of the parent being destroyed. Unless @foreign_destroy.
926 * @foreign_destroy: If %TRUE, the surface or a parent was destroyed by some
927 * external agency. The surface has already been destroyed and no windowing
928 * system calls should be made. (This may never happen for some windowing
929 * systems.)
930 *
931 * Internal function to destroy a surface. Like gdk_surface_destroy(),
932 * but does not drop the reference count created by gdk_surface_new().
933 */
934static void
935_gdk_surface_destroy_hierarchy (GdkSurface *surface,
936 gboolean foreign_destroy)
937{
938 G_GNUC_UNUSED GdkSurfacePrivate *priv = gdk_surface_get_instance_private (self: surface);
939
940 g_return_if_fail (GDK_IS_SURFACE (surface));
941
942 if (GDK_SURFACE_DESTROYED (surface))
943 return;
944
945 GDK_SURFACE_GET_CLASS (surface)->destroy (surface, foreign_destroy);
946
947 /* backend must have unset this */
948 g_assert (priv->egl_native_window == NULL);
949
950 if (surface->gl_paint_context)
951 {
952 /* Make sure to destroy if current */
953 g_object_run_dispose (G_OBJECT (surface->gl_paint_context));
954 g_object_unref (object: surface->gl_paint_context);
955 surface->gl_paint_context = NULL;
956 }
957
958 if (surface->frame_clock)
959 {
960 if (surface->parent == NULL)
961 g_object_run_dispose (G_OBJECT (surface->frame_clock));
962 gdk_surface_set_frame_clock (surface, NULL);
963 }
964
965 _gdk_surface_clear_update_area (surface);
966
967 g_clear_handle_id (&surface->set_is_mapped_source_id, g_source_remove);
968 surface->is_mapped = FALSE;
969 surface->pending_is_mapped = FALSE;
970
971 surface->destroyed = TRUE;
972
973 surface_remove_from_pointer_info (surface, display: surface->display);
974
975 if (GDK_IS_TOPLEVEL (ptr: surface))
976 g_object_notify (G_OBJECT (surface), property_name: "state");
977 g_object_notify_by_pspec (G_OBJECT (surface), pspec: properties[PROP_MAPPED]);
978}
979
980/**
981 * _gdk_surface_destroy:
982 * @surface: a `GdkSurface`
983 * @foreign_destroy: If %TRUE, the surface or a parent was destroyed by some
984 * external agency. The surface has already been destroyed and no windowing
985 * system calls should be made. (This may never happen for some windowing
986 * systems.)
987 *
988 * Internal function to destroy a surface. Like gdk_surface_destroy(),
989 * but does not drop the reference count created by gdk_surface_new().
990 */
991void
992_gdk_surface_destroy (GdkSurface *surface,
993 gboolean foreign_destroy)
994{
995 _gdk_surface_destroy_hierarchy (surface, foreign_destroy);
996}
997
998/**
999 * gdk_surface_destroy:
1000 * @surface: a `GdkSurface`
1001 *
1002 * Destroys the window system resources associated with @surface and
1003 * decrements @surface's reference count.
1004 *
1005 * The window system resources for all children of @surface are also
1006 * destroyed, but the children’s reference counts are not decremented.
1007 *
1008 * Note that a surface will not be destroyed automatically when its
1009 * reference count reaches zero. You must call this function yourself
1010 * before that happens.
1011 */
1012void
1013gdk_surface_destroy (GdkSurface *surface)
1014{
1015 _gdk_surface_destroy_hierarchy (surface, FALSE);
1016 g_object_unref (object: surface);
1017}
1018
1019void
1020gdk_surface_set_widget (GdkSurface *self,
1021 gpointer widget)
1022{
1023 GdkSurfacePrivate *priv = gdk_surface_get_instance_private (self);
1024
1025 priv->widget = widget;
1026}
1027
1028gpointer
1029gdk_surface_get_widget (GdkSurface *self)
1030{
1031 GdkSurfacePrivate *priv = gdk_surface_get_instance_private (self);
1032
1033 return priv->widget;
1034}
1035
1036/**
1037 * gdk_surface_get_display: (attributes org.gtk.Method.get_property=display)
1038 * @surface: a `GdkSurface`
1039 *
1040 * Gets the `GdkDisplay` associated with a `GdkSurface`.
1041 *
1042 * Returns: (transfer none): the `GdkDisplay` associated with @surface
1043 */
1044GdkDisplay *
1045gdk_surface_get_display (GdkSurface *surface)
1046{
1047 g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL);
1048
1049 return surface->display;
1050}
1051/**
1052 * gdk_surface_is_destroyed:
1053 * @surface: a `GdkSurface`
1054 *
1055 * Check to see if a surface is destroyed.
1056 *
1057 * Returns: %TRUE if the surface is destroyed
1058 */
1059gboolean
1060gdk_surface_is_destroyed (GdkSurface *surface)
1061{
1062 return GDK_SURFACE_DESTROYED (surface);
1063}
1064
1065/**
1066 * gdk_surface_get_mapped: (attributes org.gtk.Method.get_property=mapped)
1067 * @surface: a `GdkSurface`
1068 *
1069 * Checks whether the surface has been mapped.
1070 *
1071 * A surface is mapped with [method@Gdk.Toplevel.present]
1072 * or [method@Gdk.Popup.present].
1073 *
1074 * Returns: %TRUE if the surface is mapped
1075 */
1076gboolean
1077gdk_surface_get_mapped (GdkSurface *surface)
1078{
1079 g_return_val_if_fail (GDK_IS_SURFACE (surface), FALSE);
1080
1081 return GDK_SURFACE_IS_MAPPED (surface);
1082}
1083
1084void
1085gdk_surface_set_egl_native_window (GdkSurface *self,
1086 gpointer native_window)
1087{
1088#ifdef HAVE_EGL
1089 GdkSurfacePrivate *priv = gdk_surface_get_instance_private (self);
1090
1091 /* This checks that all EGL platforms we support conform to the same struct sizes.
1092 * When this ever fails, there will be some fun times happening for whoever tries
1093 * this weird EGL backend... */
1094 G_STATIC_ASSERT (sizeof (gpointer) == sizeof (EGLNativeWindowType));
1095
1096 if (priv->egl_surface != NULL)
1097 {
1098 gdk_gl_context_clear_current_if_surface (surface: self);
1099 eglDestroySurface (gdk_surface_get_display (surface: self), priv->egl_surface);
1100 priv->egl_surface = NULL;
1101 }
1102
1103 priv->egl_native_window = native_window;
1104}
1105
1106gpointer /* EGLSurface */
1107gdk_surface_get_egl_surface (GdkSurface *self)
1108{
1109 GdkSurfacePrivate *priv = gdk_surface_get_instance_private (self);
1110
1111 return priv->egl_surface;
1112}
1113
1114void
1115gdk_surface_ensure_egl_surface (GdkSurface *self,
1116 gboolean high_depth)
1117{
1118 GdkSurfacePrivate *priv = gdk_surface_get_instance_private (self);
1119 GdkDisplay *display = gdk_surface_get_display (surface: self);
1120
1121 g_return_if_fail (priv->egl_native_window != NULL);
1122
1123 if (priv->egl_surface_high_depth != high_depth &&
1124 priv->egl_surface != NULL &&
1125 gdk_display_get_egl_config_high_depth (display) != gdk_display_get_egl_config (display))
1126 {
1127 gdk_gl_context_clear_current_if_surface (surface: self);
1128 eglDestroySurface (gdk_display_get_egl_display (display), priv->egl_surface);
1129 priv->egl_surface = NULL;
1130 }
1131
1132 if (priv->egl_surface == NULL)
1133 {
1134 priv->egl_surface = eglCreateWindowSurface (gdk_display_get_egl_display (display),
1135 high_depth ? gdk_display_get_egl_config_high_depth (display)
1136 : gdk_display_get_egl_config (display),
1137 (EGLNativeWindowType) priv->egl_native_window,
1138 NULL);
1139 priv->egl_surface_high_depth = high_depth;
1140 }
1141#endif
1142}
1143
1144GdkGLContext *
1145gdk_surface_get_paint_gl_context (GdkSurface *surface,
1146 GError **error)
1147{
1148 if (!gdk_display_prepare_gl (self: surface->display, error))
1149 return NULL;
1150
1151 if (surface->gl_paint_context == NULL)
1152 {
1153 surface->gl_paint_context = gdk_surface_create_gl_context (surface, error);
1154 if (surface->gl_paint_context == NULL)
1155 return NULL;
1156 }
1157
1158 if (!gdk_gl_context_realize (context: surface->gl_paint_context, error))
1159 {
1160 g_clear_object (&surface->gl_paint_context);
1161 return NULL;
1162 }
1163
1164 return surface->gl_paint_context;
1165}
1166
1167/**
1168 * gdk_surface_create_gl_context:
1169 * @surface: a `GdkSurface`
1170 * @error: return location for an error
1171 *
1172 * Creates a new `GdkGLContext` for the `GdkSurface`.
1173 *
1174 * The context is disconnected from any particular surface or surface.
1175 * If the creation of the `GdkGLContext` failed, @error will be set.
1176 * Before using the returned `GdkGLContext`, you will need to
1177 * call [method@Gdk.GLContext.make_current] or [method@Gdk.GLContext.realize].
1178 *
1179 * Returns: (transfer full): the newly created `GdkGLContext`
1180 */
1181GdkGLContext *
1182gdk_surface_create_gl_context (GdkSurface *surface,
1183 GError **error)
1184{
1185 g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL);
1186 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1187
1188 if (!gdk_display_prepare_gl (self: surface->display, error))
1189 return NULL;
1190
1191 return gdk_gl_context_new (display: surface->display, surface);
1192}
1193
1194/**
1195 * gdk_surface_create_cairo_context:
1196 * @surface: a `GdkSurface`
1197 *
1198 * Creates a new `GdkCairoContext` for rendering on @surface.
1199 *
1200 * Returns: (transfer full): the newly created `GdkCairoContext`
1201 */
1202GdkCairoContext *
1203gdk_surface_create_cairo_context (GdkSurface *surface)
1204{
1205 GdkDisplay *display;
1206
1207 g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL);
1208
1209 display = surface->display;
1210
1211 return g_object_new (GDK_DISPLAY_GET_CLASS (display)->cairo_context_type,
1212 first_property_name: "surface", surface,
1213 NULL);
1214}
1215
1216/**
1217 * gdk_surface_create_vulkan_context:
1218 * @surface: a `GdkSurface`
1219 * @error: return location for an error
1220 *
1221 * Creates a new `GdkVulkanContext` for rendering on @surface.
1222 *
1223 * If the creation of the `GdkVulkanContext` failed, @error will be set.
1224 *
1225 * Returns: (transfer full): the newly created `GdkVulkanContext`, or
1226 * %NULL on error
1227 */
1228GdkVulkanContext *
1229gdk_surface_create_vulkan_context (GdkSurface *surface,
1230 GError **error)
1231{
1232 GdkDisplay *display;
1233
1234 g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL);
1235 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1236
1237 if (GDK_DISPLAY_DEBUG_CHECK (surface->display, VULKAN_DISABLE))
1238 {
1239 g_set_error_literal (err: error, GDK_VULKAN_ERROR, code: GDK_VULKAN_ERROR_NOT_AVAILABLE,
1240 _("Vulkan support disabled via GDK_DEBUG"));
1241 return NULL;
1242 }
1243
1244 display = surface->display;
1245
1246 if (GDK_DISPLAY_GET_CLASS (display)->vk_extension_name == NULL)
1247 {
1248 g_set_error (err: error, GDK_VULKAN_ERROR, code: GDK_VULKAN_ERROR_UNSUPPORTED,
1249 format: "The %s backend has no Vulkan support.", G_OBJECT_TYPE_NAME (display));
1250 return FALSE;
1251 }
1252
1253 return g_initable_new (GDK_DISPLAY_GET_CLASS (display)->vk_context_type,
1254 NULL,
1255 error,
1256 first_property_name: "surface", surface,
1257 NULL);
1258}
1259
1260/* Code for dirty-region queueing
1261 */
1262static GSList *update_surfaces = NULL;
1263
1264static void
1265gdk_surface_add_update_surface (GdkSurface *surface)
1266{
1267 GSList *tmp;
1268
1269 /* Check whether "surface" is already in "update_surfaces" list.
1270 * It could be added during execution of gtk_widget_destroy() when
1271 * setting focus widget to NULL and redrawing old focus widget.
1272 * See bug 711552.
1273 */
1274 tmp = g_slist_find (list: update_surfaces, data: surface);
1275 if (tmp != NULL)
1276 return;
1277
1278 update_surfaces = g_slist_prepend (list: update_surfaces, g_object_ref (surface));
1279}
1280
1281static void
1282gdk_surface_remove_update_surface (GdkSurface *surface)
1283{
1284 GSList *link;
1285
1286 link = g_slist_find (list: update_surfaces, data: surface);
1287 if (link != NULL)
1288 {
1289 update_surfaces = g_slist_delete_link (list: update_surfaces, link_: link);
1290 g_object_unref (object: surface);
1291 }
1292}
1293
1294static gboolean
1295gdk_surface_is_toplevel_frozen (GdkSurface *surface)
1296{
1297 return surface->update_and_descendants_freeze_count > 0;
1298}
1299
1300static void
1301gdk_surface_schedule_update (GdkSurface *surface)
1302{
1303 GdkFrameClock *frame_clock;
1304
1305 g_return_if_fail (surface);
1306
1307 surface->pending_phases |= GDK_FRAME_CLOCK_PHASE_PAINT;
1308
1309 if (surface->update_freeze_count ||
1310 gdk_surface_is_toplevel_frozen (surface))
1311 return;
1312
1313 /* If there's no frame clock (a foreign surface), then the invalid
1314 * region will just stick around unless gdk_surface_process_updates()
1315 * is called. */
1316 frame_clock = gdk_surface_get_frame_clock (surface);
1317 if (frame_clock)
1318 gdk_frame_clock_request_phase (frame_clock: gdk_surface_get_frame_clock (surface),
1319 phase: GDK_FRAME_CLOCK_PHASE_PAINT);
1320}
1321
1322static void
1323gdk_surface_process_updates_internal (GdkSurface *surface)
1324{
1325 /* Ensure the surface lives while updating it */
1326 g_object_ref (surface);
1327
1328 surface->in_update = TRUE;
1329
1330 /* If an update got queued during update processing, we can get a
1331 * surface in the update queue that has an empty update_area.
1332 * just ignore it.
1333 */
1334 if (surface->update_area)
1335 {
1336 g_assert (surface->active_update_area == NULL); /* No reentrancy */
1337
1338 surface->active_update_area = surface->update_area;
1339 surface->update_area = NULL;
1340
1341 if (GDK_SURFACE_IS_MAPPED (surface))
1342 {
1343 cairo_region_t *expose_region;
1344 gboolean handled;
1345
1346 expose_region = cairo_region_copy (original: surface->active_update_area);
1347
1348 g_signal_emit (instance: surface, signal_id: signals[RENDER], detail: 0, expose_region, &handled);
1349
1350 cairo_region_destroy (region: expose_region);
1351 }
1352
1353 cairo_region_destroy (region: surface->active_update_area);
1354 surface->active_update_area = NULL;
1355 }
1356
1357 surface->in_update = FALSE;
1358
1359 g_object_unref (object: surface);
1360}
1361
1362static void
1363gdk_surface_layout_on_clock (GdkFrameClock *clock,
1364 void *data)
1365{
1366 GdkSurface *surface = GDK_SURFACE (data);
1367 GdkSurfaceClass *class;
1368
1369 g_return_if_fail (GDK_IS_SURFACE (surface));
1370
1371 if (GDK_SURFACE_DESTROYED (surface))
1372 return;
1373
1374 if (!GDK_SURFACE_IS_MAPPED (surface))
1375 return;
1376
1377 surface->pending_phases &= ~GDK_FRAME_CLOCK_PHASE_LAYOUT;
1378
1379 class = GDK_SURFACE_GET_CLASS (surface);
1380 if (class->compute_size)
1381 {
1382 if (class->compute_size (surface))
1383 return;
1384 }
1385
1386 g_signal_emit (instance: surface, signal_id: signals[LAYOUT], detail: 0, surface->width, surface->height);
1387}
1388
1389/**
1390 * gdk_surface_request_layout:
1391 * @surface: a `GdkSurface`
1392 *
1393 * Request a layout phase from the surface's frame clock.
1394 *
1395 * See [method@Gdk.FrameClock.request_phase].
1396 */
1397void
1398gdk_surface_request_layout (GdkSurface *surface)
1399{
1400 GdkSurfaceClass *class;
1401 GdkFrameClock *frame_clock;
1402
1403 class = GDK_SURFACE_GET_CLASS (surface);
1404 if (class->request_layout)
1405 class->request_layout (surface);
1406
1407 frame_clock = gdk_surface_get_frame_clock (surface);
1408 g_return_if_fail (frame_clock);
1409
1410 gdk_frame_clock_request_phase (frame_clock,
1411 phase: GDK_FRAME_CLOCK_PHASE_LAYOUT);
1412}
1413
1414static void
1415gdk_surface_paint_on_clock (GdkFrameClock *clock,
1416 void *data)
1417{
1418 GdkSurface *surface = GDK_SURFACE (data);
1419
1420 g_return_if_fail (GDK_IS_SURFACE (surface));
1421
1422 if (GDK_SURFACE_DESTROYED (surface))
1423 return;
1424
1425 g_object_ref (surface);
1426
1427 if (surface->update_area &&
1428 !surface->update_freeze_count &&
1429 !gdk_surface_is_toplevel_frozen (surface) &&
1430
1431 /* Don't recurse into process_updates_internal, we'll
1432 * do the update later when idle instead. */
1433 !surface->in_update)
1434 {
1435 surface->pending_phases &= ~GDK_FRAME_CLOCK_PHASE_PAINT;
1436 gdk_surface_process_updates_internal (surface);
1437 gdk_surface_remove_update_surface (surface);
1438 }
1439
1440 g_object_unref (object: surface);
1441}
1442
1443/*
1444 * gdk_surface_invalidate_rect:
1445 * @surface: a `GdkSurface`
1446 * @rect: (nullable): rectangle to invalidate or %NULL to
1447 * invalidate the whole surface
1448 *
1449 * Invalidate a rectangular region of @surface.
1450 *
1451 * This is a convenience wrapper around
1452 * [method@Gdk.Surface.invalidate_region].
1453 */
1454void
1455gdk_surface_invalidate_rect (GdkSurface *surface,
1456 const GdkRectangle *rect)
1457{
1458 GdkRectangle surface_rect;
1459 cairo_region_t *region;
1460
1461 g_return_if_fail (GDK_IS_SURFACE (surface));
1462
1463 if (!GDK_SURFACE_IS_MAPPED (surface))
1464 return;
1465
1466 if (!rect)
1467 {
1468 surface_rect.x = 0;
1469 surface_rect.y = 0;
1470 surface_rect.width = surface->width;
1471 surface_rect.height = surface->height;
1472 rect = &surface_rect;
1473 }
1474
1475 region = cairo_region_create_rectangle (rectangle: rect);
1476 gdk_surface_invalidate_region (surface, region);
1477 cairo_region_destroy (region);
1478}
1479
1480static void
1481impl_surface_add_update_area (GdkSurface *impl_surface,
1482 cairo_region_t *region)
1483{
1484 if (impl_surface->update_area)
1485 cairo_region_union (dst: impl_surface->update_area, other: region);
1486 else
1487 {
1488 gdk_surface_add_update_surface (surface: impl_surface);
1489 impl_surface->update_area = cairo_region_copy (original: region);
1490 gdk_surface_schedule_update (surface: impl_surface);
1491 }
1492}
1493
1494/**
1495 * gdk_surface_queue_render:
1496 * @surface: a `GdkSurface`
1497 *
1498 * Forces a [signal@Gdk.Surface::render] signal emission for @surface
1499 * to be scheduled.
1500 *
1501 * This function is useful for implementations that track invalid
1502 * regions on their own.
1503 */
1504void
1505gdk_surface_queue_render (GdkSurface *surface)
1506{
1507 cairo_region_t *region;
1508
1509 g_return_if_fail (GDK_IS_SURFACE (surface));
1510
1511 region = cairo_region_create ();
1512 impl_surface_add_update_area (impl_surface: surface, region);
1513 cairo_region_destroy (region);
1514}
1515
1516/*
1517 * gdk_surface_invalidate_region:
1518 * @surface: a `GdkSurface`
1519 * @region: a `cairo_region_t`
1520 *
1521 * Adds @region to the update area for @surface.
1522 *
1523 * The update area is the region that needs to be redrawn,
1524 * or “dirty region.”
1525 *
1526 * GDK will process all updates whenever the frame clock schedules
1527 * a redraw, so there’s no need to do forces redraws manually, you
1528 * just need to invalidate regions that you know should be redrawn.
1529 */
1530void
1531gdk_surface_invalidate_region (GdkSurface *surface,
1532 const cairo_region_t *region)
1533{
1534 cairo_region_t *visible_region;
1535 cairo_rectangle_int_t r;
1536
1537 g_return_if_fail (GDK_IS_SURFACE (surface));
1538
1539 if (!GDK_SURFACE_IS_MAPPED (surface))
1540 return;
1541
1542 if (cairo_region_is_empty (region))
1543 return;
1544
1545 r.x = 0;
1546 r.y = 0;
1547 r.width = surface->width;
1548 r.height = surface->height;
1549
1550 visible_region = cairo_region_copy (original: region);
1551
1552 cairo_region_intersect_rectangle (dst: visible_region, rectangle: &r);
1553 impl_surface_add_update_area (impl_surface: surface, region: visible_region);
1554
1555 cairo_region_destroy (region: visible_region);
1556}
1557
1558/*
1559 * _gdk_surface_clear_update_area:
1560 * @surface: a `GdkSurface`
1561 *
1562 * Internal function to clear the update area for a surface.
1563 * This is called when the surface is hidden or destroyed.
1564 */
1565void
1566_gdk_surface_clear_update_area (GdkSurface *surface)
1567{
1568 g_return_if_fail (GDK_IS_SURFACE (surface));
1569
1570 if (surface->update_area)
1571 {
1572 gdk_surface_remove_update_surface (surface);
1573
1574 cairo_region_destroy (region: surface->update_area);
1575 surface->update_area = NULL;
1576 }
1577}
1578
1579/*
1580 * gdk_surface_freeze_updates:
1581 * @surface: a `GdkSurface`
1582 *
1583 * Temporarily freezes a surface such that it won’t receive expose
1584 * events. The surface will begin receiving expose events again when
1585 * gdk_surface_thaw_updates() is called. If gdk_surface_freeze_updates()
1586 * has been called more than once, gdk_surface_thaw_updates() must be
1587 * called an equal number of times to begin processing exposes.
1588 */
1589void
1590gdk_surface_freeze_updates (GdkSurface *surface)
1591{
1592 g_return_if_fail (GDK_IS_SURFACE (surface));
1593
1594 surface->update_freeze_count++;
1595 if (surface->update_freeze_count == 1)
1596 _gdk_frame_clock_uninhibit_freeze (clock: surface->frame_clock);
1597}
1598
1599static gboolean
1600request_motion_cb (void *data)
1601{
1602 GdkSurface *surface = GDK_SURFACE (data);
1603 GdkFrameClock *clock = gdk_surface_get_frame_clock (surface);
1604
1605 if (clock)
1606 gdk_frame_clock_request_phase (frame_clock: clock, phase: GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS);
1607 surface->request_motion_id = 0;
1608
1609 return G_SOURCE_REMOVE;
1610}
1611
1612
1613/*
1614 * gdk_surface_thaw_updates:
1615 * @surface: a `GdkSurface`
1616 *
1617 * Thaws a surface frozen with gdk_surface_freeze_updates(). Note that this
1618 * will not necessarily schedule updates if the surface freeze count reaches
1619 * zero.
1620 */
1621void
1622gdk_surface_thaw_updates (GdkSurface *surface)
1623{
1624 g_return_if_fail (GDK_IS_SURFACE (surface));
1625
1626 g_return_if_fail (surface->update_freeze_count > 0);
1627
1628 if (--surface->update_freeze_count == 0)
1629 {
1630 GdkFrameClock *frame_clock = surface->frame_clock;
1631
1632 _gdk_frame_clock_inhibit_freeze (clock: frame_clock);
1633
1634 if (surface->pending_phases)
1635 gdk_frame_clock_request_phase (frame_clock, phase: surface->pending_phases);
1636
1637 if (surface->request_motion && surface->request_motion_id == 0)
1638 {
1639 surface->request_motion_id =
1640 g_idle_add_full (GDK_PRIORITY_REDRAW + 20,
1641 function: request_motion_cb, data: surface, NULL);
1642 }
1643 }
1644}
1645
1646/*
1647 * gdk_surface_constrain_size:
1648 * @geometry: a `GdkGeometry` structure
1649 * @flags: a mask indicating what portions of @geometry are set
1650 * @width: desired width of surface
1651 * @height: desired height of the surface
1652 * @new_width: (out): location to store resulting width
1653 * @new_height: (out): location to store resulting height
1654 *
1655 * Constrains a desired width and height according to a
1656 * set of geometry hints (such as minimum and maximum size).
1657 */
1658void
1659gdk_surface_constrain_size (GdkGeometry *geometry,
1660 GdkSurfaceHints flags,
1661 int width,
1662 int height,
1663 int *new_width,
1664 int *new_height)
1665{
1666 /* This routine is partially borrowed from fvwm.
1667 *
1668 * Copyright 1993, Robert Nation
1669 * You may use this code for any purpose, as long as the original
1670 * copyright remains in the source code and all documentation
1671 *
1672 * which in turn borrows parts of the algorithm from uwm
1673 */
1674 int min_width = 0;
1675 int min_height = 0;
1676 int max_width = G_MAXINT;
1677 int max_height = G_MAXINT;
1678
1679 if (flags & GDK_HINT_MIN_SIZE)
1680 {
1681 min_width = geometry->min_width;
1682 min_height = geometry->min_height;
1683 }
1684
1685 if (flags & GDK_HINT_MAX_SIZE)
1686 {
1687 max_width = geometry->max_width ;
1688 max_height = geometry->max_height;
1689 }
1690
1691 /* clamp width and height to min and max values
1692 */
1693 width = CLAMP (width, min_width, max_width);
1694 height = CLAMP (height, min_height, max_height);
1695
1696 *new_width = width;
1697 *new_height = height;
1698}
1699
1700/**
1701 * gdk_surface_get_device_position:
1702 * @surface: a `GdkSurface`
1703 * @device: pointer `GdkDevice` to query to
1704 * @x: (out) (optional): return location for the X coordinate of @device
1705 * @y: (out) (optional): return location for the Y coordinate of @device
1706 * @mask: (out) (optional): return location for the modifier mask
1707 *
1708 * Obtains the current device position and modifier state.
1709 *
1710 * The position is given in coordinates relative to the upper
1711 * left corner of @surface.
1712 *
1713 * Return: %TRUE if the device is over the surface
1714 */
1715gboolean
1716gdk_surface_get_device_position (GdkSurface *surface,
1717 GdkDevice *device,
1718 double *x,
1719 double *y,
1720 GdkModifierType *mask)
1721{
1722 double tmp_x, tmp_y;
1723 GdkModifierType tmp_mask;
1724 gboolean ret;
1725
1726 g_return_val_if_fail (GDK_IS_SURFACE (surface), FALSE);
1727 g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
1728 g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, FALSE);
1729
1730 tmp_x = 0;
1731 tmp_y = 0;
1732 tmp_mask = 0;
1733
1734 ret = GDK_SURFACE_GET_CLASS (surface)->get_device_state (surface,
1735 device,
1736 &tmp_x, &tmp_y,
1737 &tmp_mask);
1738
1739 if (x)
1740 *x = tmp_x;
1741 if (y)
1742 *y = tmp_y;
1743 if (mask)
1744 *mask = tmp_mask;
1745
1746 return ret;
1747}
1748
1749/**
1750 * gdk_surface_hide:
1751 * @surface: a `GdkSurface`
1752 *
1753 * Hide the surface.
1754 *
1755 * For toplevel surfaces, withdraws them, so they will no longer be
1756 * known to the window manager; for all surfaces, unmaps them, so
1757 * they won’t be displayed. Normally done automatically as
1758 * part of [method@Gtk.Widget.hide].
1759 */
1760void
1761gdk_surface_hide (GdkSurface *surface)
1762{
1763 gboolean was_mapped;
1764
1765 g_return_if_fail (GDK_IS_SURFACE (surface));
1766
1767 if (surface->destroyed)
1768 return;
1769
1770 was_mapped = GDK_SURFACE_IS_MAPPED (surface);
1771
1772 gdk_surface_queue_set_is_mapped (surface, FALSE);
1773
1774 if (was_mapped)
1775 {
1776 GdkDisplay *display;
1777 GdkSeat *seat;
1778 GList *devices, *d;
1779
1780 /* May need to break grabs on children */
1781 display = surface->display;
1782 seat = gdk_display_get_default_seat (display);
1783 if (seat)
1784 {
1785 devices = gdk_seat_get_devices (seat, capabilities: GDK_SEAT_CAPABILITY_ALL);
1786 devices = g_list_prepend (list: devices, data: gdk_seat_get_keyboard (seat));
1787 devices = g_list_prepend (list: devices, data: gdk_seat_get_pointer (seat));
1788 }
1789 else
1790 devices = NULL;
1791
1792 for (d = devices; d; d = d->next)
1793 {
1794 GdkDevice *device = d->data;
1795
1796 if (_gdk_display_end_device_grab (display,
1797 device,
1798 serial: _gdk_display_get_next_serial (display),
1799 if_child: surface,
1800 TRUE))
1801 {
1802G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1803 gdk_device_ungrab (device, GDK_CURRENT_TIME);
1804G_GNUC_END_IGNORE_DEPRECATIONS
1805 }
1806 }
1807
1808 g_list_free (list: devices);
1809 }
1810
1811 GDK_SURFACE_GET_CLASS (surface)->hide (surface);
1812
1813 surface->popup.rect_anchor = 0;
1814 surface->popup.surface_anchor = 0;
1815 surface->x = 0;
1816 surface->y = 0;
1817}
1818
1819static void
1820gdk_surface_set_cursor_internal (GdkSurface *surface,
1821 GdkDevice *device,
1822 GdkCursor *cursor)
1823{
1824 GdkPointerSurfaceInfo *pointer_info;
1825
1826 if (GDK_SURFACE_DESTROYED (surface))
1827 return;
1828
1829 g_assert (surface->display == gdk_device_get_display (device));
1830
1831 pointer_info = _gdk_display_get_pointer_info (display: surface->display, device);
1832
1833 if (surface == pointer_info->surface_under_pointer)
1834 update_cursor (display: surface->display, device);
1835}
1836
1837/**
1838 * gdk_surface_get_cursor: (attributes org.gtk.Method.get_property=cursor)
1839 * @surface: a `GdkSurface`
1840 *
1841 * Retrieves a `GdkCursor` pointer for the cursor currently set on the
1842 * `GdkSurface`.
1843 *
1844 * If the return value is %NULL then there is no custom cursor set on
1845 * the surface, and it is using the cursor for its parent surface.
1846 *
1847 * Use [method@Gdk.Surface.set_cursor] to unset the cursor of the surface.
1848 *
1849 * Returns: (nullable) (transfer none): a `GdkCursor`
1850 */
1851GdkCursor *
1852gdk_surface_get_cursor (GdkSurface *surface)
1853{
1854 g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL);
1855
1856 return surface->cursor;
1857}
1858
1859/**
1860 * gdk_surface_set_cursor: (attributes org.gtk.Method.set_property=cursor)
1861 * @surface: a `GdkSurface`
1862 * @cursor: (nullable): a `GdkCursor`
1863 *
1864 * Sets the default mouse pointer for a `GdkSurface`.
1865 *
1866 * Passing %NULL for the @cursor argument means that @surface will use
1867 * the cursor of its parent surface. Most surfaces should use this default.
1868 * Note that @cursor must be for the same display as @surface.
1869 *
1870 * Use [ctor@Gdk.Cursor.new_from_name] or [ctor@Gdk.Cursor.new_from_texture]
1871 * to create the cursor. To make the cursor invisible, use %GDK_BLANK_CURSOR.
1872 */
1873void
1874gdk_surface_set_cursor (GdkSurface *surface,
1875 GdkCursor *cursor)
1876{
1877 g_return_if_fail (GDK_IS_SURFACE (surface));
1878
1879 if (surface->cursor)
1880 {
1881 g_object_unref (object: surface->cursor);
1882 surface->cursor = NULL;
1883 }
1884
1885 if (!GDK_SURFACE_DESTROYED (surface))
1886 {
1887 GdkDevice *device;
1888 GList *seats, *s;
1889
1890 if (cursor)
1891 surface->cursor = g_object_ref (cursor);
1892
1893 seats = gdk_display_list_seats (display: surface->display);
1894
1895 for (s = seats; s; s = s->next)
1896 {
1897 GList *devices, *d;
1898
1899 device = gdk_seat_get_pointer (seat: s->data);
1900 gdk_surface_set_cursor_internal (surface, device, cursor: surface->cursor);
1901
1902 devices = gdk_seat_get_devices (seat: s->data, capabilities: GDK_SEAT_CAPABILITY_TABLET_STYLUS);
1903 for (d = devices; d; d = d->next)
1904 {
1905 device = d->data;
1906 gdk_surface_set_cursor_internal (surface, device, cursor: surface->cursor);
1907 }
1908 g_list_free (list: devices);
1909 }
1910
1911 g_list_free (list: seats);
1912 g_object_notify_by_pspec (G_OBJECT (surface), pspec: properties[PROP_CURSOR]);
1913 }
1914}
1915
1916/**
1917 * gdk_surface_get_device_cursor:
1918 * @surface: a `GdkSurface`
1919 * @device: a pointer `GdkDevice`
1920 *
1921 * Retrieves a `GdkCursor` pointer for the @device currently set on the
1922 * specified `GdkSurface`.
1923 *
1924 * If the return value is %NULL then there is no custom cursor set on the
1925 * specified surface, and it is using the cursor for its parent surface.
1926 *
1927 * Use [method@Gdk.Surface.set_cursor] to unset the cursor of the surface.
1928 *
1929 * Returns: (nullable) (transfer none): a `GdkCursor`
1930 */
1931GdkCursor *
1932gdk_surface_get_device_cursor (GdkSurface *surface,
1933 GdkDevice *device)
1934{
1935 g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL);
1936 g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
1937 g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, NULL);
1938
1939 return g_hash_table_lookup (hash_table: surface->device_cursor, key: device);
1940}
1941
1942/**
1943 * gdk_surface_set_device_cursor:
1944 * @surface: a `GdkSurface`
1945 * @device: a pointer `GdkDevice`
1946 * @cursor: a `GdkCursor`
1947 *
1948 * Sets a specific `GdkCursor` for a given device when it gets inside @surface.
1949 *
1950 * Passing %NULL for the @cursor argument means that @surface will use the
1951 * cursor of its parent surface. Most surfaces should use this default.
1952 *
1953 * Use [ctor@Gdk.Cursor.new_from_name] or [ctor@Gdk.Cursor.new_from_texture]
1954 * to create the cursor. To make the cursor invisible, use %GDK_BLANK_CURSOR.
1955 */
1956void
1957gdk_surface_set_device_cursor (GdkSurface *surface,
1958 GdkDevice *device,
1959 GdkCursor *cursor)
1960{
1961 g_return_if_fail (GDK_IS_SURFACE (surface));
1962 g_return_if_fail (GDK_IS_DEVICE (device));
1963 g_return_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD);
1964
1965 if (!cursor)
1966 g_hash_table_remove (hash_table: surface->device_cursor, key: device);
1967 else
1968 g_hash_table_replace (hash_table: surface->device_cursor, key: device, g_object_ref (cursor));
1969
1970 gdk_surface_set_cursor_internal (surface, device, cursor);
1971}
1972
1973/*
1974 * gdk_surface_get_geometry:
1975 * @surface: a `GdkSurface`
1976 * @x: (out) (optional): return location for X coordinate of surface (relative to its parent)
1977 * @y: (out) (optional): return location for Y coordinate of surface (relative to its parent)
1978 * @width: (out) (optional): return location for width of surface
1979 * @height: (out) (optional): return location for height of surface
1980 *
1981 * Get the geometry of the surface.
1982 *
1983 * The X and Y coordinates returned are relative to the parent surface
1984 * of @surface, which for toplevels usually means relative to the
1985 * surface decorations (titlebar, etc.) rather than relative to the
1986 * root window (screen-size background window).
1987 *
1988 * On the X11 platform, the geometry is obtained from the X server, so
1989 * reflects the latest position of @surface; this may be out-of-sync with
1990 * the position of @surface delivered in the most-recently-processed
1991 * `GdkEventConfigure`. [method@Gdk.Surface.get_position] in contrast gets
1992 * the position from the most recent configure event.
1993 *
1994 * Any of the return location arguments to this function may be %NULL,
1995 * if you aren’t interested in getting the value of that field.
1996 *
1997 * Note: If @surface is not a toplevel, it is much better to call
1998 * [method@Gdk.Surface.get_position], [method@Gdk.Surface.get_width] and
1999 * [method@Gdk.Surface.get_height] instead, because it avoids the roundtrip
2000 * to the X server and because these functions support the full 32-bit
2001 * coordinate space, whereas gdk_surface_get_geometry() is restricted to
2002 * the 16-bit coordinates of X11.
2003 */
2004void
2005gdk_surface_get_geometry (GdkSurface *surface,
2006 int *x,
2007 int *y,
2008 int *width,
2009 int *height)
2010{
2011 g_return_if_fail (GDK_IS_SURFACE (surface));
2012
2013 if (GDK_SURFACE_DESTROYED (surface))
2014 return;
2015
2016 GDK_SURFACE_GET_CLASS (surface)->get_geometry (surface, x, y, width, height);
2017}
2018
2019/**
2020 * gdk_surface_get_width: (attributes org.gtk.Method.get_property=width)
2021 * @surface: a `GdkSurface`
2022 *
2023 * Returns the width of the given @surface.
2024 *
2025 * Surface size is reported in ”application pixels”, not
2026 * ”device pixels” (see [method@Gdk.Surface.get_scale_factor]).
2027 *
2028 * Returns: The width of @surface
2029 */
2030int
2031gdk_surface_get_width (GdkSurface *surface)
2032{
2033 g_return_val_if_fail (GDK_IS_SURFACE (surface), 0);
2034
2035 return surface->width;
2036}
2037
2038/**
2039 * gdk_surface_get_height: (attributes org.gtk.Method.get_property=height)
2040 * @surface: a `GdkSurface`
2041 *
2042 * Returns the height of the given @surface.
2043 *
2044 * Surface size is reported in ”application pixels”, not
2045 * ”device pixels” (see [method@Gdk.Surface.get_scale_factor]).
2046 *
2047 * Returns: The height of @surface
2048 */
2049int
2050gdk_surface_get_height (GdkSurface *surface)
2051{
2052 g_return_val_if_fail (GDK_IS_SURFACE (surface), 0);
2053
2054 return surface->height;
2055}
2056
2057/*
2058 * gdk_surface_get_origin:
2059 * @surface: a `GdkSurface`
2060 * @x: (out): return location for X coordinate
2061 * @y: (out): return location for Y coordinate
2062 *
2063 * Obtains the position of a surface in root window coordinates.
2064 *
2065 * (Compare with gdk_surface_get_position() and
2066 * gdk_surface_get_geometry() which return the position
2067 * of a surface relative to its parent surface.)
2068 */
2069void
2070gdk_surface_get_origin (GdkSurface *surface,
2071 int *x,
2072 int *y)
2073{
2074 g_return_if_fail (GDK_IS_SURFACE (surface));
2075
2076 gdk_surface_get_root_coords (surface, x: 0, y: 0, root_x: x, root_y: y);
2077}
2078
2079/*
2080 * gdk_surface_get_root_coords:
2081 * @surface: a `GdkSurface`
2082 * @x: X coordinate in surface
2083 * @y: Y coordinate in surface
2084 * @root_x: (out): return location for X coordinate
2085 * @root_y: (out): return location for Y coordinate
2086 *
2087 * Obtains the position of a surface position in root
2088 * window coordinates. This is similar to
2089 * gdk_surface_get_origin() but allows you to pass
2090 * in any position in the surface, not just the origin.
2091 */
2092void
2093gdk_surface_get_root_coords (GdkSurface *surface,
2094 int x,
2095 int y,
2096 int *root_x,
2097 int *root_y)
2098{
2099 g_return_if_fail (GDK_IS_SURFACE (surface));
2100
2101 if (GDK_SURFACE_DESTROYED (surface))
2102 {
2103 *root_x = 0;
2104 *root_y = 0;
2105 return;
2106 }
2107
2108 GDK_SURFACE_GET_CLASS (surface)->get_root_coords (surface, x, y, root_x, root_y);
2109}
2110
2111/**
2112 * gdk_surface_set_input_region:
2113 * @surface: a `GdkSurface`
2114 * @region: region of surface to be reactive
2115 *
2116 * Apply the region to the surface for the purpose of event
2117 * handling.
2118 *
2119 * Mouse events which happen while the pointer position corresponds
2120 * to an unset bit in the mask will be passed on the surface below
2121 * @surface.
2122 *
2123 * An input region is typically used with RGBA surfaces. The alpha
2124 * channel of the surface defines which pixels are invisible and
2125 * allows for nicely antialiased borders, and the input region
2126 * controls where the surface is “clickable”.
2127 *
2128 * Use [method@Gdk.Display.supports_input_shapes] to find out if
2129 * a particular backend supports input regions.
2130 */
2131void
2132gdk_surface_set_input_region (GdkSurface *surface,
2133 cairo_region_t *region)
2134{
2135 g_return_if_fail (GDK_IS_SURFACE (surface));
2136
2137 if (GDK_SURFACE_DESTROYED (surface))
2138 return;
2139
2140 if (cairo_region_equal (a: surface->input_region, b: region))
2141 return;
2142
2143 if (surface->input_region)
2144 cairo_region_destroy (region: surface->input_region);
2145
2146 if (region)
2147 surface->input_region = cairo_region_copy (original: region);
2148 else
2149 surface->input_region = NULL;
2150
2151 GDK_SURFACE_GET_CLASS (surface)->set_input_region (surface, surface->input_region);
2152}
2153
2154static void
2155update_cursor (GdkDisplay *display,
2156 GdkDevice *device)
2157{
2158 GdkSurface *cursor_surface;
2159 GdkSurface *pointer_surface;
2160 GdkPointerSurfaceInfo *pointer_info;
2161 GdkDeviceGrabInfo *grab;
2162 GdkCursor *cursor;
2163
2164 g_assert (display);
2165 g_assert (device);
2166
2167 pointer_info = _gdk_display_get_pointer_info (display, device);
2168 pointer_surface = pointer_info->surface_under_pointer;
2169
2170 /* We ignore the serials here and just pick the last grab
2171 we've sent, as that would shortly be used anyway. */
2172 grab = _gdk_display_get_last_device_grab (display, device);
2173 if (grab != NULL)
2174 {
2175 /* use the cursor from the grab surface */
2176 cursor_surface = grab->surface;
2177 }
2178 else
2179 {
2180 /* otherwise use the cursor from the pointer surface */
2181 cursor_surface = pointer_surface;
2182 }
2183
2184 cursor = g_hash_table_lookup (hash_table: cursor_surface->device_cursor, key: device);
2185
2186 if (!cursor)
2187 cursor = cursor_surface->cursor;
2188
2189 GDK_DEVICE_GET_CLASS (device)->set_surface_cursor (device, pointer_surface, cursor);
2190}
2191
2192/**
2193 * gdk_surface_beep:
2194 * @surface: a toplevel `GdkSurface`
2195 *
2196 * Emits a short beep associated to @surface.
2197 *
2198 * If the display of @surface does not support per-surface beeps,
2199 * emits a short beep on the display just as [method@Gdk.Display.beep].
2200 */
2201void
2202gdk_surface_beep (GdkSurface *surface)
2203{
2204 g_return_if_fail (GDK_IS_SURFACE (surface));
2205
2206 if (GDK_SURFACE_DESTROYED (surface))
2207 return;
2208
2209 if (GDK_SURFACE_GET_CLASS (surface)->beep (surface))
2210 return;
2211
2212 gdk_display_beep (display: surface->display);
2213}
2214
2215void
2216_gdk_display_set_surface_under_pointer (GdkDisplay *display,
2217 GdkDevice *device,
2218 GdkSurface *surface)
2219{
2220 GdkPointerSurfaceInfo *device_info;
2221
2222 device_info = _gdk_display_get_pointer_info (display, device);
2223
2224 if (device_info->surface_under_pointer)
2225 g_object_unref (object: device_info->surface_under_pointer);
2226 device_info->surface_under_pointer = surface;
2227
2228 if (surface)
2229 {
2230 g_object_ref (surface);
2231 update_cursor (display, device);
2232 }
2233}
2234
2235#define GDK_ANY_BUTTON_MASK (GDK_BUTTON1_MASK | \
2236 GDK_BUTTON2_MASK | \
2237 GDK_BUTTON3_MASK | \
2238 GDK_BUTTON4_MASK | \
2239 GDK_BUTTON5_MASK)
2240
2241void
2242_gdk_windowing_got_event (GdkDisplay *display,
2243 GList *event_link,
2244 GdkEvent *event,
2245 gulong serial)
2246{
2247 GdkSurface *event_surface = NULL;
2248 gboolean unlink_event = FALSE;
2249 GdkDeviceGrabInfo *button_release_grab;
2250 GdkPointerSurfaceInfo *pointer_info = NULL;
2251 GdkDevice *device;
2252 GdkEventType type;
2253 guint32 timestamp;
2254
2255 _gdk_display_update_last_event (display, event);
2256
2257 device = gdk_event_get_device (event);
2258 timestamp = gdk_event_get_time (event);
2259
2260 if (device)
2261 {
2262 if (timestamp != GDK_CURRENT_TIME)
2263 gdk_device_set_timestamp (device, timestamp);
2264
2265 if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD &&
2266 gdk_device_get_source (device) != GDK_SOURCE_TABLET_PAD)
2267 {
2268 pointer_info = _gdk_display_get_pointer_info (display, device);
2269 pointer_info->last_physical_device = device;
2270 }
2271
2272 _gdk_display_device_grab_update (display, device, current_serial: serial);
2273 }
2274
2275 event_surface = gdk_event_get_surface (event);
2276 if (!event_surface)
2277 goto out;
2278
2279 type = gdk_event_get_event_type (event);
2280 if (type == GDK_ENTER_NOTIFY)
2281 _gdk_display_set_surface_under_pointer (display, device, surface: event_surface);
2282 else if (type == GDK_LEAVE_NOTIFY)
2283 _gdk_display_set_surface_under_pointer (display, device, NULL);
2284
2285 if (type == GDK_BUTTON_PRESS)
2286 {
2287 GdkSurface *grab_surface;
2288 gboolean owner_events;
2289
2290 if (!gdk_device_grab_info (display, device, grab_surface: &grab_surface, owner_events: &owner_events))
2291 {
2292 _gdk_display_add_device_grab (display,
2293 device,
2294 surface: event_surface,
2295 FALSE,
2296 event_mask: GDK_ALL_EVENTS_MASK,
2297 serial_start: serial,
2298 time: gdk_event_get_time (event),
2299 TRUE);
2300 _gdk_display_device_grab_update (display, device, current_serial: serial);
2301 }
2302 }
2303 else if (type == GDK_BUTTON_RELEASE ||
2304 type == GDK_TOUCH_CANCEL ||
2305 type == GDK_TOUCH_END)
2306 {
2307 if (type == GDK_BUTTON_RELEASE ||
2308 gdk_event_get_pointer_emulated (event))
2309 {
2310 button_release_grab =
2311 _gdk_display_has_device_grab (display, device, serial);
2312
2313 if (button_release_grab &&
2314 button_release_grab->implicit &&
2315 (gdk_event_get_modifier_state (event) & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (gdk_button_event_get_button (event) - 1))) == 0)
2316 {
2317 button_release_grab->serial_end = serial;
2318 button_release_grab->implicit_ungrab = FALSE;
2319 _gdk_display_device_grab_update (display, device, current_serial: serial);
2320 }
2321 }
2322 }
2323
2324 out:
2325 if (unlink_event)
2326 {
2327 _gdk_event_queue_remove_link (display, node: event_link);
2328 g_list_free_1 (list: event_link);
2329 gdk_event_unref (event);
2330 }
2331
2332 /* This does two things - first it sees if there are motions at the
2333 * end of the queue that can be compressed. Second, if there is just
2334 * a single motion that won't be dispatched because it is a compression
2335 * candidate it queues up flushing the event queue.
2336 */
2337 _gdk_event_queue_handle_motion_compression (display);
2338 gdk_event_queue_handle_scroll_compression (display);
2339
2340 if (event_surface)
2341 {
2342 GdkFrameClock *clock = gdk_surface_get_frame_clock (surface: event_surface);
2343
2344 if (clock) /* might be NULL if surface was destroyed */
2345 gdk_frame_clock_request_phase (frame_clock: clock, phase: GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS);
2346 }
2347}
2348
2349/**
2350 * gdk_surface_create_similar_surface:
2351 * @surface: surface to make new surface similar to
2352 * @content: the content for the new surface
2353 * @width: width of the new surface
2354 * @height: height of the new surface
2355 *
2356 * Create a new Cairo surface that is as compatible as possible with the
2357 * given @surface.
2358 *
2359 * For example the new surface will have the same fallback resolution
2360 * and font options as @surface. Generally, the new surface will also
2361 * use the same backend as @surface, unless that is not possible for
2362 * some reason. The type of the returned surface may be examined with
2363 * cairo_surface_get_type().
2364 *
2365 * Initially the surface contents are all 0 (transparent if contents
2366 * have transparency, black otherwise.)
2367 *
2368 * This function always returns a valid pointer, but it will return a
2369 * pointer to a “nil” surface if @other is already in an error state
2370 * or any other error occurs.
2371 *
2372 * Returns: a pointer to the newly allocated surface. The caller
2373 * owns the surface and should call cairo_surface_destroy() when done
2374 * with it.
2375 */
2376cairo_surface_t *
2377gdk_surface_create_similar_surface (GdkSurface * surface,
2378 cairo_content_t content,
2379 int width,
2380 int height)
2381{
2382 cairo_surface_t *similar_surface;
2383 int scale;
2384
2385 g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL);
2386
2387 scale = gdk_surface_get_scale_factor (surface);
2388
2389 similar_surface = cairo_image_surface_create (format: content == CAIRO_CONTENT_COLOR ? CAIRO_FORMAT_RGB24 :
2390 content == CAIRO_CONTENT_ALPHA ? CAIRO_FORMAT_A8 : CAIRO_FORMAT_ARGB32,
2391 width: width * scale, height: height * scale);
2392 cairo_surface_set_device_scale (surface: similar_surface, x_scale: scale, y_scale: scale);
2393
2394 return similar_surface;
2395}
2396
2397/* This function is called when the XWindow is really gone.
2398 */
2399void
2400gdk_surface_destroy_notify (GdkSurface *surface)
2401{
2402 GDK_SURFACE_GET_CLASS (surface)->destroy_notify (surface);
2403}
2404
2405/**
2406 * gdk_drag_begin:
2407 * @surface: the source surface for this drag
2408 * @device: the device that controls this drag
2409 * @content: (transfer none): the offered content
2410 * @actions: the actions supported by this drag
2411 * @dx: the x offset to @device's position where the drag nominally started
2412 * @dy: the y offset to @device's position where the drag nominally started
2413 *
2414 * Starts a drag and creates a new drag context for it.
2415 *
2416 * This function is called by the drag source. After this call, you
2417 * probably want to set up the drag icon using the surface returned
2418 * by [method@Gdk.Drag.get_drag_surface].
2419 *
2420 * This function returns a reference to the [class@Gdk.Drag] object,
2421 * but GTK keeps its own reference as well, as long as the DND operation
2422 * is going on.
2423 *
2424 * Note: if @actions include %GDK_ACTION_MOVE, you need to listen for
2425 * the [signal@Gdk.Drag::dnd-finished] signal and delete the data at
2426 * the source if [method@Gdk.Drag.get_selected_action] returns
2427 * %GDK_ACTION_MOVE.
2428 *
2429 * Returns: (transfer full) (nullable): a newly created `GdkDrag`
2430 */
2431GdkDrag *
2432gdk_drag_begin (GdkSurface *surface,
2433 GdkDevice *device,
2434 GdkContentProvider *content,
2435 GdkDragAction actions,
2436 double dx,
2437 double dy)
2438{
2439 g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL);
2440 g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
2441 g_return_val_if_fail (surface->display == gdk_device_get_display (device), NULL);
2442 g_return_val_if_fail (GDK_IS_CONTENT_PROVIDER (content), NULL);
2443
2444 return GDK_SURFACE_GET_CLASS (surface)->drag_begin (surface, device, content, actions, dx, dy);
2445}
2446
2447static void
2448gdk_surface_ensure_motion (GdkSurface *surface)
2449{
2450 GdkDisplay *display;
2451 GdkSeat *seat;
2452 GdkDevice *device;
2453 GdkEvent *event;
2454 double x, y;
2455 GdkModifierType state;
2456 GdkSurface *grab_surface;
2457
2458 if (!surface->request_motion)
2459 return;
2460
2461 surface->request_motion = FALSE;
2462
2463 display = gdk_surface_get_display (surface);
2464 seat = gdk_display_get_default_seat (display);
2465 if (!seat)
2466 return;
2467
2468 device = gdk_seat_get_pointer (seat);
2469
2470 if (!gdk_surface_get_device_position (surface, device, x: &x, y: &y, mask: &state))
2471 return;
2472
2473 if (gdk_device_grab_info (display, device, grab_surface: &grab_surface, NULL))
2474 {
2475 if (grab_surface != surface)
2476 return;
2477 }
2478
2479 event = gdk_motion_event_new (surface,
2480 device,
2481 NULL,
2482 GDK_CURRENT_TIME,
2483 state,
2484 x, y,
2485 NULL);
2486
2487 gdk_surface_handle_event (event);
2488 gdk_event_unref (event);
2489}
2490
2491static void
2492gdk_surface_flush_events (GdkFrameClock *clock,
2493 void *data)
2494{
2495 GdkSurface *surface = GDK_SURFACE (data);
2496
2497 _gdk_event_queue_flush (display: surface->display);
2498 gdk_surface_ensure_motion (surface);
2499 _gdk_display_pause_events (display: surface->display);
2500
2501 gdk_frame_clock_request_phase (frame_clock: clock, phase: GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS);
2502 surface->frame_clock_events_paused = TRUE;
2503}
2504
2505static void
2506gdk_surface_resume_events (GdkFrameClock *clock,
2507 void *data)
2508{
2509 GdkSurface *surface = GDK_SURFACE (data);
2510
2511 if (surface->frame_clock_events_paused)
2512 {
2513 _gdk_display_unpause_events (display: surface->display);
2514 surface->frame_clock_events_paused = FALSE;
2515 }
2516}
2517
2518static void
2519gdk_surface_set_frame_clock (GdkSurface *surface,
2520 GdkFrameClock *clock)
2521{
2522 g_return_if_fail (GDK_IS_SURFACE (surface));
2523 g_return_if_fail (clock == NULL || GDK_IS_FRAME_CLOCK (clock));
2524
2525 if (clock == surface->frame_clock)
2526 return;
2527
2528 if (clock)
2529 {
2530 g_object_ref (clock);
2531
2532 g_signal_connect (G_OBJECT (clock),
2533 "flush-events",
2534 G_CALLBACK (gdk_surface_flush_events),
2535 surface);
2536 g_signal_connect (G_OBJECT (clock),
2537 "resume-events",
2538 G_CALLBACK (gdk_surface_resume_events),
2539 surface);
2540 g_signal_connect (G_OBJECT (clock),
2541 "layout",
2542 G_CALLBACK (gdk_surface_layout_on_clock),
2543 surface);
2544 g_signal_connect (G_OBJECT (clock),
2545 "paint",
2546 G_CALLBACK (gdk_surface_paint_on_clock),
2547 surface);
2548
2549 if (surface->update_freeze_count == 0)
2550 _gdk_frame_clock_inhibit_freeze (clock);
2551 }
2552
2553 if (surface->frame_clock)
2554 {
2555 if (surface->frame_clock_events_paused)
2556 gdk_surface_resume_events (clock: surface->frame_clock, G_OBJECT (surface));
2557
2558 g_signal_handlers_disconnect_by_func (G_OBJECT (surface->frame_clock),
2559 G_CALLBACK (gdk_surface_flush_events),
2560 surface);
2561 g_signal_handlers_disconnect_by_func (G_OBJECT (surface->frame_clock),
2562 G_CALLBACK (gdk_surface_resume_events),
2563 surface);
2564 g_signal_handlers_disconnect_by_func (G_OBJECT (surface->frame_clock),
2565 G_CALLBACK (gdk_surface_layout_on_clock),
2566 surface);
2567 g_signal_handlers_disconnect_by_func (G_OBJECT (surface->frame_clock),
2568 G_CALLBACK (gdk_surface_paint_on_clock),
2569 surface);
2570
2571 if (surface->update_freeze_count == 0)
2572 _gdk_frame_clock_uninhibit_freeze (clock: surface->frame_clock);
2573
2574 g_object_unref (object: surface->frame_clock);
2575 }
2576
2577 surface->frame_clock = clock;
2578}
2579
2580/**
2581 * gdk_surface_get_frame_clock: (attributes org.gtk.Method.get_property=frame-clock)
2582 * @surface: surface to get frame clock for
2583 *
2584 * Gets the frame clock for the surface.
2585 *
2586 * The frame clock for a surface never changes unless the surface is
2587 * reparented to a new toplevel surface.
2588 *
2589 * Returns: (transfer none): the frame clock
2590 */
2591GdkFrameClock *
2592gdk_surface_get_frame_clock (GdkSurface *surface)
2593{
2594 g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL);
2595
2596 return surface->frame_clock;
2597}
2598
2599/**
2600 * gdk_surface_get_scale_factor: (attributes org.gtk.Method.get_property=scale-factor)
2601 * @surface: surface to get scale factor for
2602 *
2603 * Returns the internal scale factor that maps from surface coordinates
2604 * to the actual device pixels.
2605 *
2606 * On traditional systems this is 1, but on very high density outputs
2607 * this can be a higher value (often 2). A higher value means that drawing
2608 * is automatically scaled up to a higher resolution, so any code doing
2609 * drawing will automatically look nicer. However, if you are supplying
2610 * pixel-based data the scale value can be used to determine whether to
2611 * use a pixel resource with higher resolution data.
2612 *
2613 * The scale of a surface may change during runtime.
2614 *
2615 * Returns: the scale factor
2616 */
2617int
2618gdk_surface_get_scale_factor (GdkSurface *surface)
2619{
2620 GdkSurfaceClass *class;
2621
2622 g_return_val_if_fail (GDK_IS_SURFACE (surface), 1);
2623
2624 if (GDK_SURFACE_DESTROYED (surface))
2625 return 1;
2626
2627 class = GDK_SURFACE_GET_CLASS (surface);
2628 if (class->get_scale_factor)
2629 return class->get_scale_factor (surface);
2630
2631 return 1;
2632}
2633
2634/**
2635 * gdk_surface_set_opaque_region:
2636 * @surface: a top-level `GdkSurface`
2637 * @region: (nullable): a region, or %NULL to make the entire
2638 * surface opaque
2639 *
2640 * Marks a region of the `GdkSurface` as opaque.
2641 *
2642 * For optimisation purposes, compositing window managers may
2643 * like to not draw obscured regions of surfaces, or turn off blending
2644 * during for these regions. With RGB windows with no transparency,
2645 * this is just the shape of the window, but with ARGB32 windows, the
2646 * compositor does not know what regions of the window are transparent
2647 * or not.
2648 *
2649 * This function only works for toplevel surfaces.
2650 *
2651 * GTK will update this property automatically if the @surface background
2652 * is opaque, as we know where the opaque regions are. If your surface
2653 * background is not opaque, please update this property in your
2654 * [vfunc@Gtk.Widget.css_changed] handler.
2655 */
2656void
2657gdk_surface_set_opaque_region (GdkSurface *surface,
2658 cairo_region_t *region)
2659{
2660 GdkSurfaceClass *class;
2661
2662 g_return_if_fail (GDK_IS_SURFACE (surface));
2663 g_return_if_fail (!GDK_SURFACE_DESTROYED (surface));
2664
2665 if (cairo_region_equal (a: surface->opaque_region, b: region))
2666 return;
2667
2668 g_clear_pointer (&surface->opaque_region, cairo_region_destroy);
2669
2670 if (region != NULL)
2671 surface->opaque_region = cairo_region_reference (region);
2672
2673 class = GDK_SURFACE_GET_CLASS (surface);
2674 if (class->set_opaque_region)
2675 class->set_opaque_region (surface, region);
2676}
2677
2678void
2679gdk_surface_set_state (GdkSurface *surface,
2680 GdkToplevelState new_state)
2681{
2682 gboolean was_sticky, sticky;
2683 g_return_if_fail (GDK_IS_SURFACE (surface));
2684
2685 if (new_state == surface->state)
2686 return; /* No actual work to do, nothing changed. */
2687
2688 /* Actually update the field in GdkSurface, this is sort of an odd
2689 * place to do it, but seems like the safest since it ensures we expose no
2690 * inconsistent state to the user.
2691 */
2692
2693 was_sticky = GDK_SURFACE_IS_STICKY (surface);
2694
2695 surface->state = new_state;
2696
2697 sticky = GDK_SURFACE_IS_STICKY (surface);
2698
2699 if (GDK_IS_TOPLEVEL (ptr: surface))
2700 g_object_notify (G_OBJECT (surface), property_name: "state");
2701
2702 if (was_sticky != sticky)
2703 g_object_notify (G_OBJECT (surface), property_name: "sticky");
2704}
2705
2706void
2707gdk_synthesize_surface_state (GdkSurface *surface,
2708 GdkToplevelState unset_flags,
2709 GdkToplevelState set_flags)
2710{
2711 gdk_surface_set_state (surface, new_state: (surface->state | set_flags) & ~unset_flags);
2712}
2713
2714void
2715gdk_surface_queue_state_change (GdkSurface *surface,
2716 GdkToplevelState unset_flags,
2717 GdkToplevelState set_flags)
2718{
2719 surface->pending_unset_flags |= unset_flags;
2720 surface->pending_set_flags &= ~unset_flags;
2721
2722 surface->pending_set_flags |= set_flags;
2723 surface->pending_unset_flags &= ~set_flags;
2724}
2725
2726void
2727gdk_surface_apply_state_change (GdkSurface *surface)
2728{
2729 if (!surface->pending_unset_flags && !surface->pending_set_flags)
2730 return;
2731
2732 gdk_synthesize_surface_state (surface,
2733 unset_flags: surface->pending_unset_flags,
2734 set_flags: surface->pending_set_flags);
2735 surface->pending_unset_flags = 0;
2736 surface->pending_set_flags = 0;
2737}
2738
2739static gboolean
2740set_is_mapped_idle (gpointer user_data)
2741{
2742 GdkSurface *surface = GDK_SURFACE (user_data);
2743
2744 surface->set_is_mapped_source_id = 0;
2745
2746 g_return_val_if_fail (surface->pending_is_mapped != surface->is_mapped,
2747 G_SOURCE_REMOVE);
2748
2749 surface->is_mapped = surface->pending_is_mapped;
2750 if (surface->is_mapped)
2751 gdk_surface_invalidate_rect (surface, NULL);
2752
2753 g_object_notify (G_OBJECT (surface), property_name: "mapped");
2754
2755 return G_SOURCE_REMOVE;
2756}
2757
2758void
2759gdk_surface_set_is_mapped (GdkSurface *surface,
2760 gboolean is_mapped)
2761{
2762 gboolean was_mapped;
2763
2764 if (surface->pending_is_mapped != surface->is_mapped)
2765 g_clear_handle_id (&surface->set_is_mapped_source_id, g_source_remove);
2766
2767 surface->pending_is_mapped = is_mapped;
2768
2769 was_mapped = surface->is_mapped;
2770 surface->is_mapped = is_mapped;
2771 if (surface->is_mapped)
2772 gdk_surface_invalidate_rect (surface, NULL);
2773
2774 if (was_mapped != is_mapped)
2775 g_object_notify (G_OBJECT (surface), property_name: "mapped");
2776}
2777
2778static void
2779gdk_surface_queue_set_is_mapped (GdkSurface *surface,
2780 gboolean is_mapped)
2781{
2782 if (surface->pending_is_mapped == is_mapped)
2783 return;
2784
2785 surface->pending_is_mapped = is_mapped;
2786
2787 if (surface->is_mapped == surface->pending_is_mapped)
2788 {
2789 g_clear_handle_id (&surface->set_is_mapped_source_id, g_source_remove);
2790 }
2791 else
2792 {
2793 g_return_if_fail (!surface->set_is_mapped_source_id);
2794
2795 surface->set_is_mapped_source_id =
2796 g_idle_add_full (G_PRIORITY_HIGH - 10,
2797 function: set_is_mapped_idle,
2798 data: surface, NULL);
2799 }
2800}
2801
2802static gboolean
2803check_autohide (GdkEvent *event)
2804{
2805 GdkDisplay *display;
2806 GdkDevice *device;
2807 GdkSurface *grab_surface;
2808
2809 switch ((guint) gdk_event_get_event_type (event))
2810 {
2811 case GDK_BUTTON_PRESS:
2812#if 0
2813 // FIXME: we need to ignore the release that is paired
2814 // with the press starting the grab - due to implicit
2815 // grabs, it will be delivered to the same place as the
2816 // press, and will cause the auto dismissal to be triggered.
2817 case GDK_BUTTON_RELEASE:
2818#endif
2819 case GDK_TOUCH_BEGIN:
2820 case GDK_TOUCH_END:
2821 case GDK_TOUCH_CANCEL:
2822 case GDK_TOUCHPAD_SWIPE:
2823 case GDK_TOUCHPAD_PINCH:
2824 display = gdk_event_get_display (event);
2825 device = gdk_event_get_device (event);
2826 if (gdk_device_grab_info (display, device, grab_surface: &grab_surface, NULL))
2827 {
2828 GdkSurface *event_surface;
2829
2830 event_surface = gdk_event_get_surface (event);
2831
2832 if (grab_surface != event_surface &&
2833 grab_surface != event_surface->parent &&
2834 grab_surface->autohide)
2835 {
2836 GdkSurface *surface = grab_surface;
2837
2838 do
2839 {
2840 gdk_surface_hide (surface);
2841 surface = surface->parent;
2842 }
2843 while (surface->autohide && surface != event_surface);
2844
2845 return TRUE;
2846 }
2847 }
2848 break;
2849 default:;
2850 }
2851
2852 return FALSE;
2853}
2854
2855static inline void
2856add_event_mark (GdkEvent *event,
2857 gint64 time,
2858 gint64 end_time)
2859{
2860#ifdef HAVE_SYSPROF
2861 char *message = NULL;
2862 const char *kind;
2863 GEnumClass *class;
2864 GEnumValue *value;
2865 GdkEventType event_type;
2866
2867 event_type = gdk_event_get_event_type (event);
2868 class = g_type_class_ref (GDK_TYPE_EVENT_TYPE);
2869 value = g_enum_get_value (class, event_type);
2870 g_type_class_unref (class);
2871 kind = value ? value->value_nick : "event";
2872
2873 switch ((int) event_type)
2874 {
2875 case GDK_MOTION_NOTIFY:
2876 {
2877 double x, y;
2878 gdk_event_get_position (event, &x, &y);
2879 message = g_strdup_printf ("%s {x=%lf, y=%lf, state=0x%x}",
2880 kind,
2881 x, y,
2882 gdk_event_get_modifier_state (event));
2883 break;
2884 }
2885
2886 case GDK_BUTTON_PRESS:
2887 case GDK_BUTTON_RELEASE:
2888 {
2889 double x, y;
2890 gdk_event_get_position (event, &x, &y);
2891 message = g_strdup_printf ("%s {button=%u, x=%lf, y=%lf, state=0x%x}",
2892 kind,
2893 gdk_button_event_get_button (event),
2894 x, y,
2895 gdk_event_get_modifier_state (event));
2896 break;
2897 }
2898
2899 case GDK_KEY_PRESS:
2900 case GDK_KEY_RELEASE:
2901 {
2902 message = g_strdup_printf ("%s {keyval=%u, state=0x%x, keycode=%u layout=%u level=%u is_modifier=%u}",
2903 kind,
2904 gdk_key_event_get_keyval (event),
2905 gdk_event_get_modifier_state (event),
2906 gdk_key_event_get_keycode (event),
2907 gdk_key_event_get_layout (event),
2908 gdk_key_event_get_level (event),
2909 gdk_key_event_is_modifier (event));
2910 break;
2911 }
2912
2913 case GDK_ENTER_NOTIFY:
2914 case GDK_LEAVE_NOTIFY:
2915 case GDK_TOUCHPAD_SWIPE:
2916 case GDK_TOUCHPAD_PINCH:
2917 case GDK_SCROLL:
2918 case GDK_DRAG_ENTER:
2919 case GDK_DRAG_LEAVE:
2920 case GDK_DRAG_MOTION:
2921 case GDK_DROP_START:
2922 case GDK_TOUCH_BEGIN:
2923 case GDK_TOUCH_UPDATE:
2924 case GDK_TOUCH_END:
2925 case GDK_TOUCH_CANCEL:
2926 case GDK_PAD_BUTTON_PRESS:
2927 case GDK_PAD_BUTTON_RELEASE:
2928 case GDK_PAD_RING:
2929 case GDK_PAD_STRIP:
2930 case GDK_PAD_GROUP_MODE:
2931 case GDK_GRAB_BROKEN:
2932 case GDK_DELETE:
2933 case GDK_FOCUS_CHANGE:
2934 case GDK_PROXIMITY_IN:
2935 case GDK_PROXIMITY_OUT:
2936 case GDK_EVENT_LAST:
2937 default:
2938 break;
2939 }
2940
2941 gdk_profiler_add_mark (time, end_time - time, "event", message ? message : kind);
2942
2943 g_free (message);
2944#endif
2945}
2946
2947gboolean
2948gdk_surface_handle_event (GdkEvent *event)
2949{
2950 GdkSurface *surface = gdk_event_get_surface (event);
2951 gint64 begin_time = GDK_PROFILER_CURRENT_TIME;
2952 gboolean handled = FALSE;
2953
2954 if (check_autohide (event))
2955 return TRUE;
2956
2957
2958 if (gdk_event_get_event_type (event) == GDK_MOTION_NOTIFY)
2959 surface->request_motion = FALSE;
2960
2961 g_signal_emit (instance: surface, signal_id: signals[EVENT], detail: 0, event, &handled);
2962
2963 if (GDK_PROFILER_IS_RUNNING)
2964 add_event_mark (event, time: begin_time, GDK_PROFILER_CURRENT_TIME);
2965
2966 return handled;
2967}
2968
2969/*
2970 * gdk_surface_request_motion:
2971 * @surface: a `GdkSurface`
2972 *
2973 * Request that the next frame cycle should deliver a motion
2974 * event for @surface.
2975 *
2976 * The motion event will be delivered if the pointer is over the
2977 * surface, regardless whether the pointer has moved or not. This
2978 * is used by GTK after moving widgets around.
2979 */
2980void
2981gdk_surface_request_motion (GdkSurface *surface)
2982{
2983 surface->request_motion = TRUE;
2984}
2985
2986/**
2987 * gdk_surface_translate_coordinates:
2988 * @from: the origin surface
2989 * @to: the target surface
2990 * @x: (inout): coordinates to translate
2991 * @y: (inout): coordinates to translate
2992 *
2993 * Translates coordinates between two surfaces.
2994 *
2995 * Note that this only works if @to and @from are popups or
2996 * transient-for to the same toplevel (directly or indirectly).
2997 *
2998 * Returns: %TRUE if the coordinates were successfully translated
2999 */
3000gboolean
3001gdk_surface_translate_coordinates (GdkSurface *from,
3002 GdkSurface *to,
3003 double *x,
3004 double *y)
3005{
3006 double in_x, in_y, out_x, out_y;
3007 int x1, y1, x2, y2;
3008 GdkSurface *f, *t;
3009
3010 g_return_val_if_fail (GDK_IS_SURFACE (from), FALSE);
3011 g_return_val_if_fail (GDK_IS_SURFACE (to), FALSE);
3012 g_return_val_if_fail (x != NULL, FALSE);
3013 g_return_val_if_fail (y != NULL, FALSE);
3014
3015 in_x = *x;
3016 in_y = *y;
3017
3018 x1 = 0;
3019 y1 = 0;
3020 f = from;
3021 while (f->parent)
3022 {
3023 x1 += f->x;
3024 y1 += f->y;
3025 f = f->parent;
3026 }
3027
3028 x2 = 0;
3029 y2 = 0;
3030 t = to;
3031 while (t->parent)
3032 {
3033 x2 += t->x;
3034 y2 += t->y;
3035 t = t->parent;
3036 }
3037
3038 if (f != t)
3039 return FALSE;
3040
3041 out_x = in_x + (x1 - x2);
3042 out_y = in_y + (y1 - y2);
3043
3044 *x = out_x;
3045 *y = out_y;
3046
3047 return TRUE;
3048}
3049
3050GdkSeat *
3051gdk_surface_get_seat_from_event (GdkSurface *surface,
3052 GdkEvent *event)
3053{
3054 if (event)
3055 {
3056 GdkSeat *seat = NULL;
3057
3058 seat = gdk_event_get_seat (event);
3059
3060 if (seat)
3061 return seat;
3062 }
3063 return gdk_display_get_default_seat (display: surface->display);
3064}
3065
3066void
3067gdk_surface_enter_monitor (GdkSurface *surface,
3068 GdkMonitor *monitor)
3069{
3070 g_signal_emit (instance: surface, signal_id: signals[ENTER_MONITOR], detail: 0, monitor);
3071}
3072
3073void
3074gdk_surface_leave_monitor (GdkSurface *surface,
3075 GdkMonitor *monitor)
3076{
3077 g_signal_emit (instance: surface, signal_id: signals[LEAVE_MONITOR], detail: 0, monitor);
3078}
3079

source code of gtk/gdk/gdksurface.c