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