summaryrefslogtreecommitdiff
path: root/x11-wm
diff options
context:
space:
mode:
Diffstat (limited to 'x11-wm')
-rw-r--r--x11-wm/mutter/files/mutter-3.16.3-GL_EXT_x11_sync_object.patch840
-rw-r--r--x11-wm/mutter/files/mutter-3.16.3-crash-border.patch32
-rw-r--r--x11-wm/mutter/files/mutter-3.16.3-fallback-keymap.patch28
-rw-r--r--x11-wm/mutter/files/mutter-3.16.3-fix-race.patch114
-rw-r--r--x11-wm/mutter/files/mutter-3.16.3-fix-return.patch32
-rw-r--r--x11-wm/mutter/files/mutter-3.16.3-flickering.patch114
-rw-r--r--x11-wm/mutter/mutter-3.16.3-r1.ebuild114
7 files changed, 1274 insertions, 0 deletions
diff --git a/x11-wm/mutter/files/mutter-3.16.3-GL_EXT_x11_sync_object.patch b/x11-wm/mutter/files/mutter-3.16.3-GL_EXT_x11_sync_object.patch
new file mode 100644
index 000000000000..401c1752bd8b
--- /dev/null
+++ b/x11-wm/mutter/files/mutter-3.16.3-GL_EXT_x11_sync_object.patch
@@ -0,0 +1,840 @@
+From 9cc80497a262edafc58062fd860ef7a9dcab688c Mon Sep 17 00:00:00 2001
+From: Rui Matos <tiagomatos@gmail.com>
+Date: Fri, 18 Apr 2014 20:21:20 +0200
+Subject: compositor: Add support for GL_EXT_x11_sync_object
+
+If GL advertises this extension we'll use it to synchronize X with GL
+rendering instead of relying on the XSync() behavior with open source
+drivers.
+
+Some driver bugs were uncovered while working on this so if we have
+had to reboot the ring a few times, something is probably wrong and
+we're likely to just make things worse by continuing to try. Let's
+err on the side of caution, disable ourselves and fallback to the
+XSync() path in the compositor.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=728464
+
+diff --git a/configure.ac b/configure.ac
+index 01d75cb..6eea6b2 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -332,6 +332,11 @@ fi
+
+ GTK_DOC_CHECK([1.15], [--flavour no-tmpl])
+
++AC_CHECK_DECL([GL_EXT_x11_sync_object],
++ [],
++ [AC_MSG_ERROR([GL_EXT_x11_sync_object definition not found, please update your GL headers])],
++ [#include <GL/glx.h>])
++
+ #### Warnings (last since -Werror can disturb other tests)
+
+ # Stay command-line compatible with the gnome-common configure option. Here
+diff --git a/src/Makefile.am b/src/Makefile.am
+index baadb41..a4e07a9 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -139,6 +139,8 @@ libmutter_la_SOURCES = \
+ compositor/meta-surface-actor.h \
+ compositor/meta-surface-actor-x11.c \
+ compositor/meta-surface-actor-x11.h \
++ compositor/meta-sync-ring.c \
++ compositor/meta-sync-ring.h \
+ compositor/meta-texture-rectangle.c \
+ compositor/meta-texture-rectangle.h \
+ compositor/meta-texture-tower.c \
+diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
+index 3ff8431..ac38ffc 100644
+--- a/src/backends/x11/meta-backend-x11.c
++++ b/src/backends/x11/meta-backend-x11.c
+@@ -45,6 +45,7 @@
+ #include <meta/util.h>
+ #include "display-private.h"
+ #include "compositor/compositor-private.h"
++#include "compositor/meta-sync-ring.h"
+
+ struct _MetaBackendX11Private
+ {
+@@ -255,6 +256,8 @@ handle_host_xevent (MetaBackend *backend,
+ MetaCompositor *compositor = display->compositor;
+ if (meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event))
+ bypass_clutter = TRUE;
++ if (compositor->have_x11_sync_object)
++ meta_sync_ring_handle_event (event);
+ }
+ }
+
+diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h
+index 80fb4e2..9e3e73d 100644
+--- a/src/compositor/compositor-private.h
++++ b/src/compositor/compositor-private.h
+@@ -15,7 +15,8 @@ struct _MetaCompositor
+ {
+ MetaDisplay *display;
+
+- guint repaint_func_id;
++ guint pre_paint_func_id;
++ guint post_paint_func_id;
+
+ gint64 server_time_query_time;
+ gint64 server_time_offset;
+@@ -40,6 +41,7 @@ struct _MetaCompositor
+ MetaPluginManager *plugin_mgr;
+
+ gboolean frame_has_updated_xsurfaces;
++ gboolean have_x11_sync_object;
+ };
+
+ /* Wait 2ms after vblank before starting to draw next frame */
+diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
+index 250d489..554faa1 100644
+--- a/src/compositor/compositor.c
++++ b/src/compositor/compositor.c
+@@ -79,6 +79,7 @@
+ #include "frame.h"
+ #include <X11/extensions/shape.h>
+ #include <X11/extensions/Xcomposite.h>
++#include "meta-sync-ring.h"
+
+ #include "backends/x11/meta-backend-x11.h"
+
+@@ -125,7 +126,11 @@ meta_switch_workspace_completed (MetaCompositor *compositor)
+ void
+ meta_compositor_destroy (MetaCompositor *compositor)
+ {
+- clutter_threads_remove_repaint_func (compositor->repaint_func_id);
++ clutter_threads_remove_repaint_func (compositor->pre_paint_func_id);
++ clutter_threads_remove_repaint_func (compositor->post_paint_func_id);
++
++ if (compositor->have_x11_sync_object)
++ meta_sync_ring_destroy ();
+ }
+
+ static void
+@@ -468,13 +473,11 @@ meta_compositor_manage (MetaCompositor *compositor)
+ MetaDisplay *display = compositor->display;
+ Display *xdisplay = display->xdisplay;
+ MetaScreen *screen = display->screen;
++ MetaBackend *backend = meta_get_backend ();
+
+ meta_screen_set_cm_selection (display->screen);
+
+- {
+- MetaBackend *backend = meta_get_backend ();
+- compositor->stage = meta_backend_get_stage (backend);
+- }
++ compositor->stage = meta_backend_get_stage (backend);
+
+ /* We use connect_after() here to accomodate code in GNOME Shell that,
+ * when benchmarking drawing performance, connects to ::after-paint
+@@ -510,7 +513,7 @@ meta_compositor_manage (MetaCompositor *compositor)
+
+ compositor->output = screen->composite_overlay_window;
+
+- xwin = meta_backend_x11_get_xwindow (META_BACKEND_X11 (meta_get_backend ()));
++ xwin = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend));
+
+ XReparentWindow (xdisplay, xwin, compositor->output, 0, 0);
+
+@@ -530,6 +533,9 @@ meta_compositor_manage (MetaCompositor *compositor)
+ * contents until we show the stage.
+ */
+ XMapWindow (xdisplay, compositor->output);
++
++ compositor->have_x11_sync_object =
++ meta_sync_ring_init (meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)));
+ }
+
+ redirect_windows (display->screen);
+@@ -1044,11 +1050,12 @@ frame_callback (CoglOnscreen *onscreen,
+ }
+ }
+
+-static void
+-pre_paint_windows (MetaCompositor *compositor)
++static gboolean
++meta_pre_paint_func (gpointer data)
+ {
+ GList *l;
+ MetaWindowActor *top_window;
++ MetaCompositor *compositor = data;
+
+ if (compositor->onscreen == NULL)
+ {
+@@ -1060,7 +1067,7 @@ pre_paint_windows (MetaCompositor *compositor)
+ }
+
+ if (compositor->windows == NULL)
+- return;
++ return TRUE;
+
+ top_window = g_list_last (compositor->windows)->data;
+
+@@ -1077,10 +1084,12 @@ pre_paint_windows (MetaCompositor *compositor)
+ {
+ /* We need to make sure that any X drawing that happens before
+ * the XDamageSubtract() for each window above is visible to
+- * subsequent GL rendering; the only standardized way to do this
+- * is EXT_x11_sync_object, which isn't yet widely available. For
+- * now, we count on details of Xorg and the open source drivers,
+- * and hope for the best otherwise.
++ * subsequent GL rendering; the standardized way to do this is
++ * GL_EXT_X11_sync_object. Since this isn't implemented yet in
++ * mesa, we also have a path that relies on the implementation
++ * of the open source drivers.
++ *
++ * Anything else, we just hope for the best.
+ *
+ * Xorg and open source driver specifics:
+ *
+@@ -1095,17 +1104,28 @@ pre_paint_windows (MetaCompositor *compositor)
+ * round trip request at this point is sufficient to flush the
+ * GLX buffers.
+ */
+- XSync (compositor->display->xdisplay, False);
+-
+- compositor->frame_has_updated_xsurfaces = FALSE;
++ if (compositor->have_x11_sync_object)
++ compositor->have_x11_sync_object = meta_sync_ring_insert_wait ();
++ else
++ XSync (compositor->display->xdisplay, False);
+ }
++
++ return TRUE;
+ }
+
+ static gboolean
+-meta_repaint_func (gpointer data)
++meta_post_paint_func (gpointer data)
+ {
+ MetaCompositor *compositor = data;
+- pre_paint_windows (compositor);
++
++ if (compositor->frame_has_updated_xsurfaces)
++ {
++ if (compositor->have_x11_sync_object)
++ compositor->have_x11_sync_object = meta_sync_ring_after_frame ();
++
++ compositor->frame_has_updated_xsurfaces = FALSE;
++ }
++
+ return TRUE;
+ }
+
+@@ -1140,10 +1160,16 @@ meta_compositor_new (MetaDisplay *display)
+ G_CALLBACK (on_shadow_factory_changed),
+ compositor);
+
+- compositor->repaint_func_id = clutter_threads_add_repaint_func (meta_repaint_func,
+- compositor,
+- NULL);
+-
++ compositor->pre_paint_func_id =
++ clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_PRE_PAINT,
++ meta_pre_paint_func,
++ compositor,
++ NULL);
++ compositor->post_paint_func_id =
++ clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
++ meta_post_paint_func,
++ compositor,
++ NULL);
+ return compositor;
+ }
+
+diff --git a/src/compositor/meta-sync-ring.c b/src/compositor/meta-sync-ring.c
+new file mode 100644
+index 0000000..4ee61f8
+--- /dev/null
++++ b/src/compositor/meta-sync-ring.c
+@@ -0,0 +1,566 @@
++/*
++ * This is based on an original C++ implementation for compiz that
++ * carries the following copyright notice:
++ *
++ *
++ * Copyright © 2011 NVIDIA Corporation
++ *
++ * Permission to use, copy, modify, distribute, and sell this software
++ * and its documentation for any purpose is hereby granted without
++ * fee, provided that the above copyright notice appear in all copies
++ * and that both that copyright notice and this permission notice
++ * appear in supporting documentation, and that the name of NVIDIA
++ * Corporation not be used in advertising or publicity pertaining to
++ * distribution of the software without specific, written prior
++ * permission. NVIDIA Corporation makes no representations about the
++ * suitability of this software for any purpose. It is provided "as
++ * is" without express or implied warranty.
++ *
++ * NVIDIA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
++ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
++ * FITNESS, IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
++ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
++ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
++ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
++ * SOFTWARE.
++ *
++ * Authors: James Jones <jajones@nvidia.com>
++ */
++
++#include <string.h>
++
++#include <GL/gl.h>
++#include <GL/glx.h>
++#include <X11/extensions/sync.h>
++
++#include <cogl/cogl.h>
++#include <clutter/clutter.h>
++
++#include <meta/util.h>
++
++#include "meta-sync-ring.h"
++
++/* Theory of operation:
++ *
++ * We use a ring of NUM_SYNCS fence objects. On each frame we advance
++ * to the next fence in the ring. For each fence we do:
++ *
++ * 1. fence is XSyncTriggerFence()'d and glWaitSync()'d
++ * 2. NUM_SYNCS / 2 frames later, fence should be triggered
++ * 3. fence is XSyncResetFence()'d
++ * 4. NUM_SYNCS / 2 frames later, fence should be reset
++ * 5. go back to 1 and re-use fence
++ *
++ * glClientWaitSync() and XAlarms are used in steps 2 and 4,
++ * respectively, to double-check the expectections.
++ */
++
++#define NUM_SYNCS 10
++#define MAX_SYNC_WAIT_TIME (1 * 1000 * 1000 * 1000) /* one sec */
++#define MAX_REBOOT_ATTEMPTS 2
++
++typedef enum
++{
++ META_SYNC_STATE_READY,
++ META_SYNC_STATE_WAITING,
++ META_SYNC_STATE_DONE,
++ META_SYNC_STATE_RESET_PENDING,
++} MetaSyncState;
++
++typedef struct
++{
++ Display *xdisplay;
++
++ XSyncFence xfence;
++ GLsync glsync;
++
++ XSyncCounter xcounter;
++ XSyncAlarm xalarm;
++ XSyncValue next_counter_value;
++
++ MetaSyncState state;
++} MetaSync;
++
++typedef struct
++{
++ Display *xdisplay;
++ int xsync_event_base;
++ int xsync_error_base;
++
++ GHashTable *alarm_to_sync;
++
++ MetaSync *syncs_array[NUM_SYNCS];
++ guint current_sync_idx;
++ MetaSync *current_sync;
++ guint warmup_syncs;
++
++ guint reboots;
++} MetaSyncRing;
++
++static MetaSyncRing meta_sync_ring = { 0 };
++
++static XSyncValue SYNC_VALUE_ZERO;
++static XSyncValue SYNC_VALUE_ONE;
++
++static const char* (*meta_gl_get_string) (GLenum name);
++static void (*meta_gl_get_integerv) (GLenum pname,
++ GLint *params);
++static const char* (*meta_gl_get_stringi) (GLenum name,
++ GLuint index);
++static void (*meta_gl_delete_sync) (GLsync sync);
++static GLenum (*meta_gl_client_wait_sync) (GLsync sync,
++ GLbitfield flags,
++ GLuint64 timeout);
++static void (*meta_gl_wait_sync) (GLsync sync,
++ GLbitfield flags,
++ GLuint64 timeout);
++static GLsync (*meta_gl_import_sync) (GLenum external_sync_type,
++ GLintptr external_sync,
++ GLbitfield flags);
++
++static MetaSyncRing *
++meta_sync_ring_get (void)
++{
++ if (meta_sync_ring.reboots > MAX_REBOOT_ATTEMPTS)
++ return NULL;
++
++ return &meta_sync_ring;
++}
++
++static gboolean
++load_gl_symbol (const char *name,
++ void **func)
++{
++ *func = cogl_get_proc_address (name);
++ if (!*func)
++ {
++ meta_verbose ("MetaSyncRing: failed to resolve required GL symbol \"%s\"\n", name);
++ return FALSE;
++ }
++ return TRUE;
++}
++
++static gboolean
++check_gl_extensions (void)
++{
++ ClutterBackend *backend;
++ CoglContext *cogl_context;
++ CoglDisplay *cogl_display;
++ CoglRenderer *cogl_renderer;
++
++ backend = clutter_get_default_backend ();
++ cogl_context = clutter_backend_get_cogl_context (backend);
++ cogl_display = cogl_context_get_display (cogl_context);
++ cogl_renderer = cogl_display_get_renderer (cogl_display);
++
++ switch (cogl_renderer_get_driver (cogl_renderer))
++ {
++ case COGL_DRIVER_GL3:
++ {
++ int num_extensions, i;
++ gboolean arb_sync = FALSE;
++ gboolean x11_sync_object = FALSE;
++
++ meta_gl_get_integerv (GL_NUM_EXTENSIONS, &num_extensions);
++
++ for (i = 0; i < num_extensions; ++i)
++ {
++ const char *ext = meta_gl_get_stringi (GL_EXTENSIONS, i);
++
++ if (g_strcmp0 ("GL_ARB_sync", ext) == 0)
++ arb_sync = TRUE;
++ else if (g_strcmp0 ("GL_EXT_x11_sync_object", ext) == 0)
++ x11_sync_object = TRUE;
++ }
++
++ return arb_sync && x11_sync_object;
++ }
++ case COGL_DRIVER_GL:
++ {
++ const char *extensions = meta_gl_get_string (GL_EXTENSIONS);
++ return (extensions != NULL &&
++ strstr (extensions, "GL_ARB_sync") != NULL &&
++ strstr (extensions, "GL_EXT_x11_sync_object") != NULL);
++ }
++ default:
++ break;
++ }
++
++ return FALSE;
++}
++
++static gboolean
++load_required_symbols (void)
++{
++ static gboolean success = FALSE;
++
++ if (success)
++ return TRUE;
++
++ /* We don't link against libGL directly because cogl may want to
++ * use something else. This assumes that cogl has been initialized
++ * and dynamically loaded libGL at this point.
++ */
++
++ if (!load_gl_symbol ("glGetString", (void **) &meta_gl_get_string))
++ goto out;
++ if (!load_gl_symbol ("glGetIntegerv", (void **) &meta_gl_get_integerv))
++ goto out;
++ if (!load_gl_symbol ("glGetStringi", (void **) &meta_gl_get_stringi))
++ goto out;
++
++ if (!check_gl_extensions ())
++ {
++ meta_verbose ("MetaSyncRing: couldn't find required GL extensions\n");
++ goto out;
++ }
++
++ if (!load_gl_symbol ("glDeleteSync", (void **) &meta_gl_delete_sync))
++ goto out;
++ if (!load_gl_symbol ("glClientWaitSync", (void **) &meta_gl_client_wait_sync))
++ goto out;
++ if (!load_gl_symbol ("glWaitSync", (void **) &meta_gl_wait_sync))
++ goto out;
++ if (!load_gl_symbol ("glImportSyncEXT", (void **) &meta_gl_import_sync))
++ goto out;
++
++ success = TRUE;
++ out:
++ return success;
++}
++
++static void
++meta_sync_insert (MetaSync *self)
++{
++ g_return_if_fail (self->state == META_SYNC_STATE_READY);
++
++ XSyncTriggerFence (self->xdisplay, self->xfence);
++ XFlush (self->xdisplay);
++
++ meta_gl_wait_sync (self->glsync, 0, GL_TIMEOUT_IGNORED);
++
++ self->state = META_SYNC_STATE_WAITING;
++}
++
++static GLenum
++meta_sync_check_update_finished (MetaSync *self,
++ GLuint64 timeout)
++{
++ GLenum status = GL_WAIT_FAILED;
++
++ switch (self->state)
++ {
++ case META_SYNC_STATE_DONE:
++ status = GL_ALREADY_SIGNALED;
++ break;
++ case META_SYNC_STATE_WAITING:
++ status = meta_gl_client_wait_sync (self->glsync, 0, timeout);
++ if (status == GL_ALREADY_SIGNALED || status == GL_CONDITION_SATISFIED)
++ self->state = META_SYNC_STATE_DONE;
++ break;
++ default:
++ break;
++ }
++
++ g_warn_if_fail (status != GL_WAIT_FAILED);
++
++ return status;
++}
++
++static void
++meta_sync_reset (MetaSync *self)
++{
++ XSyncAlarmAttributes attrs;
++ int overflow;
++
++ g_return_if_fail (self->state == META_SYNC_STATE_DONE);
++
++ XSyncResetFence (self->xdisplay, self->xfence);
++
++ attrs.trigger.wait_value = self->next_counter_value;
++
++ XSyncChangeAlarm (self->xdisplay, self->xalarm, XSyncCAValue, &attrs);
++ XSyncSetCounter (self->xdisplay, self->xcounter, self->next_counter_value);
++
++ XSyncValueAdd (&self->next_counter_value,
++ self->next_counter_value,
++ SYNC_VALUE_ONE,
++ &overflow);
++
++ self->state = META_SYNC_STATE_RESET_PENDING;
++}
++
++static void
++meta_sync_handle_event (MetaSync *self,
++ XSyncAlarmNotifyEvent *event)
++{
++ g_return_if_fail (event->alarm == self->xalarm);
++ g_return_if_fail (self->state == META_SYNC_STATE_RESET_PENDING);
++
++ self->state = META_SYNC_STATE_READY;
++}
++
++static MetaSync *
++meta_sync_new (Display *xdisplay)
++{
++ MetaSync *self;
++ XSyncAlarmAttributes attrs;
++
++ self = g_malloc0 (sizeof (MetaSync));
++
++ self->xdisplay = xdisplay;
++
++ self->xfence = XSyncCreateFence (xdisplay, DefaultRootWindow (xdisplay), FALSE);
++ self->glsync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0);
++
++ self->xcounter = XSyncCreateCounter (xdisplay, SYNC_VALUE_ZERO);
++
++ attrs.trigger.counter = self->xcounter;
++ attrs.trigger.value_type = XSyncAbsolute;
++ attrs.trigger.wait_value = SYNC_VALUE_ONE;
++ attrs.trigger.test_type = XSyncPositiveTransition;
++ attrs.events = TRUE;
++ self->xalarm = XSyncCreateAlarm (xdisplay,
++ XSyncCACounter |
++ XSyncCAValueType |
++ XSyncCAValue |
++ XSyncCATestType |
++ XSyncCAEvents,
++ &attrs);
++
++ XSyncIntToValue (&self->next_counter_value, 1);
++
++ self->state = META_SYNC_STATE_READY;
++
++ return self;
++}
++
++static Bool
++alarm_event_predicate (Display *dpy,
++ XEvent *event,
++ XPointer data)
++{
++ MetaSyncRing *ring = meta_sync_ring_get ();
++
++ if (!ring)
++ return False;
++
++ if (event->type == ring->xsync_event_base + XSyncAlarmNotify)
++ {
++ if (((MetaSync *) data)->xalarm == ((XSyncAlarmNotifyEvent *) event)->alarm)
++ return True;
++ }
++ return False;
++}
++
++static void
++meta_sync_free (MetaSync *self)
++{
++ /* When our assumptions don't hold, something has gone wrong but we
++ * don't know what, so we reboot the ring. While doing that, we
++ * trigger fences before deleting them to try to get ourselves out
++ * of a potentially stuck GPU state.
++ */
++ switch (self->state)
++ {
++ case META_SYNC_STATE_WAITING:
++ case META_SYNC_STATE_DONE:
++ /* nothing to do */
++ break;
++ case META_SYNC_STATE_RESET_PENDING:
++ {
++ XEvent event;
++ XIfEvent (self->xdisplay, &event, alarm_event_predicate, (XPointer) self);
++ meta_sync_handle_event (self, (XSyncAlarmNotifyEvent *) &event);
++ }
++ /* fall through */
++ case META_SYNC_STATE_READY:
++ XSyncTriggerFence (self->xdisplay, self->xfence);
++ XFlush (self->xdisplay);
++ break;
++ default:
++ break;
++ }
++
++ meta_gl_delete_sync (self->glsync);
++ XSyncDestroyFence (self->xdisplay, self->xfence);
++ XSyncDestroyCounter (self->xdisplay, self->xcounter);
++ XSyncDestroyAlarm (self->xdisplay, self->xalarm);
++
++ g_free (self);
++}
++
++gboolean
++meta_sync_ring_init (Display *xdisplay)
++{
++ gint major, minor;
++ guint i;
++ MetaSyncRing *ring = meta_sync_ring_get ();
++
++ if (!ring)
++ return FALSE;
++
++ g_return_val_if_fail (xdisplay != NULL, FALSE);
++ g_return_val_if_fail (ring->xdisplay == NULL, FALSE);
++
++ if (!load_required_symbols ())
++ return FALSE;
++
++ if (!XSyncQueryExtension (xdisplay, &ring->xsync_event_base, &ring->xsync_error_base) ||
++ !XSyncInitialize (xdisplay, &major, &minor))
++ return FALSE;
++
++ XSyncIntToValue (&SYNC_VALUE_ZERO, 0);
++ XSyncIntToValue (&SYNC_VALUE_ONE, 1);
++
++ ring->xdisplay = xdisplay;
++
++ ring->alarm_to_sync = g_hash_table_new (NULL, NULL);
++
++ for (i = 0; i < NUM_SYNCS; ++i)
++ {
++ MetaSync *sync = meta_sync_new (ring->xdisplay);
++ ring->syncs_array[i] = sync;
++ g_hash_table_replace (ring->alarm_to_sync, (gpointer) sync->xalarm, sync);
++ }
++
++ ring->current_sync_idx = 0;
++ ring->current_sync = ring->syncs_array[0];
++ ring->warmup_syncs = 0;
++
++ return TRUE;
++}
++
++void
++meta_sync_ring_destroy (void)
++{
++ guint i;
++ MetaSyncRing *ring = meta_sync_ring_get ();
++
++ if (!ring)
++ return;
++
++ g_return_if_fail (ring->xdisplay != NULL);
++
++ ring->current_sync_idx = 0;
++ ring->current_sync = NULL;
++ ring->warmup_syncs = 0;
++
++ for (i = 0; i < NUM_SYNCS; ++i)
++ meta_sync_free (ring->syncs_array[i]);
++
++ g_hash_table_destroy (ring->alarm_to_sync);
++
++ ring->xsync_event_base = 0;
++ ring->xsync_error_base = 0;
++ ring->xdisplay = NULL;
++}
++
++static gboolean
++meta_sync_ring_reboot (Display *xdisplay)
++{
++ MetaSyncRing *ring = meta_sync_ring_get ();
++
++ if (!ring)
++ return FALSE;
++
++ meta_sync_ring_destroy ();
++
++ ring->reboots += 1;
++
++ if (!meta_sync_ring_get ())
++ {
++ meta_warning ("MetaSyncRing: Too many reboots -- disabling\n");
++ return FALSE;
++ }
++
++ return meta_sync_ring_init (xdisplay);
++}
++
++gboolean
++meta_sync_ring_after_frame (void)
++{
++ MetaSyncRing *ring = meta_sync_ring_get ();
++
++ if (!ring)
++ return FALSE;
++
++ g_return_if_fail (ring->xdisplay != NULL);
++
++ if (ring->warmup_syncs >= NUM_SYNCS / 2)
++ {
++ guint reset_sync_idx = (ring->current_sync_idx + NUM_SYNCS - (NUM_SYNCS / 2)) % NUM_SYNCS;
++ MetaSync *sync_to_reset = ring->syncs_array[reset_sync_idx];
++
++ GLenum status = meta_sync_check_update_finished (sync_to_reset, 0);
++ if (status == GL_TIMEOUT_EXPIRED)
++ {
++ meta_warning ("MetaSyncRing: We should never wait for a sync -- add more syncs?\n");
++ status = meta_sync_check_update_finished (sync_to_reset, MAX_SYNC_WAIT_TIME);
++ }
++
++ if (status != GL_ALREADY_SIGNALED && status != GL_CONDITION_SATISFIED)
++ {
++ meta_warning ("MetaSyncRing: Timed out waiting for sync object.\n");
++ return meta_sync_ring_reboot (ring->xdisplay);
++ }
++
++ meta_sync_reset (sync_to_reset);
++ }
++ else
++ {
++ ring->warmup_syncs += 1;
++ }
++
++ ring->current_sync_idx += 1;
++ ring->current_sync_idx %= NUM_SYNCS;
++
++ ring->current_sync = ring->syncs_array[ring->current_sync_idx];
++
++ return TRUE;
++}
++
++gboolean
++meta_sync_ring_insert_wait (void)
++{
++ MetaSyncRing *ring = meta_sync_ring_get ();
++
++ if (!ring)
++ return FALSE;
++
++ g_return_if_fail (ring->xdisplay != NULL);
++
++ if (ring->current_sync->state != META_SYNC_STATE_READY)
++ {
++ meta_warning ("MetaSyncRing: Sync object is not ready -- were events handled properly?\n");
++ if (!meta_sync_ring_reboot (ring->xdisplay))
++ return FALSE;
++ }
++
++ meta_sync_insert (ring->current_sync);
++
++ return TRUE;
++}
++
++void
++meta_sync_ring_handle_event (XEvent *xevent)
++{
++ XSyncAlarmNotifyEvent *event;
++ MetaSync *sync;
++ MetaSyncRing *ring = meta_sync_ring_get ();
++
++ if (!ring)
++ return;
++
++ g_return_if_fail (ring->xdisplay != NULL);
++
++ if (xevent->type != (ring->xsync_event_base + XSyncAlarmNotify))
++ return;
++
++ event = (XSyncAlarmNotifyEvent *) xevent;
++
++ sync = g_hash_table_lookup (ring->alarm_to_sync, (gpointer) event->alarm);
++ if (sync)
++ meta_sync_handle_event (sync, event);
++}
+diff --git a/src/compositor/meta-sync-ring.h b/src/compositor/meta-sync-ring.h
+new file mode 100644
+index 0000000..6dca8ef
+--- /dev/null
++++ b/src/compositor/meta-sync-ring.h
+@@ -0,0 +1,14 @@
++#ifndef _META_SYNC_RING_H_
++#define _META_SYNC_RING_H_
++
++#include <glib.h>
++
++#include <X11/Xlib.h>
++
++gboolean meta_sync_ring_init (Display *dpy);
++void meta_sync_ring_destroy (void);
++gboolean meta_sync_ring_after_frame (void);
++gboolean meta_sync_ring_insert_wait (void);
++void meta_sync_ring_handle_event (XEvent *event);
++
++#endif /* _META_SYNC_RING_H_ */
+--
+cgit v0.10.2
+
diff --git a/x11-wm/mutter/files/mutter-3.16.3-crash-border.patch b/x11-wm/mutter/files/mutter-3.16.3-crash-border.patch
new file mode 100644
index 000000000000..9cbd0d06e44a
--- /dev/null
+++ b/x11-wm/mutter/files/mutter-3.16.3-crash-border.patch
@@ -0,0 +1,32 @@
+From f60c33b5afc4b1dff0b31f17d7ae222db8aa789f Mon Sep 17 00:00:00 2001
+From: Marek Chalupa <mchqwerty@gmail.com>
+Date: Fri, 3 Jul 2015 11:28:00 +0200
+Subject: frames: handle META_FRAME_CONTROL_NONE on left click
+
+We can get this operation in some cases, for example when
+we're trying to resize window that cannot be resized.
+This can occur with maximized windows that have a border
+(without border we couldn't resize them by mouse in maximized state).
+In this case we reached abort() beacuse we did not handle this op.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=751884
+
+diff --git a/src/ui/frames.c b/src/ui/frames.c
+index 362d7b6..a2f7f45 100644
+--- a/src/ui/frames.c
++++ b/src/ui/frames.c
+@@ -1053,6 +1053,11 @@ meta_frame_left_click_event (MetaUIFrame *frame,
+ }
+
+ return TRUE;
++ case META_FRAME_CONTROL_NONE:
++ /* We can get this for example when trying to resize window
++ * that cannot be resized (e. g. it is maximized and the theme
++ * currently used has borders for maximized windows), see #751884 */
++ return FALSE;
+ default:
+ g_assert_not_reached ();
+ }
+--
+cgit v0.10.2
+
diff --git a/x11-wm/mutter/files/mutter-3.16.3-fallback-keymap.patch b/x11-wm/mutter/files/mutter-3.16.3-fallback-keymap.patch
new file mode 100644
index 000000000000..f77234ba3b20
--- /dev/null
+++ b/x11-wm/mutter/files/mutter-3.16.3-fallback-keymap.patch
@@ -0,0 +1,28 @@
+From 9abc0712836c9e56ed08796645874cc0d10b1826 Mon Sep 17 00:00:00 2001
+From: Rui Matos <tiagomatos@gmail.com>
+Date: Mon, 21 Sep 2015 17:25:40 +0200
+Subject: backend-x11: Fallback to a default keymap if getting it from X fails
+
+This shouldn't fail but apparently sometimes it does and in that case
+having a possibly wrong idea of the keymap is still better than
+crashing.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=754979
+
+diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
+index 7ad28fd..dbcd13f 100644
+--- a/src/backends/x11/meta-backend-x11.c
++++ b/src/backends/x11/meta-backend-x11.c
+@@ -760,6 +760,9 @@ meta_backend_x11_get_keymap (MetaBackend *backend)
+ priv->xcb,
+ xkb_x11_get_core_keyboard_device_id (priv->xcb),
+ XKB_KEYMAP_COMPILE_NO_FLAGS);
++ if (priv->keymap == NULL)
++ priv->keymap = xkb_keymap_new_from_names (context, NULL, XKB_KEYMAP_COMPILE_NO_FLAGS);
++
+ xkb_context_unref (context);
+ }
+
+--
+cgit v0.10.2
+
diff --git a/x11-wm/mutter/files/mutter-3.16.3-fix-race.patch b/x11-wm/mutter/files/mutter-3.16.3-fix-race.patch
new file mode 100644
index 000000000000..a0b493b64f4c
--- /dev/null
+++ b/x11-wm/mutter/files/mutter-3.16.3-fix-race.patch
@@ -0,0 +1,114 @@
+From c77e482b60bea40a422691b16af02a429d9c2edc Mon Sep 17 00:00:00 2001
+From: Aaron Plattner <aplattner@nvidia.com>
+Date: Mon, 3 Aug 2015 21:15:15 -0700
+Subject: compositor: Fix GL_EXT_x11_sync_object race condition
+
+The compositor maintains a ring of shared fences with the X server in order to
+properly synchronize rendering between the X server and the compositor's GPU
+channel. When all of the fences have been used, the compositor needs to reset
+one so that it can be reused. It does this by first waiting on the CPU for the
+fence to become triggered, and then sending a request to the X server to reset
+the fence.
+
+If the compositor's GPU channel is busy processing other work (e.g. the desktop
+switcher animation), then the X server may process the reset request before the
+GPU has consumed the fence. This causes the GPU channel to hang.
+
+Fix the problem by having the compositor's GPU channel trigger its own fence
+after waiting for the X server's fence. Wait for that fence on the CPU before
+sending the reset request to the X server. This ensures that the GPU has
+consumed the X11 fence before the server resets it.
+
+Signed-off-by: Aaron Plattner <aplattner@nvidia.com>
+
+https://bugzilla.gnome.org/show_bug.cgi?id=728464
+
+diff --git a/src/compositor/meta-sync-ring.c b/src/compositor/meta-sync-ring.c
+index 4ee61f8..44b1c41 100644
+--- a/src/compositor/meta-sync-ring.c
++++ b/src/compositor/meta-sync-ring.c
+@@ -73,7 +73,8 @@ typedef struct
+ Display *xdisplay;
+
+ XSyncFence xfence;
+- GLsync glsync;
++ GLsync gl_x11_sync;
++ GLsync gpu_fence;
+
+ XSyncCounter xcounter;
+ XSyncAlarm xalarm;
+@@ -118,6 +119,8 @@ static void (*meta_gl_wait_sync) (GLsync sync,
+ static GLsync (*meta_gl_import_sync) (GLenum external_sync_type,
+ GLintptr external_sync,
+ GLbitfield flags);
++static GLsync (*meta_gl_fence_sync) (GLenum condition,
++ GLbitfield flags);
+
+ static MetaSyncRing *
+ meta_sync_ring_get (void)
+@@ -224,6 +227,8 @@ load_required_symbols (void)
+ goto out;
+ if (!load_gl_symbol ("glImportSyncEXT", (void **) &meta_gl_import_sync))
+ goto out;
++ if (!load_gl_symbol ("glFenceSync", (void **) &meta_gl_fence_sync))
++ goto out;
+
+ success = TRUE;
+ out:
+@@ -238,7 +243,8 @@ meta_sync_insert (MetaSync *self)
+ XSyncTriggerFence (self->xdisplay, self->xfence);
+ XFlush (self->xdisplay);
+
+- meta_gl_wait_sync (self->glsync, 0, GL_TIMEOUT_IGNORED);
++ meta_gl_wait_sync (self->gl_x11_sync, 0, GL_TIMEOUT_IGNORED);
++ self->gpu_fence = meta_gl_fence_sync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+
+ self->state = META_SYNC_STATE_WAITING;
+ }
+@@ -255,9 +261,13 @@ meta_sync_check_update_finished (MetaSync *self,
+ status = GL_ALREADY_SIGNALED;
+ break;
+ case META_SYNC_STATE_WAITING:
+- status = meta_gl_client_wait_sync (self->glsync, 0, timeout);
++ status = meta_gl_client_wait_sync (self->gpu_fence, 0, timeout);
+ if (status == GL_ALREADY_SIGNALED || status == GL_CONDITION_SATISFIED)
+- self->state = META_SYNC_STATE_DONE;
++ {
++ self->state = META_SYNC_STATE_DONE;
++ meta_gl_delete_sync (self->gpu_fence);
++ self->gpu_fence = 0;
++ }
+ break;
+ default:
+ break;
+@@ -312,7 +322,8 @@ meta_sync_new (Display *xdisplay)
+ self->xdisplay = xdisplay;
+
+ self->xfence = XSyncCreateFence (xdisplay, DefaultRootWindow (xdisplay), FALSE);
+- self->glsync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0);
++ self->gl_x11_sync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0);
++ self->gpu_fence = 0;
+
+ self->xcounter = XSyncCreateCounter (xdisplay, SYNC_VALUE_ZERO);
+
+@@ -365,6 +376,8 @@ meta_sync_free (MetaSync *self)
+ switch (self->state)
+ {
+ case META_SYNC_STATE_WAITING:
++ meta_gl_delete_sync (self->gpu_fence);
++ break;
+ case META_SYNC_STATE_DONE:
+ /* nothing to do */
+ break;
+@@ -383,7 +396,7 @@ meta_sync_free (MetaSync *self)
+ break;
+ }
+
+- meta_gl_delete_sync (self->glsync);
++ meta_gl_delete_sync (self->gl_x11_sync);
+ XSyncDestroyFence (self->xdisplay, self->xfence);
+ XSyncDestroyCounter (self->xdisplay, self->xcounter);
+ XSyncDestroyAlarm (self->xdisplay, self->xalarm);
+--
+cgit v0.10.2
+
diff --git a/x11-wm/mutter/files/mutter-3.16.3-fix-return.patch b/x11-wm/mutter/files/mutter-3.16.3-fix-return.patch
new file mode 100644
index 000000000000..2898d5238813
--- /dev/null
+++ b/x11-wm/mutter/files/mutter-3.16.3-fix-return.patch
@@ -0,0 +1,32 @@
+From a54b1261d3ec5ccf7a8262c88557b6b952bc8a2e Mon Sep 17 00:00:00 2001
+From: Ting-Wei Lan <lantw@src.gnome.org>
+Date: Sat, 8 Aug 2015 20:12:09 +0800
+Subject: build: Fix return value in meta-sync-ring.c
+
+https://bugzilla.gnome.org/show_bug.cgi?id=753380
+
+diff --git a/src/compositor/meta-sync-ring.c b/src/compositor/meta-sync-ring.c
+index 44b1c41..217ebe5 100644
+--- a/src/compositor/meta-sync-ring.c
++++ b/src/compositor/meta-sync-ring.c
+@@ -499,7 +499,7 @@ meta_sync_ring_after_frame (void)
+ if (!ring)
+ return FALSE;
+
+- g_return_if_fail (ring->xdisplay != NULL);
++ g_return_val_if_fail (ring->xdisplay != NULL, FALSE);
+
+ if (ring->warmup_syncs >= NUM_SYNCS / 2)
+ {
+@@ -542,7 +542,7 @@ meta_sync_ring_insert_wait (void)
+ if (!ring)
+ return FALSE;
+
+- g_return_if_fail (ring->xdisplay != NULL);
++ g_return_val_if_fail (ring->xdisplay != NULL, FALSE);
+
+ if (ring->current_sync->state != META_SYNC_STATE_READY)
+ {
+--
+cgit v0.10.2
+
diff --git a/x11-wm/mutter/files/mutter-3.16.3-flickering.patch b/x11-wm/mutter/files/mutter-3.16.3-flickering.patch
new file mode 100644
index 000000000000..6267a4e33348
--- /dev/null
+++ b/x11-wm/mutter/files/mutter-3.16.3-flickering.patch
@@ -0,0 +1,114 @@
+From 916070cc7218cc80f4565ea265b0dd6e5e93cb98 Mon Sep 17 00:00:00 2001
+From: Rui Matos <tiagomatos@gmail.com>
+Date: Wed, 12 Aug 2015 15:26:34 +0200
+Subject: compositor: Handle fences in the frontend X connection
+
+Since mutter has two X connections and does damage handling on the
+frontend while fence triggering is done on the backend, we have a race
+between XDamageSubtract() and XSyncFenceTrigger() causing missed
+redraws in the GL_EXT_X11_sync_object path.
+
+If the fence trigger gets processed first by the server, any client
+drawing that happens between that and the damage subtract being
+processed and is completely contained in the last damage event box
+that mutter got, won't be included in the current frame nor will it
+cause a new damage event.
+
+A simple fix for this would be XSync()ing on the frontend connection
+after doing all the damage subtracts but that would add a round trip
+on every frame again which defeats the asynchronous design of X
+fences.
+
+Instead, if we move fence handling to the frontend we automatically
+get the right ordering between damage subtracts and fence triggers.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=728464
+
+diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
+index ac38ffc..3ff8431 100644
+--- a/src/backends/x11/meta-backend-x11.c
++++ b/src/backends/x11/meta-backend-x11.c
+@@ -45,7 +45,6 @@
+ #include <meta/util.h>
+ #include "display-private.h"
+ #include "compositor/compositor-private.h"
+-#include "compositor/meta-sync-ring.h"
+
+ struct _MetaBackendX11Private
+ {
+@@ -256,8 +255,6 @@ handle_host_xevent (MetaBackend *backend,
+ MetaCompositor *compositor = display->compositor;
+ if (meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event))
+ bypass_clutter = TRUE;
+- if (compositor->have_x11_sync_object)
+- meta_sync_ring_handle_event (event);
+ }
+ }
+
+diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
+index 554faa1..2e182c2 100644
+--- a/src/compositor/compositor.c
++++ b/src/compositor/compositor.c
+@@ -534,8 +534,7 @@ meta_compositor_manage (MetaCompositor *compositor)
+ */
+ XMapWindow (xdisplay, compositor->output);
+
+- compositor->have_x11_sync_object =
+- meta_sync_ring_init (meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)));
++ compositor->have_x11_sync_object = meta_sync_ring_init (xdisplay);
+ }
+
+ redirect_windows (display->screen);
+@@ -737,6 +736,9 @@ meta_compositor_process_event (MetaCompositor *compositor,
+ process_damage (compositor, (XDamageNotifyEvent *) event, window);
+ }
+
++ if (compositor->have_x11_sync_object)
++ meta_sync_ring_handle_event (event);
++
+ /* Clutter needs to know about MapNotify events otherwise it will
+ think the stage is invisible */
+ if (!meta_is_wayland_compositor () && event->type == MapNotify)
+diff --git a/src/compositor/meta-sync-ring.c b/src/compositor/meta-sync-ring.c
+index 217ebe5..336ccd4 100644
+--- a/src/compositor/meta-sync-ring.c
++++ b/src/compositor/meta-sync-ring.c
+@@ -322,7 +322,7 @@ meta_sync_new (Display *xdisplay)
+ self->xdisplay = xdisplay;
+
+ self->xfence = XSyncCreateFence (xdisplay, DefaultRootWindow (xdisplay), FALSE);
+- self->gl_x11_sync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0);
++ self->gl_x11_sync = 0;
+ self->gpu_fence = 0;
+
+ self->xcounter = XSyncCreateCounter (xdisplay, SYNC_VALUE_ZERO);
+@@ -347,6 +347,13 @@ meta_sync_new (Display *xdisplay)
+ return self;
+ }
+
++static void
++meta_sync_import (MetaSync *self)
++{
++ g_return_if_fail (self->gl_x11_sync == 0);
++ self->gl_x11_sync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0);
++}
++
+ static Bool
+ alarm_event_predicate (Display *dpy,
+ XEvent *event,
+@@ -437,6 +444,12 @@ meta_sync_ring_init (Display *xdisplay)
+ ring->syncs_array[i] = sync;
+ g_hash_table_replace (ring->alarm_to_sync, (gpointer) sync->xalarm, sync);
+ }
++ /* Since the connection we create the X fences on isn't the same as
++ * the one used for the GLX context, we need to XSync() here to
++ * ensure glImportSync() succeeds. */
++ XSync (xdisplay, False);
++ for (i = 0; i < NUM_SYNCS; ++i)
++ meta_sync_import (ring->syncs_array[i]);
+
+ ring->current_sync_idx = 0;
+ ring->current_sync = ring->syncs_array[0];
+--
+cgit v0.10.2
+
diff --git a/x11-wm/mutter/mutter-3.16.3-r1.ebuild b/x11-wm/mutter/mutter-3.16.3-r1.ebuild
new file mode 100644
index 000000000000..98cc39c2a7d0
--- /dev/null
+++ b/x11-wm/mutter/mutter-3.16.3-r1.ebuild
@@ -0,0 +1,114 @@
+# Copyright 1999-2015 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+EAPI="5"
+GCONF_DEBUG="yes"
+
+inherit autotools eutils gnome2
+
+DESCRIPTION="GNOME 3 compositing window manager based on Clutter"
+HOMEPAGE="https://git.gnome.org/browse/mutter/"
+
+LICENSE="GPL-2+"
+SLOT="0"
+IUSE="+introspection +kms test wayland"
+KEYWORDS="~alpha ~amd64 ~arm ~ia64 ~ppc ~ppc64 ~sparc ~x86"
+
+# libXi-1.7.4 or newer needed per:
+# https://bugzilla.gnome.org/show_bug.cgi?id=738944
+COMMON_DEPEND="
+ >=x11-libs/pango-1.2[X,introspection?]
+ >=x11-libs/cairo-1.10[X]
+ >=x11-libs/gtk+-3.9.11:3[X,introspection?]
+ >=dev-libs/glib-2.36.0:2[dbus]
+ >=media-libs/clutter-1.21.3:1.0[introspection?]
+ >=media-libs/cogl-1.17.1:1.0=[introspection?]
+ >=media-libs/libcanberra-0.26[gtk3]
+ >=x11-libs/startup-notification-0.7
+ >=x11-libs/libXcomposite-0.2
+ >=gnome-base/gsettings-desktop-schemas-3.15.92[introspection?]
+ gnome-base/gnome-desktop:3=
+ >sys-power/upower-0.99:=
+
+ x11-libs/libICE
+ x11-libs/libSM
+ x11-libs/libX11
+ >=x11-libs/libXcomposite-0.2
+ x11-libs/libXcursor
+ x11-libs/libXdamage
+ x11-libs/libXext
+ x11-libs/libXfixes
+ >=x11-libs/libXi-1.7.4
+ x11-libs/libXinerama
+ x11-libs/libXrandr
+ x11-libs/libXrender
+ x11-libs/libxcb
+ x11-libs/libxkbfile
+ >=x11-libs/libxkbcommon-0.4.3[X]
+ x11-misc/xkeyboard-config
+
+ gnome-extra/zenity
+
+ introspection? ( >=dev-libs/gobject-introspection-1.42:= )
+ kms? (
+ dev-libs/libinput
+ >=media-libs/clutter-1.20[egl]
+ media-libs/cogl:1.0=[kms]
+ >=media-libs/mesa-10.3[gbm]
+ sys-apps/systemd
+ virtual/libgudev
+ x11-libs/libdrm:= )
+ wayland? (
+ >=dev-libs/wayland-1.6.90
+ >=media-libs/clutter-1.20[wayland]
+ x11-base/xorg-server[wayland] )
+"
+DEPEND="${COMMON_DEPEND}
+ >=dev-util/gtk-doc-am-1.15
+ >=dev-util/intltool-0.41
+ sys-devel/gettext
+ virtual/pkgconfig
+ x11-proto/xextproto
+ x11-proto/xineramaproto
+ x11-proto/xproto
+ test? ( app-text/docbook-xml-dtd:4.5 )
+"
+RDEPEND="${COMMON_DEPEND}
+ !x11-misc/expocity
+"
+
+src_prepare() {
+ # Fallback to a default keymap if getting it from X fails (from 'master')
+ epatch "${FILESDIR}"/${PN}-3.16.3-fallback-keymap.patch
+
+ # frames: handle META_FRAME_CONTROL_NONE on left click (from '3.16')
+ epatch "${FILESDIR}"/${P}-crash-border.patch
+
+ # compositor: Add support for GL_EXT_x11_sync_object (from '3.16')
+ epatch "${FILESDIR}"/${P}-GL_EXT_x11_sync_object.patch
+
+ # compositor: Fix GL_EXT_x11_sync_object race condition (from '3.16')
+ epatch "${FILESDIR}"/${P}-fix-race.patch
+
+ # build: Fix return value in meta-sync-ring.c (from '3.16')
+ epatch "${FILESDIR}"/${P}-fix-return.patch
+
+ # compositor: Handle fences in the frontend X connection (from '3.16')
+ epatch "${FILESDIR}"/${P}-flickering.patch
+
+ eautoreconf
+ gnome2_src_prepare
+}
+
+src_configure() {
+ gnome2_src_configure \
+ --disable-static \
+ --enable-sm \
+ --enable-startup-notification \
+ --enable-verbose-mode \
+ --with-libcanberra \
+ $(use_enable introspection) \
+ $(use_enable kms native-backend) \
+ $(use_enable wayland)
+}