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