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