1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /*
4 * Copyright (C) 2001 Havoc Pennington, Anders Carlsson
5 * Copyright (C) 2002, 2003 Red Hat, Inc.
6 * Copyright (C) 2003 Rob Adams
7 * Copyright (C) 2004-2006 Elijah Newren
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "config.h"
24
25 #include "x11/window-x11.h"
26 #include "x11/window-x11-private.h"
27
28 #include <string.h>
29 #include <X11/Xatom.h>
30 #include <X11/Xlibint.h>
31 #include <X11/Xlib-xcb.h>
32 #include <X11/extensions/shape.h>
33 #include <X11/extensions/Xcomposite.h>
34 #include <xcb/res.h>
35
36 #include "backends/meta-logical-monitor.h"
37 #include "backends/x11/meta-backend-x11.h"
38 #include "compositor/meta-window-actor-private.h"
39 #include "core/boxes-private.h"
40 #include "core/frame.h"
41 #include "core/meta-workspace-manager-private.h"
42 #include "core/window-private.h"
43 #include "core/workspace-private.h"
44 #include "meta/common.h"
45 #include "meta/meta-cursor-tracker.h"
46 #include "meta/meta-x11-errors.h"
47 #include "meta/prefs.h"
48 #include "x11/meta-x11-display-private.h"
49 #include "x11/session.h"
50 #include "x11/window-props.h"
51 #include "x11/xprops.h"
52
53 #define TAKE_FOCUS_FALLBACK_DELAY_MS 150
54
55 enum _MetaGtkEdgeConstraints
56 {
57 META_GTK_EDGE_CONSTRAINT_TOP_TILED = 1 << 0,
58 META_GTK_EDGE_CONSTRAINT_TOP_RESIZABLE = 1 << 1,
59 META_GTK_EDGE_CONSTRAINT_RIGHT_TILED = 1 << 2,
60 META_GTK_EDGE_CONSTRAINT_RIGHT_RESIZABLE = 1 << 3,
61 META_GTK_EDGE_CONSTRAINT_BOTTOM_TILED = 1 << 4,
62 META_GTK_EDGE_CONSTRAINT_BOTTOM_RESIZABLE = 1 << 5,
63 META_GTK_EDGE_CONSTRAINT_LEFT_TILED = 1 << 6,
64 META_GTK_EDGE_CONSTRAINT_LEFT_RESIZABLE = 1 << 7
65 } MetaGtkEdgeConstraints;
66
67 G_DEFINE_TYPE_WITH_PRIVATE (MetaWindowX11, meta_window_x11, META_TYPE_WINDOW)
68
69 static void
70 meta_window_x11_maybe_focus_delayed (MetaWindow *window,
71 GQueue *other_focus_candidates,
72 guint32 timestamp);
73
74 static void
meta_window_x11_init(MetaWindowX11 * window_x11)75 meta_window_x11_init (MetaWindowX11 *window_x11)
76 {
77 }
78
79 MetaWindowX11Private *
meta_window_x11_get_private(MetaWindowX11 * window_x11)80 meta_window_x11_get_private (MetaWindowX11 *window_x11)
81 {
82 return meta_window_x11_get_instance_private (window_x11);
83 }
84
85 static void
send_icccm_message(MetaWindow * window,Atom atom,guint32 timestamp)86 send_icccm_message (MetaWindow *window,
87 Atom atom,
88 guint32 timestamp)
89 {
90 /* This comment and code are from twm, copyright
91 * Open Group, Evans & Sutherland, etc.
92 */
93
94 /*
95 * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
96 * client messages will have the following form:
97 *
98 * event type ClientMessage
99 * message type _XA_WM_PROTOCOLS
100 * window tmp->w
101 * format 32
102 * data[0] message atom
103 * data[1] time stamp
104 */
105
106 XClientMessageEvent ev;
107 MetaX11Display *x11_display = window->display->x11_display;
108
109 ev.type = ClientMessage;
110 ev.window = window->xwindow;
111 ev.message_type = x11_display->atom_WM_PROTOCOLS;
112 ev.format = 32;
113 ev.data.l[0] = atom;
114 ev.data.l[1] = timestamp;
115
116 meta_x11_error_trap_push (x11_display);
117 XSendEvent (x11_display->xdisplay,
118 window->xwindow, False, 0, (XEvent*) &ev);
119 meta_x11_error_trap_pop (x11_display);
120 }
121
122 static Window
read_client_leader(MetaDisplay * display,Window xwindow)123 read_client_leader (MetaDisplay *display,
124 Window xwindow)
125 {
126 Window retval = None;
127
128 meta_prop_get_window (display->x11_display, xwindow,
129 display->x11_display->atom_WM_CLIENT_LEADER,
130 &retval);
131
132 return retval;
133 }
134
135 typedef struct
136 {
137 Window leader;
138 } ClientLeaderData;
139
140 static gboolean
find_client_leader_func(MetaWindow * ancestor,void * data)141 find_client_leader_func (MetaWindow *ancestor,
142 void *data)
143 {
144 ClientLeaderData *d;
145
146 d = data;
147
148 d->leader = read_client_leader (ancestor->display,
149 ancestor->xwindow);
150
151 /* keep going if no client leader found */
152 return d->leader == None;
153 }
154
155 static void
update_sm_hints(MetaWindow * window)156 update_sm_hints (MetaWindow *window)
157 {
158 Window leader;
159
160 window->xclient_leader = None;
161 window->sm_client_id = NULL;
162
163 /* If not on the current window, we can get the client
164 * leader from transient parents. If we find a client
165 * leader, we read the SM_CLIENT_ID from it.
166 */
167 leader = read_client_leader (window->display, window->xwindow);
168 if (leader == None)
169 {
170 ClientLeaderData d;
171 d.leader = None;
172 meta_window_foreach_ancestor (window, find_client_leader_func,
173 &d);
174 leader = d.leader;
175 }
176
177 if (leader != None)
178 {
179 window->xclient_leader = leader;
180
181 meta_prop_get_latin1_string (window->display->x11_display, leader,
182 window->display->x11_display->atom_SM_CLIENT_ID,
183 &window->sm_client_id);
184 }
185 else
186 {
187 meta_verbose ("Didn't find a client leader for %s", window->desc);
188
189 if (!meta_prefs_get_disable_workarounds ())
190 {
191 /* Some broken apps (kdelibs fault?) set SM_CLIENT_ID on the app
192 * instead of the client leader
193 */
194 meta_prop_get_latin1_string (window->display->x11_display, window->xwindow,
195 window->display->x11_display->atom_SM_CLIENT_ID,
196 &window->sm_client_id);
197
198 if (window->sm_client_id)
199 meta_warning ("Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER window as specified in the ICCCM.",
200 window->desc);
201 }
202 }
203
204 meta_verbose ("Window %s client leader: 0x%lx SM_CLIENT_ID: '%s'",
205 window->desc, window->xclient_leader,
206 window->sm_client_id ? window->sm_client_id : "none");
207 }
208
209 static void
send_configure_notify(MetaWindow * window)210 send_configure_notify (MetaWindow *window)
211 {
212 MetaX11Display *x11_display = window->display->x11_display;
213 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
214 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
215 XEvent event;
216
217 g_assert (!window->override_redirect);
218
219 /* from twm */
220
221 event.type = ConfigureNotify;
222 event.xconfigure.display = x11_display->xdisplay;
223 event.xconfigure.event = window->xwindow;
224 event.xconfigure.window = window->xwindow;
225 event.xconfigure.x = priv->client_rect.x - priv->border_width;
226 event.xconfigure.y = priv->client_rect.y - priv->border_width;
227 if (window->frame)
228 {
229 if (window->withdrawn)
230 {
231 MetaFrameBorders borders;
232 /* We reparent the client window and put it to the position
233 * where the visible top-left of the frame window currently is.
234 */
235
236 meta_frame_calc_borders (window->frame, &borders);
237
238 event.xconfigure.x = window->frame->rect.x + borders.invisible.left;
239 event.xconfigure.y = window->frame->rect.y + borders.invisible.top;
240 }
241 else
242 {
243 /* Need to be in root window coordinates */
244 event.xconfigure.x += window->frame->rect.x;
245 event.xconfigure.y += window->frame->rect.y;
246 }
247 }
248 event.xconfigure.width = priv->client_rect.width;
249 event.xconfigure.height = priv->client_rect.height;
250 event.xconfigure.border_width = priv->border_width; /* requested not actual */
251 event.xconfigure.above = None; /* FIXME */
252 event.xconfigure.override_redirect = False;
253
254 meta_topic (META_DEBUG_GEOMETRY,
255 "Sending synthetic configure notify to %s with x: %d y: %d w: %d h: %d",
256 window->desc,
257 event.xconfigure.x, event.xconfigure.y,
258 event.xconfigure.width, event.xconfigure.height);
259
260 meta_x11_error_trap_push (x11_display);
261 XSendEvent (x11_display->xdisplay,
262 window->xwindow,
263 False, StructureNotifyMask, &event);
264 meta_x11_error_trap_pop (x11_display);
265 }
266
267 static void
adjust_for_gravity(MetaWindow * window,gboolean coords_assume_border,MetaGravity gravity,MetaRectangle * rect)268 adjust_for_gravity (MetaWindow *window,
269 gboolean coords_assume_border,
270 MetaGravity gravity,
271 MetaRectangle *rect)
272 {
273 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
274 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
275 int ref_x, ref_y;
276 int bw;
277 int child_x, child_y;
278 int frame_width, frame_height;
279 MetaFrameBorders borders;
280
281 /* We're computing position to pass to window_move, which is
282 * the position of the client window (META_GRAVITY_STATIC basically)
283 *
284 * (see WM spec description of gravity computation, but note that
285 * their formulas assume we're honoring the border width, rather
286 * than compensating for having turned it off)
287 */
288
289 if (gravity == META_GRAVITY_STATIC)
290 return;
291
292 if (coords_assume_border)
293 bw = priv->border_width;
294 else
295 bw = 0;
296
297 meta_frame_calc_borders (window->frame, &borders);
298
299 child_x = borders.visible.left;
300 child_y = borders.visible.top;
301 frame_width = child_x + rect->width + borders.visible.right;
302 frame_height = child_y + rect->height + borders.visible.bottom;
303
304 /* Calculate the the reference point, which is the corner of the
305 * outer window specified by the gravity. So, META_GRAVITY_NORTH_EAST
306 * would have the reference point as the top-right corner of the
307 * outer window. */
308 ref_x = rect->x;
309 ref_y = rect->y;
310
311 switch (gravity)
312 {
313 case META_GRAVITY_NORTH:
314 case META_GRAVITY_CENTER:
315 case META_GRAVITY_SOUTH:
316 ref_x += rect->width / 2 + bw;
317 break;
318 case META_GRAVITY_NORTH_EAST:
319 case META_GRAVITY_EAST:
320 case META_GRAVITY_SOUTH_EAST:
321 ref_x += rect->width + bw * 2;
322 break;
323 default:
324 break;
325 }
326
327 switch (gravity)
328 {
329 case META_GRAVITY_WEST:
330 case META_GRAVITY_CENTER:
331 case META_GRAVITY_EAST:
332 ref_y += rect->height / 2 + bw;
333 break;
334 case META_GRAVITY_SOUTH_WEST:
335 case META_GRAVITY_SOUTH:
336 case META_GRAVITY_SOUTH_EAST:
337 ref_y += rect->height + bw * 2;
338 break;
339 default:
340 break;
341 }
342
343 /* Find the top-left corner of the outer window from
344 * the reference point. */
345
346 rect->x = ref_x;
347 rect->y = ref_y;
348
349 switch (gravity)
350 {
351 case META_GRAVITY_NORTH:
352 case META_GRAVITY_CENTER:
353 case META_GRAVITY_SOUTH:
354 rect->x -= frame_width / 2;
355 break;
356 case META_GRAVITY_NORTH_EAST:
357 case META_GRAVITY_EAST:
358 case META_GRAVITY_SOUTH_EAST:
359 rect->x -= frame_width;
360 break;
361 default:
362 break;
363 }
364
365 switch (gravity)
366 {
367 case META_GRAVITY_WEST:
368 case META_GRAVITY_CENTER:
369 case META_GRAVITY_EAST:
370 rect->y -= frame_height / 2;
371 break;
372 case META_GRAVITY_SOUTH_WEST:
373 case META_GRAVITY_SOUTH:
374 case META_GRAVITY_SOUTH_EAST:
375 rect->y -= frame_height;
376 break;
377 default:
378 break;
379 }
380
381 /* Adjust to get the top-left corner of the inner window. */
382 rect->x += child_x;
383 rect->y += child_y;
384 }
385
386 static void
meta_window_apply_session_info(MetaWindow * window,const MetaWindowSessionInfo * info)387 meta_window_apply_session_info (MetaWindow *window,
388 const MetaWindowSessionInfo *info)
389 {
390 if (info->stack_position_set)
391 {
392 meta_topic (META_DEBUG_SM,
393 "Restoring stack position %d for window %s",
394 info->stack_position, window->desc);
395
396 /* FIXME well, I'm not sure how to do this. */
397 }
398
399 if (info->minimized_set)
400 {
401 meta_topic (META_DEBUG_SM,
402 "Restoring minimized state %d for window %s",
403 info->minimized, window->desc);
404
405 if (info->minimized)
406 meta_window_minimize (window);
407 }
408
409 if (info->maximized_set)
410 {
411 meta_topic (META_DEBUG_SM,
412 "Restoring maximized state %d for window %s",
413 info->maximized, window->desc);
414
415 if (window->has_maximize_func && info->maximized)
416 {
417 meta_window_maximize (window, META_MAXIMIZE_BOTH);
418
419 if (info->saved_rect_set)
420 {
421 meta_topic (META_DEBUG_SM,
422 "Restoring saved rect %d,%d %dx%d for window %s",
423 info->saved_rect.x,
424 info->saved_rect.y,
425 info->saved_rect.width,
426 info->saved_rect.height,
427 window->desc);
428
429 window->saved_rect.x = info->saved_rect.x;
430 window->saved_rect.y = info->saved_rect.y;
431 window->saved_rect.width = info->saved_rect.width;
432 window->saved_rect.height = info->saved_rect.height;
433 }
434 }
435 }
436
437 if (info->on_all_workspaces_set)
438 {
439 window->on_all_workspaces_requested = info->on_all_workspaces;
440 meta_window_on_all_workspaces_changed (window);
441 meta_topic (META_DEBUG_SM,
442 "Restoring sticky state %d for window %s",
443 window->on_all_workspaces_requested, window->desc);
444 }
445
446 if (info->workspace_indices)
447 {
448 GSList *tmp;
449 GSList *spaces;
450
451 spaces = NULL;
452
453 tmp = info->workspace_indices;
454 while (tmp != NULL)
455 {
456 MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
457 MetaWorkspace *space;
458
459 space =
460 meta_workspace_manager_get_workspace_by_index (workspace_manager,
461 GPOINTER_TO_INT (tmp->data));
462
463 if (space)
464 spaces = g_slist_prepend (spaces, space);
465
466 tmp = tmp->next;
467 }
468
469 if (spaces)
470 {
471 /* XXX: What should we do if there's more than one workspace
472 * listed? We only support one workspace for each window.
473 *
474 * For now, just choose the first one.
475 */
476 MetaWorkspace *workspace = spaces->data;
477
478 meta_window_change_workspace (window, workspace);
479 window->initial_workspace_set = TRUE;
480
481 meta_topic (META_DEBUG_SM,
482 "Restoring saved window %s to workspace %d",
483 window->desc,
484 meta_workspace_index (workspace));
485
486 g_slist_free (spaces);
487 }
488 }
489
490 if (info->geometry_set)
491 {
492 MetaRectangle rect;
493 MetaMoveResizeFlags flags;
494 MetaGravity gravity;
495
496 window->placed = TRUE; /* don't do placement algorithms later */
497
498 rect.x = info->rect.x;
499 rect.y = info->rect.y;
500
501 rect.width = window->size_hints.base_width + info->rect.width * window->size_hints.width_inc;
502 rect.height = window->size_hints.base_height + info->rect.height * window->size_hints.height_inc;
503
504 /* Force old gravity, ignoring anything now set */
505 window->size_hints.win_gravity = info->gravity;
506 gravity = window->size_hints.win_gravity;
507
508 flags = META_MOVE_RESIZE_MOVE_ACTION | META_MOVE_RESIZE_RESIZE_ACTION;
509
510 adjust_for_gravity (window, FALSE, gravity, &rect);
511 meta_window_client_rect_to_frame_rect (window, &rect, &rect);
512 meta_window_move_resize_internal (window, flags, gravity, rect);
513 }
514 }
515
516 static void
meta_window_x11_manage(MetaWindow * window)517 meta_window_x11_manage (MetaWindow *window)
518 {
519 MetaDisplay *display = window->display;
520 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
521 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
522
523 meta_icon_cache_init (&priv->icon_cache);
524
525 meta_x11_display_register_x_window (display->x11_display,
526 &window->xwindow,
527 window);
528
529 /* assign the window to its group, or create a new group if needed */
530 window->group = NULL;
531 window->xgroup_leader = None;
532 meta_window_compute_group (window);
533
534 meta_window_load_initial_properties (window);
535
536 if (!window->override_redirect)
537 update_sm_hints (window); /* must come after transient_for */
538
539 if (window->decorated)
540 meta_window_ensure_frame (window);
541
542 /* Now try applying saved stuff from the session */
543 {
544 const MetaWindowSessionInfo *info;
545
546 info = meta_window_lookup_saved_state (window);
547
548 if (info)
549 {
550 meta_window_apply_session_info (window, info);
551 meta_window_release_saved_state (info);
552 }
553 }
554
555 /* For override-redirect windows, save the client rect
556 * directly. window->rect was assigned from the XWindowAttributes
557 * in the main meta_window_shared_new.
558 *
559 * For normal windows, do a full ConfigureRequest based on the
560 * window hints, as that's what the ICCCM says to do.
561 */
562 priv->client_rect = window->rect;
563 window->buffer_rect = window->rect;
564
565 if (!window->override_redirect)
566 {
567 MetaRectangle rect;
568 MetaMoveResizeFlags flags;
569 MetaGravity gravity = window->size_hints.win_gravity;
570
571 rect.x = window->size_hints.x;
572 rect.y = window->size_hints.y;
573 rect.width = window->size_hints.width;
574 rect.height = window->size_hints.height;
575
576 flags = META_MOVE_RESIZE_CONFIGURE_REQUEST | META_MOVE_RESIZE_MOVE_ACTION | META_MOVE_RESIZE_RESIZE_ACTION;
577
578 adjust_for_gravity (window, TRUE, gravity, &rect);
579 meta_window_client_rect_to_frame_rect (window, &rect, &rect);
580 meta_window_move_resize_internal (window, flags, gravity, rect);
581 }
582
583 meta_window_x11_update_shape_region (window);
584 meta_window_x11_update_input_region (window);
585 }
586
587 static void
meta_window_x11_unmanage(MetaWindow * window)588 meta_window_x11_unmanage (MetaWindow *window)
589 {
590 MetaX11Display *x11_display = window->display->x11_display;
591 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
592 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
593
594 meta_x11_error_trap_push (x11_display);
595
596 meta_window_x11_destroy_sync_request_alarm (window);
597
598 if (window->withdrawn)
599 {
600 /* We need to clean off the window's state so it
601 * won't be restored if the app maps it again.
602 */
603 meta_verbose ("Cleaning state from window %s", window->desc);
604 XDeleteProperty (x11_display->xdisplay,
605 window->xwindow,
606 x11_display->atom__NET_WM_DESKTOP);
607 XDeleteProperty (x11_display->xdisplay,
608 window->xwindow,
609 x11_display->atom__NET_WM_STATE);
610 XDeleteProperty (x11_display->xdisplay,
611 window->xwindow,
612 x11_display->atom__NET_WM_FULLSCREEN_MONITORS);
613 meta_window_x11_set_wm_state (window);
614 }
615 else
616 {
617 /* We need to put WM_STATE so that others will understand it on
618 * restart.
619 */
620 if (!window->minimized)
621 meta_window_x11_set_wm_state (window);
622
623 /* If we're unmanaging a window that is not withdrawn, then
624 * either (a) mutter is exiting, in which case we need to map
625 * the window so the next WM will know that it's not Withdrawn,
626 * or (b) we want to create a new MetaWindow to replace the
627 * current one, which will happen automatically if we re-map
628 * the X Window.
629 */
630 XMapWindow (x11_display->xdisplay,
631 window->xwindow);
632 }
633
634 meta_x11_display_unregister_x_window (x11_display, window->xwindow);
635
636 /* Put back anything we messed up */
637 if (priv->border_width != 0)
638 XSetWindowBorderWidth (x11_display->xdisplay,
639 window->xwindow,
640 priv->border_width);
641
642 /* No save set */
643 XRemoveFromSaveSet (x11_display->xdisplay,
644 window->xwindow);
645
646 /* Even though the window is now unmanaged, we can't unselect events. This
647 * window might be a window from this process, like a GdkMenu, in
648 * which case it will have pointer events and so forth selected
649 * for it by GDK. There's no way to disentangle those events from the events
650 * we've selected. Even for a window from a different X client,
651 * GDK could also have selected events for it for IPC purposes, so we
652 * can't unselect in that case either.
653 *
654 * Similarly, we can't unselected for events on window->user_time_window.
655 * It might be our own GDK focus window, or it might be a window that a
656 * different client is using for multiple different things:
657 * _NET_WM_USER_TIME_WINDOW and IPC, perhaps.
658 */
659
660 if (window->user_time_window != None)
661 {
662 meta_x11_display_unregister_x_window (x11_display,
663 window->user_time_window);
664 window->user_time_window = None;
665 }
666
667 if (META_X11_DISPLAY_HAS_SHAPE (x11_display))
668 XShapeSelectInput (x11_display->xdisplay, window->xwindow, NoEventMask);
669
670 meta_window_ungrab_keys (window);
671 meta_display_ungrab_window_buttons (window->display, window->xwindow);
672 meta_display_ungrab_focus_window_button (window->display, window);
673
674 meta_x11_error_trap_pop (x11_display);
675
676 if (window->frame)
677 {
678 /* The XReparentWindow call in meta_window_destroy_frame() moves the
679 * window so we need to send a configure notify; see bug 399552. (We
680 * also do this just in case a window got unmaximized.)
681 */
682 send_configure_notify (window);
683
684 meta_window_destroy_frame (window);
685 }
686 }
687
688 void
meta_window_x11_set_wm_ping(MetaWindow * window,gboolean ping)689 meta_window_x11_set_wm_ping (MetaWindow *window,
690 gboolean ping)
691 {
692 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
693 MetaWindowX11Private *priv =
694 meta_window_x11_get_instance_private (window_x11);
695
696 priv->wm_ping = ping;
697 }
698
699 static gboolean
meta_window_x11_can_ping(MetaWindow * window)700 meta_window_x11_can_ping (MetaWindow *window)
701 {
702 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
703 MetaWindowX11Private *priv =
704 meta_window_x11_get_instance_private (window_x11);
705
706 return priv->wm_ping;
707 }
708
709 static void
meta_window_x11_ping(MetaWindow * window,guint32 serial)710 meta_window_x11_ping (MetaWindow *window,
711 guint32 serial)
712 {
713 MetaDisplay *display = window->display;
714
715 send_icccm_message (window, display->x11_display->atom__NET_WM_PING, serial);
716 }
717
718 void
meta_window_x11_set_wm_delete_window(MetaWindow * window,gboolean delete_window)719 meta_window_x11_set_wm_delete_window (MetaWindow *window,
720 gboolean delete_window)
721 {
722 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
723 MetaWindowX11Private *priv =
724 meta_window_x11_get_instance_private (window_x11);
725
726 priv->wm_delete_window = delete_window;
727 }
728
729 static void
meta_window_x11_delete(MetaWindow * window,guint32 timestamp)730 meta_window_x11_delete (MetaWindow *window,
731 guint32 timestamp)
732 {
733 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
734 MetaWindowX11Private *priv =
735 meta_window_x11_get_instance_private (window_x11);
736 MetaX11Display *x11_display = window->display->x11_display;
737
738 meta_x11_error_trap_push (x11_display);
739 if (priv->wm_delete_window)
740 {
741 meta_topic (META_DEBUG_WINDOW_OPS,
742 "Deleting %s with delete_window request",
743 window->desc);
744 send_icccm_message (window, x11_display->atom_WM_DELETE_WINDOW, timestamp);
745 }
746 else
747 {
748 meta_topic (META_DEBUG_WINDOW_OPS,
749 "Deleting %s with explicit kill",
750 window->desc);
751 XKillClient (x11_display->xdisplay, window->xwindow);
752 }
753 meta_x11_error_trap_pop (x11_display);
754 }
755
756 static void
meta_window_x11_kill(MetaWindow * window)757 meta_window_x11_kill (MetaWindow *window)
758 {
759 MetaX11Display *x11_display = window->display->x11_display;
760
761 meta_topic (META_DEBUG_WINDOW_OPS,
762 "Disconnecting %s with XKillClient()",
763 window->desc);
764
765 meta_x11_error_trap_push (x11_display);
766 XKillClient (x11_display->xdisplay, window->xwindow);
767 meta_x11_error_trap_pop (x11_display);
768 }
769
770 static void
request_take_focus(MetaWindow * window,guint32 timestamp)771 request_take_focus (MetaWindow *window,
772 guint32 timestamp)
773 {
774 MetaDisplay *display = window->display;
775
776 meta_topic (META_DEBUG_FOCUS, "WM_TAKE_FOCUS(%s, %u)",
777 window->desc, timestamp);
778
779 send_icccm_message (window, display->x11_display->atom_WM_TAKE_FOCUS, timestamp);
780 }
781
782 typedef struct
783 {
784 MetaWindow *window;
785 GQueue *pending_focus_candidates;
786 guint32 timestamp;
787 guint timeout_id;
788 gulong unmanaged_id;
789 gulong focused_changed_id;
790 } MetaWindowX11DelayedFocusData;
791
792 static void
disconnect_pending_focus_window_signals(MetaWindow * window,GQueue * focus_candidates)793 disconnect_pending_focus_window_signals (MetaWindow *window,
794 GQueue *focus_candidates)
795 {
796 g_signal_handlers_disconnect_by_func (window, g_queue_remove,
797 focus_candidates);
798 }
799
800 static void
meta_window_x11_delayed_focus_data_free(MetaWindowX11DelayedFocusData * data)801 meta_window_x11_delayed_focus_data_free (MetaWindowX11DelayedFocusData *data)
802 {
803 g_clear_signal_handler (&data->unmanaged_id, data->window);
804 g_clear_signal_handler (&data->focused_changed_id, data->window->display);
805
806 if (data->pending_focus_candidates)
807 {
808 g_queue_foreach (data->pending_focus_candidates,
809 (GFunc) disconnect_pending_focus_window_signals,
810 data->pending_focus_candidates);
811 g_queue_free (data->pending_focus_candidates);
812 }
813
814 g_clear_handle_id (&data->timeout_id, g_source_remove);
815 g_free (data);
816 }
817
818 static void
focus_candidates_maybe_take_and_focus_next(GQueue ** focus_candidates_ptr,guint32 timestamp)819 focus_candidates_maybe_take_and_focus_next (GQueue **focus_candidates_ptr,
820 guint32 timestamp)
821 {
822 MetaWindow *focus_window;
823 GQueue *focus_candidates;
824
825 g_assert (*focus_candidates_ptr);
826
827 if (g_queue_is_empty (*focus_candidates_ptr))
828 return;
829
830 focus_candidates = g_steal_pointer (focus_candidates_ptr);
831 focus_window = g_queue_pop_head (focus_candidates);
832
833 disconnect_pending_focus_window_signals (focus_window, focus_candidates);
834 meta_window_x11_maybe_focus_delayed (focus_window, focus_candidates, timestamp);
835 }
836
837 static void
focus_window_delayed_unmanaged(gpointer user_data)838 focus_window_delayed_unmanaged (gpointer user_data)
839 {
840 MetaWindowX11DelayedFocusData *data = user_data;
841 uint32_t timestamp = data->timestamp;
842
843 focus_candidates_maybe_take_and_focus_next (&data->pending_focus_candidates,
844 timestamp);
845
846 meta_window_x11_delayed_focus_data_free (data);
847 }
848
849 static gboolean
focus_window_delayed_timeout(gpointer user_data)850 focus_window_delayed_timeout (gpointer user_data)
851 {
852 MetaWindowX11DelayedFocusData *data = user_data;
853 MetaWindow *window = data->window;
854 guint32 timestamp = data->timestamp;
855
856 focus_candidates_maybe_take_and_focus_next (&data->pending_focus_candidates,
857 timestamp);
858
859 data->timeout_id = 0;
860 meta_window_x11_delayed_focus_data_free (data);
861
862 meta_window_focus (window, timestamp);
863
864 return G_SOURCE_REMOVE;
865 }
866
867 static void
meta_window_x11_maybe_focus_delayed(MetaWindow * window,GQueue * other_focus_candidates,guint32 timestamp)868 meta_window_x11_maybe_focus_delayed (MetaWindow *window,
869 GQueue *other_focus_candidates,
870 guint32 timestamp)
871 {
872 MetaWindowX11DelayedFocusData *data;
873
874 data = g_new0 (MetaWindowX11DelayedFocusData, 1);
875 data->window = window;
876 data->timestamp = timestamp;
877 data->pending_focus_candidates = other_focus_candidates;
878
879 meta_topic (META_DEBUG_FOCUS,
880 "Requesting delayed focus to %s", window->desc);
881
882 data->unmanaged_id =
883 g_signal_connect_swapped (window, "unmanaged",
884 G_CALLBACK (focus_window_delayed_unmanaged),
885 data);
886
887 data->focused_changed_id =
888 g_signal_connect_swapped (window->display, "notify::focus-window",
889 G_CALLBACK (meta_window_x11_delayed_focus_data_free),
890 data);
891
892 data->timeout_id = g_timeout_add (TAKE_FOCUS_FALLBACK_DELAY_MS,
893 focus_window_delayed_timeout, data);
894 }
895
896 static void
maybe_focus_default_window(MetaDisplay * display,MetaWindow * not_this_one,guint32 timestamp)897 maybe_focus_default_window (MetaDisplay *display,
898 MetaWindow *not_this_one,
899 guint32 timestamp)
900 {
901 MetaWorkspace *workspace;
902 MetaStack *stack = display->stack;
903 g_autoptr (GList) focusable_windows = NULL;
904 g_autoptr (GQueue) focus_candidates = NULL;
905 GList *l;
906
907 if (not_this_one && not_this_one->workspace)
908 workspace = not_this_one->workspace;
909 else
910 workspace = display->workspace_manager->active_workspace;
911
912 /* Go through all the focusable windows and try to focus them
913 * in order, waiting for a delay. The first one that replies to
914 * the request (in case of take focus windows) changing the display
915 * focused window, will stop the chained requests.
916 */
917 focusable_windows =
918 meta_stack_get_default_focus_candidates (stack, workspace);
919 focus_candidates = g_queue_new ();
920
921 for (l = g_list_last (focusable_windows); l; l = l->prev)
922 {
923 MetaWindow *focus_window = l->data;
924
925 if (focus_window == not_this_one)
926 continue;
927
928 g_queue_push_tail (focus_candidates, focus_window);
929 g_signal_connect_swapped (focus_window, "unmanaged",
930 G_CALLBACK (g_queue_remove),
931 focus_candidates);
932
933 if (!META_IS_WINDOW_X11 (focus_window))
934 break;
935
936 if (focus_window->input)
937 break;
938
939 if (focus_window->shaded && focus_window->frame)
940 break;
941 }
942
943 focus_candidates_maybe_take_and_focus_next (&focus_candidates, timestamp);
944 }
945
946 static void
meta_window_x11_focus(MetaWindow * window,guint32 timestamp)947 meta_window_x11_focus (MetaWindow *window,
948 guint32 timestamp)
949 {
950 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
951 MetaWindowX11Private *priv =
952 meta_window_x11_get_instance_private (window_x11);
953 /* For output-only or shaded windows, focus the frame.
954 * This seems to result in the client window getting key events
955 * though, so I don't know if it's icccm-compliant.
956 *
957 * Still, we have to do this or keynav breaks for these windows.
958 */
959 if (window->frame &&
960 (window->shaded || !meta_window_is_focusable (window)))
961 {
962 meta_topic (META_DEBUG_FOCUS,
963 "Focusing frame of %s", window->desc);
964 meta_display_set_input_focus (window->display,
965 window,
966 TRUE,
967 timestamp);
968 }
969 else
970 {
971 if (window->input)
972 {
973 meta_topic (META_DEBUG_FOCUS,
974 "Setting input focus on %s since input = true",
975 window->desc);
976 meta_display_set_input_focus (window->display,
977 window,
978 FALSE,
979 timestamp);
980 }
981
982 if (priv->wm_take_focus)
983 {
984 meta_topic (META_DEBUG_FOCUS,
985 "Sending WM_TAKE_FOCUS to %s since take_focus = true",
986 window->desc);
987
988 if (!window->input)
989 {
990 /* The "Globally Active Input" window case, where the window
991 * doesn't want us to call XSetInputFocus on it, but does
992 * want us to send a WM_TAKE_FOCUS.
993 *
994 * Normally, we want to just leave the focus undisturbed until
995 * the window responds to WM_TAKE_FOCUS, but if we're unmanaging
996 * the current focus window we *need* to move the focus away, so
997 * we focus the no focus window before sending WM_TAKE_FOCUS,
998 * and eventually the default focus window excluding this one,
999 * if meanwhile we don't get any focus request.
1000 */
1001 if (window->display->focus_window != NULL &&
1002 window->display->focus_window->unmanaging)
1003 {
1004 meta_display_unset_input_focus (window->display, timestamp);
1005 maybe_focus_default_window (window->display, window,
1006 timestamp);
1007 }
1008 }
1009
1010 request_take_focus (window, timestamp);
1011 }
1012 }
1013 }
1014
1015 static void
meta_window_get_client_root_coords(MetaWindow * window,MetaRectangle * rect)1016 meta_window_get_client_root_coords (MetaWindow *window,
1017 MetaRectangle *rect)
1018 {
1019 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
1020 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
1021
1022 *rect = priv->client_rect;
1023
1024 if (window->frame)
1025 {
1026 rect->x += window->frame->rect.x;
1027 rect->y += window->frame->rect.y;
1028 }
1029 }
1030
1031 static void
meta_window_refresh_resize_popup(MetaWindow * window)1032 meta_window_refresh_resize_popup (MetaWindow *window)
1033 {
1034 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
1035 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
1036
1037 if (priv->showing_resize_popup)
1038 {
1039 MetaRectangle rect;
1040 int display_w, display_h;
1041
1042 meta_window_get_client_root_coords (window, &rect);
1043
1044 display_w = (rect.width - window->size_hints.base_width);
1045 if (window->size_hints.width_inc > 0)
1046 display_w /= window->size_hints.width_inc;
1047
1048 display_h = (rect.height - window->size_hints.base_height);
1049 if (window->size_hints.height_inc > 0)
1050 display_h /= window->size_hints.height_inc;
1051
1052 meta_display_show_resize_popup (window->display, TRUE, &rect, display_w, display_h);
1053 }
1054 else
1055 {
1056 meta_display_show_resize_popup (window->display, FALSE, NULL, 0, 0);
1057 }
1058 }
1059
1060 static void
meta_window_x11_grab_op_began(MetaWindow * window,MetaGrabOp op)1061 meta_window_x11_grab_op_began (MetaWindow *window,
1062 MetaGrabOp op)
1063 {
1064 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
1065 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
1066
1067 if (meta_grab_op_is_resizing (op))
1068 {
1069 if (window->sync_request_counter != None)
1070 meta_window_x11_create_sync_request_alarm (window);
1071
1072 if (window->size_hints.width_inc > 2 || window->size_hints.height_inc > 2)
1073 {
1074 priv->showing_resize_popup = TRUE;
1075 meta_window_refresh_resize_popup (window);
1076 }
1077 }
1078
1079 META_WINDOW_CLASS (meta_window_x11_parent_class)->grab_op_began (window, op);
1080 }
1081
1082 static void
meta_window_x11_grab_op_ended(MetaWindow * window,MetaGrabOp op)1083 meta_window_x11_grab_op_ended (MetaWindow *window,
1084 MetaGrabOp op)
1085 {
1086 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
1087 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
1088
1089 if (priv->showing_resize_popup)
1090 {
1091 priv->showing_resize_popup = FALSE;
1092 meta_window_refresh_resize_popup (window);
1093 }
1094
1095 META_WINDOW_CLASS (meta_window_x11_parent_class)->grab_op_ended (window, op);
1096 }
1097
1098 static void
update_net_frame_extents(MetaWindow * window)1099 update_net_frame_extents (MetaWindow *window)
1100 {
1101 MetaX11Display *x11_display = window->display->x11_display;
1102
1103 unsigned long data[4];
1104 MetaFrameBorders borders;
1105
1106 meta_frame_calc_borders (window->frame, &borders);
1107 /* Left */
1108 data[0] = borders.visible.left;
1109 /* Right */
1110 data[1] = borders.visible.right;
1111 /* Top */
1112 data[2] = borders.visible.top;
1113 /* Bottom */
1114 data[3] = borders.visible.bottom;
1115
1116 meta_topic (META_DEBUG_GEOMETRY,
1117 "Setting _NET_FRAME_EXTENTS on managed window 0x%lx "
1118 "to left = %lu, right = %lu, top = %lu, bottom = %lu",
1119 window->xwindow, data[0], data[1], data[2], data[3]);
1120
1121 meta_x11_error_trap_push (x11_display);
1122 XChangeProperty (x11_display->xdisplay, window->xwindow,
1123 x11_display->atom__NET_FRAME_EXTENTS,
1124 XA_CARDINAL,
1125 32, PropModeReplace, (guchar*) data, 4);
1126 meta_x11_error_trap_pop (x11_display);
1127 }
1128
1129 static gboolean
is_edge_constraint_resizable(MetaEdgeConstraint constraint)1130 is_edge_constraint_resizable (MetaEdgeConstraint constraint)
1131 {
1132 switch (constraint)
1133 {
1134 case META_EDGE_CONSTRAINT_NONE:
1135 case META_EDGE_CONSTRAINT_WINDOW:
1136 return TRUE;
1137 case META_EDGE_CONSTRAINT_MONITOR:
1138 return FALSE;
1139 }
1140
1141 g_assert_not_reached ();
1142 return FALSE;
1143 }
1144
1145 static gboolean
is_edge_constraint_tiled(MetaEdgeConstraint constraint)1146 is_edge_constraint_tiled (MetaEdgeConstraint constraint)
1147 {
1148 switch (constraint)
1149 {
1150 case META_EDGE_CONSTRAINT_NONE:
1151 return FALSE;
1152 case META_EDGE_CONSTRAINT_WINDOW:
1153 case META_EDGE_CONSTRAINT_MONITOR:
1154 return TRUE;
1155 }
1156
1157 g_assert_not_reached ();
1158 return FALSE;
1159 }
1160
1161 static unsigned long
edge_constraints_to_gtk_edge_constraints(MetaWindow * window)1162 edge_constraints_to_gtk_edge_constraints (MetaWindow *window)
1163 {
1164 unsigned long gtk_edge_constraints = 0;
1165
1166 if (is_edge_constraint_tiled (window->edge_constraints.top))
1167 gtk_edge_constraints |= META_GTK_EDGE_CONSTRAINT_TOP_TILED;
1168 if (is_edge_constraint_resizable (window->edge_constraints.top))
1169 gtk_edge_constraints |= META_GTK_EDGE_CONSTRAINT_TOP_RESIZABLE;
1170
1171 if (is_edge_constraint_tiled (window->edge_constraints.right))
1172 gtk_edge_constraints |= META_GTK_EDGE_CONSTRAINT_RIGHT_TILED;
1173 if (is_edge_constraint_resizable (window->edge_constraints.right))
1174 gtk_edge_constraints |= META_GTK_EDGE_CONSTRAINT_RIGHT_RESIZABLE;
1175
1176 if (is_edge_constraint_tiled (window->edge_constraints.bottom))
1177 gtk_edge_constraints |= META_GTK_EDGE_CONSTRAINT_BOTTOM_TILED;
1178 if (is_edge_constraint_resizable (window->edge_constraints.bottom))
1179 gtk_edge_constraints |= META_GTK_EDGE_CONSTRAINT_BOTTOM_RESIZABLE;
1180
1181 if (is_edge_constraint_tiled (window->edge_constraints.left))
1182 gtk_edge_constraints |= META_GTK_EDGE_CONSTRAINT_LEFT_TILED;
1183 if (is_edge_constraint_resizable (window->edge_constraints.left))
1184 gtk_edge_constraints |= META_GTK_EDGE_CONSTRAINT_LEFT_RESIZABLE;
1185
1186 return gtk_edge_constraints;
1187 }
1188
1189 static void
update_gtk_edge_constraints(MetaWindow * window)1190 update_gtk_edge_constraints (MetaWindow *window)
1191 {
1192 MetaX11Display *x11_display = window->display->x11_display;
1193 unsigned long data[1];
1194
1195 data[0] = edge_constraints_to_gtk_edge_constraints (window);
1196
1197 meta_verbose ("Setting _GTK_EDGE_CONSTRAINTS to %lu", data[0]);
1198
1199 meta_x11_error_trap_push (x11_display);
1200 XChangeProperty (x11_display->xdisplay,
1201 window->xwindow,
1202 x11_display->atom__GTK_EDGE_CONSTRAINTS,
1203 XA_CARDINAL, 32, PropModeReplace,
1204 (guchar*) data, 1);
1205 meta_x11_error_trap_pop (x11_display);
1206 }
1207
1208 static gboolean
sync_request_timeout(gpointer data)1209 sync_request_timeout (gpointer data)
1210 {
1211 MetaWindow *window = data;
1212
1213 window->sync_request_timeout_id = 0;
1214
1215 /* We have now waited for more than a second for the
1216 * application to respond to the sync request
1217 */
1218 window->disable_sync = TRUE;
1219
1220 /* Reset the wait serial, so we don't continue freezing
1221 * window updates
1222 */
1223 window->sync_request_wait_serial = 0;
1224 meta_compositor_sync_updates_frozen (window->display->compositor, window);
1225
1226 if (window == window->display->grab_window &&
1227 meta_grab_op_is_resizing (window->display->grab_op))
1228 {
1229 meta_window_update_resize (window,
1230 window->display->grab_last_edge_resistance_flags,
1231 window->display->grab_latest_motion_x,
1232 window->display->grab_latest_motion_y,
1233 TRUE);
1234 }
1235
1236 return FALSE;
1237 }
1238
1239 static void
send_sync_request(MetaWindow * window)1240 send_sync_request (MetaWindow *window)
1241 {
1242 MetaX11Display *x11_display = window->display->x11_display;
1243 XClientMessageEvent ev;
1244 gint64 wait_serial;
1245
1246 /* For the old style of _NET_WM_SYNC_REQUEST_COUNTER, we just have to
1247 * increase the value, but for the new "extended" style we need to
1248 * pick an even (unfrozen) value sufficiently ahead of the last serial
1249 * that we received from the client; the same code still works
1250 * for the old style. The increment of 240 is specified by the EWMH
1251 * and is (1 second) * (60fps) * (an increment of 4 per frame).
1252 */
1253 wait_serial = window->sync_request_serial + 240;
1254
1255 window->sync_request_wait_serial = wait_serial;
1256
1257 ev.type = ClientMessage;
1258 ev.window = window->xwindow;
1259 ev.message_type = x11_display->atom_WM_PROTOCOLS;
1260 ev.format = 32;
1261 ev.data.l[0] = x11_display->atom__NET_WM_SYNC_REQUEST;
1262 /* FIXME: meta_display_get_current_time() is bad, but since calls
1263 * come from meta_window_move_resize_internal (which in turn come
1264 * from all over), I'm not sure what we can do to fix it. Do we
1265 * want to use _roundtrip, though?
1266 */
1267 ev.data.l[1] = meta_display_get_current_time (window->display);
1268 ev.data.l[2] = wait_serial & G_GUINT64_CONSTANT(0xffffffff);
1269 ev.data.l[3] = wait_serial >> 32;
1270 ev.data.l[4] = window->extended_sync_request_counter ? 1 : 0;
1271
1272 /* We don't need to trap errors here as we are already
1273 * inside an error_trap_push()/pop() pair.
1274 */
1275 XSendEvent (x11_display->xdisplay,
1276 window->xwindow, False, 0, (XEvent*) &ev);
1277
1278 /* We give the window 1 sec to respond to _NET_WM_SYNC_REQUEST;
1279 * if this time expires, we consider the window unresponsive
1280 * and resize it unsynchonized.
1281 */
1282 window->sync_request_timeout_id = g_timeout_add (1000,
1283 sync_request_timeout,
1284 window);
1285 g_source_set_name_by_id (window->sync_request_timeout_id,
1286 "[mutter] sync_request_timeout");
1287
1288 meta_compositor_sync_updates_frozen (window->display->compositor, window);
1289 }
1290
1291 static unsigned long
meta_window_get_net_wm_desktop(MetaWindow * window)1292 meta_window_get_net_wm_desktop (MetaWindow *window)
1293 {
1294 if (window->on_all_workspaces)
1295 return 0xFFFFFFFF;
1296 else
1297 return meta_workspace_index (window->workspace);
1298 }
1299
1300 static void
meta_window_x11_current_workspace_changed(MetaWindow * window)1301 meta_window_x11_current_workspace_changed (MetaWindow *window)
1302 {
1303 MetaX11Display *x11_display = window->display->x11_display;
1304 /* FIXME if on more than one workspace, we claim to be "sticky",
1305 * the WM spec doesn't say what to do here.
1306 */
1307 unsigned long data[1];
1308
1309 if (window->workspace == NULL)
1310 {
1311 /* this happens when unmanaging windows */
1312 return;
1313 }
1314
1315 data[0] = meta_window_get_net_wm_desktop (window);
1316
1317 meta_verbose ("Setting _NET_WM_DESKTOP of %s to %lu",
1318 window->desc, data[0]);
1319
1320 meta_x11_error_trap_push (x11_display);
1321 XChangeProperty (x11_display->xdisplay, window->xwindow,
1322 x11_display->atom__NET_WM_DESKTOP,
1323 XA_CARDINAL,
1324 32, PropModeReplace, (guchar*) data, 1);
1325 meta_x11_error_trap_pop (x11_display);
1326 }
1327
1328 static gboolean
meta_window_x11_can_freeze_commits(MetaWindow * window)1329 meta_window_x11_can_freeze_commits (MetaWindow *window)
1330 {
1331 MetaWindowActor *window_actor;
1332
1333 window_actor = meta_window_actor_from_window (window);
1334 if (window_actor == NULL)
1335 return FALSE;
1336
1337 return meta_window_actor_can_freeze_commits (window_actor);
1338 }
1339
1340 static void
meta_window_x11_move_resize_internal(MetaWindow * window,MetaGravity gravity,MetaRectangle unconstrained_rect,MetaRectangle constrained_rect,MetaRectangle intermediate_rect,int rel_x,int rel_y,MetaMoveResizeFlags flags,MetaMoveResizeResultFlags * result)1341 meta_window_x11_move_resize_internal (MetaWindow *window,
1342 MetaGravity gravity,
1343 MetaRectangle unconstrained_rect,
1344 MetaRectangle constrained_rect,
1345 MetaRectangle intermediate_rect,
1346 int rel_x,
1347 int rel_y,
1348 MetaMoveResizeFlags flags,
1349 MetaMoveResizeResultFlags *result)
1350 {
1351 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
1352 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
1353 MetaFrameBorders borders;
1354 MetaRectangle client_rect;
1355 int size_dx, size_dy;
1356 XWindowChanges values;
1357 unsigned int mask;
1358 gboolean need_configure_notify;
1359 gboolean need_move_client = FALSE;
1360 gboolean need_move_frame = FALSE;
1361 gboolean need_resize_client = FALSE;
1362 gboolean need_resize_frame = FALSE;
1363 gboolean frame_shape_changed = FALSE;
1364 gboolean configure_frame_first;
1365
1366 gboolean is_configure_request;
1367
1368 is_configure_request = (flags & META_MOVE_RESIZE_CONFIGURE_REQUEST) != 0;
1369
1370 meta_frame_calc_borders (window->frame, &borders);
1371
1372 size_dx = constrained_rect.x - window->rect.width;
1373 size_dy = constrained_rect.y - window->rect.height;
1374
1375 window->rect = constrained_rect;
1376
1377 if (window->frame)
1378 {
1379 int new_w, new_h;
1380 int new_x, new_y;
1381
1382 /* Compute new frame size */
1383 new_w = window->rect.width + borders.invisible.left + borders.invisible.right;
1384
1385 if (window->shaded)
1386 new_h = borders.total.top + borders.total.bottom;
1387 else
1388 new_h = window->rect.height + borders.invisible.top + borders.invisible.bottom;
1389
1390 if (new_w != window->frame->rect.width ||
1391 new_h != window->frame->rect.height)
1392 {
1393 need_resize_frame = TRUE;
1394 window->frame->rect.width = new_w;
1395 window->frame->rect.height = new_h;
1396 }
1397
1398 /* Compute new frame coords */
1399 new_x = window->rect.x - borders.invisible.left;
1400 new_y = window->rect.y - borders.invisible.top;
1401
1402 if (new_x != window->frame->rect.x ||
1403 new_y != window->frame->rect.y)
1404 {
1405 need_move_frame = TRUE;
1406 window->frame->rect.x = new_x;
1407 window->frame->rect.y = new_y;
1408 }
1409 }
1410
1411 /* Calculate the new client rect */
1412 meta_window_frame_rect_to_client_rect (window, &constrained_rect, &client_rect);
1413
1414 /* The above client_rect is in root window coordinates. The
1415 * values we need to pass to XConfigureWindow are in parent
1416 * coordinates, so if the window is in a frame, we need to
1417 * correct the x/y positions here. */
1418 if (window->frame)
1419 {
1420 client_rect.x = borders.total.left;
1421 client_rect.y = borders.total.top;
1422 }
1423
1424 if (client_rect.x != priv->client_rect.x ||
1425 client_rect.y != priv->client_rect.y)
1426 {
1427 need_move_client = TRUE;
1428 priv->client_rect.x = client_rect.x;
1429 priv->client_rect.y = client_rect.y;
1430 }
1431
1432 if (client_rect.width != priv->client_rect.width ||
1433 client_rect.height != priv->client_rect.height)
1434 {
1435 need_resize_client = TRUE;
1436 priv->client_rect.width = client_rect.width;
1437 priv->client_rect.height = client_rect.height;
1438 }
1439
1440 /* If frame extents have changed, fill in other frame fields and
1441 change frame's extents property. */
1442 if (window->frame &&
1443 (window->frame->child_x != borders.total.left ||
1444 window->frame->child_y != borders.total.top ||
1445 window->frame->right_width != borders.total.right ||
1446 window->frame->bottom_height != borders.total.bottom))
1447 {
1448 window->frame->child_x = borders.total.left;
1449 window->frame->child_y = borders.total.top;
1450 window->frame->right_width = borders.total.right;
1451 window->frame->bottom_height = borders.total.bottom;
1452
1453 update_net_frame_extents (window);
1454 }
1455
1456 /* See ICCCM 4.1.5 for when to send ConfigureNotify */
1457
1458 need_configure_notify = FALSE;
1459
1460 /* If this is a configure request and we change nothing, then we
1461 * must send configure notify.
1462 */
1463 if (is_configure_request &&
1464 !(need_move_client || need_move_frame ||
1465 need_resize_client || need_resize_frame ||
1466 priv->border_width != 0))
1467 need_configure_notify = TRUE;
1468
1469 /* We must send configure notify if we move but don't resize, since
1470 * the client window may not get a real event
1471 */
1472 if ((need_move_client || need_move_frame) &&
1473 !(need_resize_client || need_resize_frame))
1474 need_configure_notify = TRUE;
1475
1476 /* MapRequest events with a PPosition or UPosition hint with a frame
1477 * are moved by mutter without resizing; send a configure notify
1478 * in such cases. See #322840. (Note that window->constructing is
1479 * only true iff this call is due to a MapRequest, and when
1480 * PPosition/UPosition hints aren't set, mutter seems to send a
1481 * ConfigureNotify anyway due to the above code.)
1482 */
1483 if (window->constructing && window->frame &&
1484 ((window->size_hints.flags & PPosition) ||
1485 (window->size_hints.flags & USPosition)))
1486 need_configure_notify = TRUE;
1487
1488 /* If resizing, freeze commits - This is for Xwayland, and a no-op on Xorg */
1489 if (need_resize_client || need_resize_frame)
1490 {
1491 if (meta_window_x11_can_freeze_commits (window) &&
1492 !meta_window_x11_should_thaw_after_paint (window))
1493 {
1494 meta_window_x11_set_thaw_after_paint (window, TRUE);
1495 meta_window_x11_freeze_commits (window);
1496 }
1497 }
1498
1499 /* The rest of this function syncs our new size/pos with X as
1500 * efficiently as possible
1501 */
1502
1503 /* For nice effect, when growing the window we want to move/resize
1504 * the frame first, when shrinking the window we want to move/resize
1505 * the client first. If we grow one way and shrink the other,
1506 * see which way we're moving "more"
1507 *
1508 * Mail from Owen subject "Suggestion: Gravity and resizing from the left"
1509 * http://mail.gnome.org/archives/wm-spec-list/1999-November/msg00088.html
1510 *
1511 * An annoying fact you need to know in this code is that META_GRAVITY_STATIC
1512 * does nothing if you _only_ resize or _only_ move the frame;
1513 * it must move _and_ resize, otherwise you get META_GRAVITY_NORTH_WEST
1514 * behavior. The move and resize must actually occur, it is not
1515 * enough to set CWX | CWWidth but pass in the current size/pos.
1516 */
1517
1518 /* Normally, we configure the frame first depending on whether
1519 * we grow the frame more than we shrink. The idea is to avoid
1520 * messing up the window contents by having a temporary situation
1521 * where the frame is smaller than the window. However, if we're
1522 * cooperating with the client to create an atomic frame update,
1523 * and the window is redirected, then we should always update
1524 * the frame first, since updating the frame will force a new
1525 * backing pixmap to be allocated, and the old backing pixmap
1526 * will be left undisturbed for us to paint to the screen until
1527 * the client finishes redrawing.
1528 */
1529 if (window->extended_sync_request_counter)
1530 configure_frame_first = TRUE;
1531 else
1532 configure_frame_first = size_dx + size_dy >= 0;
1533
1534 if (configure_frame_first && window->frame)
1535 frame_shape_changed = meta_frame_sync_to_window (window->frame, need_resize_frame);
1536
1537 values.border_width = 0;
1538 values.x = client_rect.x;
1539 values.y = client_rect.y;
1540 values.width = client_rect.width;
1541 values.height = client_rect.height;
1542
1543 mask = 0;
1544 if (is_configure_request && priv->border_width != 0)
1545 mask |= CWBorderWidth; /* must force to 0 */
1546 if (need_move_client)
1547 mask |= (CWX | CWY);
1548 if (need_resize_client)
1549 mask |= (CWWidth | CWHeight);
1550
1551 if (mask != 0)
1552 {
1553 meta_x11_error_trap_push (window->display->x11_display);
1554
1555 if (window == window->display->grab_window &&
1556 meta_grab_op_is_resizing (window->display->grab_op) &&
1557 !window->disable_sync &&
1558 window->sync_request_counter != None &&
1559 window->sync_request_alarm != None &&
1560 window->sync_request_timeout_id == 0)
1561 {
1562 send_sync_request (window);
1563 }
1564
1565 XConfigureWindow (window->display->x11_display->xdisplay,
1566 window->xwindow,
1567 mask,
1568 &values);
1569
1570 meta_x11_error_trap_pop (window->display->x11_display);
1571 }
1572
1573 if (!configure_frame_first && window->frame)
1574 frame_shape_changed = meta_frame_sync_to_window (window->frame, need_resize_frame);
1575
1576 if (window->frame)
1577 window->buffer_rect = window->frame->rect;
1578 else
1579 window->buffer_rect = client_rect;
1580
1581 if (need_configure_notify)
1582 send_configure_notify (window);
1583
1584 if (priv->showing_resize_popup)
1585 meta_window_refresh_resize_popup (window);
1586
1587 if (frame_shape_changed)
1588 *result |= META_MOVE_RESIZE_RESULT_FRAME_SHAPE_CHANGED;
1589 if (need_move_client || need_move_frame)
1590 *result |= META_MOVE_RESIZE_RESULT_MOVED;
1591 if (need_resize_client || need_resize_frame)
1592 *result |= META_MOVE_RESIZE_RESULT_RESIZED;
1593 if (flags & META_MOVE_RESIZE_STATE_CHANGED)
1594 *result |= META_MOVE_RESIZE_RESULT_STATE_CHANGED;
1595
1596 update_gtk_edge_constraints (window);
1597 }
1598
1599 static gboolean
meta_window_x11_update_struts(MetaWindow * window)1600 meta_window_x11_update_struts (MetaWindow *window)
1601 {
1602 GSList *old_struts;
1603 GSList *new_struts;
1604 GSList *old_iter, *new_iter;
1605 uint32_t *struts = NULL;
1606 int nitems;
1607 gboolean changed;
1608
1609 g_return_val_if_fail (!window->override_redirect, FALSE);
1610
1611 meta_verbose ("Updating struts for %s", window->desc);
1612
1613 old_struts = window->struts;
1614 new_struts = NULL;
1615
1616 if (meta_prop_get_cardinal_list (window->display->x11_display,
1617 window->xwindow,
1618 window->display->x11_display->atom__NET_WM_STRUT_PARTIAL,
1619 &struts, &nitems))
1620 {
1621 if (nitems != 12)
1622 meta_verbose ("_NET_WM_STRUT_PARTIAL on %s has %d values instead "
1623 "of 12",
1624 window->desc, nitems);
1625 else
1626 {
1627 /* Pull out the strut info for each side in the hint */
1628 int i;
1629 for (i=0; i<4; i++)
1630 {
1631 MetaStrut *temp;
1632 int thickness, strut_begin, strut_end;
1633
1634 thickness = struts[i];
1635 if (thickness == 0)
1636 continue;
1637 strut_begin = struts[4+(i*2)];
1638 strut_end = struts[4+(i*2)+1];
1639
1640 temp = g_new0 (MetaStrut, 1);
1641 temp->side = 1 << i; /* See MetaSide def. Matches nicely, eh? */
1642 meta_display_get_size (window->display,
1643 &temp->rect.width, &temp->rect.height);
1644 switch (temp->side)
1645 {
1646 case META_SIDE_RIGHT:
1647 temp->rect.x = BOX_RIGHT(temp->rect) - thickness;
1648 G_GNUC_FALLTHROUGH;
1649 case META_SIDE_LEFT:
1650 temp->rect.width = thickness;
1651 temp->rect.y = strut_begin;
1652 temp->rect.height = strut_end - strut_begin + 1;
1653 break;
1654 case META_SIDE_BOTTOM:
1655 temp->rect.y = BOX_BOTTOM(temp->rect) - thickness;
1656 G_GNUC_FALLTHROUGH;
1657 case META_SIDE_TOP:
1658 temp->rect.height = thickness;
1659 temp->rect.x = strut_begin;
1660 temp->rect.width = strut_end - strut_begin + 1;
1661 break;
1662 default:
1663 g_assert_not_reached ();
1664 }
1665
1666 new_struts = g_slist_prepend (new_struts, temp);
1667 }
1668
1669 meta_verbose ("_NET_WM_STRUT_PARTIAL struts %u %u %u %u for "
1670 "window %s",
1671 struts[0], struts[1], struts[2], struts[3],
1672 window->desc);
1673 }
1674 g_free (struts);
1675 }
1676 else
1677 {
1678 meta_verbose ("No _NET_WM_STRUT property for %s",
1679 window->desc);
1680 }
1681
1682 if (!new_struts &&
1683 meta_prop_get_cardinal_list (window->display->x11_display,
1684 window->xwindow,
1685 window->display->x11_display->atom__NET_WM_STRUT,
1686 &struts, &nitems))
1687 {
1688 if (nitems != 4)
1689 meta_verbose ("_NET_WM_STRUT on %s has %d values instead of 4",
1690 window->desc, nitems);
1691 else
1692 {
1693 /* Pull out the strut info for each side in the hint */
1694 int i;
1695 for (i=0; i<4; i++)
1696 {
1697 MetaStrut *temp;
1698 int thickness;
1699
1700 thickness = struts[i];
1701 if (thickness == 0)
1702 continue;
1703
1704 temp = g_new0 (MetaStrut, 1);
1705 temp->side = 1 << i;
1706 meta_display_get_size (window->display,
1707 &temp->rect.width, &temp->rect.height);
1708 switch (temp->side)
1709 {
1710 case META_SIDE_RIGHT:
1711 temp->rect.x = BOX_RIGHT(temp->rect) - thickness;
1712 G_GNUC_FALLTHROUGH;
1713 case META_SIDE_LEFT:
1714 temp->rect.width = thickness;
1715 break;
1716 case META_SIDE_BOTTOM:
1717 temp->rect.y = BOX_BOTTOM(temp->rect) - thickness;
1718 G_GNUC_FALLTHROUGH;
1719 case META_SIDE_TOP:
1720 temp->rect.height = thickness;
1721 break;
1722 default:
1723 g_assert_not_reached ();
1724 }
1725
1726 new_struts = g_slist_prepend (new_struts, temp);
1727 }
1728
1729 meta_verbose ("_NET_WM_STRUT struts %u %u %u %u for window %s",
1730 struts[0], struts[1], struts[2], struts[3],
1731 window->desc);
1732 }
1733 g_free (struts);
1734 }
1735 else if (!new_struts)
1736 {
1737 meta_verbose ("No _NET_WM_STRUT property for %s",
1738 window->desc);
1739 }
1740
1741 /* Determine whether old_struts and new_struts are the same */
1742 old_iter = old_struts;
1743 new_iter = new_struts;
1744 while (old_iter && new_iter)
1745 {
1746 MetaStrut *old_strut = (MetaStrut*) old_iter->data;
1747 MetaStrut *new_strut = (MetaStrut*) new_iter->data;
1748
1749 if (old_strut->side != new_strut->side ||
1750 !meta_rectangle_equal (&old_strut->rect, &new_strut->rect))
1751 break;
1752
1753 old_iter = old_iter->next;
1754 new_iter = new_iter->next;
1755 }
1756 changed = (old_iter != NULL || new_iter != NULL);
1757
1758 /* Update appropriately */
1759 g_slist_free_full (old_struts, g_free);
1760 window->struts = new_struts;
1761 return changed;
1762 }
1763
1764 static void
meta_window_x11_get_default_skip_hints(MetaWindow * window,gboolean * skip_taskbar_out,gboolean * skip_pager_out)1765 meta_window_x11_get_default_skip_hints (MetaWindow *window,
1766 gboolean *skip_taskbar_out,
1767 gboolean *skip_pager_out)
1768 {
1769 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
1770 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
1771
1772 *skip_taskbar_out = priv->wm_state_skip_taskbar;
1773 *skip_pager_out = priv->wm_state_skip_pager;
1774 }
1775
1776 static gboolean
meta_window_x11_update_icon(MetaWindow * window,cairo_surface_t ** icon,cairo_surface_t ** mini_icon)1777 meta_window_x11_update_icon (MetaWindow *window,
1778 cairo_surface_t **icon,
1779 cairo_surface_t **mini_icon)
1780 {
1781 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
1782 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
1783
1784 return meta_read_icons (window->display->x11_display,
1785 window->xwindow,
1786 &priv->icon_cache,
1787 priv->wm_hints_pixmap,
1788 priv->wm_hints_mask,
1789 icon,
1790 META_ICON_WIDTH, META_ICON_HEIGHT,
1791 mini_icon,
1792 META_MINI_ICON_WIDTH, META_MINI_ICON_HEIGHT);
1793 }
1794
1795 static void
meta_window_x11_update_main_monitor(MetaWindow * window,MetaWindowUpdateMonitorFlags flags)1796 meta_window_x11_update_main_monitor (MetaWindow *window,
1797 MetaWindowUpdateMonitorFlags flags)
1798 {
1799 window->monitor = meta_window_calculate_main_logical_monitor (window);
1800 }
1801
1802 static void
meta_window_x11_main_monitor_changed(MetaWindow * window,const MetaLogicalMonitor * old)1803 meta_window_x11_main_monitor_changed (MetaWindow *window,
1804 const MetaLogicalMonitor *old)
1805 {
1806 }
1807
1808 static pid_t
meta_window_x11_get_client_pid(MetaWindow * window)1809 meta_window_x11_get_client_pid (MetaWindow *window)
1810 {
1811 MetaX11Display *x11_display = window->display->x11_display;
1812 xcb_connection_t *xcb = XGetXCBConnection (x11_display->xdisplay);
1813 xcb_res_client_id_spec_t spec = { 0 };
1814 xcb_res_query_client_ids_cookie_t cookie;
1815 xcb_res_query_client_ids_reply_t *reply = NULL;
1816
1817 spec.client = window->xwindow;
1818 spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
1819
1820 cookie = xcb_res_query_client_ids (xcb, 1, &spec);
1821 reply = xcb_res_query_client_ids_reply (xcb, cookie, NULL);
1822
1823 if (reply == NULL)
1824 return 0;
1825
1826 uint32_t pid = 0, *value;
1827 xcb_res_client_id_value_iterator_t it;
1828 for (it = xcb_res_query_client_ids_ids_iterator (reply);
1829 it.rem;
1830 xcb_res_client_id_value_next (&it))
1831 {
1832 spec = it.data->spec;
1833 if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID)
1834 {
1835 value = xcb_res_client_id_value_value (it.data);
1836 pid = *value;
1837 break;
1838 }
1839 }
1840
1841 free (reply);
1842 return (pid_t) pid;
1843 }
1844
1845 static void
meta_window_x11_force_restore_shortcuts(MetaWindow * window,ClutterInputDevice * source)1846 meta_window_x11_force_restore_shortcuts (MetaWindow *window,
1847 ClutterInputDevice *source)
1848 {
1849 /*
1850 * Not needed on X11 because clients can use a keyboard grab
1851 * to bypass the compositor shortcuts.
1852 */
1853 }
1854
1855 static gboolean
meta_window_x11_shortcuts_inhibited(MetaWindow * window,ClutterInputDevice * source)1856 meta_window_x11_shortcuts_inhibited (MetaWindow *window,
1857 ClutterInputDevice *source)
1858 {
1859 /*
1860 * On X11, we don't use a shortcuts inhibitor, clients just grab
1861 * the keyboard.
1862 */
1863 return FALSE;
1864 }
1865
1866 void
meta_window_x11_set_wm_take_focus(MetaWindow * window,gboolean take_focus)1867 meta_window_x11_set_wm_take_focus (MetaWindow *window,
1868 gboolean take_focus)
1869 {
1870 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
1871 MetaWindowX11Private *priv =
1872 meta_window_x11_get_instance_private (window_x11);
1873
1874 priv->wm_take_focus = take_focus;
1875 }
1876
1877 static gboolean
meta_window_x11_is_focusable(MetaWindow * window)1878 meta_window_x11_is_focusable (MetaWindow *window)
1879 {
1880 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
1881 MetaWindowX11Private *priv =
1882 meta_window_x11_get_instance_private (window_x11);
1883
1884 return window->input || priv->wm_take_focus;
1885 }
1886
1887 static gboolean
meta_window_x11_is_stackable(MetaWindow * window)1888 meta_window_x11_is_stackable (MetaWindow *window)
1889 {
1890 return !window->override_redirect;
1891 }
1892
1893 static gboolean
meta_window_x11_are_updates_frozen(MetaWindow * window)1894 meta_window_x11_are_updates_frozen (MetaWindow *window)
1895 {
1896 if (window->extended_sync_request_counter &&
1897 window->sync_request_serial % 2 == 1)
1898 return TRUE;
1899
1900 if (window->sync_request_serial < window->sync_request_wait_serial)
1901 return TRUE;
1902
1903 return FALSE;
1904 }
1905
1906 /* Get layer ignoring any transient or group relationships */
1907 static MetaStackLayer
get_standalone_layer(MetaWindow * window)1908 get_standalone_layer (MetaWindow *window)
1909 {
1910 MetaStackLayer layer;
1911
1912 switch (window->type)
1913 {
1914 case META_WINDOW_DESKTOP:
1915 layer = META_LAYER_DESKTOP;
1916 break;
1917
1918 case META_WINDOW_DOCK:
1919 if (window->wm_state_below ||
1920 (window->monitor && window->monitor->in_fullscreen))
1921 layer = META_LAYER_BOTTOM;
1922 else
1923 layer = META_LAYER_DOCK;
1924 break;
1925
1926 case META_WINDOW_DROPDOWN_MENU:
1927 case META_WINDOW_POPUP_MENU:
1928 case META_WINDOW_TOOLTIP:
1929 case META_WINDOW_NOTIFICATION:
1930 case META_WINDOW_COMBO:
1931 case META_WINDOW_OVERRIDE_OTHER:
1932 layer = META_LAYER_OVERRIDE_REDIRECT;
1933 break;
1934
1935 default:
1936 layer = meta_window_get_default_layer (window);
1937 break;
1938 }
1939
1940 return layer;
1941 }
1942
1943 /* Note that this function can never use window->layer only
1944 * get_standalone_layer, or we'd have issues.
1945 */
1946 static MetaStackLayer
get_maximum_layer_in_group(MetaWindow * window)1947 get_maximum_layer_in_group (MetaWindow *window)
1948 {
1949 GSList *members;
1950 MetaGroup *group;
1951 GSList *tmp;
1952 MetaStackLayer max;
1953 MetaStackLayer layer;
1954
1955 max = META_LAYER_DESKTOP;
1956
1957 group = meta_window_get_group (window);
1958
1959 if (group != NULL)
1960 members = meta_group_list_windows (group);
1961 else
1962 members = NULL;
1963
1964 tmp = members;
1965 while (tmp != NULL)
1966 {
1967 MetaWindow *w = tmp->data;
1968
1969 if (!w->override_redirect)
1970 {
1971 layer = get_standalone_layer (w);
1972 if (layer > max)
1973 max = layer;
1974 }
1975
1976 tmp = tmp->next;
1977 }
1978
1979 g_slist_free (members);
1980
1981 return max;
1982 }
1983
1984 static MetaStackLayer
meta_window_x11_calculate_layer(MetaWindow * window)1985 meta_window_x11_calculate_layer (MetaWindow *window)
1986 {
1987 MetaStackLayer layer = get_standalone_layer (window);
1988
1989 /* We can only do promotion-due-to-group for dialogs and other
1990 * transients, or weird stuff happens like the desktop window and
1991 * nautilus windows getting in the same layer, or all gnome-terminal
1992 * windows getting in fullscreen layer if any terminal is
1993 * fullscreen.
1994 */
1995 if (layer != META_LAYER_DESKTOP &&
1996 meta_window_has_transient_type (window) &&
1997 window->transient_for == NULL)
1998 {
1999 /* We only do the group thing if the dialog is NOT transient for
2000 * a particular window. Imagine a group with a normal window, a dock,
2001 * and a dialog transient for the normal window; you don't want the dialog
2002 * above the dock if it wouldn't normally be.
2003 */
2004
2005 MetaStackLayer group_max;
2006
2007 group_max = get_maximum_layer_in_group (window);
2008
2009 if (group_max > layer)
2010 {
2011 meta_topic (META_DEBUG_STACK,
2012 "Promoting window %s from layer %u to %u due to group membership",
2013 window->desc, layer, group_max);
2014 layer = group_max;
2015 }
2016 }
2017
2018 meta_topic (META_DEBUG_STACK,
2019 "Window %s on layer %u type = %u has_focus = %d",
2020 window->desc, layer,
2021 window->type, window->has_focus);
2022 return layer;
2023 }
2024
2025 static void
meta_window_x11_impl_freeze_commits(MetaWindow * window)2026 meta_window_x11_impl_freeze_commits (MetaWindow *window)
2027 {
2028 }
2029
2030 static void
meta_window_x11_impl_thaw_commits(MetaWindow * window)2031 meta_window_x11_impl_thaw_commits (MetaWindow *window)
2032 {
2033 }
2034
2035 static void
meta_window_x11_map(MetaWindow * window)2036 meta_window_x11_map (MetaWindow *window)
2037 {
2038 MetaX11Display *x11_display = window->display->x11_display;
2039
2040 meta_x11_error_trap_push (x11_display);
2041 XMapWindow (x11_display->xdisplay, window->xwindow);
2042 meta_x11_error_trap_pop (x11_display);
2043 }
2044
2045 static void
meta_window_x11_unmap(MetaWindow * window)2046 meta_window_x11_unmap (MetaWindow *window)
2047 {
2048 MetaX11Display *x11_display = window->display->x11_display;
2049
2050 meta_x11_error_trap_push (x11_display);
2051 XUnmapWindow (x11_display->xdisplay, window->xwindow);
2052 meta_x11_error_trap_pop (x11_display);
2053 window->unmaps_pending ++;
2054 }
2055
2056 static gboolean
meta_window_x11_impl_always_update_shape(MetaWindow * window)2057 meta_window_x11_impl_always_update_shape (MetaWindow *window)
2058 {
2059 return FALSE;
2060 }
2061
2062 static gboolean
meta_window_x11_is_focus_async(MetaWindow * window)2063 meta_window_x11_is_focus_async (MetaWindow *window)
2064 {
2065 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
2066 MetaWindowX11Private *priv =
2067 meta_window_x11_get_instance_private (window_x11);
2068
2069 return !window->input && priv->wm_take_focus;
2070 }
2071
2072 static void
meta_window_x11_class_init(MetaWindowX11Class * klass)2073 meta_window_x11_class_init (MetaWindowX11Class *klass)
2074 {
2075 MetaWindowClass *window_class = META_WINDOW_CLASS (klass);
2076
2077 window_class->manage = meta_window_x11_manage;
2078 window_class->unmanage = meta_window_x11_unmanage;
2079 window_class->ping = meta_window_x11_ping;
2080 window_class->delete = meta_window_x11_delete;
2081 window_class->kill = meta_window_x11_kill;
2082 window_class->focus = meta_window_x11_focus;
2083 window_class->grab_op_began = meta_window_x11_grab_op_began;
2084 window_class->grab_op_ended = meta_window_x11_grab_op_ended;
2085 window_class->current_workspace_changed = meta_window_x11_current_workspace_changed;
2086 window_class->move_resize_internal = meta_window_x11_move_resize_internal;
2087 window_class->update_struts = meta_window_x11_update_struts;
2088 window_class->get_default_skip_hints = meta_window_x11_get_default_skip_hints;
2089 window_class->update_icon = meta_window_x11_update_icon;
2090 window_class->update_main_monitor = meta_window_x11_update_main_monitor;
2091 window_class->main_monitor_changed = meta_window_x11_main_monitor_changed;
2092 window_class->get_client_pid = meta_window_x11_get_client_pid;
2093 window_class->force_restore_shortcuts = meta_window_x11_force_restore_shortcuts;
2094 window_class->shortcuts_inhibited = meta_window_x11_shortcuts_inhibited;
2095 window_class->is_focusable = meta_window_x11_is_focusable;
2096 window_class->is_stackable = meta_window_x11_is_stackable;
2097 window_class->can_ping = meta_window_x11_can_ping;
2098 window_class->are_updates_frozen = meta_window_x11_are_updates_frozen;
2099 window_class->calculate_layer = meta_window_x11_calculate_layer;
2100 window_class->map = meta_window_x11_map;
2101 window_class->unmap = meta_window_x11_unmap;
2102 window_class->is_focus_async = meta_window_x11_is_focus_async;
2103
2104 klass->freeze_commits = meta_window_x11_impl_freeze_commits;
2105 klass->thaw_commits = meta_window_x11_impl_thaw_commits;
2106 klass->always_update_shape = meta_window_x11_impl_always_update_shape;
2107 }
2108
2109 void
meta_window_x11_set_net_wm_state(MetaWindow * window)2110 meta_window_x11_set_net_wm_state (MetaWindow *window)
2111 {
2112 MetaX11Display *x11_display = window->display->x11_display;
2113 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
2114 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
2115 int i;
2116 unsigned long data[13];
2117
2118 i = 0;
2119 if (window->shaded)
2120 {
2121 data[i] = x11_display->atom__NET_WM_STATE_SHADED;
2122 ++i;
2123 }
2124 if (priv->wm_state_modal)
2125 {
2126 data[i] = x11_display->atom__NET_WM_STATE_MODAL;
2127 ++i;
2128 }
2129 if (window->skip_pager)
2130 {
2131 data[i] = x11_display->atom__NET_WM_STATE_SKIP_PAGER;
2132 ++i;
2133 }
2134 if (window->skip_taskbar)
2135 {
2136 data[i] = x11_display->atom__NET_WM_STATE_SKIP_TASKBAR;
2137 ++i;
2138 }
2139 if (window->maximized_horizontally)
2140 {
2141 data[i] = x11_display->atom__NET_WM_STATE_MAXIMIZED_HORZ;
2142 ++i;
2143 }
2144 if (window->maximized_vertically)
2145 {
2146 data[i] = x11_display->atom__NET_WM_STATE_MAXIMIZED_VERT;
2147 ++i;
2148 }
2149 if (window->fullscreen)
2150 {
2151 data[i] = x11_display->atom__NET_WM_STATE_FULLSCREEN;
2152 ++i;
2153 }
2154 if (!meta_window_showing_on_its_workspace (window) || window->shaded)
2155 {
2156 data[i] = x11_display->atom__NET_WM_STATE_HIDDEN;
2157 ++i;
2158 }
2159 if (window->wm_state_above)
2160 {
2161 data[i] = x11_display->atom__NET_WM_STATE_ABOVE;
2162 ++i;
2163 }
2164 if (window->wm_state_below)
2165 {
2166 data[i] = x11_display->atom__NET_WM_STATE_BELOW;
2167 ++i;
2168 }
2169 if (window->wm_state_demands_attention)
2170 {
2171 data[i] = x11_display->atom__NET_WM_STATE_DEMANDS_ATTENTION;
2172 ++i;
2173 }
2174 if (window->on_all_workspaces_requested)
2175 {
2176 data[i] = x11_display->atom__NET_WM_STATE_STICKY;
2177 ++i;
2178 }
2179 if (meta_window_appears_focused (window))
2180 {
2181 data[i] = x11_display->atom__NET_WM_STATE_FOCUSED;
2182 ++i;
2183 }
2184
2185 meta_verbose ("Setting _NET_WM_STATE with %d atoms", i);
2186
2187 meta_x11_error_trap_push (x11_display);
2188 XChangeProperty (x11_display->xdisplay, window->xwindow,
2189 x11_display->atom__NET_WM_STATE,
2190 XA_ATOM,
2191 32, PropModeReplace, (guchar*) data, i);
2192 meta_x11_error_trap_pop (x11_display);
2193
2194 if (window->fullscreen)
2195 {
2196 if (meta_window_has_fullscreen_monitors (window))
2197 {
2198 data[0] =
2199 meta_x11_display_logical_monitor_to_xinerama_index (window->display->x11_display,
2200 window->fullscreen_monitors.top);
2201 data[1] =
2202 meta_x11_display_logical_monitor_to_xinerama_index (window->display->x11_display,
2203 window->fullscreen_monitors.bottom);
2204 data[2] =
2205 meta_x11_display_logical_monitor_to_xinerama_index (window->display->x11_display,
2206 window->fullscreen_monitors.left);
2207 data[3] =
2208 meta_x11_display_logical_monitor_to_xinerama_index (window->display->x11_display,
2209 window->fullscreen_monitors.right);
2210
2211 meta_verbose ("Setting _NET_WM_FULLSCREEN_MONITORS");
2212 meta_x11_error_trap_push (x11_display);
2213 XChangeProperty (x11_display->xdisplay,
2214 window->xwindow,
2215 x11_display->atom__NET_WM_FULLSCREEN_MONITORS,
2216 XA_CARDINAL, 32, PropModeReplace,
2217 (guchar*) data, 4);
2218 meta_x11_error_trap_pop (x11_display);
2219 }
2220 else
2221 {
2222 meta_verbose ("Clearing _NET_WM_FULLSCREEN_MONITORS");
2223 meta_x11_error_trap_push (x11_display);
2224 XDeleteProperty (x11_display->xdisplay,
2225 window->xwindow,
2226 x11_display->atom__NET_WM_FULLSCREEN_MONITORS);
2227 meta_x11_error_trap_pop (x11_display);
2228 }
2229 }
2230
2231 /* Edge constraints */
2232 update_gtk_edge_constraints (window);
2233 }
2234
2235 static cairo_region_t *
region_create_from_x_rectangles(const XRectangle * rects,int n_rects)2236 region_create_from_x_rectangles (const XRectangle *rects,
2237 int n_rects)
2238 {
2239 int i;
2240 cairo_rectangle_int_t *cairo_rects = g_newa (cairo_rectangle_int_t, n_rects);
2241
2242 for (i = 0; i < n_rects; i ++)
2243 {
2244 cairo_rects[i].x = rects[i].x;
2245 cairo_rects[i].y = rects[i].y;
2246 cairo_rects[i].width = rects[i].width;
2247 cairo_rects[i].height = rects[i].height;
2248 }
2249
2250 return cairo_region_create_rectangles (cairo_rects, n_rects);
2251 }
2252
2253 static void
meta_window_set_input_region(MetaWindow * window,cairo_region_t * region)2254 meta_window_set_input_region (MetaWindow *window,
2255 cairo_region_t *region)
2256 {
2257 if (cairo_region_equal (window->input_region, region))
2258 return;
2259
2260 g_clear_pointer (&window->input_region, cairo_region_destroy);
2261
2262 if (region != NULL)
2263 window->input_region = cairo_region_reference (region);
2264
2265 meta_compositor_window_shape_changed (window->display->compositor, window);
2266 }
2267
2268 #if 0
2269 /* Print out a region; useful for debugging */
2270 static void
2271 print_region (cairo_region_t *region)
2272 {
2273 int n_rects;
2274 int i;
2275
2276 n_rects = cairo_region_num_rectangles (region);
2277 g_print ("[");
2278 for (i = 0; i < n_rects; i++)
2279 {
2280 cairo_rectangle_int_t rect;
2281 cairo_region_get_rectangle (region, i, &rect);
2282 g_print ("+%d+%dx%dx%d ",
2283 rect.x, rect.y, rect.width, rect.height);
2284 }
2285 g_print ("]\n");
2286 }
2287 #endif
2288
2289 void
meta_window_x11_update_input_region(MetaWindow * window)2290 meta_window_x11_update_input_region (MetaWindow *window)
2291 {
2292 MetaX11Display *x11_display = window->display->x11_display;
2293 cairo_region_t *region = NULL;
2294 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
2295 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
2296
2297 /* Decorated windows don't have an input region, because
2298 we don't shape the frame to match the client windows
2299 (so the events are blocked by the frame anyway)
2300 */
2301 if (window->decorated)
2302 {
2303 if (window->input_region)
2304 meta_window_set_input_region (window, NULL);
2305 return;
2306 }
2307
2308 if (META_X11_DISPLAY_HAS_SHAPE (x11_display))
2309 {
2310 /* Translate the set of XShape rectangles that we
2311 * get from the X server to a cairo_region. */
2312 XRectangle *rects = NULL;
2313 int n_rects = -1, ordering;
2314
2315 meta_x11_error_trap_push (x11_display);
2316 rects = XShapeGetRectangles (x11_display->xdisplay,
2317 window->xwindow,
2318 ShapeInput,
2319 &n_rects,
2320 &ordering);
2321 meta_x11_error_trap_pop (x11_display);
2322
2323 /* XXX: The X Shape specification is quite unfortunately specified.
2324 *
2325 * By default, the window has a shape the same as its bounding region,
2326 * which we consider "NULL".
2327 *
2328 * If the window sets an empty region, then we'll get n_rects as 0
2329 * and rects as NULL, which we need to transform back into an empty
2330 * region.
2331 *
2332 * It would be great to have a less-broken extension for this, but
2333 * hey, it's X11!
2334 */
2335
2336 if (n_rects == -1)
2337 {
2338 /* We had an error. */
2339 region = NULL;
2340 }
2341 else if (n_rects == 0)
2342 {
2343 /* Client set an empty region. */
2344 region = cairo_region_create ();
2345 }
2346 else if (n_rects == 1 &&
2347 (rects[0].x == 0 &&
2348 rects[0].y == 0 &&
2349 rects[0].width == priv->client_rect.width &&
2350 rects[0].height == priv->client_rect.height))
2351 {
2352 /* This is the bounding region case. Keep the
2353 * region as NULL. */
2354 region = NULL;
2355 }
2356 else
2357 {
2358 /* Window has a custom shape. */
2359 region = region_create_from_x_rectangles (rects, n_rects);
2360 }
2361
2362 meta_XFree (rects);
2363 }
2364
2365 if (region != NULL)
2366 {
2367 cairo_rectangle_int_t client_area;
2368
2369 client_area.x = 0;
2370 client_area.y = 0;
2371 client_area.width = priv->client_rect.width;
2372 client_area.height = priv->client_rect.height;
2373
2374 /* The shape we get back from the client may have coordinates
2375 * outside of the frame. The X SHAPE Extension requires that
2376 * the overall shape the client provides never exceeds the
2377 * "bounding rectangle" of the window -- the shape that the
2378 * window would have gotten if it was unshaped. In our case,
2379 * this is simply the client area.
2380 */
2381 cairo_region_intersect_rectangle (region, &client_area);
2382 }
2383
2384 meta_window_set_input_region (window, region);
2385 cairo_region_destroy (region);
2386 }
2387
2388 static void
meta_window_set_shape_region(MetaWindow * window,cairo_region_t * region)2389 meta_window_set_shape_region (MetaWindow *window,
2390 cairo_region_t *region)
2391 {
2392 if (cairo_region_equal (window->shape_region, region))
2393 return;
2394
2395 g_clear_pointer (&window->shape_region, cairo_region_destroy);
2396
2397 if (region != NULL)
2398 window->shape_region = cairo_region_reference (region);
2399
2400 meta_compositor_window_shape_changed (window->display->compositor, window);
2401 }
2402
2403 void
meta_window_x11_update_shape_region(MetaWindow * window)2404 meta_window_x11_update_shape_region (MetaWindow *window)
2405 {
2406 MetaX11Display *x11_display = window->display->x11_display;
2407 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
2408 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
2409 cairo_region_t *region = NULL;
2410
2411 if (META_X11_DISPLAY_HAS_SHAPE (x11_display))
2412 {
2413 /* Translate the set of XShape rectangles that we
2414 * get from the X server to a cairo_region. */
2415 XRectangle *rects = NULL;
2416 int n_rects, ordering;
2417
2418 int x_bounding, y_bounding, x_clip, y_clip;
2419 unsigned w_bounding, h_bounding, w_clip, h_clip;
2420 int bounding_shaped, clip_shaped;
2421
2422 meta_x11_error_trap_push (x11_display);
2423 XShapeQueryExtents (x11_display->xdisplay, window->xwindow,
2424 &bounding_shaped, &x_bounding, &y_bounding,
2425 &w_bounding, &h_bounding,
2426 &clip_shaped, &x_clip, &y_clip,
2427 &w_clip, &h_clip);
2428
2429 if (bounding_shaped)
2430 {
2431 rects = XShapeGetRectangles (x11_display->xdisplay,
2432 window->xwindow,
2433 ShapeBounding,
2434 &n_rects,
2435 &ordering);
2436 }
2437 meta_x11_error_trap_pop (x11_display);
2438
2439 if (rects)
2440 {
2441 region = region_create_from_x_rectangles (rects, n_rects);
2442 XFree (rects);
2443 }
2444 }
2445
2446 if (region != NULL)
2447 {
2448 cairo_rectangle_int_t client_area;
2449
2450 client_area.x = 0;
2451 client_area.y = 0;
2452 client_area.width = priv->client_rect.width;
2453 client_area.height = priv->client_rect.height;
2454
2455 /* The shape we get back from the client may have coordinates
2456 * outside of the frame. The X SHAPE Extension requires that
2457 * the overall shape the client provides never exceeds the
2458 * "bounding rectangle" of the window -- the shape that the
2459 * window would have gotten if it was unshaped. In our case,
2460 * this is simply the client area.
2461 */
2462 cairo_region_intersect_rectangle (region, &client_area);
2463 /* Some applications might explicitly set their bounding region
2464 * to the client area. Detect these cases, and throw out the
2465 * bounding region in this case for decorated windows. */
2466 if (window->decorated &&
2467 cairo_region_contains_rectangle (region, &client_area) == CAIRO_REGION_OVERLAP_IN)
2468 g_clear_pointer (®ion, cairo_region_destroy);
2469 }
2470
2471 meta_window_set_shape_region (window, region);
2472 cairo_region_destroy (region);
2473 }
2474
2475 /* Generally meta_window_same_application() is a better idea
2476 * of "sameness", since it handles the case where multiple apps
2477 * want to look like the same app or the same app wants to look
2478 * like multiple apps, but in the case of workarounds for legacy
2479 * applications (which likely aren't setting the group properly
2480 * anyways), it may be desirable to check this as well.
2481 */
2482 static gboolean
meta_window_same_client(MetaWindow * window,MetaWindow * other_window)2483 meta_window_same_client (MetaWindow *window,
2484 MetaWindow *other_window)
2485 {
2486 int resource_mask = window->display->x11_display->xdisplay->resource_mask;
2487
2488 return ((window->xwindow & ~resource_mask) ==
2489 (other_window->xwindow & ~resource_mask));
2490 }
2491
2492 static void
meta_window_move_resize_request(MetaWindow * window,guint value_mask,MetaGravity gravity,int new_x,int new_y,int new_width,int new_height)2493 meta_window_move_resize_request (MetaWindow *window,
2494 guint value_mask,
2495 MetaGravity gravity,
2496 int new_x,
2497 int new_y,
2498 int new_width,
2499 int new_height)
2500 {
2501 int x, y, width, height;
2502 gboolean allow_position_change;
2503 gboolean in_grab_op;
2504 MetaMoveResizeFlags flags;
2505 MetaRectangle buffer_rect;
2506
2507 /* We ignore configure requests while the user is moving/resizing
2508 * the window, since these represent the app sucking and fighting
2509 * the user, most likely due to a bug in the app (e.g. pfaedit
2510 * seemed to do this)
2511 *
2512 * Still have to do the ConfigureNotify and all, but pretend the
2513 * app asked for the current size/position instead of the new one.
2514 */
2515 in_grab_op = (window->display->grab_window == window &&
2516 meta_grab_op_is_mouse (window->display->grab_op));
2517
2518 /* it's essential to use only the explicitly-set fields,
2519 * and otherwise use our current up-to-date position.
2520 *
2521 * Otherwise you get spurious position changes when the app changes
2522 * size, for example, if window->rect is not in sync with the
2523 * server-side position in effect when the configure request was
2524 * generated.
2525 */
2526 meta_window_get_gravity_position (window,
2527 gravity,
2528 &x, &y);
2529
2530 allow_position_change = FALSE;
2531
2532 if (meta_prefs_get_disable_workarounds ())
2533 {
2534 if (window->type == META_WINDOW_DIALOG ||
2535 window->type == META_WINDOW_MODAL_DIALOG ||
2536 window->type == META_WINDOW_SPLASHSCREEN)
2537 ; /* No position change for these */
2538 else if ((window->size_hints.flags & PPosition) ||
2539 /* USPosition is just stale if window is placed;
2540 * no --geometry involved here.
2541 */
2542 ((window->size_hints.flags & USPosition) &&
2543 !window->placed))
2544 allow_position_change = TRUE;
2545 }
2546 else
2547 {
2548 allow_position_change = TRUE;
2549 }
2550
2551 if (in_grab_op)
2552 allow_position_change = FALSE;
2553
2554 if (allow_position_change)
2555 {
2556 if (value_mask & CWX)
2557 x = new_x;
2558 if (value_mask & CWY)
2559 y = new_y;
2560 if (value_mask & (CWX | CWY))
2561 {
2562 /* Once manually positioned, windows shouldn't be placed
2563 * by the window manager.
2564 */
2565 window->placed = TRUE;
2566 }
2567 }
2568 else
2569 {
2570 meta_topic (META_DEBUG_GEOMETRY,
2571 "Not allowing position change for window %s PPosition 0x%lx USPosition 0x%lx type %u",
2572 window->desc, window->size_hints.flags & PPosition,
2573 window->size_hints.flags & USPosition,
2574 window->type);
2575 }
2576
2577 meta_window_get_buffer_rect (window, &buffer_rect);
2578 width = buffer_rect.width;
2579 height = buffer_rect.height;
2580 if (!in_grab_op || !meta_grab_op_is_resizing (window->display->grab_op))
2581 {
2582 if (value_mask & CWWidth)
2583 width = new_width;
2584
2585 if (value_mask & CWHeight)
2586 height = new_height;
2587 }
2588
2589 /* ICCCM 4.1.5 */
2590
2591 /* We're ignoring the value_mask here, since sizes
2592 * not in the mask will be the current window geometry.
2593 */
2594 window->size_hints.x = x;
2595 window->size_hints.y = y;
2596 window->size_hints.width = width;
2597 window->size_hints.height = height;
2598
2599 /* NOTE: We consider ConfigureRequests to be "user" actions in one
2600 * way, but not in another. Explanation of the two cases are in the
2601 * next two big comments.
2602 */
2603
2604 /* The constraints code allows user actions to move windows
2605 * offscreen, etc., and configure request actions would often send
2606 * windows offscreen when users don't want it if not constrained
2607 * (e.g. hitting a dropdown triangle in a fileselector to show more
2608 * options, which makes the window bigger). Thus we do not set
2609 * META_MOVE_RESIZE_USER_ACTION in flags to the
2610 * meta_window_move_resize_internal() call.
2611 */
2612 flags = META_MOVE_RESIZE_CONFIGURE_REQUEST;
2613 if (value_mask & (CWX | CWY))
2614 flags |= META_MOVE_RESIZE_MOVE_ACTION;
2615 if (value_mask & (CWWidth | CWHeight))
2616 flags |= META_MOVE_RESIZE_RESIZE_ACTION;
2617
2618 if (flags & (META_MOVE_RESIZE_MOVE_ACTION | META_MOVE_RESIZE_RESIZE_ACTION))
2619 {
2620 MetaRectangle rect;
2621
2622 rect.x = x;
2623 rect.y = y;
2624 rect.width = width;
2625 rect.height = height;
2626
2627 if (window->monitor)
2628 {
2629 MetaRectangle monitor_rect;
2630
2631 meta_display_get_monitor_geometry (window->display,
2632 window->monitor->number,
2633 &monitor_rect);
2634
2635 /* Workaround braindead legacy apps that don't know how to
2636 * fullscreen themselves properly - don't get fooled by
2637 * windows which hide their titlebar when maximized or which are
2638 * client decorated; that's not the same as fullscreen, even
2639 * if there are no struts making the workarea smaller than
2640 * the monitor.
2641 */
2642 if (meta_prefs_get_force_fullscreen() &&
2643 (window->decorated || !meta_window_is_client_decorated (window)) &&
2644 meta_rectangle_equal (&rect, &monitor_rect) &&
2645 window->has_fullscreen_func &&
2646 !window->fullscreen)
2647 {
2648 /*
2649 meta_topic (META_DEBUG_GEOMETRY,
2650 */
2651 meta_warning (
2652 "Treating resize request of legacy application %s as a "
2653 "fullscreen request",
2654 window->desc);
2655 meta_window_make_fullscreen_internal (window);
2656 }
2657 }
2658
2659 adjust_for_gravity (window, TRUE, gravity, &rect);
2660 meta_window_client_rect_to_frame_rect (window, &rect, &rect);
2661 meta_window_move_resize_internal (window, flags, gravity, rect);
2662 }
2663 }
2664
2665 static void
restack_window(MetaWindow * window,MetaWindow * sibling,int direction)2666 restack_window (MetaWindow *window,
2667 MetaWindow *sibling,
2668 int direction)
2669 {
2670 switch (direction)
2671 {
2672 case Above:
2673 if (sibling)
2674 meta_window_stack_just_above (window, sibling);
2675 else
2676 meta_window_raise (window);
2677 break;
2678 case Below:
2679 if (sibling)
2680 meta_window_stack_just_below (window, sibling);
2681 else
2682 meta_window_lower (window);
2683 break;
2684 case TopIf:
2685 case BottomIf:
2686 case Opposite:
2687 break;
2688 }
2689 }
2690
2691 gboolean
meta_window_x11_configure_request(MetaWindow * window,XEvent * event)2692 meta_window_x11_configure_request (MetaWindow *window,
2693 XEvent *event)
2694 {
2695 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
2696 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
2697
2698 /* Note that x, y is the corner of the window border,
2699 * and width, height is the size of the window inside
2700 * its border, but that we always deny border requests
2701 * and give windows a border of 0. But we save the
2702 * requested border here.
2703 */
2704 if (event->xconfigurerequest.value_mask & CWBorderWidth)
2705 priv->border_width = event->xconfigurerequest.border_width;
2706
2707 meta_window_move_resize_request(window,
2708 event->xconfigurerequest.value_mask,
2709 window->size_hints.win_gravity,
2710 event->xconfigurerequest.x,
2711 event->xconfigurerequest.y,
2712 event->xconfigurerequest.width,
2713 event->xconfigurerequest.height);
2714
2715 /* Handle stacking. We only handle raises/lowers, mostly because
2716 * stack.c really can't deal with anything else. I guess we'll fix
2717 * that if a client turns up that really requires it. Only a very
2718 * few clients even require the raise/lower (and in fact all client
2719 * attempts to deal with stacking order are essentially broken,
2720 * since they have no idea what other clients are involved or how
2721 * the stack looks).
2722 *
2723 * I'm pretty sure no interesting client uses TopIf, BottomIf, or
2724 * Opposite anyway.
2725 */
2726 if (event->xconfigurerequest.value_mask & CWStackMode)
2727 {
2728 MetaWindow *active_window;
2729 active_window = window->display->focus_window;
2730 if (meta_prefs_get_disable_workarounds ())
2731 {
2732 meta_topic (META_DEBUG_STACK,
2733 "%s sent an xconfigure stacking request; this is "
2734 "broken behavior and the request is being ignored.",
2735 window->desc);
2736 }
2737 else if (active_window &&
2738 !meta_window_same_application (window, active_window) &&
2739 !meta_window_same_client (window, active_window) &&
2740 XSERVER_TIME_IS_BEFORE (window->net_wm_user_time,
2741 active_window->net_wm_user_time))
2742 {
2743 meta_topic (META_DEBUG_STACK,
2744 "Ignoring xconfigure stacking request from %s (with "
2745 "user_time %u); currently active application is %s (with "
2746 "user_time %u).",
2747 window->desc,
2748 window->net_wm_user_time,
2749 active_window->desc,
2750 active_window->net_wm_user_time);
2751 if (event->xconfigurerequest.detail == Above)
2752 meta_window_set_demands_attention(window);
2753 }
2754 else
2755 {
2756 MetaWindow *sibling = NULL;
2757 /* Handle Above/Below with a sibling set */
2758 if (event->xconfigurerequest.above != None)
2759 {
2760 MetaDisplay *display;
2761
2762 display = meta_window_get_display (window);
2763 sibling = meta_x11_display_lookup_x_window (display->x11_display,
2764 event->xconfigurerequest.above);
2765 if (sibling == NULL)
2766 return TRUE;
2767
2768 meta_topic (META_DEBUG_STACK,
2769 "xconfigure stacking request from window %s sibling %s stackmode %d",
2770 window->desc, sibling->desc, event->xconfigurerequest.detail);
2771 }
2772 restack_window (window, sibling, event->xconfigurerequest.detail);
2773 }
2774 }
2775
2776 return TRUE;
2777 }
2778
2779 static gboolean
process_property_notify(MetaWindow * window,XPropertyEvent * event)2780 process_property_notify (MetaWindow *window,
2781 XPropertyEvent *event)
2782 {
2783 Window xid = window->xwindow;
2784
2785 if (meta_is_verbose ()) /* avoid looking up the name if we don't have to */
2786 {
2787 char *property_name = XGetAtomName (window->display->x11_display->xdisplay,
2788 event->atom);
2789
2790 meta_verbose ("Property notify on %s for %s",
2791 window->desc, property_name);
2792 XFree (property_name);
2793 }
2794
2795 if (event->atom == window->display->x11_display->atom__NET_WM_USER_TIME &&
2796 window->user_time_window)
2797 {
2798 xid = window->user_time_window;
2799 }
2800
2801 meta_window_reload_property_from_xwindow (window, xid, event->atom, FALSE);
2802
2803 return TRUE;
2804 }
2805
2806 gboolean
meta_window_x11_property_notify(MetaWindow * window,XEvent * event)2807 meta_window_x11_property_notify (MetaWindow *window,
2808 XEvent *event)
2809 {
2810 return process_property_notify (window, &event->xproperty);
2811 }
2812
2813 #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
2814 #define _NET_WM_MOVERESIZE_SIZE_TOP 1
2815 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
2816 #define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
2817 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
2818 #define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
2819 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
2820 #define _NET_WM_MOVERESIZE_SIZE_LEFT 7
2821 #define _NET_WM_MOVERESIZE_MOVE 8
2822 #define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9
2823 #define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10
2824 #define _NET_WM_MOVERESIZE_CANCEL 11
2825
2826 static int
query_pressed_buttons(MetaWindow * window)2827 query_pressed_buttons (MetaWindow *window)
2828 {
2829 MetaCursorTracker *tracker = meta_cursor_tracker_get_for_display (window->display);
2830 ClutterModifierType mods;
2831 int button = 0;
2832
2833 meta_cursor_tracker_get_pointer (tracker, NULL, &mods);
2834
2835 if (mods & CLUTTER_BUTTON1_MASK)
2836 button |= 1 << 1;
2837 if (mods & CLUTTER_BUTTON2_MASK)
2838 button |= 1 << 2;
2839 if (mods & CLUTTER_BUTTON3_MASK)
2840 button |= 1 << 3;
2841
2842 return button;
2843 }
2844
2845 static void
handle_net_restack_window(MetaDisplay * display,XEvent * event)2846 handle_net_restack_window (MetaDisplay *display,
2847 XEvent *event)
2848 {
2849 MetaWindow *window, *sibling = NULL;
2850
2851 /* Ignore if this does not come from a pager, see the WM spec
2852 */
2853 if (event->xclient.data.l[0] != 2)
2854 return;
2855
2856 window = meta_x11_display_lookup_x_window (display->x11_display,
2857 event->xclient.window);
2858
2859 if (window)
2860 {
2861 if (event->xclient.data.l[1])
2862 sibling = meta_x11_display_lookup_x_window (display->x11_display,
2863 event->xclient.data.l[1]);
2864
2865 restack_window (window, sibling, event->xclient.data.l[2]);
2866 }
2867 }
2868
2869 gboolean
meta_window_x11_client_message(MetaWindow * window,XEvent * event)2870 meta_window_x11_client_message (MetaWindow *window,
2871 XEvent *event)
2872 {
2873 MetaX11Display *x11_display = window->display->x11_display;
2874 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
2875 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
2876 MetaDisplay *display;
2877
2878 display = window->display;
2879
2880 if (window->override_redirect)
2881 {
2882 /* Don't warn here: we could warn on any of the messages below,
2883 * but we might also receive other client messages that are
2884 * part of protocols we don't know anything about. So, silently
2885 * ignoring is simplest.
2886 */
2887 return FALSE;
2888 }
2889
2890 if (event->xclient.message_type ==
2891 x11_display->atom__NET_CLOSE_WINDOW)
2892 {
2893 guint32 timestamp;
2894
2895 if (event->xclient.data.l[0] != 0)
2896 timestamp = event->xclient.data.l[0];
2897 else
2898 {
2899 meta_warning ("Receiving a NET_CLOSE_WINDOW message for %s without "
2900 "a timestamp! This means some buggy (outdated) "
2901 "application is on the loose!",
2902 window->desc);
2903 timestamp = meta_display_get_current_time (window->display);
2904 }
2905
2906 meta_window_delete (window, timestamp);
2907
2908 return TRUE;
2909 }
2910 else if (event->xclient.message_type ==
2911 x11_display->atom__NET_WM_DESKTOP)
2912 {
2913 int space;
2914 MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
2915 MetaWorkspace *workspace;
2916
2917 space = event->xclient.data.l[0];
2918
2919 meta_verbose ("Request to move %s to workspace %d",
2920 window->desc, space);
2921
2922 workspace =
2923 meta_workspace_manager_get_workspace_by_index (workspace_manager,
2924 space);
2925
2926 if (workspace)
2927 meta_window_change_workspace (window, workspace);
2928 else if (space == (int) 0xFFFFFFFF)
2929 meta_window_stick (window);
2930 else
2931 meta_verbose ("No such workspace %d for screen", space);
2932
2933 meta_verbose ("Window %s now on_all_workspaces = %d",
2934 window->desc, window->on_all_workspaces);
2935
2936 return TRUE;
2937 }
2938 else if (event->xclient.message_type ==
2939 x11_display->atom__NET_WM_STATE)
2940 {
2941 gulong action;
2942 Atom first;
2943 Atom second;
2944
2945 action = event->xclient.data.l[0];
2946 first = event->xclient.data.l[1];
2947 second = event->xclient.data.l[2];
2948
2949 if (meta_is_verbose ())
2950 {
2951 char *str1;
2952 char *str2;
2953
2954 meta_x11_error_trap_push (x11_display);
2955 str1 = XGetAtomName (x11_display->xdisplay, first);
2956 if (meta_x11_error_trap_pop_with_return (x11_display) != Success)
2957 str1 = NULL;
2958
2959 meta_x11_error_trap_push (x11_display);
2960 str2 = XGetAtomName (x11_display->xdisplay, second);
2961 if (meta_x11_error_trap_pop_with_return (x11_display) != Success)
2962 str2 = NULL;
2963
2964 meta_verbose ("Request to change _NET_WM_STATE action %lu atom1: %s atom2: %s",
2965 action,
2966 str1 ? str1 : "(unknown)",
2967 str2 ? str2 : "(unknown)");
2968
2969 meta_XFree (str1);
2970 meta_XFree (str2);
2971 }
2972
2973 if (first == x11_display->atom__NET_WM_STATE_SHADED ||
2974 second == x11_display->atom__NET_WM_STATE_SHADED)
2975 {
2976 gboolean shade;
2977 guint32 timestamp;
2978
2979 /* Stupid protocol has no timestamp; of course, shading
2980 * sucks anyway so who really cares that we're forced to do
2981 * a roundtrip here?
2982 */
2983 timestamp = meta_display_get_current_time_roundtrip (window->display);
2984
2985 shade = (action == _NET_WM_STATE_ADD ||
2986 (action == _NET_WM_STATE_TOGGLE && !window->shaded));
2987 if (shade && window->has_shade_func)
2988 meta_window_shade (window, timestamp);
2989 else
2990 meta_window_unshade (window, timestamp);
2991 }
2992
2993 if (first == x11_display->atom__NET_WM_STATE_FULLSCREEN ||
2994 second == x11_display->atom__NET_WM_STATE_FULLSCREEN)
2995 {
2996 gboolean make_fullscreen;
2997
2998 make_fullscreen = (action == _NET_WM_STATE_ADD ||
2999 (action == _NET_WM_STATE_TOGGLE && !window->fullscreen));
3000 if (make_fullscreen && window->has_fullscreen_func)
3001 meta_window_make_fullscreen (window);
3002 else
3003 meta_window_unmake_fullscreen (window);
3004 }
3005
3006 if (first == x11_display->atom__NET_WM_STATE_MAXIMIZED_HORZ ||
3007 second == x11_display->atom__NET_WM_STATE_MAXIMIZED_HORZ ||
3008 first == x11_display->atom__NET_WM_STATE_MAXIMIZED_VERT ||
3009 second == x11_display->atom__NET_WM_STATE_MAXIMIZED_VERT)
3010 {
3011 gboolean max;
3012 MetaMaximizeFlags directions = 0;
3013
3014 max = (action == _NET_WM_STATE_ADD ||
3015 (action == _NET_WM_STATE_TOGGLE &&
3016 !window->maximized_horizontally));
3017
3018 if (first == x11_display->atom__NET_WM_STATE_MAXIMIZED_HORZ ||
3019 second == x11_display->atom__NET_WM_STATE_MAXIMIZED_HORZ)
3020 directions |= META_MAXIMIZE_HORIZONTAL;
3021
3022 if (first == x11_display->atom__NET_WM_STATE_MAXIMIZED_VERT ||
3023 second == x11_display->atom__NET_WM_STATE_MAXIMIZED_VERT)
3024 directions |= META_MAXIMIZE_VERTICAL;
3025
3026 if (max && window->has_maximize_func)
3027 {
3028 if (meta_prefs_get_raise_on_click ())
3029 meta_window_raise (window);
3030 meta_window_maximize (window, directions);
3031 }
3032 else
3033 {
3034 if (meta_prefs_get_raise_on_click ())
3035 meta_window_raise (window);
3036 meta_window_unmaximize (window, directions);
3037 }
3038 }
3039
3040 if (first == x11_display->atom__NET_WM_STATE_MODAL ||
3041 second == x11_display->atom__NET_WM_STATE_MODAL)
3042 {
3043 priv->wm_state_modal =
3044 (action == _NET_WM_STATE_ADD) ||
3045 (action == _NET_WM_STATE_TOGGLE && !priv->wm_state_modal);
3046
3047 meta_window_x11_recalc_window_type (window);
3048 meta_window_queue(window, META_QUEUE_MOVE_RESIZE);
3049 }
3050
3051 if (first == x11_display->atom__NET_WM_STATE_SKIP_PAGER ||
3052 second == x11_display->atom__NET_WM_STATE_SKIP_PAGER)
3053 {
3054 priv->wm_state_skip_pager =
3055 (action == _NET_WM_STATE_ADD) ||
3056 (action == _NET_WM_STATE_TOGGLE && !window->skip_pager);
3057
3058 meta_window_recalc_features (window);
3059 meta_window_x11_set_net_wm_state (window);
3060 }
3061
3062 if (first == x11_display->atom__NET_WM_STATE_SKIP_TASKBAR ||
3063 second == x11_display->atom__NET_WM_STATE_SKIP_TASKBAR)
3064 {
3065 priv->wm_state_skip_taskbar =
3066 (action == _NET_WM_STATE_ADD) ||
3067 (action == _NET_WM_STATE_TOGGLE && !window->skip_taskbar);
3068
3069 meta_window_recalc_features (window);
3070 meta_window_x11_set_net_wm_state (window);
3071 }
3072
3073 if (first == x11_display->atom__NET_WM_STATE_ABOVE ||
3074 second == x11_display->atom__NET_WM_STATE_ABOVE)
3075 {
3076 if ((action == _NET_WM_STATE_ADD) ||
3077 (action == _NET_WM_STATE_TOGGLE && !window->wm_state_demands_attention))
3078 meta_window_make_above (window);
3079 else
3080 meta_window_unmake_above (window);
3081 }
3082
3083 if (first == x11_display->atom__NET_WM_STATE_BELOW ||
3084 second == x11_display->atom__NET_WM_STATE_BELOW)
3085 {
3086 window->wm_state_below =
3087 (action == _NET_WM_STATE_ADD) ||
3088 (action == _NET_WM_STATE_TOGGLE && !window->wm_state_below);
3089
3090 meta_window_update_layer (window);
3091 meta_window_x11_set_net_wm_state (window);
3092 }
3093
3094 if (first == x11_display->atom__NET_WM_STATE_DEMANDS_ATTENTION ||
3095 second == x11_display->atom__NET_WM_STATE_DEMANDS_ATTENTION)
3096 {
3097 if ((action == _NET_WM_STATE_ADD) ||
3098 (action == _NET_WM_STATE_TOGGLE && !window->wm_state_demands_attention))
3099 meta_window_set_demands_attention (window);
3100 else
3101 meta_window_unset_demands_attention (window);
3102 }
3103
3104 if (first == x11_display->atom__NET_WM_STATE_STICKY ||
3105 second == x11_display->atom__NET_WM_STATE_STICKY)
3106 {
3107 if ((action == _NET_WM_STATE_ADD) ||
3108 (action == _NET_WM_STATE_TOGGLE && !window->on_all_workspaces_requested))
3109 meta_window_stick (window);
3110 else
3111 meta_window_unstick (window);
3112 }
3113
3114 return TRUE;
3115 }
3116 else if (event->xclient.message_type ==
3117 x11_display->atom_WM_CHANGE_STATE)
3118 {
3119 meta_verbose ("WM_CHANGE_STATE client message, state: %ld",
3120 event->xclient.data.l[0]);
3121 if (event->xclient.data.l[0] == IconicState)
3122 meta_window_minimize (window);
3123
3124 return TRUE;
3125 }
3126 else if (event->xclient.message_type ==
3127 x11_display->atom__NET_WM_MOVERESIZE)
3128 {
3129 int x_root;
3130 int y_root;
3131 int action;
3132 MetaGrabOp op;
3133 int button;
3134 guint32 timestamp;
3135
3136 /* _NET_WM_MOVERESIZE messages are almost certainly going to come from
3137 * clients when users click on the fake "frame" that the client has,
3138 * thus we should also treat such messages as though it were a
3139 * "frame action".
3140 */
3141 gboolean const frame_action = TRUE;
3142
3143 x_root = event->xclient.data.l[0];
3144 y_root = event->xclient.data.l[1];
3145 action = event->xclient.data.l[2];
3146 button = event->xclient.data.l[3];
3147
3148 /* FIXME: What a braindead protocol; no timestamp?!? */
3149 timestamp = meta_display_get_current_time_roundtrip (display);
3150 meta_topic (META_DEBUG_WINDOW_OPS,
3151 "Received _NET_WM_MOVERESIZE message on %s, %d,%d action = %d, button %d",
3152 window->desc,
3153 x_root, y_root, action, button);
3154
3155 op = META_GRAB_OP_NONE;
3156 switch (action)
3157 {
3158 case _NET_WM_MOVERESIZE_SIZE_TOPLEFT:
3159 op = META_GRAB_OP_RESIZING_NW;
3160 break;
3161 case _NET_WM_MOVERESIZE_SIZE_TOP:
3162 op = META_GRAB_OP_RESIZING_N;
3163 break;
3164 case _NET_WM_MOVERESIZE_SIZE_TOPRIGHT:
3165 op = META_GRAB_OP_RESIZING_NE;
3166 break;
3167 case _NET_WM_MOVERESIZE_SIZE_RIGHT:
3168 op = META_GRAB_OP_RESIZING_E;
3169 break;
3170 case _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT:
3171 op = META_GRAB_OP_RESIZING_SE;
3172 break;
3173 case _NET_WM_MOVERESIZE_SIZE_BOTTOM:
3174 op = META_GRAB_OP_RESIZING_S;
3175 break;
3176 case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT:
3177 op = META_GRAB_OP_RESIZING_SW;
3178 break;
3179 case _NET_WM_MOVERESIZE_SIZE_LEFT:
3180 op = META_GRAB_OP_RESIZING_W;
3181 break;
3182 case _NET_WM_MOVERESIZE_MOVE:
3183 op = META_GRAB_OP_MOVING;
3184 break;
3185 case _NET_WM_MOVERESIZE_SIZE_KEYBOARD:
3186 op = META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN;
3187 break;
3188 case _NET_WM_MOVERESIZE_MOVE_KEYBOARD:
3189 op = META_GRAB_OP_KEYBOARD_MOVING;
3190 break;
3191 case _NET_WM_MOVERESIZE_CANCEL:
3192 /* handled below */
3193 break;
3194 default:
3195 break;
3196 }
3197
3198 if (action == _NET_WM_MOVERESIZE_CANCEL)
3199 {
3200 meta_display_end_grab_op (window->display, timestamp);
3201 }
3202 else if (op != META_GRAB_OP_NONE &&
3203 ((window->has_move_func && op == META_GRAB_OP_KEYBOARD_MOVING) ||
3204 (window->has_resize_func && op == META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN)))
3205 {
3206 meta_window_begin_grab_op (window, op, frame_action, timestamp);
3207 }
3208 else if (op != META_GRAB_OP_NONE &&
3209 ((window->has_move_func && op == META_GRAB_OP_MOVING) ||
3210 (window->has_resize_func &&
3211 (op != META_GRAB_OP_MOVING &&
3212 op != META_GRAB_OP_KEYBOARD_MOVING))))
3213 {
3214 int button_mask;
3215
3216 meta_topic (META_DEBUG_WINDOW_OPS,
3217 "Beginning move/resize with button = %d", button);
3218 meta_display_begin_grab_op (window->display,
3219 window,
3220 op,
3221 FALSE,
3222 frame_action,
3223 button, 0,
3224 timestamp,
3225 x_root,
3226 y_root);
3227
3228 button_mask = query_pressed_buttons (window);
3229
3230 if (button == 0)
3231 {
3232 /*
3233 * the button SHOULD already be included in the message
3234 */
3235 if ((button_mask & (1 << 1)) != 0)
3236 button = 1;
3237 else if ((button_mask & (1 << 2)) != 0)
3238 button = 2;
3239 else if ((button_mask & (1 << 3)) != 0)
3240 button = 3;
3241
3242 if (button != 0)
3243 window->display->grab_button = button;
3244 else
3245 meta_display_end_grab_op (window->display,
3246 timestamp);
3247 }
3248 else
3249 {
3250 /* There is a potential race here. If the user presses and
3251 * releases their mouse button very fast, it's possible for
3252 * both the ButtonPress and ButtonRelease to be sent to the
3253 * client before it can get a chance to send _NET_WM_MOVERESIZE
3254 * to us. When that happens, we'll become stuck in a grab
3255 * state, as we haven't received a ButtonRelease to cancel the
3256 * grab.
3257 *
3258 * We can solve this by querying after we take the explicit
3259 * pointer grab -- if the button isn't pressed, we cancel the
3260 * drag immediately.
3261 */
3262
3263 if ((button_mask & (1 << button)) == 0)
3264 meta_display_end_grab_op (window->display, timestamp);
3265 }
3266 }
3267
3268 return TRUE;
3269 }
3270 else if (event->xclient.message_type ==
3271 x11_display->atom__NET_MOVERESIZE_WINDOW)
3272 {
3273 MetaGravity gravity;
3274 guint value_mask;
3275
3276 gravity = (MetaGravity) (event->xclient.data.l[0] & 0xff);
3277 value_mask = (event->xclient.data.l[0] & 0xf00) >> 8;
3278 /* source = (event->xclient.data.l[0] & 0xf000) >> 12; */
3279
3280 if (gravity == 0)
3281 gravity = window->size_hints.win_gravity;
3282
3283 meta_window_move_resize_request(window,
3284 value_mask,
3285 gravity,
3286 event->xclient.data.l[1], /* x */
3287 event->xclient.data.l[2], /* y */
3288 event->xclient.data.l[3], /* width */
3289 event->xclient.data.l[4]); /* height */
3290 }
3291 else if (event->xclient.message_type ==
3292 x11_display->atom__NET_ACTIVE_WINDOW)
3293 {
3294 MetaClientType source_indication;
3295 guint32 timestamp;
3296
3297 meta_verbose ("_NET_ACTIVE_WINDOW request for window '%s', activating",
3298 window->desc);
3299
3300 source_indication = event->xclient.data.l[0];
3301 timestamp = event->xclient.data.l[1];
3302
3303 if (source_indication > META_CLIENT_TYPE_MAX_RECOGNIZED)
3304 source_indication = META_CLIENT_TYPE_UNKNOWN;
3305
3306 if (timestamp == 0)
3307 {
3308 /* Client using older EWMH _NET_ACTIVE_WINDOW without a timestamp */
3309 meta_warning ("Buggy client sent a _NET_ACTIVE_WINDOW message with a "
3310 "timestamp of 0 for %s",
3311 window->desc);
3312 timestamp = meta_display_get_current_time (display);
3313 }
3314
3315 meta_window_activate_full (window, timestamp, source_indication, NULL);
3316 return TRUE;
3317 }
3318 else if (event->xclient.message_type ==
3319 x11_display->atom__NET_WM_FULLSCREEN_MONITORS)
3320 {
3321 MetaLogicalMonitor *top, *bottom, *left, *right;
3322
3323 meta_verbose ("_NET_WM_FULLSCREEN_MONITORS request for window '%s'",
3324 window->desc);
3325
3326 top =
3327 meta_x11_display_xinerama_index_to_logical_monitor (window->display->x11_display,
3328 event->xclient.data.l[0]);
3329 bottom =
3330 meta_x11_display_xinerama_index_to_logical_monitor (window->display->x11_display,
3331 event->xclient.data.l[1]);
3332 left =
3333 meta_x11_display_xinerama_index_to_logical_monitor (window->display->x11_display,
3334 event->xclient.data.l[2]);
3335 right =
3336 meta_x11_display_xinerama_index_to_logical_monitor (window->display->x11_display,
3337 event->xclient.data.l[3]);
3338 /* source_indication = event->xclient.data.l[4]; */
3339
3340 meta_window_update_fullscreen_monitors (window, top, bottom, left, right);
3341 }
3342 else if (event->xclient.message_type ==
3343 x11_display->atom__GTK_SHOW_WINDOW_MENU)
3344 {
3345 gulong x, y;
3346
3347 /* l[0] is device_id, which we don't use */
3348 x = event->xclient.data.l[1];
3349 y = event->xclient.data.l[2];
3350
3351 meta_window_show_menu (window, META_WINDOW_MENU_WM, x, y);
3352 }
3353 else if (event->xclient.message_type ==
3354 x11_display->atom__NET_RESTACK_WINDOW)
3355 {
3356 handle_net_restack_window (display, event);
3357 }
3358
3359 return FALSE;
3360 }
3361
3362 static void
set_wm_state_on_xwindow(MetaDisplay * display,Window xwindow,int state)3363 set_wm_state_on_xwindow (MetaDisplay *display,
3364 Window xwindow,
3365 int state)
3366 {
3367 unsigned long data[2];
3368
3369 /* Mutter doesn't use icon windows, so data[1] should be None
3370 * according to the ICCCM 2.0 Section 4.1.3.1.
3371 */
3372 data[0] = state;
3373 data[1] = None;
3374
3375 meta_x11_error_trap_push (display->x11_display);
3376 XChangeProperty (display->x11_display->xdisplay, xwindow,
3377 display->x11_display->atom_WM_STATE,
3378 display->x11_display->atom_WM_STATE,
3379 32, PropModeReplace, (guchar*) data, 2);
3380 meta_x11_error_trap_pop (display->x11_display);
3381 }
3382
3383 void
meta_window_x11_set_wm_state(MetaWindow * window)3384 meta_window_x11_set_wm_state (MetaWindow *window)
3385 {
3386 int state;
3387
3388 if (window->withdrawn)
3389 state = WithdrawnState;
3390 else if (window->iconic)
3391 state = IconicState;
3392 else
3393 state = NormalState;
3394
3395 set_wm_state_on_xwindow (window->display, window->xwindow, state);
3396 }
3397
3398 /* The MUTTER_WM_CLASS_FILTER environment variable is designed for
3399 * performance and regression testing environments where we want to do
3400 * tests with only a limited set of windows and ignore all other windows
3401 *
3402 * When it is set to a comma separated list of WM_CLASS class names, all
3403 * windows not matching the list will be ignored.
3404 *
3405 * Returns TRUE if window has been filtered out and should be ignored.
3406 */
3407 static gboolean
maybe_filter_xwindow(MetaDisplay * display,Window xwindow,gboolean must_be_viewable,XWindowAttributes * attrs)3408 maybe_filter_xwindow (MetaDisplay *display,
3409 Window xwindow,
3410 gboolean must_be_viewable,
3411 XWindowAttributes *attrs)
3412 {
3413 static char **filter_wm_classes = NULL;
3414 static gboolean initialized = FALSE;
3415 XClassHint class_hint;
3416 gboolean filtered;
3417 Status success;
3418 int i;
3419
3420 if (!initialized)
3421 {
3422 const char *filter_string = g_getenv ("MUTTER_WM_CLASS_FILTER");
3423 if (filter_string)
3424 filter_wm_classes = g_strsplit (filter_string, ",", -1);
3425 initialized = TRUE;
3426 }
3427
3428 if (!filter_wm_classes || !filter_wm_classes[0])
3429 return FALSE;
3430
3431 filtered = TRUE;
3432
3433 meta_x11_error_trap_push (display->x11_display);
3434 success = XGetClassHint (display->x11_display->xdisplay,
3435 xwindow, &class_hint);
3436
3437 if (success)
3438 {
3439 for (i = 0; filter_wm_classes[i]; i++)
3440 {
3441 if (strcmp (class_hint.res_class, filter_wm_classes[i]) == 0)
3442 {
3443 filtered = FALSE;
3444 break;
3445 }
3446 }
3447
3448 XFree (class_hint.res_name);
3449 XFree (class_hint.res_class);
3450 }
3451
3452 if (filtered)
3453 {
3454 /* We want to try and get the window managed by the next WM that come along,
3455 * so we need to make sure that windows that are requested to be mapped while
3456 * Mutter is running (!must_be_viewable), or windows already viewable at startup
3457 * get a non-withdrawn WM_STATE property. Previously unmapped windows are left
3458 * with whatever WM_STATE property they had.
3459 */
3460 if (!must_be_viewable || attrs->map_state == IsViewable)
3461 {
3462 uint32_t old_state;
3463
3464 if (!meta_prop_get_cardinal_with_atom_type (display->x11_display, xwindow,
3465 display->x11_display->atom_WM_STATE,
3466 display->x11_display->atom_WM_STATE,
3467 &old_state))
3468 old_state = WithdrawnState;
3469
3470 if (old_state == WithdrawnState)
3471 set_wm_state_on_xwindow (display, xwindow, NormalState);
3472 }
3473
3474 /* Make sure filtered windows are hidden from view */
3475 XUnmapWindow (display->x11_display->xdisplay, xwindow);
3476 }
3477
3478 meta_x11_error_trap_pop (display->x11_display);
3479
3480 return filtered;
3481 }
3482
3483 static gboolean
is_our_xwindow(MetaX11Display * x11_display,Window xwindow,XWindowAttributes * attrs)3484 is_our_xwindow (MetaX11Display *x11_display,
3485 Window xwindow,
3486 XWindowAttributes *attrs)
3487 {
3488 if (xwindow == x11_display->no_focus_window)
3489 return TRUE;
3490
3491 if (xwindow == x11_display->wm_sn_selection_window)
3492 return TRUE;
3493
3494 if (xwindow == x11_display->wm_cm_selection_window)
3495 return TRUE;
3496
3497 if (xwindow == x11_display->guard_window)
3498 return TRUE;
3499
3500 if (xwindow == x11_display->composite_overlay_window)
3501 return TRUE;
3502
3503 {
3504 MetaBackend *backend = meta_get_backend ();
3505
3506 if (META_IS_BACKEND_X11 (backend))
3507 {
3508 if (xwindow == meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend)))
3509 return TRUE;
3510 }
3511 }
3512
3513 /* Any windows created via meta_create_offscreen_window */
3514 if (attrs->override_redirect && attrs->x == -100 && attrs->y == -100 && attrs->width == 1 && attrs->height == 1)
3515 return TRUE;
3516
3517 return FALSE;
3518 }
3519
3520 #ifdef WITH_VERBOSE_MODE
3521 static const char*
wm_state_to_string(int state)3522 wm_state_to_string (int state)
3523 {
3524 switch (state)
3525 {
3526 case NormalState:
3527 return "NormalState";
3528 case IconicState:
3529 return "IconicState";
3530 case WithdrawnState:
3531 return "WithdrawnState";
3532 }
3533
3534 return "Unknown";
3535 }
3536 #endif
3537
3538 MetaWindow *
meta_window_x11_new(MetaDisplay * display,Window xwindow,gboolean must_be_viewable,MetaCompEffect effect)3539 meta_window_x11_new (MetaDisplay *display,
3540 Window xwindow,
3541 gboolean must_be_viewable,
3542 MetaCompEffect effect)
3543 {
3544 MetaX11Display *x11_display = display->x11_display;
3545 XWindowAttributes attrs;
3546 gulong existing_wm_state;
3547 MetaWindow *window = NULL;
3548 gulong event_mask;
3549
3550 meta_verbose ("Attempting to manage 0x%lx", xwindow);
3551
3552 if (meta_x11_display_xwindow_is_a_no_focus_window (x11_display, xwindow))
3553 {
3554 meta_verbose ("Not managing no_focus_window 0x%lx",
3555 xwindow);
3556 return NULL;
3557 }
3558
3559 meta_x11_error_trap_push (x11_display); /* Push a trap over all of window
3560 * creation, to reduce XSync() calls
3561 */
3562 /*
3563 * This function executes without any server grabs held. This means that
3564 * the window could have already gone away, or could go away at any point,
3565 * so we must be careful with X error handling.
3566 */
3567
3568 if (!XGetWindowAttributes (x11_display->xdisplay, xwindow, &attrs))
3569 {
3570 meta_verbose ("Failed to get attributes for window 0x%lx",
3571 xwindow);
3572 goto error;
3573 }
3574
3575 if (attrs.root != x11_display->xroot)
3576 {
3577 meta_verbose ("Not on our screen");
3578 goto error;
3579 }
3580
3581 if (attrs.class == InputOnly)
3582 {
3583 meta_verbose ("Not managing InputOnly windows");
3584 goto error;
3585 }
3586
3587 if (is_our_xwindow (x11_display, xwindow, &attrs))
3588 {
3589 meta_verbose ("Not managing our own windows");
3590 goto error;
3591 }
3592
3593 if (maybe_filter_xwindow (display, xwindow, must_be_viewable, &attrs))
3594 {
3595 meta_verbose ("Not managing filtered window");
3596 goto error;
3597 }
3598
3599 existing_wm_state = WithdrawnState;
3600 if (must_be_viewable && attrs.map_state != IsViewable)
3601 {
3602 /* Only manage if WM_STATE is IconicState or NormalState */
3603 uint32_t state;
3604
3605 /* WM_STATE isn't a cardinal, it's type WM_STATE, but is an int */
3606 if (!(meta_prop_get_cardinal_with_atom_type (x11_display, xwindow,
3607 x11_display->atom_WM_STATE,
3608 x11_display->atom_WM_STATE,
3609 &state) &&
3610 (state == IconicState || state == NormalState)))
3611 {
3612 meta_verbose ("Deciding not to manage unmapped or unviewable window 0x%lx",
3613 xwindow);
3614 goto error;
3615 }
3616
3617 existing_wm_state = state;
3618 meta_verbose ("WM_STATE of %lx = %s", xwindow,
3619 wm_state_to_string (existing_wm_state));
3620 }
3621
3622 /*
3623 * XAddToSaveSet can only be called on windows created by a different
3624 * client. with Mutter we want to be able to create manageable windows
3625 * from within the process (such as a dummy desktop window). As we do not
3626 * want this call failing to prevent the window from being managed, we
3627 * call this before creating the return-checked error trap.
3628 */
3629 XAddToSaveSet (x11_display->xdisplay, xwindow);
3630
3631 meta_x11_error_trap_push (x11_display);
3632
3633 event_mask = PropertyChangeMask;
3634 if (attrs.override_redirect)
3635 event_mask |= StructureNotifyMask;
3636
3637 /* If the window is from this client (a menu, say) we need to augment
3638 * the event mask, not replace it. For windows from other clients,
3639 * attrs.your_event_mask will be empty at this point.
3640 */
3641 XSelectInput (x11_display->xdisplay, xwindow, attrs.your_event_mask | event_mask);
3642
3643 {
3644 unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
3645 XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
3646
3647 XISetMask (mask.mask, XI_Enter);
3648 XISetMask (mask.mask, XI_Leave);
3649 XISetMask (mask.mask, XI_FocusIn);
3650 XISetMask (mask.mask, XI_FocusOut);
3651
3652 XISelectEvents (x11_display->xdisplay, xwindow, &mask, 1);
3653 }
3654
3655 if (META_X11_DISPLAY_HAS_SHAPE (x11_display))
3656 XShapeSelectInput (x11_display->xdisplay, xwindow, ShapeNotifyMask);
3657
3658 /* Get rid of any borders */
3659 if (attrs.border_width != 0)
3660 XSetWindowBorderWidth (x11_display->xdisplay, xwindow, 0);
3661
3662 /* Get rid of weird gravities */
3663 if (attrs.win_gravity != NorthWestGravity)
3664 {
3665 XSetWindowAttributes set_attrs;
3666
3667 set_attrs.win_gravity = NorthWestGravity;
3668
3669 XChangeWindowAttributes (x11_display->xdisplay,
3670 xwindow,
3671 CWWinGravity,
3672 &set_attrs);
3673 }
3674
3675 if (meta_x11_error_trap_pop_with_return (x11_display) != Success)
3676 {
3677 meta_verbose ("Window 0x%lx disappeared just as we tried to manage it",
3678 xwindow);
3679 goto error;
3680 }
3681
3682 window = _meta_window_shared_new (display,
3683 META_WINDOW_CLIENT_TYPE_X11,
3684 NULL,
3685 xwindow,
3686 existing_wm_state,
3687 effect,
3688 &attrs);
3689
3690 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
3691 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
3692
3693 priv->border_width = attrs.border_width;
3694
3695 meta_window_grab_keys (window);
3696 if (window->type != META_WINDOW_DOCK && !window->override_redirect)
3697 {
3698 meta_display_grab_window_buttons (window->display, window->xwindow);
3699 meta_display_grab_focus_window_button (window->display, window);
3700 }
3701
3702 meta_x11_error_trap_pop (x11_display); /* pop the XSync()-reducing trap */
3703 return window;
3704
3705 error:
3706 meta_x11_error_trap_pop (x11_display);
3707 return NULL;
3708 }
3709
3710 void
meta_window_x11_recalc_window_type(MetaWindow * window)3711 meta_window_x11_recalc_window_type (MetaWindow *window)
3712 {
3713 MetaX11Display *x11_display = window->display->x11_display;
3714 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
3715 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
3716 MetaWindowType type;
3717
3718 if (priv->type_atom != None)
3719 {
3720 if (priv->type_atom == x11_display->atom__NET_WM_WINDOW_TYPE_DESKTOP)
3721 type = META_WINDOW_DESKTOP;
3722 else if (priv->type_atom == x11_display->atom__NET_WM_WINDOW_TYPE_DOCK)
3723 type = META_WINDOW_DOCK;
3724 else if (priv->type_atom == x11_display->atom__NET_WM_WINDOW_TYPE_TOOLBAR)
3725 type = META_WINDOW_TOOLBAR;
3726 else if (priv->type_atom == x11_display->atom__NET_WM_WINDOW_TYPE_MENU)
3727 type = META_WINDOW_MENU;
3728 else if (priv->type_atom == x11_display->atom__NET_WM_WINDOW_TYPE_UTILITY)
3729 type = META_WINDOW_UTILITY;
3730 else if (priv->type_atom == x11_display->atom__NET_WM_WINDOW_TYPE_SPLASH)
3731 type = META_WINDOW_SPLASHSCREEN;
3732 else if (priv->type_atom == x11_display->atom__NET_WM_WINDOW_TYPE_DIALOG)
3733 type = META_WINDOW_DIALOG;
3734 else if (priv->type_atom == x11_display->atom__NET_WM_WINDOW_TYPE_NORMAL)
3735 type = META_WINDOW_NORMAL;
3736 /* The below are *typically* override-redirect windows, but the spec does
3737 * not disallow using them for managed windows.
3738 */
3739 else if (priv->type_atom == x11_display->atom__NET_WM_WINDOW_TYPE_DROPDOWN_MENU)
3740 type = META_WINDOW_DROPDOWN_MENU;
3741 else if (priv->type_atom == x11_display->atom__NET_WM_WINDOW_TYPE_POPUP_MENU)
3742 type = META_WINDOW_POPUP_MENU;
3743 else if (priv->type_atom == x11_display->atom__NET_WM_WINDOW_TYPE_TOOLTIP)
3744 type = META_WINDOW_TOOLTIP;
3745 else if (priv->type_atom == x11_display->atom__NET_WM_WINDOW_TYPE_NOTIFICATION)
3746 type = META_WINDOW_NOTIFICATION;
3747 else if (priv->type_atom == x11_display->atom__NET_WM_WINDOW_TYPE_COMBO)
3748 type = META_WINDOW_COMBO;
3749 else if (priv->type_atom == x11_display->atom__NET_WM_WINDOW_TYPE_DND)
3750 type = META_WINDOW_DND;
3751 else
3752 {
3753 char *atom_name;
3754
3755 /*
3756 * Fallback on a normal type, and print warning. Don't abort.
3757 */
3758 type = META_WINDOW_NORMAL;
3759
3760 meta_x11_error_trap_push (x11_display);
3761 atom_name = XGetAtomName (x11_display->xdisplay,
3762 priv->type_atom);
3763 meta_x11_error_trap_pop (x11_display);
3764
3765 meta_warning ("Unrecognized type atom [%s] set for %s ",
3766 atom_name ? atom_name : "unknown",
3767 window->desc);
3768
3769 if (atom_name)
3770 XFree (atom_name);
3771 }
3772 }
3773 else if (window->transient_for != NULL)
3774 {
3775 type = META_WINDOW_DIALOG;
3776 }
3777 else
3778 {
3779 type = META_WINDOW_NORMAL;
3780 }
3781
3782 if (type == META_WINDOW_DIALOG && priv->wm_state_modal)
3783 type = META_WINDOW_MODAL_DIALOG;
3784
3785 /* We don't want to allow override-redirect windows to have decorated-window
3786 * types since that's just confusing.
3787 */
3788 if (window->override_redirect)
3789 {
3790 switch (type)
3791 {
3792 /* Decorated types */
3793 case META_WINDOW_NORMAL:
3794 case META_WINDOW_DIALOG:
3795 case META_WINDOW_MODAL_DIALOG:
3796 case META_WINDOW_MENU:
3797 case META_WINDOW_UTILITY:
3798 type = META_WINDOW_OVERRIDE_OTHER;
3799 break;
3800 /* Undecorated types, normally not override-redirect */
3801 case META_WINDOW_DESKTOP:
3802 case META_WINDOW_DOCK:
3803 case META_WINDOW_TOOLBAR:
3804 case META_WINDOW_SPLASHSCREEN:
3805 /* Undecorated types, normally override-redirect types */
3806 case META_WINDOW_DROPDOWN_MENU:
3807 case META_WINDOW_POPUP_MENU:
3808 case META_WINDOW_TOOLTIP:
3809 case META_WINDOW_NOTIFICATION:
3810 case META_WINDOW_COMBO:
3811 case META_WINDOW_DND:
3812 /* To complete enum */
3813 case META_WINDOW_OVERRIDE_OTHER:
3814 break;
3815 }
3816 }
3817
3818 meta_verbose ("Calculated type %u for %s, old type %u",
3819 type, window->desc, type);
3820 meta_window_set_type (window, type);
3821 }
3822
3823 /**
3824 * meta_window_x11_configure_notify: (skip)
3825 * @window: a #MetaWindow
3826 * @event: a #XConfigureEvent
3827 *
3828 * This is used to notify us of an unrequested configuration
3829 * (only applicable to override redirect windows)
3830 */
3831 void
meta_window_x11_configure_notify(MetaWindow * window,XConfigureEvent * event)3832 meta_window_x11_configure_notify (MetaWindow *window,
3833 XConfigureEvent *event)
3834 {
3835 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
3836 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
3837
3838 g_assert (window->override_redirect);
3839 g_assert (window->frame == NULL);
3840
3841 window->rect.x = event->x;
3842 window->rect.y = event->y;
3843 window->rect.width = event->width;
3844 window->rect.height = event->height;
3845
3846 priv->client_rect = window->rect;
3847 window->buffer_rect = window->rect;
3848
3849 meta_window_update_monitor (window, META_WINDOW_UPDATE_MONITOR_FLAGS_NONE);
3850
3851 /* Whether an override-redirect window is considered fullscreen depends
3852 * on its geometry.
3853 */
3854 if (window->override_redirect)
3855 meta_display_queue_check_fullscreen (window->display);
3856
3857 if (!event->override_redirect && !event->send_event)
3858 meta_warning ("Unhandled change of windows override redirect status");
3859
3860 meta_compositor_sync_window_geometry (window->display->compositor, window, FALSE);
3861 }
3862
3863 void
meta_window_x11_set_allowed_actions_hint(MetaWindow * window)3864 meta_window_x11_set_allowed_actions_hint (MetaWindow *window)
3865 {
3866 MetaX11Display *x11_display = window->display->x11_display;
3867 #define MAX_N_ACTIONS 12
3868 unsigned long data[MAX_N_ACTIONS];
3869 int i;
3870
3871 i = 0;
3872 if (window->has_move_func)
3873 {
3874 data[i] = x11_display->atom__NET_WM_ACTION_MOVE;
3875 ++i;
3876 }
3877 if (window->has_resize_func)
3878 {
3879 data[i] = x11_display->atom__NET_WM_ACTION_RESIZE;
3880 ++i;
3881 }
3882 if (window->has_fullscreen_func)
3883 {
3884 data[i] = x11_display->atom__NET_WM_ACTION_FULLSCREEN;
3885 ++i;
3886 }
3887 if (window->has_minimize_func)
3888 {
3889 data[i] = x11_display->atom__NET_WM_ACTION_MINIMIZE;
3890 ++i;
3891 }
3892 if (window->has_shade_func)
3893 {
3894 data[i] = x11_display->atom__NET_WM_ACTION_SHADE;
3895 ++i;
3896 }
3897 /* sticky according to EWMH is different from mutter's sticky;
3898 * mutter doesn't support EWMH sticky
3899 */
3900 if (window->has_maximize_func)
3901 {
3902 data[i] = x11_display->atom__NET_WM_ACTION_MAXIMIZE_HORZ;
3903 ++i;
3904 data[i] = x11_display->atom__NET_WM_ACTION_MAXIMIZE_VERT;
3905 ++i;
3906 }
3907 /* We always allow this */
3908 data[i] = x11_display->atom__NET_WM_ACTION_CHANGE_DESKTOP;
3909 ++i;
3910 if (window->has_close_func)
3911 {
3912 data[i] = x11_display->atom__NET_WM_ACTION_CLOSE;
3913 ++i;
3914 }
3915
3916 /* I guess we always allow above/below operations */
3917 data[i] = x11_display->atom__NET_WM_ACTION_ABOVE;
3918 ++i;
3919 data[i] = x11_display->atom__NET_WM_ACTION_BELOW;
3920 ++i;
3921
3922 g_assert (i <= MAX_N_ACTIONS);
3923
3924 meta_verbose ("Setting _NET_WM_ALLOWED_ACTIONS with %d atoms", i);
3925
3926 meta_x11_error_trap_push (x11_display);
3927 XChangeProperty (x11_display->xdisplay, window->xwindow,
3928 x11_display->atom__NET_WM_ALLOWED_ACTIONS,
3929 XA_ATOM,
3930 32, PropModeReplace, (guchar*) data, i);
3931 meta_x11_error_trap_pop (x11_display);
3932 #undef MAX_N_ACTIONS
3933 }
3934
3935 void
meta_window_x11_create_sync_request_alarm(MetaWindow * window)3936 meta_window_x11_create_sync_request_alarm (MetaWindow *window)
3937 {
3938 MetaX11Display *x11_display = window->display->x11_display;
3939 XSyncAlarmAttributes values;
3940 XSyncValue init;
3941
3942 if (window->sync_request_counter == None ||
3943 window->sync_request_alarm != None)
3944 return;
3945
3946 meta_x11_error_trap_push (x11_display);
3947
3948 /* In the new (extended style), the counter value is initialized by
3949 * the client before mapping the window. In the old style, we're
3950 * responsible for setting the initial value of the counter.
3951 */
3952 if (window->extended_sync_request_counter)
3953 {
3954 if (!XSyncQueryCounter(x11_display->xdisplay,
3955 window->sync_request_counter,
3956 &init))
3957 {
3958 meta_x11_error_trap_pop_with_return (x11_display);
3959 window->sync_request_counter = None;
3960 return;
3961 }
3962
3963 window->sync_request_serial =
3964 XSyncValueLow32 (init) + ((gint64)XSyncValueHigh32 (init) << 32);
3965 }
3966 else
3967 {
3968 XSyncIntToValue (&init, 0);
3969 XSyncSetCounter (x11_display->xdisplay,
3970 window->sync_request_counter, init);
3971 window->sync_request_serial = 0;
3972 }
3973
3974 values.trigger.counter = window->sync_request_counter;
3975 values.trigger.test_type = XSyncPositiveComparison;
3976
3977 /* Initialize to one greater than the current value */
3978 values.trigger.value_type = XSyncRelative;
3979 XSyncIntToValue (&values.trigger.wait_value, 1);
3980
3981 /* After triggering, increment test_value by this until
3982 * until the test condition is false */
3983 XSyncIntToValue (&values.delta, 1);
3984
3985 /* we want events (on by default anyway) */
3986 values.events = True;
3987
3988 window->sync_request_alarm = XSyncCreateAlarm (x11_display->xdisplay,
3989 XSyncCACounter |
3990 XSyncCAValueType |
3991 XSyncCAValue |
3992 XSyncCATestType |
3993 XSyncCADelta |
3994 XSyncCAEvents,
3995 &values);
3996
3997 if (meta_x11_error_trap_pop_with_return (x11_display) == Success)
3998 meta_x11_display_register_sync_alarm (x11_display, &window->sync_request_alarm, window);
3999 else
4000 {
4001 window->sync_request_alarm = None;
4002 window->sync_request_counter = None;
4003 }
4004 }
4005
4006 void
meta_window_x11_destroy_sync_request_alarm(MetaWindow * window)4007 meta_window_x11_destroy_sync_request_alarm (MetaWindow *window)
4008 {
4009 MetaX11Display *x11_display = window->display->x11_display;
4010
4011 if (window->sync_request_alarm != None)
4012 {
4013 /* Has to be unregistered _before_ clearing the structure field */
4014 meta_x11_display_unregister_sync_alarm (x11_display, window->sync_request_alarm);
4015 XSyncDestroyAlarm (x11_display->xdisplay,
4016 window->sync_request_alarm);
4017 window->sync_request_alarm = None;
4018 }
4019 }
4020
4021 void
meta_window_x11_update_sync_request_counter(MetaWindow * window,gint64 new_counter_value)4022 meta_window_x11_update_sync_request_counter (MetaWindow *window,
4023 gint64 new_counter_value)
4024 {
4025 gboolean needs_frame_drawn = FALSE;
4026 gboolean no_delay_frame = FALSE;
4027
4028 COGL_TRACE_BEGIN (MetaWindowSyncRequestCounter, "X11: Sync request counter");
4029
4030 if (window->extended_sync_request_counter && new_counter_value % 2 == 0)
4031 {
4032 needs_frame_drawn = TRUE;
4033 no_delay_frame = new_counter_value == window->sync_request_serial + 1;
4034 }
4035
4036 window->sync_request_serial = new_counter_value;
4037 meta_compositor_sync_updates_frozen (window->display->compositor, window);
4038
4039 if (new_counter_value >= window->sync_request_wait_serial &&
4040 window->sync_request_timeout_id)
4041 {
4042
4043 if (!window->extended_sync_request_counter ||
4044 new_counter_value % 2 == 0)
4045 g_clear_handle_id (&window->sync_request_timeout_id, g_source_remove);
4046
4047 if (window == window->display->grab_window &&
4048 meta_grab_op_is_resizing (window->display->grab_op) &&
4049 (!window->extended_sync_request_counter ||
4050 new_counter_value % 2 == 0))
4051 {
4052 meta_topic (META_DEBUG_RESIZING,
4053 "Alarm event received last motion x = %d y = %d",
4054 window->display->grab_latest_motion_x,
4055 window->display->grab_latest_motion_y);
4056
4057 /* This means we are ready for another configure;
4058 * no pointer round trip here, to keep in sync */
4059 meta_window_update_resize (window,
4060 window->display->grab_last_edge_resistance_flags,
4061 window->display->grab_latest_motion_x,
4062 window->display->grab_latest_motion_y,
4063 TRUE);
4064 }
4065 }
4066
4067 /* If sync was previously disabled, turn it back on and hope
4068 * the application has come to its senses (maybe it was just
4069 * busy with a pagefault or a long computation).
4070 */
4071 window->disable_sync = FALSE;
4072
4073 if (needs_frame_drawn)
4074 meta_compositor_queue_frame_drawn (window->display->compositor, window,
4075 no_delay_frame);
4076
4077 #ifdef COGL_HAS_TRACING
4078 if (G_UNLIKELY (cogl_is_tracing_enabled ()))
4079 {
4080 g_autofree char *description = NULL;
4081
4082 description =
4083 g_strdup_printf ("sync request serial: %" G_GINT64_FORMAT ", "
4084 "needs frame drawn: %s",
4085 new_counter_value,
4086 needs_frame_drawn ? "yes" : "no");
4087 COGL_TRACE_DESCRIBE (MetaWindowSyncRequestCounter, description);
4088 COGL_TRACE_END (MetaWindowSyncRequestCounter);
4089 }
4090 #endif
4091 }
4092
4093 Window
meta_window_x11_get_toplevel_xwindow(MetaWindow * window)4094 meta_window_x11_get_toplevel_xwindow (MetaWindow *window)
4095 {
4096 return window->frame ? window->frame->xwindow : window->xwindow;
4097 }
4098
4099 void
meta_window_x11_freeze_commits(MetaWindow * window)4100 meta_window_x11_freeze_commits (MetaWindow *window)
4101 {
4102 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
4103 META_WINDOW_X11_GET_CLASS (window_x11)->freeze_commits (window);
4104 }
4105
4106 void
meta_window_x11_thaw_commits(MetaWindow * window)4107 meta_window_x11_thaw_commits (MetaWindow *window)
4108 {
4109 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
4110 META_WINDOW_X11_GET_CLASS (window_x11)->thaw_commits (window);
4111 }
4112
4113 void
meta_window_x11_set_thaw_after_paint(MetaWindow * window,gboolean thaw_after_paint)4114 meta_window_x11_set_thaw_after_paint (MetaWindow *window,
4115 gboolean thaw_after_paint)
4116 {
4117 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
4118 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
4119
4120 priv->thaw_after_paint = thaw_after_paint;
4121 }
4122
4123 gboolean
meta_window_x11_should_thaw_after_paint(MetaWindow * window)4124 meta_window_x11_should_thaw_after_paint (MetaWindow *window)
4125 {
4126 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
4127 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
4128
4129 return priv->thaw_after_paint;
4130 }
4131
4132 gboolean
meta_window_x11_always_update_shape(MetaWindow * window)4133 meta_window_x11_always_update_shape (MetaWindow *window)
4134 {
4135 MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
4136
4137 return META_WINDOW_X11_GET_CLASS (window_x11)->always_update_shape (window);
4138 }
4139
4140 void
meta_window_x11_surface_rect_to_frame_rect(MetaWindow * window,MetaRectangle * surface_rect,MetaRectangle * frame_rect)4141 meta_window_x11_surface_rect_to_frame_rect (MetaWindow *window,
4142 MetaRectangle *surface_rect,
4143 MetaRectangle *frame_rect)
4144
4145 {
4146 MetaFrameBorders borders;
4147
4148 g_return_if_fail (window->frame);
4149
4150 meta_frame_calc_borders (window->frame, &borders);
4151
4152 *frame_rect = *surface_rect;
4153 frame_rect->x += borders.invisible.left;
4154 frame_rect->y += borders.invisible.top;
4155 frame_rect->width -= borders.invisible.left + borders.invisible.right;
4156 frame_rect->height -= borders.invisible.top + borders.invisible.bottom;
4157 }
4158
4159 void
meta_window_x11_surface_rect_to_client_rect(MetaWindow * window,MetaRectangle * surface_rect,MetaRectangle * client_rect)4160 meta_window_x11_surface_rect_to_client_rect (MetaWindow *window,
4161 MetaRectangle *surface_rect,
4162 MetaRectangle *client_rect)
4163 {
4164 MetaFrameBorders borders;
4165
4166 meta_frame_calc_borders (window->frame, &borders);
4167
4168 *client_rect = *surface_rect;
4169 client_rect->x += borders.total.left;
4170 client_rect->y += borders.total.top;
4171 client_rect->width -= borders.total.left + borders.total.right;
4172 client_rect->height -= borders.total.top + borders.total.bottom;
4173 }
4174
4175 MetaRectangle
meta_window_x11_get_client_rect(MetaWindowX11 * window_x11)4176 meta_window_x11_get_client_rect (MetaWindowX11 *window_x11)
4177 {
4178 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
4179
4180 return priv->client_rect;
4181 }
4182
4183 static gboolean
has_requested_bypass_compositor(MetaWindowX11 * window_x11)4184 has_requested_bypass_compositor (MetaWindowX11 *window_x11)
4185 {
4186 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
4187
4188 return priv->bypass_compositor == META_BYPASS_COMPOSITOR_HINT_ON;
4189 }
4190
4191 static gboolean
has_requested_dont_bypass_compositor(MetaWindowX11 * window_x11)4192 has_requested_dont_bypass_compositor (MetaWindowX11 *window_x11)
4193 {
4194 MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
4195
4196 return priv->bypass_compositor == META_BYPASS_COMPOSITOR_HINT_OFF;
4197 }
4198
4199 gboolean
meta_window_x11_can_unredirect(MetaWindowX11 * window_x11)4200 meta_window_x11_can_unredirect (MetaWindowX11 *window_x11)
4201 {
4202 MetaWindow *window = META_WINDOW (window_x11);
4203
4204 if (has_requested_dont_bypass_compositor (window_x11))
4205 return FALSE;
4206
4207 if (window->opacity != 0xFF)
4208 return FALSE;
4209
4210 if (window->shape_region != NULL)
4211 return FALSE;
4212
4213 if (!window->monitor)
4214 return FALSE;
4215
4216 if (window->fullscreen)
4217 return TRUE;
4218
4219 if (meta_window_is_screen_sized (window))
4220 return TRUE;
4221
4222 if (has_requested_bypass_compositor (window_x11))
4223 return TRUE;
4224
4225 if (window->override_redirect)
4226 {
4227 MetaRectangle window_rect;
4228 MetaRectangle logical_monitor_layout;
4229 MetaLogicalMonitor *logical_monitor = window->monitor;
4230
4231 meta_window_get_frame_rect (window, &window_rect);
4232 logical_monitor_layout =
4233 meta_logical_monitor_get_layout (logical_monitor);
4234
4235 if (meta_rectangle_equal (&window_rect, &logical_monitor_layout))
4236 return TRUE;
4237 }
4238
4239 return FALSE;
4240 }
4241