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 (&param_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