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

source code of gtk/gdk/x11/gdksurface-x11.c