1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 
3 /**
4  * SECTION:compositor
5  * @title: MetaCompositor
6  * @short_Description: Compositor API
7  *
8  * At a high-level, a window is not-visible or visible. When a
9  * window is added (with meta_compositor_add_window()) it is not visible.
10  * meta_compositor_show_window() indicates a transition from not-visible to
11  * visible. Some of the reasons for this:
12  *
13  * - Window newly created
14  * - Window is unminimized
15  * - Window is moved to the current desktop
16  * - Window was made sticky
17  *
18  * meta_compositor_hide_window() indicates that the window has transitioned from
19  * visible to not-visible. Some reasons include:
20  *
21  * - Window was destroyed
22  * - Window is minimized
23  * - Window is moved to a different desktop
24  * - Window no longer sticky.
25  *
26  * Note that combinations are possible - a window might have first
27  * been minimized and then moved to a different desktop. The 'effect' parameter
28  * to meta_compositor_show_window() and meta_compositor_hide_window() is a hint
29  * as to the appropriate effect to show the user and should not
30  * be considered to be indicative of a state change.
31  *
32  * When the active workspace is changed, meta_compositor_switch_workspace() is
33  * called first, then meta_compositor_show_window() and
34  * meta_compositor_hide_window() are called individually for each window
35  * affected, with an effect of META_COMP_EFFECT_NONE.
36  * If hiding windows will affect the switch workspace animation, the
37  * compositor needs to delay hiding the windows until the switch
38  * workspace animation completes.
39  *
40  * meta_compositor_maximize_window() and meta_compositor_unmaximize_window()
41  * are transitions within the visible state. The window is resized __before__
42  * the call, so it may be necessary to readjust the display based on the
43  * old_rect to start the animation.
44  *
45  * # Containers #
46  *
47  * There's two containers in the stage that are used to place window actors, here
48  * are listed in the order in which they are painted:
49  *
50  * - window group, accessible with meta_get_window_group_for_screen()
51  * - top window group, accessible with meta_get_top_window_group_for_screen()
52  *
53  * Muffin will place actors representing windows in the window group, except for
54  * override-redirect windows (ie. popups and menus) which will be placed in the
55  * top window group.
56  */
57 
58 
59 #include <config.h>
60 
61 #include <clutter/x11/clutter-x11.h>
62 
63 #include <meta/screen.h>
64 #include <meta/errors.h>
65 #include <meta/window.h>
66 #include "compositor-private.h"
67 #include <meta/compositor-muffin.h>
68 #include "xprops.h"
69 #include <meta/prefs.h>
70 #include <meta/main.h>
71 #include <meta/meta-shadow-factory.h>
72 #include "meta-window-actor-private.h"
73 #include "meta-window-group.h"
74 #include "meta-background-actor-private.h"
75 #include "window-private.h" /* to check window->hidden */
76 #include "display-private.h" /* for meta_display_lookup_x_window() */
77 #include "util-private.h"
78 #include <X11/extensions/shape.h>
79 #include <X11/extensions/Xcomposite.h>
80 #include "meta-sync-ring.h"
81 
82 /* #define DEBUG_TRACE g_print */
83 #define DEBUG_TRACE(X)
84 
85 static MetaCompositor *compositor_global = NULL;
86 
87 static void
88 frame_callback (ClutterStage     *stage,
89                 CoglFrameEvent    event,
90                 ClutterFrameInfo *frame_info,
91                 MetaCompositor   *compositor);
92 
93 static inline gboolean
composite_at_least_version(MetaDisplay * display,int maj,int min)94 composite_at_least_version (MetaDisplay *display, int maj, int min)
95 {
96   static int major = -1;
97   static int minor = -1;
98 
99   if (major == -1)
100     meta_display_get_compositor_version (display, &major, &minor);
101 
102   return (major > maj || (major == maj && minor >= min));
103 }
104 
105 static void sync_actor_stacking (MetaCompositor *compositor);
106 
107 static void
meta_finish_workspace_switch(MetaCompositor * compositor)108 meta_finish_workspace_switch (MetaCompositor *compositor)
109 {
110   GList *l;
111 
112   /* Finish hiding and showing actors for the new workspace */
113   for (l = compositor->windows; l; l = l->next)
114     meta_window_actor_sync_visibility (l->data);
115 
116   /*
117    * Fix up stacking order in case the plugin messed it up.
118    */
119   sync_actor_stacking (compositor);
120 
121 /*   printf ("... FINISHED DESKTOP SWITCH\n"); */
122 
123 }
124 
125 LOCAL_SYMBOL void
meta_switch_workspace_completed(MetaScreen * screen)126 meta_switch_workspace_completed (MetaScreen *screen)
127 {
128   MetaCompositor *compositor = screen->display->compositor;
129 
130   /* FIXME -- must redo stacking order */
131   compositor->switch_workspace_in_progress--;
132   if (compositor->switch_workspace_in_progress < 0)
133     {
134       g_warning ("Error in workspace_switch accounting!");
135       compositor->switch_workspace_in_progress = 0;
136     }
137 
138   if (!compositor->switch_workspace_in_progress)
139     meta_finish_workspace_switch (compositor);
140 }
141 
142 void
meta_compositor_destroy(MetaCompositor * compositor)143 meta_compositor_destroy (MetaCompositor *compositor)
144 {
145   clutter_threads_remove_repaint_func (compositor->pre_paint_func_id);
146   clutter_threads_remove_repaint_func (compositor->post_paint_func_id);
147 
148   if (compositor->have_x11_sync_object)
149     meta_sync_ring_destroy ();
150 }
151 
152 static void
add_win(MetaWindow * window)153 add_win (MetaWindow *window)
154 {
155   meta_window_actor_new (window);
156 
157   sync_actor_stacking (window->screen->display->compositor);
158 }
159 
160 static void
process_damage(MetaCompositor * compositor,XDamageNotifyEvent * event,MetaWindow * window)161 process_damage (MetaCompositor     *compositor,
162                 XDamageNotifyEvent *event,
163                 MetaWindow         *window)
164 {
165   MetaWindowActor *window_actor;
166 
167   if (window == NULL)
168     return;
169 
170   window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
171   if (window_actor == NULL)
172     return;
173 
174   meta_window_actor_process_damage (window_actor, event);
175 
176   compositor->frame_has_updated_xsurfaces = TRUE;
177 }
178 
179 static void
process_property_notify(MetaCompositor * compositor,XPropertyEvent * event,MetaWindow * window)180 process_property_notify (MetaCompositor	*compositor,
181                          XPropertyEvent *event,
182                          MetaWindow     *window)
183 {
184   MetaWindowActor *window_actor;
185 
186   if (event->atom == compositor->atom_x_root_pixmap)
187     {
188       GSList *l;
189 
190       for (l = meta_display_get_screens (compositor->display); l; l = l->next)
191         {
192 	  MetaScreen  *screen = l->data;
193           if (event->window == meta_screen_get_xroot (screen))
194             {
195               meta_background_actor_update (screen);
196               return;
197             }
198         }
199     }
200 
201   if (window == NULL)
202     return;
203 
204   window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
205   if (window_actor == NULL)
206     return;
207 
208   /* Check for the opacity changing */
209   if (event->atom == compositor->atom_net_wm_window_opacity)
210     {
211       meta_window_actor_update_opacity (window_actor);
212       DEBUG_TRACE ("process_property_notify: net_wm_window_opacity\n");
213       return;
214     }
215 
216   DEBUG_TRACE ("process_property_notify: unknown\n");
217 }
218 
219 static Window
get_output_window(MetaScreen * screen)220 get_output_window (MetaScreen *screen)
221 {
222   MetaDisplay *display = meta_screen_get_display (screen);
223   Display     *xdisplay = meta_display_get_xdisplay (display);
224   Window       output, xroot;
225   XWindowAttributes attr;
226   long         event_mask;
227 
228   xroot = meta_screen_get_xroot (screen);
229 
230   event_mask = FocusChangeMask |
231                ExposureMask |
232                EnterWindowMask | LeaveWindowMask |
233 	       PointerMotionMask |
234                PropertyChangeMask |
235                ButtonPressMask | ButtonReleaseMask |
236                KeyPressMask | KeyReleaseMask;
237 
238   output = screen->composite_overlay_window;
239 
240   if (XGetWindowAttributes (xdisplay, output, &attr))
241       {
242         event_mask |= attr.your_event_mask;
243       }
244 
245   XSelectInput (xdisplay, output, event_mask);
246 
247   return output;
248 }
249 
250 /**
251  * meta_get_stage_for_screen:
252  * @screen: a #MetaScreen
253  *
254  * Returns: (transfer none): The #ClutterStage for the screen
255  */
256 ClutterActor *
meta_get_stage_for_screen(MetaScreen * screen)257 meta_get_stage_for_screen (MetaScreen *screen)
258 {
259   return screen->display->compositor->stage;
260 }
261 
262 /**
263  * meta_get_overlay_group_for_screen:
264  * @screen: a #MetaScreen
265  *
266  * Returns: (transfer none): The overlay group corresponding to @screen
267  */
268 ClutterActor *
meta_get_overlay_group_for_screen(MetaScreen * screen)269 meta_get_overlay_group_for_screen (MetaScreen *screen)
270 {
271   return screen->display->compositor->overlay_group;
272 }
273 
274 /**
275  * meta_get_window_group_for_screen:
276  * @screen: a #MetaScreen
277  *
278  * Returns: (transfer none): The window group corresponding to @screen
279  */
280 ClutterActor *
meta_get_window_group_for_screen(MetaScreen * screen)281 meta_get_window_group_for_screen (MetaScreen *screen)
282 {
283   return screen->display->compositor->window_group;
284 }
285 
286 /**
287  * meta_get_bottom_window_group_for_screen:
288  * @screen: a #MetaScreen
289  *
290  * Returns: (transfer none): The bottom window group corresponding to @screen
291  */
292 ClutterActor *
meta_get_bottom_window_group_for_screen(MetaScreen * screen)293 meta_get_bottom_window_group_for_screen (MetaScreen *screen)
294 {
295   return screen->display->compositor->bottom_window_group;
296 }
297 
298 /**
299  * meta_get_top_window_group_for_screen:
300  * @screen: a #MetaScreen
301  *
302  * Returns: (transfer none): The top window group corresponding to @screen
303  */
304 ClutterActor *
meta_get_top_window_group_for_screen(MetaScreen * screen)305 meta_get_top_window_group_for_screen (MetaScreen *screen)
306 {
307   return screen->display->compositor->top_window_group;
308 }
309 
310 /**
311  * meta_get_background_actor_for_screen:
312  * @screen: a #MetaScreen
313  *
314  * Gets the actor that draws the root window background under the windows.
315  * The root window background automatically tracks the image or color set
316  * by the environment.
317  *
318  * Returns: (transfer none): The background actor corresponding to @screen
319  */
320 ClutterActor *
meta_get_background_actor_for_screen(MetaScreen * screen)321 meta_get_background_actor_for_screen (MetaScreen *screen)
322 {
323   return screen->display->compositor->background_actor;
324 }
325 
326 /**
327  * meta_get_window_actors:
328  * @screen: a #MetaScreen
329  *
330  * Returns: (transfer none) (element-type Clutter.Actor): The set of #MetaWindowActor on @screen
331  */
332 GList *
meta_get_window_actors(MetaScreen * screen)333 meta_get_window_actors (MetaScreen *screen)
334 {
335   return screen->display->compositor->windows;
336 }
337 
338 static void
do_set_stage_input_region(MetaScreen * screen,XserverRegion region)339 do_set_stage_input_region (MetaScreen   *screen,
340                            XserverRegion region)
341 {
342   MetaDisplay *display = screen->display;
343   MetaCompositor *compositor = display->compositor;
344   Display *xdpy = display->xdisplay;
345   Window xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage));
346 
347   XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region);
348 
349   /* It's generally a good heuristic that when a crossing event is generated because
350    * we reshape the overlay, we don't want it to affect focus-follows-mouse focus -
351    * it's not the user doing something, it's the environment changing under the user.
352    */
353   meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy));
354   XFixesSetWindowShapeRegion (xdpy, compositor->output, ShapeInput, 0, 0, region);
355 }
356 
357 void
meta_set_stage_input_region(MetaScreen * screen,XserverRegion region)358 meta_set_stage_input_region (MetaScreen   *screen,
359                              XserverRegion region)
360 {
361   MetaDisplay  *display = screen->display;
362   MetaCompositor *compositor = display->compositor;
363   Display *xdpy = display->xdisplay;
364 
365   if (compositor->stage && compositor->output)
366     {
367       do_set_stage_input_region (screen, region);
368     }
369   else
370     {
371       /* Reset compositor->pending_input_region if one existed before and set the new
372        * one to use it later. */
373       if (compositor->pending_input_region)
374         {
375           XFixesDestroyRegion (xdpy, compositor->pending_input_region);
376           compositor->pending_input_region = None;
377         }
378       if (region != None)
379         {
380           compositor->pending_input_region = XFixesCreateRegion (xdpy, NULL, 0);
381           XFixesCopyRegion (xdpy, compositor->pending_input_region, region);
382         }
383     }
384 }
385 
386 void
meta_empty_stage_input_region(MetaScreen * screen)387 meta_empty_stage_input_region (MetaScreen *screen)
388 {
389   /* Using a static region here is a bit hacky, but Metacity never opens more than
390    * one XDisplay, so it works fine. */
391   static XserverRegion region = None;
392 
393   if (region == None)
394     {
395       MetaDisplay  *display = meta_screen_get_display (screen);
396       Display      *xdpy    = meta_display_get_xdisplay (display);
397       region = XFixesCreateRegion (xdpy, NULL, 0);
398     }
399 
400   meta_set_stage_input_region (screen, region);
401 }
402 
403 LOCAL_SYMBOL gboolean
meta_begin_modal_for_plugin(MetaScreen * screen,MetaPlugin * plugin,Window grab_window,Cursor cursor,MetaModalOptions options,guint32 timestamp)404 meta_begin_modal_for_plugin (MetaScreen       *screen,
405                              MetaPlugin       *plugin,
406                              Window            grab_window,
407                              Cursor            cursor,
408                              MetaModalOptions  options,
409                              guint32           timestamp)
410 {
411   /* To some extent this duplicates code in meta_display_begin_grab_op(), but there
412    * are significant differences in how we handle grabs that make it difficult to
413    * merge the two.
414    */
415 
416   MetaDisplay    *display    = meta_screen_get_display (screen);
417   Display        *xdpy       = meta_display_get_xdisplay (display);
418   MetaCompositor *compositor = display->compositor;
419   gboolean pointer_grabbed = FALSE;
420   int result;
421 
422   if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE)
423     return FALSE;
424 
425   if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
426     {
427       result = XGrabPointer (xdpy, grab_window,
428                              False, /* owner_events */
429                              (ButtonPressMask | ButtonReleaseMask |
430                               EnterWindowMask | LeaveWindowMask | PointerMotionMask),
431                              GrabModeAsync, GrabModeAsync,
432                              None, /* confine to */
433                              cursor,
434                              timestamp);
435       if (result != Success)
436         goto fail;
437 
438       pointer_grabbed = TRUE;
439     }
440 
441   if ((options & META_MODAL_KEYBOARD_ALREADY_GRABBED) == 0)
442     {
443       result = XGrabKeyboard (xdpy, grab_window,
444                               False, /* owner_events */
445                               GrabModeAsync, GrabModeAsync,
446                               timestamp);
447 
448       if (result != Success)
449         goto fail;
450     }
451 
452   display->grab_op = META_GRAB_OP_COMPOSITOR;
453   display->grab_window = NULL;
454   display->grab_screen = screen;
455   display->grab_have_pointer = TRUE;
456   display->grab_have_keyboard = TRUE;
457 
458   compositor->modal_plugin = plugin;
459 
460   return TRUE;
461 
462  fail:
463   if (pointer_grabbed)
464     XUngrabPointer (xdpy, timestamp);
465 
466   return FALSE;
467 }
468 
469 LOCAL_SYMBOL void
meta_end_modal_for_plugin(MetaScreen * screen,MetaPlugin * plugin,guint32 timestamp)470 meta_end_modal_for_plugin (MetaScreen     *screen,
471                            MetaPlugin     *plugin,
472                            guint32         timestamp)
473 {
474   MetaDisplay    *display    = meta_screen_get_display (screen);
475   Display        *xdpy = meta_display_get_xdisplay (display);
476   MetaCompositor *compositor = display->compositor;
477 
478   g_return_if_fail (compositor->modal_plugin == plugin);
479 
480   XUngrabPointer (xdpy, timestamp);
481   XUngrabKeyboard (xdpy, timestamp);
482 
483   display->grab_op = META_GRAB_OP_NONE;
484   display->grab_window = NULL;
485   display->grab_screen = NULL;
486   display->grab_have_pointer = FALSE;
487   display->grab_have_keyboard = FALSE;
488 
489   compositor->modal_plugin = NULL;
490 }
491 
492 /* This is used when reloading plugins to make sure we don't have
493  * a left-over modal grab for this screen.
494  */
495 LOCAL_SYMBOL void
meta_check_end_modal(MetaScreen * screen)496 meta_check_end_modal (MetaScreen *screen)
497 {
498   MetaDisplay    *display    = meta_screen_get_display (screen);
499   MetaCompositor *compositor = display->compositor;
500 
501   if (compositor->modal_plugin &&
502       meta_plugin_get_screen (compositor->modal_plugin) == screen)
503     {
504       meta_end_modal_for_plugin (screen,
505                                  compositor->modal_plugin,
506                                  CurrentTime);
507     }
508 }
509 
510 static void
after_stage_paint(ClutterStage * stage,gpointer data)511 after_stage_paint (ClutterStage *stage,
512                    gpointer      data)
513 {
514   MetaCompositor *compositor = (MetaCompositor*) data;
515   GList *l;
516 
517   for (l = compositor->windows; l; l = l->next)
518     meta_window_actor_post_paint (l->data);
519 }
520 
521 static void
redirect_windows(MetaCompositor * compositor,MetaScreen * screen)522 redirect_windows (MetaCompositor *compositor,
523                   MetaScreen     *screen)
524 {
525   MetaDisplay *display       = meta_screen_get_display (screen);
526   Display     *xdisplay      = meta_display_get_xdisplay (display);
527   Window       xroot         = meta_screen_get_xroot (screen);
528   int          screen_number = meta_screen_get_screen_number (screen);
529   guint        n_retries;
530   guint        max_retries;
531 
532   if (meta_get_replace_current_wm ())
533     max_retries = 5;
534   else
535     max_retries = 1;
536 
537   n_retries = 0;
538 
539   /* Some compositors (like old versions of Muffin) might not properly unredirect
540    * subwindows before destroying the WM selection window; so we wait a while
541    * for such a compositor to exit before giving up.
542    */
543   while (TRUE)
544     {
545       meta_error_trap_push_with_return (display);
546       XCompositeRedirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
547       XSync (xdisplay, FALSE);
548 
549       if (!meta_error_trap_pop_with_return (display))
550         break;
551 
552       if (n_retries == max_retries)
553         {
554           /* This probably means that a non-WM compositor like xcompmgr is running;
555            * we have no way to get it to exit */
556           meta_fatal ("Another compositing manager is already running on screen %i on display \"%s\".",
557                       screen_number, display->name);
558         }
559 
560       n_retries++;
561       g_usleep (G_USEC_PER_SEC);
562     }
563 }
564 
565 LOCAL_SYMBOL void
meta_compositor_toggle_send_frame_timings(MetaScreen * screen)566 meta_compositor_toggle_send_frame_timings (MetaScreen *screen)
567 {
568   MetaCompositor *compositor = screen->display->compositor;
569   if (meta_prefs_get_send_frame_timings())
570     {
571       g_signal_connect_after (CLUTTER_STAGE (compositor->stage), "presented",
572                               G_CALLBACK (frame_callback), compositor);
573     }
574   else
575     {
576       g_signal_handlers_disconnect_by_func (CLUTTER_STAGE (compositor->stage),
577                                             frame_callback, NULL);
578     }
579 }
580 
581 void
meta_compositor_manage_screen(MetaCompositor * compositor,MetaScreen * screen)582 meta_compositor_manage_screen (MetaCompositor *compositor,
583                                MetaScreen     *screen)
584 {
585   MetaDisplay    *display       = meta_screen_get_display (screen);
586   Display        *xdisplay      = meta_display_get_xdisplay (display);
587   Window          xwin;
588   gint            width, height;
589   XWindowAttributes attr;
590   long            event_mask;
591 
592   redirect_windows (compositor, screen);
593 
594   /*
595    * We use an empty input region for Clutter as a default because that allows
596    * the user to interact with all the windows displayed on the screen.
597    * We have to initialize compositor->pending_input_region to an empty region explicitly,
598    * because None value is used to mean that the whole screen is an input region.
599    */
600   compositor->pending_input_region = XFixesCreateRegion (xdisplay, NULL, 0);
601 
602   compositor->screen = screen;
603   compositor->output = None;
604   compositor->windows = NULL;
605 
606   meta_screen_set_cm_selection (screen);
607 
608   compositor->stage = clutter_stage_new ();
609 
610   meta_compositor_toggle_send_frame_timings(screen);
611 
612   g_signal_connect_after (CLUTTER_STAGE (compositor->stage), "after-paint",
613                           G_CALLBACK (after_stage_paint), compositor);
614 
615   clutter_stage_set_sync_delay (CLUTTER_STAGE (compositor->stage), META_SYNC_DELAY);
616 
617   meta_screen_get_size (screen, &width, &height);
618   clutter_actor_realize (compositor->stage);
619 
620   xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage));
621 
622   XResizeWindow (xdisplay, xwin, width, height);
623 
624   event_mask = FocusChangeMask |
625                ExposureMask |
626                EnterWindowMask | LeaveWindowMask |
627                PointerMotionMask |
628                PropertyChangeMask |
629                ButtonPressMask | ButtonReleaseMask |
630                KeyPressMask | KeyReleaseMask |
631                StructureNotifyMask;
632 
633   if (XGetWindowAttributes (xdisplay, xwin, &attr))
634       {
635         event_mask |= attr.your_event_mask;
636       }
637 
638   XSelectInput (xdisplay, xwin, event_mask);
639 
640   compositor->window_group = meta_window_group_new (screen);
641   compositor->background_actor = meta_background_actor_new_for_screen (screen);
642   compositor->bottom_window_group = clutter_actor_new();
643   compositor->overlay_group = clutter_actor_new ();
644   compositor->top_window_group = meta_window_group_new (screen);
645   compositor->hidden_group = clutter_actor_new ();
646 
647   clutter_actor_add_child (compositor->window_group, compositor->background_actor);
648   clutter_actor_add_child (compositor->stage, compositor->window_group);
649   clutter_actor_add_child (compositor->stage, compositor->top_window_group);
650   clutter_actor_add_child (compositor->stage, compositor->overlay_group);
651   clutter_actor_add_child (compositor->stage, compositor->hidden_group);
652 
653   clutter_actor_hide (compositor->hidden_group);
654 
655   compositor->plugin_mgr = meta_plugin_manager_new (screen);
656 
657   /*
658    * Delay the creation of the overlay window as long as we can, to avoid
659    * blanking out the screen. This means that during the plugin loading, the
660    * overlay window is not accessible; if the plugin needs to access it
661    * directly, it should hook into the "show" signal on stage, and do
662    * its stuff there.
663    */
664   compositor->output = get_output_window (screen);
665   XReparentWindow (xdisplay, xwin, compositor->output, 0, 0);
666 
667  /* Make sure there isn't any left-over output shape on the
668   * overlay window by setting the whole screen to be an
669   * output region.
670   *
671   * Note: there doesn't seem to be any real chance of that
672   *  because the X server will destroy the overlay window
673   *  when the last client using it exits.
674   */
675   XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, None);
676 
677   do_set_stage_input_region (screen, compositor->pending_input_region);
678   if (compositor->pending_input_region != None)
679     {
680       XFixesDestroyRegion (xdisplay, compositor->pending_input_region);
681       compositor->pending_input_region = None;
682     }
683 
684   clutter_actor_show (compositor->overlay_group);
685   clutter_actor_show (compositor->stage);
686 
687   /* Map overlay window before redirecting windows offscreen so we catch their
688    * contents until we show the stage.
689    */
690   XMapWindow (xdisplay, compositor->output);
691 
692   compositor->have_x11_sync_object = meta_sync_ring_init (xdisplay);
693 }
694 
695 void
meta_compositor_unmanage_screen(MetaCompositor * compositor,MetaScreen * screen)696 meta_compositor_unmanage_screen (MetaCompositor *compositor,
697                                  MetaScreen     *screen)
698 {
699   MetaDisplay    *display       = meta_screen_get_display (screen);
700   Display        *xdisplay      = meta_display_get_xdisplay (display);
701   Window          xroot         = meta_screen_get_xroot (screen);
702 
703   /* This is the most important part of cleanup - we have to do this
704    * before giving up the window manager selection or the next
705    * window manager won't be able to redirect subwindows */
706   XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
707 }
708 
709 /*
710  * Shapes the cow so that the given window is exposed,
711  * when metaWindow is NULL it clears the shape again
712  */
713 static void
meta_shape_cow_for_window(MetaScreen * screen,MetaWindow * metaWindow)714 meta_shape_cow_for_window (MetaScreen *screen,
715                            MetaWindow *metaWindow)
716 {
717   MetaDisplay *display = screen->display;
718   MetaCompositor *compositor = display->compositor;
719   Display *xdisplay = display->xdisplay;
720 
721   if (metaWindow == NULL)
722       XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, None);
723   else
724     {
725       XserverRegion output_region;
726       XRectangle screen_rect, window_bounds;
727       int width, height;
728       MetaRectangle rect;
729 
730       meta_window_get_outer_rect (metaWindow, &rect);
731 
732       window_bounds.x = rect.x;
733       window_bounds.y = rect.y;
734       window_bounds.width = rect.width;
735       window_bounds.height = rect.height;
736 
737       meta_screen_get_size (screen, &width, &height);
738       screen_rect.x = 0;
739       screen_rect.y = 0;
740       screen_rect.width = width;
741       screen_rect.height = height;
742 
743       output_region = XFixesCreateRegion (xdisplay, &window_bounds, 1);
744 
745       XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region);
746       XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, output_region);
747       XFixesDestroyRegion (xdisplay, output_region);
748     }
749 }
750 
751 void
meta_compositor_add_window(MetaCompositor * compositor,MetaWindow * window)752 meta_compositor_add_window (MetaCompositor    *compositor,
753                             MetaWindow        *window)
754 {
755   MetaScreen *screen = meta_window_get_screen (window);
756   MetaDisplay *display = meta_screen_get_display (screen);
757 
758   DEBUG_TRACE ("meta_compositor_add_window\n");
759   meta_error_trap_push (display);
760 
761   add_win (window);
762 
763   meta_error_trap_pop (display);
764 }
765 
766 void
meta_compositor_remove_window(MetaCompositor * compositor,MetaWindow * window)767 meta_compositor_remove_window (MetaCompositor *compositor,
768                                MetaWindow     *window)
769 {
770   MetaWindowActor         *window_actor     = NULL;
771   MetaScreen *screen;
772 
773   DEBUG_TRACE ("meta_compositor_remove_window\n");
774   window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
775   if (!window_actor)
776     return;
777 
778   screen = window->screen;
779 
780   if (window_actor == compositor->unredirected_window)
781     {
782       meta_window_actor_set_redirected (window_actor, TRUE);
783       meta_shape_cow_for_window (screen,  NULL);
784       compositor->unredirected_window = NULL;
785     }
786 
787   meta_window_actor_destroy (window_actor);
788 }
789 
790 void
meta_compositor_set_updates_frozen(MetaCompositor * compositor,MetaWindow * window,gboolean updates_frozen)791 meta_compositor_set_updates_frozen (MetaCompositor *compositor,
792                                     MetaWindow     *window,
793                                     gboolean        updates_frozen)
794 {
795   MetaWindowActor *window_actor;
796 
797   DEBUG_TRACE ("meta_compositor_set_updates_frozen\n");
798   window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
799   if (!window_actor)
800     return;
801 
802   meta_window_actor_set_updates_frozen (window_actor, updates_frozen);
803 }
804 
805 void
meta_compositor_queue_frame_drawn(MetaCompositor * compositor,MetaWindow * window,gboolean no_delay_frame)806 meta_compositor_queue_frame_drawn (MetaCompositor *compositor,
807                                    MetaWindow     *window,
808                                    gboolean        no_delay_frame)
809 {
810   MetaWindowActor *window_actor;
811 
812   DEBUG_TRACE ("meta_compositor_queue_frame_drawn\n");
813   window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
814   if (!window_actor)
815     return;
816 
817   meta_window_actor_queue_frame_drawn (window_actor, no_delay_frame);
818 }
819 
820 static gboolean
is_grabbed_event(XEvent * event)821 is_grabbed_event (XEvent *event)
822 {
823   switch (event->xany.type)
824     {
825     case ButtonPress:
826     case ButtonRelease:
827     case EnterNotify:
828     case LeaveNotify:
829     case MotionNotify:
830     case KeyPress:
831     case KeyRelease:
832       return TRUE;
833     }
834 
835   return FALSE;
836 }
837 
838 void
meta_compositor_window_shape_changed(MetaCompositor * compositor,MetaWindow * window)839 meta_compositor_window_shape_changed (MetaCompositor *compositor,
840                                       MetaWindow     *window)
841 {
842   MetaWindowActor *window_actor;
843   window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
844   if (!window_actor)
845     return;
846 
847   meta_window_actor_update_shape (window_actor);
848 }
849 
850 /**
851  * meta_compositor_process_event: (skip)
852  *
853  */
854 gboolean
meta_compositor_process_event(MetaCompositor * compositor,XEvent * event,MetaWindow * window)855 meta_compositor_process_event (MetaCompositor *compositor,
856                                XEvent         *event,
857                                MetaWindow     *window)
858 {
859   if (compositor->modal_plugin && is_grabbed_event (event))
860     {
861       MetaPluginClass *klass = META_PLUGIN_GET_CLASS (compositor->modal_plugin);
862 
863       if (klass->xevent_filter)
864         klass->xevent_filter (compositor->modal_plugin, event);
865 
866       /* We always consume events even if the plugin says it didn't handle them;
867        * exclusive is exclusive */
868       return TRUE;
869     }
870 
871   if (meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event))
872     {
873       DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n");
874       return TRUE;
875     }
876 
877   switch (event->type)
878     {
879     case PropertyNotify:
880       process_property_notify (compositor, (XPropertyEvent *) event, window);
881       break;
882 
883     default:
884       if (event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify)
885         {
886           /* Core code doesn't handle damage events, so we need to extract the MetaWindow
887            * ourselves
888            */
889           if (window == NULL)
890             {
891               Window xwin = ((XDamageNotifyEvent *) event)->drawable;
892               window = meta_display_lookup_x_window (compositor->display, xwin);
893             }
894 
895           DEBUG_TRACE ("meta_compositor_process_event (process_damage)\n");
896 
897           if (window)
898             process_damage (compositor, (XDamageNotifyEvent *) event, window);
899         }
900       break;
901     }
902 
903   if (compositor->have_x11_sync_object)
904     meta_sync_ring_handle_event (event);
905 
906   /* Clutter needs to know about MapNotify events otherwise it will
907      think the stage is invisible */
908   if (event->type == MapNotify)
909     clutter_x11_handle_event (event);
910 
911   /* The above handling is basically just "observing" the events, so we return
912    * FALSE to indicate that the event should not be filtered out; if we have
913    * GTK+ windows in the same process, GTK+ needs the ConfigureNotify event, for example.
914    */
915   return FALSE;
916 }
917 
918 void
meta_compositor_show_window(MetaCompositor * compositor,MetaWindow * window,MetaCompEffect effect)919 meta_compositor_show_window (MetaCompositor *compositor,
920 			     MetaWindow	    *window,
921                              MetaCompEffect  effect)
922 {
923   MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
924   DEBUG_TRACE ("meta_compositor_show_window\n");
925   if (!window_actor)
926     return;
927 
928   meta_window_actor_show (window_actor, effect);
929 }
930 
931 void
meta_compositor_hide_window(MetaCompositor * compositor,MetaWindow * window,MetaCompEffect effect)932 meta_compositor_hide_window (MetaCompositor *compositor,
933                              MetaWindow     *window,
934                              MetaCompEffect  effect)
935 {
936   MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
937   DEBUG_TRACE ("meta_compositor_hide_window\n");
938   if (!window_actor)
939     return;
940 
941   meta_window_actor_hide (window_actor, effect);
942 }
943 
944 void
meta_compositor_maximize_window(MetaCompositor * compositor,MetaWindow * window,MetaRectangle * old_rect,MetaRectangle * new_rect)945 meta_compositor_maximize_window (MetaCompositor    *compositor,
946                                  MetaWindow        *window,
947 				 MetaRectangle	   *old_rect,
948 				 MetaRectangle	   *new_rect)
949 {
950   MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
951   DEBUG_TRACE ("meta_compositor_maximize_window\n");
952   if (!window_actor)
953     return;
954 
955   meta_window_actor_maximize (window_actor, old_rect, new_rect);
956 }
957 
958 void
meta_compositor_unmaximize_window(MetaCompositor * compositor,MetaWindow * window,MetaRectangle * old_rect,MetaRectangle * new_rect)959 meta_compositor_unmaximize_window (MetaCompositor    *compositor,
960                                    MetaWindow        *window,
961 				   MetaRectangle     *old_rect,
962 				   MetaRectangle     *new_rect)
963 {
964   MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
965   DEBUG_TRACE ("meta_compositor_unmaximize_window\n");
966   if (!window_actor)
967     return;
968 
969   meta_window_actor_unmaximize (window_actor, old_rect, new_rect);
970 }
971 
972 void
meta_compositor_switch_workspace(MetaCompositor * compositor,MetaScreen * screen,MetaWorkspace * from,MetaWorkspace * to,MetaMotionDirection direction)973 meta_compositor_switch_workspace (MetaCompositor     *compositor,
974                                   MetaScreen         *screen,
975                                   MetaWorkspace      *from,
976                                   MetaWorkspace      *to,
977                                   MetaMotionDirection direction)
978 {
979   gint to_indx, from_indx;
980   to_indx   = meta_workspace_index (to);
981   from_indx = meta_workspace_index (from);
982 
983   DEBUG_TRACE ("meta_compositor_switch_workspace\n");
984 
985   compositor->switch_workspace_in_progress++;
986 
987   if (!compositor->plugin_mgr ||
988       !meta_plugin_manager_switch_workspace (compositor->plugin_mgr,
989                                              from_indx,
990                                              to_indx,
991                                              direction))
992     {
993       compositor->switch_workspace_in_progress--;
994 
995       /* We have to explicitely call this to fix up stacking order of the
996        * actors; this is because the abs stacking position of actors does not
997        * necessarily change during the window hiding/unhiding, only their
998        * relative position toward the destkop window.
999        */
1000       meta_finish_workspace_switch (compositor);
1001     }
1002 }
1003 
1004 void
meta_compositor_tile_window(MetaCompositor * compositor,MetaWindow * window,MetaRectangle * old_rect,MetaRectangle * new_rect)1005 meta_compositor_tile_window (MetaCompositor    *compositor,
1006                                  MetaWindow        *window,
1007                                MetaRectangle     *old_rect,
1008                                MetaRectangle     *new_rect)
1009 {
1010   MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
1011   DEBUG_TRACE ("meta_compositor_tile_window\n");
1012   if (!window_actor)
1013     return;
1014 
1015   meta_window_actor_tile (window_actor, old_rect, new_rect);
1016 }
1017 
1018 static void
sync_actor_stacking(MetaCompositor * compositor)1019 sync_actor_stacking (MetaCompositor *compositor)
1020 {
1021   GList *children;
1022   GList *tmp;
1023   GList *old;
1024   gboolean reordered;
1025 
1026   /* NB: The first entries in the lists are stacked the lowest */
1027 
1028   /* Restacking will trigger full screen redraws, so it's worth a
1029    * little effort to make sure we actually need to restack before
1030    * we go ahead and do it */
1031 
1032   children = clutter_actor_get_children (compositor->window_group);
1033   reordered = FALSE;
1034 
1035   old = children;
1036 
1037   /* We allow for actors in the window group other than the actors we
1038    * know about, but it's up to a plugin to try and keep them stacked correctly
1039    * (we really need extra API to make that reliable.)
1040    */
1041 
1042   /* Of the actors we know, the bottom actor should be the background actor */
1043 
1044   while (old && old->data != compositor->background_actor && !META_IS_WINDOW_ACTOR (old->data))
1045     old = old->next;
1046   if (old == NULL || old->data != compositor->background_actor)
1047     {
1048       reordered = TRUE;
1049       goto done_with_check;
1050     }
1051 
1052   /* Then the window actors should follow in sequence */
1053 
1054   old = old->next;
1055   for (tmp = compositor->windows; tmp != NULL; tmp = tmp->next)
1056     {
1057       while (old && !META_IS_WINDOW_ACTOR (old->data))
1058         old = old->next;
1059 
1060       /* old == NULL: someone reparented a window out of the window group,
1061        * order undefined, always restack */
1062       if (old == NULL || old->data != tmp->data)
1063         {
1064           reordered = TRUE;
1065           goto done_with_check;
1066         }
1067 
1068       old = old->next;
1069     }
1070 
1071  done_with_check:
1072 
1073   g_list_free (children);
1074 
1075   if (!reordered)
1076     return;
1077 
1078   ClutterActor *parent;
1079 
1080   for (tmp = g_list_last (compositor->windows); tmp != NULL; tmp = tmp->prev)
1081     {
1082       ClutterActor *actor = tmp->data;
1083 
1084       parent = clutter_actor_get_parent (actor);
1085       clutter_actor_set_child_below_sibling (parent, actor, NULL);
1086     }
1087 
1088   parent = clutter_actor_get_parent (compositor->background_actor);
1089   clutter_actor_set_child_below_sibling (parent, compositor->background_actor, NULL);
1090 }
1091 
1092 void
meta_compositor_sync_stack(MetaCompositor * compositor,MetaScreen * screen,GList * stack)1093 meta_compositor_sync_stack (MetaCompositor  *compositor,
1094                             MetaScreen	    *screen,
1095                             GList	          *stack)
1096 {
1097   GList *old_stack;
1098 
1099   DEBUG_TRACE ("meta_compositor_sync_stack\n");
1100 
1101   /* This is painful because hidden windows that we are in the process
1102    * of animating out of existence. They'll be at the bottom of the
1103    * stack of X windows, but we want to leave them in their old position
1104    * until the animation effect finishes.
1105    */
1106 
1107   /* Sources: first window is the highest */
1108   stack = g_list_copy (stack); /* The new stack of MetaWindow */
1109   old_stack = g_list_reverse (compositor->windows); /* The old stack of MetaWindowActor */
1110   compositor->windows = NULL;
1111 
1112   while (TRUE)
1113     {
1114       MetaWindowActor *old_actor = NULL, *stack_actor = NULL, *actor;
1115       MetaWindow *old_window = NULL, *stack_window = NULL, *window;
1116 
1117       /* Find the remaining top actor in our existing stack (ignoring
1118        * windows that have been hidden and are no longer animating) */
1119       while (old_stack)
1120         {
1121           old_actor = old_stack->data;
1122           old_window = meta_window_actor_get_meta_window (old_actor);
1123 
1124           if ((old_window->hidden || old_window->unmanaging) &&
1125               !meta_window_actor_effect_in_progress (old_actor))
1126             {
1127               old_stack = g_list_delete_link (old_stack, old_stack);
1128               old_actor = NULL;
1129             }
1130           else
1131             break;
1132         }
1133 
1134       /* And the remaining top actor in the new stack */
1135       while (stack)
1136         {
1137           stack_window = stack->data;
1138           stack_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (stack_window));
1139           if (!stack_actor)
1140             {
1141               meta_verbose ("Failed to find corresponding MetaWindowActor "
1142                             "for window %s\n", meta_window_get_description (stack_window));
1143               stack = g_list_delete_link (stack, stack);
1144             }
1145           else
1146             break;
1147         }
1148 
1149       if (!old_actor && !stack_actor) /* Nothing more to stack */
1150         break;
1151 
1152       /* We usually prefer the window in the new stack, but if if we
1153        * found a hidden window in the process of being animated out
1154        * of existence in the old stack we use that instead. We've
1155        * filtered out non-animating hidden windows above.
1156        */
1157       if (old_actor &&
1158           (!stack_actor || old_window->hidden || old_window->unmanaging))
1159         {
1160           actor = old_actor;
1161           window = old_window;
1162         }
1163       else
1164         {
1165           actor = stack_actor;
1166           window = stack_window;
1167         }
1168 
1169       /* OK, we know what actor we want next. Add it to our window
1170        * list, and remove it from both source lists. (It will
1171        * be at the front of at least one, hopefully it will be
1172        * near the front of the other.)
1173        */
1174       compositor->windows = g_list_prepend (compositor->windows, actor);
1175 
1176       stack = g_list_remove (stack, window);
1177       old_stack = g_list_remove (old_stack, actor);
1178     }
1179 
1180   sync_actor_stacking (compositor);
1181 }
1182 
1183 void
meta_compositor_sync_window_geometry(MetaCompositor * compositor,MetaWindow * window,gboolean did_placement)1184 meta_compositor_sync_window_geometry (MetaCompositor *compositor,
1185 				                              MetaWindow *window,
1186                                       gboolean did_placement)
1187 {
1188   MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
1189 
1190   DEBUG_TRACE ("meta_compositor_sync_window_geometry\n");
1191 
1192   if (!window_actor)
1193     return;
1194 
1195   meta_window_actor_sync_actor_geometry (window_actor, did_placement);
1196 }
1197 
1198 void
meta_compositor_sync_screen_size(MetaCompositor * compositor,MetaScreen * screen,guint width,guint height)1199 meta_compositor_sync_screen_size (MetaCompositor *compositor,
1200                                   MetaScreen	   *screen,
1201                                   guint		        width,
1202                                   guint		        height)
1203 {
1204   MetaDisplay *display = compositor->display;
1205   Display *xdisplay;
1206   Window xwin;
1207 
1208   DEBUG_TRACE ("meta_compositor_sync_screen_size\n");
1209 
1210   xdisplay = meta_display_get_xdisplay (display);
1211   xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage));
1212 
1213   XResizeWindow (xdisplay, xwin, width, height);
1214 
1215   meta_background_actor_screen_size_changed (screen);
1216 
1217   meta_verbose ("Changed size for stage on screen %d to %dx%d\n",
1218 		meta_screen_get_screen_number (screen),
1219 		width, height);
1220 }
1221 
1222 static void
frame_callback(ClutterStage * stage,CoglFrameEvent event,ClutterFrameInfo * frame_info,MetaCompositor * compositor)1223 frame_callback (ClutterStage     *stage,
1224                 CoglFrameEvent    event,
1225                 ClutterFrameInfo *frame_info,
1226                 MetaCompositor   *compositor)
1227 {
1228   GList *l;
1229 
1230   if (event == COGL_FRAME_EVENT_COMPLETE)
1231     {
1232       gint64 presentation_time_cogl = frame_info->presentation_time;
1233       gint64 presentation_time;
1234 
1235       if (presentation_time_cogl != 0)
1236         {
1237           /* Cogl reports presentation in terms of its own clock, which is
1238            * guaranteed to be in nanoseconds but with no specified base. The
1239            * normal case with the open source GPU drivers on Linux 3.8 and
1240            * newer is that the base of cogl_get_clock_time() is that of
1241            * clock_gettime(CLOCK_MONOTONIC), so the same as g_get_monotonic_time),
1242            * but there's no exposure of that through the API. clock_gettime()
1243            * is fairly fast, so calling it twice and subtracting to get a
1244            * nearly-zero number is acceptable, if a litle ugly.
1245            */
1246           gint64 current_cogl_time = cogl_get_clock_time (compositor->context);
1247           gint64 current_monotonic_time = g_get_monotonic_time ();
1248 
1249           presentation_time =
1250             current_monotonic_time + (presentation_time_cogl - current_cogl_time) / 1000;
1251         }
1252       else
1253         {
1254           presentation_time = 0;
1255         }
1256 
1257       for (l = compositor->windows; l; l = l->next)
1258         meta_window_actor_frame_complete (l->data, frame_info, presentation_time);
1259     }
1260 }
1261 
1262 static gboolean
meta_pre_paint_func(gpointer data)1263 meta_pre_paint_func (gpointer data)
1264 {
1265   GList *l;
1266   MetaCompositor *compositor = data;
1267   GSList *screens = compositor->display->screens;
1268   MetaWindowActor *top_window;
1269   MetaWindowActor *expected_unredirected_window = NULL;
1270 
1271   if (compositor->windows == NULL)
1272     return TRUE;
1273 
1274   top_window = g_list_last (compositor->windows)->data;
1275 
1276   if (meta_window_actor_should_unredirect (top_window) &&
1277       compositor->disable_unredirect_count == 0)
1278     expected_unredirected_window = top_window;
1279 
1280   if (compositor->unredirected_window != expected_unredirected_window)
1281     {
1282       if (compositor->unredirected_window != NULL)
1283         {
1284           meta_window_actor_set_redirected (compositor->unredirected_window, TRUE);
1285           meta_shape_cow_for_window (compositor->display->active_screen, NULL);
1286         }
1287 
1288       if (expected_unredirected_window != NULL)
1289         {
1290           meta_shape_cow_for_window (compositor->display->active_screen,
1291                                      meta_window_actor_get_meta_window (top_window));
1292           meta_window_actor_set_redirected (top_window, FALSE);
1293         }
1294 
1295       compositor->unredirected_window = expected_unredirected_window;
1296     }
1297 
1298   for (l = compositor->windows; l; l = l->next)
1299     meta_window_actor_pre_paint (l->data);
1300 
1301   if (compositor->frame_has_updated_xsurfaces)
1302     {
1303       /* We need to make sure that any X drawing that happens before
1304        * the XDamageSubtract() for each window above is visible to
1305        * subsequent GL rendering; the standardized way to do this is
1306        * GL_EXT_X11_sync_object. Since this isn't implemented yet in
1307        * mesa, we also have a path that relies on the implementation
1308        * of the open source drivers.
1309        *
1310        * Anything else, we just hope for the best.
1311        *
1312        * Xorg and open source driver specifics:
1313        *
1314        * The X server makes sure to flush drawing to the kernel before
1315        * sending out damage events, but since we use
1316        * DamageReportBoundingBox there may be drawing between the last
1317        * damage event and the XDamageSubtract() that needs to be
1318        * flushed as well.
1319        *
1320        * Xorg always makes sure that drawing is flushed to the kernel
1321        * before writing events or responses to the client, so any
1322        * round trip request at this point is sufficient to flush the
1323        * GLX buffers.
1324        */
1325       if (compositor->have_x11_sync_object)
1326         compositor->have_x11_sync_object = meta_sync_ring_insert_wait ();
1327       else
1328         XSync (compositor->display->xdisplay, False);
1329     }
1330 
1331   return TRUE;
1332 }
1333 
1334 static gboolean
meta_post_paint_func(gpointer data)1335 meta_post_paint_func (gpointer data)
1336 {
1337   MetaCompositor *compositor = data;
1338   CoglGraphicsResetStatus status;
1339 
1340   if (compositor->frame_has_updated_xsurfaces)
1341     {
1342       if (compositor->have_x11_sync_object)
1343         compositor->have_x11_sync_object = meta_sync_ring_after_frame ();
1344 
1345       compositor->frame_has_updated_xsurfaces = FALSE;
1346     }
1347 
1348   status = cogl_get_graphics_reset_status (compositor->context);
1349   switch (status)
1350     {
1351     case COGL_GRAPHICS_RESET_STATUS_NO_ERROR:
1352       break;
1353 
1354     case COGL_GRAPHICS_RESET_STATUS_PURGED_CONTEXT_RESET:
1355       g_signal_emit_by_name (compositor->display, "gl-video-memory-purged");
1356       clutter_actor_queue_redraw (CLUTTER_ACTOR (compositor->stage));
1357       break;
1358 
1359     default:
1360       /* The ARB_robustness spec says that, on error, the application
1361          should destroy the old context and create a new one. Since we
1362          don't have the necessary plumbing to do this we'll simply
1363          restart the process. Obviously we can't do this when we are
1364          a wayland compositor but in that case we shouldn't get here
1365          since we don't enable robustness in that case. */
1366       meta_restart ();
1367       break;
1368     }
1369 
1370   return TRUE;
1371 }
1372 
1373 void
meta_compositor_on_shadow_factory_changed(void)1374 meta_compositor_on_shadow_factory_changed (void)
1375 {
1376   GList *l;
1377 
1378   for (l = compositor_global->windows; l; l = l->next)
1379     meta_window_actor_invalidate_shadow (l->data);
1380 }
1381 
1382 /**
1383  * meta_compositor_new: (skip)
1384  *
1385  */
1386 MetaCompositor *
meta_compositor_new(MetaDisplay * display)1387 meta_compositor_new (MetaDisplay *display)
1388 {
1389   char *atom_names[] = {
1390     "_XROOTPMAP_ID",
1391     "_XSETROOT_ID",
1392     "_NET_WM_WINDOW_OPACITY",
1393   };
1394   Atom                   atoms[G_N_ELEMENTS(atom_names)];
1395   MetaCompositor        *compositor;
1396   Display               *xdisplay = meta_display_get_xdisplay (display);
1397 
1398   if (!composite_at_least_version (display, 0, 3))
1399     return NULL;
1400 
1401   compositor = g_new0 (MetaCompositor, 1);
1402 
1403   compositor->display = display;
1404   compositor->context = clutter_backend_get_cogl_context (clutter_get_default_backend ());
1405 
1406   if (g_getenv("META_DISABLE_MIPMAPS"))
1407     compositor->no_mipmaps = TRUE;
1408 
1409   meta_verbose ("Creating %d atoms\n", (int) G_N_ELEMENTS (atom_names));
1410   XInternAtoms (xdisplay, atom_names, G_N_ELEMENTS (atom_names),
1411                 False, atoms);
1412 
1413   compositor->atom_x_root_pixmap = atoms[0];
1414   compositor->atom_x_set_root = atoms[1];
1415   compositor->atom_net_wm_window_opacity = atoms[2];
1416 
1417   compositor->pre_paint_func_id =
1418     clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_PRE_PAINT,
1419                                            meta_pre_paint_func,
1420                                            compositor,
1421                                            NULL);
1422   compositor->post_paint_func_id =
1423     clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
1424                                            meta_post_paint_func,
1425                                            compositor,
1426                                            NULL);
1427 
1428   compositor_global = compositor;
1429 
1430   return compositor;
1431 }
1432 
1433 /**
1434  * meta_get_overlay_window: (skip)
1435  *
1436  */
1437 Window
meta_get_overlay_window(MetaScreen * screen)1438 meta_get_overlay_window (MetaScreen *screen)
1439 {
1440   return screen->display->compositor->output;
1441 }
1442 
1443 /**
1444  * meta_disable_unredirect_for_screen:
1445  * @screen: a #MetaScreen
1446  *
1447  * Disables unredirection, can be usefull in situations where having
1448  * unredirected windows is undesireable like when recording a video.
1449  *
1450  */
1451 void
meta_disable_unredirect_for_screen(MetaScreen * screen)1452 meta_disable_unredirect_for_screen (MetaScreen *screen)
1453 {
1454   MetaCompositor *compositor = screen->display->compositor;
1455 
1456   compositor->disable_unredirect_count = compositor->disable_unredirect_count + 1;
1457 }
1458 
1459 /**
1460  * meta_enable_unredirect_for_screen:
1461  * @screen: a #MetaScreen
1462  *
1463  * Enables unredirection which reduces the overhead for apps like games.
1464  *
1465  */
1466 void
meta_enable_unredirect_for_screen(MetaScreen * screen)1467 meta_enable_unredirect_for_screen (MetaScreen *screen)
1468 {
1469   MetaCompositor *compositor = screen->display->compositor;
1470   if (compositor->disable_unredirect_count == 0)
1471     g_warning ("Called enable_unredirect_for_screen while unredirection is enabled.");
1472   if (compositor->disable_unredirect_count > 0)
1473    compositor->disable_unredirect_count = compositor->disable_unredirect_count - 1;
1474 }
1475 
1476 #define FLASH_TIME_MS 50
1477 
1478 static void
flash_out_completed(ClutterTimeline * timeline,gboolean is_finished,gpointer user_data)1479 flash_out_completed (ClutterTimeline *timeline,
1480                      gboolean         is_finished,
1481                      gpointer         user_data)
1482 {
1483   ClutterActor *flash = CLUTTER_ACTOR (user_data);
1484   clutter_actor_destroy (flash);
1485 }
1486 
1487 void
meta_compositor_flash_screen(MetaCompositor * compositor,MetaScreen * screen)1488 meta_compositor_flash_screen (MetaCompositor *compositor,
1489                               MetaScreen     *screen)
1490 {
1491   ClutterActor *stage;
1492   ClutterActor *flash;
1493   ClutterTransition *transition;
1494   gfloat width, height;
1495 
1496   stage = meta_get_stage_for_screen (screen);
1497   clutter_actor_get_size (stage, &width, &height);
1498 
1499   flash = clutter_actor_new ();
1500   clutter_actor_set_background_color (flash, CLUTTER_COLOR_Black);
1501   clutter_actor_set_size (flash, width, height);
1502   clutter_actor_set_opacity (flash, 0);
1503   clutter_actor_add_child (stage, flash);
1504 
1505   clutter_actor_save_easing_state (flash);
1506   clutter_actor_set_easing_mode (flash, CLUTTER_EASE_IN_QUAD);
1507   clutter_actor_set_easing_duration (flash, FLASH_TIME_MS);
1508   clutter_actor_set_opacity (flash, 192);
1509 
1510   transition = clutter_actor_get_transition (flash, "opacity");
1511   clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
1512   clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
1513 
1514   g_signal_connect (transition, "stopped",
1515                     G_CALLBACK (flash_out_completed), flash);
1516 
1517   clutter_actor_restore_easing_state (flash);
1518 }
1519 
1520 void
meta_compositor_show_tile_preview(MetaCompositor * compositor,MetaScreen * screen,MetaWindow * window,MetaRectangle * tile_rect,int tile_monitor_number,guint snap_queued)1521 meta_compositor_show_tile_preview (MetaCompositor *compositor,
1522                                    MetaScreen     *screen,
1523                                    MetaWindow     *window,
1524                                    MetaRectangle  *tile_rect,
1525                                    int            tile_monitor_number,
1526                                    guint          snap_queued)
1527 {
1528   meta_plugin_manager_show_tile_preview (compositor->plugin_mgr,
1529                                           window, tile_rect, tile_monitor_number,
1530                                           snap_queued);
1531 }
1532 
1533 void
meta_compositor_hide_tile_preview(MetaCompositor * compositor,MetaScreen * screen)1534 meta_compositor_hide_tile_preview (MetaCompositor *compositor,
1535                                    MetaScreen     *screen)
1536 {
1537   meta_plugin_manager_hide_tile_preview (compositor->plugin_mgr);
1538 }
1539 
1540 void
meta_compositor_show_hud_preview(MetaCompositor * compositor,MetaScreen * screen,guint current_proximity_zone,MetaRectangle * work_area,guint snap_queued)1541 meta_compositor_show_hud_preview (MetaCompositor *compositor,
1542                                   MetaScreen     *screen,
1543                                   guint          current_proximity_zone,
1544                                   MetaRectangle  *work_area,
1545                                   guint          snap_queued)
1546 {
1547   meta_plugin_manager_show_hud_preview (compositor->plugin_mgr,
1548                                         current_proximity_zone,
1549                                         work_area,
1550                                         snap_queued);
1551 }
1552 
1553 void
meta_compositor_hide_hud_preview(MetaCompositor * compositor,MetaScreen * screen)1554 meta_compositor_hide_hud_preview (MetaCompositor *compositor,
1555                                   MetaScreen     *screen)
1556 {
1557   meta_plugin_manager_hide_hud_preview (compositor->plugin_mgr);
1558 }
1559 
1560 /**
1561  * meta_compositor_monotonic_time_to_server_time:
1562  * @display: a #MetaDisplay
1563  * @monotonic_time: time in the units of g_get_monotonic_time()
1564  *
1565  * _NET_WM_FRAME_DRAWN and _NET_WM_FRAME_TIMINGS messages represent time
1566  * as a "high resolution server time" - this is the server time interpolated
1567  * to microsecond resolution. The advantage of this time representation
1568  * is that if  X server is running on the same computer as a client, and
1569  * the Xserver uses 'clock_gettime(CLOCK_MONOTONIC, ...)' for the server
1570  * time, the client can detect this, and all such clients will share a
1571  * a time representation with high accuracy. If there is not a common
1572  * time source, then the time synchronization will be less accurate.
1573  */
1574 gint64
meta_compositor_monotonic_time_to_server_time(MetaDisplay * display,gint64 monotonic_time)1575 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
1576                                                gint64       monotonic_time)
1577 {
1578   MetaCompositor *compositor = display->compositor;
1579 
1580   if (compositor->server_time_query_time == 0 ||
1581       (!compositor->server_time_is_monotonic_time &&
1582        monotonic_time > compositor->server_time_query_time + 10*1000*1000)) /* 10 seconds */
1583     {
1584       guint32 server_time = meta_display_get_current_time_roundtrip (display);
1585       gint64 server_time_usec = (gint64)server_time * 1000;
1586       gint64 current_monotonic_time = g_get_monotonic_time ();
1587       compositor->server_time_query_time = current_monotonic_time;
1588 
1589       /* If the server time is within a second of the monotonic time,
1590        * we assume that they are identical. This seems like a big margin,
1591        * but we want to be as robust as possible even if the system
1592        * is under load and our processing of the server response is
1593        * delayed.
1594        */
1595       if (server_time_usec > current_monotonic_time - 1000*1000 &&
1596           server_time_usec < current_monotonic_time + 1000*1000)
1597         compositor->server_time_is_monotonic_time = TRUE;
1598 
1599       compositor->server_time_offset = server_time_usec - current_monotonic_time;
1600     }
1601 
1602   if (compositor->server_time_is_monotonic_time)
1603     return monotonic_time;
1604   else
1605     return monotonic_time + compositor->server_time_offset;
1606 }
1607 
1608 void
meta_compositor_grab_op_begin(MetaCompositor * compositor)1609 meta_compositor_grab_op_begin (MetaCompositor *compositor)
1610 {
1611   // CLUTTER_ACTOR_NO_LAYOUT set on the window group improves responsiveness of windows,
1612   // but causes windows to flicker in and out of view sporadically on some configurations
1613   // while dragging windows. Make sure it is disabled during the grab.
1614   clutter_actor_unset_flags (compositor->window_group, CLUTTER_ACTOR_NO_LAYOUT);
1615 }
1616 
1617 void
meta_compositor_grab_op_end(MetaCompositor * compositor)1618 meta_compositor_grab_op_end (MetaCompositor *compositor)
1619 {
1620   clutter_actor_set_flags (compositor->window_group, CLUTTER_ACTOR_NO_LAYOUT);
1621 }
1622 
1623 CoglContext *
meta_compositor_get_cogl_context(void)1624 meta_compositor_get_cogl_context (void)
1625 {
1626   return compositor_global->context;
1627 }
1628 
1629 void
meta_compositor_update_sync_state(MetaCompositor * compositor,MetaSyncMethod method)1630 meta_compositor_update_sync_state (MetaCompositor *compositor,
1631                                    MetaSyncMethod  method)
1632 {
1633   clutter_stage_x11_update_sync_state (compositor->stage, method);
1634 }
1635