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 "gdksurface-x11.h"
29 
30 #include "gdksurfaceprivate.h"
31 #include "gdkpopupprivate.h"
32 #include "gdktoplevelprivate.h"
33 #include "gdkdragsurfaceprivate.h"
34 #include "gdkinternals.h"
35 #include "gdkdeviceprivate.h"
36 #include "gdkdevice-xi2-private.h"
37 #include "gdkframeclockidleprivate.h"
38 #include "gdkasync.h"
39 #include "gdkeventsource.h"
40 #include "gdkdisplay-x11.h"
41 #include "gdkglcontext-x11.h"
42 #include "gdkprivate-x11.h"
43 #include "gdktextureprivate.h"
44 #include "gdk-private.h"
45 
46 #include <graphene.h>
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <netinet/in.h>
51 #include <unistd.h>
52 
53 #include <cairo-xlib.h>
54 
55 #include "MwmUtil.h"
56 
57 #include <X11/Xlib.h>
58 #include <X11/Xutil.h>
59 #include <X11/Xatom.h>
60 
61 #include <X11/extensions/shape.h>
62 
63 #ifdef HAVE_XKB
64 #include <X11/XKBlib.h>
65 #endif
66 
67 const int _gdk_x11_event_mask_table[21] =
68 {
69   ExposureMask,
70   PointerMotionMask,
71   PointerMotionHintMask,
72   ButtonMotionMask,
73   Button1MotionMask,
74   Button2MotionMask,
75   Button3MotionMask,
76   ButtonPressMask,
77   ButtonReleaseMask,
78   KeyPressMask,
79   KeyReleaseMask,
80   EnterWindowMask,
81   LeaveWindowMask,
82   FocusChangeMask,
83   StructureNotifyMask,
84   PropertyChangeMask,
85   VisibilityChangeMask,
86   0,                    /* PROXIMITY_IN */
87   0,                    /* PROXIMTY_OUT */
88   SubstructureNotifyMask,
89   ButtonPressMask      /* SCROLL; on X mouse wheel events is treated as mouse button 4/5 */
90 };
91 
92 typedef struct {
93   GdkX11Surface parent_instance;
94 } GdkX11Toplevel;
95 
96 typedef struct {
97   GdkX11SurfaceClass parent_class;
98 } GdkX11ToplevelClass;
99 
100 const int _gdk_x11_event_mask_table_size = G_N_ELEMENTS (_gdk_x11_event_mask_table);
101 
102 /* Forward declarations */
103 static void     gdk_x11_surface_apply_fullscreen_mode (GdkSurface  *surface);
104 static gboolean gdk_surface_icon_name_set          (GdkSurface  *surface);
105 static void     set_wm_name                       (GdkDisplay  *display,
106 						   Window       xwindow,
107 						   const char *name);
108 static void     move_to_current_desktop           (GdkSurface *surface);
109 static void     gdk_x11_toplevel_state_callback   (GdkSurface *surface);
110 static gboolean gdk_x11_toplevel_event_callback   (GdkSurface *surface,
111                                                    GdkEvent   *gdk_event);
112 
113 static void     gdk_x11_surface_toplevel_resize   (GdkSurface *surface,
114                                                    int         width,
115                                                    int         height);
116 
117 static void gdk_x11_surface_set_geometry_hints (GdkSurface        *surface,
118                                                 const GdkGeometry *geometry,
119                                                 GdkSurfaceHints    geom_mask);
120 
121 /* Return whether time1 is considered later than time2 as far as xserver
122  * time is concerned.  Accounts for wraparound.
123  */
124 #define XSERVER_TIME_IS_LATER(time1, time2)                        \
125   ( (( time1 > time2 ) && ( time1 - time2 < ((guint32)-1)/2 )) ||  \
126     (( time1 < time2 ) && ( time2 - time1 > ((guint32)-1)/2 ))     \
127   )
128 
129 G_DEFINE_TYPE (GdkX11Surface, gdk_x11_surface, GDK_TYPE_SURFACE)
130 
131 GType gdk_x11_toplevel_get_type (void) G_GNUC_CONST;
132 GType gdk_x11_popup_get_type (void) G_GNUC_CONST;
133 GType gdk_x11_drag_surface_get_type (void) G_GNUC_CONST;
134 
135 #define GDK_TYPE_X11_TOPLEVEL (gdk_x11_toplevel_get_type ())
136 #define GDK_TYPE_X11_POPUP (gdk_x11_popup_get_type ())
137 #define GDK_TYPE_X11_DRAG_SURFACE (gdk_x11_drag_surface_get_type ())
138 
139 static void
gdk_x11_surface_init(GdkX11Surface * impl)140 gdk_x11_surface_init (GdkX11Surface *impl)
141 {
142   impl->surface_scale = 1;
143   impl->frame_sync_enabled = TRUE;
144   impl->surface_is_on_monitor = NULL;
145 }
146 
147 GdkToplevelX11 *
_gdk_x11_surface_get_toplevel(GdkSurface * surface)148 _gdk_x11_surface_get_toplevel (GdkSurface *surface)
149 {
150   GdkX11Surface *impl;
151 
152   g_assert (GDK_IS_SURFACE (surface));
153 
154   impl = GDK_X11_SURFACE (surface);
155 
156   if (!impl->toplevel)
157     {
158       impl->toplevel = g_new0 (GdkToplevelX11, 1);
159       impl->toplevel->have_focused = FALSE;
160       g_signal_connect (surface, "notify::state",
161                         G_CALLBACK (gdk_x11_toplevel_state_callback),
162                         NULL);
163       g_signal_connect (surface, "event",
164                         G_CALLBACK (gdk_x11_toplevel_event_callback),
165                         NULL);
166     }
167 
168   return impl->toplevel;
169 }
170 
171 /*
172  * gdk_x11_surface_update_size:
173  * @self: a `GdkX11Surface`
174  * @width: the new width of the surface
175  * @height: the new height of the surface
176  * @scale: the new scale of the surface
177  *
178  * Updates the state of the surface (in particular the drawable's
179  * cairo surface) when its size has changed.
180  *
181  * Returns: %TRUE if the surface was updated, %FALSE if no updates
182  *   where necessary
183  */
184 static gboolean
gdk_x11_surface_update_size(GdkX11Surface * self,int width,int height,int scale)185 gdk_x11_surface_update_size (GdkX11Surface *self,
186                              int            width,
187                              int            height,
188                              int            scale)
189 {
190   GdkSurface *surface = GDK_SURFACE (self);
191 
192   if (surface->width == width &&
193       surface->height == height &&
194       self->surface_scale == scale)
195     return FALSE;
196 
197   surface->width = width;
198   surface->height = height;
199   self->surface_scale = scale;
200 
201   _gdk_surface_update_size (surface);
202 
203   if (self->cairo_surface)
204     {
205       cairo_xlib_surface_set_size (self->cairo_surface,
206                                    self->unscaled_width, self->unscaled_height);
207       cairo_surface_set_device_scale (self->cairo_surface, scale, scale);
208     }
209 
210   return TRUE;
211 }
212 
213 static void
update_shadow_size(GdkSurface * surface,int shadow_left,int shadow_right,int shadow_top,int shadow_bottom)214 update_shadow_size (GdkSurface *surface,
215                     int         shadow_left,
216                     int         shadow_right,
217                     int         shadow_top,
218                     int         shadow_bottom)
219 {
220   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
221   Atom frame_extents;
222   gulong data[4];
223 
224   if (impl->shadow_left == shadow_left &&
225       impl->shadow_right == shadow_right &&
226       impl->shadow_top == shadow_top &&
227       impl->shadow_bottom == shadow_bottom)
228     return;
229 
230   impl->shadow_left = shadow_left;
231   impl->shadow_right = shadow_right;
232   impl->shadow_top = shadow_top;
233   impl->shadow_bottom = shadow_bottom;
234 
235   data[0] = shadow_left * impl->surface_scale;
236   data[1] = shadow_right * impl->surface_scale;
237   data[2] = shadow_top * impl->surface_scale;
238   data[3] = shadow_bottom * impl->surface_scale;
239 
240   frame_extents = gdk_x11_get_xatom_by_name_for_display (gdk_surface_get_display (surface),
241                                                          "_GTK_FRAME_EXTENTS");
242   XChangeProperty (GDK_SURFACE_XDISPLAY (surface),
243                    GDK_SURFACE_XID (surface),
244                    frame_extents, XA_CARDINAL,
245                    32, PropModeReplace,
246                    (guchar *) &data, 4);
247 }
248 
249 #define UPDATE_GEOMETRY TRUE
250 #define DONT_UPDATE_GEOMETRY FALSE
251 
252 static gboolean
compute_toplevel_size(GdkSurface * surface,gboolean update_geometry,int * width,int * height)253 compute_toplevel_size (GdkSurface *surface,
254                        gboolean    update_geometry,
255                        int        *width,
256                        int        *height)
257 {
258   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
259   GdkDisplay *display = gdk_surface_get_display (surface);
260   GdkMonitor *monitor;
261   GdkToplevelSize size;
262   int bounds_width, bounds_height;
263 
264   monitor = gdk_display_get_monitor_at_surface (display, surface);
265   if (monitor)
266     {
267       GdkRectangle workarea;
268 
269       gdk_x11_monitor_get_workarea (monitor, &workarea);
270       bounds_width = workarea.width;
271       bounds_height = workarea.height;
272     }
273   else
274     {
275       bounds_width = G_MAXINT;
276       bounds_height = G_MAXINT;
277     }
278 
279   gdk_toplevel_size_init (&size, bounds_width, bounds_height);
280   gdk_toplevel_notify_compute_size (GDK_TOPLEVEL (surface), &size);
281 
282   if (size.shadow.is_valid && update_geometry)
283     {
284       update_shadow_size (surface,
285                           size.shadow.left,
286                           size.shadow.right,
287                           size.shadow.top,
288                           size.shadow.bottom);
289     }
290 
291   if (update_geometry)
292     {
293       GdkGeometry geometry;
294       GdkSurfaceHints mask;
295 
296       if (!impl->toplevel_layout || gdk_toplevel_layout_get_resizable (impl->toplevel_layout))
297         {
298           geometry.min_width = size.min_width;
299           geometry.min_height = size.min_height;
300           mask = GDK_HINT_MIN_SIZE;
301         }
302       else
303         {
304           geometry.max_width = geometry.min_width = size.width;
305           geometry.max_height = geometry.min_height = size.height;
306           mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
307         }
308       gdk_x11_surface_set_geometry_hints (surface, &geometry, mask);
309     }
310 
311   if (!(surface->state & (GDK_TOPLEVEL_STATE_FULLSCREEN |
312                           GDK_TOPLEVEL_STATE_MAXIMIZED |
313                           GDK_TOPLEVEL_STATE_TILED |
314                           GDK_TOPLEVEL_STATE_TOP_TILED |
315                           GDK_TOPLEVEL_STATE_RIGHT_TILED |
316                           GDK_TOPLEVEL_STATE_BOTTOM_TILED |
317                           GDK_TOPLEVEL_STATE_LEFT_TILED |
318                           GDK_TOPLEVEL_STATE_MINIMIZED)) &&
319       (!impl->next_layout.configure_pending || surface->resize_count > 0))
320     {
321       GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (surface);
322       GdkGeometry geometry;
323       GdkSurfaceHints mask;
324 
325       geometry = toplevel->last_geometry_hints;
326       mask = toplevel->last_geometry_hints_mask;
327       gdk_surface_constrain_size (&geometry, mask,
328                                   size.width, size.height,
329                                   &size.width, &size.height);
330       if ((impl->last_computed_width != size.width ||
331            impl->last_computed_height != size.height) &&
332           (impl->next_layout.configured_width != size.width ||
333            impl->next_layout.configured_height != size.height))
334         {
335           *width = size.width;
336           *height = size.height;
337           impl->last_computed_width = size.width;
338           impl->last_computed_height = size.height;
339 
340           return TRUE;
341         }
342     }
343 
344   return FALSE;
345 }
346 
347 static gboolean
compute_size_idle(gpointer user_data)348 compute_size_idle (gpointer user_data)
349 {
350   GdkSurface *surface = user_data;
351   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
352   int width, height;
353 
354   impl->compute_size_source_id = 0;
355   if (compute_toplevel_size (surface, UPDATE_GEOMETRY, &width, &height))
356     gdk_x11_surface_toplevel_resize (surface, width, height);
357 
358   return G_SOURCE_REMOVE;
359 }
360 
361 static void
gdk_x11_surface_request_layout(GdkSurface * surface)362 gdk_x11_surface_request_layout (GdkSurface *surface)
363 {
364   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
365 
366   if (!impl->compute_size_source_id &&
367       GDK_IS_TOPLEVEL (surface))
368     {
369       impl->compute_size_source_id = g_idle_add_full (G_PRIORITY_HIGH - 10,
370                                                       compute_size_idle,
371                                                       surface,
372                                                       NULL);
373     }
374 }
375 
376 static gboolean
gdk_x11_surface_compute_size(GdkSurface * surface)377 gdk_x11_surface_compute_size (GdkSurface *surface)
378 {
379   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
380 
381   if (GDK_IS_TOPLEVEL (surface))
382     {
383       int width, height;
384 
385       if (compute_toplevel_size (surface, UPDATE_GEOMETRY, &width, &height))
386         gdk_x11_surface_toplevel_resize (surface, width, height);
387 
388       if (surface->resize_count == 0)
389         {
390           gdk_x11_surface_update_size (impl,
391                                        impl->next_layout.configured_width,
392                                        impl->next_layout.configured_height,
393                                        impl->surface_scale);
394         }
395 
396       impl->next_layout.surface_geometry_dirty = FALSE;
397       impl->next_layout.configure_pending = FALSE;
398     }
399   else
400     {
401       gdk_x11_surface_update_size (impl,
402                                    impl->next_layout.configured_width,
403                                    impl->next_layout.configured_height,
404                                    impl->surface_scale);
405 
406       impl->next_layout.surface_geometry_dirty = FALSE;
407     }
408 
409   return surface->resize_count > 0;
410 }
411 
412 gboolean
gdk_x11_surface_supports_edge_constraints(GdkSurface * surface)413 gdk_x11_surface_supports_edge_constraints (GdkSurface *surface)
414 {
415   return gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (surface),
416                                               g_intern_static_string ("_GTK_EDGE_CONSTRAINTS"));
417 }
418 
419 static void
set_sync_counter(Display * display,XSyncCounter counter,gint64 value)420 set_sync_counter(Display     *display,
421 		 XSyncCounter counter,
422                  gint64       value)
423 {
424     XSyncValue sync_value;
425 
426     XSyncIntsToValue (&sync_value,
427                       value & G_GINT64_CONSTANT(0xFFFFFFFF),
428                       value >> 32);
429     XSyncSetCounter (display, counter, sync_value);
430 }
431 
432 void
gdk_x11_surface_pre_damage(GdkSurface * surface)433 gdk_x11_surface_pre_damage (GdkSurface *surface)
434 {
435   GdkX11Surface *impl;
436 
437   impl = GDK_X11_SURFACE (surface);
438 
439   if (impl->toplevel->in_frame &&
440       impl->toplevel->current_counter_value % 2 == 0)
441     {
442       impl->toplevel->current_counter_value += 1;
443       set_sync_counter (GDK_SURFACE_XDISPLAY (surface),
444 		        impl->toplevel->extended_update_counter,
445                         impl->toplevel->current_counter_value);
446     }
447 }
448 
449 static void
on_surface_changed(void * data)450 on_surface_changed (void *data)
451 {
452   GdkSurface *surface = data;
453   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
454 
455   if (impl->tracking_damage)
456     gdk_x11_surface_pre_damage (surface);
457 }
458 
459 /* We want to know when cairo drawing causes damage to the window,
460  * so we engage in the _NET_WM_FRAME_DRAWN protocol with the
461  * window only when there actually is drawing. To do that we use
462  * a technique (hack) suggested by Uli Schlachter - if we set
463  * a dummy "mime data" on the cairo surface (this facility is
464  * used to attach JPEG data to an imager), then cairo will flush
465  * and remove the mime data before making any changes to the window.
466  */
467 
468 static void
hook_surface_changed(GdkSurface * surface)469 hook_surface_changed (GdkSurface *surface)
470 {
471   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
472 
473   if (impl->cairo_surface)
474     {
475       cairo_surface_set_mime_data (impl->cairo_surface,
476                                    "x-gdk/change-notify",
477                                    (unsigned char *)"X",
478                                    1,
479                                    on_surface_changed,
480                                    surface);
481       impl->tracking_damage = 1;
482     }
483 }
484 
485 static void
unhook_surface_changed(GdkSurface * surface)486 unhook_surface_changed (GdkSurface *surface)
487 {
488   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
489 
490   if (impl->cairo_surface)
491     {
492       impl->tracking_damage = 0;
493       cairo_surface_set_mime_data (impl->cairo_surface,
494                                    "x-gdk/change-notify",
495                                    NULL, 0,
496                                    NULL, NULL);
497     }
498 }
499 
500 static void
gdk_x11_surface_predict_presentation_time(GdkSurface * surface)501 gdk_x11_surface_predict_presentation_time (GdkSurface *surface)
502 {
503   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
504   GdkFrameClock *clock;
505   GdkFrameTimings *timings;
506   gint64 presentation_time;
507   gint64 refresh_interval;
508 
509   clock = gdk_surface_get_frame_clock (surface);
510 
511   timings = gdk_frame_clock_get_current_timings (clock);
512 
513   gdk_frame_clock_get_refresh_info (clock,
514                                     timings->frame_time,
515                                     &refresh_interval, &presentation_time);
516 
517   if (presentation_time != 0)
518     {
519       if (timings->slept_before)
520         {
521           presentation_time += refresh_interval;
522         }
523       else
524         {
525           if (presentation_time < timings->frame_time + refresh_interval / 2)
526             presentation_time += refresh_interval;
527         }
528     }
529   else
530     {
531       if (timings->slept_before)
532         presentation_time = timings->frame_time + refresh_interval + refresh_interval / 2;
533       else
534         presentation_time = timings->frame_time + refresh_interval;
535     }
536 
537   if (presentation_time < impl->toplevel->throttled_presentation_time)
538     presentation_time = impl->toplevel->throttled_presentation_time;
539 
540   timings->predicted_presentation_time = presentation_time;
541 }
542 
543 static void
gdk_x11_surface_begin_frame(GdkSurface * surface,gboolean force_frame)544 gdk_x11_surface_begin_frame (GdkSurface *surface,
545                             gboolean   force_frame)
546 {
547   GdkX11Surface *impl;
548 
549   g_return_if_fail (GDK_IS_SURFACE (surface));
550 
551   impl = GDK_X11_SURFACE (surface);
552 
553   if (impl->toplevel->extended_update_counter == None)
554     return;
555 
556   impl->toplevel->in_frame = TRUE;
557 
558   if (impl->toplevel->configure_counter_value != 0 &&
559       impl->toplevel->configure_counter_value_is_extended)
560     {
561       impl->toplevel->current_counter_value = impl->toplevel->configure_counter_value;
562       if ((impl->toplevel->current_counter_value % 2) == 1)
563         impl->toplevel->current_counter_value += 1;
564 
565       impl->toplevel->configure_counter_value = 0;
566 
567       gdk_x11_surface_pre_damage (surface);
568     }
569   else if (force_frame)
570     {
571       /* When mapping the surface, we really want to freeze the
572          rendering of the surface by the compositor until we've
573          actually painted something into the surface's buffer. */
574       gdk_x11_surface_pre_damage (surface);
575     }
576   else
577     {
578       hook_surface_changed (surface);
579     }
580 }
581 
582 gboolean
_gdk_x11_surface_syncs_frames(GdkSurface * surface)583 _gdk_x11_surface_syncs_frames (GdkSurface *surface)
584 {
585   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
586 
587   /* disabled client side */
588   if (!impl->frame_sync_enabled)
589     return FALSE;
590 
591   /* disabled compositor side */
592   if (!gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (surface),
593                                             g_intern_static_string ("_NET_WM_FRAME_DRAWN")))
594     return FALSE;
595 
596   return TRUE;
597 }
598 
599 static void
sync_counter_for_end_frame(GdkSurface * surface)600 sync_counter_for_end_frame (GdkSurface *surface)
601 {
602   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
603 
604   g_assert (!impl->toplevel->in_frame);
605   g_assert (impl->toplevel->extended_update_counter != None);
606   g_assert ((impl->toplevel->current_counter_value % 2) == 0);
607 
608   set_sync_counter (GDK_SURFACE_XDISPLAY (surface),
609                     impl->toplevel->extended_update_counter,
610                     impl->toplevel->current_counter_value);
611 }
612 
613 static void
maybe_sync_counter_for_end_frame(GdkSurface * surface)614 maybe_sync_counter_for_end_frame (GdkSurface *surface)
615 {
616   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
617   gboolean frame_sync_negotiated = _gdk_x11_surface_syncs_frames (surface);
618   gboolean frame_done_painting;
619 
620 #ifdef HAVE_XDAMAGE
621   frame_done_painting = !impl->toplevel->frame_still_painting && frame_sync_negotiated;
622 #else
623   frame_done_painting = !impl->toplevel->frame_pending;
624 #endif
625 
626   if (!impl->toplevel->frame_pending)
627     {
628       if (!frame_sync_negotiated || frame_done_painting)
629         sync_counter_for_end_frame (surface);
630     }
631   else
632     {
633       if (frame_done_painting)
634         sync_counter_for_end_frame (surface);
635     }
636 }
637 
638 #ifdef HAVE_XDAMAGE
639 void
_gdk_x11_surface_set_frame_still_painting(GdkSurface * surface,gboolean painting)640 _gdk_x11_surface_set_frame_still_painting (GdkSurface *surface,
641                                            gboolean    painting)
642 {
643   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
644 
645   if (impl->toplevel->frame_still_painting == painting)
646     return;
647 
648   impl->toplevel->frame_still_painting = painting;
649 
650   if (!impl->toplevel->frame_still_painting)
651     maybe_sync_counter_for_end_frame (surface);
652 }
653 #endif
654 
655 static void
gdk_x11_surface_end_frame(GdkSurface * surface)656 gdk_x11_surface_end_frame (GdkSurface *surface)
657 {
658   GdkFrameClock *clock;
659   GdkFrameTimings *timings;
660   GdkX11Surface *impl;
661 
662   g_return_if_fail (GDK_IS_SURFACE (surface));
663 
664   impl = GDK_X11_SURFACE (surface);
665 
666   if (impl->toplevel->extended_update_counter == None ||
667       !impl->toplevel->in_frame)
668     return;
669 
670   clock = gdk_surface_get_frame_clock (surface);
671   timings = gdk_frame_clock_get_current_timings (clock);
672 
673   /* Make sure we request timing updates even if nothing was damaged.
674    * We want the frame clock to be accurate. */
675   gdk_x11_surface_pre_damage (surface);
676 
677   impl->toplevel->in_frame = FALSE;
678 
679   if (impl->toplevel->current_counter_value % 2 == 1)
680     {
681       if (GDK_DISPLAY_DEBUG_CHECK (gdk_surface_get_display (surface), FRAMES))
682         {
683           XImage *image = XGetImage (GDK_SURFACE_XDISPLAY (surface),
684                                      GDK_SURFACE_XID (surface),
685                                      0, 0, 1, 1,
686                                      (1 << 24) - 1,
687                                      ZPixmap);
688           XDestroyImage (image);
689         }
690 
691       /* An increment of 3 means that the frame was not drawn as fast as possible,
692        * but rather at a particular time. This can trigger different handling from
693        * the compositor.
694        */
695       if (timings->slept_before)
696         impl->toplevel->current_counter_value += 3;
697       else
698         impl->toplevel->current_counter_value += 1;
699 
700       maybe_sync_counter_for_end_frame (surface);
701 
702       if (_gdk_x11_surface_syncs_frames (surface))
703         {
704           impl->toplevel->frame_pending = TRUE;
705           gdk_surface_freeze_updates (surface);
706           timings->cookie = impl->toplevel->current_counter_value;
707         }
708     }
709 
710   unhook_surface_changed (surface);
711 
712   if (impl->toplevel->configure_counter_value != 0 &&
713       !impl->toplevel->configure_counter_value_is_extended)
714     {
715       set_sync_counter (GDK_SURFACE_XDISPLAY (surface),
716                         impl->toplevel->update_counter,
717                         impl->toplevel->configure_counter_value);
718 
719       impl->toplevel->configure_counter_value = 0;
720     }
721 
722   if (!impl->toplevel->frame_pending)
723     timings->complete = TRUE;
724 }
725 
726 /*****************************************************
727  * X11 specific implementations of generic functions *
728  *****************************************************/
729 
730 static void
gdk_x11_surface_finalize(GObject * object)731 gdk_x11_surface_finalize (GObject *object)
732 {
733   GdkX11Surface *impl;
734 
735   g_return_if_fail (GDK_IS_X11_SURFACE (object));
736 
737   impl = GDK_X11_SURFACE (object);
738 
739   if (impl->toplevel->in_frame)
740     unhook_surface_changed (GDK_SURFACE (impl));
741 
742   g_signal_handlers_disconnect_by_func (GDK_SURFACE (impl),
743                                         gdk_x11_toplevel_state_callback,
744                                         NULL);
745   g_signal_handlers_disconnect_by_func (GDK_SURFACE (impl),
746                                         gdk_x11_toplevel_event_callback,
747                                         NULL);
748 
749   _gdk_x11_surface_grab_check_destroy (GDK_SURFACE (impl));
750 
751   if (!GDK_SURFACE_DESTROYED (impl))
752     {
753       GdkDisplay *display = GDK_SURFACE_DISPLAY (GDK_SURFACE (impl));
754 
755       _gdk_x11_display_remove_window (display, impl->xid);
756       if (impl->toplevel && impl->toplevel->focus_window)
757         _gdk_x11_display_remove_window (display, impl->toplevel->focus_window);
758     }
759 
760   g_clear_pointer (&impl->surface_is_on_monitor, g_list_free);
761 
762   g_free (impl->toplevel);
763 
764   if (impl->cursor)
765     g_object_unref (impl->cursor);
766 
767   G_OBJECT_CLASS (gdk_x11_surface_parent_class)->finalize (object);
768 }
769 
770 typedef struct {
771   GdkDisplay *display;
772   Pixmap pixmap;
773 } FreePixmapData;
774 
775 static void
free_pixmap(gpointer datap)776 free_pixmap (gpointer datap)
777 {
778   FreePixmapData *data = datap;
779 
780   if (!gdk_display_is_closed (data->display))
781     {
782       XFreePixmap (GDK_DISPLAY_XDISPLAY (data->display),
783                    data->pixmap);
784     }
785 
786   g_object_unref (data->display);
787   g_slice_free (FreePixmapData, data);
788 }
789 
790 static void
attach_free_pixmap_handler(cairo_surface_t * surface,GdkDisplay * display,Pixmap pixmap)791 attach_free_pixmap_handler (cairo_surface_t *surface,
792                             GdkDisplay      *display,
793                             Pixmap           pixmap)
794 {
795   static const cairo_user_data_key_t key;
796   FreePixmapData *data;
797 
798   data = g_slice_new (FreePixmapData);
799   data->display = g_object_ref (display);
800   data->pixmap = pixmap;
801 
802   cairo_surface_set_user_data (surface, &key, data, free_pixmap);
803 }
804 
805 /* Cairo does not guarantee we get an xlib surface if we call
806  * cairo_surface_create_similar(). In some cases however, we must use a
807  * pixmap or bitmap in the X11 API.
808  * These functions ensure an Xlib surface.
809  */
810 cairo_surface_t *
_gdk_x11_display_create_bitmap_surface(GdkDisplay * display,int width,int height)811 _gdk_x11_display_create_bitmap_surface (GdkDisplay *display,
812                                         int         width,
813                                         int         height)
814 {
815   cairo_surface_t *surface;
816   Pixmap pixmap;
817 
818   pixmap = XCreatePixmap (GDK_DISPLAY_XDISPLAY (display),
819                           GDK_SCREEN_XROOTWIN (GDK_X11_DISPLAY (display)->screen),
820                           width, height, 1);
821   surface = cairo_xlib_surface_create_for_bitmap (GDK_DISPLAY_XDISPLAY (display),
822                                                   pixmap,
823                                                   GDK_X11_SCREEN (GDK_X11_DISPLAY (display)->screen)->xscreen,
824                                                   width, height);
825   attach_free_pixmap_handler (surface, display, pixmap);
826 
827   return surface;
828 }
829 
830 /* Create a surface backed with a pixmap without alpha on the same screen as surface */
831 static cairo_surface_t *
gdk_x11_surface_create_pixmap_surface(GdkSurface * surface,int width,int height)832 gdk_x11_surface_create_pixmap_surface (GdkSurface *surface,
833                                       int        width,
834                                       int        height)
835 {
836   GdkDisplay *display;
837   Display *dpy;
838   cairo_surface_t *cairo_surface;
839   Pixmap pixmap;
840 
841   display = gdk_surface_get_display (surface);
842   dpy = GDK_DISPLAY_XDISPLAY (display);
843 
844   pixmap = XCreatePixmap (dpy,
845                           GDK_SURFACE_XID (surface),
846                           width, height,
847                           DefaultDepth (dpy, DefaultScreen (dpy)));
848   cairo_surface = cairo_xlib_surface_create (dpy,
849                                        pixmap,
850                                        DefaultVisual (dpy, DefaultScreen (dpy)),
851                                        width, height);
852   attach_free_pixmap_handler (cairo_surface, display, pixmap);
853 
854   return cairo_surface;
855 }
856 
857 static void
set_wm_protocols(GdkSurface * surface)858 set_wm_protocols (GdkSurface *surface)
859 {
860   GdkDisplay *display = gdk_surface_get_display (surface);
861   Atom protocols[4];
862   int n = 0;
863 
864   protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW");
865   protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS");
866   protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING");
867 
868 #ifdef HAVE_XSYNC
869   if (GDK_X11_DISPLAY (display)->use_sync)
870     protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_SYNC_REQUEST");
871 #endif
872 
873   XSetWMProtocols (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (surface), protocols, n);
874 }
875 
876 static const char *
get_default_title(void)877 get_default_title (void)
878 {
879   const char *title;
880 
881   title = g_get_application_name ();
882   if (!title)
883     title = g_get_prgname ();
884   if (!title)
885     title = "";
886 
887   return title;
888 }
889 
890 static void
check_leader_window_title(GdkDisplay * display)891 check_leader_window_title (GdkDisplay *display)
892 {
893   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
894 
895   if (display_x11->leader_window && !display_x11->leader_window_title_set)
896     {
897       set_wm_name (display,
898 		   display_x11->leader_window,
899 		   get_default_title ());
900 
901       display_x11->leader_window_title_set = TRUE;
902     }
903 }
904 
905 static Window
create_focus_window(GdkDisplay * display,XID parent)906 create_focus_window (GdkDisplay *display,
907 		     XID         parent)
908 {
909   GdkX11Display *display_x11;
910   GdkEventMask event_mask;
911   Display *xdisplay;
912   Window focus_window;
913   XSetWindowAttributes attrs;
914 
915   xdisplay = GDK_DISPLAY_XDISPLAY (display);
916   display_x11 = GDK_X11_DISPLAY (display);
917 
918   focus_window = XCreateWindow (xdisplay, parent,
919                                 -1, -1, 1, 1, 0,
920                                 0, /* depth */
921                                 InputOnly,
922                                 CopyFromParent,
923                                 0, &attrs);
924 
925   event_mask = (GDK_KEY_PRESS_MASK |
926                 GDK_KEY_RELEASE_MASK |
927                 GDK_FOCUS_CHANGE_MASK);
928 
929   gdk_x11_event_source_select_events ((GdkEventSource *) display_x11->event_source,
930                                       focus_window,
931                                       event_mask, 0);
932 
933   XMapWindow (xdisplay, focus_window);
934 
935   return focus_window;
936 }
937 
938 static void
ensure_sync_counter(GdkSurface * surface)939 ensure_sync_counter (GdkSurface *surface)
940 {
941 #ifdef HAVE_XSYNC
942   if (!GDK_SURFACE_DESTROYED (surface))
943     {
944       GdkDisplay *display = GDK_SURFACE_DISPLAY (surface);
945       GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (surface);
946 
947       if (toplevel &&
948 	  toplevel->update_counter == None &&
949 	  GDK_X11_DISPLAY (display)->use_sync)
950 	{
951 	  Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
952 	  XSyncValue value;
953 	  Atom atom;
954 	  XID counters[2];
955 
956 	  XSyncIntToValue (&value, 0);
957 
958 	  toplevel->update_counter = XSyncCreateCounter (xdisplay, value);
959 	  toplevel->extended_update_counter = XSyncCreateCounter (xdisplay, value);
960 
961 	  atom = gdk_x11_get_xatom_by_name_for_display (display,
962 							"_NET_WM_SYNC_REQUEST_COUNTER");
963 
964 	  counters[0] = toplevel->update_counter;
965 	  counters[1] = toplevel->extended_update_counter;
966 	  XChangeProperty (xdisplay, GDK_SURFACE_XID (surface),
967 			   atom, XA_CARDINAL,
968 			   32, PropModeReplace,
969 			   (guchar *)counters, 2);
970 
971 	  toplevel->current_counter_value = 0;
972 	}
973     }
974 #endif
975 }
976 
977 static void
setup_toplevel_window(GdkSurface * surface,GdkX11Screen * x11_screen)978 setup_toplevel_window (GdkSurface    *surface,
979 		       GdkX11Screen *x11_screen)
980 {
981   GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (surface);
982   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
983   GdkDisplay *display = gdk_surface_get_display (surface);
984   Display *xdisplay = GDK_SURFACE_XDISPLAY (surface);
985   XID xid = GDK_SURFACE_XID (surface);
986   XSizeHints size_hints;
987   Window leader_window;
988 
989   set_wm_protocols (surface);
990 
991   /* The focus surface is off the visible area, and serves to receive key
992    * press events so they don't get sent to child surfaces.
993    */
994   toplevel->focus_window = create_focus_window (display, xid);
995   _gdk_x11_display_add_window (x11_screen->display,
996                                &toplevel->focus_window,
997                                surface);
998 
999   check_leader_window_title (x11_screen->display);
1000 
1001   /* FIXME: Is there any point in doing this? Do any WM's pay
1002    * attention to PSize, and even if they do, is this the
1003    * correct value???
1004    */
1005   size_hints.flags = PSize;
1006   size_hints.width = surface->width * impl->surface_scale;
1007   size_hints.height = surface->height * impl->surface_scale;
1008 
1009   XSetWMNormalHints (xdisplay, xid, &size_hints);
1010 
1011   /* This will set WM_CLIENT_MACHINE and WM_LOCALE_NAME */
1012   XSetWMProperties (xdisplay, xid, NULL, NULL, NULL, 0, NULL, NULL, NULL);
1013 
1014   if (!gdk_running_in_sandbox ())
1015     {
1016       /* if sandboxed, we're likely in a pid namespace and would only confuse the wm with this */
1017       long pid = getpid ();
1018       XChangeProperty (xdisplay, xid,
1019                        gdk_x11_get_xatom_by_name_for_display (x11_screen->display, "_NET_WM_PID"),
1020                        XA_CARDINAL, 32,
1021                        PropModeReplace,
1022                        (guchar *)&pid, 1);
1023     }
1024 
1025   leader_window = GDK_X11_DISPLAY (x11_screen->display)->leader_window;
1026   if (!leader_window)
1027     leader_window = xid;
1028   XChangeProperty (xdisplay, xid,
1029 		   gdk_x11_get_xatom_by_name_for_display (x11_screen->display, "WM_CLIENT_LEADER"),
1030 		   XA_WINDOW, 32, PropModeReplace,
1031 		   (guchar *) &leader_window, 1);
1032 
1033   if (toplevel->focus_window != None)
1034     XChangeProperty (xdisplay, xid,
1035                      gdk_x11_get_xatom_by_name_for_display (x11_screen->display, "_NET_WM_USER_TIME_WINDOW"),
1036                      XA_WINDOW, 32, PropModeReplace,
1037                      (guchar *) &toplevel->focus_window, 1);
1038 
1039   if (GDK_X11_DISPLAY (x11_screen->display)->user_time != 0)
1040     gdk_x11_surface_set_user_time (surface, GDK_X11_DISPLAY (x11_screen->display)->user_time);
1041 
1042   ensure_sync_counter (surface);
1043 
1044   /* Start off in a frozen state - we'll finish this when we first paint */
1045   gdk_x11_surface_begin_frame (surface, TRUE);
1046 }
1047 
1048 static void
on_frame_clock_before_paint(GdkFrameClock * clock,GdkSurface * surface)1049 on_frame_clock_before_paint (GdkFrameClock *clock,
1050                              GdkSurface     *surface)
1051 {
1052   if (surface->update_freeze_count > 0)
1053     return;
1054 
1055   gdk_x11_surface_predict_presentation_time (surface);
1056   gdk_x11_surface_begin_frame (surface, FALSE);
1057 }
1058 
1059 static void
on_frame_clock_after_update(GdkFrameClock * clock,GdkSurface * surface)1060 on_frame_clock_after_update (GdkFrameClock *clock,
1061                              GdkSurface    *surface)
1062 {
1063   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
1064 
1065   if (impl->compute_size_source_id)
1066     {
1067       g_clear_handle_id (&impl->compute_size_source_id, g_source_remove);
1068       compute_size_idle (surface);
1069     }
1070 }
1071 
1072 static void
on_frame_clock_after_paint(GdkFrameClock * clock,GdkSurface * surface)1073 on_frame_clock_after_paint (GdkFrameClock *clock,
1074                             GdkSurface     *surface)
1075 {
1076   if (surface->update_freeze_count > 0)
1077     return;
1078 
1079   gdk_x11_surface_end_frame (surface);
1080 }
1081 
1082 static void
connect_frame_clock(GdkSurface * surface)1083 connect_frame_clock (GdkSurface *surface)
1084 {
1085   GdkX11Surface *impl;
1086 
1087   impl = GDK_X11_SURFACE (surface);
1088   if (!impl->frame_clock_connected)
1089     {
1090       GdkFrameClock *frame_clock = gdk_surface_get_frame_clock (surface);
1091 
1092       g_signal_connect (frame_clock, "before-paint",
1093                         G_CALLBACK (on_frame_clock_before_paint), surface);
1094       g_signal_connect_after (frame_clock, "update",
1095                               G_CALLBACK (on_frame_clock_after_update), surface);
1096       g_signal_connect (frame_clock, "after-paint",
1097                         G_CALLBACK (on_frame_clock_after_paint), surface);
1098 
1099       impl->frame_clock_connected = TRUE;
1100     }
1101 }
1102 
1103 static void
disconnect_frame_clock(GdkSurface * surface)1104 disconnect_frame_clock (GdkSurface *surface)
1105 {
1106   GdkX11Surface *impl;
1107 
1108   impl = GDK_X11_SURFACE (surface);
1109   if (impl->frame_clock_connected)
1110     {
1111       GdkFrameClock *frame_clock = gdk_surface_get_frame_clock (surface);
1112 
1113       g_signal_handlers_disconnect_by_func (frame_clock,
1114                                             on_frame_clock_before_paint, surface);
1115       g_signal_handlers_disconnect_by_func (frame_clock,
1116                                             on_frame_clock_after_update, surface);
1117       g_signal_handlers_disconnect_by_func (frame_clock,
1118                                             on_frame_clock_after_paint, surface);
1119 
1120       impl->frame_clock_connected = FALSE;
1121     }
1122 }
1123 
1124 typedef enum
1125 {
1126   GDK_SURFACE_TYPE_HINT_NORMAL,
1127   GDK_SURFACE_TYPE_HINT_DIALOG,
1128   GDK_SURFACE_TYPE_HINT_MENU,           /* Torn off menu */
1129   GDK_SURFACE_TYPE_HINT_TOOLBAR,
1130   GDK_SURFACE_TYPE_HINT_SPLASHSCREEN,
1131   GDK_SURFACE_TYPE_HINT_UTILITY,
1132   GDK_SURFACE_TYPE_HINT_DOCK,
1133   GDK_SURFACE_TYPE_HINT_DESKTOP,
1134   GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU,  /* A drop down menu (from a menubar) */
1135   GDK_SURFACE_TYPE_HINT_POPUP_MENU,     /* A popup menu (from right-click) */
1136   GDK_SURFACE_TYPE_HINT_TOOLTIP,
1137   GDK_SURFACE_TYPE_HINT_NOTIFICATION,
1138   GDK_SURFACE_TYPE_HINT_COMBO,
1139   GDK_SURFACE_TYPE_HINT_DND
1140 } GdkSurfaceTypeHint;
1141 
1142 static void gdk_x11_surface_set_title (GdkSurface *surface,
1143                                        const char *title);
1144 static void gdk_x11_surface_set_type_hint (GdkSurface        *surface,
1145                                            GdkSurfaceTypeHint hint);
1146 
1147 GdkSurface *
_gdk_x11_display_create_surface(GdkDisplay * display,GdkSurfaceType surface_type,GdkSurface * parent,int x,int y,int width,int height)1148 _gdk_x11_display_create_surface (GdkDisplay     *display,
1149                                  GdkSurfaceType  surface_type,
1150                                  GdkSurface     *parent,
1151                                  int             x,
1152                                  int             y,
1153                                  int             width,
1154                                  int             height)
1155 {
1156   GdkSurface *surface;
1157   GdkFrameClock *frame_clock;
1158   GdkX11Surface *impl;
1159   GdkX11Screen *x11_screen;
1160   GdkX11Display *display_x11;
1161 
1162   Window xparent;
1163   Display *xdisplay;
1164 
1165   XSetWindowAttributes xattributes;
1166   long xattributes_mask;
1167   XClassHint *class_hint;
1168 
1169   int abs_x;
1170   int abs_y;
1171 
1172   display_x11 = GDK_X11_DISPLAY (display);
1173   x11_screen = GDK_X11_SCREEN (display_x11->screen);
1174   xparent = GDK_SCREEN_XROOTWIN (x11_screen);
1175 
1176   if (parent)
1177     frame_clock = g_object_ref (gdk_surface_get_frame_clock (parent));
1178   else
1179     frame_clock = _gdk_frame_clock_idle_new ();
1180 
1181   switch (surface_type)
1182     {
1183     case GDK_SURFACE_TOPLEVEL:
1184       surface = g_object_new (GDK_TYPE_X11_TOPLEVEL,
1185                               "display", display,
1186                               "frame-clock", frame_clock,
1187                               NULL);
1188       break;
1189     case GDK_SURFACE_POPUP:
1190       surface = g_object_new (GDK_TYPE_X11_POPUP,
1191                               "parent", parent,
1192                               "display", display,
1193                               "frame-clock", frame_clock,
1194                               NULL);
1195       break;
1196     case GDK_SURFACE_TEMP:
1197       surface = g_object_new (GDK_TYPE_X11_DRAG_SURFACE,
1198                               "display", display,
1199                               "frame-clock", frame_clock,
1200                               NULL);
1201       break;
1202     default:
1203       g_assert_not_reached ();
1204       break;
1205     }
1206 
1207   g_object_unref (frame_clock);
1208 
1209   surface->x = x;
1210   surface->y = y;
1211   surface->width = width;
1212   surface->height = height;
1213 
1214   impl = GDK_X11_SURFACE (surface);
1215   impl->surface_scale = x11_screen->surface_scale;
1216 
1217   xdisplay = x11_screen->xdisplay;
1218 
1219   xattributes_mask = 0;
1220 
1221   impl->override_redirect = FALSE;
1222 
1223   xattributes.background_pixmap = None;
1224   xattributes_mask |= CWBackPixmap;
1225 
1226   xattributes.border_pixel = BlackPixel (xdisplay, x11_screen->screen_num);
1227   xattributes_mask |= CWBorderPixel;
1228 
1229   xattributes.bit_gravity = NorthWestGravity;
1230   xattributes_mask |= CWBitGravity;
1231 
1232   xattributes.colormap = gdk_x11_display_get_window_colormap (display_x11);
1233   xattributes_mask |= CWColormap;
1234 
1235   if (surface_type == GDK_SURFACE_TEMP ||
1236       surface_type == GDK_SURFACE_POPUP)
1237     {
1238       xattributes.save_under = True;
1239       xattributes.override_redirect = True;
1240       xattributes.cursor = None;
1241       xattributes_mask |= CWSaveUnder | CWOverrideRedirect;
1242 
1243       impl->override_redirect = TRUE;
1244     }
1245 
1246   if (surface->width * impl->surface_scale > 32767 ||
1247       surface->height * impl->surface_scale > 32767)
1248     {
1249       g_warning ("Native Windows wider or taller than 32767 pixels are not supported");
1250 
1251       if (surface->width * impl->surface_scale > 32767)
1252         surface->width = 32767 / impl->surface_scale;
1253       if (surface->height  * impl->surface_scale > 32767)
1254         surface->height = 32767 /  impl->surface_scale;
1255     }
1256 
1257   impl->unscaled_width = surface->width * impl->surface_scale;
1258   impl->unscaled_height = surface->height * impl->surface_scale;
1259 
1260   abs_x = 0;
1261   abs_y = 0;
1262 
1263   impl->xid = XCreateWindow (xdisplay, xparent,
1264                              (surface->x + abs_x) * impl->surface_scale,
1265                              (surface->y + abs_y) * impl->surface_scale,
1266                              MAX (1, surface->width * impl->surface_scale),
1267                              MAX (1, surface->height * impl->surface_scale),
1268                              0,
1269                              gdk_x11_display_get_window_depth (display_x11),
1270                              InputOutput,
1271                              gdk_x11_display_get_window_visual (display_x11),
1272                              xattributes_mask, &xattributes);
1273 
1274   g_object_ref (surface);
1275   _gdk_x11_display_add_window (x11_screen->display, &impl->xid, surface);
1276 
1277   gdk_x11_surface_set_title (surface, get_default_title ());
1278   if (surface_type == GDK_SURFACE_TOPLEVEL)
1279     gdk_x11_surface_set_type_hint (surface, GDK_SURFACE_TYPE_HINT_NORMAL);
1280   else if (surface_type == GDK_SURFACE_POPUP)
1281     gdk_x11_surface_set_type_hint (surface, GDK_SURFACE_TYPE_HINT_MENU);
1282 
1283   class_hint = XAllocClassHint ();
1284   class_hint->res_name = (char *) g_get_prgname ();
1285   if (display_x11->program_class)
1286     class_hint->res_class = (char *) display_x11->program_class;
1287   else
1288     class_hint->res_class = class_hint->res_name;
1289   XSetClassHint (xdisplay, impl->xid, class_hint);
1290   XFree (class_hint);
1291 
1292   setup_toplevel_window (surface, x11_screen);
1293 
1294   gdk_x11_event_source_select_events ((GdkEventSource *) display_x11->event_source,
1295                                       GDK_SURFACE_XID (surface), GDK_ALL_EVENTS_MASK,
1296                                       StructureNotifyMask | PropertyChangeMask);
1297 
1298   _gdk_x11_surface_register_dnd (surface);
1299 
1300   connect_frame_clock (surface);
1301 
1302   gdk_surface_freeze_updates (surface);
1303 
1304   return surface;
1305 }
1306 
1307 static void
gdk_toplevel_x11_free_contents(GdkDisplay * display,GdkToplevelX11 * toplevel)1308 gdk_toplevel_x11_free_contents (GdkDisplay *display,
1309 				GdkToplevelX11 *toplevel)
1310 {
1311   if (toplevel->icon_pixmap)
1312     {
1313       cairo_surface_destroy (toplevel->icon_pixmap);
1314       toplevel->icon_pixmap = NULL;
1315     }
1316   if (toplevel->icon_mask)
1317     {
1318       cairo_surface_destroy (toplevel->icon_mask);
1319       toplevel->icon_mask = NULL;
1320     }
1321   if (toplevel->group_leader)
1322     {
1323       g_object_unref (toplevel->group_leader);
1324       toplevel->group_leader = NULL;
1325     }
1326 #ifdef HAVE_XSYNC
1327   if (toplevel->update_counter != None)
1328     {
1329       XSyncDestroyCounter (GDK_DISPLAY_XDISPLAY (display),
1330 			   toplevel->update_counter);
1331       XSyncDestroyCounter (GDK_DISPLAY_XDISPLAY (display),
1332                            toplevel->extended_update_counter);
1333       toplevel->update_counter = None;
1334       toplevel->extended_update_counter = None;
1335 
1336       toplevel->current_counter_value = 0;
1337     }
1338 #endif
1339 }
1340 
1341 static void
gdk_x11_surface_destroy(GdkSurface * surface,gboolean foreign_destroy)1342 gdk_x11_surface_destroy (GdkSurface *surface,
1343                          gboolean    foreign_destroy)
1344 {
1345   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
1346   GdkToplevelX11 *toplevel;
1347 
1348   g_return_if_fail (GDK_IS_SURFACE (surface));
1349 
1350   toplevel = _gdk_x11_surface_get_toplevel (surface);
1351   if (toplevel)
1352     gdk_toplevel_x11_free_contents (GDK_SURFACE_DISPLAY (surface), toplevel);
1353 
1354   unhook_surface_changed (surface);
1355   disconnect_frame_clock (surface);
1356 
1357   if (impl->cairo_surface)
1358     {
1359       cairo_surface_finish (impl->cairo_surface);
1360       cairo_surface_destroy (impl->cairo_surface);
1361       impl->cairo_surface = NULL;
1362     }
1363 
1364   if (!foreign_destroy)
1365     {
1366       gdk_x11_surface_destroy_egl_surface (impl);
1367       gdk_x11_surface_destroy_glx_drawable (impl);
1368 
1369       XDestroyWindow (GDK_SURFACE_XDISPLAY (surface), GDK_SURFACE_XID (surface));
1370     }
1371 }
1372 
1373 /* This function is called when the XWindow is really gone.
1374  */
1375 static void
gdk_x11_surface_destroy_notify(GdkSurface * surface)1376 gdk_x11_surface_destroy_notify (GdkSurface *surface)
1377 {
1378   GdkX11Surface *surface_impl;
1379 
1380   surface_impl = GDK_X11_SURFACE (surface);
1381 
1382   if (!GDK_SURFACE_DESTROYED (surface))
1383     {
1384       g_warning ("GdkSurface %#lx unexpectedly destroyed", GDK_SURFACE_XID (surface));
1385 
1386       _gdk_surface_destroy (surface, TRUE);
1387     }
1388 
1389   _gdk_x11_display_remove_window (GDK_SURFACE_DISPLAY (surface), GDK_SURFACE_XID (surface));
1390   if (surface_impl->toplevel && surface_impl->toplevel->focus_window)
1391     _gdk_x11_display_remove_window (GDK_SURFACE_DISPLAY (surface), surface_impl->toplevel->focus_window);
1392 
1393   _gdk_x11_surface_grab_check_destroy (surface);
1394 
1395   g_object_unref (surface);
1396 }
1397 
1398 static void
update_wm_hints(GdkSurface * surface,gboolean force)1399 update_wm_hints (GdkSurface *surface,
1400 		 gboolean   force)
1401 {
1402   GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (surface);
1403   GdkDisplay *display = GDK_SURFACE_DISPLAY (surface);
1404   XWMHints wm_hints;
1405 
1406   if (!force &&
1407       !toplevel->is_leader &&
1408       !GDK_SURFACE_IS_MAPPED (surface))
1409     return;
1410 
1411   wm_hints.flags = StateHint | InputHint;
1412   wm_hints.input = True;
1413   wm_hints.initial_state = NormalState;
1414 
1415   if (surface->state & GDK_TOPLEVEL_STATE_MINIMIZED)
1416     {
1417       wm_hints.flags |= StateHint;
1418       wm_hints.initial_state = IconicState;
1419     }
1420 
1421   if (toplevel->icon_pixmap)
1422     {
1423       wm_hints.flags |= IconPixmapHint;
1424       wm_hints.icon_pixmap = cairo_xlib_surface_get_drawable (toplevel->icon_pixmap);
1425     }
1426 
1427   if (toplevel->icon_mask)
1428     {
1429       wm_hints.flags |= IconMaskHint;
1430       wm_hints.icon_mask = cairo_xlib_surface_get_drawable (toplevel->icon_mask);
1431     }
1432 
1433   wm_hints.flags |= WindowGroupHint;
1434   if (toplevel->group_leader && !GDK_SURFACE_DESTROYED (toplevel->group_leader))
1435     {
1436       wm_hints.flags |= WindowGroupHint;
1437       wm_hints.window_group = GDK_SURFACE_XID (toplevel->group_leader);
1438     }
1439   else
1440     wm_hints.window_group = GDK_X11_DISPLAY (display)->leader_window;
1441 
1442   if (toplevel->urgency_hint)
1443     wm_hints.flags |= XUrgencyHint;
1444 
1445   XSetWMHints (GDK_SURFACE_XDISPLAY (surface),
1446 	       GDK_SURFACE_XID (surface),
1447 	       &wm_hints);
1448 }
1449 
1450 static void
set_initial_hints(GdkSurface * surface)1451 set_initial_hints (GdkSurface *surface)
1452 {
1453   GdkDisplay *display = GDK_SURFACE_DISPLAY (surface);
1454   Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
1455   Window xwindow = GDK_SURFACE_XID (surface);
1456   GdkToplevelX11 *toplevel;
1457   Atom atoms[9];
1458   int i;
1459 
1460   toplevel = _gdk_x11_surface_get_toplevel (surface);
1461 
1462   if (!toplevel)
1463     return;
1464 
1465   update_wm_hints (surface, TRUE);
1466 
1467   /* We set the spec hints regardless of whether the spec is supported,
1468    * since it can't hurt and it's kind of expensive to check whether
1469    * it's supported.
1470    */
1471 
1472   i = 0;
1473 
1474   if (surface->state & GDK_TOPLEVEL_STATE_MAXIMIZED)
1475     {
1476       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1477 							"_NET_WM_STATE_MAXIMIZED_VERT");
1478       ++i;
1479       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1480 							"_NET_WM_STATE_MAXIMIZED_HORZ");
1481       ++i;
1482       toplevel->have_maxhorz = toplevel->have_maxvert = TRUE;
1483     }
1484 
1485   if (surface->state & GDK_TOPLEVEL_STATE_ABOVE)
1486     {
1487       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1488 							"_NET_WM_STATE_ABOVE");
1489       ++i;
1490     }
1491 
1492   if (surface->state & GDK_TOPLEVEL_STATE_BELOW)
1493     {
1494       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1495 							"_NET_WM_STATE_BELOW");
1496       ++i;
1497     }
1498 
1499   if (surface->state & GDK_TOPLEVEL_STATE_FULLSCREEN)
1500     {
1501       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1502 							"_NET_WM_STATE_FULLSCREEN");
1503       ++i;
1504       toplevel->have_fullscreen = TRUE;
1505     }
1506 
1507   if (surface->modal_hint)
1508     {
1509       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1510 							"_NET_WM_STATE_MODAL");
1511       ++i;
1512     }
1513 
1514   if (toplevel->skip_taskbar_hint)
1515     {
1516       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1517 							"_NET_WM_STATE_SKIP_TASKBAR");
1518       ++i;
1519     }
1520 
1521   if (toplevel->skip_pager_hint)
1522     {
1523       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1524 							"_NET_WM_STATE_SKIP_PAGER");
1525       ++i;
1526     }
1527 
1528   if (surface->state & GDK_TOPLEVEL_STATE_MINIMIZED)
1529     {
1530       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1531 							"_NET_WM_STATE_HIDDEN");
1532       ++i;
1533       toplevel->have_hidden = TRUE;
1534     }
1535 
1536   if (i > 0)
1537     {
1538       XChangeProperty (xdisplay,
1539                        xwindow,
1540 		       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
1541                        XA_ATOM, 32, PropModeReplace,
1542                        (guchar*) atoms, i);
1543     }
1544   else
1545     {
1546       XDeleteProperty (xdisplay,
1547                        xwindow,
1548 		       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"));
1549     }
1550 
1551   if (surface->state & GDK_TOPLEVEL_STATE_STICKY)
1552     {
1553       atoms[0] = 0xFFFFFFFF;
1554       XChangeProperty (xdisplay,
1555                        xwindow,
1556 		       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"),
1557                        XA_CARDINAL, 32, PropModeReplace,
1558                        (guchar*) atoms, 1);
1559       toplevel->on_all_desktops = TRUE;
1560     }
1561   else
1562     {
1563       XDeleteProperty (xdisplay,
1564                        xwindow,
1565 		       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"));
1566     }
1567 
1568   toplevel->map_serial = NextRequest (xdisplay);
1569 }
1570 
1571 void
gdk_x11_surface_show(GdkSurface * surface,gboolean already_mapped)1572 gdk_x11_surface_show (GdkSurface *surface, gboolean already_mapped)
1573 {
1574   GdkDisplay *display;
1575   GdkX11Display *display_x11;
1576   GdkToplevelX11 *toplevel;
1577   Display *xdisplay = GDK_SURFACE_XDISPLAY (surface);
1578   Window xwindow = GDK_SURFACE_XID (surface);
1579 
1580   if (!already_mapped)
1581     set_initial_hints (surface);
1582 
1583   display = gdk_surface_get_display (surface);
1584   display_x11 = GDK_X11_DISPLAY (display);
1585   toplevel = _gdk_x11_surface_get_toplevel (surface);
1586 
1587   if (toplevel->user_time != 0 &&
1588       display_x11->user_time != 0 &&
1589       XSERVER_TIME_IS_LATER (display_x11->user_time, toplevel->user_time))
1590     gdk_x11_surface_set_user_time (surface, display_x11->user_time);
1591 
1592  if (GDK_PROFILER_IS_RUNNING)
1593    {
1594      GdkX11Surface *impl = GDK_X11_SURFACE (surface);
1595      if (impl->map_time == 0)
1596        impl->map_time = g_get_monotonic_time ();
1597    }
1598 
1599   XMapWindow (xdisplay, xwindow);
1600 
1601   /* Fullscreen on current monitor is the default, no need to apply this mode
1602    * when mapping a window. This also ensures that the default behavior remains
1603    * consistent with pre-fullscreen mode implementation.
1604    */
1605   if (surface->fullscreen_mode != GDK_FULLSCREEN_ON_CURRENT_MONITOR)
1606     gdk_x11_surface_apply_fullscreen_mode (surface);
1607 }
1608 
1609 static void
gdk_x11_surface_withdraw(GdkSurface * surface)1610 gdk_x11_surface_withdraw (GdkSurface *surface)
1611 {
1612   if (!surface->destroyed)
1613     {
1614       if (GDK_SURFACE_IS_MAPPED (surface))
1615         gdk_surface_set_is_mapped (surface, FALSE);
1616 
1617       g_assert (!GDK_SURFACE_IS_MAPPED (surface));
1618       XWithdrawWindow (GDK_SURFACE_XDISPLAY (surface),
1619                        GDK_SURFACE_XID (surface), 0);
1620     }
1621 }
1622 
1623 static void
gdk_x11_surface_hide(GdkSurface * surface)1624 gdk_x11_surface_hide (GdkSurface *surface)
1625 {
1626   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
1627 
1628   /* We'll get the unmap notify eventually, and handle it then,
1629    * but checking here makes things more consistent if we are
1630    * just doing stuff ourself.
1631    */
1632   _gdk_x11_surface_grab_check_unmap (surface,
1633                                     NextRequest (GDK_SURFACE_XDISPLAY (surface)));
1634 
1635   g_clear_handle_id (&impl->compute_size_source_id, g_source_remove);
1636   g_clear_pointer (&impl->toplevel_layout, gdk_toplevel_layout_unref);
1637 
1638   gdk_x11_surface_withdraw (surface);
1639 
1640   impl->glx_frame_counter = 0;
1641 }
1642 
1643 static inline void
x11_surface_move(GdkSurface * surface,int x,int y)1644 x11_surface_move (GdkSurface *surface,
1645                   int         x,
1646                   int         y)
1647 {
1648   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
1649 
1650   XMoveWindow (GDK_SURFACE_XDISPLAY (surface),
1651                GDK_SURFACE_XID (surface),
1652                x * impl->surface_scale, y * impl->surface_scale);
1653 
1654   if (impl->override_redirect)
1655     {
1656       impl->abs_x = x;
1657       impl->abs_y = y;
1658 
1659       if (surface->parent)
1660         {
1661           surface->x = impl->abs_x - GDK_X11_SURFACE (surface->parent)->abs_x;
1662           surface->y = impl->abs_y - GDK_X11_SURFACE (surface->parent)->abs_y;
1663         }
1664       else
1665         {
1666           surface->x = x;
1667           surface->y = y;
1668         }
1669 
1670       impl->next_layout.surface_geometry_dirty = TRUE;
1671       gdk_surface_request_layout (surface);
1672     }
1673 }
1674 
1675 static inline void
x11_surface_resize(GdkSurface * surface,int width,int height)1676 x11_surface_resize (GdkSurface *surface,
1677                    int        width,
1678                    int        height)
1679 {
1680   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
1681 
1682   if (width < 1)
1683     width = 1;
1684 
1685   if (height < 1)
1686     height = 1;
1687 
1688   gdk_x11_surface_pre_damage (surface);
1689 
1690   XResizeWindow (GDK_SURFACE_XDISPLAY (surface),
1691                  GDK_SURFACE_XID (surface),
1692                  width * impl->surface_scale, height * impl->surface_scale);
1693 
1694   if (impl->override_redirect)
1695     {
1696       impl->unscaled_width = width * impl->surface_scale;
1697       impl->unscaled_height = height * impl->surface_scale;
1698       impl->next_layout.configured_width = width;
1699       impl->next_layout.configured_height = height;
1700       impl->next_layout.surface_geometry_dirty = TRUE;
1701       gdk_surface_request_layout (surface);
1702     }
1703   else
1704     {
1705       if (width * impl->surface_scale != impl->unscaled_width ||
1706           height * impl->surface_scale != impl->unscaled_height)
1707         {
1708           surface->resize_count++;
1709           if (surface->resize_count == 1)
1710             gdk_surface_freeze_updates (surface);
1711         }
1712     }
1713 }
1714 
1715 static inline void
x11_surface_move_resize(GdkSurface * surface,int x,int y,int width,int height)1716 x11_surface_move_resize (GdkSurface *surface,
1717                          int         x,
1718                          int         y,
1719                          int         width,
1720                          int         height)
1721 {
1722   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
1723 
1724   if (width < 1)
1725     width = 1;
1726 
1727   if (height < 1)
1728     height = 1;
1729 
1730   gdk_x11_surface_pre_damage (surface);
1731 
1732   XMoveResizeWindow (GDK_SURFACE_XDISPLAY (surface),
1733                      GDK_SURFACE_XID (surface),
1734                      x * impl->surface_scale, y * impl->surface_scale,
1735                      width * impl->surface_scale, height * impl->surface_scale);
1736 
1737   if (impl->override_redirect)
1738     {
1739       impl->abs_x = x;
1740       impl->abs_y = y;
1741 
1742       impl->unscaled_width = width * impl->surface_scale;
1743       impl->unscaled_height = height * impl->surface_scale;
1744       impl->next_layout.configured_width = width;
1745       impl->next_layout.configured_height = height;
1746       impl->next_layout.surface_geometry_dirty = TRUE;
1747       gdk_surface_request_layout (surface);
1748 
1749       if (surface->parent)
1750         {
1751           surface->x = impl->abs_x - GDK_X11_SURFACE (surface->parent)->abs_x;
1752           surface->y = impl->abs_y - GDK_X11_SURFACE (surface->parent)->abs_y;
1753         }
1754       else
1755         {
1756           surface->x = x;
1757           surface->y = y;
1758         }
1759     }
1760   else
1761     {
1762       if (width * impl->surface_scale != impl->unscaled_width ||
1763           height * impl->surface_scale != impl->unscaled_height)
1764         {
1765           surface->resize_count++;
1766           if (surface->resize_count == 1)
1767             gdk_surface_freeze_updates (surface);
1768         }
1769     }
1770 }
1771 
1772 static void
gdk_x11_surface_move_resize(GdkSurface * surface,gboolean with_move,int x,int y,int width,int height)1773 gdk_x11_surface_move_resize (GdkSurface *surface,
1774                              gboolean    with_move,
1775                              int         x,
1776                              int         y,
1777                              int         width,
1778                              int         height)
1779 {
1780   if (with_move && (width < 0 && height < 0))
1781     x11_surface_move (surface, x, y);
1782   else
1783     {
1784       if (with_move)
1785         x11_surface_move_resize (surface, x, y, width, height);
1786       else
1787         x11_surface_resize (surface, width, height);
1788     }
1789 }
1790 
1791 static void
gdk_x11_surface_toplevel_resize(GdkSurface * surface,int width,int height)1792 gdk_x11_surface_toplevel_resize (GdkSurface *surface,
1793                                  int         width,
1794                                  int         height)
1795 {
1796   x11_surface_resize (surface, width, height);
1797 }
1798 
1799 void
gdk_x11_surface_move(GdkSurface * surface,int x,int y)1800 gdk_x11_surface_move (GdkSurface *surface,
1801                       int         x,
1802                       int         y)
1803 {
1804   gdk_x11_surface_move_resize (surface, TRUE, x, y, -1, -1);
1805 }
1806 
1807 static void
gdk_x11_surface_layout_popup(GdkSurface * surface,int width,int height,GdkPopupLayout * layout)1808 gdk_x11_surface_layout_popup (GdkSurface     *surface,
1809                               int             width,
1810                               int             height,
1811                               GdkPopupLayout *layout)
1812 {
1813   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
1814   GdkMonitor *monitor;
1815   GdkRectangle bounds;
1816   GdkRectangle final_rect;
1817   int x, y;
1818 
1819   monitor = gdk_surface_get_layout_monitor (surface, layout,
1820                                             gdk_x11_monitor_get_workarea);
1821   if (monitor)
1822     gdk_x11_monitor_get_workarea (monitor, &bounds);
1823   else
1824     {
1825       monitor = gdk_surface_get_layout_monitor (surface, layout,
1826                                                 gdk_monitor_get_geometry);
1827       gdk_monitor_get_geometry (monitor, &bounds);
1828     }
1829 
1830   gdk_popup_layout_get_shadow_width (layout,
1831                                      &impl->shadow_left,
1832                                      &impl->shadow_right,
1833                                      &impl->shadow_top,
1834                                      &impl->shadow_bottom);
1835 
1836   gdk_surface_layout_popup_helper (surface,
1837                                    width,
1838                                    height,
1839                                    impl->shadow_left,
1840                                    impl->shadow_right,
1841                                    impl->shadow_top,
1842                                    impl->shadow_bottom,
1843                                    monitor,
1844                                    &bounds,
1845                                    layout,
1846                                    &final_rect);
1847 
1848   gdk_surface_get_origin (surface->parent, &x, &y);
1849   x += final_rect.x;
1850   y += final_rect.y;
1851 
1852   if (final_rect.width != surface->width ||
1853       final_rect.height != surface->height)
1854     {
1855       gdk_x11_surface_move_resize (surface,
1856                                    TRUE,
1857                                    x,
1858                                    y,
1859                                    final_rect.width,
1860                                    final_rect.height);
1861     }
1862   else
1863     {
1864       gdk_x11_surface_move (surface, x, y);
1865     }
1866 }
1867 
1868 static void
show_popup(GdkSurface * surface)1869 show_popup (GdkSurface *surface)
1870 {
1871   gdk_x11_surface_raise (surface);
1872   gdk_surface_set_is_mapped (surface, TRUE);
1873   gdk_x11_surface_show (surface, FALSE);
1874   gdk_surface_invalidate_rect (surface, NULL);
1875 }
1876 
1877 static void
show_grabbing_popup(GdkSeat * seat,GdkSurface * surface,gpointer user_data)1878 show_grabbing_popup (GdkSeat    *seat,
1879                      GdkSurface *surface,
1880                      gpointer    user_data)
1881 {
1882   show_popup (surface);
1883 }
1884 
1885 static gboolean
gdk_x11_surface_present_popup(GdkSurface * surface,int width,int height,GdkPopupLayout * layout)1886 gdk_x11_surface_present_popup (GdkSurface     *surface,
1887                                int             width,
1888                                int             height,
1889                                GdkPopupLayout *layout)
1890 {
1891   gdk_x11_surface_layout_popup (surface, width, height, layout);
1892 
1893   if (GDK_SURFACE_IS_MAPPED (surface))
1894     return TRUE;
1895 
1896   if (surface->autohide)
1897     {
1898       gdk_seat_grab (gdk_display_get_default_seat (surface->display),
1899                      surface,
1900                      GDK_SEAT_CAPABILITY_ALL,
1901                      TRUE,
1902                      NULL, NULL,
1903                      show_grabbing_popup, NULL);
1904     }
1905   else
1906     {
1907       show_popup (surface);
1908     }
1909 
1910   return GDK_SURFACE_IS_MAPPED (surface);
1911 }
1912 
1913 static void gdk_x11_surface_restack_toplevel (GdkSurface *surface,
1914                                               GdkSurface *sibling,
1915                                               gboolean    above);
1916 
1917 void
gdk_x11_surface_update_popups(GdkSurface * parent)1918 gdk_x11_surface_update_popups (GdkSurface *parent)
1919 {
1920   GList *l;
1921 
1922   for (l = parent->children; l; l = l->next)
1923     {
1924       GdkX11Surface *popup_impl = l->data;
1925       GdkSurface *popup = GDK_SURFACE (popup_impl);
1926       int new_x, new_y;
1927 
1928       if (GDK_SURFACE_DESTROYED (popup))
1929         continue;
1930 
1931       new_x = GDK_X11_SURFACE (parent)->abs_x + popup->x;
1932       new_y = GDK_X11_SURFACE (parent)->abs_y + popup->y;
1933 
1934       if (new_x != popup_impl->abs_x || new_y != popup_impl->abs_y)
1935         x11_surface_move (popup, new_x, new_y);
1936       gdk_x11_surface_restack_toplevel (popup, parent, TRUE);
1937     }
1938 }
1939 
1940 static void
gdk_x11_surface_set_is_on_monitor(GdkSurface * surface,GdkMonitor * monitor,gboolean is_on_monitor)1941 gdk_x11_surface_set_is_on_monitor (GdkSurface *surface,
1942                                    GdkMonitor *monitor,
1943                                    gboolean    is_on_monitor)
1944 {
1945   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
1946   GList *was_on_monitor;
1947 
1948   was_on_monitor = g_list_find (impl->surface_is_on_monitor, monitor);
1949 
1950   if (!was_on_monitor && is_on_monitor)
1951     {
1952       impl->surface_is_on_monitor = g_list_append (impl->surface_is_on_monitor,
1953                                                    monitor);
1954       gdk_surface_enter_monitor (surface, monitor);
1955     }
1956   else if (was_on_monitor && !is_on_monitor)
1957     {
1958       impl->surface_is_on_monitor = g_list_remove (impl->surface_is_on_monitor,
1959                                                    monitor);
1960       gdk_surface_leave_monitor (surface, monitor);
1961     }
1962 }
1963 
1964 void
gdk_x11_surface_check_monitor(GdkSurface * surface,GdkMonitor * monitor)1965 gdk_x11_surface_check_monitor (GdkSurface *surface,
1966                                GdkMonitor *monitor)
1967 {
1968   GdkRectangle monitor_geometry;
1969   GdkRectangle surface_geometry;
1970   gboolean is_on_monitor;
1971 
1972   gdk_monitor_get_geometry (monitor, &monitor_geometry);
1973   gdk_surface_get_geometry (surface,
1974                             &surface_geometry.x,
1975                             &surface_geometry.y,
1976                             &surface_geometry.width,
1977                             &surface_geometry.height);
1978 
1979   is_on_monitor = gdk_rectangle_intersect (&surface_geometry,
1980                                            &monitor_geometry,
1981                                            NULL);
1982 
1983   gdk_x11_surface_set_is_on_monitor (surface, monitor, is_on_monitor);
1984 }
1985 
1986 void
gdk_x11_surface_enter_leave_monitors(GdkSurface * surface)1987 gdk_x11_surface_enter_leave_monitors (GdkSurface *surface)
1988 {
1989   GdkDisplay *display = gdk_surface_get_display (surface);
1990   GListModel *monitors;
1991   guint i;
1992 
1993   monitors = gdk_display_get_monitors (display);
1994   for (i = 0; i < g_list_model_get_n_items (monitors); i++)
1995     {
1996       GdkMonitor *monitor = g_list_model_get_item (monitors, i);
1997       gdk_x11_surface_check_monitor (surface, monitor);
1998       g_object_unref (monitor);
1999     }
2000 }
2001 
2002 void
_gdk_x11_surface_set_surface_scale(GdkSurface * surface,int scale)2003 _gdk_x11_surface_set_surface_scale (GdkSurface *surface,
2004 				    int scale)
2005 {
2006   GdkX11Surface *impl;
2007   GdkToplevelX11 *toplevel;
2008   GdkSurfaceHints geom_mask;
2009 
2010   impl = GDK_X11_SURFACE (surface);
2011 
2012   if (!gdk_x11_surface_update_size (impl, surface->width, surface->height, scale))
2013     return;
2014 
2015   toplevel = _gdk_x11_surface_get_toplevel (surface);
2016   if (toplevel)
2017     {
2018       /* These are affected by surface scale: */
2019       geom_mask = toplevel->last_geometry_hints_mask & (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
2020       if (geom_mask)
2021         gdk_x11_surface_set_geometry_hints (surface,
2022                                             &toplevel->last_geometry_hints,
2023                                             geom_mask);
2024     }
2025 
2026   if (impl->override_redirect)
2027     {
2028       impl->unscaled_width = surface->width * impl->surface_scale;
2029       impl->unscaled_height = surface->height * impl->surface_scale;
2030     }
2031 
2032   XResizeWindow (GDK_SURFACE_XDISPLAY (surface),
2033                  GDK_SURFACE_XID (surface),
2034                  surface->width * impl->surface_scale,
2035                  surface->height * impl->surface_scale);
2036 
2037   gdk_surface_invalidate_rect (surface, NULL);
2038 
2039   g_object_notify (G_OBJECT (surface), "scale-factor");
2040 }
2041 
2042 void
gdk_x11_surface_raise(GdkSurface * surface)2043 gdk_x11_surface_raise (GdkSurface *surface)
2044 {
2045   XRaiseWindow (GDK_SURFACE_XDISPLAY (surface), GDK_SURFACE_XID (surface));
2046 }
2047 
2048 static void
gdk_x11_surface_restack_toplevel(GdkSurface * surface,GdkSurface * sibling,gboolean above)2049 gdk_x11_surface_restack_toplevel (GdkSurface *surface,
2050                                   GdkSurface *sibling,
2051                                   gboolean    above)
2052 {
2053   XWindowChanges changes;
2054 
2055   changes.sibling = GDK_SURFACE_XID (sibling);
2056   changes.stack_mode = above ? Above : Below;
2057   XReconfigureWMWindow (GDK_SURFACE_XDISPLAY (surface),
2058 			GDK_SURFACE_XID (surface),
2059 			gdk_x11_screen_get_screen_number (GDK_SURFACE_SCREEN (surface)),
2060 			CWStackMode | CWSibling, &changes);
2061 }
2062 
2063 static void
gdk_x11_surface_lower(GdkSurface * surface)2064 gdk_x11_surface_lower (GdkSurface *surface)
2065 {
2066   XLowerWindow (GDK_SURFACE_XDISPLAY (surface), GDK_SURFACE_XID (surface));
2067 }
2068 
2069 /**
2070  * gdk_x11_surface_move_to_current_desktop:
2071  * @surface: (type GdkX11Surface): a `GdkSurface`
2072  *
2073  * Moves the surface to the correct workspace when running under a
2074  * window manager that supports multiple workspaces, as described
2075  * in the [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec) specification.
2076  * Will not do anything if the surface is already on all workspaces.
2077  */
2078 void
gdk_x11_surface_move_to_current_desktop(GdkSurface * surface)2079 gdk_x11_surface_move_to_current_desktop (GdkSurface *surface)
2080 {
2081   GdkToplevelX11 *toplevel;
2082 
2083   g_return_if_fail (GDK_IS_SURFACE (surface));
2084 
2085   toplevel = _gdk_x11_surface_get_toplevel (surface);
2086 
2087   if (toplevel->on_all_desktops)
2088     return;
2089 
2090   move_to_current_desktop (surface);
2091 }
2092 
2093 static void
move_to_current_desktop(GdkSurface * surface)2094 move_to_current_desktop (GdkSurface *surface)
2095 {
2096   guint32 desktop;
2097 
2098   desktop = gdk_x11_screen_get_current_desktop (GDK_SURFACE_SCREEN (surface));
2099   gdk_x11_surface_move_to_desktop (surface, desktop);
2100 }
2101 
2102 static guint32
get_netwm_cardinal_property(GdkSurface * surface,const char * name)2103 get_netwm_cardinal_property (GdkSurface   *surface,
2104                              const char *name)
2105 {
2106   GdkX11Screen *x11_screen = GDK_SURFACE_SCREEN (surface);
2107   guint32 prop = 0;
2108   Atom type;
2109   int format;
2110   gulong nitems;
2111   gulong bytes_after;
2112   guchar *data;
2113 
2114   if (!gdk_x11_screen_supports_net_wm_hint (x11_screen, name))
2115     return 0;
2116 
2117   XGetWindowProperty (x11_screen->xdisplay,
2118                       GDK_SURFACE_XID (surface),
2119                       gdk_x11_get_xatom_by_name_for_display (GDK_SURFACE_DISPLAY (surface), name),
2120                       0, G_MAXLONG,
2121                       False, XA_CARDINAL, &type, &format, &nitems,
2122                       &bytes_after, &data);
2123   if (type == XA_CARDINAL)
2124     {
2125       prop = *(gulong *)data;
2126       XFree (data);
2127     }
2128 
2129   return prop;
2130 }
2131 
2132 /**
2133  * gdk_x11_surface_get_desktop:
2134  * @surface: (type GdkX11Surface): a `GdkSurface`
2135  *
2136  * Gets the number of the workspace @surface is on.
2137  *
2138  * Returns: the current workspace of @surface
2139  */
2140 guint32
gdk_x11_surface_get_desktop(GdkSurface * surface)2141 gdk_x11_surface_get_desktop (GdkSurface *surface)
2142 {
2143   g_return_val_if_fail (GDK_IS_SURFACE (surface), 0);
2144 
2145   return get_netwm_cardinal_property (surface, "_NET_WM_DESKTOP");
2146 }
2147 
2148 /**
2149  * gdk_x11_surface_move_to_desktop:
2150  * @surface: (type GdkX11Surface): a `GdkSurface`
2151  * @desktop: the number of the workspace to move the surface to
2152  *
2153  * Moves the surface to the given workspace when running unde a
2154  * window manager that supports multiple workspaces, as described
2155  * in the [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec) specification.
2156  */
2157 void
gdk_x11_surface_move_to_desktop(GdkSurface * surface,guint32 desktop)2158 gdk_x11_surface_move_to_desktop (GdkSurface *surface,
2159                                 guint32    desktop)
2160 {
2161   const char *atom_name = "_NET_WM_DESKTOP";
2162   XClientMessageEvent xclient;
2163 
2164   g_return_if_fail (GDK_IS_SURFACE (surface));
2165 
2166   if (!gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (surface), atom_name))
2167     return;
2168 
2169   memset (&xclient, 0, sizeof (xclient));
2170   xclient.type = ClientMessage;
2171   xclient.serial = 0;
2172   xclient.send_event = True;
2173   xclient.window = GDK_SURFACE_XID (surface);
2174   xclient.message_type = gdk_x11_get_xatom_by_name_for_display (GDK_SURFACE_DISPLAY (surface), atom_name);
2175   xclient.format = 32;
2176 
2177   xclient.data.l[0] = desktop;
2178   xclient.data.l[1] = 1; /* source indication */
2179   xclient.data.l[2] = 0;
2180   xclient.data.l[3] = 0;
2181   xclient.data.l[4] = 0;
2182 
2183   XSendEvent (GDK_SURFACE_XDISPLAY (surface),
2184               GDK_SURFACE_XROOTWIN (surface),
2185               False,
2186               SubstructureRedirectMask | SubstructureNotifyMask,
2187               (XEvent *)&xclient);
2188 }
2189 
2190 static void
gdk_x11_surface_focus(GdkSurface * surface,guint32 timestamp)2191 gdk_x11_surface_focus (GdkSurface *surface,
2192 		      guint32    timestamp)
2193 {
2194   GdkDisplay *display;
2195 
2196   g_return_if_fail (GDK_IS_SURFACE (surface));
2197 
2198   if (GDK_SURFACE_DESTROYED (surface))
2199     return;
2200 
2201   display = GDK_SURFACE_DISPLAY (surface);
2202 
2203   if (gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (surface),
2204 					   g_intern_static_string ("_NET_ACTIVE_WINDOW")))
2205     {
2206       XClientMessageEvent xclient;
2207 
2208       memset (&xclient, 0, sizeof (xclient));
2209       xclient.type = ClientMessage;
2210       xclient.window = GDK_SURFACE_XID (surface);
2211       xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
2212                                                                     "_NET_ACTIVE_WINDOW");
2213       xclient.format = 32;
2214       xclient.data.l[0] = 1; /* requestor type; we're an app */
2215       xclient.data.l[1] = timestamp;
2216       xclient.data.l[2] = None; /* currently active window */
2217       xclient.data.l[3] = 0;
2218       xclient.data.l[4] = 0;
2219 
2220       XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XROOTWIN (surface), False,
2221                   SubstructureRedirectMask | SubstructureNotifyMask,
2222                   (XEvent *)&xclient);
2223     }
2224   else
2225     {
2226       XRaiseWindow (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (surface));
2227 
2228       /* There is no way of knowing reliably whether we are viewable;
2229        * so trap errors asynchronously around the XSetInputFocus call
2230        */
2231       gdk_x11_display_error_trap_push (display);
2232       XSetInputFocus (GDK_DISPLAY_XDISPLAY (display),
2233                       GDK_SURFACE_XID (surface),
2234                       RevertToParent,
2235                       timestamp);
2236       gdk_x11_display_error_trap_pop_ignored (display);
2237     }
2238 }
2239 
2240 static void
gdk_x11_surface_set_type_hint(GdkSurface * surface,GdkSurfaceTypeHint hint)2241 gdk_x11_surface_set_type_hint (GdkSurface        *surface,
2242 			      GdkSurfaceTypeHint hint)
2243 {
2244   GdkDisplay *display;
2245   Atom atom;
2246 
2247   if (GDK_SURFACE_DESTROYED (surface))
2248     return;
2249 
2250   display = gdk_surface_get_display (surface);
2251 
2252   switch (hint)
2253     {
2254     case GDK_SURFACE_TYPE_HINT_DIALOG:
2255       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DIALOG");
2256       break;
2257     case GDK_SURFACE_TYPE_HINT_MENU:
2258       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_MENU");
2259       break;
2260     case GDK_SURFACE_TYPE_HINT_TOOLBAR:
2261       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLBAR");
2262       break;
2263     case GDK_SURFACE_TYPE_HINT_UTILITY:
2264       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_UTILITY");
2265       break;
2266     case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
2267       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_SPLASH");
2268       break;
2269     case GDK_SURFACE_TYPE_HINT_DOCK:
2270       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DOCK");
2271       break;
2272     case GDK_SURFACE_TYPE_HINT_DESKTOP:
2273       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DESKTOP");
2274       break;
2275     case GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU:
2276       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU");
2277       break;
2278     case GDK_SURFACE_TYPE_HINT_POPUP_MENU:
2279       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_POPUP_MENU");
2280       break;
2281     case GDK_SURFACE_TYPE_HINT_TOOLTIP:
2282       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLTIP");
2283       break;
2284     case GDK_SURFACE_TYPE_HINT_NOTIFICATION:
2285       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_NOTIFICATION");
2286       break;
2287     case GDK_SURFACE_TYPE_HINT_COMBO:
2288       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_COMBO");
2289       break;
2290     case GDK_SURFACE_TYPE_HINT_DND:
2291       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DND");
2292       break;
2293     default:
2294       g_warning ("Unknown hint %d passed to gdk_surface_set_type_hint", hint);
2295       G_GNUC_FALLTHROUGH;
2296     case GDK_SURFACE_TYPE_HINT_NORMAL:
2297       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_NORMAL");
2298       break;
2299     }
2300 
2301   XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (surface),
2302 		   gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE"),
2303 		   XA_ATOM, 32, PropModeReplace,
2304 		   (guchar *)&atom, 1);
2305 }
2306 
2307 static void
gdk_wmspec_change_state(gboolean add,GdkSurface * surface,const char * state1,const char * state2)2308 gdk_wmspec_change_state (gboolean    add,
2309 			 GdkSurface *surface,
2310 			 const char *state1,
2311 			 const char *state2)
2312 {
2313   GdkDisplay *display = GDK_SURFACE_DISPLAY (surface);
2314   XClientMessageEvent xclient;
2315 
2316 #define _NET_WM_STATE_REMOVE        0    /* remove/unset property */
2317 #define _NET_WM_STATE_ADD           1    /* add/set property */
2318 #define _NET_WM_STATE_TOGGLE        2    /* toggle property  */
2319 
2320   memset (&xclient, 0, sizeof (xclient));
2321   xclient.type = ClientMessage;
2322   xclient.window = GDK_SURFACE_XID (surface);
2323   xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE");
2324   xclient.format = 32;
2325   xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
2326   xclient.data.l[1] = gdk_x11_get_xatom_by_name_for_display (display, state1);
2327   xclient.data.l[2] = gdk_x11_get_xatom_by_name_for_display (display, state2);
2328   xclient.data.l[3] = 1; /* source indication */
2329   xclient.data.l[4] = 0;
2330 
2331   XSendEvent (GDK_SURFACE_XDISPLAY (surface), GDK_SURFACE_XROOTWIN (surface), False,
2332 	      SubstructureRedirectMask | SubstructureNotifyMask,
2333 	      (XEvent *)&xclient);
2334 }
2335 
2336 static void
gdk_x11_surface_set_modal_hint(GdkSurface * surface,gboolean modal)2337 gdk_x11_surface_set_modal_hint (GdkSurface *surface,
2338 			       gboolean   modal)
2339 {
2340   if (GDK_SURFACE_DESTROYED (surface))
2341     return;
2342 
2343   surface->modal_hint = modal;
2344 
2345   if (GDK_SURFACE_IS_MAPPED (surface))
2346     gdk_wmspec_change_state (modal, surface,
2347 			     "_NET_WM_STATE_MODAL",
2348 			     NULL);
2349 }
2350 
2351 /**
2352  * gdk_x11_surface_set_skip_taskbar_hint:
2353  * @surface: (type GdkX11Surface): a native `GdkSurface`
2354  * @skips_taskbar: %TRUE to skip taskbars
2355  *
2356  * Sets a hint on @surface that taskbars should not
2357  * display it. See the EWMH for details.
2358  */
2359 void
gdk_x11_surface_set_skip_taskbar_hint(GdkSurface * surface,gboolean skips_taskbar)2360 gdk_x11_surface_set_skip_taskbar_hint (GdkSurface *surface,
2361                                        gboolean    skips_taskbar)
2362 {
2363   GdkToplevelX11 *toplevel;
2364 
2365   if (GDK_SURFACE_DESTROYED (surface))
2366     return;
2367 
2368   toplevel = _gdk_x11_surface_get_toplevel (surface);
2369   toplevel->skip_taskbar_hint = skips_taskbar;
2370 
2371   if (GDK_SURFACE_IS_MAPPED (surface))
2372     gdk_wmspec_change_state (skips_taskbar, surface,
2373 			     "_NET_WM_STATE_SKIP_TASKBAR",
2374 			     NULL);
2375 }
2376 
2377 /**
2378  * gdk_x11_surface_set_skip_pager_hint:
2379  * @surface: (type GdkX11Surface): a `GdkSurface`
2380  * @skips_pager: %TRUE to skip pagers
2381  *
2382  * Sets a hint on @surface that pagers should not
2383  * display it. See the EWMH for details.
2384  */
2385 void
gdk_x11_surface_set_skip_pager_hint(GdkSurface * surface,gboolean skips_pager)2386 gdk_x11_surface_set_skip_pager_hint (GdkSurface *surface,
2387                                      gboolean    skips_pager)
2388 {
2389   GdkToplevelX11 *toplevel;
2390 
2391   if (GDK_SURFACE_DESTROYED (surface))
2392     return;
2393 
2394   toplevel = _gdk_x11_surface_get_toplevel (surface);
2395   toplevel->skip_pager_hint = skips_pager;
2396 
2397   if (GDK_SURFACE_IS_MAPPED (surface))
2398     gdk_wmspec_change_state (skips_pager, surface,
2399 			     "_NET_WM_STATE_SKIP_PAGER",
2400 			     NULL);
2401 }
2402 
2403 /**
2404  * gdk_x11_surface_set_urgency_hint:
2405  * @surface: (type GdkX11Surface): a native `GdkSurface`
2406  * @urgent: %TRUE to indicate urgenct attention needed
2407  *
2408  * Sets a hint on @surface that it needs user attention.
2409  * See the ICCCM for details.
2410  */
2411 void
gdk_x11_surface_set_urgency_hint(GdkSurface * surface,gboolean urgent)2412 gdk_x11_surface_set_urgency_hint (GdkSurface *surface,
2413                                   gboolean    urgent)
2414 {
2415   GdkToplevelX11 *toplevel;
2416 
2417   if (GDK_SURFACE_DESTROYED (surface))
2418     return;
2419 
2420   toplevel = _gdk_x11_surface_get_toplevel (surface);
2421   toplevel->urgency_hint = urgent;
2422 
2423   update_wm_hints (surface, FALSE);
2424 }
2425 
2426 static void
gdk_x11_surface_set_geometry_hints(GdkSurface * surface,const GdkGeometry * geometry,GdkSurfaceHints geom_mask)2427 gdk_x11_surface_set_geometry_hints (GdkSurface         *surface,
2428 				   const GdkGeometry *geometry,
2429 				   GdkSurfaceHints     geom_mask)
2430 {
2431   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
2432   XSizeHints size_hints;
2433   GdkToplevelX11 *toplevel;
2434 
2435   if (GDK_SURFACE_DESTROYED (surface))
2436     return;
2437 
2438   toplevel = _gdk_x11_surface_get_toplevel (surface);
2439   if (toplevel)
2440     {
2441       if (geometry)
2442         toplevel->last_geometry_hints = *geometry;
2443       toplevel->last_geometry_hints_mask = geom_mask;
2444     }
2445 
2446   size_hints.flags = 0;
2447 
2448   if (geom_mask & GDK_HINT_MIN_SIZE)
2449     {
2450       size_hints.flags |= PMinSize;
2451       size_hints.min_width = geometry->min_width * impl->surface_scale;
2452       size_hints.min_height = geometry->min_height * impl->surface_scale;
2453     }
2454 
2455   if (geom_mask & GDK_HINT_MAX_SIZE)
2456     {
2457       size_hints.flags |= PMaxSize;
2458       size_hints.max_width = MAX (geometry->max_width, 1) * impl->surface_scale;
2459       size_hints.max_height = MAX (geometry->max_height, 1) * impl->surface_scale;
2460     }
2461 
2462   else if (impl->surface_scale > 1)
2463     {
2464       size_hints.flags |= PResizeInc;
2465       size_hints.width_inc = impl->surface_scale;
2466       size_hints.height_inc = impl->surface_scale;
2467     }
2468 
2469   /* FIXME: Would it be better to delete this property if
2470    *        geom_mask == 0? It would save space on the server
2471    */
2472   XSetWMNormalHints (GDK_SURFACE_XDISPLAY (surface),
2473 		     GDK_SURFACE_XID (surface),
2474 		     &size_hints);
2475 }
2476 
2477 static void
gdk_surface_get_geometry_hints(GdkSurface * surface,GdkGeometry * geometry,GdkSurfaceHints * geom_mask)2478 gdk_surface_get_geometry_hints (GdkSurface      *surface,
2479                                GdkGeometry    *geometry,
2480                                GdkSurfaceHints *geom_mask)
2481 {
2482   GdkX11Surface *impl;
2483   XSizeHints *size_hints;
2484   glong junk_supplied_mask = 0;
2485 
2486   g_return_if_fail (GDK_IS_SURFACE (surface));
2487   g_return_if_fail (geometry != NULL);
2488   g_return_if_fail (geom_mask != NULL);
2489 
2490   *geom_mask = 0;
2491 
2492   if (GDK_SURFACE_DESTROYED (surface))
2493     return;
2494 
2495   impl = GDK_X11_SURFACE (surface);
2496 
2497   size_hints = XAllocSizeHints ();
2498   if (!size_hints)
2499     return;
2500 
2501   if (!XGetWMNormalHints (GDK_SURFACE_XDISPLAY (surface),
2502                           GDK_SURFACE_XID (surface),
2503                           size_hints,
2504                           &junk_supplied_mask))
2505     size_hints->flags = 0;
2506 
2507   if (size_hints->flags & PMinSize)
2508     {
2509       *geom_mask |= GDK_HINT_MIN_SIZE;
2510       geometry->min_width = size_hints->min_width / impl->surface_scale;
2511       geometry->min_height = size_hints->min_height / impl->surface_scale;
2512     }
2513 
2514   if (size_hints->flags & PMaxSize)
2515     {
2516       *geom_mask |= GDK_HINT_MAX_SIZE;
2517       geometry->max_width = MAX (size_hints->max_width, 1) / impl->surface_scale;
2518       geometry->max_height = MAX (size_hints->max_height, 1) / impl->surface_scale;
2519     }
2520 
2521   XFree (size_hints);
2522 }
2523 
2524 static gboolean
utf8_is_latin1(const char * str)2525 utf8_is_latin1 (const char *str)
2526 {
2527   const char *p = str;
2528 
2529   while (*p)
2530     {
2531       gunichar ch = g_utf8_get_char (p);
2532 
2533       if (ch > 0xff)
2534 	return FALSE;
2535 
2536       p = g_utf8_next_char (p);
2537     }
2538 
2539   return TRUE;
2540 }
2541 
2542 /* Set the property to @utf8_str as STRING if the @utf8_str is fully
2543  * convertible to STRING, otherwise, set it as compound text
2544  */
2545 static void
set_text_property(GdkDisplay * display,Window xwindow,Atom property,const char * utf8_str)2546 set_text_property (GdkDisplay  *display,
2547 		   Window       xwindow,
2548 		   Atom         property,
2549 		   const char *utf8_str)
2550 {
2551   char *prop_text = NULL;
2552   Atom prop_type;
2553   int prop_length;
2554   int prop_format;
2555   gboolean is_compound_text;
2556 
2557   if (utf8_is_latin1 (utf8_str))
2558     {
2559       prop_type = XA_STRING;
2560       prop_text = gdk_x11_utf8_to_string_target (utf8_str, TRUE);
2561       prop_length = prop_text ? strlen (prop_text) : 0;
2562       prop_format = 8;
2563       is_compound_text = FALSE;
2564     }
2565   else
2566     {
2567       const char *gdk_type;
2568 
2569       gdk_x11_display_utf8_to_compound_text (display,
2570                                              utf8_str, &gdk_type, &prop_format,
2571                                              (guchar **)&prop_text, &prop_length);
2572       prop_type = gdk_x11_get_xatom_by_name_for_display (display, gdk_type);
2573       is_compound_text = TRUE;
2574     }
2575 
2576   if (prop_text)
2577     {
2578       XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
2579 		       xwindow,
2580 		       property,
2581 		       prop_type, prop_format,
2582 		       PropModeReplace, (guchar *)prop_text,
2583 		       prop_length);
2584 
2585       if (is_compound_text)
2586 	gdk_x11_free_compound_text ((guchar *)prop_text);
2587       else
2588 	g_free (prop_text);
2589     }
2590 }
2591 
2592 /* Set WM_NAME and _NET_WM_NAME
2593  */
2594 static void
set_wm_name(GdkDisplay * display,Window xwindow,const char * name)2595 set_wm_name (GdkDisplay  *display,
2596 	     Window       xwindow,
2597 	     const char *name)
2598 {
2599   XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
2600 		   gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME"),
2601 		   gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
2602 		   PropModeReplace, (guchar *)name, strlen (name));
2603 
2604   set_text_property (display, xwindow,
2605 		     gdk_x11_get_xatom_by_name_for_display (display, "WM_NAME"),
2606 		     name);
2607 }
2608 
2609 static void
gdk_x11_surface_set_title(GdkSurface * surface,const char * title)2610 gdk_x11_surface_set_title (GdkSurface   *surface,
2611 			  const char *title)
2612 {
2613   GdkDisplay *display;
2614   Display *xdisplay;
2615   Window xwindow;
2616 
2617   g_return_if_fail (title != NULL);
2618 
2619   if (GDK_SURFACE_DESTROYED (surface))
2620     return;
2621 
2622   display = gdk_surface_get_display (surface);
2623   xdisplay = GDK_DISPLAY_XDISPLAY (display);
2624   xwindow = GDK_SURFACE_XID (surface);
2625 
2626   set_wm_name (display, xwindow, title);
2627 
2628   if (!gdk_surface_icon_name_set (surface))
2629     {
2630       XChangeProperty (xdisplay, xwindow,
2631 		       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"),
2632 		       gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
2633 		       PropModeReplace, (guchar *)title, strlen (title));
2634 
2635       set_text_property (display, xwindow,
2636 			 gdk_x11_get_xatom_by_name_for_display (display, "WM_ICON_NAME"),
2637 			 title);
2638     }
2639 }
2640 
2641 static void
gdk_x11_surface_set_startup_id(GdkSurface * surface,const char * startup_id)2642 gdk_x11_surface_set_startup_id (GdkSurface   *surface,
2643 			       const char *startup_id)
2644 {
2645   GdkDisplay *display;
2646 
2647   g_return_if_fail (GDK_IS_SURFACE (surface));
2648 
2649   display = gdk_surface_get_display (surface);
2650 
2651   if (GDK_SURFACE_DESTROYED (surface))
2652     return;
2653 
2654   if (startup_id)
2655     XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (surface),
2656                      gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"),
2657                      gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
2658                      PropModeReplace, (unsigned char *)startup_id, strlen (startup_id));
2659   else
2660     XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (surface),
2661                      gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"));
2662 }
2663 
2664 static void
gdk_x11_surface_set_transient_for(GdkSurface * surface,GdkSurface * parent)2665 gdk_x11_surface_set_transient_for (GdkSurface *surface,
2666 				  GdkSurface *parent)
2667 {
2668   if (GDK_SURFACE_DESTROYED (surface))
2669     return;
2670 
2671   /* XSetTransientForHint() doesn't allow unsetting, so do it manually */
2672   if (parent && !GDK_SURFACE_DESTROYED (parent))
2673     {
2674       XSetTransientForHint (GDK_SURFACE_XDISPLAY (surface),
2675                             GDK_SURFACE_XID (surface),
2676                             GDK_SURFACE_XID (parent));
2677       gdk_x11_surface_set_type_hint (surface, GDK_SURFACE_TYPE_HINT_DIALOG);
2678     }
2679   else
2680     {
2681       XDeleteProperty (GDK_SURFACE_XDISPLAY (surface),
2682                        GDK_SURFACE_XID (surface),
2683                        gdk_x11_get_xatom_by_name_for_display (GDK_SURFACE_DISPLAY (surface), "WM_TRANSIENT_FOR"));
2684       gdk_x11_surface_set_type_hint (surface, GDK_SURFACE_TYPE_HINT_NORMAL);
2685     }
2686 }
2687 
2688 GdkCursor *
_gdk_x11_surface_get_cursor(GdkSurface * surface)2689 _gdk_x11_surface_get_cursor (GdkSurface *surface)
2690 {
2691   GdkX11Surface *impl;
2692 
2693   g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL);
2694 
2695   impl = GDK_X11_SURFACE (surface);
2696 
2697   return impl->cursor;
2698 }
2699 
2700 static void
gdk_x11_surface_get_geometry(GdkSurface * surface,int * x,int * y,int * width,int * height)2701 gdk_x11_surface_get_geometry (GdkSurface *surface,
2702                              int       *x,
2703                              int       *y,
2704                              int       *width,
2705                              int       *height)
2706 {
2707   GdkX11Surface *impl;
2708   Window root;
2709   int tx;
2710   int ty;
2711   guint twidth;
2712   guint theight;
2713   guint tborder_width;
2714   guint tdepth;
2715 
2716   if (!GDK_SURFACE_DESTROYED (surface))
2717     {
2718       impl = GDK_X11_SURFACE (surface);
2719 
2720       XGetGeometry (GDK_SURFACE_XDISPLAY (surface),
2721 		    GDK_SURFACE_XID (surface),
2722 		    &root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth);
2723 
2724       if (x)
2725 	*x = tx / impl->surface_scale;
2726       if (y)
2727 	*y = ty / impl->surface_scale;
2728       if (width)
2729 	*width = twidth / impl->surface_scale;
2730       if (height)
2731 	*height = theight / impl->surface_scale;
2732     }
2733 }
2734 
2735 void
gdk_x11_surface_get_root_coords(GdkSurface * surface,int x,int y,int * root_x,int * root_y)2736 gdk_x11_surface_get_root_coords (GdkSurface *surface,
2737 				int        x,
2738 				int        y,
2739 				int       *root_x,
2740 				int       *root_y)
2741 {
2742   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
2743   Window child;
2744   int tx;
2745   int ty;
2746 
2747   XTranslateCoordinates (GDK_SURFACE_XDISPLAY (surface),
2748                          GDK_SURFACE_XID (surface),
2749                          GDK_SURFACE_XROOTWIN (surface),
2750                          x * impl->surface_scale, y * impl->surface_scale, &tx, &ty,
2751                          &child);
2752 
2753   if (root_x)
2754     *root_x = tx / impl->surface_scale;
2755   if (root_y)
2756     *root_y = ty / impl->surface_scale;
2757 }
2758 
2759 static void
gdk_x11_surface_get_frame_extents(GdkSurface * surface,GdkRectangle * rect)2760 gdk_x11_surface_get_frame_extents (GdkSurface    *surface,
2761                                   GdkRectangle *rect)
2762 {
2763   GdkDisplay *display;
2764   GdkX11Surface *impl;
2765   Window xwindow;
2766   Window xparent;
2767   Window root;
2768   Window child;
2769   Window *children;
2770   guchar *data;
2771   Window *vroots;
2772   Atom type_return;
2773   guint nchildren;
2774   guint nvroots;
2775   gulong nitems_return;
2776   gulong bytes_after_return;
2777   int format_return;
2778   int i;
2779   guint ww, wh, wb, wd;
2780   int wx, wy;
2781   gboolean got_frame_extents = FALSE;
2782 
2783   g_return_if_fail (rect != NULL);
2784 
2785   rect->x = 0;
2786   rect->y = 0;
2787   rect->width = 1;
2788   rect->height = 1;
2789 
2790   impl = GDK_X11_SURFACE (surface);
2791 
2792   /* Refine our fallback answer a bit using local information */
2793   rect->x = impl->abs_x * impl->surface_scale;
2794   rect->y = impl->abs_y * impl->surface_scale;
2795   rect->width = surface->width * impl->surface_scale;
2796   rect->height = surface->height * impl->surface_scale;
2797 
2798   if (GDK_SURFACE_DESTROYED (surface) || impl->override_redirect)
2799     return;
2800 
2801   nvroots = 0;
2802   vroots = NULL;
2803 
2804   display = gdk_surface_get_display (surface);
2805 
2806   gdk_x11_display_error_trap_push (display);
2807 
2808   xwindow = GDK_SURFACE_XID (surface);
2809 
2810   /* first try: use _NET_FRAME_EXTENTS */
2811   if (gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (surface),
2812                                            g_intern_static_string ("_NET_FRAME_EXTENTS")) &&
2813       XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
2814                           gdk_x11_get_xatom_by_name_for_display (display,
2815                                                                   "_NET_FRAME_EXTENTS"),
2816                           0, G_MAXLONG, False, XA_CARDINAL, &type_return,
2817                           &format_return, &nitems_return, &bytes_after_return,
2818                           &data)
2819       == Success)
2820     {
2821       if ((type_return == XA_CARDINAL) && (format_return == 32) &&
2822 	  (nitems_return == 4) && (data))
2823         {
2824 	  gulong *ldata = (gulong *) data;
2825 	  got_frame_extents = TRUE;
2826 
2827 	  /* try to get the real client window geometry */
2828 	  if (XGetGeometry (GDK_DISPLAY_XDISPLAY (display), xwindow,
2829 			    &root, &wx, &wy, &ww, &wh, &wb, &wd) &&
2830               XTranslateCoordinates (GDK_DISPLAY_XDISPLAY (display),
2831 	  			     xwindow, root, 0, 0, &wx, &wy, &child))
2832             {
2833 	      rect->x = wx;
2834 	      rect->y = wy;
2835 	      rect->width = ww;
2836 	      rect->height = wh;
2837 	    }
2838 
2839 	  /* _NET_FRAME_EXTENTS format is left, right, top, bottom */
2840 	  rect->x -= ldata[0];
2841 	  rect->y -= ldata[2];
2842 	  rect->width += ldata[0] + ldata[1];
2843 	  rect->height += ldata[2] + ldata[3];
2844 	}
2845 
2846       if (data)
2847 	XFree (data);
2848     }
2849 
2850   if (got_frame_extents)
2851     goto out;
2852 
2853   /* no frame extents property available, which means we either have a WM that
2854      is not EWMH compliant or is broken - try fallback and walk up the window
2855      tree to get our window's parent which hopefully is the window frame */
2856 
2857   /* use NETWM_VIRTUAL_ROOTS if available */
2858   root = GDK_SURFACE_XROOTWIN (surface);
2859 
2860   if (gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (surface),
2861                                            g_intern_static_string ("_NET_VIRTUAL_ROOTS")) &&
2862       XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), root,
2863 			  gdk_x11_get_xatom_by_name_for_display (display,
2864 								 "_NET_VIRTUAL_ROOTS"),
2865 			  0, G_MAXLONG, False, XA_WINDOW, &type_return,
2866 			  &format_return, &nitems_return, &bytes_after_return,
2867 			  &data)
2868       == Success)
2869     {
2870       if ((type_return == XA_WINDOW) && (format_return == 32) && (data))
2871 	{
2872 	  nvroots = nitems_return;
2873 	  vroots = (Window *)data;
2874 	}
2875     }
2876 
2877   xparent = GDK_SURFACE_XID (surface);
2878 
2879   do
2880     {
2881       xwindow = xparent;
2882 
2883       if (!XQueryTree (GDK_DISPLAY_XDISPLAY (display), xwindow,
2884 		       &root, &xparent,
2885 		       &children, &nchildren))
2886 	goto out;
2887 
2888       if (children)
2889 	XFree (children);
2890 
2891       /* check virtual roots */
2892       for (i = 0; i < nvroots; i++)
2893 	{
2894 	  if (xparent == vroots[i])
2895 	    {
2896 	      root = xparent;
2897 	      break;
2898            }
2899 	}
2900     }
2901   while (xparent != root);
2902 
2903   if (XGetGeometry (GDK_DISPLAY_XDISPLAY (display), xwindow,
2904 		    &root, &wx, &wy, &ww, &wh, &wb, &wd))
2905     {
2906       rect->x = wx;
2907       rect->y = wy;
2908       rect->width = ww;
2909       rect->height = wh;
2910     }
2911 
2912  out:
2913   if (vroots)
2914     XFree (vroots);
2915 
2916   /* Here we extend the size to include the extra pixels if we round x/y down
2917      as well as round the size up when we divide by scale so that the returned
2918      size is guaranteed to cover the real pixels, but it may overshoot a bit
2919      in case the window is not positioned/sized according to the scale */
2920   rect->width = (rect->width + rect->x % impl->surface_scale + impl->surface_scale - 1) / impl->surface_scale;
2921   rect->height = (rect->height + rect->y % impl->surface_scale + impl->surface_scale - 1) / impl->surface_scale;
2922   rect->x = rect->x / impl->surface_scale;
2923   rect->y = rect->y / impl->surface_scale;
2924   gdk_x11_display_error_trap_pop_ignored (display);
2925 }
2926 
2927 static gboolean
gdk_x11_surface_get_device_state(GdkSurface * surface,GdkDevice * device,double * x,double * y,GdkModifierType * mask)2928 gdk_x11_surface_get_device_state (GdkSurface     *surface,
2929                                   GdkDevice       *device,
2930                                   double          *x,
2931                                   double          *y,
2932                                   GdkModifierType *mask)
2933 {
2934   if (GDK_SURFACE_DESTROYED (surface))
2935     return FALSE;
2936 
2937   gdk_x11_device_xi2_query_state (device, surface, x, y, mask);
2938 
2939   return *x >= 0 && *y >= 0 && *x < surface->width && *y < surface->height;
2940 }
2941 
2942 static void
gdk_x11_surface_set_input_region(GdkSurface * surface,cairo_region_t * input_region)2943 gdk_x11_surface_set_input_region (GdkSurface     *surface,
2944                                   cairo_region_t *input_region)
2945 {
2946 #ifdef ShapeInput
2947   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
2948 
2949   if (GDK_SURFACE_DESTROYED (surface))
2950     return;
2951 
2952   if (!gdk_display_supports_input_shapes (GDK_SURFACE_DISPLAY (surface)))
2953     return;
2954 
2955   if (input_region == NULL)
2956     {
2957       XShapeCombineMask (GDK_SURFACE_XDISPLAY (surface),
2958                          GDK_SURFACE_XID (surface),
2959                          ShapeInput,
2960                          0, 0,
2961                          None,
2962                          ShapeSet);
2963       return;
2964     }
2965   else
2966     {
2967       int n_rects = 0;
2968       XRectangle *xrects = NULL;
2969 
2970       _gdk_x11_region_get_xrectangles (input_region,
2971                                        0, 0, impl->surface_scale,
2972                                        &xrects, &n_rects);
2973 
2974       XShapeCombineRectangles (GDK_SURFACE_XDISPLAY (surface),
2975                                GDK_SURFACE_XID (surface),
2976 			       ShapeInput,
2977                                0, 0,
2978                                xrects, n_rects,
2979                                ShapeSet,
2980                                YXBanded);
2981 
2982       g_free (xrects);
2983     }
2984 #endif
2985 }
2986 
2987 /**
2988  * gdk_x11_surface_set_user_time:
2989  * @surface: (type GdkX11Surface): A toplevel `GdkSurface`
2990  * @timestamp: An XServer timestamp to which the property should be set
2991  *
2992  * The application can use this call to update the _NET_WM_USER_TIME
2993  * property on a toplevel surface.  This property stores an Xserver
2994  * time which represents the time of the last user input event
2995  * received for this surface.  This property may be used by the window
2996  * manager to alter the focus, stacking, and/or placement behavior of
2997  * surfaces when they are mapped depending on whether the new surface
2998  * was created by a user action or is a "pop-up" surface activated by a
2999  * timer or some other event.
3000  *
3001  * Note that this property is automatically updated by GDK, so this
3002  * function should only be used by applications which handle input
3003  * events bypassing GDK.
3004  **/
3005 void
gdk_x11_surface_set_user_time(GdkSurface * surface,guint32 timestamp)3006 gdk_x11_surface_set_user_time (GdkSurface *surface,
3007                               guint32    timestamp)
3008 {
3009   GdkDisplay *display;
3010   GdkX11Display *display_x11;
3011   GdkToplevelX11 *toplevel;
3012   glong timestamp_long = (glong)timestamp;
3013   Window xid;
3014 
3015   if (GDK_SURFACE_DESTROYED (surface))
3016     return;
3017 
3018   display = gdk_surface_get_display (surface);
3019   display_x11 = GDK_X11_DISPLAY (display);
3020   toplevel = _gdk_x11_surface_get_toplevel (surface);
3021 
3022   if (!toplevel)
3023     {
3024       g_warning ("gdk_surface_set_user_time called on non-toplevel\n");
3025       return;
3026     }
3027 
3028   if (toplevel->focus_window != None &&
3029       gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (surface),
3030                                            g_intern_static_string ("_NET_WM_USER_TIME_WINDOW")))
3031     xid = toplevel->focus_window;
3032   else
3033     xid = GDK_SURFACE_XID (surface);
3034 
3035   XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xid,
3036                    gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_USER_TIME"),
3037                    XA_CARDINAL, 32, PropModeReplace,
3038                    (guchar *)&timestamp_long, 1);
3039 
3040   if (timestamp_long != GDK_CURRENT_TIME &&
3041       (display_x11->user_time == GDK_CURRENT_TIME ||
3042        XSERVER_TIME_IS_LATER (timestamp_long, display_x11->user_time)))
3043     display_x11->user_time = timestamp_long;
3044 
3045   if (toplevel)
3046     toplevel->user_time = timestamp_long;
3047 }
3048 
3049 /**
3050  * gdk_x11_surface_set_utf8_property:
3051  * @surface: (type GdkX11Surface): a `GdkSurface`
3052  * @name: Property name, will be interned as an X atom
3053  * @value: (nullable): Property value, or %NULL to delete
3054  *
3055  * This function modifies or removes an arbitrary X11 window
3056  * property of type UTF8_STRING.  If the given @surface is
3057  * not a toplevel surface, it is ignored.
3058  */
3059 void
gdk_x11_surface_set_utf8_property(GdkSurface * surface,const char * name,const char * value)3060 gdk_x11_surface_set_utf8_property  (GdkSurface *surface,
3061 				   const char *name,
3062 				   const char *value)
3063 {
3064   GdkDisplay *display;
3065 
3066   display = gdk_surface_get_display (surface);
3067 
3068   if (value != NULL)
3069     {
3070       XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
3071                        GDK_SURFACE_XID (surface),
3072                        gdk_x11_get_xatom_by_name_for_display (display, name),
3073                        gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
3074                        PropModeReplace, (guchar *)value, strlen (value));
3075     }
3076   else
3077     {
3078       XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
3079                        GDK_SURFACE_XID (surface),
3080                        gdk_x11_get_xatom_by_name_for_display (display, name));
3081     }
3082 }
3083 
3084 /**
3085  * gdk_x11_surface_set_theme_variant:
3086  * @surface: (type GdkX11Surface): a `GdkSurface`
3087  * @variant: the theme variant to export
3088  *
3089  * GTK applications can request a dark theme variant. In order to
3090  * make other applications - namely window managers using GTK for
3091  * themeing - aware of this choice, GTK uses this function to
3092  * export the requested theme variant as _GTK_THEME_VARIANT property
3093  * on toplevel surfaces.
3094  *
3095  * Note that this property is automatically updated by GTK, so this
3096  * function should only be used by applications which do not use GTK
3097  * to create toplevel surfaces.
3098  */
3099 void
gdk_x11_surface_set_theme_variant(GdkSurface * surface,const char * variant)3100 gdk_x11_surface_set_theme_variant (GdkSurface  *surface,
3101                                   const char *variant)
3102 {
3103   gdk_x11_surface_set_utf8_property (surface, "_GTK_THEME_VARIANT",
3104                                     variant ? variant : "");
3105 }
3106 
3107 #define GDK_SELECTION_MAX_SIZE(display)                                 \
3108   MIN(262144,                                                           \
3109       XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) == 0     \
3110        ? XMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100         \
3111        : XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100)
3112 
3113 static void
gdk_surface_update_icon(GdkSurface * surface,GList * icon_list)3114 gdk_surface_update_icon (GdkSurface *surface,
3115                         GList     *icon_list)
3116 {
3117   GdkToplevelX11 *toplevel;
3118   GdkTexture *best_icon;
3119   GList *tmp_list;
3120   int best_size;
3121 
3122   toplevel = _gdk_x11_surface_get_toplevel (surface);
3123 
3124   if (toplevel->icon_pixmap != NULL)
3125     {
3126       cairo_surface_destroy (toplevel->icon_pixmap);
3127       toplevel->icon_pixmap = NULL;
3128     }
3129 
3130   if (toplevel->icon_mask != NULL)
3131     {
3132       cairo_surface_destroy (toplevel->icon_mask);
3133       toplevel->icon_mask = NULL;
3134     }
3135 
3136 #define IDEAL_SIZE 48
3137 
3138   best_size = G_MAXINT;
3139   best_icon = NULL;
3140   for (tmp_list = icon_list; tmp_list; tmp_list = tmp_list->next)
3141     {
3142       GdkTexture *texture = tmp_list->data;
3143       int this;
3144 
3145       /* average width and height - if someone passes in a rectangular
3146        * icon they deserve what they get.
3147        */
3148       this = gdk_texture_get_width (texture) + gdk_texture_get_height (texture);
3149       this /= 2;
3150 
3151       if (best_icon == NULL)
3152         {
3153           best_icon = texture;
3154           best_size = this;
3155         }
3156       else
3157         {
3158           /* icon is better if it's 32 pixels or larger, and closer to
3159            * the ideal size than the current best.
3160            */
3161           if (this >= 32 &&
3162               (ABS (best_size - IDEAL_SIZE) <
3163                ABS (this - IDEAL_SIZE)))
3164             {
3165               best_icon = texture;
3166               best_size = this;
3167             }
3168         }
3169     }
3170 
3171   if (best_icon)
3172     {
3173       int width = gdk_texture_get_width (best_icon);
3174       int height = gdk_texture_get_height (best_icon);
3175       cairo_surface_t *cairo_surface;
3176       cairo_t *cr;
3177 
3178       toplevel->icon_pixmap = gdk_x11_surface_create_pixmap_surface (surface, width, height);
3179 
3180       cairo_surface = gdk_texture_download_surface (best_icon);
3181 
3182       cr = cairo_create (toplevel->icon_pixmap);
3183       cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3184       cairo_set_source_surface (cr, cairo_surface, 0, 0);
3185       if (cairo_surface_get_content (cairo_surface) == CAIRO_CONTENT_COLOR_ALPHA)
3186         {
3187           /* Saturate the image, so it has bilevel alpha */
3188           cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA);
3189           cairo_paint (cr);
3190           cairo_set_operator (cr, CAIRO_OPERATOR_SATURATE);
3191           cairo_paint (cr);
3192           cairo_pop_group_to_source (cr);
3193         }
3194       cairo_paint (cr);
3195       cairo_destroy (cr);
3196 
3197       if (cairo_surface_get_content (cairo_surface) == CAIRO_CONTENT_COLOR_ALPHA)
3198         {
3199           GdkDisplay *display = gdk_surface_get_display (surface);
3200 
3201           toplevel->icon_mask = _gdk_x11_display_create_bitmap_surface (display, width, height);
3202 
3203           cr = cairo_create (toplevel->icon_mask);
3204           cairo_set_source_surface (cr, cairo_surface, 0, 0);
3205           cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3206           cairo_paint (cr);
3207           cairo_destroy (cr);
3208         }
3209 
3210       cairo_surface_destroy (cairo_surface);
3211     }
3212 
3213   update_wm_hints (surface, FALSE);
3214 }
3215 
3216 static void
gdk_x11_surface_set_icon_list(GdkSurface * surface,GList * textures)3217 gdk_x11_surface_set_icon_list (GdkSurface *surface,
3218 			      GList     *textures)
3219 {
3220   gulong *data;
3221   gulong *p;
3222   int size;
3223   GList *l;
3224   int width, height;
3225   GdkTexture *texture;
3226   GdkDisplay *display;
3227   int i, n;
3228 
3229   if (GDK_SURFACE_DESTROYED (surface))
3230     return;
3231 
3232   display = gdk_surface_get_display (surface);
3233 
3234   size = 0;
3235   n = 0;
3236   for (l = textures; l != NULL; l = l->next)
3237     {
3238       texture = l->data;
3239 
3240       width = gdk_texture_get_width (texture);
3241       height = gdk_texture_get_height (texture);
3242 
3243       /* silently ignore overlarge icons */
3244       if (size + 2 + width * height > GDK_SELECTION_MAX_SIZE(display))
3245         break;
3246 
3247       n++;
3248       size += 2 + width * height;
3249     }
3250 
3251   data = g_malloc (size * sizeof (gulong));
3252 
3253   p = data;
3254   for (l = textures; l != NULL && n > 0; l = l->next)
3255     {
3256       texture = l->data;
3257 
3258       width = gdk_texture_get_width (texture);
3259       height = gdk_texture_get_height (texture);
3260 
3261       *p++ = width;
3262       *p++ = height;
3263 
3264       gdk_texture_download (texture, (guchar *) p, width * 4);
3265       if (sizeof (gulong) > 4)
3266         {
3267           i = width * height;
3268           while (i-- > 0)
3269             p[i] = ((guint32 *) p)[i];
3270         }
3271 
3272       p += width * height;
3273       n--;
3274     }
3275 
3276   if (size > 0)
3277     {
3278       XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
3279                        GDK_SURFACE_XID (surface),
3280 		       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON"),
3281                        XA_CARDINAL, 32,
3282                        PropModeReplace,
3283                        (guchar*) data, size);
3284     }
3285   else
3286     {
3287       XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
3288                        GDK_SURFACE_XID (surface),
3289 		       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON"));
3290     }
3291 
3292   g_free (data);
3293 
3294   gdk_surface_update_icon (surface, textures);
3295 }
3296 
3297 static gboolean
gdk_surface_icon_name_set(GdkSurface * surface)3298 gdk_surface_icon_name_set (GdkSurface *surface)
3299 {
3300   return GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (surface),
3301 					       g_quark_from_static_string ("gdk-icon-name-set")));
3302 }
3303 
3304 static void
gdk_x11_surface_minimize(GdkSurface * surface)3305 gdk_x11_surface_minimize (GdkSurface *surface)
3306 {
3307   if (GDK_SURFACE_DESTROYED (surface))
3308     return;
3309 
3310   if (GDK_SURFACE_IS_MAPPED (surface))
3311     {
3312       XIconifyWindow (GDK_SURFACE_XDISPLAY (surface),
3313 		      GDK_SURFACE_XID (surface),
3314 		      gdk_x11_screen_get_screen_number (GDK_SURFACE_SCREEN (surface)));
3315     }
3316   else
3317     {
3318       /* Flip our client side flag, the real work happens on map. */
3319       gdk_synthesize_surface_state (surface, 0, GDK_TOPLEVEL_STATE_MINIMIZED);
3320       gdk_wmspec_change_state (TRUE, surface,
3321                                "_NET_WM_STATE_HIDDEN",
3322                                NULL);
3323     }
3324 }
3325 
3326 static void
gdk_x11_surface_unminimize(GdkSurface * surface)3327 gdk_x11_surface_unminimize (GdkSurface *surface)
3328 {
3329   if (GDK_SURFACE_DESTROYED (surface))
3330     return;
3331 
3332   if (GDK_SURFACE_IS_MAPPED (surface))
3333     {
3334       gdk_x11_surface_show (surface, TRUE);
3335       gdk_wmspec_change_state (FALSE, surface,
3336                                "_NET_WM_STATE_HIDDEN",
3337                                NULL);
3338     }
3339   else
3340     {
3341       /* Flip our client side flag, the real work happens on map. */
3342       gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_MINIMIZED, 0);
3343       gdk_wmspec_change_state (FALSE, surface,
3344                                "_NET_WM_STATE_HIDDEN",
3345                                NULL);
3346     }
3347 }
3348 
3349 static void
gdk_x11_surface_maximize(GdkSurface * surface)3350 gdk_x11_surface_maximize (GdkSurface *surface)
3351 {
3352   if (GDK_SURFACE_DESTROYED (surface))
3353     return;
3354 
3355   if (GDK_SURFACE_IS_MAPPED (surface))
3356     gdk_wmspec_change_state (TRUE, surface,
3357 			     "_NET_WM_STATE_MAXIMIZED_VERT",
3358 			     "_NET_WM_STATE_MAXIMIZED_HORZ");
3359   else
3360     gdk_synthesize_surface_state (surface,
3361 				 0,
3362 				 GDK_TOPLEVEL_STATE_MAXIMIZED);
3363 }
3364 
3365 static void
gdk_x11_surface_unmaximize(GdkSurface * surface)3366 gdk_x11_surface_unmaximize (GdkSurface *surface)
3367 {
3368   if (GDK_SURFACE_DESTROYED (surface))
3369     return;
3370 
3371   if (GDK_SURFACE_IS_MAPPED (surface))
3372     gdk_wmspec_change_state (FALSE, surface,
3373 			     "_NET_WM_STATE_MAXIMIZED_VERT",
3374 			     "_NET_WM_STATE_MAXIMIZED_HORZ");
3375   else
3376     gdk_synthesize_surface_state (surface,
3377 				 GDK_TOPLEVEL_STATE_MAXIMIZED,
3378 				 0);
3379 }
3380 
3381 static void
gdk_x11_surface_apply_fullscreen_mode(GdkSurface * surface)3382 gdk_x11_surface_apply_fullscreen_mode (GdkSurface *surface)
3383 {
3384   if (GDK_SURFACE_DESTROYED (surface))
3385     return;
3386 
3387   /* _NET_WM_FULLSCREEN_MONITORS gives an indication to the window manager as
3388    * to which monitors so span across when the surface is fullscreen, but it's
3389    * not a state in itself so this would have no effect if the surface is not
3390    * mapped.
3391    */
3392 
3393   if (GDK_SURFACE_IS_MAPPED (surface))
3394     {
3395       XClientMessageEvent xclient;
3396       int                 monitors[4];
3397       int                 i;
3398 
3399       memset (&xclient, 0, sizeof (xclient));
3400       xclient.type = ClientMessage;
3401       xclient.window = GDK_SURFACE_XID (surface);
3402       xclient.display = GDK_SURFACE_XDISPLAY (surface);
3403       xclient.format = 32;
3404 
3405       switch (surface->fullscreen_mode)
3406 	{
3407 	case GDK_FULLSCREEN_ON_CURRENT_MONITOR:
3408 
3409 	  /* FIXME: This is not part of the EWMH spec!
3410 	   *
3411 	   * There is no documented mechanism to remove the property
3412 	   * _NET_WM_FULLSCREEN_MONITORS once set, so we use a set of
3413 	   * invalid, largest possible value.
3414 	   *
3415 	   * When given values larger than actual possible monitor values, most
3416 	   * window managers who support the _NET_WM_FULLSCREEN_MONITORS spec
3417 	   * will simply unset _NET_WM_FULLSCREEN_MONITORS and revert to their
3418 	   * default behavior.
3419 	   *
3420 	   * Successfully tested on mutter/metacity, kwin, compiz and xfwm4.
3421 	   *
3422 	   * Note, this (non documented) mechanism is unlikely to be an issue
3423 	   * as it's used only for transitionning back from "all monitors" to
3424 	   * "current monitor" mode.
3425 	   *
3426 	   * Applications who don't change the default mode won't trigger this
3427 	   * mechanism.
3428 	   */
3429 	  for (i = 0; i < 4; ++i)
3430 	    xclient.data.l[i] = G_MAXLONG;
3431 
3432 	  break;
3433 
3434 	case GDK_FULLSCREEN_ON_ALL_MONITORS:
3435 
3436 	  _gdk_x11_screen_get_edge_monitors (GDK_SURFACE_SCREEN (surface),
3437 					     &monitors[0],
3438 					     &monitors[1],
3439 					     &monitors[2],
3440 					     &monitors[3]);
3441 	  /* Translate all 4 monitors from the GDK set into XINERAMA indices */
3442 	  for (i = 0; i < 4; ++i)
3443 	    {
3444 	      xclient.data.l[i] = monitors[i];
3445 	      /* Sanity check, if XINERAMA is not available, we could have invalid
3446 	       * negative values for the XINERAMA indices.
3447 	       */
3448 	      if (xclient.data.l[i] < 0)
3449 		{
3450 		  g_warning ("gdk_x11_surface_apply_fullscreen_mode: Invalid XINERAMA monitor index");
3451 		  return;
3452 		}
3453 	    }
3454 	  break;
3455 
3456 	default:
3457 	  g_warning ("gdk_x11_surface_apply_fullscreen_mode: Unhandled fullscreen mode %d",
3458 		     surface->fullscreen_mode);
3459 	  return;
3460 	}
3461 
3462       /* Send fullscreen monitors client message */
3463       xclient.data.l[4] = 1; /* source indication */
3464       xclient.message_type = gdk_x11_get_xatom_by_name_for_display (GDK_SURFACE_DISPLAY (surface),
3465 								    "_NET_WM_FULLSCREEN_MONITORS");
3466       XSendEvent (GDK_SURFACE_XDISPLAY (surface), GDK_SURFACE_XROOTWIN (surface), False,
3467                   SubstructureRedirectMask | SubstructureNotifyMask,
3468                   (XEvent *)&xclient);
3469     }
3470 }
3471 
3472 static void
gdk_x11_surface_fullscreen(GdkSurface * surface)3473 gdk_x11_surface_fullscreen (GdkSurface *surface)
3474 {
3475   if (GDK_SURFACE_DESTROYED (surface))
3476     return;
3477 
3478   if (GDK_SURFACE_IS_MAPPED (surface))
3479     {
3480       gdk_wmspec_change_state (TRUE, surface,
3481 			       "_NET_WM_STATE_FULLSCREEN",
3482                                NULL);
3483       /* Actual XRandR layout may have change since we computed the fullscreen
3484        * monitors in GDK_FULLSCREEN_ON_ALL_MONITORS mode.
3485        */
3486       if (surface->fullscreen_mode == GDK_FULLSCREEN_ON_ALL_MONITORS)
3487 	gdk_x11_surface_apply_fullscreen_mode (surface);
3488     }
3489   else
3490     gdk_synthesize_surface_state (surface,
3491                                  0,
3492                                  GDK_TOPLEVEL_STATE_FULLSCREEN);
3493 }
3494 
3495 static void
gdk_x11_surface_fullscreen_on_monitor(GdkSurface * surface,GdkMonitor * monitor)3496 gdk_x11_surface_fullscreen_on_monitor (GdkSurface  *surface,
3497                                       GdkMonitor *monitor)
3498 {
3499   GdkRectangle geom;
3500 
3501   if (GDK_SURFACE_DESTROYED (surface))
3502     return;
3503 
3504   gdk_monitor_get_geometry (monitor, &geom);
3505   gdk_x11_surface_move (surface, geom.x, geom.y);
3506 
3507   surface->fullscreen_mode = GDK_FULLSCREEN_ON_CURRENT_MONITOR;
3508   g_object_notify (G_OBJECT (surface), "fullscreen-mode");
3509   gdk_x11_surface_fullscreen (surface);
3510 }
3511 
3512 static void
gdk_x11_surface_unfullscreen(GdkSurface * surface)3513 gdk_x11_surface_unfullscreen (GdkSurface *surface)
3514 {
3515   if (GDK_SURFACE_DESTROYED (surface))
3516     return;
3517 
3518   if (GDK_SURFACE_IS_MAPPED (surface))
3519     gdk_wmspec_change_state (FALSE, surface,
3520 			     "_NET_WM_STATE_FULLSCREEN",
3521                              NULL);
3522 
3523   else
3524     gdk_synthesize_surface_state (surface,
3525 				 GDK_TOPLEVEL_STATE_FULLSCREEN,
3526 				 0);
3527 }
3528 
3529 /**
3530  * gdk_x11_surface_get_group:
3531  * @surface: (type GdkX11Surface): The `GdkSurface`
3532  *
3533  * Returns the group this surface belongs to.
3534  *
3535  * Returns: (transfer none): The group of this surface;
3536  */
3537 GdkSurface *
gdk_x11_surface_get_group(GdkSurface * surface)3538 gdk_x11_surface_get_group (GdkSurface *surface)
3539 {
3540   GdkToplevelX11 *toplevel;
3541 
3542   if (GDK_SURFACE_DESTROYED (surface))
3543     return NULL;
3544 
3545   toplevel = _gdk_x11_surface_get_toplevel (surface);
3546 
3547   return toplevel->group_leader;
3548 }
3549 
3550 /**
3551  * gdk_x11_surface_set_group:
3552  * @surface: (type GdkX11Surface): a native `GdkSurface`
3553  * @leader: a `GdkSurface`
3554  *
3555  * Sets the group leader of @surface to be @leader.
3556  * See the ICCCM for details.
3557  */
3558 void
gdk_x11_surface_set_group(GdkSurface * surface,GdkSurface * leader)3559 gdk_x11_surface_set_group (GdkSurface *surface,
3560                            GdkSurface *leader)
3561 {
3562   GdkToplevelX11 *toplevel;
3563 
3564   g_return_if_fail (GDK_IS_SURFACE (surface));
3565   g_return_if_fail (leader == NULL || GDK_IS_SURFACE (leader));
3566 
3567   if (GDK_SURFACE_DESTROYED (surface) ||
3568       (leader != NULL && GDK_SURFACE_DESTROYED (leader)))
3569     return;
3570 
3571   toplevel = _gdk_x11_surface_get_toplevel (surface);
3572 
3573   if (leader == NULL)
3574     leader = gdk_x11_display_get_default_group (gdk_surface_get_display (surface));
3575 
3576   if (toplevel->group_leader != leader)
3577     {
3578       if (toplevel->group_leader)
3579 	g_object_unref (toplevel->group_leader);
3580       toplevel->group_leader = g_object_ref (leader);
3581       (_gdk_x11_surface_get_toplevel (leader))->is_leader = TRUE;
3582     }
3583 
3584   update_wm_hints (surface, FALSE);
3585 }
3586 
3587 static MotifWmHints *
gdk_surface_get_mwm_hints(GdkSurface * surface)3588 gdk_surface_get_mwm_hints (GdkSurface *surface)
3589 {
3590   GdkDisplay *display;
3591   Atom hints_atom = None;
3592   guchar *data;
3593   Atom type;
3594   int format;
3595   gulong nitems;
3596   gulong bytes_after;
3597 
3598   if (GDK_SURFACE_DESTROYED (surface))
3599     return NULL;
3600 
3601   display = gdk_surface_get_display (surface);
3602 
3603   hints_atom = gdk_x11_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS);
3604 
3605   XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (surface),
3606 		      hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
3607 		      False, AnyPropertyType, &type, &format, &nitems,
3608 		      &bytes_after, &data);
3609 
3610   if (type == None)
3611     return NULL;
3612 
3613   return (MotifWmHints *)data;
3614 }
3615 
3616 static void
gdk_surface_set_mwm_hints(GdkSurface * surface,MotifWmHints * new_hints)3617 gdk_surface_set_mwm_hints (GdkSurface *surface,
3618 			  MotifWmHints *new_hints)
3619 {
3620   GdkDisplay *display;
3621   Atom hints_atom = None;
3622   guchar *data;
3623   MotifWmHints *hints;
3624   Atom type;
3625   int format;
3626   gulong nitems;
3627   gulong bytes_after;
3628 
3629   if (GDK_SURFACE_DESTROYED (surface))
3630     return;
3631 
3632   display = gdk_surface_get_display (surface);
3633 
3634   hints_atom = gdk_x11_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS);
3635 
3636   XGetWindowProperty (GDK_SURFACE_XDISPLAY (surface), GDK_SURFACE_XID (surface),
3637 		      hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
3638 		      False, AnyPropertyType, &type, &format, &nitems,
3639 		      &bytes_after, &data);
3640 
3641   if (type == None)
3642     hints = new_hints;
3643   else
3644     {
3645       hints = (MotifWmHints *)data;
3646 
3647       if (new_hints->flags & MWM_HINTS_FUNCTIONS)
3648 	{
3649 	  hints->flags |= MWM_HINTS_FUNCTIONS;
3650 	  hints->functions = new_hints->functions;
3651 	}
3652       if (new_hints->flags & MWM_HINTS_DECORATIONS)
3653 	{
3654 	  hints->flags |= MWM_HINTS_DECORATIONS;
3655 	  hints->decorations = new_hints->decorations;
3656 	}
3657     }
3658 
3659   XChangeProperty (GDK_SURFACE_XDISPLAY (surface), GDK_SURFACE_XID (surface),
3660 		   hints_atom, hints_atom, 32, PropModeReplace,
3661 		   (guchar *)hints, sizeof (MotifWmHints)/sizeof (long));
3662 
3663   if (hints != new_hints)
3664     XFree (hints);
3665 }
3666 
3667 typedef enum
3668 {
3669   GDK_DECOR_ALL         = 1 << 0,
3670   GDK_DECOR_BORDER      = 1 << 1,
3671   GDK_DECOR_RESIZEH     = 1 << 2,
3672   GDK_DECOR_TITLE       = 1 << 3,
3673   GDK_DECOR_MENU        = 1 << 4,
3674   GDK_DECOR_MINIMIZE    = 1 << 5,
3675   GDK_DECOR_MAXIMIZE    = 1 << 6
3676 } GdkWMDecoration;
3677 
3678 static void
gdk_x11_surface_set_decorations(GdkSurface * surface,GdkWMDecoration decorations)3679 gdk_x11_surface_set_decorations (GdkSurface      *surface,
3680 				GdkWMDecoration decorations)
3681 {
3682   MotifWmHints hints;
3683 
3684   if (GDK_SURFACE_DESTROYED (surface))
3685     return;
3686 
3687   /* initialize to zero to avoid writing uninitialized data to socket */
3688   memset(&hints, 0, sizeof(hints));
3689   hints.flags = MWM_HINTS_DECORATIONS;
3690   hints.decorations = decorations;
3691 
3692   gdk_surface_set_mwm_hints (surface, &hints);
3693 }
3694 
3695 static gboolean
gdk_x11_surface_get_decorations(GdkSurface * surface,GdkWMDecoration * decorations)3696 gdk_x11_surface_get_decorations(GdkSurface       *surface,
3697 			       GdkWMDecoration *decorations)
3698 {
3699   MotifWmHints *hints;
3700   gboolean result = FALSE;
3701 
3702   if (GDK_SURFACE_DESTROYED (surface))
3703     return FALSE;
3704 
3705   hints = gdk_surface_get_mwm_hints (surface);
3706 
3707   if (hints)
3708     {
3709       if (hints->flags & MWM_HINTS_DECORATIONS)
3710 	{
3711 	  if (decorations)
3712 	    *decorations = hints->decorations;
3713 	  result = TRUE;
3714 	}
3715 
3716       XFree (hints);
3717     }
3718 
3719   return result;
3720 }
3721 
3722 typedef enum
3723 {
3724   GDK_FUNC_ALL          = 1 << 0,
3725   GDK_FUNC_RESIZE       = 1 << 1,
3726   GDK_FUNC_MOVE         = 1 << 2,
3727   GDK_FUNC_MINIMIZE     = 1 << 3,
3728   GDK_FUNC_MAXIMIZE     = 1 << 4,
3729   GDK_FUNC_CLOSE        = 1 << 5
3730 } GdkWMFunction;
3731 
3732 static void
gdk_x11_surface_set_functions(GdkSurface * surface,GdkWMFunction functions)3733 gdk_x11_surface_set_functions (GdkSurface    *surface,
3734                               GdkWMFunction functions)
3735 {
3736   MotifWmHints hints;
3737 
3738   g_return_if_fail (GDK_IS_SURFACE (surface));
3739 
3740   if (GDK_SURFACE_DESTROYED (surface))
3741     return;
3742 
3743   /* initialize to zero to avoid writing uninitialized data to socket */
3744   memset(&hints, 0, sizeof(hints));
3745   hints.flags = MWM_HINTS_FUNCTIONS;
3746   hints.functions = functions;
3747 
3748   gdk_surface_set_mwm_hints (surface, &hints);
3749 }
3750 
3751 static gboolean
gdk_x11_surface_get_functions(GdkSurface * surface,GdkWMFunction * functions)3752 gdk_x11_surface_get_functions (GdkSurface       *surface,
3753 			       GdkWMFunction    *functions)
3754 {
3755   MotifWmHints *hints;
3756   gboolean result = FALSE;
3757 
3758   if (GDK_SURFACE_DESTROYED (surface))
3759     return FALSE;
3760 
3761   hints = gdk_surface_get_mwm_hints (surface);
3762 
3763   if (hints)
3764     {
3765       if (hints->flags & MWM_HINTS_DECORATIONS)
3766 	{
3767 	  if (functions)
3768 	    *functions = hints->functions;
3769 	  result = TRUE;
3770 	}
3771 
3772       XFree (hints);
3773     }
3774 
3775   return result;
3776 }
3777 
3778 cairo_region_t *
_gdk_x11_xwindow_get_shape(Display * xdisplay,Window window,int scale,int shape_type)3779 _gdk_x11_xwindow_get_shape (Display *xdisplay,
3780                             Window   window,
3781                             int      scale,
3782                             int      shape_type)
3783 {
3784   cairo_region_t *shape;
3785   GdkRectangle *rl;
3786   XRectangle *xrl;
3787   int rn, ord, i;
3788 
3789   shape = NULL;
3790   rn = 0;
3791 
3792   /* Note that XShapeGetRectangles returns NULL in two situations:
3793    * - the server doesn't support the SHAPE extension
3794    * - the shape is empty
3795    *
3796    * Since we can't discriminate these here, we always return
3797    * an empty shape. It is the callers responsibility to check
3798    * whether the server supports the SHAPE extensions beforehand.
3799    */
3800   xrl = XShapeGetRectangles (xdisplay, window, shape_type, &rn, &ord);
3801 
3802   if (rn == 0)
3803     return cairo_region_create (); /* Empty */
3804 
3805   if (ord != YXBanded)
3806     {
3807       /* This really shouldn't happen with any xserver, as they
3808        * generally convert regions to YXBanded internally
3809        */
3810       g_warning ("non YXBanded shape masks not supported");
3811       XFree (xrl);
3812       return NULL;
3813     }
3814 
3815   /* NOTE: The scale divisions here may lose some precision if someone
3816      else set the shape to be non-scale precision */
3817   rl = g_new (GdkRectangle, rn);
3818   for (i = 0; i < rn; i++)
3819     {
3820       rl[i].x = xrl[i].x / scale;
3821       rl[i].y = xrl[i].y / scale;
3822       rl[i].width = xrl[i].width / scale;
3823       rl[i].height = xrl[i].height / scale;
3824     }
3825   XFree (xrl);
3826 
3827   shape = cairo_region_create_rectangles (rl, rn);
3828   g_free (rl);
3829 
3830   return shape;
3831 }
3832 
3833 /* From the WM spec */
3834 #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
3835 #define _NET_WM_MOVERESIZE_SIZE_TOP          1
3836 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
3837 #define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
3838 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
3839 #define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
3840 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
3841 #define _NET_WM_MOVERESIZE_SIZE_LEFT         7
3842 #define _NET_WM_MOVERESIZE_MOVE              8   /* movement only */
3843 #define _NET_WM_MOVERESIZE_SIZE_KEYBOARD     9   /* size via keyboard */
3844 #define _NET_WM_MOVERESIZE_MOVE_KEYBOARD    10   /* move via keyboard */
3845 #define _NET_WM_MOVERESIZE_CANCEL           11   /* cancel operation */
3846 
3847 static void
wmspec_send_message(GdkDisplay * display,GdkSurface * surface,int root_x,int root_y,int action,int button)3848 wmspec_send_message (GdkDisplay *display,
3849                      GdkSurface  *surface,
3850                      int         root_x,
3851                      int         root_y,
3852                      int         action,
3853                      int         button)
3854 {
3855   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
3856   XClientMessageEvent xclient;
3857 
3858   memset (&xclient, 0, sizeof (xclient));
3859   xclient.type = ClientMessage;
3860   xclient.window = GDK_SURFACE_XID (surface);
3861   xclient.message_type =
3862     gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_MOVERESIZE");
3863   xclient.format = 32;
3864   xclient.data.l[0] = root_x * impl->surface_scale;
3865   xclient.data.l[1] = root_y * impl->surface_scale;
3866   xclient.data.l[2] = action;
3867   xclient.data.l[3] = button;
3868   xclient.data.l[4] = 1;  /* source indication */
3869 
3870   XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XROOTWIN (surface), False,
3871               SubstructureRedirectMask | SubstructureNotifyMask,
3872               (XEvent *)&xclient);
3873 }
3874 
3875 static void
handle_wmspec_button_release(GdkDisplay * display,const XEvent * xevent)3876 handle_wmspec_button_release (GdkDisplay   *display,
3877                               const XEvent *xevent)
3878 {
3879   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
3880   GdkSurface *surface;
3881 
3882   XIEvent *xiev = (XIEvent *) xevent->xcookie.data;
3883   XIDeviceEvent *xidev = (XIDeviceEvent *) xiev;
3884 
3885   if (xevent->xany.type == GenericEvent)
3886     surface = gdk_x11_surface_lookup_for_display (display, xidev->event);
3887   else
3888     surface = gdk_x11_surface_lookup_for_display (display, xevent->xany.window);
3889 
3890   if (display_x11->wm_moveresize_button != 0 && surface != NULL)
3891     {
3892       if ((xevent->xany.type == ButtonRelease &&
3893            xevent->xbutton.button == display_x11->wm_moveresize_button) ||
3894           (xevent->xany.type == GenericEvent &&
3895            xiev->evtype == XI_ButtonRelease &&
3896            xidev->detail == display_x11->wm_moveresize_button))
3897         {
3898           display_x11->wm_moveresize_button = 0;
3899           wmspec_send_message (display, surface, 0, 0, _NET_WM_MOVERESIZE_CANCEL, 0);
3900         }
3901     }
3902 }
3903 
3904 static void
wmspec_moveresize(GdkSurface * surface,int direction,GdkDevice * device,int button,int root_x,int root_y,guint32 timestamp)3905 wmspec_moveresize (GdkSurface *surface,
3906                    int        direction,
3907                    GdkDevice *device,
3908                    int        button,
3909                    int        root_x,
3910                    int        root_y,
3911                    guint32    timestamp)
3912 {
3913   GdkDisplay *display = GDK_SURFACE_DISPLAY (surface);
3914 
3915   if (button != 0)
3916     gdk_seat_ungrab (gdk_device_get_seat (device)); /* Release passive grab */
3917   GDK_X11_DISPLAY (display)->wm_moveresize_button = button;
3918 
3919   wmspec_send_message (display, surface, root_x, root_y, direction, button);
3920 }
3921 
3922 static void
wmspec_resize_drag(GdkSurface * surface,GdkSurfaceEdge edge,GdkDevice * device,int button,int root_x,int root_y,guint32 timestamp)3923 wmspec_resize_drag (GdkSurface     *surface,
3924                     GdkSurfaceEdge  edge,
3925                     GdkDevice     *device,
3926                     int            button,
3927                     int            root_x,
3928                     int            root_y,
3929                     guint32        timestamp)
3930 {
3931   int direction;
3932 
3933   if (button == 0)
3934     direction = _NET_WM_MOVERESIZE_SIZE_KEYBOARD;
3935   else
3936     switch (edge)
3937       {
3938       /* Let the compiler turn a switch into a table, instead
3939        * of doing the table manually, this way is easier to verify.
3940        */
3941       case GDK_SURFACE_EDGE_NORTH_WEST:
3942         direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
3943         break;
3944 
3945       case GDK_SURFACE_EDGE_NORTH:
3946         direction = _NET_WM_MOVERESIZE_SIZE_TOP;
3947         break;
3948 
3949       case GDK_SURFACE_EDGE_NORTH_EAST:
3950         direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
3951         break;
3952 
3953       case GDK_SURFACE_EDGE_WEST:
3954         direction = _NET_WM_MOVERESIZE_SIZE_LEFT;
3955         break;
3956 
3957       case GDK_SURFACE_EDGE_EAST:
3958         direction = _NET_WM_MOVERESIZE_SIZE_RIGHT;
3959         break;
3960 
3961       case GDK_SURFACE_EDGE_SOUTH_WEST:
3962         direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
3963         break;
3964 
3965       case GDK_SURFACE_EDGE_SOUTH:
3966         direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
3967         break;
3968 
3969       case GDK_SURFACE_EDGE_SOUTH_EAST:
3970         direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
3971         break;
3972 
3973       default:
3974         g_warning ("gdk_toplevel_begin_resize: bad resize edge %d!",
3975                    edge);
3976         return;
3977       }
3978 
3979   wmspec_moveresize (surface, direction, device, button, root_x, root_y, timestamp);
3980 }
3981 
3982 typedef struct _MoveResizeData MoveResizeData;
3983 
3984 struct _MoveResizeData
3985 {
3986   GdkDisplay *display;
3987 
3988   GdkSurface *moveresize_surface;
3989   GdkSurface *moveresize_emulation_surface;
3990   gboolean is_resize;
3991   GdkSurfaceEdge resize_edge;
3992   GdkDevice *device;
3993   int moveresize_button;
3994   int moveresize_x;
3995   int moveresize_y;
3996   int moveresize_orig_x;
3997   int moveresize_orig_y;
3998   int moveresize_orig_width;
3999   int moveresize_orig_height;
4000   GdkSurfaceHints moveresize_geom_mask;
4001   GdkGeometry moveresize_geometry;
4002   Time moveresize_process_time;
4003   XEvent *moveresize_pending_event;
4004 };
4005 
4006 static MoveResizeData *
get_move_resize_data(GdkDisplay * display,gboolean create)4007 get_move_resize_data (GdkDisplay *display,
4008 		      gboolean    create)
4009 {
4010   MoveResizeData *mv_resize;
4011   static GQuark move_resize_quark = 0;
4012 
4013   if (!move_resize_quark)
4014     move_resize_quark = g_quark_from_static_string ("gdk-surface-moveresize");
4015 
4016   mv_resize = g_object_get_qdata (G_OBJECT (display), move_resize_quark);
4017 
4018   if (!mv_resize && create)
4019     {
4020       mv_resize = g_new0 (MoveResizeData, 1);
4021       mv_resize->display = display;
4022 
4023       g_object_set_qdata (G_OBJECT (display), move_resize_quark, mv_resize);
4024     }
4025 
4026   return mv_resize;
4027 }
4028 
4029 static void
check_maximize(MoveResizeData * mv_resize,double x_root,double y_root)4030 check_maximize (MoveResizeData *mv_resize,
4031                 double          x_root,
4032                 double          y_root)
4033 {
4034   GdkToplevelState state;
4035   int y;
4036 
4037   if (mv_resize->is_resize)
4038     return;
4039 
4040   state = gdk_toplevel_get_state (GDK_TOPLEVEL (mv_resize->moveresize_surface));
4041 
4042   if (state & GDK_TOPLEVEL_STATE_MAXIMIZED)
4043     return;
4044 
4045   y = mv_resize->moveresize_orig_y + (y_root - mv_resize->moveresize_y);
4046 
4047   if (y < 10)
4048     gdk_x11_surface_maximize (mv_resize->moveresize_surface);
4049 }
4050 
4051 static void
check_unmaximize(MoveResizeData * mv_resize,double x_root,double y_root)4052 check_unmaximize (MoveResizeData *mv_resize,
4053                   double          x_root,
4054                   double          y_root)
4055 {
4056   GdkToplevelState state;
4057   int dx, dy;
4058 
4059   if (mv_resize->is_resize)
4060     return;
4061 
4062   state = gdk_toplevel_get_state (GDK_TOPLEVEL (mv_resize->moveresize_surface));
4063 
4064   if ((state & (GDK_TOPLEVEL_STATE_MAXIMIZED | GDK_TOPLEVEL_STATE_TILED)) == 0)
4065     return;
4066 
4067   dx = x_root - mv_resize->moveresize_x;
4068   dy = y_root - mv_resize->moveresize_y;
4069 
4070   if (ABS (dx) > 20 || ABS (dy) > 20)
4071     gdk_x11_surface_unmaximize (mv_resize->moveresize_surface);
4072 }
4073 
4074 static void
update_pos(MoveResizeData * mv_resize,int new_root_x,int new_root_y)4075 update_pos (MoveResizeData *mv_resize,
4076 	    int             new_root_x,
4077 	    int             new_root_y)
4078 {
4079   int dx, dy;
4080 
4081   check_unmaximize (mv_resize, new_root_x, new_root_y);
4082   dx = new_root_x - mv_resize->moveresize_x;
4083   dy = new_root_y - mv_resize->moveresize_y;
4084 
4085   if (mv_resize->is_resize)
4086     {
4087       int x, y, w, h;
4088 
4089       x = mv_resize->moveresize_orig_x;
4090       y = mv_resize->moveresize_orig_y;
4091 
4092       w = mv_resize->moveresize_orig_width;
4093       h = mv_resize->moveresize_orig_height;
4094 
4095       switch (mv_resize->resize_edge)
4096 	{
4097 	case GDK_SURFACE_EDGE_NORTH_WEST:
4098 	  x += dx;
4099 	  y += dy;
4100 	  w -= dx;
4101 	  h -= dy;
4102 	  break;
4103 	case GDK_SURFACE_EDGE_NORTH:
4104 	  y += dy;
4105 	  h -= dy;
4106 	  break;
4107 	case GDK_SURFACE_EDGE_NORTH_EAST:
4108 	  y += dy;
4109 	  h -= dy;
4110 	  w += dx;
4111 	  break;
4112 	case GDK_SURFACE_EDGE_SOUTH_WEST:
4113 	  h += dy;
4114 	  x += dx;
4115 	  w -= dx;
4116 	  break;
4117 	case GDK_SURFACE_EDGE_SOUTH_EAST:
4118 	  w += dx;
4119 	  h += dy;
4120 	  break;
4121 	case GDK_SURFACE_EDGE_SOUTH:
4122 	  h += dy;
4123 	  break;
4124 	case GDK_SURFACE_EDGE_EAST:
4125 	  w += dx;
4126 	  break;
4127 	case GDK_SURFACE_EDGE_WEST:
4128 	  x += dx;
4129 	  w -= dx;
4130 	  break;
4131         default:
4132           break;
4133 	}
4134 
4135       x = MAX (x, 0);
4136       y = MAX (y, 0);
4137       w = MAX (w, 1);
4138       h = MAX (h, 1);
4139 
4140       if (mv_resize->moveresize_geom_mask)
4141 	{
4142 	  gdk_surface_constrain_size (&mv_resize->moveresize_geometry,
4143 				     mv_resize->moveresize_geom_mask,
4144 				     w, h, &w, &h);
4145 	}
4146 
4147       gdk_x11_surface_move_resize (mv_resize->moveresize_surface, TRUE,
4148                                    x, y, w, h);
4149     }
4150   else
4151     {
4152       int x, y;
4153 
4154       x = mv_resize->moveresize_orig_x + dx;
4155       y = mv_resize->moveresize_orig_y + dy;
4156 
4157       gdk_x11_surface_move (mv_resize->moveresize_surface, x, y);
4158     }
4159 }
4160 
4161 static void
finish_drag(MoveResizeData * mv_resize)4162 finish_drag (MoveResizeData *mv_resize)
4163 {
4164   gdk_surface_destroy (mv_resize->moveresize_emulation_surface);
4165   mv_resize->moveresize_emulation_surface = NULL;
4166   g_clear_object (&mv_resize->moveresize_surface);
4167   g_clear_pointer (&mv_resize->moveresize_pending_event, g_free);
4168 }
4169 
4170 static int
lookahead_motion_predicate(Display * xdisplay,XEvent * event,XPointer arg)4171 lookahead_motion_predicate (Display *xdisplay,
4172 			    XEvent  *event,
4173 			    XPointer arg)
4174 {
4175   gboolean *seen_release = (gboolean *)arg;
4176   GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
4177   MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
4178 
4179   if (*seen_release)
4180     return False;
4181 
4182   switch (event->xany.type)
4183     {
4184     case ButtonRelease:
4185       *seen_release = TRUE;
4186       break;
4187     case MotionNotify:
4188       mv_resize->moveresize_process_time = event->xmotion.time;
4189       break;
4190     default:
4191       break;
4192     }
4193 
4194   return False;
4195 }
4196 
4197 static gboolean
moveresize_lookahead(MoveResizeData * mv_resize,const XEvent * event)4198 moveresize_lookahead (MoveResizeData *mv_resize,
4199 		      const XEvent   *event)
4200 {
4201   XEvent tmp_event;
4202   gboolean seen_release = FALSE;
4203 
4204   if (mv_resize->moveresize_process_time)
4205     {
4206       if (event->xmotion.time == mv_resize->moveresize_process_time)
4207         {
4208           mv_resize->moveresize_process_time = 0;
4209           return TRUE;
4210         }
4211       else
4212         return FALSE;
4213     }
4214 
4215   XCheckIfEvent (event->xany.display, &tmp_event,
4216                  lookahead_motion_predicate, (XPointer) & seen_release);
4217 
4218   return mv_resize->moveresize_process_time == 0;
4219 }
4220 
4221 gboolean
_gdk_x11_moveresize_handle_event(const XEvent * event)4222 _gdk_x11_moveresize_handle_event (const XEvent *event)
4223 {
4224   guint button_mask = 0;
4225   GdkDisplay *display = gdk_x11_lookup_xdisplay (event->xany.display);
4226   MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
4227   GdkX11Surface *impl;
4228 
4229   if (!mv_resize || !mv_resize->moveresize_surface)
4230     {
4231       handle_wmspec_button_release (display, event);
4232       return FALSE;
4233     }
4234 
4235   impl = GDK_X11_SURFACE (mv_resize->moveresize_surface);
4236 
4237   if (mv_resize->moveresize_button != 0)
4238     button_mask = GDK_BUTTON1_MASK << (mv_resize->moveresize_button - 1);
4239 
4240   switch (event->xany.type)
4241     {
4242     case MotionNotify:
4243       if (mv_resize->moveresize_surface->resize_count > 0)
4244         {
4245           if (mv_resize->moveresize_pending_event)
4246             *mv_resize->moveresize_pending_event = *event;
4247           else
4248             mv_resize->moveresize_pending_event =
4249               g_memdup2 (event, sizeof (XEvent));
4250 
4251           break;
4252         }
4253       if (!moveresize_lookahead (mv_resize, event))
4254         break;
4255 
4256       update_pos (mv_resize,
4257                   event->xmotion.x_root / impl->surface_scale,
4258                   event->xmotion.y_root / impl->surface_scale);
4259 
4260       /* This should never be triggered in normal cases, but in the
4261        * case where the drag started without an implicit grab being
4262        * in effect, we could miss the release if it occurs before
4263        * we grab the pointer; this ensures that we will never
4264        * get a permanently stuck grab.
4265        */
4266       if ((event->xmotion.state & button_mask) == 0)
4267         {
4268           check_maximize (mv_resize,
4269                           event->xmotion.x_root / impl->surface_scale,
4270                           event->xmotion.y_root / impl->surface_scale);
4271           finish_drag (mv_resize);
4272         }
4273       break;
4274 
4275     case ButtonRelease:
4276       update_pos (mv_resize,
4277                   event->xbutton.x_root / impl->surface_scale,
4278                   event->xbutton.y_root / impl->surface_scale);
4279 
4280       if (event->xbutton.button == mv_resize->moveresize_button)
4281         {
4282           check_maximize (mv_resize,
4283                           event->xmotion.x_root / impl->surface_scale,
4284                           event->xmotion.y_root / impl->surface_scale);
4285           finish_drag (mv_resize);
4286         }
4287       break;
4288 
4289     case GenericEvent:
4290       {
4291         /* we just assume this is an XI2 event */
4292         XIEvent *ev = (XIEvent *) event->xcookie.data;
4293         XIDeviceEvent *xev = (XIDeviceEvent *)ev;
4294         int state;
4295         switch (ev->evtype)
4296           {
4297           case XI_Motion:
4298             update_pos (mv_resize, xev->root_x / impl->surface_scale, xev->root_y / impl->surface_scale);
4299             state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
4300             if ((state & button_mask) == 0)
4301               {
4302                 check_maximize (mv_resize,
4303                                 xev->root_x / impl->surface_scale,
4304                                 xev->root_y / impl->surface_scale);
4305                 finish_drag (mv_resize);
4306               }
4307             break;
4308 
4309           case XI_ButtonRelease:
4310             update_pos (mv_resize, xev->root_x / impl->surface_scale, xev->root_y / impl->surface_scale);
4311             if (xev->detail == mv_resize->moveresize_button)
4312               {
4313                 check_maximize (mv_resize,
4314                                 xev->root_x / impl->surface_scale,
4315                                 xev->root_y / impl->surface_scale);
4316                 finish_drag (mv_resize);
4317               }
4318             break;
4319           default:
4320             break;
4321           }
4322       }
4323       break;
4324 
4325     default:
4326       break;
4327 
4328     }
4329   return TRUE;
4330 }
4331 
4332 gboolean
_gdk_x11_moveresize_configure_done(GdkDisplay * display,GdkSurface * surface)4333 _gdk_x11_moveresize_configure_done (GdkDisplay *display,
4334                                     GdkSurface  *surface)
4335 {
4336   XEvent *tmp_event;
4337   MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
4338 
4339   gdk_surface_thaw_updates (surface);
4340   gdk_surface_request_layout (surface);
4341 
4342   if (!mv_resize || surface != mv_resize->moveresize_surface)
4343     return FALSE;
4344 
4345   if (mv_resize->moveresize_pending_event)
4346     {
4347       tmp_event = mv_resize->moveresize_pending_event;
4348       mv_resize->moveresize_pending_event = NULL;
4349       _gdk_x11_moveresize_handle_event (tmp_event);
4350       g_free (tmp_event);
4351     }
4352 
4353   return TRUE;
4354 }
4355 
4356 static void
create_moveresize_surface(MoveResizeData * mv_resize,guint32 timestamp)4357 create_moveresize_surface (MoveResizeData *mv_resize,
4358                           guint32         timestamp)
4359 {
4360   GdkGrabStatus status;
4361 
4362   g_assert (mv_resize->moveresize_emulation_surface == NULL);
4363 
4364   mv_resize->moveresize_emulation_surface =
4365       _gdk_x11_display_create_surface (mv_resize->display,
4366                                        GDK_SURFACE_TEMP,
4367                                        NULL,
4368                                        -100, -100, 1, 1);
4369 
4370   gdk_surface_set_is_mapped (mv_resize->moveresize_emulation_surface, TRUE);
4371   gdk_x11_surface_show (mv_resize->moveresize_emulation_surface, FALSE);
4372 
4373   status = gdk_seat_grab (gdk_device_get_seat (mv_resize->device),
4374                           mv_resize->moveresize_emulation_surface,
4375                           GDK_SEAT_CAPABILITY_POINTER, FALSE,
4376                           NULL, NULL, NULL, NULL);
4377 
4378   if (status != GDK_GRAB_SUCCESS)
4379     {
4380       /* If this fails, some other client has grabbed the surface
4381        * already.
4382        */
4383       finish_drag (mv_resize);
4384     }
4385 
4386   mv_resize->moveresize_process_time = 0;
4387 }
4388 
4389 /*
4390    Calculate mv_resize->moveresize_orig_x and mv_resize->moveresize_orig_y
4391    so that calling XMoveWindow with these coordinates will not move the
4392    surface.
4393    Note that this depends on the WM to implement ICCCM-compliant reference
4394    point handling.
4395 */
4396 static void
calculate_unmoving_origin(MoveResizeData * mv_resize)4397 calculate_unmoving_origin (MoveResizeData *mv_resize)
4398 {
4399   GdkRectangle rect;
4400 
4401   gdk_x11_surface_get_frame_extents (mv_resize->moveresize_surface, &rect);
4402   mv_resize->moveresize_orig_x = rect.x;
4403   mv_resize->moveresize_orig_y = rect.y;
4404 }
4405 
4406 static void
emulate_resize_drag(GdkSurface * surface,GdkSurfaceEdge edge,GdkDevice * device,int button,int root_x,int root_y,guint32 timestamp)4407 emulate_resize_drag (GdkSurface     *surface,
4408                      GdkSurfaceEdge  edge,
4409                      GdkDevice     *device,
4410                      int            button,
4411                      int            root_x,
4412                      int            root_y,
4413                      guint32        timestamp)
4414 {
4415   MoveResizeData *mv_resize = get_move_resize_data (GDK_SURFACE_DISPLAY (surface), TRUE);
4416 
4417   if (mv_resize->moveresize_surface != NULL)
4418     return; /* already a drag operation in progress */
4419 
4420   mv_resize->is_resize = TRUE;
4421   mv_resize->moveresize_button = button;
4422   mv_resize->resize_edge = edge;
4423   mv_resize->device = device;
4424   mv_resize->moveresize_x = root_x;
4425   mv_resize->moveresize_y = root_y;
4426   mv_resize->moveresize_surface = g_object_ref (surface);
4427 
4428   mv_resize->moveresize_orig_width = gdk_surface_get_width (surface);
4429   mv_resize->moveresize_orig_height = gdk_surface_get_height (surface);
4430 
4431   mv_resize->moveresize_geom_mask = 0;
4432   gdk_surface_get_geometry_hints (surface,
4433 				 &mv_resize->moveresize_geometry,
4434 				 &mv_resize->moveresize_geom_mask);
4435 
4436   calculate_unmoving_origin (mv_resize);
4437 
4438   create_moveresize_surface (mv_resize, timestamp);
4439 }
4440 
4441 static void
emulate_move_drag(GdkSurface * surface,GdkDevice * device,int button,int root_x,int root_y,guint32 timestamp)4442 emulate_move_drag (GdkSurface *surface,
4443                    GdkDevice  *device,
4444                    int         button,
4445                    int         root_x,
4446                    int         root_y,
4447                    guint32     timestamp)
4448 {
4449   MoveResizeData *mv_resize = get_move_resize_data (GDK_SURFACE_DISPLAY (surface), TRUE);
4450 
4451   if (mv_resize->moveresize_surface != NULL)
4452     return; /* already a drag operation in progress */
4453 
4454   mv_resize->is_resize = FALSE;
4455   mv_resize->device = device;
4456   mv_resize->moveresize_button = button;
4457   mv_resize->moveresize_x = root_x;
4458   mv_resize->moveresize_y = root_y;
4459 
4460   mv_resize->moveresize_surface = g_object_ref (surface);
4461 
4462   calculate_unmoving_origin (mv_resize);
4463 
4464   create_moveresize_surface (mv_resize, timestamp);
4465 }
4466 
4467 static gboolean
_should_perform_ewmh_drag(GdkSurface * surface,GdkDevice * device)4468 _should_perform_ewmh_drag (GdkSurface *surface,
4469                            GdkDevice *device)
4470 {
4471   GdkPointerSurfaceInfo *info;
4472   GdkDisplay *display;
4473 
4474   display = gdk_surface_get_display (surface);
4475   info = _gdk_display_get_pointer_info (display, device);
4476 
4477   if ((info->last_physical_device == NULL ||
4478        gdk_device_get_source (info->last_physical_device) != GDK_SOURCE_TOUCHSCREEN) &&
4479       gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (surface),
4480                                            g_intern_static_string ("_NET_WM_MOVERESIZE")))
4481     return TRUE;
4482 
4483   return FALSE;
4484 }
4485 
4486 static void
gdk_x11_toplevel_begin_resize(GdkToplevel * toplevel,GdkSurfaceEdge edge,GdkDevice * device,int button,double x,double y,guint32 timestamp)4487 gdk_x11_toplevel_begin_resize (GdkToplevel    *toplevel,
4488                                GdkSurfaceEdge  edge,
4489                                GdkDevice      *device,
4490                                int             button,
4491                                double          x,
4492                                double          y,
4493                                guint32         timestamp)
4494 {
4495   GdkSurface *surface = GDK_SURFACE (toplevel);
4496   int root_x, root_y;
4497 
4498   if (GDK_SURFACE_DESTROYED (surface))
4499     return;
4500 
4501   gdk_x11_surface_get_root_coords (surface, x, y, &root_x, &root_y);
4502 
4503   /* Avoid EWMH for touch devices */
4504   if (_should_perform_ewmh_drag (surface, device))
4505     wmspec_resize_drag (surface, edge, device, button, root_x, root_y, timestamp);
4506   else
4507     emulate_resize_drag (surface, edge, device, button, root_x, root_y, timestamp);
4508 }
4509 
4510 static void
gdk_x11_toplevel_begin_move(GdkToplevel * toplevel,GdkDevice * device,int button,double x,double y,guint32 timestamp)4511 gdk_x11_toplevel_begin_move (GdkToplevel *toplevel,
4512                              GdkDevice   *device,
4513                              int          button,
4514                              double       x,
4515                              double       y,
4516                              guint32      timestamp)
4517 {
4518   GdkSurface *surface = GDK_SURFACE (toplevel);
4519   int root_x, root_y;
4520   int direction;
4521 
4522   if (GDK_SURFACE_DESTROYED (surface))
4523     return;
4524 
4525   if (button == 0)
4526     direction = _NET_WM_MOVERESIZE_MOVE_KEYBOARD;
4527   else
4528     direction = _NET_WM_MOVERESIZE_MOVE;
4529 
4530   gdk_x11_surface_get_root_coords (surface, x, y, &root_x, &root_y);
4531 
4532   /* Avoid EWMH for touch devices */
4533   if (_should_perform_ewmh_drag (surface, device))
4534     wmspec_moveresize (surface, direction, device, button, root_x, root_y, timestamp);
4535   else
4536     emulate_move_drag (surface, device, button, root_x, root_y, timestamp);
4537 }
4538 
4539 static gboolean
gdk_x11_surface_beep(GdkSurface * surface)4540 gdk_x11_surface_beep (GdkSurface *surface)
4541 {
4542   GdkDisplay *display;
4543 
4544   display = GDK_SURFACE_DISPLAY (surface);
4545 
4546   if (!GDK_X11_DISPLAY (display)->trusted_client)
4547     return FALSE;
4548 
4549 #ifdef HAVE_XKB
4550   if (GDK_X11_DISPLAY (display)->use_xkb)
4551     {
4552       XkbBell (GDK_DISPLAY_XDISPLAY (display),
4553                GDK_SURFACE_XID (surface),
4554                0,
4555                None);
4556       return TRUE;
4557     }
4558 #endif
4559 
4560   return FALSE;
4561 }
4562 
4563 void
gdk_x11_surface_set_opacity(GdkSurface * surface,double opacity)4564 gdk_x11_surface_set_opacity (GdkSurface *surface,
4565 			     double      opacity)
4566 {
4567   GdkDisplay *display;
4568   gulong cardinal;
4569 
4570   g_return_if_fail (GDK_IS_SURFACE (surface));
4571 
4572   if (GDK_SURFACE_DESTROYED (surface))
4573     return;
4574 
4575   display = gdk_surface_get_display (surface);
4576 
4577   if (opacity < 0)
4578     opacity = 0;
4579   else if (opacity > 1)
4580     opacity = 1;
4581 
4582   cardinal = opacity * 0xffffffff;
4583 
4584   if (cardinal == 0xffffffff)
4585     XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
4586 		     GDK_SURFACE_XID (surface),
4587 		     gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_OPACITY"));
4588   else
4589     XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
4590 		     GDK_SURFACE_XID (surface),
4591 		     gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_OPACITY"),
4592 		     XA_CARDINAL, 32,
4593 		     PropModeReplace,
4594 		     (guchar *) &cardinal, 1);
4595 }
4596 
4597 static Bool
timestamp_predicate(Display * display,XEvent * xevent,XPointer arg)4598 timestamp_predicate (Display *display,
4599 		     XEvent  *xevent,
4600 		     XPointer arg)
4601 {
4602   Window xwindow = GPOINTER_TO_UINT (arg);
4603   GdkDisplay *gdk_display = gdk_x11_lookup_xdisplay (display);
4604 
4605   if (xevent->type == PropertyNotify &&
4606       xevent->xproperty.window == xwindow &&
4607       xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (gdk_display,
4608 								       "GDK_TIMESTAMP_PROP"))
4609     return True;
4610 
4611   return False;
4612 }
4613 
4614 /**
4615  * gdk_x11_get_server_time:
4616  * @surface: (type GdkX11Surface): a `GdkSurface`, used for communication
4617  *   with the server. The surface must have `GDK_PROPERTY_CHANGE_MASK` in
4618  *   its events mask or a hang will result.
4619  *
4620  * Routine to get the current X server time stamp.
4621  *
4622  * Returns: the time stamp
4623  */
4624 guint32
gdk_x11_get_server_time(GdkSurface * surface)4625 gdk_x11_get_server_time (GdkSurface *surface)
4626 {
4627   Display *xdisplay;
4628   Window   xwindow;
4629   guchar c = 'a';
4630   XEvent xevent;
4631   Atom timestamp_prop_atom;
4632 
4633   g_return_val_if_fail (GDK_IS_SURFACE (surface), 0);
4634   g_return_val_if_fail (!GDK_SURFACE_DESTROYED (surface), 0);
4635 
4636   xdisplay = GDK_SURFACE_XDISPLAY (surface);
4637   xwindow = GDK_SURFACE_XID (surface);
4638   timestamp_prop_atom =
4639     gdk_x11_get_xatom_by_name_for_display (GDK_SURFACE_DISPLAY (surface),
4640 					   "GDK_TIMESTAMP_PROP");
4641 
4642   XChangeProperty (xdisplay, xwindow, timestamp_prop_atom,
4643 		   timestamp_prop_atom,
4644 		   8, PropModeReplace, &c, 1);
4645 
4646   XIfEvent (xdisplay, &xevent,
4647 	    timestamp_predicate, GUINT_TO_POINTER(xwindow));
4648 
4649   return xevent.xproperty.time;
4650 }
4651 
4652 /**
4653  * gdk_x11_surface_get_xid:
4654  * @surface: (type GdkX11Surface): a native `GdkSurface`.
4655  *
4656  * Returns the X resource (surface) belonging to a `GdkSurface`.
4657  *
4658  * Returns: the ID of @drawable’s X resource.
4659  **/
4660 XID
gdk_x11_surface_get_xid(GdkSurface * surface)4661 gdk_x11_surface_get_xid (GdkSurface *surface)
4662 {
4663   return GDK_X11_SURFACE (surface)->xid;
4664 }
4665 
4666 static int
gdk_x11_surface_get_scale_factor(GdkSurface * surface)4667 gdk_x11_surface_get_scale_factor (GdkSurface *surface)
4668 {
4669   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
4670 
4671   if (GDK_SURFACE_DESTROYED (surface))
4672     return 1;
4673 
4674   return impl->surface_scale;
4675 }
4676 
4677 /**
4678  * gdk_x11_surface_set_frame_sync_enabled:
4679  * @surface: (type GdkX11Surface): a native `GdkSurface`
4680  * @frame_sync_enabled: whether frame-synchronization should be enabled
4681  *
4682  * This function can be used to disable frame synchronization for a surface.
4683  * Normally frame synchronziation will be enabled or disabled based on whether
4684  * the system has a compositor that supports frame synchronization, but if
4685  * the surface is not directly managed by the window manager, then frame
4686  * synchronziation may need to be disabled. This is the case for a surface
4687  * embedded via the XEMBED protocol.
4688  */
4689 void
gdk_x11_surface_set_frame_sync_enabled(GdkSurface * surface,gboolean frame_sync_enabled)4690 gdk_x11_surface_set_frame_sync_enabled (GdkSurface *surface,
4691                                        gboolean   frame_sync_enabled)
4692 {
4693   GDK_X11_SURFACE (surface)->frame_sync_enabled = FALSE;
4694 }
4695 
4696 static void
gdk_x11_surface_set_opaque_region(GdkSurface * surface,cairo_region_t * region)4697 gdk_x11_surface_set_opaque_region (GdkSurface      *surface,
4698                                   cairo_region_t *region)
4699 {
4700   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
4701   GdkDisplay *display;
4702   int nitems;
4703   gulong *data;
4704 
4705   if (GDK_SURFACE_DESTROYED (surface))
4706     return;
4707 
4708   if (region != NULL)
4709     {
4710       int i, nrects;
4711 
4712       nrects = cairo_region_num_rectangles (region);
4713       nitems = nrects * 4;
4714       data = g_new (gulong, nitems);
4715 
4716       for (i = 0; i < nrects; i++)
4717         {
4718           cairo_rectangle_int_t rect;
4719           cairo_region_get_rectangle (region, i, &rect);
4720           data[i*4+0] = rect.x * impl->surface_scale;
4721           data[i*4+1] = rect.y * impl->surface_scale;
4722           data[i*4+2] = rect.width * impl->surface_scale;
4723           data[i*4+3] = rect.height * impl->surface_scale;
4724         }
4725     }
4726   else
4727     {
4728       nitems = 0;
4729       data = NULL;
4730     }
4731 
4732   display = gdk_surface_get_display (surface);
4733 
4734   XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
4735                    GDK_SURFACE_XID (surface),
4736                    gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_OPAQUE_REGION"),
4737                    XA_CARDINAL, 32, PropModeReplace,
4738                    (guchar *) data, nitems);
4739 
4740   g_free (data);
4741 }
4742 
4743 static gboolean
gdk_x11_surface_show_window_menu(GdkSurface * surface,GdkEvent * event)4744 gdk_x11_surface_show_window_menu (GdkSurface *surface,
4745                                   GdkEvent   *event)
4746 {
4747   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
4748   GdkDisplay *display = GDK_SURFACE_DISPLAY (surface);
4749   GdkDevice *device;
4750   int device_id;
4751   double x, y;
4752   int x_root, y_root;
4753   XClientMessageEvent xclient = { 0 };
4754 
4755   GdkEventType event_type = gdk_event_get_event_type (event);
4756 
4757   switch ((guint) event_type)
4758     {
4759     case GDK_BUTTON_PRESS:
4760     case GDK_BUTTON_RELEASE:
4761       break;
4762     default:
4763       return FALSE;
4764     }
4765 
4766   if (!gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (surface),
4767                                             g_intern_static_string ("_GTK_SHOW_WINDOW_MENU")))
4768     return FALSE;
4769 
4770   gdk_event_get_position (event, &x, &y);
4771   gdk_x11_surface_get_root_coords (surface, x, y, &x_root, &y_root);
4772   device = gdk_event_get_device (event);
4773   g_object_get (G_OBJECT (device),
4774                 "device-id", &device_id,
4775                 NULL);
4776 
4777   /* Ungrab the implicit grab */
4778   gdk_seat_ungrab (gdk_device_get_seat (device));
4779 
4780   xclient.type = ClientMessage;
4781   xclient.window = GDK_SURFACE_XID (surface);
4782   xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_GTK_SHOW_WINDOW_MENU");
4783   xclient.data.l[0] = device_id;
4784   xclient.data.l[1] = x_root * impl->surface_scale;
4785   xclient.data.l[2] = y_root * impl->surface_scale;
4786   xclient.format = 32;
4787 
4788   XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XROOTWIN (surface), False,
4789               SubstructureRedirectMask | SubstructureNotifyMask,
4790               (XEvent *)&xclient);
4791 
4792   return TRUE;
4793 }
4794 
4795 static void
gdk_x11_surface_class_init(GdkX11SurfaceClass * klass)4796 gdk_x11_surface_class_init (GdkX11SurfaceClass *klass)
4797 {
4798   GObjectClass *object_class = G_OBJECT_CLASS (klass);
4799   GdkSurfaceClass *impl_class = GDK_SURFACE_CLASS (klass);
4800 
4801   object_class->finalize = gdk_x11_surface_finalize;
4802 
4803   impl_class->hide = gdk_x11_surface_hide;
4804   impl_class->get_geometry = gdk_x11_surface_get_geometry;
4805   impl_class->get_root_coords = gdk_x11_surface_get_root_coords;
4806   impl_class->get_device_state = gdk_x11_surface_get_device_state;
4807   impl_class->set_input_region = gdk_x11_surface_set_input_region;
4808   impl_class->destroy = gdk_x11_surface_destroy;
4809   impl_class->beep = gdk_x11_surface_beep;
4810 
4811   impl_class->destroy_notify = gdk_x11_surface_destroy_notify;
4812   impl_class->drag_begin = _gdk_x11_surface_drag_begin;
4813   impl_class->get_scale_factor = gdk_x11_surface_get_scale_factor;
4814   impl_class->set_opaque_region = gdk_x11_surface_set_opaque_region;
4815   impl_class->request_layout = gdk_x11_surface_request_layout;
4816   impl_class->compute_size = gdk_x11_surface_compute_size;
4817 }
4818 
4819 #define LAST_PROP 1
4820 
4821 typedef struct {
4822   GdkX11Surface parent_instance;
4823 } GdkX11Popup;
4824 
4825 typedef struct {
4826   GdkX11SurfaceClass parent_class;
4827 } GdkX11PopupClass;
4828 
4829 static void gdk_x11_popup_iface_init (GdkPopupInterface *iface);
4830 
G_DEFINE_TYPE_WITH_CODE(GdkX11Popup,gdk_x11_popup,GDK_TYPE_X11_SURFACE,G_IMPLEMENT_INTERFACE (GDK_TYPE_POPUP,gdk_x11_popup_iface_init))4831 G_DEFINE_TYPE_WITH_CODE (GdkX11Popup, gdk_x11_popup, GDK_TYPE_X11_SURFACE,
4832                          G_IMPLEMENT_INTERFACE (GDK_TYPE_POPUP,
4833                                                 gdk_x11_popup_iface_init))
4834 
4835 static void
4836 gdk_x11_popup_init (GdkX11Popup *popup)
4837 {
4838 }
4839 
4840 static void
gdk_x11_popup_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)4841 gdk_x11_popup_get_property (GObject    *object,
4842                             guint       prop_id,
4843                             GValue     *value,
4844                             GParamSpec *pspec)
4845 {
4846   GdkSurface *surface = GDK_SURFACE (object);
4847 
4848   switch (prop_id)
4849     {
4850     case LAST_PROP + GDK_POPUP_PROP_PARENT:
4851       g_value_set_object (value, surface->parent);
4852       break;
4853 
4854     case LAST_PROP + GDK_POPUP_PROP_AUTOHIDE:
4855       g_value_set_boolean (value, surface->autohide);
4856       break;
4857 
4858     default:
4859       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4860       break;
4861     }
4862 }
4863 
4864 static void
gdk_x11_popup_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)4865 gdk_x11_popup_set_property (GObject      *object,
4866                             guint         prop_id,
4867                             const GValue *value,
4868                             GParamSpec   *pspec)
4869 {
4870   GdkSurface *surface = GDK_SURFACE (object);
4871 
4872   switch (prop_id)
4873     {
4874     case LAST_PROP + GDK_POPUP_PROP_PARENT:
4875       surface->parent = g_value_dup_object (value);
4876       if (surface->parent != NULL)
4877         surface->parent->children = g_list_prepend (surface->parent->children, surface);
4878       break;
4879 
4880     case LAST_PROP + GDK_POPUP_PROP_AUTOHIDE:
4881       surface->autohide = g_value_get_boolean (value);
4882       break;
4883 
4884     default:
4885       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4886       break;
4887     }
4888 }
4889 
4890 
4891 static void
gdk_x11_popup_class_init(GdkX11PopupClass * class)4892 gdk_x11_popup_class_init (GdkX11PopupClass *class)
4893 {
4894   GObjectClass *object_class = G_OBJECT_CLASS (class);
4895 
4896   object_class->get_property = gdk_x11_popup_get_property;
4897   object_class->set_property = gdk_x11_popup_set_property;
4898 
4899   gdk_popup_install_properties (object_class, 1);
4900 }
4901 
4902 static gboolean
gdk_x11_popup_present(GdkPopup * popup,int width,int height,GdkPopupLayout * layout)4903 gdk_x11_popup_present (GdkPopup       *popup,
4904                        int             width,
4905                        int             height,
4906                        GdkPopupLayout *layout)
4907 {
4908   return gdk_x11_surface_present_popup (GDK_SURFACE (popup), width, height, layout);
4909 }
4910 
4911 static GdkGravity
gdk_x11_popup_get_surface_anchor(GdkPopup * popup)4912 gdk_x11_popup_get_surface_anchor (GdkPopup *popup)
4913 {
4914   return GDK_SURFACE (popup)->popup.surface_anchor;
4915 }
4916 
4917 static GdkGravity
gdk_x11_popup_get_rect_anchor(GdkPopup * popup)4918 gdk_x11_popup_get_rect_anchor (GdkPopup *popup)
4919 {
4920   return GDK_SURFACE (popup)->popup.rect_anchor;
4921 }
4922 
4923 static int
gdk_x11_popup_get_position_x(GdkPopup * popup)4924 gdk_x11_popup_get_position_x (GdkPopup *popup)
4925 {
4926   return GDK_SURFACE (popup)->x;
4927 }
4928 
4929 static int
gdk_x11_popup_get_position_y(GdkPopup * popup)4930 gdk_x11_popup_get_position_y (GdkPopup *popup)
4931 {
4932   return GDK_SURFACE (popup)->y;
4933 }
4934 
4935 static void
gdk_x11_popup_iface_init(GdkPopupInterface * iface)4936 gdk_x11_popup_iface_init (GdkPopupInterface *iface)
4937 {
4938   iface->present = gdk_x11_popup_present;
4939   iface->get_surface_anchor = gdk_x11_popup_get_surface_anchor;
4940   iface->get_rect_anchor = gdk_x11_popup_get_rect_anchor;
4941   iface->get_position_x = gdk_x11_popup_get_position_x;
4942   iface->get_position_y = gdk_x11_popup_get_position_y;
4943 }
4944 
4945 static void gdk_x11_toplevel_iface_init (GdkToplevelInterface *iface);
4946 
G_DEFINE_TYPE_WITH_CODE(GdkX11Toplevel,gdk_x11_toplevel,GDK_TYPE_X11_SURFACE,G_IMPLEMENT_INTERFACE (GDK_TYPE_TOPLEVEL,gdk_x11_toplevel_iface_init))4947 G_DEFINE_TYPE_WITH_CODE (GdkX11Toplevel, gdk_x11_toplevel, GDK_TYPE_X11_SURFACE,
4948                          G_IMPLEMENT_INTERFACE (GDK_TYPE_TOPLEVEL,
4949                                                 gdk_x11_toplevel_iface_init))
4950 
4951 static void
4952 gdk_x11_toplevel_init (GdkX11Toplevel *toplevel)
4953 {
4954 }
4955 static void
gdk_x11_toplevel_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)4956 gdk_x11_toplevel_set_property (GObject      *object,
4957                                guint         prop_id,
4958                                const GValue *value,
4959                                GParamSpec   *pspec)
4960 {
4961   GdkSurface *surface = GDK_SURFACE (object);
4962 
4963   switch (prop_id)
4964     {
4965     case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE:
4966       gdk_x11_surface_set_title (surface, g_value_get_string (value));
4967       g_object_notify_by_pspec (G_OBJECT (surface), pspec);
4968       break;
4969 
4970     case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID:
4971       gdk_x11_surface_set_startup_id (surface, g_value_get_string (value));
4972       g_object_notify_by_pspec (G_OBJECT (surface), pspec);
4973       break;
4974 
4975     case LAST_PROP + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
4976       gdk_x11_surface_set_transient_for (surface, g_value_get_object (value));
4977       g_object_notify_by_pspec (G_OBJECT (surface), pspec);
4978       break;
4979 
4980     case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL:
4981       gdk_x11_surface_set_modal_hint (surface, g_value_get_boolean (value));
4982       g_object_notify_by_pspec (G_OBJECT (surface), pspec);
4983       break;
4984 
4985     case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
4986       gdk_x11_surface_set_icon_list (surface, g_value_get_pointer (value));
4987       g_object_notify_by_pspec (G_OBJECT (surface), pspec);
4988       break;
4989 
4990     case LAST_PROP + GDK_TOPLEVEL_PROP_DECORATED:
4991       gdk_x11_surface_set_decorations (surface, g_value_get_boolean (value) ? GDK_DECOR_ALL : 0);
4992       g_object_notify_by_pspec (G_OBJECT (surface), pspec);
4993       break;
4994 
4995     case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
4996       gdk_x11_surface_set_functions (surface, g_value_get_boolean (value) ? GDK_FUNC_ALL : GDK_FUNC_ALL | GDK_FUNC_CLOSE);
4997       g_object_notify_by_pspec (G_OBJECT (surface), pspec);
4998       break;
4999 
5000     case LAST_PROP + GDK_TOPLEVEL_PROP_FULLSCREEN_MODE:
5001       surface->fullscreen_mode = g_value_get_enum (value);
5002       gdk_x11_surface_apply_fullscreen_mode (surface);
5003       g_object_notify_by_pspec (G_OBJECT (surface), pspec);
5004       break;
5005 
5006     case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
5007       break;
5008 
5009     default:
5010       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5011       break;
5012     }
5013 }
5014 
5015 static void
gdk_x11_toplevel_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)5016 gdk_x11_toplevel_get_property (GObject    *object,
5017                                guint       prop_id,
5018                                GValue     *value,
5019                                GParamSpec *pspec)
5020 {
5021   GdkSurface *surface = GDK_SURFACE (object);
5022 
5023   switch (prop_id)
5024     {
5025     case LAST_PROP + GDK_TOPLEVEL_PROP_STATE:
5026       g_value_set_flags (value, surface->state);
5027       break;
5028 
5029     case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE:
5030       g_value_set_string (value, "");
5031       break;
5032 
5033     case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID:
5034       g_value_set_string (value, "");
5035       break;
5036 
5037     case LAST_PROP + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
5038       g_value_set_object (value, surface->transient_for);
5039       break;
5040 
5041     case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL:
5042       g_value_set_boolean (value, surface->modal_hint);
5043       break;
5044 
5045     case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
5046       g_value_set_pointer (value, NULL);
5047       break;
5048 
5049     case LAST_PROP + GDK_TOPLEVEL_PROP_DECORATED:
5050       {
5051         GdkWMDecoration decorations = GDK_DECOR_ALL;
5052         gdk_x11_surface_get_decorations (surface, &decorations);
5053         g_value_set_boolean (value, decorations != 0);
5054       }
5055       break;
5056 
5057     case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
5058       {
5059         GdkWMFunction functions = GDK_FUNC_ALL;
5060         gdk_x11_surface_get_functions (surface, &functions);
5061         g_value_set_boolean (value, functions == GDK_FUNC_ALL);
5062       }
5063       break;
5064 
5065     case LAST_PROP + GDK_TOPLEVEL_PROP_FULLSCREEN_MODE:
5066       g_value_set_enum (value, surface->fullscreen_mode);
5067       break;
5068 
5069     case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
5070       g_value_set_boolean (value, surface->shortcuts_inhibited);
5071       break;
5072 
5073     default:
5074       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5075       break;
5076     }
5077 }
5078 
5079 static void
gdk_x11_toplevel_class_init(GdkX11ToplevelClass * class)5080 gdk_x11_toplevel_class_init (GdkX11ToplevelClass *class)
5081 {
5082   GObjectClass *object_class = G_OBJECT_CLASS (class);
5083 
5084   object_class->get_property = gdk_x11_toplevel_get_property;
5085   object_class->set_property = gdk_x11_toplevel_set_property;
5086 
5087   gdk_toplevel_install_properties (object_class, LAST_PROP);
5088 }
5089 
5090 static void
gdk_x11_toplevel_present(GdkToplevel * toplevel,GdkToplevelLayout * layout)5091 gdk_x11_toplevel_present (GdkToplevel       *toplevel,
5092                           GdkToplevelLayout *layout)
5093 {
5094   GdkSurface *surface = GDK_SURFACE (toplevel);
5095   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
5096   int width, height;
5097   gboolean was_mapped;
5098   gboolean maximize;
5099   gboolean fullscreen;
5100 
5101   if (surface->destroyed)
5102     return;
5103 
5104   was_mapped = GDK_SURFACE_IS_MAPPED (surface);
5105 
5106   gdk_x11_surface_unminimize (surface);
5107 
5108   g_clear_pointer (&impl->toplevel_layout, gdk_toplevel_layout_unref);
5109   impl->toplevel_layout = gdk_toplevel_layout_copy (layout);
5110 
5111   if (compute_toplevel_size (surface, DONT_UPDATE_GEOMETRY, &width, &height))
5112     gdk_x11_surface_toplevel_resize (surface, width, height);
5113 
5114   if (gdk_toplevel_layout_get_maximized (layout, &maximize))
5115     {
5116       if (maximize)
5117         gdk_x11_surface_maximize (surface);
5118       else
5119         gdk_x11_surface_unmaximize (surface);
5120     }
5121 
5122   if (gdk_toplevel_layout_get_fullscreen (layout, &fullscreen))
5123     {
5124       if (fullscreen)
5125         {
5126           GdkMonitor *fullscreen_monitor =
5127             gdk_toplevel_layout_get_fullscreen_monitor (layout);
5128 
5129           if (fullscreen_monitor)
5130             gdk_x11_surface_fullscreen_on_monitor (surface, fullscreen_monitor);
5131           else
5132             gdk_x11_surface_fullscreen (surface);
5133         }
5134       else
5135         {
5136           gdk_x11_surface_unfullscreen (surface);
5137         }
5138     }
5139 
5140   impl->next_layout.surface_geometry_dirty = TRUE;
5141   gdk_surface_request_layout (surface);
5142 
5143   if (!was_mapped)
5144     gdk_surface_set_is_mapped (surface, TRUE);
5145 
5146   gdk_x11_surface_show (surface, was_mapped);
5147 
5148   if (!was_mapped)
5149     gdk_surface_invalidate_rect (surface, NULL);
5150 }
5151 
5152 static gboolean
gdk_x11_toplevel_minimize(GdkToplevel * toplevel)5153 gdk_x11_toplevel_minimize (GdkToplevel *toplevel)
5154 {
5155   gdk_x11_surface_minimize (GDK_SURFACE (toplevel));
5156 
5157   return TRUE;
5158 }
5159 
5160 static gboolean
gdk_x11_toplevel_lower(GdkToplevel * toplevel)5161 gdk_x11_toplevel_lower (GdkToplevel *toplevel)
5162 {
5163   gdk_x11_surface_lower (GDK_SURFACE (toplevel));
5164 
5165   return TRUE;
5166 }
5167 
5168 static void
gdk_x11_toplevel_focus(GdkToplevel * toplevel,guint32 timestamp)5169 gdk_x11_toplevel_focus (GdkToplevel *toplevel,
5170                         guint32      timestamp)
5171 {
5172   gdk_x11_surface_focus (GDK_SURFACE (toplevel), timestamp);
5173 }
5174 
5175 static gboolean
gdk_x11_toplevel_show_window_menu(GdkToplevel * toplevel,GdkEvent * event)5176 gdk_x11_toplevel_show_window_menu (GdkToplevel *toplevel,
5177                                    GdkEvent    *event)
5178 {
5179   return gdk_x11_surface_show_window_menu (GDK_SURFACE (toplevel), event);
5180 }
5181 
5182 static gboolean
gdk_x11_toplevel_supports_edge_constraints(GdkToplevel * toplevel)5183 gdk_x11_toplevel_supports_edge_constraints (GdkToplevel *toplevel)
5184 {
5185   return gdk_x11_surface_supports_edge_constraints (GDK_SURFACE (toplevel));
5186 }
5187 
5188 static void
gdk_x11_toplevel_inhibit_system_shortcuts(GdkToplevel * toplevel,GdkEvent * gdk_event)5189 gdk_x11_toplevel_inhibit_system_shortcuts (GdkToplevel *toplevel,
5190                                            GdkEvent    *gdk_event)
5191 {
5192   GdkSurface *surface = GDK_SURFACE (toplevel);
5193   GdkSeat *gdk_seat;
5194   GdkGrabStatus status;
5195 
5196   if (surface->shortcuts_inhibited)
5197     return; /* Already inhibited */
5198 
5199   if (!(surface->state & GDK_TOPLEVEL_STATE_FOCUSED))
5200     return;
5201 
5202   gdk_seat = gdk_surface_get_seat_from_event (surface, gdk_event);
5203 
5204   if (!(gdk_seat_get_capabilities (gdk_seat) & GDK_SEAT_CAPABILITY_KEYBOARD))
5205     return;
5206 
5207   status = gdk_seat_grab (gdk_seat, surface, GDK_SEAT_CAPABILITY_KEYBOARD,
5208                           TRUE, NULL, gdk_event, NULL, NULL);
5209 
5210   if (status != GDK_GRAB_SUCCESS)
5211     return;
5212 
5213   surface->shortcuts_inhibited = TRUE;
5214   surface->current_shortcuts_inhibited_seat = gdk_seat;
5215   g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited");
5216 }
5217 
5218 static void
gdk_x11_toplevel_restore_system_shortcuts(GdkToplevel * toplevel)5219 gdk_x11_toplevel_restore_system_shortcuts (GdkToplevel *toplevel)
5220 {
5221   GdkSurface *surface = GDK_SURFACE (toplevel);
5222   GdkSeat *gdk_seat;
5223 
5224   if (!surface->shortcuts_inhibited)
5225     return; /* Not inhibited */
5226 
5227   gdk_seat = surface->current_shortcuts_inhibited_seat;
5228   gdk_seat_ungrab (gdk_seat);
5229   surface->current_shortcuts_inhibited_seat = NULL;
5230 
5231   surface->shortcuts_inhibited = FALSE;
5232   g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited");
5233 }
5234 
5235 static void
gdk_x11_toplevel_state_callback(GdkSurface * surface)5236 gdk_x11_toplevel_state_callback (GdkSurface *surface)
5237 {
5238   if (surface->state & GDK_TOPLEVEL_STATE_FOCUSED)
5239     return;
5240 
5241   if (surface->shortcuts_inhibited)
5242     gdk_x11_toplevel_restore_system_shortcuts (GDK_TOPLEVEL (surface));
5243 }
5244 
5245 static gboolean
gdk_x11_toplevel_event_callback(GdkSurface * surface,GdkEvent * gdk_event)5246 gdk_x11_toplevel_event_callback (GdkSurface *surface,
5247                                  GdkEvent   *gdk_event)
5248 {
5249   GdkSeat *gdk_seat;
5250 
5251   if (!surface->shortcuts_inhibited)
5252     return FALSE;
5253 
5254   if (gdk_event_get_event_type (gdk_event) != GDK_GRAB_BROKEN)
5255     return FALSE;
5256 
5257   gdk_seat = gdk_surface_get_seat_from_event (surface, gdk_event);
5258   if (gdk_seat != surface->current_shortcuts_inhibited_seat)
5259     return FALSE;
5260 
5261   surface->current_shortcuts_inhibited_seat = NULL;
5262   surface->shortcuts_inhibited = FALSE;
5263   g_object_notify (G_OBJECT (surface), "shortcuts-inhibited");
5264 
5265   return FALSE;
5266 }
5267 
5268 static void
gdk_x11_toplevel_iface_init(GdkToplevelInterface * iface)5269 gdk_x11_toplevel_iface_init (GdkToplevelInterface *iface)
5270 {
5271   iface->present = gdk_x11_toplevel_present;
5272   iface->minimize = gdk_x11_toplevel_minimize;
5273   iface->lower = gdk_x11_toplevel_lower;
5274   iface->focus = gdk_x11_toplevel_focus;
5275   iface->show_window_menu = gdk_x11_toplevel_show_window_menu;
5276   iface->supports_edge_constraints = gdk_x11_toplevel_supports_edge_constraints;
5277   iface->inhibit_system_shortcuts = gdk_x11_toplevel_inhibit_system_shortcuts;
5278   iface->restore_system_shortcuts = gdk_x11_toplevel_restore_system_shortcuts;
5279   iface->begin_resize = gdk_x11_toplevel_begin_resize;
5280   iface->begin_move = gdk_x11_toplevel_begin_move;
5281 }
5282 
5283 typedef struct {
5284   GdkX11Surface parent_instance;
5285 } GdkX11DragSurface;
5286 
5287 typedef struct {
5288   GdkX11SurfaceClass parent_class;
5289 } GdkX11DragSurfaceClass;
5290 
5291 static void gdk_x11_drag_surface_iface_init (GdkDragSurfaceInterface *iface);
5292 
G_DEFINE_TYPE_WITH_CODE(GdkX11DragSurface,gdk_x11_drag_surface,GDK_TYPE_X11_SURFACE,G_IMPLEMENT_INTERFACE (GDK_TYPE_DRAG_SURFACE,gdk_x11_drag_surface_iface_init))5293 G_DEFINE_TYPE_WITH_CODE (GdkX11DragSurface, gdk_x11_drag_surface, GDK_TYPE_X11_SURFACE,
5294                          G_IMPLEMENT_INTERFACE (GDK_TYPE_DRAG_SURFACE,
5295                                                 gdk_x11_drag_surface_iface_init))
5296 
5297 static void
5298 gdk_x11_drag_surface_init (GdkX11DragSurface *surface)
5299 {
5300 }
5301 
5302 static void
gdk_x11_drag_surface_class_init(GdkX11DragSurfaceClass * class)5303 gdk_x11_drag_surface_class_init (GdkX11DragSurfaceClass *class)
5304 {
5305 }
5306 
5307 static gboolean
gdk_x11_drag_surface_present(GdkDragSurface * drag_surface,int width,int height)5308 gdk_x11_drag_surface_present (GdkDragSurface *drag_surface,
5309                               int             width,
5310                               int             height)
5311 {
5312   GdkSurface *surface = GDK_SURFACE (drag_surface);
5313 
5314   gdk_x11_surface_toplevel_resize (surface, width, height);
5315   gdk_surface_set_is_mapped (surface, TRUE);
5316   gdk_x11_surface_show (surface, FALSE);
5317   gdk_surface_invalidate_rect (surface, NULL);
5318 
5319   return TRUE;
5320 }
5321 
5322 static void
gdk_x11_drag_surface_iface_init(GdkDragSurfaceInterface * iface)5323 gdk_x11_drag_surface_iface_init (GdkDragSurfaceInterface *iface)
5324 {
5325   iface->present = gdk_x11_drag_surface_present;
5326 }
5327