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 (&region, 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