From db633a463a7b3ea3db4fd04bfb0bb9d06996557e Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 30 2017 13:44:50 +0000 Subject: import mutter-3.22.3-12.el7_4 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..31242bd --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/mutter-3.22.3.tar.xz diff --git a/.mutter.metadata b/.mutter.metadata new file mode 100644 index 0000000..0aaec90 --- /dev/null +++ b/.mutter.metadata @@ -0,0 +1 @@ +90bf3c4a65b474e958a1b13f80c47ebcdb411b42 SOURCES/mutter-3.22.3.tar.xz diff --git a/README.md b/README.md deleted file mode 100644 index 0e7897f..0000000 --- a/README.md +++ /dev/null @@ -1,5 +0,0 @@ -The master branch has no content - -Look at the c7 branch if you are working with CentOS-7, or the c4/c5/c6 branch for CentOS-4, 5 or 6 - -If you find this file in a distro specific branch, it means that no content has been checked in yet diff --git a/SOURCES/0001-Revert-backend-x11-Ensure-the-Xkb-group-index-remain.patch b/SOURCES/0001-Revert-backend-x11-Ensure-the-Xkb-group-index-remain.patch new file mode 100644 index 0000000..ee3b81c --- /dev/null +++ b/SOURCES/0001-Revert-backend-x11-Ensure-the-Xkb-group-index-remain.patch @@ -0,0 +1,61 @@ +From 090ac268b91c3b07f90d9d4ebe481bfe649836df Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Mon, 13 Jun 2016 19:32:43 +0200 +Subject: [PATCH] Revert "backend-x11: Ensure the Xkb group index remains + properly set" + +This reverts commit 2857fdbdb887fcaa2e2f25d268c34ae039646e78. +--- + src/backends/x11/meta-backend-x11.c | 16 +++------------- + 1 file changed, 3 insertions(+), 13 deletions(-) + +diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c +index a645bbd..dbcd13f 100644 +--- a/src/backends/x11/meta-backend-x11.c ++++ b/src/backends/x11/meta-backend-x11.c +@@ -82,7 +82,6 @@ struct _MetaBackendX11Private + gchar *keymap_layouts; + gchar *keymap_variants; + gchar *keymap_options; +- int locked_group; + }; + typedef struct _MetaBackendX11Private MetaBackendX11Private; + +@@ -298,23 +297,15 @@ handle_host_xevent (MetaBackend *backend, + + if (event->type == priv->xkb_event_base) + { +- XkbEvent *xkb_ev = (XkbEvent *) event; ++ XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event; + +- if (xkb_ev->any.device == META_VIRTUAL_CORE_KEYBOARD_ID) ++ if (xkb_ev->device == META_VIRTUAL_CORE_KEYBOARD_ID) + { +- switch (xkb_ev->any.xkb_type) ++ switch (xkb_ev->xkb_type) + { + case XkbNewKeyboardNotify: + case XkbMapNotify: + keymap_changed (backend); +- break; +- case XkbStateNotify: +- if (xkb_ev->state.changed & XkbGroupLockMask) +- { +- if (priv->locked_group != xkb_ev->state.locked_group) +- XkbLockGroup (priv->xdisplay, XkbUseCoreKbd, priv->locked_group); +- } +- break; + default: + break; + } +@@ -785,7 +776,6 @@ meta_backend_x11_lock_layout_group (MetaBackend *backend, + MetaBackendX11 *x11 = META_BACKEND_X11 (backend); + MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); + +- priv->locked_group = idx; + XkbLockGroup (priv->xdisplay, XkbUseCoreKbd, idx); + } + +-- +2.7.4 + diff --git a/SOURCES/0001-backends-x11-Support-synaptics-configuration.patch b/SOURCES/0001-backends-x11-Support-synaptics-configuration.patch new file mode 100644 index 0000000..059728b --- /dev/null +++ b/SOURCES/0001-backends-x11-Support-synaptics-configuration.patch @@ -0,0 +1,345 @@ +From 10b63b27ba84458884138cecc1b914b4f69bc9b9 Mon Sep 17 00:00:00 2001 +From: Carlos Garnacho +Date: Thu, 19 Jan 2017 15:03:41 +0100 +Subject: [PATCH] backends/x11: Support synaptics configuration + +The code is taken mostly as-is from g-s-d, so we can drag the +dead horse a bit longer. +--- + src/backends/x11/meta-input-settings-x11.c | 264 +++++++++++++++++++++++++++++ + 1 file changed, 264 insertions(+) + +diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c +index 8f962b4..75ceb0c 100644 +--- a/src/backends/x11/meta-input-settings-x11.c ++++ b/src/backends/x11/meta-input-settings-x11.c +@@ -26,6 +26,7 @@ + #include "meta-backend-x11.h" + #include "meta-input-settings-x11.h" + ++#include + #include + #include + #include +@@ -118,6 +119,177 @@ change_property (ClutterInputDevice *device, + meta_XFree (data_ret); + } + ++static gboolean ++is_device_synaptics (ClutterInputDevice *device) ++{ ++ guchar *has_setting; ++ ++ /* We just need looking for a synaptics-specific property */ ++ has_setting = get_property (device, "Synaptics Off", XA_INTEGER, 8, 1); ++ if (!has_setting) ++ return FALSE; ++ ++ meta_XFree (has_setting); ++ return TRUE; ++} ++ ++static void ++change_synaptics_tap_left_handed (ClutterInputDevice *device, ++ gboolean tap_enabled, ++ gboolean left_handed) ++{ ++ MetaDisplay *display = meta_get_display (); ++ MetaBackend *backend = meta_get_backend (); ++ Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); ++ XDevice *xdevice; ++ guchar *tap_action, *buttons; ++ guint buttons_capacity = 16, n_buttons; ++ ++ xdevice = XOpenDevice(xdisplay, clutter_input_device_get_device_id (device)); ++ if (!xdevice) ++ return; ++ ++ tap_action = get_property (device, "Synaptics Tap Action", ++ XA_INTEGER, 8, 7); ++ if (!tap_action) ++ goto out; ++ ++ tap_action[4] = tap_enabled ? (left_handed ? 3 : 1) : 0; ++ tap_action[5] = tap_enabled ? (left_handed ? 1 : 3) : 0; ++ tap_action[6] = tap_enabled ? 2 : 0; ++ ++ change_property (device, "Synaptics Tap Action", ++ XA_INTEGER, 8, tap_action, 7); ++ meta_XFree (tap_action); ++ ++ if (display) ++ meta_error_trap_push (display); ++ buttons = g_new (guchar, buttons_capacity); ++ n_buttons = XGetDeviceButtonMapping (xdisplay, xdevice, ++ buttons, buttons_capacity); ++ ++ while (n_buttons > buttons_capacity) ++ { ++ buttons_capacity = n_buttons; ++ buttons = (guchar *) g_realloc (buttons, ++ buttons_capacity * sizeof (guchar)); ++ ++ n_buttons = XGetDeviceButtonMapping (xdisplay, xdevice, ++ buttons, buttons_capacity); ++ } ++ ++ buttons[0] = left_handed ? 3 : 1; ++ buttons[2] = left_handed ? 1 : 3; ++ XSetDeviceButtonMapping (xdisplay, xdevice, buttons, n_buttons); ++ ++ if (display && meta_error_trap_pop_with_return (display)) ++ { ++ g_warning ("Could not set synaptics touchpad left-handed for %s", ++ clutter_input_device_get_device_name (device)); ++ } ++ ++ out: ++ XCloseDevice (xdisplay, xdevice); ++} ++ ++static void ++change_synaptics_speed (ClutterInputDevice *device, ++ gdouble speed) ++{ ++ MetaDisplay *display = meta_get_display (); ++ MetaBackend *backend = meta_get_backend (); ++ Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); ++ XDevice *xdevice; ++ XPtrFeedbackControl feedback; ++ XFeedbackState *states, *state; ++ int i, num_feedbacks, motion_threshold, numerator, denominator; ++ gfloat motion_acceleration; ++ ++ xdevice = XOpenDevice(xdisplay, clutter_input_device_get_device_id (device)); ++ if (!xdevice) ++ return; ++ /* Get the list of feedbacks for the device */ ++ states = XGetFeedbackControl (xdisplay, xdevice, &num_feedbacks); ++ if (!states) ++ return; ++ ++ /* Calculate acceleration and threshold */ ++ motion_acceleration = (speed + 1) * 5; /* speed is [-1..1], map to [0..10] */ ++ motion_threshold = CLAMP (10 - floor (motion_acceleration), 1, 10); ++ ++ if (motion_acceleration >= 1.0) ++ { ++ /* we want to get the acceleration, with a resolution of 0.5 ++ */ ++ if ((motion_acceleration - floor (motion_acceleration)) < 0.25) ++ { ++ numerator = floor (motion_acceleration); ++ denominator = 1; ++ } ++ else if ((motion_acceleration - floor (motion_acceleration)) < 0.5) ++ { ++ numerator = ceil (2.0 * motion_acceleration); ++ denominator = 2; ++ } ++ else if ((motion_acceleration - floor (motion_acceleration)) < 0.75) ++ { ++ numerator = floor (2.0 *motion_acceleration); ++ denominator = 2; ++ } ++ else ++ { ++ numerator = ceil (motion_acceleration); ++ denominator = 1; ++ } ++ } ++ else if (motion_acceleration < 1.0 && motion_acceleration > 0) ++ { ++ /* This we do to 1/10ths */ ++ numerator = floor (motion_acceleration * 10) + 1; ++ denominator= 10; ++ } ++ else ++ { ++ numerator = -1; ++ denominator = -1; ++ } ++ ++ if (display) ++ meta_error_trap_push (display); ++ ++ state = (XFeedbackState *) states; ++ ++ for (i = 0; i < num_feedbacks; i++) ++ { ++ if (state->class == PtrFeedbackClass) ++ { ++ /* And tell the device */ ++ feedback.class = PtrFeedbackClass; ++ feedback.length = sizeof (XPtrFeedbackControl); ++ feedback.id = state->id; ++ feedback.threshold = motion_threshold; ++ feedback.accelNum = numerator; ++ feedback.accelDenom = denominator; ++ ++ XChangeFeedbackControl (xdisplay, xdevice, ++ DvAccelNum | DvAccelDenom | DvThreshold, ++ (XFeedbackControl *) &feedback); ++ break; ++ } ++ ++ state = (XFeedbackState *) ((char *) state + state->length); ++ } ++ ++ if (display && meta_error_trap_pop_with_return (display)) ++ { ++ g_warning ("Could not set synaptics touchpad acceleration for %s", ++ clutter_input_device_get_device_name (device)); ++ } ++ ++ XFreeFeedbackList (states); ++ XCloseDevice (xdisplay, xdevice); ++} ++ + static void + meta_input_settings_x11_set_send_events (MetaInputSettings *settings, + ClutterInputDevice *device, +@@ -126,6 +298,13 @@ meta_input_settings_x11_set_send_events (MetaInputSettings *settings, + guchar values[2] = { 0 }; /* disabled, disabled-on-external-mouse */ + guchar *available; + ++ if (is_device_synaptics (device)) ++ { ++ values[0] = mode != G_DESKTOP_DEVICE_SEND_EVENTS_ENABLED; ++ change_property (device, "Synaptics Off", XA_INTEGER, 8, &values, 1); ++ return; ++ } ++ + available = get_property (device, "libinput Send Events Modes Available", + XA_INTEGER, 8, 2); + if (!available) +@@ -178,6 +357,12 @@ meta_input_settings_x11_set_speed (MetaInputSettings *settings, + Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); + gfloat value = speed; + ++ if (is_device_synaptics (device)) ++ { ++ change_synaptics_speed (device, speed); ++ return; ++ } ++ + change_property (device, "libinput Accel Speed", + XInternAtom (xdisplay, "FLOAT", False), + 32, &value, 1); +@@ -190,6 +375,18 @@ meta_input_settings_x11_set_left_handed (MetaInputSettings *settings, + { + guchar value = (enabled) ? 1 : 0; + ++ if (is_device_synaptics (device)) ++ { ++ GSettings *settings; ++ ++ settings = g_settings_new ("org.gnome.desktop.peripherals.touchpad"); ++ change_synaptics_tap_left_handed (device, ++ g_settings_get_boolean (settings, "tap-to-click"), ++ enabled); ++ g_object_unref (settings); ++ return; ++ } ++ + change_property (device, "libinput Left Handed Enabled", + XA_INTEGER, 8, &value, 1); + } +@@ -201,6 +398,20 @@ meta_input_settings_x11_set_tap_enabled (MetaInputSettings *settings, + { + guchar value = (enabled) ? 1 : 0; + ++ if (is_device_synaptics (device)) ++ { ++ GDesktopTouchpadHandedness handedness; ++ GSettings *settings; ++ ++ settings = g_settings_new ("org.gnome.desktop.peripherals.touchpad"); ++ handedness = g_settings_get_enum (settings, "left-handed"); ++ g_object_unref (settings); ++ ++ change_synaptics_tap_left_handed (device, enabled, ++ handedness == G_DESKTOP_TOUCHPAD_HANDEDNESS_LEFT); ++ return; ++ } ++ + change_property (device, "libinput Tapping Enabled", + XA_INTEGER, 8, &value, 1); + } +@@ -212,6 +423,27 @@ meta_input_settings_x11_set_invert_scroll (MetaInputSettings *settings, + { + guchar value = (inverted) ? 1 : 0; + ++ if (is_device_synaptics (device)) ++ { ++ gint32 *scrolling_distance; ++ ++ scrolling_distance = get_property (device, "Synaptics Scrolling Distance", ++ XA_INTEGER, 32, 2); ++ if (scrolling_distance) ++ { ++ scrolling_distance[0] = inverted ? ++ -abs (scrolling_distance[0]) : abs (scrolling_distance[0]); ++ scrolling_distance[1] = inverted ? ++ -abs (scrolling_distance[1]) : abs (scrolling_distance[1]); ++ ++ change_property (device, "Synaptics Scrolling Distance", ++ XA_INTEGER, 32, scrolling_distance, 2); ++ meta_XFree (scrolling_distance); ++ } ++ ++ return; ++ } ++ + change_property (device, "libinput Natural Scrolling Enabled", + XA_INTEGER, 8, &value, 1); + } +@@ -225,6 +457,22 @@ meta_input_settings_x11_set_edge_scroll (MetaInputSettings *settings, + guchar *current = NULL; + guchar *available = NULL; + ++ if (is_device_synaptics (device)) ++ { ++ current = get_property (device, "Synaptics Edge Scrolling", ++ XA_INTEGER, 8, 3); ++ if (current) ++ { ++ current[0] = !!edge_scroll_enabled; ++ current[1] = !!edge_scroll_enabled; ++ change_property (device, "Synaptics Edge Scrolling", ++ XA_INTEGER, 8, current, 3); ++ meta_XFree (current); ++ } ++ ++ return; ++ } ++ + available = get_property (device, "libinput Scroll Methods Available", + XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS); + if (!available || !available[SCROLL_METHOD_FIELD_EDGE]) +@@ -254,6 +502,22 @@ meta_input_settings_x11_set_two_finger_scroll (MetaInputSettings *set + guchar *current = NULL; + guchar *available = NULL; + ++ if (is_device_synaptics (device)) ++ { ++ current = get_property (device, "Synaptics Two-Finger Scrolling", ++ XA_INTEGER, 8, 2); ++ if (current) ++ { ++ current[0] = !!two_finger_scroll_enabled; ++ current[1] = !!two_finger_scroll_enabled; ++ change_property (device, "Synaptics Two-Finger Scrolling", ++ XA_INTEGER, 8, current, 2); ++ meta_XFree (current); ++ } ++ ++ return; ++ } ++ + available = get_property (device, "libinput Scroll Methods Available", + XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS); + if (!available || !available[SCROLL_METHOD_FIELD_2FG]) +-- +2.9.3 + diff --git a/SOURCES/0001-build-Lower-automake-requirement.patch b/SOURCES/0001-build-Lower-automake-requirement.patch new file mode 100644 index 0000000..f7c7af6 --- /dev/null +++ b/SOURCES/0001-build-Lower-automake-requirement.patch @@ -0,0 +1,25 @@ +From e19b0723e829a102f930af735c9ff6d08ec9232f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Fri, 17 Mar 2017 16:44:11 +0100 +Subject: [PATCH] build: Lower automake requirement + +--- + cogl/configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/cogl/configure.ac b/cogl/configure.ac +index 3ed761c57..1b259af58 100644 +--- a/cogl/configure.ac ++++ b/cogl/configure.ac +@@ -113,7 +113,7 @@ AC_SUBST([WAYLAND_SERVER_REQ_VERSION], [wayland_server_req_version]) + # want to know if the user specified custom cflags or not. + cflags_set=${CFLAGS+set} + +-AM_INIT_AUTOMAKE([1.14 foreign -Wno-portability no-define no-dist-gzip dist-xz tar-ustar subdir-objects]) ++AM_INIT_AUTOMAKE([1.11 foreign -Wno-portability no-define no-dist-gzip dist-xz tar-ustar]) + AM_SILENT_RULES([yes]) + + AH_BOTTOM([#include "config-custom.h"]) +-- +2.12.0 + diff --git a/SOURCES/0001-cally-Fix-translation-to-screen-coordinates.patch b/SOURCES/0001-cally-Fix-translation-to-screen-coordinates.patch new file mode 100644 index 0000000..33370b3 --- /dev/null +++ b/SOURCES/0001-cally-Fix-translation-to-screen-coordinates.patch @@ -0,0 +1,31 @@ +From 59eb6a6ff7d6356213db1ea22616315c215ae4a1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Fri, 28 Apr 2017 17:12:40 +0200 +Subject: [PATCH] cally: Fix translation to screen coordinates + +Due to an accidental swap of an else statement and a preprocessor #else, +the output x coordinate is currently only set when not using the X11 +windowing system, whoops. + +https://bugzilla.gnome.org/show_bug.cgi?id=781902 +--- + clutter/clutter/cally/cally-actor.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/clutter/clutter/cally/cally-actor.c b/clutter/clutter/cally/cally-actor.c +index fe3e27433..8ff5b09e1 100644 +--- a/clutter/clutter/cally/cally-actor.c ++++ b/clutter/clutter/cally/cally-actor.c +@@ -780,8 +780,8 @@ _cally_actor_get_top_level_origin (ClutterActor *actor, + g_warning ("[x11] We were not able to get proper absolute " + "position of the stage"); + } +- else + #else ++ else + { + static gboolean yet_warned = FALSE; + +-- +2.12.2 + diff --git a/SOURCES/0001-clutter-clone-Unset-source-when-source-actor-is-dest.patch b/SOURCES/0001-clutter-clone-Unset-source-when-source-actor-is-dest.patch new file mode 100644 index 0000000..f30481a --- /dev/null +++ b/SOURCES/0001-clutter-clone-Unset-source-when-source-actor-is-dest.patch @@ -0,0 +1,60 @@ +From 82eb06def0b02efec2852aced4f0e609abb12557 Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Thu, 2 Mar 2017 19:18:43 +0100 +Subject: [PATCH] clutter-clone: Unset source when source actor is destroyed + +Otherwise we might be holding on to a source actor that's no longer +fully functioning and cause crashes if for example we try to paint it. + +https://bugzilla.gnome.org/show_bug.cgi?id=779483 +--- + clutter/clutter/clutter-clone.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/clutter/clutter/clutter-clone.c b/clutter/clutter/clutter-clone.c +index af03a4e81..f0eea2459 100644 +--- a/clutter/clutter/clutter-clone.c ++++ b/clutter/clutter/clutter-clone.c +@@ -54,6 +54,7 @@ + struct _ClutterClonePrivate + { + ClutterActor *clone_source; ++ gulong source_destroy_id; + }; + + G_DEFINE_TYPE_WITH_PRIVATE (ClutterClone, clutter_clone, CLUTTER_TYPE_ACTOR) +@@ -377,6 +378,13 @@ clutter_clone_new (ClutterActor *source) + } + + static void ++on_source_destroyed (ClutterActor *source, ++ ClutterClone *self) ++{ ++ clutter_clone_set_source_internal (self, NULL); ++} ++ ++static void + clutter_clone_set_source_internal (ClutterClone *self, + ClutterActor *source) + { +@@ -387,6 +395,8 @@ clutter_clone_set_source_internal (ClutterClone *self, + + if (priv->clone_source != NULL) + { ++ g_signal_handler_disconnect (priv->clone_source, priv->source_destroy_id); ++ priv->source_destroy_id = 0; + _clutter_actor_detach_clone (priv->clone_source, CLUTTER_ACTOR (self)); + g_object_unref (priv->clone_source); + priv->clone_source = NULL; +@@ -396,6 +406,8 @@ clutter_clone_set_source_internal (ClutterClone *self, + { + priv->clone_source = g_object_ref (source); + _clutter_actor_attach_clone (priv->clone_source, CLUTTER_ACTOR (self)); ++ priv->source_destroy_id = g_signal_connect (priv->clone_source, "destroy", ++ G_CALLBACK (on_source_destroyed), self); + } + + g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SOURCE]); +-- +2.13.0 + diff --git a/SOURCES/0001-cogl-Prefer-swizzling-to-convert-BGRA-buffers.patch b/SOURCES/0001-cogl-Prefer-swizzling-to-convert-BGRA-buffers.patch new file mode 100644 index 0000000..5ef1fad --- /dev/null +++ b/SOURCES/0001-cogl-Prefer-swizzling-to-convert-BGRA-buffers.patch @@ -0,0 +1,248 @@ +From 32faf80489f8ee7b4c973660c286f6d228f8e738 Mon Sep 17 00:00:00 2001 +From: Carlos Garnacho +Date: Sat, 25 Feb 2017 23:21:06 +0100 +Subject: [PATCH] cogl: Prefer swizzling to convert BGRA buffers + +(squashed/rebased for gnome-3-22) + +If the GL implementation/hw supports the GL_*_texture_swizzle extension, +pretend that BGRA textures shall contain RGBA data, and let the flipping +happen when the texture will be used in the rendering pipeline. + +This avoids rather expensive format conversions when forcing BGRA buffers +into RGBA textures, which happens rather often with WL_SHM_FORMAT_ARGB8888 +buffers (like gtk+ uses) in little-endian machines. + +In intel/mesa/wayland, the performance improvement is rather noticeable, +CPU% as seen by top decreases from 45-50% to 25-30% when running +gtk+/tests/scrolling-performance with a cairo renderer. + +https://bugzilla.gnome.org/show_bug.cgi?id=779234 +--- + cogl/cogl/cogl-driver.h | 7 +++++ + cogl/cogl/driver/gl/cogl-framebuffer-gl.c | 9 ++++++ + cogl/cogl/driver/gl/cogl-texture-2d-gl.c | 11 ++++---- + cogl/cogl/driver/gl/gl/cogl-driver-gl.c | 37 +++++++++++++++++++++---- + cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c | 12 ++++++++ + cogl/cogl/driver/gl/gles/cogl-driver-gles.c | 26 +++++++++++++---- + cogl/cogl/driver/nop/cogl-driver-nop.c | 1 + + 7 files changed, 87 insertions(+), 16 deletions(-) + +diff --git a/cogl/cogl/cogl-driver.h b/cogl/cogl/cogl-driver.h +index 648228c..85aa0d8 100644 +--- a/cogl/cogl/cogl-driver.h ++++ b/cogl/cogl/cogl-driver.h +@@ -55,6 +55,13 @@ struct _CoglDriverVtable + GLenum *out_glintformat, + GLenum *out_glformat, + GLenum *out_gltype); ++ CoglPixelFormat ++ (* pixel_format_to_gl_with_target) (CoglContext *context, ++ CoglPixelFormat format, ++ CoglPixelFormat target_format, ++ GLenum *out_glintformat, ++ GLenum *out_glformat, ++ GLenum *out_gltype); + + CoglBool + (* update_features) (CoglContext *context, +diff --git a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c +index 18ba08a..2af36f0 100644 +--- a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c ++++ b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c +@@ -1418,6 +1418,15 @@ _cogl_framebuffer_gl_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, + &gl_format, + &gl_type); + ++ /* As we are reading pixels, we want to consider the bitmap according to ++ * its real pixel format, not the swizzled channels we pretend face to the ++ * pipeline. ++ */ ++ if ((format == COGL_PIXEL_FORMAT_BGRA_8888 || ++ format == COGL_PIXEL_FORMAT_BGRA_8888_PRE) && ++ _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE)) ++ gl_format = GL_BGRA; ++ + /* NB: All offscreen rendering is done upside down so there is no need + * to flip in this case... */ + if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_MESA_PACK_INVERT) && +diff --git a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c +index 1193df4..817dd53 100644 +--- a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c ++++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c +@@ -657,11 +657,12 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, + + upload_format = cogl_bitmap_get_format (upload_bmp); + +- ctx->driver_vtable->pixel_format_to_gl (ctx, +- upload_format, +- NULL, /* internal format */ +- &gl_format, +- &gl_type); ++ ctx->driver_vtable->pixel_format_to_gl_with_target (ctx, ++ upload_format, ++ _cogl_texture_get_format (tex), ++ NULL, /* internal gl format */ ++ &gl_format, ++ &gl_type); + + /* If this touches the first pixel then we'll update our copy */ + if (dst_x == 0 && dst_y == 0 && +diff --git a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c +index 2b9a49c..178262a 100644 +--- a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c ++++ b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c +@@ -96,11 +96,12 @@ _cogl_driver_pixel_format_from_gl_internal (CoglContext *context, + } + + static CoglPixelFormat +-_cogl_driver_pixel_format_to_gl (CoglContext *context, +- CoglPixelFormat format, +- GLenum *out_glintformat, +- GLenum *out_glformat, +- GLenum *out_gltype) ++_cogl_driver_pixel_format_to_gl_with_target (CoglContext *context, ++ CoglPixelFormat format, ++ CoglPixelFormat target_format, ++ GLenum *out_glintformat, ++ GLenum *out_glformat, ++ GLenum *out_gltype) + { + CoglPixelFormat required_format; + GLenum glintformat = 0; +@@ -174,7 +175,16 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context, + case COGL_PIXEL_FORMAT_BGRA_8888: + case COGL_PIXEL_FORMAT_BGRA_8888_PRE: + glintformat = GL_RGBA; +- glformat = GL_BGRA; ++ /* If the driver has texture_swizzle, pretend internal ++ * and buffer format are the same here, the pixels ++ * will be flipped through this extension. ++ */ ++ if (target_format == format && ++ _cogl_has_private_feature ++ (context, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE)) ++ glformat = GL_RGBA; ++ else ++ glformat = GL_BGRA; + gltype = GL_UNSIGNED_BYTE; + break; + +@@ -289,6 +299,20 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context, + return required_format; + } + ++static CoglPixelFormat ++_cogl_driver_pixel_format_to_gl (CoglContext *context, ++ CoglPixelFormat format, ++ GLenum *out_glintformat, ++ GLenum *out_glformat, ++ GLenum *out_gltype) ++{ ++ return _cogl_driver_pixel_format_to_gl_with_target (context, ++ format, format, ++ out_glintformat, ++ out_glformat, ++ out_gltype); ++} ++ + static CoglBool + _cogl_get_gl_version (CoglContext *ctx, + int *major_out, +@@ -669,6 +693,7 @@ _cogl_driver_gl = + { + _cogl_driver_pixel_format_from_gl_internal, + _cogl_driver_pixel_format_to_gl, ++ _cogl_driver_pixel_format_to_gl_with_target, + _cogl_driver_update_features, + _cogl_offscreen_gl_allocate, + _cogl_offscreen_gl_free, +diff --git a/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c +index c76a0cf..d5ee4b4 100644 +--- a/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c ++++ b/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c +@@ -114,6 +114,18 @@ _cogl_texture_driver_gen (CoglContext *ctx, + red_swizzle) ); + } + ++ /* If swizzle extension is available, prefer it to flip bgra buffers to rgba */ ++ if ((internal_format == COGL_PIXEL_FORMAT_BGRA_8888 || ++ internal_format == COGL_PIXEL_FORMAT_BGRA_8888_PRE) && ++ _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE)) ++ { ++ static const GLint bgra_swizzle[] = { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA }; ++ ++ GE( ctx, glTexParameteriv (gl_target, ++ GL_TEXTURE_SWIZZLE_RGBA, ++ bgra_swizzle) ); ++ } ++ + return tex; + } + +diff --git a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c +index bf63fcc..521f6ef 100644 +--- a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c ++++ b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c +@@ -67,11 +67,12 @@ _cogl_driver_pixel_format_from_gl_internal (CoglContext *context, + } + + static CoglPixelFormat +-_cogl_driver_pixel_format_to_gl (CoglContext *context, +- CoglPixelFormat format, +- GLenum *out_glintformat, +- GLenum *out_glformat, +- GLenum *out_gltype) ++_cogl_driver_pixel_format_to_gl_with_target (CoglContext *context, ++ CoglPixelFormat format, ++ CoglPixelFormat target_format, ++ GLenum *out_glintformat, ++ GLenum *out_glformat, ++ GLenum *out_gltype) + { + CoglPixelFormat required_format; + GLenum glintformat; +@@ -219,6 +220,20 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context, + return required_format; + } + ++static CoglPixelFormat ++_cogl_driver_pixel_format_to_gl (CoglContext *context, ++ CoglPixelFormat format, ++ GLenum *out_glintformat, ++ GLenum *out_glformat, ++ GLenum *out_gltype) ++{ ++ return _cogl_driver_pixel_format_to_gl_with_target (context, ++ format, format, ++ out_glintformat, ++ out_glformat, ++ out_gltype); ++} ++ + static CoglBool + _cogl_get_gl_version (CoglContext *ctx, + int *major_out, +@@ -457,6 +472,7 @@ _cogl_driver_gles = + { + _cogl_driver_pixel_format_from_gl_internal, + _cogl_driver_pixel_format_to_gl, ++ _cogl_driver_pixel_format_to_gl_with_target, + _cogl_driver_update_features, + _cogl_offscreen_gl_allocate, + _cogl_offscreen_gl_free, +diff --git a/cogl/cogl/driver/nop/cogl-driver-nop.c b/cogl/cogl/driver/nop/cogl-driver-nop.c +index d9b1d0f..6e04e71 100644 +--- a/cogl/cogl/driver/nop/cogl-driver-nop.c ++++ b/cogl/cogl/driver/nop/cogl-driver-nop.c +@@ -61,6 +61,7 @@ _cogl_driver_nop = + { + NULL, /* pixel_format_from_gl_internal */ + NULL, /* pixel_format_to_gl */ ++ NULL, /* pixel_format_to_gl_with_target */ + _cogl_driver_update_features, + _cogl_offscreen_nop_allocate, + _cogl_offscreen_nop_free, +-- +2.9.3 + diff --git a/SOURCES/0001-display-Check-we-have-a-screen-before-freeing-it.patch b/SOURCES/0001-display-Check-we-have-a-screen-before-freeing-it.patch new file mode 100644 index 0000000..5b8c284 --- /dev/null +++ b/SOURCES/0001-display-Check-we-have-a-screen-before-freeing-it.patch @@ -0,0 +1,32 @@ +From 91dced2ea5e4317c0067df28071c7694fb2f35ac Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Fri, 17 Feb 2017 14:24:38 +0100 +Subject: [PATCH] display: Check we have a screen before freeing it + +The reason for the display to be closed may be meta_screen_new() +returning NULL, in which case we don't have a screen to free. +Avoid a segfault on exit by adding a proper check. + +https://bugzilla.gnome.org/show_bug.cgi?id=778831 +--- + src/core/display.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/core/display.c b/src/core/display.c +index 42a530f6c..c6248ce34 100644 +--- a/src/core/display.c ++++ b/src/core/display.c +@@ -1113,7 +1113,9 @@ meta_display_close (MetaDisplay *display, + meta_display_free_events_x11 (display); + meta_display_free_events (display); + +- meta_screen_free (display->screen, timestamp); ++ if (display->screen) ++ meta_screen_free (display->screen, timestamp); ++ display->screen = NULL; + + /* Must be after all calls to meta_window_unmanage() since they + * unregister windows +-- +2.12.0 + diff --git a/SOURCES/0001-events-Don-t-move-sloppy-focus-while-buttons-are-pre.patch b/SOURCES/0001-events-Don-t-move-sloppy-focus-while-buttons-are-pre.patch new file mode 100644 index 0000000..3a6d899 --- /dev/null +++ b/SOURCES/0001-events-Don-t-move-sloppy-focus-while-buttons-are-pre.patch @@ -0,0 +1,42 @@ +From def9c7e2cb32d8aeb7c48f126a43e2ff97fe14e2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 21 Jul 2016 15:43:12 +0200 +Subject: [PATCH] events: Don't move (sloppy) focus while buttons are pressed + +(https://bugzilla.redhat.com/show_bug.cgi?id=1358535) +--- + src/x11/events.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/src/x11/events.c b/src/x11/events.c +index 98f5f03a9..b763af312 100644 +--- a/src/x11/events.c ++++ b/src/x11/events.c +@@ -830,6 +830,16 @@ crossing_serial_is_ignored (MetaDisplay *display, + } + + static gboolean ++event_has_button_mask (XIEnterEvent *enter_event) ++{ ++ int i; ++ for (i = 0; i < enter_event->buttons.mask_len; i++) ++ if (enter_event->buttons.mask[i] != '\0') ++ return TRUE; ++ return FALSE; ++} ++ ++static gboolean + handle_input_xevent (MetaDisplay *display, + XIEvent *input_event, + unsigned long serial) +@@ -870,6 +880,7 @@ handle_input_xevent (MetaDisplay *display, + * avoid races. + */ + if (window && !crossing_serial_is_ignored (display, serial) && ++ !event_has_button_mask (enter_event) && + enter_event->mode != XINotifyGrab && + enter_event->mode != XINotifyUngrab && + enter_event->detail != XINotifyInferior && +-- +2.12.0 + diff --git a/SOURCES/0001-monitor-config-Consider-external-layout-before-defau.patch b/SOURCES/0001-monitor-config-Consider-external-layout-before-defau.patch new file mode 100644 index 0000000..2527d38 --- /dev/null +++ b/SOURCES/0001-monitor-config-Consider-external-layout-before-defau.patch @@ -0,0 +1,127 @@ +From d2cc8089a6fd31e302b23ac787d84ff5a3257b6c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 28 Jan 2016 15:26:33 +0100 +Subject: [PATCH] monitor-config: Consider external layout before default + linear config + +In case of no existing configuration, we use a default layout of +aligning attached displays horizontally. This sidesteps any layout +configuration that is done externally, for instance via xorg.conf, +which is not desirable. Instead, base the initial configuration on +the existing layout if it passes some sanity checks before falling +back to the default linear config. +--- + src/backends/meta-monitor-config.c | 76 +++++++++++++++++++++++++++++--------- + 1 file changed, 59 insertions(+), 17 deletions(-) + +diff --git a/src/backends/meta-monitor-config.c b/src/backends/meta-monitor-config.c +index 21e3126f2..492b0ffe1 100644 +--- a/src/backends/meta-monitor-config.c ++++ b/src/backends/meta-monitor-config.c +@@ -1130,6 +1130,23 @@ init_config_from_preferred_mode (MetaOutputConfig *config, + config->is_presentation = FALSE; + } + ++static void ++init_config_from_output (MetaOutputConfig *config, ++ MetaOutput *output) ++{ ++ config->enabled = (output->crtc != NULL); ++ ++ if (!config->enabled) ++ return; ++ ++ config->rect = output->crtc->rect; ++ config->refresh_rate = output->crtc->current_mode->refresh_rate; ++ config->transform = output->crtc->transform; ++ config->is_primary = output->is_primary; ++ config->is_presentation = output->is_presentation; ++ config->is_underscanning = output->is_underscanning; ++} ++ + /* This function handles configuring the outputs when the driver provides a + * suggested layout position for each output. This is done in recent versions + * of qxl and allows displays to be aligned on the guest in the same order as +@@ -1368,6 +1385,45 @@ extend_stored_config (MetaMonitorConfig *self, + return FALSE; + } + ++static gboolean ++make_initial_config_from_current (MetaMonitorConfig *self, ++ MetaOutput *outputs, ++ unsigned n_outputs, ++ int max_width, ++ int max_height, ++ MetaConfiguration *config) ++{ ++ GList *region = NULL; ++ unsigned i; ++ ++ g_return_val_if_fail (config != NULL, FALSE); ++ ++ if (g_hash_table_size (self->configs) > 0) ++ return FALSE; ++ ++ g_assert (config->n_outputs == n_outputs); ++ ++ for (i = 0; i < n_outputs; i++) ++ { ++ init_config_from_output (&config->outputs[i], &outputs[i]); ++ ++ /* Reject the configuration if the suggested positions result in ++ * overlapping displays */ ++ if (meta_rectangle_overlaps_with_region (region, &config->outputs[i].rect)) ++ { ++ g_warning ("Overlapping outputs, rejecting suggested configuration"); ++ g_list_free (region); ++ return FALSE; ++ } ++ ++ region = g_list_prepend (region, &config->outputs[i].rect); ++ } ++ ++ g_list_free (region); ++ ++ return TRUE; ++} ++ + static MetaConfiguration * + make_default_config (MetaMonitorConfig *self, + MetaOutput *outputs, +@@ -1399,6 +1455,9 @@ make_default_config (MetaMonitorConfig *self, + extend_stored_config (self, outputs, n_outputs, max_width, max_height, ret)) + goto check_limits; + ++ if (make_initial_config_from_current (self, outputs, n_outputs, max_width, max_height, ret)) ++ goto check_limits; ++ + make_linear_config (self, outputs, n_outputs, max_width, max_height, ret); + + check_limits: +@@ -1500,23 +1559,6 @@ meta_monitor_config_make_default (MetaMonitorConfig *self, + } + } + +-static void +-init_config_from_output (MetaOutputConfig *config, +- MetaOutput *output) +-{ +- config->enabled = (output->crtc != NULL); +- +- if (!config->enabled) +- return; +- +- config->rect = output->crtc->rect; +- config->refresh_rate = output->crtc->current_mode->refresh_rate; +- config->transform = output->crtc->transform; +- config->is_primary = output->is_primary; +- config->is_presentation = output->is_presentation; +- config->is_underscanning = output->is_underscanning; +-} +- + void + meta_monitor_config_update_current (MetaMonitorConfig *self, + MetaMonitorManager *manager) +-- +2.12.0 + diff --git a/SOURCES/0001-monitor-manager-xrandr-Force-an-update-when-resuming.patch b/SOURCES/0001-monitor-manager-xrandr-Force-an-update-when-resuming.patch new file mode 100644 index 0000000..c81b5bb --- /dev/null +++ b/SOURCES/0001-monitor-manager-xrandr-Force-an-update-when-resuming.patch @@ -0,0 +1,228 @@ +From 677c216fbf52e5cbc1d5f0890ebc1ee9216cfd27 Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Sun, 25 Oct 2015 16:14:58 +0100 +Subject: [PATCH] monitor-manager-xrandr: Force an update when resuming from + suspend + +The stack below us isn't as reliable as we'd like and in some cases +doesn't generate RRScreenChangeNotify events when e.g. resuming a +laptop on a dock, meaning that we'd miss newly attached outputs. +--- + src/backends/x11/meta-monitor-manager-xrandr.c | 157 +++++++++++++++++++------ + 1 file changed, 122 insertions(+), 35 deletions(-) + +diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c +index 4a27b3a14..aa3ff76f5 100644 +--- a/src/backends/x11/meta-monitor-manager-xrandr.c ++++ b/src/backends/x11/meta-monitor-manager-xrandr.c +@@ -58,6 +58,11 @@ struct _MetaMonitorManagerXrandr + XRRScreenResources *resources; + int rr_event_base; + int rr_error_base; ++ ++ guint logind_watch_id; ++ guint logind_signal_sub_id; ++ ++ gboolean need_hardware_poll; + gboolean has_randr15; + }; + +@@ -763,8 +768,15 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager) + manager->screen_width = WidthOfScreen (screen); + manager->screen_height = HeightOfScreen (screen); + +- resources = XRRGetScreenResourcesCurrent (manager_xrandr->xdisplay, +- DefaultRootWindow (manager_xrandr->xdisplay)); ++ if (manager_xrandr->need_hardware_poll) ++ { ++ resources = XRRGetScreenResources (manager_xrandr->xdisplay, ++ DefaultRootWindow (manager_xrandr->xdisplay)); ++ manager_xrandr->need_hardware_poll = FALSE; ++ } ++ else ++ resources = XRRGetScreenResourcesCurrent (manager_xrandr->xdisplay, ++ DefaultRootWindow (manager_xrandr->xdisplay)); + if (!resources) + return; + +@@ -1414,6 +1426,100 @@ meta_monitor_manager_xrandr_init_monitors(MetaMonitorManagerXrandr *manager_xran + } + #endif + ++static gboolean ++is_xvnc (MetaMonitorManager *manager) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < manager->n_outputs; ++i) ++ if (g_str_has_prefix (manager->outputs[i].name, "VNC-")) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++static void ++meta_monitor_manager_xrandr_update (MetaMonitorManagerXrandr *manager_xrandr) ++{ ++ MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr); ++ gboolean hotplug; ++ unsigned int timestamp; ++ ++ meta_monitor_manager_read_current_config (manager); ++ ++ timestamp = manager_xrandr->resources->timestamp; ++ if (is_xvnc (manager)) ++ timestamp += 100; ++ ++ hotplug = timestamp < manager_xrandr->resources->configTimestamp; ++ if (hotplug) ++ { ++ /* This is a hotplug event, so go ahead and build a new configuration. */ ++ meta_monitor_manager_on_hotplug (manager); ++ } ++ else ++ { ++ /* Something else changed -- tell the world about it. */ ++ meta_monitor_manager_rebuild_derived (manager); ++ } ++} ++ ++static void ++logind_signal_handler (GDBusConnection *connection, ++ const gchar *sender_name, ++ const gchar *object_path, ++ const gchar *interface_name, ++ const gchar *signal_name, ++ GVariant *parameters, ++ gpointer user_data) ++{ ++ MetaMonitorManagerXrandr *manager_xrandr = user_data; ++ gboolean suspending; ++ ++ if (!g_str_equal (signal_name, "PrepareForSleep")) ++ return; ++ ++ g_variant_get (parameters, "(b)", &suspending); ++ if (!suspending) ++ { ++ manager_xrandr->need_hardware_poll = TRUE; ++ meta_monitor_manager_xrandr_update (manager_xrandr); ++ } ++} ++ ++static void ++logind_appeared (GDBusConnection *connection, ++ const gchar *name, ++ const gchar *name_owner, ++ gpointer user_data) ++{ ++ MetaMonitorManagerXrandr *manager_xrandr = user_data; ++ ++ manager_xrandr->logind_signal_sub_id = g_dbus_connection_signal_subscribe (connection, ++ "org.freedesktop.login1", ++ "org.freedesktop.login1.Manager", ++ "PrepareForSleep", ++ "/org/freedesktop/login1", ++ NULL, ++ G_DBUS_SIGNAL_FLAGS_NONE, ++ logind_signal_handler, ++ manager_xrandr, ++ NULL); ++} ++ ++static void ++logind_vanished (GDBusConnection *connection, ++ const gchar *name, ++ gpointer user_data) ++{ ++ MetaMonitorManagerXrandr *manager_xrandr = user_data; ++ ++ if (connection && manager_xrandr->logind_signal_sub_id > 0) ++ g_dbus_connection_signal_unsubscribe (connection, manager_xrandr->logind_signal_sub_id); ++ ++ manager_xrandr->logind_signal_sub_id = 0; ++} ++ + static void + meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr) + { +@@ -1449,6 +1555,15 @@ meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr) + meta_monitor_manager_xrandr_init_monitors (manager_xrandr); + #endif + } ++ ++ manager_xrandr->logind_watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM, ++ "org.freedesktop.login1", ++ G_BUS_NAME_WATCHER_FLAGS_NONE, ++ logind_appeared, ++ logind_vanished, ++ manager_xrandr, ++ NULL); ++ manager_xrandr->need_hardware_poll = TRUE; + } + + static void +@@ -1460,6 +1575,10 @@ meta_monitor_manager_xrandr_finalize (GObject *object) + XRRFreeScreenResources (manager_xrandr->resources); + manager_xrandr->resources = NULL; + ++ if (manager_xrandr->logind_watch_id > 0) ++ g_bus_unwatch_name (manager_xrandr->logind_watch_id); ++ manager_xrandr->logind_watch_id = 0; ++ + G_OBJECT_CLASS (meta_monitor_manager_xrandr_parent_class)->finalize (object); + } + +@@ -1484,48 +1603,16 @@ meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass) + #endif + } + +-static gboolean +-is_xvnc (MetaMonitorManager *manager) +-{ +- unsigned int i; +- +- for (i = 0; i < manager->n_outputs; ++i) +- if (g_str_has_prefix (manager->outputs[i].name, "VNC-")) +- return TRUE; +- +- return FALSE; +-} +- + gboolean + meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr, + XEvent *event) + { +- MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr); +- gboolean hotplug; +- unsigned int timestamp; +- + if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify) + return FALSE; + + XRRUpdateConfiguration (event); + +- meta_monitor_manager_read_current_config (manager); +- +- timestamp = manager_xrandr->resources->timestamp; +- if (is_xvnc (manager)) +- timestamp += 100; +- +- hotplug = timestamp < manager_xrandr->resources->configTimestamp; +- if (hotplug) +- { +- /* This is a hotplug event, so go ahead and build a new configuration. */ +- meta_monitor_manager_on_hotplug (manager); +- } +- else +- { +- /* Something else changed -- tell the world about it. */ +- meta_monitor_manager_rebuild_derived (manager); +- } ++ meta_monitor_manager_xrandr_update (manager_xrandr); + + return TRUE; + } +-- +2.12.0 + diff --git a/SOURCES/0001-monitor-manager-xrandr-Work-around-spurious-hotplugs.patch b/SOURCES/0001-monitor-manager-xrandr-Work-around-spurious-hotplugs.patch new file mode 100644 index 0000000..f77a18f --- /dev/null +++ b/SOURCES/0001-monitor-manager-xrandr-Work-around-spurious-hotplugs.patch @@ -0,0 +1,60 @@ +From 257c8e8d3b7103973dfdc2665d210c63496be457 Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Tue, 6 Oct 2015 21:16:18 +0200 +Subject: [PATCH] monitor-manager-xrandr: Work around spurious hotplugs on Xvnc + +Xvnc turns its outputs off/on on every mode set which makes us believe +there was an hotplug when there actually wasn't. Work around this by +requiring new randr configuration timestamps to be ahead of the last +set timestamp by at least 100 ms for us to consider them an actual +hotplug. +--- + src/backends/x11/meta-monitor-manager-xrandr.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c +index b82120af9..4a27b3a14 100644 +--- a/src/backends/x11/meta-monitor-manager-xrandr.c ++++ b/src/backends/x11/meta-monitor-manager-xrandr.c +@@ -1484,12 +1484,25 @@ meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass) + #endif + } + ++static gboolean ++is_xvnc (MetaMonitorManager *manager) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < manager->n_outputs; ++i) ++ if (g_str_has_prefix (manager->outputs[i].name, "VNC-")) ++ return TRUE; ++ ++ return FALSE; ++} ++ + gboolean + meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr, + XEvent *event) + { + MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr); + gboolean hotplug; ++ unsigned int timestamp; + + if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify) + return FALSE; +@@ -1498,7 +1511,11 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra + + meta_monitor_manager_read_current_config (manager); + +- hotplug = manager_xrandr->resources->timestamp < manager_xrandr->resources->configTimestamp; ++ timestamp = manager_xrandr->resources->timestamp; ++ if (is_xvnc (manager)) ++ timestamp += 100; ++ ++ hotplug = timestamp < manager_xrandr->resources->configTimestamp; + if (hotplug) + { + /* This is a hotplug event, so go ahead and build a new configuration. */ +-- +2.12.0 + diff --git a/SOURCES/0001-screen-Remove-stray-assert.patch b/SOURCES/0001-screen-Remove-stray-assert.patch new file mode 100644 index 0000000..221f9ef --- /dev/null +++ b/SOURCES/0001-screen-Remove-stray-assert.patch @@ -0,0 +1,41 @@ +From fd41db64169f6e0b36d56e054967cb406e32fa74 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Mon, 26 Jun 2017 17:56:36 +0200 +Subject: [PATCH] screen: Remove stray assert + +When the number of (static) workspaces decreases, we relocate windows +from extra workspaces before removing them. As removing a non-empty +workspace is not allowed, we assert that it doesn't contain any windows +before removing it. + +However that assert is + + - pointless, because meta_workspace_remove() already asserts that + the workspace is empty + + - wrong, because even empty workspaces contain windows that are set + to show on all workspaces + +Simply drop the assert to avoid a crash when trying to remove a workspace +while on-all-workspaces windows are present. + +https://bugzilla.gnome.org/show_bug.cgi?id=784223 +--- + src/core/screen.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/core/screen.c b/src/core/screen.c +index d6b5eac53..c6aa9e194 100644 +--- a/src/core/screen.c ++++ b/src/core/screen.c +@@ -1260,7 +1260,6 @@ update_num_workspaces (MetaScreen *screen, + { + MetaWorkspace *w = l->data; + +- g_assert (w->windows == NULL); + meta_workspace_remove (w); + } + +-- +2.13.0 + diff --git a/SOURCES/0001-stack-tracker-Keep-override-redirect-windows-on-top.patch b/SOURCES/0001-stack-tracker-Keep-override-redirect-windows-on-top.patch new file mode 100644 index 0000000..3ee1d5d --- /dev/null +++ b/SOURCES/0001-stack-tracker-Keep-override-redirect-windows-on-top.patch @@ -0,0 +1,83 @@ +From 245a3c2e12b4aad2e752675f82be9517235d5498 Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Fri, 19 May 2017 17:11:19 +0200 +Subject: [PATCH] stack-tracker: Keep override redirect windows on top + +Since commit 6b5cf2e, we keep override redirect windows on a layer +above regular windows in the clutter actor scene graph. In the X +server, and thus for input purposes, these windows might end up being +stacked below regular windows though, e.g. because a new regular +window is mapped after an OR window. + +Fix this disconnect by re-stacking OR windows on top when syncing the +window stack with the compositor. + +https://bugzilla.gnome.org/show_bug.cgi?id=780485 +--- + src/core/stack-tracker.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/src/core/stack-tracker.c b/src/core/stack-tracker.c +index a76b42cbf..82afd644a 100644 +--- a/src/core/stack-tracker.c ++++ b/src/core/stack-tracker.c +@@ -168,6 +168,9 @@ struct _MetaStackTracker + guint sync_stack_later; + }; + ++static void ++meta_stack_tracker_keep_override_redirect_on_top (MetaStackTracker *tracker); ++ + static inline const char * + get_window_desc (MetaStackTracker *tracker, + guint64 window) +@@ -835,6 +838,8 @@ meta_stack_tracker_sync_stack (MetaStackTracker *tracker) + tracker->sync_stack_later = 0; + } + ++ meta_stack_tracker_keep_override_redirect_on_top (tracker); ++ + meta_stack_tracker_get_stack (tracker, &windows, &n_windows); + + meta_windows = NULL; +@@ -1040,6 +1045,37 @@ meta_stack_tracker_lower (MetaStackTracker *tracker, + meta_stack_tracker_raise_above (tracker, window, None); + } + ++static void ++meta_stack_tracker_keep_override_redirect_on_top (MetaStackTracker *tracker) ++{ ++ MetaWindow *window; ++ guint64 *stack; ++ int n_windows, i; ++ int topmost_non_or; ++ ++ meta_stack_tracker_get_stack (tracker, &stack, &n_windows); ++ ++ for (i = n_windows - 1; i >= 0; i--) ++ { ++ window = meta_display_lookup_stack_id (tracker->screen->display, stack[i]); ++ if (window && window->layer != META_LAYER_OVERRIDE_REDIRECT) ++ break; ++ } ++ ++ topmost_non_or = i; ++ ++ for (i -= 1; i >= 0; i--) ++ { ++ window = meta_display_lookup_stack_id (tracker->screen->display, stack[i]); ++ if (window && window->layer == META_LAYER_OVERRIDE_REDIRECT) ++ { ++ meta_stack_tracker_raise_above (tracker, stack[i], stack[topmost_non_or]); ++ meta_stack_tracker_get_stack (tracker, &stack, &n_windows); ++ topmost_non_or -= 1; ++ } ++ } ++} ++ + void + meta_stack_tracker_restack_managed (MetaStackTracker *tracker, + const guint64 *managed, +-- +2.13.0 + diff --git a/SOURCES/0001-wayland-xdg-shell-Handle-the-wl_output-on-the-set_fu.patch b/SOURCES/0001-wayland-xdg-shell-Handle-the-wl_output-on-the-set_fu.patch new file mode 100644 index 0000000..5ef1077 --- /dev/null +++ b/SOURCES/0001-wayland-xdg-shell-Handle-the-wl_output-on-the-set_fu.patch @@ -0,0 +1,42 @@ +From 4ee272a5a88351a03619deae4e5dd4ab16f32b07 Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Wed, 2 Nov 2016 17:55:01 +0100 +Subject: [PATCH] wayland-xdg-shell: Handle the wl_output on the set_fullscreen + request + +This makes us fullscreen wayland windows on the requested monitor. + +https://bugzilla.gnome.org/show_bug.cgi?id=772525 +--- + src/wayland/meta-wayland-xdg-shell.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/wayland/meta-wayland-xdg-shell.c b/src/wayland/meta-wayland-xdg-shell.c +index 450acda..e1195c7 100644 +--- a/src/wayland/meta-wayland-xdg-shell.c ++++ b/src/wayland/meta-wayland-xdg-shell.c +@@ -27,6 +27,7 @@ + + #include "core/window-private.h" + #include "wayland/meta-wayland.h" ++#include "wayland/meta-wayland-outputs.h" + #include "wayland/meta-wayland-popup.h" + #include "wayland/meta-wayland-private.h" + #include "wayland/meta-wayland-seat.h" +@@ -363,6 +364,13 @@ xdg_toplevel_set_fullscreen (struct wl_client *client, + { + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); + ++ if (output_resource) ++ { ++ MetaWaylandOutput *output = wl_resource_get_user_data (output_resource); ++ if (output) ++ meta_window_move_to_monitor (surface->window, output->monitor_info->number); ++ } ++ + meta_window_make_fullscreen (surface->window); + } + +-- +2.9.3 + diff --git a/SOURCES/0001-window-actor-Special-case-shaped-Java-windows.patch b/SOURCES/0001-window-actor-Special-case-shaped-Java-windows.patch new file mode 100644 index 0000000..fad3a5f --- /dev/null +++ b/SOURCES/0001-window-actor-Special-case-shaped-Java-windows.patch @@ -0,0 +1,35 @@ +From 4cd334074a411f1bdc018f74ef51e9ac8dea9fa0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Fri, 12 May 2017 13:40:31 +0200 +Subject: [PATCH] window-actor: Special-case shaped Java windows + +OpenJDK wrongly assumes that shaping a window implies no shadows. +They got lucky until commit b975676c changed the fallback case, +but now their compliance tests are broken. Make them happy again +by special-casing shaped Java windows. +--- + src/compositor/meta-window-actor.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c +index 7595adb66..8768b477c 100644 +--- a/src/compositor/meta-window-actor.c ++++ b/src/compositor/meta-window-actor.c +@@ -842,6 +842,14 @@ meta_window_actor_has_shadow (MetaWindowActor *self) + return FALSE; + + /* ++ * OpenJDK wrongly assumes that shaping a window implies no compositor ++ * shadows; make its compliance tests happy to give it what it wants ... ++ */ ++ if (g_strcmp0 (priv->window->res_name, "sun-awt-X11-XWindowPeer") == 0 && ++ priv->window->shape_region != NULL) ++ return FALSE; ++ ++ /* + * Generate shadows for all other windows. + */ + return TRUE; +-- +2.12.2 + diff --git a/SOURCES/0008-Add-support-for-quad-buffer-stereo.patch b/SOURCES/0008-Add-support-for-quad-buffer-stereo.patch new file mode 100644 index 0000000..1a44410 --- /dev/null +++ b/SOURCES/0008-Add-support-for-quad-buffer-stereo.patch @@ -0,0 +1,978 @@ +From 1292ea32ce34e804b709af0cdbc9fda87d142e9b Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Thu, 8 May 2014 18:44:15 -0400 +Subject: [PATCH 8/8] Add support for quad-buffer stereo + +Track the stereo status of windows using the new EXT_stereo_tree +GLX extension. + +When stereo is enabled or disabled, a restart is triggered via +meta_restart() after a timeout, setting a _META_ENABLE_STEREO +property on the root window to indicate whether we should +turn on a stereo stage for clutter. The property avoids a loop, +since we need to enable stereo *before* initializing Clutter and GL, +but we need GL to figure out whether we have stereo windows. + +Stereo windows are drawn to the stage using new functionality +in Cogl to setup a stereo context, select which buffer to draw +to, and draw either the left or right buffer of a stereo +texture_from_pixmap. +--- + src/Makefile.am | 2 + + src/compositor/compositor-private.h | 9 ++ + src/compositor/compositor.c | 128 ++++++++++++++++++++++ + src/compositor/meta-shaped-texture-private.h | 5 +- + src/compositor/meta-shaped-texture.c | 157 ++++++++++++++++++++------- + src/compositor/meta-surface-actor-wayland.c | 2 +- + src/compositor/meta-surface-actor-x11.c | 56 ++++++++-- + src/compositor/meta-surface-actor-x11.h | 5 + + src/compositor/meta-window-actor-private.h | 5 + + src/compositor/meta-window-actor.c | 22 ++++ + src/core/main.c | 4 + + src/core/stereo.c | 153 ++++++++++++++++++++++++++ + src/core/stereo.h | 28 +++++ + 13 files changed, 526 insertions(+), 50 deletions(-) + create mode 100644 src/core/stereo.c + create mode 100644 src/core/stereo.h + +diff --git a/src/Makefile.am b/src/Makefile.am +index da4e3df..aea37da 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -233,6 +233,8 @@ libmutter_la_SOURCES = \ + core/stack.h \ + core/stack-tracker.c \ + core/stack-tracker.h \ ++ core/stereo.c \ ++ core/stereo.h \ + core/util.c \ + meta/util.h \ + core/util-private.h \ +diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h +index 4629fa5..27813ba 100644 +--- a/src/compositor/compositor-private.h ++++ b/src/compositor/compositor-private.h +@@ -21,6 +21,10 @@ struct _MetaCompositor + gint64 server_time_query_time; + gint64 server_time_offset; + ++ int glx_opcode; ++ guint stereo_tree_ext : 1; ++ guint have_stereo_windows : 1; ++ + guint server_time_is_monotonic_time : 1; + guint no_mipmaps : 1; + +@@ -59,6 +63,11 @@ void meta_end_modal_for_plugin (MetaCompositor *compositor, + gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display, + gint64 monotonic_time); + ++gboolean meta_compositor_window_is_stereo (MetaScreen *screen, ++ Window xwindow); ++void meta_compositor_select_stereo_notify (MetaScreen *screen, ++ Window xwindow); ++ + void meta_compositor_flash_window (MetaCompositor *compositor, + MetaWindow *window); + +diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c +index f001dfd..f8198d5 100644 +--- a/src/compositor/compositor.c ++++ b/src/compositor/compositor.c +@@ -70,6 +70,8 @@ + #include "meta-window-group.h" + #include "window-private.h" /* to check window->hidden */ + #include "display-private.h" /* for meta_display_lookup_x_window() and meta_display_cancel_touch() */ ++#include "stack-tracker.h" ++#include "stereo.h" + #include "util-private.h" + #include "frame.h" + #include +@@ -477,6 +479,97 @@ redirect_windows (MetaScreen *screen) + } + } + ++#define GLX_STEREO_TREE_EXT 0x20F5 ++#define GLX_STEREO_NOTIFY_MASK_EXT 0x00000001 ++#define GLX_STEREO_NOTIFY_EXT 0x00000000 ++ ++typedef struct { ++ int type; ++ unsigned long serial; ++ Bool send_event; ++ Display *display; ++ int extension; ++ int evtype; ++ Drawable window; ++ Bool stereo_tree; ++} StereoNotifyEvent; ++ ++static gboolean ++screen_has_stereo_tree_ext (MetaScreen *screen) ++{ ++ MetaDisplay *display = meta_screen_get_display (screen); ++ Display *xdisplay = meta_display_get_xdisplay (display); ++ const char *extensions_string; ++ ++ static const char * (*query_extensions_string) (Display *display, ++ int screen); ++ ++ if (query_extensions_string == NULL) ++ query_extensions_string = ++ (const char * (*) (Display *, int)) ++ cogl_get_proc_address ("glXQueryExtensionsString"); ++ ++ extensions_string = query_extensions_string (xdisplay, ++ meta_screen_get_screen_number (screen)); ++ ++ return strstr (extensions_string, "EXT_stereo_tree") != 0; ++} ++ ++#include ++ ++gboolean ++meta_compositor_window_is_stereo (MetaScreen *screen, ++ Window xwindow) ++{ ++ MetaCompositor *compositor = get_compositor_for_screen (screen); ++ MetaDisplay *display = meta_screen_get_display (screen); ++ Display *xdisplay = meta_display_get_xdisplay (display); ++ ++ static int (*query_drawable) (Display *dpy, ++ Drawable draw, ++ int attribute, ++ unsigned int *value); ++ ++ if (compositor->stereo_tree_ext) ++ { ++ unsigned int stereo_tree = 0; ++ ++ if (query_drawable == NULL) ++ query_drawable = ++ (int (*) (Display *, Drawable, int, unsigned int *)) ++ cogl_get_proc_address ("glXQueryDrawable"); ++ ++ query_drawable (xdisplay, xwindow, GLX_STEREO_TREE_EXT, &stereo_tree); ++ ++ return stereo_tree != 0; ++ } ++ else ++ return FALSE; ++} ++ ++void ++meta_compositor_select_stereo_notify (MetaScreen *screen, ++ Window xwindow) ++{ ++ MetaCompositor *compositor = get_compositor_for_screen (screen); ++ MetaDisplay *display = meta_screen_get_display (screen); ++ Display *xdisplay = meta_display_get_xdisplay (display); ++ ++ static void (*select_event) (Display *dpy, ++ Drawable draw, ++ unsigned long event_mask); ++ ++ if (compositor->stereo_tree_ext) ++ { ++ if (select_event == NULL) ++ select_event = ++ (void (*) (Display *, Drawable, unsigned long)) ++ cogl_get_proc_address ("glXSelectEvent"); ++ ++ select_event (xdisplay, xwindow, GLX_STEREO_NOTIFY_MASK_EXT); ++ } ++} ++ + void + meta_compositor_manage (MetaCompositor *compositor) + { +@@ -485,6 +578,8 @@ meta_compositor_manage (MetaCompositor *compositor) + MetaScreen *screen = display->screen; + MetaBackend *backend = meta_get_backend (); + ++ compositor->stereo_tree_ext = screen_has_stereo_tree_ext (screen); ++ + meta_screen_set_cm_selection (display->screen); + + compositor->stage = meta_backend_get_stage (backend); +@@ -749,6 +844,23 @@ meta_compositor_process_event (MetaCompositor *compositor, + if (window) + process_damage (compositor, (XDamageNotifyEvent *) event, window); + } ++ else if (!meta_is_wayland_compositor () && ++ event->type == GenericEvent && ++ event->xcookie.extension == compositor->glx_opcode) ++ { ++ if (event->xcookie.evtype == GLX_STEREO_NOTIFY_EXT) ++ { ++ StereoNotifyEvent *stereo_event = (StereoNotifyEvent *)(event->xcookie.data); ++ window = meta_display_lookup_x_window (compositor->display, stereo_event->window); ++ ++ if (window != NULL) ++ { ++ MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); ++ meta_window_actor_stereo_notify (window_actor, stereo_event->stereo_tree); ++ meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker); ++ } ++ } ++ } + + if (compositor->have_x11_sync_object) + meta_sync_ring_handle_event (event); +@@ -923,6 +1035,7 @@ meta_compositor_sync_stack (MetaCompositor *compositor, + GList *stack) + { + GList *old_stack; ++ int stereo_window_count = 0; + + /* This is painful because hidden windows that we are in the process + * of animating out of existence. They'll be at the bottom of the +@@ -998,12 +1111,16 @@ meta_compositor_sync_stack (MetaCompositor *compositor, + * near the front of the other.) + */ + compositor->windows = g_list_prepend (compositor->windows, actor); ++ if (meta_window_actor_is_stereo (actor)) ++ stereo_window_count++; + + stack = g_list_remove (stack, window); + old_stack = g_list_remove (old_stack, actor); + } + + sync_actor_stacking (compositor); ++ ++ meta_stereo_set_have_stereo_windows (stereo_window_count > 0); + } + + void +@@ -1193,6 +1310,17 @@ meta_compositor_new (MetaDisplay *display) + meta_post_paint_func, + compositor, + NULL); ++ if (!meta_is_wayland_compositor ()) ++ { ++ Display *xdisplay = meta_display_get_xdisplay (display); ++ int glx_major_opcode, glx_first_event, glx_first_error; ++ ++ if (XQueryExtension (xdisplay, ++ "GLX", ++ &glx_major_opcode, &glx_first_event, &glx_first_error)) ++ compositor->glx_opcode = glx_major_opcode; ++ } ++ + return compositor; + } + +diff --git a/src/compositor/meta-shaped-texture-private.h b/src/compositor/meta-shaped-texture-private.h +index 1a841de..79912e7 100644 +--- a/src/compositor/meta-shaped-texture-private.h ++++ b/src/compositor/meta-shaped-texture-private.h +@@ -30,8 +30,9 @@ + #include + + ClutterActor *meta_shaped_texture_new (void); +-void meta_shaped_texture_set_texture (MetaShapedTexture *stex, +- CoglTexture *texture); ++void meta_shaped_texture_set_textures (MetaShapedTexture *stex, ++ CoglTexture *texture, ++ CoglTexture *texture_right); + void meta_shaped_texture_set_fallback_size (MetaShapedTexture *stex, + guint fallback_width, + guint fallback_height); +diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c +index 5b2630b..830aa67 100644 +--- a/src/compositor/meta-shaped-texture.c ++++ b/src/compositor/meta-shaped-texture.c +@@ -74,8 +74,10 @@ static guint signals[LAST_SIGNAL]; + struct _MetaShapedTexturePrivate + { + MetaTextureTower *paint_tower; ++ MetaTextureTower *paint_tower_right; + + CoglTexture *texture; ++ CoglTexture *texture_right; + CoglTexture *mask_texture; + + /* The region containing only fully opaque pixels */ +@@ -122,8 +124,10 @@ meta_shaped_texture_init (MetaShapedTexture *self) + priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self); + + priv->paint_tower = meta_texture_tower_new (); ++ priv->paint_tower_right = NULL; /* demand create */ + + priv->texture = NULL; ++ priv->texture_right = NULL; + priv->mask_texture = NULL; + priv->create_mipmaps = TRUE; + } +@@ -173,11 +177,11 @@ meta_shaped_texture_dispose (GObject *object) + MetaShapedTexture *self = (MetaShapedTexture *) object; + MetaShapedTexturePrivate *priv = self->priv; + +- if (priv->paint_tower) +- meta_texture_tower_free (priv->paint_tower); +- priv->paint_tower = NULL; ++ g_clear_pointer (&priv->paint_tower, meta_texture_tower_free); ++ g_clear_pointer (&priv->paint_tower_right, meta_texture_tower_free); + + g_clear_pointer (&priv->texture, cogl_object_unref); ++ g_clear_pointer (&priv->texture_right, cogl_object_unref); + g_clear_pointer (&priv->opaque_region, cairo_region_destroy); + + meta_shaped_texture_set_mask_texture (self, NULL); +@@ -271,8 +275,9 @@ paint_clipped_rectangle (CoglFramebuffer *fb, + } + + static void +-set_cogl_texture (MetaShapedTexture *stex, +- CoglTexture *cogl_tex) ++set_cogl_textures (MetaShapedTexture *stex, ++ CoglTexture *cogl_tex, ++ CoglTexture *cogl_tex_right) + { + MetaShapedTexturePrivate *priv; + guint width, height; +@@ -283,8 +288,11 @@ set_cogl_texture (MetaShapedTexture *stex, + + if (priv->texture) + cogl_object_unref (priv->texture); ++ if (priv->texture_right) ++ cogl_object_unref (priv->texture_right); + + priv->texture = cogl_tex; ++ priv->texture_right = cogl_tex_right; + + if (cogl_tex != NULL) + { +@@ -298,6 +306,9 @@ set_cogl_texture (MetaShapedTexture *stex, + height = 0; + } + ++ if (cogl_tex_right != NULL) ++ cogl_object_ref (cogl_tex_right); ++ + if (priv->tex_width != width || + priv->tex_height != height) + { +@@ -313,52 +324,41 @@ set_cogl_texture (MetaShapedTexture *stex, + * previous buffer. We only queue a redraw in response to surface + * damage. */ + ++ if (cogl_tex_right != NULL) ++ { ++ if (priv->paint_tower_right == NULL) ++ priv->paint_tower_right = meta_texture_tower_new (); ++ } ++ else ++ { ++ g_clear_pointer (&priv->paint_tower_right, meta_texture_tower_free); ++ } ++ + if (priv->create_mipmaps) +- meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex); ++ { ++ meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex); ++ ++ if (priv->paint_tower_right) ++ meta_texture_tower_set_base_texture (priv->paint_tower_right, cogl_tex_right); ++ } + } + + static void +-meta_shaped_texture_paint (ClutterActor *actor) ++paint_texture (MetaShapedTexture *stex, ++ CoglTexture *paint_tex) + { +- MetaShapedTexture *stex = (MetaShapedTexture *) actor; ++ ClutterActor *actor = CLUTTER_ACTOR (stex); + MetaShapedTexturePrivate *priv = stex->priv; + guint tex_width, tex_height; + guchar opacity; + CoglContext *ctx; + CoglFramebuffer *fb; +- CoglTexture *paint_tex; + ClutterActorBox alloc; + CoglPipelineFilter filter; + + if (priv->clip_region && cairo_region_is_empty (priv->clip_region)) + return; + +- if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex))) +- clutter_actor_realize (CLUTTER_ACTOR (stex)); +- +- /* The GL EXT_texture_from_pixmap extension does allow for it to be +- * used together with SGIS_generate_mipmap, however this is very +- * rarely supported. Also, even when it is supported there +- * are distinct performance implications from: +- * +- * - Updating mipmaps that we don't need +- * - Having to reallocate pixmaps on the server into larger buffers +- * +- * So, we just unconditionally use our mipmap emulation code. If we +- * wanted to use SGIS_generate_mipmap, we'd have to query COGL to +- * see if it was supported (no API currently), and then if and only +- * if that was the case, set the clutter texture quality to HIGH. +- * Setting the texture quality to high without SGIS_generate_mipmap +- * support for TFP textures will result in fallbacks to XGetImage. +- */ +- if (priv->create_mipmaps) +- paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower); +- else +- paint_tex = COGL_TEXTURE (priv->texture); +- +- if (paint_tex == NULL) +- return; +- + tex_width = priv->tex_width; + tex_height = priv->tex_height; + +@@ -519,6 +519,76 @@ meta_shaped_texture_paint (ClutterActor *actor) + } + + static void ++meta_shaped_texture_paint (ClutterActor *actor) ++{ ++ MetaShapedTexture *stex = (MetaShapedTexture *) actor; ++ MetaShapedTexturePrivate *priv = stex->priv; ++ CoglFramebuffer *fb; ++ gboolean stereo; ++ CoglTexture *paint_tex; ++ CoglTexture *paint_tex_right; ++ ++ if (priv->clip_region && cairo_region_is_empty (priv->clip_region)) ++ return; ++ ++ if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex))) ++ clutter_actor_realize (CLUTTER_ACTOR (stex)); ++ ++ /* The GL EXT_texture_from_pixmap extension does allow for it to be ++ * used together with SGIS_generate_mipmap, however this is very ++ * rarely supported. Also, even when it is supported there ++ * are distinct performance implications from: ++ * ++ * - Updating mipmaps that we don't need ++ * - Having to reallocate pixmaps on the server into larger buffers ++ * ++ * So, we just unconditionally use our mipmap emulation code. If we ++ * wanted to use SGIS_generate_mipmap, we'd have to query COGL to ++ * see if it was supported (no API currently), and then if and only ++ * if that was the case, set the clutter texture quality to HIGH. ++ * Setting the texture quality to high without SGIS_generate_mipmap ++ * support for TFP textures will result in fallbacks to XGetImage. ++ */ ++ if (priv->create_mipmaps) ++ paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower); ++ else ++ paint_tex = COGL_TEXTURE (priv->texture); ++ ++ if (paint_tex == NULL) ++ return; ++ ++ fb = cogl_get_draw_framebuffer (); ++ ++ stereo = priv->texture_right && cogl_framebuffer_get_is_stereo (fb); ++ ++ if (stereo) ++ { ++ if (priv->create_mipmaps) ++ paint_tex_right = meta_texture_tower_get_paint_texture (priv->paint_tower_right); ++ else ++ paint_tex_right = COGL_TEXTURE (priv->texture_right); ++ } ++ else ++ paint_tex_right = NULL; ++ ++ if (paint_tex != NULL) ++ { ++ if (stereo) ++ cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_LEFT); ++ paint_texture (stex, paint_tex); ++ if (stereo) ++ cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_BOTH); ++ } ++ ++ if (paint_tex_right != NULL) ++ { ++ cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_RIGHT); ++ paint_texture (stex, paint_tex_right); ++ cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_BOTH); ++ } ++} ++ ++static void + meta_shaped_texture_get_preferred_width (ClutterActor *self, + gfloat for_height, + gfloat *min_width_p, +@@ -637,6 +707,12 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex, + priv->create_mipmaps = create_mipmaps; + base_texture = create_mipmaps ? priv->texture : NULL; + meta_texture_tower_set_base_texture (priv->paint_tower, base_texture); ++ ++ if (priv->paint_tower_right) ++ { ++ base_texture = create_mipmaps ? priv->texture_right : NULL; ++ meta_texture_tower_set_base_texture (priv->paint_tower_right, base_texture); ++ } + } + } + +@@ -702,6 +778,8 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, + return FALSE; + + meta_texture_tower_update_area (priv->paint_tower, x, y, width, height); ++ if (priv->paint_tower_right) ++ meta_texture_tower_update_area (priv->paint_tower_right, x, y, width, height); + + unobscured_region = effective_unobscured_region (stex); + if (unobscured_region) +@@ -734,17 +812,18 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, + } + + /** +- * meta_shaped_texture_set_texture: ++ * meta_shaped_texture_set_textures: + * @stex: The #MetaShapedTexture + * @pixmap: The #CoglTexture to display + */ + void +-meta_shaped_texture_set_texture (MetaShapedTexture *stex, +- CoglTexture *texture) ++meta_shaped_texture_set_textures (MetaShapedTexture *stex, ++ CoglTexture *texture, ++ CoglTexture *texture_right) + { + g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); + +- set_cogl_texture (stex, texture); ++ set_cogl_textures (stex, texture, texture_right); + } + + /** +diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c +index 33036d8..f38c7d3 100644 +--- a/src/compositor/meta-surface-actor-wayland.c ++++ b/src/compositor/meta-surface-actor-wayland.c +@@ -477,7 +477,7 @@ meta_surface_actor_wayland_set_texture (MetaSurfaceActorWayland *self, + CoglTexture *texture) + { + MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); +- meta_shaped_texture_set_texture (stex, texture); ++ meta_shaped_texture_set_textures (stex, texture, NULL); + } + + MetaWaylandSurface * +diff --git a/src/compositor/meta-surface-actor-x11.c b/src/compositor/meta-surface-actor-x11.c +index d32aeb6..52db380 100644 +--- a/src/compositor/meta-surface-actor-x11.c ++++ b/src/compositor/meta-surface-actor-x11.c +@@ -31,6 +31,7 @@ + #include + + #include ++#include "compositor-private.h" + #include "window-private.h" + #include "meta-shaped-texture-private.h" + #include "meta-cullable.h" +@@ -43,6 +44,7 @@ struct _MetaSurfaceActorX11Private + MetaDisplay *display; + + CoglTexture *texture; ++ CoglTexture *texture_right; + Pixmap pixmap; + Damage damage; + +@@ -58,6 +60,8 @@ struct _MetaSurfaceActorX11Private + guint size_changed : 1; + + guint unredirected : 1; ++ ++ guint stereo : 1; + }; + typedef struct _MetaSurfaceActorX11Private MetaSurfaceActorX11Private; + +@@ -94,7 +98,7 @@ detach_pixmap (MetaSurfaceActorX11 *self) + * you are supposed to be able to free a GLXPixmap after freeing the underlying + * pixmap, but it certainly doesn't work with current DRI/Mesa + */ +- meta_shaped_texture_set_texture (stex, NULL); ++ meta_shaped_texture_set_textures (stex, NULL, NULL); + cogl_flush (); + + meta_error_trap_push (display); +@@ -103,6 +107,7 @@ detach_pixmap (MetaSurfaceActorX11 *self) + meta_error_trap_pop (display); + + g_clear_pointer (&priv->texture, cogl_object_unref); ++ g_clear_pointer (&priv->texture_right, cogl_object_unref); + } + + static void +@@ -114,23 +119,35 @@ set_pixmap (MetaSurfaceActorX11 *self, + CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); + CoglError *error = NULL; +- CoglTexture *texture; ++ CoglTexturePixmapX11 *texture; ++ CoglTexturePixmapX11 *texture_right; + + g_assert (priv->pixmap == None); + priv->pixmap = pixmap; + +- texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->pixmap, FALSE, &error)); ++ if (priv->stereo) ++ texture = cogl_texture_pixmap_x11_new_left (ctx, pixmap, FALSE, &error); ++ else ++ texture = cogl_texture_pixmap_x11_new (ctx, pixmap, FALSE, &error); ++ ++ if (priv->stereo) ++ texture_right = cogl_texture_pixmap_x11_new_right (texture); ++ else ++ texture_right = NULL; + + if (error != NULL) + { + g_warning ("Failed to allocate stex texture: %s", error->message); + cogl_error_free (error); + } +- else if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture)))) ++ else if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (texture))) + g_warning ("NOTE: Not using GLX TFP!\n"); + +- priv->texture = texture; +- meta_shaped_texture_set_texture (stex, texture); ++ priv->texture = COGL_TEXTURE (texture); ++ if (priv->stereo) ++ priv->texture_right = COGL_TEXTURE (texture_right); ++ ++ meta_shaped_texture_set_textures (stex, COGL_TEXTURE (texture), COGL_TEXTURE (texture_right)); + } + + static void +@@ -433,8 +450,8 @@ reset_texture (MetaSurfaceActorX11 *self) + /* Setting the texture to NULL will cause all the FBO's cached by the + * shaped texture's MetaTextureTower to be discarded and recreated. + */ +- meta_shaped_texture_set_texture (stex, NULL); +- meta_shaped_texture_set_texture (stex, priv->texture); ++ meta_shaped_texture_set_textures (stex, NULL, NULL); ++ meta_shaped_texture_set_textures (stex, priv->texture, priv->texture_right); + } + + MetaSurfaceActor * +@@ -443,12 +460,17 @@ meta_surface_actor_x11_new (MetaWindow *window) + MetaSurfaceActorX11 *self = g_object_new (META_TYPE_SURFACE_ACTOR_X11, NULL); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = meta_window_get_display (window); ++ Window xwindow; + + g_assert (!meta_is_wayland_compositor ()); + + priv->window = window; + priv->display = display; + ++ xwindow = meta_window_x11_get_toplevel_xwindow (window); ++ priv->stereo = meta_compositor_window_is_stereo (display->screen, xwindow); ++ meta_compositor_select_stereo_notify (display->screen, xwindow); ++ + g_signal_connect_object (priv->display, "gl-video-memory-purged", + G_CALLBACK (reset_texture), self, G_CONNECT_SWAPPED); + +@@ -479,3 +501,21 @@ meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self, + priv->last_height = height; + meta_shaped_texture_set_fallback_size (stex, width, height); + } ++ ++void ++meta_surface_actor_x11_stereo_notify (MetaSurfaceActorX11 *self, ++ gboolean stereo_tree) ++{ ++ MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); ++ ++ priv->stereo = stereo_tree != FALSE; ++ detach_pixmap (self); ++} ++ ++gboolean ++meta_surface_actor_x11_is_stereo (MetaSurfaceActorX11 *self) ++{ ++ MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); ++ ++ return priv->stereo; ++} +diff --git a/src/compositor/meta-surface-actor-x11.h b/src/compositor/meta-surface-actor-x11.h +index 0e692ee..4b2eccc 100644 +--- a/src/compositor/meta-surface-actor-x11.h ++++ b/src/compositor/meta-surface-actor-x11.h +@@ -64,6 +64,11 @@ MetaSurfaceActor * meta_surface_actor_x11_new (MetaWindow *window); + void meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self, + int width, int height); + ++void meta_surface_actor_x11_stereo_notify (MetaSurfaceActorX11 *self, ++ gboolean stereo_tree); ++ ++gboolean meta_surface_actor_x11_is_stereo (MetaSurfaceActorX11 *self); ++ + G_END_DECLS + + #endif /* __META_SURFACE_ACTOR_X11_H__ */ +diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h +index 72dcd14..035d756 100644 +--- a/src/compositor/meta-window-actor-private.h ++++ b/src/compositor/meta-window-actor-private.h +@@ -59,4 +59,9 @@ void meta_window_actor_effect_completed (MetaWindowActor *actor, + MetaSurfaceActor *meta_window_actor_get_surface (MetaWindowActor *self); + void meta_window_actor_update_surface (MetaWindowActor *self); + ++void meta_window_actor_stereo_notify (MetaWindowActor *actor, ++ gboolean stereo_tree); ++ ++gboolean meta_window_actor_is_stereo (MetaWindowActor *actor); ++ + #endif /* META_WINDOW_ACTOR_PRIVATE_H */ +diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c +index 9395caa..f763964 100644 +--- a/src/compositor/meta-window-actor.c ++++ b/src/compositor/meta-window-actor.c +@@ -2146,3 +2146,25 @@ meta_window_actor_sync_updates_frozen (MetaWindowActor *self) + + meta_window_actor_set_updates_frozen (self, meta_window_updates_are_frozen (window)); + } ++ ++void ++meta_window_actor_stereo_notify (MetaWindowActor *self, ++ gboolean stereo_tree) ++{ ++ MetaWindowActorPrivate *priv = self->priv; ++ ++ if (META_IS_SURFACE_ACTOR_X11 (priv->surface)) ++ meta_surface_actor_x11_stereo_notify (META_SURFACE_ACTOR_X11 (priv->surface), ++ stereo_tree); ++} ++ ++gboolean ++meta_window_actor_is_stereo (MetaWindowActor *self) ++{ ++ MetaWindowActorPrivate *priv = self->priv; ++ ++ if (META_IS_SURFACE_ACTOR_X11 (priv->surface)) ++ return meta_surface_actor_x11_is_stereo (META_SURFACE_ACTOR_X11 (priv->surface)); ++ else ++ return FALSE; ++} +diff --git a/src/core/main.c b/src/core/main.c +index 25586be..23d9d6d 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -47,6 +47,7 @@ + #include + #include "util-private.h" + #include "display-private.h" ++#include "stereo.h" + #include + #include "ui.h" + #include +@@ -490,6 +491,9 @@ meta_init (void) + + meta_init_backend (backend_type); + ++ if (!meta_is_wayland_compositor ()) ++ meta_stereo_init (); ++ + meta_clutter_init (); + + #ifdef HAVE_WAYLAND +diff --git a/src/core/stereo.c b/src/core/stereo.c +new file mode 100644 +index 0000000..5a232b6 +--- /dev/null ++++ b/src/core/stereo.c +@@ -0,0 +1,153 @@ ++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ ++ ++/* ++ * Copyright (C) 2014 Red Hat, Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++ ++/* ++ * SECTION:stereo ++ * @short_description: Keep track of whether we are a stereo compositor ++ * ++ * With GLX, we need to use a different GL context for stereo and ++ * non-stereo support. Support for multiple GL contexts is unfinished ++ * in Cogl and entirely lacking in Clutter, so it's by far easier ++ * to just restart Mutter when we detect a stereo window. ++ * ++ * A property _MUTTER_ENABLE_STEREO is maintained on the root window ++ * to know whether we should initialize clutter for stereo or not. ++ * When the presence or absence of stereo windows mismatches the ++ * stereo-enabled state for a sufficiently long period of time, ++ * we restart Mutter. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include "ui.h" ++#include ++#include "display-private.h" ++#include "stereo.h" ++#include "util-private.h" ++ ++static guint stereo_switch_id = 0; ++static gboolean stereo_enabled = FALSE; ++/* -1 so the first time meta_stereo_set_have_stereo_windows() is called ++ * we avoid the short-circuit and set up a timeout to restart ++ * if necessary */ ++static gboolean stereo_have_windows = (gboolean)-1; ++static gboolean stereo_restart = FALSE; ++ ++#define STEREO_ENABLE_WAIT 1000 ++#define STEREO_DISABLE_WAIT 5000 ++ ++void ++meta_stereo_init (void) ++{ ++ Display *xdisplay; ++ Window root; ++ Atom atom_enable_stereo; ++ Atom type; ++ int format; ++ unsigned long n_items, bytes_after; ++ guchar *data; ++ ++ xdisplay = XOpenDisplay (NULL); ++ if (xdisplay == NULL) ++ meta_fatal ("Unable to open X display %s\n", XDisplayName (NULL)); ++ ++ root = DefaultRootWindow (xdisplay); ++ atom_enable_stereo = XInternAtom (xdisplay, "_MUTTER_ENABLE_STEREO", False); ++ ++ XGetWindowProperty (xdisplay, root, atom_enable_stereo, ++ 0, 1, False, XA_INTEGER, ++ &type, &format, &n_items, &bytes_after, &data); ++ if (type == XA_INTEGER) ++ { ++ if (format == 32 && n_items == 1 && bytes_after == 0) ++ { ++ stereo_enabled = *(long *)data; ++ } ++ else ++ { ++ meta_warning ("Bad value for _MUTTER_ENABLE_STEREO property\n"); ++ } ++ ++ XFree (data); ++ } ++ else if (type != None) ++ { ++ meta_warning ("Bad type for _MUTTER_ENABLE_STEREO property\n"); ++ } ++ ++ meta_verbose ("On startup, _MUTTER_ENABLE_STEREO=%s", ++ stereo_enabled ? "yes" : "no"); ++ clutter_x11_set_use_stereo_stage (stereo_enabled); ++ XCloseDisplay (xdisplay); ++} ++ ++static gboolean ++meta_stereo_switch (gpointer data) ++{ ++ stereo_switch_id = 0; ++ stereo_restart = TRUE; ++ ++ meta_restart (stereo_have_windows ? ++ _("Enabling stereo...") : ++ _("Disabling stereo...")); ++ ++ return FALSE; ++} ++ ++void ++meta_stereo_set_have_stereo_windows (gboolean have_windows) ++{ ++ have_windows = have_windows != FALSE; ++ ++ if (!stereo_restart && have_windows != stereo_have_windows) ++ { ++ MetaDisplay *display = meta_get_display (); ++ Display *xdisplay = meta_display_get_xdisplay (display); ++ Window root = DefaultRootWindow (xdisplay); ++ Atom atom_enable_stereo = XInternAtom (xdisplay, "_MUTTER_ENABLE_STEREO", False); ++ long value; ++ ++ stereo_have_windows = have_windows; ++ ++ if (stereo_have_windows) ++ meta_verbose ("Detected stereo windows\n"); ++ else ++ meta_verbose ("No stereo windows detected\n"); ++ ++ value = stereo_have_windows; ++ XChangeProperty (xdisplay, root, ++ atom_enable_stereo, XA_INTEGER, 32, ++ PropModeReplace, (guchar *)&value, 1); ++ ++ if (stereo_switch_id != 0) ++ { ++ g_source_remove (stereo_switch_id); ++ stereo_switch_id = 0; ++ } ++ ++ if (stereo_have_windows != stereo_enabled) ++ stereo_switch_id = g_timeout_add (stereo_have_windows ? STEREO_ENABLE_WAIT : STEREO_DISABLE_WAIT, ++ meta_stereo_switch, NULL); ++ } ++} +diff --git a/src/core/stereo.h b/src/core/stereo.h +new file mode 100644 +index 0000000..ccd1d70 +--- /dev/null ++++ b/src/core/stereo.h +@@ -0,0 +1,28 @@ ++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ ++ ++/* ++ * Copyright (C) 2014 Red Hat, Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++ ++#ifndef META_STEREO_H ++#define META_STEREO_H ++ ++void meta_stereo_init (void); ++void meta_stereo_set_have_stereo_windows (gboolean have_windows); ++gboolean meta_stereo_is_restart (void); ++void meta_stereo_finish_restart (void); ++ ++#endif +-- +2.9.3 + diff --git a/SOURCES/Enable-threeaded-swap-wait.patch b/SOURCES/Enable-threeaded-swap-wait.patch new file mode 100644 index 0000000..5e27d79 --- /dev/null +++ b/SOURCES/Enable-threeaded-swap-wait.patch @@ -0,0 +1,887 @@ +From 4d1005e3b86050f8b5bab41baf08704117f89b21 Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Thu, 11 Feb 2016 15:06:23 -0500 +Subject: [PATCH 1/7] CoglGPUInfo - fix check for NVIDIA + +NVIDIA drivers have a vendor of "NVIDIA Corporation" not "NVIDIA". +Check for both in case older drivers did use "NVIDIA" + +https://bugzilla.gnome.org/show_bug.cgi?id=779039 +--- + cogl/cogl/cogl-gpu-info.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/cogl/cogl/cogl-gpu-info.c b/cogl/cogl/cogl-gpu-info.c +index 845382881..23a846616 100644 +--- a/cogl/cogl/cogl-gpu-info.c ++++ b/cogl/cogl/cogl-gpu-info.c +@@ -169,7 +169,8 @@ check_qualcomm_vendor (const CoglGpuInfoStrings *strings) + static CoglBool + check_nvidia_vendor (const CoglGpuInfoStrings *strings) + { +- if (strcmp (strings->vendor_string, "NVIDIA") != 0) ++ if (strcmp (strings->vendor_string, "NVIDIA") != 0 && ++ strcmp (strings->vendor_string, "NVIDIA Corporation") != 0) + return FALSE; + + return TRUE; +-- +2.12.0 + + +From 62a66bddf3aba14e65ab913746237d3d19a502dd Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Thu, 11 Feb 2016 16:33:03 -0500 +Subject: [PATCH 2/7] CoglWinsysGLX: factor out some duplicated code + +Add a helper function for repeated calls to clock_gettime(CLOCK_MONOTONIC) + +https://bugzilla.gnome.org/show_bug.cgi?id=779039 +--- + cogl/cogl/winsys/cogl-winsys-glx.c | 24 ++++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c +index c50db3a04..379658e8a 100644 +--- a/cogl/cogl/winsys/cogl-winsys-glx.c ++++ b/cogl/cogl/winsys/cogl-winsys-glx.c +@@ -192,6 +192,15 @@ find_onscreen_for_xid (CoglContext *context, uint32_t xid) + return NULL; + } + ++static int64_t ++get_monotonic_time_ns (void) ++{ ++ struct timespec ts; ++ ++ clock_gettime (CLOCK_MONOTONIC, &ts); ++ return ts.tv_sec * G_GINT64_CONSTANT (1000000000) + ts.tv_nsec; ++} ++ + static void + ensure_ust_type (CoglRenderer *renderer, + GLXDrawable drawable) +@@ -202,7 +211,6 @@ ensure_ust_type (CoglRenderer *renderer, + int64_t msc; + int64_t sbc; + struct timeval tv; +- struct timespec ts; + int64_t current_system_time; + int64_t current_monotonic_time; + +@@ -232,9 +240,7 @@ ensure_ust_type (CoglRenderer *renderer, + + /* This is the time source that the newer (fixed) linux drm + * drivers use (Linux >= 3.8) */ +- clock_gettime (CLOCK_MONOTONIC, &ts); +- current_monotonic_time = (ts.tv_sec * G_GINT64_CONSTANT (1000000)) + +- (ts.tv_nsec / G_GINT64_CONSTANT (1000)); ++ current_monotonic_time = get_monotonic_time_ns () / 1000; + + if (current_monotonic_time > ust - 1000000 && + current_monotonic_time < ust + 1000000) +@@ -310,10 +316,7 @@ _cogl_winsys_get_clock_time (CoglContext *context) + } + case COGL_GLX_UST_IS_MONOTONIC_TIME: + { +- struct timespec ts; +- +- clock_gettime (CLOCK_MONOTONIC, &ts); +- return ts.tv_sec * G_GINT64_CONSTANT (1000000000) + ts.tv_nsec; ++ return get_monotonic_time_ns (); + } + } + +@@ -1682,16 +1685,13 @@ _cogl_winsys_wait_for_vblank (CoglOnscreen *onscreen) + else + { + uint32_t current_count; +- struct timespec ts; + + glx_renderer->glXGetVideoSync (¤t_count); + glx_renderer->glXWaitVideoSync (2, + (current_count + 1) % 2, + ¤t_count); + +- clock_gettime (CLOCK_MONOTONIC, &ts); +- info->presentation_time = +- ts.tv_sec * G_GINT64_CONSTANT (1000000000) + ts.tv_nsec; ++ info->presentation_time = get_monotonic_time_ns (); + } + } + } +-- +2.12.0 + + +From 69e156c91c663e6f41759eec9f7c729a67da7dc5 Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Thu, 11 Feb 2016 17:04:08 -0500 +Subject: [PATCH 3/7] Usability of SGI_video_sync is per-display not + per-renderer + +As previously commented in the code, SGI_video_sync is per-display, rather +than per-renderer. The is_direct flag for the renderer was tested before +it was initialized (per-display) and that resulted in SGI_video_sync +never being used. + +https://bugzilla.gnome.org/show_bug.cgi?id=779039 +--- + cogl/cogl/cogl-glx-display-private.h | 3 ++ + cogl/cogl/cogl-glx-renderer-private.h | 2 -- + cogl/cogl/winsys/cogl-winsys-glx.c | 52 +++++++++++++++++++---------------- + 3 files changed, 31 insertions(+), 26 deletions(-) + +diff --git a/cogl/cogl/cogl-glx-display-private.h b/cogl/cogl/cogl-glx-display-private.h +index 133c1188c..1d1afc0cf 100644 +--- a/cogl/cogl/cogl-glx-display-private.h ++++ b/cogl/cogl/cogl-glx-display-private.h +@@ -51,6 +51,9 @@ typedef struct _CoglGLXDisplay + + CoglBool found_fbconfig; + CoglBool fbconfig_has_rgba_visual; ++ CoglBool is_direct; ++ CoglBool have_vblank_counter; ++ CoglBool can_vblank_wait; + GLXFBConfig fbconfig; + + /* Single context for all wins */ +diff --git a/cogl/cogl/cogl-glx-renderer-private.h b/cogl/cogl/cogl-glx-renderer-private.h +index cb8ff97f8..061f2ccb5 100644 +--- a/cogl/cogl/cogl-glx-renderer-private.h ++++ b/cogl/cogl/cogl-glx-renderer-private.h +@@ -43,8 +43,6 @@ typedef struct _CoglGLXRenderer + int glx_error_base; + int glx_event_base; + +- CoglBool is_direct; +- + /* Vblank stuff */ + int dri_fd; + +diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c +index 379658e8a..5a2700176 100644 +--- a/cogl/cogl/winsys/cogl-winsys-glx.c ++++ b/cogl/cogl/winsys/cogl-winsys-glx.c +@@ -715,23 +715,25 @@ update_base_winsys_features (CoglRenderer *renderer) + + g_strfreev (split_extensions); + +- /* Note: the GLX_SGI_video_sync spec explicitly states this extension +- * only works for direct contexts. */ +- if (!glx_renderer->is_direct) +- { +- glx_renderer->glXGetVideoSync = NULL; +- glx_renderer->glXWaitVideoSync = NULL; +- COGL_FLAGS_SET (glx_renderer->base_winsys_features, +- COGL_WINSYS_FEATURE_VBLANK_COUNTER, +- FALSE); +- } ++ /* The GLX_SGI_video_sync spec explicitly states this extension ++ * only works for direct contexts; we don't know per-renderer ++ * if the context is direct or not, so we turn off the feature ++ * flag; we still use the extension within this file looking ++ * instead at glx_display->have_vblank_counter. ++ */ ++ COGL_FLAGS_SET (glx_renderer->base_winsys_features, ++ COGL_WINSYS_FEATURE_VBLANK_COUNTER, ++ FALSE); ++ + + COGL_FLAGS_SET (glx_renderer->base_winsys_features, + COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN, + TRUE); + +- if (glx_renderer->glXWaitVideoSync || +- glx_renderer->glXWaitForMsc) ++ /* Because of the direct-context dependency, the VBLANK_WAIT feature ++ * doesn't reflect the presence of GLX_SGI_video_sync. ++ */ ++ if (glx_renderer->glXWaitForMsc) + COGL_FLAGS_SET (glx_renderer->base_winsys_features, + COGL_WINSYS_FEATURE_VBLANK_WAIT, + TRUE); +@@ -864,7 +866,7 @@ update_winsys_features (CoglContext *context, CoglError **error) + * by the SwapInterval so we have to throttle swap_region requests + * manually... */ + if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION) && +- _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_WAIT)) ++ (glx_display->have_vblank_counter || glx_display->can_vblank_wait)) + COGL_FLAGS_SET (context->winsys_features, + COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE, TRUE); + +@@ -1142,11 +1144,13 @@ create_context (CoglDisplay *display, CoglError **error) + return FALSE; + } + +- glx_renderer->is_direct = ++ glx_display->is_direct = + glx_renderer->glXIsDirect (xlib_renderer->xdpy, glx_display->glx_context); ++ glx_display->have_vblank_counter = glx_display->is_direct && glx_renderer->glXWaitVideoSync; ++ glx_display->can_vblank_wait = glx_renderer->glXWaitForMsc || glx_display->have_vblank_counter; + + COGL_NOTE (WINSYS, "Setting %s context", +- glx_renderer->is_direct ? "direct" : "indirect"); ++ glx_display->is_direct ? "direct" : "indirect"); + + /* XXX: GLX doesn't let us make a context current without a window + * so we create a dummy window that we can use while no CoglOnscreen +@@ -1658,12 +1662,13 @@ _cogl_winsys_wait_for_vblank (CoglOnscreen *onscreen) + CoglContext *ctx = framebuffer->context; + CoglGLXRenderer *glx_renderer; + CoglXlibRenderer *xlib_renderer; ++ CoglGLXDisplay *glx_display; + + glx_renderer = ctx->display->renderer->winsys; + xlib_renderer = _cogl_xlib_renderer_get_data (ctx->display->renderer); ++ glx_display = ctx->display->winsys; + +- if (glx_renderer->glXWaitForMsc || +- glx_renderer->glXGetVideoSync) ++ if (glx_display->can_vblank_wait) + { + CoglFrameInfo *info = g_queue_peek_tail (&onscreen->pending_frame_infos); + +@@ -1759,6 +1764,7 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen, + CoglXlibRenderer *xlib_renderer = + _cogl_xlib_renderer_get_data (context->display->renderer); + CoglGLXRenderer *glx_renderer = context->display->renderer->winsys; ++ CoglGLXDisplay *glx_display = context->display->winsys; + CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; + CoglOnscreenGLX *glx_onscreen = onscreen->winsys; + GLXDrawable drawable = +@@ -1815,9 +1821,8 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen, + + if (framebuffer->config.swap_throttled) + { +- have_counter = +- _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_COUNTER); +- can_wait = _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_WAIT); ++ have_counter = glx_display->have_vblank_counter; ++ can_wait = glx_display->can_vblank_wait; + } + else + { +@@ -1974,6 +1979,7 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + CoglXlibRenderer *xlib_renderer = + _cogl_xlib_renderer_get_data (context->display->renderer); + CoglGLXRenderer *glx_renderer = context->display->renderer->winsys; ++ CoglGLXDisplay *glx_display = context->display->winsys; + CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; + CoglOnscreenGLX *glx_onscreen = onscreen->winsys; + CoglBool have_counter; +@@ -1993,8 +1999,7 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + { + uint32_t end_frame_vsync_counter = 0; + +- have_counter = +- _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_COUNTER); ++ have_counter = glx_display->have_vblank_counter; + + /* If the swap_region API is also being used then we need to track + * the vsync counter for each swap request so we can manually +@@ -2004,8 +2009,7 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + + if (!glx_renderer->glXSwapInterval) + { +- CoglBool can_wait = +- _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_WAIT); ++ CoglBool can_wait = glx_display->can_vblank_wait; + + /* If we are going to wait for VBLANK manually, we not only + * need to flush out pending drawing to the GPU before we +-- +2.12.0 + + +From 55b8900c1d66a4568ff261a0498d12ca857d2431 Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Thu, 11 Feb 2016 17:12:09 -0500 +Subject: [PATCH 4/7] Fix the get_clock_time() without GLX_OML_sync_control + +When we don't have GLX_OML_sync_control, we still can set the +frame presentation time, but we always use the system monotonic time, +so return that from get_clock_time(). + +https://bugzilla.gnome.org/show_bug.cgi?id=779039 +--- + cogl/cogl/winsys/cogl-winsys-glx.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c +index 5a2700176..7ad1a3fdf 100644 +--- a/cogl/cogl/winsys/cogl-winsys-glx.c ++++ b/cogl/cogl/winsys/cogl-winsys-glx.c +@@ -296,6 +296,9 @@ _cogl_winsys_get_clock_time (CoglContext *context) + { + CoglGLXRenderer *glx_renderer = context->display->renderer->winsys; + ++ if (!glx_renderer->glXWaitForMsc) ++ return get_monotonic_time_ns (); ++ + /* We don't call ensure_ust_type() because we don't have a drawable + * to work with. cogl_get_clock_time() is documented to only work + * once a valid, non-zero, timestamp has been retrieved from Cogl. +-- +2.12.0 + + +From cb784a7be6c72453bc441f03ced27a531ee687d5 Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Thu, 11 Feb 2016 17:15:13 -0500 +Subject: [PATCH 5/7] For NVIDIA proprietary drivers, implement sync events + with a thread + +It's a good guess that the buffer swap will occur at the next vblank, +so use glXWaitVideoSync in a separate thread to deliver a sync event +rather than just letting the client block when frame drawing, which +can signficantly change app logic as compared to the INTEL_swap_event +case. + +https://bugzilla.gnome.org/show_bug.cgi?id=779039 +--- + cogl/cogl/cogl-private.h | 3 + + cogl/cogl/winsys/cogl-winsys-glx.c | 294 +++++++++++++++++++++++++++++++++++-- + 2 files changed, 286 insertions(+), 11 deletions(-) + +diff --git a/cogl/cogl/cogl-private.h b/cogl/cogl/cogl-private.h +index 333955c65..e5dc9feda 100644 +--- a/cogl/cogl/cogl-private.h ++++ b/cogl/cogl/cogl-private.h +@@ -77,6 +77,9 @@ typedef enum + COGL_PRIVATE_FEATURE_GL_PROGRAMMABLE, + COGL_PRIVATE_FEATURE_GL_EMBEDDED, + COGL_PRIVATE_FEATURE_GL_WEB, ++ /* This is currently only implemented for GLX, but isn't actually ++ * that winsys dependent */ ++ COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT, + + COGL_N_PRIVATE_FEATURES + } CoglPrivateFeature; +diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c +index 7ad1a3fdf..1418d1501 100644 +--- a/cogl/cogl/winsys/cogl-winsys-glx.c ++++ b/cogl/cogl/winsys/cogl-winsys-glx.c +@@ -65,12 +65,16 @@ + #include + #include + #include ++#include + #include + #include ++#include + + #include + #include + ++#include ++ + /* This is a relatively new extension */ + #ifndef GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV + #define GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x20F7 +@@ -100,6 +104,14 @@ typedef struct _CoglOnscreenGLX + CoglBool pending_sync_notify; + CoglBool pending_complete_notify; + CoglBool pending_resize_notify; ++ ++ GThread *swap_wait_thread; ++ GQueue *swap_wait_queue; ++ GCond swap_wait_cond; ++ GMutex swap_wait_mutex; ++ int swap_wait_pipe[2]; ++ GLXContext swap_wait_context; ++ CoglBool closing_down; + } CoglOnscreenGLX; + + typedef struct _CoglPixmapTextureEyeGLX +@@ -885,6 +897,28 @@ update_winsys_features (CoglContext *context, CoglError **error) + COGL_FEATURE_ID_PRESENTATION_TIME, + TRUE); + } ++ else ++ { ++ CoglGpuInfo *info = &context->gpu; ++ if (glx_display->have_vblank_counter && ++ info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA) ++ { ++ COGL_FLAGS_SET (context->winsys_features, ++ COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT, TRUE); ++ COGL_FLAGS_SET (context->winsys_features, ++ COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT, TRUE); ++ /* TODO: remove this deprecated feature */ ++ COGL_FLAGS_SET (context->features, ++ COGL_FEATURE_ID_SWAP_BUFFERS_EVENT, ++ TRUE); ++ COGL_FLAGS_SET (context->features, ++ COGL_FEATURE_ID_PRESENTATION_TIME, ++ TRUE); ++ COGL_FLAGS_SET (context->private_features, ++ COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT, ++ TRUE); ++ } ++ } + + /* We'll manually handle queueing dirty events in response to + * Expose events from X */ +@@ -1481,7 +1515,8 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen, + } + + #ifdef GLX_INTEL_swap_event +- if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT)) ++ if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT) && ++ !_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT)) + { + GLXDrawable drawable = + glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin; +@@ -1524,6 +1559,31 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen) + xlib_onscreen->output = NULL; + } + ++ if (glx_onscreen->swap_wait_thread) ++ { ++ g_mutex_lock (&glx_onscreen->swap_wait_mutex); ++ glx_onscreen->closing_down = TRUE; ++ g_cond_signal (&glx_onscreen->swap_wait_cond); ++ g_mutex_unlock (&glx_onscreen->swap_wait_mutex); ++ g_thread_join (glx_onscreen->swap_wait_thread); ++ glx_onscreen->swap_wait_thread = NULL; ++ ++ g_cond_clear (&glx_onscreen->swap_wait_cond); ++ g_mutex_clear (&glx_onscreen->swap_wait_mutex); ++ ++ g_queue_free (glx_onscreen->swap_wait_queue); ++ glx_onscreen->swap_wait_queue = NULL; ++ ++ _cogl_poll_renderer_remove_fd (context->display->renderer, ++ glx_onscreen->swap_wait_pipe[0]); ++ ++ close (glx_onscreen->swap_wait_pipe[0]); ++ close (glx_onscreen->swap_wait_pipe[1]); ++ ++ glx_renderer->glXDestroyContext (xlib_renderer->xdpy, ++ glx_onscreen->swap_wait_context); ++ } ++ + _cogl_xlib_renderer_trap_errors (context->display->renderer, &old_state); + + drawable = +@@ -1757,6 +1817,199 @@ set_frame_info_output (CoglOnscreen *onscreen, + } + } + ++static gpointer ++threaded_swap_wait (gpointer data) ++{ ++ CoglOnscreen *onscreen = data; ++ ++ CoglOnscreenGLX *glx_onscreen = onscreen->winsys; ++ ++ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); ++ CoglContext *context = framebuffer->context; ++ CoglDisplay *display = context->display; ++ CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (display->renderer); ++ CoglGLXDisplay *glx_display = display->winsys; ++ CoglGLXRenderer *glx_renderer = display->renderer->winsys; ++ GLXDrawable dummy_drawable; ++ ++ if (glx_display->dummy_glxwin) ++ dummy_drawable = glx_display->dummy_glxwin; ++ else ++ dummy_drawable = glx_display->dummy_xwin; ++ ++ glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy, ++ dummy_drawable, ++ dummy_drawable, ++ glx_onscreen->swap_wait_context); ++ ++ g_mutex_lock (&glx_onscreen->swap_wait_mutex); ++ ++ while (TRUE) ++ { ++ gpointer queue_element; ++ uint32_t vblank_counter; ++ ++ while (!glx_onscreen->closing_down && glx_onscreen->swap_wait_queue->length == 0) ++ g_cond_wait (&glx_onscreen->swap_wait_cond, &glx_onscreen->swap_wait_mutex); ++ ++ if (glx_onscreen->closing_down) ++ break; ++ ++ queue_element = g_queue_pop_tail (glx_onscreen->swap_wait_queue); ++ vblank_counter = GPOINTER_TO_UINT(queue_element); ++ ++ g_mutex_unlock (&glx_onscreen->swap_wait_mutex); ++ glx_renderer->glXWaitVideoSync (2, ++ (vblank_counter + 1) % 2, ++ &vblank_counter); ++ g_mutex_lock (&glx_onscreen->swap_wait_mutex); ++ ++ if (!glx_onscreen->closing_down) ++ { ++ int bytes_written = 0; ++ ++ union { ++ char bytes[8]; ++ int64_t presentation_time; ++ } u; ++ ++ u.presentation_time = get_monotonic_time_ns (); ++ ++ while (bytes_written < 8) ++ { ++ int res = write (glx_onscreen->swap_wait_pipe[1], u.bytes + bytes_written, 8 - bytes_written); ++ if (res == -1) ++ { ++ if (errno != EINTR) ++ g_error ("Error writing to swap notification pipe: %s\n", ++ g_strerror (errno)); ++ } ++ else ++ { ++ bytes_written += res; ++ } ++ } ++ } ++ } ++ ++ g_mutex_unlock (&glx_onscreen->swap_wait_mutex); ++ ++ glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy, ++ None, ++ None, ++ NULL); ++ ++ return NULL; ++} ++ ++static int64_t ++threaded_swap_wait_pipe_prepare (void *user_data) ++{ ++ return -1; ++} ++ ++static void ++threaded_swap_wait_pipe_dispatch (void *user_data, int revents) ++{ ++ CoglOnscreen *onscreen = user_data; ++ CoglOnscreenGLX *glx_onscreen = onscreen->winsys; ++ ++ CoglFrameInfo *info; ++ ++ if ((revents & COGL_POLL_FD_EVENT_IN)) ++ { ++ int bytes_read = 0; ++ ++ union { ++ char bytes[8]; ++ int64_t presentation_time; ++ } u; ++ ++ while (bytes_read < 8) ++ { ++ int res = read (glx_onscreen->swap_wait_pipe[0], u.bytes + bytes_read, 8 - bytes_read); ++ if (res == -1) ++ { ++ if (errno != EINTR) ++ g_error ("Error reading from swap notification pipe: %s\n", ++ g_strerror (errno)); ++ } ++ else ++ { ++ bytes_read += res; ++ } ++ } ++ ++ set_sync_pending (onscreen); ++ set_complete_pending (onscreen); ++ ++ info = g_queue_peek_head (&onscreen->pending_frame_infos); ++ info->presentation_time = u.presentation_time; ++ } ++} ++ ++static void ++start_threaded_swap_wait (CoglOnscreen *onscreen, ++ uint32_t vblank_counter) ++{ ++ CoglOnscreenGLX *glx_onscreen = onscreen->winsys; ++ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); ++ CoglContext *context = framebuffer->context; ++ ++ if (glx_onscreen->swap_wait_thread == NULL) ++ { ++ CoglDisplay *display = context->display; ++ CoglGLXRenderer *glx_renderer = display->renderer->winsys; ++ CoglGLXDisplay *glx_display = display->winsys; ++ CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; ++ CoglXlibRenderer *xlib_renderer = ++ _cogl_xlib_renderer_get_data (display->renderer); ++ ++ GLXDrawable drawable = ++ glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin; ++ int i; ++ ++ ensure_ust_type (display->renderer, drawable); ++ ++ if ((pipe (glx_onscreen->swap_wait_pipe) == -1)) ++ g_error ("Couldn't create pipe for swap notification: %s\n", ++ g_strerror (errno)); ++ ++ for (i = 0; i < 2; i++) ++ { ++ if (fcntl(glx_onscreen->swap_wait_pipe[i], F_SETFD, ++ fcntl(glx_onscreen->swap_wait_pipe[i], F_GETFD, 0) | FD_CLOEXEC) == -1) ++ g_error ("Couldn't set swap notification pipe CLOEXEC: %s\n", ++ g_strerror (errno)); ++ } ++ ++ _cogl_poll_renderer_add_fd (display->renderer, ++ glx_onscreen->swap_wait_pipe[0], ++ COGL_POLL_FD_EVENT_IN, ++ threaded_swap_wait_pipe_prepare, ++ threaded_swap_wait_pipe_dispatch, ++ onscreen); ++ ++ glx_onscreen->swap_wait_queue = g_queue_new (); ++ g_mutex_init (&glx_onscreen->swap_wait_mutex); ++ g_cond_init (&glx_onscreen->swap_wait_cond); ++ glx_onscreen->swap_wait_context = ++ glx_renderer->glXCreateNewContext (xlib_renderer->xdpy, ++ glx_display->fbconfig, ++ GLX_RGBA_TYPE, ++ glx_display->glx_context, ++ True); ++ glx_onscreen->swap_wait_thread = g_thread_new ("cogl_glx_swap_wait", ++ threaded_swap_wait, ++ onscreen); ++ } ++ ++ g_mutex_lock (&glx_onscreen->swap_wait_mutex); ++ g_queue_push_head (glx_onscreen->swap_wait_queue, GUINT_TO_POINTER(vblank_counter)); ++ g_cond_signal (&glx_onscreen->swap_wait_cond); ++ g_mutex_unlock (&glx_onscreen->swap_wait_mutex); ++} ++ + static void + _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen, + const int *user_rectangles, +@@ -2000,19 +2253,38 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + + if (framebuffer->config.swap_throttled) + { +- uint32_t end_frame_vsync_counter = 0; +- + have_counter = glx_display->have_vblank_counter; + +- /* If the swap_region API is also being used then we need to track +- * the vsync counter for each swap request so we can manually +- * throttle swap_region requests. */ +- if (have_counter) +- end_frame_vsync_counter = _cogl_winsys_get_vsync_counter (context); +- +- if (!glx_renderer->glXSwapInterval) ++ if (glx_renderer->glXSwapInterval) + { +- CoglBool can_wait = glx_display->can_vblank_wait; ++ if (_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT)) ++ { ++ /* If we didn't wait for the GPU here, then it's easy to get the case ++ * where there is a VBlank between the point where we get the vsync counter ++ * and the point where the GPU is ready to actually perform the glXSwapBuffers(), ++ * and the swap wait terminates at the first VBlank rather than the one ++ * where the swap buffers happens. Calling glFinish() here makes this a ++ * rare race since the GPU is already ready to swap when we call glXSwapBuffers(). ++ * The glFinish() also prevents any serious damage if the rare race happens, ++ * since it will wait for the preceding glXSwapBuffers() and prevent us from ++ * getting premanently ahead. (For NVIDIA drivers, glFinish() after glXSwapBuffers() ++ * waits for the buffer swap to happen.) ++ */ ++ _cogl_winsys_wait_for_gpu (onscreen); ++ start_threaded_swap_wait (onscreen, _cogl_winsys_get_vsync_counter (context)); ++ } ++ } ++ else ++ { ++ CoglBool can_wait = have_counter || glx_display->can_vblank_wait; ++ ++ uint32_t end_frame_vsync_counter = 0; ++ ++ /* If the swap_region API is also being used then we need to track ++ * the vsync counter for each swap request so we can manually ++ * throttle swap_region requests. */ ++ if (have_counter) ++ end_frame_vsync_counter = _cogl_winsys_get_vsync_counter (context); + + /* If we are going to wait for VBLANK manually, we not only + * need to flush out pending drawing to the GPU before we +-- +2.12.0 + + +From fb0978b4ea33c88e7a42d4f478d60ef86e271414 Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Wed, 29 Jun 2016 13:52:59 -0400 +Subject: [PATCH 6/7] Add cogl_xlib_renderer_set_threaded_swap_wait_enabled() + +Because the threaded-swap-wait functionality requires XInitThreads(), +and because it isn't clear that it is a win for all applications, +add a API function to conditionally enable it. + +Fix the cogl-crate example not to just have a hard-coded dependency +on libX11. + +https://bugzilla.gnome.org/show_bug.cgi?id=779039 +--- + cogl/cogl/cogl-renderer-private.h | 1 + + cogl/cogl/cogl-renderer.c | 11 +++++++++++ + cogl/cogl/cogl-xlib-renderer.h | 30 ++++++++++++++++++++++++++++++ + cogl/cogl/winsys/cogl-winsys-glx.c | 1 + + 4 files changed, 43 insertions(+) + +diff --git a/cogl/cogl/cogl-renderer-private.h b/cogl/cogl/cogl-renderer-private.h +index 8627b6cc6..33ed0ceac 100644 +--- a/cogl/cogl/cogl-renderer-private.h ++++ b/cogl/cogl/cogl-renderer-private.h +@@ -69,6 +69,7 @@ struct _CoglRenderer + Display *foreign_xdpy; + CoglBool xlib_enable_event_retrieval; + CoglBool xlib_want_reset_on_video_memory_purge; ++ CoglBool xlib_enable_threaded_swap_wait; + #endif + + CoglDriver driver; +diff --git a/cogl/cogl/cogl-renderer.c b/cogl/cogl/cogl-renderer.c +index 51a04ffdd..e6575d808 100644 +--- a/cogl/cogl/cogl-renderer.c ++++ b/cogl/cogl/cogl-renderer.c +@@ -285,6 +285,17 @@ cogl_xlib_renderer_request_reset_on_video_memory_purge (CoglRenderer *renderer, + + renderer->xlib_want_reset_on_video_memory_purge = enable; + } ++ ++void ++cogl_xlib_renderer_set_threaded_swap_wait_enabled (CoglRenderer *renderer, ++ CoglBool enable) ++{ ++ _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer)); ++ /* NB: Renderers are considered immutable once connected */ ++ _COGL_RETURN_IF_FAIL (!renderer->connected); ++ ++ renderer->xlib_enable_threaded_swap_wait = enable; ++} + #endif /* COGL_HAS_XLIB_SUPPORT */ + + CoglBool +diff --git a/cogl/cogl/cogl-xlib-renderer.h b/cogl/cogl/cogl-xlib-renderer.h +index f3c1d7c09..3c0db189b 100644 +--- a/cogl/cogl/cogl-xlib-renderer.h ++++ b/cogl/cogl/cogl-xlib-renderer.h +@@ -168,6 +168,36 @@ cogl_xlib_renderer_set_event_retrieval_enabled (CoglRenderer *renderer, + CoglBool enable); + + /** ++ * cogl_xlib_renderer_set_threaded_swap_wait_enabled: ++ * @renderer: a #CoglRenderer ++ * @enable: The new value ++ * ++ * Sets whether Cogl is allowed to use a separate threaded to wait for the ++ * completion of glXSwapBuffers() and call the frame callback for the ++ * corresponding #CoglOnscreen. This is a way of emulating the ++ * INTEL_swap_event extension, and will only ever be used if ++ * INTEL_swap_event is not present; it will also only be used for ++ * specific white-listed drivers that are known to work correctly with ++ * multiple contexts sharing state between threads. ++ * ++ * The advantage of enabling this is that it will allow your main loop ++ * to do other work while waiting for the system to be ready to draw ++ * the next frame, instead of blocking in glXSwapBuffers(). A disadvantage ++ * is that the driver will be prevented from buffering up multiple frames ++ * even if it thinks that it would be advantageous. In general, this ++ * will work best for something like a system compositor that is doing ++ * simple drawing but handling lots of other complex tasks. ++ * ++ * If you enable this, you must call XInitThreads() before any other ++ * X11 calls in your program. (See the documentation for XInitThreads()) ++ * ++ * Stability: unstable ++ */ ++void ++cogl_xlib_renderer_set_threaded_swap_wait_enabled (CoglRenderer *renderer, ++ CoglBool enable); ++ ++/** + * cogl_xlib_renderer_get_display: (skip) + */ + Display * +diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c +index 1418d1501..74b0895d1 100644 +--- a/cogl/cogl/winsys/cogl-winsys-glx.c ++++ b/cogl/cogl/winsys/cogl-winsys-glx.c +@@ -901,6 +901,7 @@ update_winsys_features (CoglContext *context, CoglError **error) + { + CoglGpuInfo *info = &context->gpu; + if (glx_display->have_vblank_counter && ++ context->display->renderer->xlib_enable_threaded_swap_wait && + info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA) + { + COGL_FLAGS_SET (context->winsys_features, +-- +2.12.0 + + +From 9505ce8cce4fe14443b5c9868e4e7301268a8d23 Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Tue, 21 Feb 2017 13:51:16 -0500 +Subject: [PATCH 7/7] Call cogl_xlib_renderer_set_threaded_swap_wait_enabled() + +Set up things so that if the INTEL_swap_event extension is not present, +but the driver is known to have good thread support, we use an extra +thread and call glXWaitVideoSync() in the thread. This allows idles +to work properly, even when Mutter is constantly redrawing new frames; +otherwise, without INTEL_swap_event, we'll just block in glXSwapBuffers(). + +https://bugzilla.gnome.org/show_bug.cgi?id=779039 +--- + src/backends/x11/meta-backend-x11.c | 6 ++++++ + src/backends/x11/meta-renderer-x11.c | 8 ++++++++ + 2 files changed, 14 insertions(+) + +diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c +index a0b196efe..413b0622a 100644 +--- a/src/backends/x11/meta-backend-x11.c ++++ b/src/backends/x11/meta-backend-x11.c +@@ -913,6 +913,12 @@ meta_backend_x11_init (MetaBackendX11 *x11) + { + MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); + ++ /* XInitThreads() is needed to use the "threaded swap wait" functionality ++ * in Cogl - see meta_renderer_x11_create_cogl_renderer(). We call it here ++ * to hopefully call it before any other use of XLib. ++ */ ++ XInitThreads(); ++ + clutter_x11_request_reset_on_video_memory_purge (); + + /* We do X11 event retrieval ourselves */ +diff --git a/src/backends/x11/meta-renderer-x11.c b/src/backends/x11/meta-renderer-x11.c +index c0405bedc..9a86f493a 100644 +--- a/src/backends/x11/meta-renderer-x11.c ++++ b/src/backends/x11/meta-renderer-x11.c +@@ -65,6 +65,14 @@ meta_renderer_x11_create_cogl_renderer (MetaRenderer *renderer) + cogl_renderer_set_custom_winsys (cogl_renderer, get_x11_cogl_winsys_vtable); + cogl_xlib_renderer_set_foreign_display (cogl_renderer, xdisplay); + ++ /* Set up things so that if the INTEL_swap_event extension is not present, ++ * but the driver is known to have good thread support, we use an extra ++ * thread and call glXWaitVideoSync() in the thread. This allows idles ++ * to work properly, even when Mutter is constantly redrawing new frames; ++ * otherwise, without INTEL_swap_event, we'll just block in glXSwapBuffers(). ++ */ ++ cogl_xlib_renderer_set_threaded_swap_wait_enabled (cogl_renderer, TRUE); ++ + return cogl_renderer; + } + +-- +2.12.0 + diff --git a/SOURCES/add-support-for-plain-old-x-device-configuration.patch b/SOURCES/add-support-for-plain-old-x-device-configuration.patch new file mode 100644 index 0000000..39ec339 --- /dev/null +++ b/SOURCES/add-support-for-plain-old-x-device-configuration.patch @@ -0,0 +1,395 @@ +From e9cd700f11565fd1723828a5cf77f994c8494ddd Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Mon, 9 Oct 2017 18:37:11 +0200 +Subject: [PATCH 1/4] backends/x11: Fix a small memory leak + +Introduced in "backends/x11: Support synaptics configuration". +--- + src/backends/x11/meta-input-settings-x11.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c +index 75ceb0c93..cfdd2ffef 100644 +--- a/src/backends/x11/meta-input-settings-x11.c ++++ b/src/backends/x11/meta-input-settings-x11.c +@@ -181,6 +181,7 @@ change_synaptics_tap_left_handed (ClutterInputDevice *device, + buttons[0] = left_handed ? 3 : 1; + buttons[2] = left_handed ? 1 : 3; + XSetDeviceButtonMapping (xdisplay, xdevice, buttons, n_buttons); ++ g_free (buttons); + + if (display && meta_error_trap_pop_with_return (display)) + { +-- +2.13.5 + +From 1df0d3b1a0d85c3a565ce6dde4faedf7c1f57930 Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Mon, 9 Oct 2017 18:39:52 +0200 +Subject: [PATCH 2/4] backends/x11: Add a synaptics check for two finger scroll + availability + +Commit "backends/x11: Support synaptics configuration" added support +for synaptics two finger scrolling but didn't add the code to check +that it is available resulting in the upper layer always assuming it +isn't. +--- + src/backends/x11/meta-input-settings-x11.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c +index cfdd2ffef..8aa8a497b 100644 +--- a/src/backends/x11/meta-input-settings-x11.c ++++ b/src/backends/x11/meta-input-settings-x11.c +@@ -546,6 +546,17 @@ meta_input_settings_x11_has_two_finger_scroll (MetaInputSettings *settings, + guchar *available = NULL; + gboolean has_two_finger = TRUE; + ++ if (is_device_synaptics (device)) ++ { ++ available = get_property (device, "Synaptics Capabilities", ++ XA_INTEGER, 8, 4); ++ if (!available || !available[3]) ++ has_two_finger = FALSE; ++ ++ meta_XFree (available); ++ return has_two_finger; ++ } ++ + available = get_property (device, "libinput Scroll Methods Available", + XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS); + if (!available || !available[SCROLL_METHOD_FIELD_2FG]) +-- +2.13.5 + +From 05b6600752ee85e0c48d4055b3ca1c2d010d2851 Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Mon, 9 Oct 2017 18:55:56 +0200 +Subject: [PATCH 3/4] backends/x11: Add disable while typing support for + synaptics + +This is basically a copy of the old g-s-d mouse plugin code to manage +syndaemon when the synaptics driver is being used. +--- + src/backends/x11/meta-input-settings-x11.c | 107 +++++++++++++++++++++++++++++ + 1 file changed, 107 insertions(+) + +diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c +index 8aa8a497b..d38e1b454 100644 +--- a/src/backends/x11/meta-input-settings-x11.c ++++ b/src/backends/x11/meta-input-settings-x11.c +@@ -35,6 +35,9 @@ + #ifdef HAVE_LIBGUDEV + #include + #endif ++#ifdef __linux ++#include ++#endif + + #include + +@@ -43,6 +46,8 @@ typedef struct _MetaInputSettingsX11Private + #ifdef HAVE_LIBGUDEV + GUdevClient *udev_client; + #endif ++ gboolean syndaemon_spawned; ++ GPid syndaemon_pid; + } MetaInputSettingsX11Private; + + G_DEFINE_TYPE_WITH_PRIVATE (MetaInputSettingsX11, meta_input_settings_x11, +@@ -291,6 +296,107 @@ change_synaptics_speed (ClutterInputDevice *device, + XCloseDevice (xdisplay, xdevice); + } + ++/* Ensure that syndaemon dies together with us, to avoid running several of ++ * them */ ++static void ++setup_syndaemon (gpointer user_data) ++{ ++#ifdef __linux ++ prctl (PR_SET_PDEATHSIG, SIGHUP); ++#endif ++} ++ ++static gboolean ++have_program_in_path (const char *name) ++{ ++ gchar *path; ++ gboolean result; ++ ++ path = g_find_program_in_path (name); ++ result = (path != NULL); ++ g_free (path); ++ return result; ++} ++ ++static void ++syndaemon_died (GPid pid, ++ gint status, ++ gpointer user_data) ++{ ++ MetaInputSettingsX11 *settings_x11 = META_INPUT_SETTINGS_X11 (user_data); ++ MetaInputSettingsX11Private *priv = ++ meta_input_settings_x11_get_instance_private (settings_x11); ++ GError *error = NULL; ++ ++ if (!g_spawn_check_exit_status (status, &error)) ++ { ++ if ((WIFSIGNALED (status) && WTERMSIG (status) != SIGHUP) || ++ error->domain == G_SPAWN_EXIT_ERROR) ++ g_warning ("Syndaemon exited unexpectedly: %s", error->message); ++ g_error_free (error); ++ } ++ ++ g_spawn_close_pid (pid); ++ priv->syndaemon_spawned = FALSE; ++} ++ ++static void ++set_synaptics_disable_w_typing (MetaInputSettings *settings, ++ gboolean state) ++{ ++ MetaInputSettingsX11 *settings_x11 = META_INPUT_SETTINGS_X11 (settings); ++ MetaInputSettingsX11Private *priv = ++ meta_input_settings_x11_get_instance_private (settings_x11); ++ ++ if (state) ++ { ++ GError *error = NULL; ++ GPtrArray *args; ++ ++ if (priv->syndaemon_spawned) ++ return; ++ ++ if (!have_program_in_path ("syndaemon")) ++ return; ++ ++ args = g_ptr_array_new (); ++ ++ g_ptr_array_add (args, "syndaemon"); ++ g_ptr_array_add (args, "-i"); ++ g_ptr_array_add (args, "1.0"); ++ g_ptr_array_add (args, "-t"); ++ g_ptr_array_add (args, "-K"); ++ g_ptr_array_add (args, "-R"); ++ g_ptr_array_add (args, NULL); ++ ++ /* we must use G_SPAWN_DO_NOT_REAP_CHILD to avoid ++ * double-forking, otherwise syndaemon will immediately get ++ * killed again through (PR_SET_PDEATHSIG when the intermediate ++ * process dies */ ++ g_spawn_async (g_get_home_dir (), (char **) args->pdata, NULL, ++ G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, setup_syndaemon, NULL, ++ &priv->syndaemon_pid, &error); ++ ++ priv->syndaemon_spawned = (error == NULL); ++ g_ptr_array_free (args, TRUE); ++ ++ if (error) ++ { ++ g_warning ("Failed to launch syndaemon: %s", error->message); ++ g_error_free (error); ++ } ++ else ++ { ++ g_child_watch_add (priv->syndaemon_pid, syndaemon_died, settings); ++ } ++ } ++ else if (priv->syndaemon_spawned) ++ { ++ kill (priv->syndaemon_pid, SIGHUP); ++ priv->syndaemon_spawned = FALSE; ++ } ++} ++ + static void + meta_input_settings_x11_set_send_events (MetaInputSettings *settings, + ClutterInputDevice *device, +@@ -303,6 +409,7 @@ meta_input_settings_x11_set_send_events (MetaInputSettings *settings, + { + values[0] = mode != G_DESKTOP_DEVICE_SEND_EVENTS_ENABLED; + change_property (device, "Synaptics Off", XA_INTEGER, 8, &values, 1); ++ set_synaptics_disable_w_typing (settings, mode == G_DESKTOP_DEVICE_SEND_EVENTS_ENABLED); + return; + } + +-- +2.13.5 + +From 94aa02bfe8364c9be9ca0251f66e8f91c38d1bdd Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Tue, 10 Oct 2017 19:07:27 +0200 +Subject: [PATCH 4/4] backends/x11: Support plain old X device configuration + +We re-use part of the code added to support synaptics and add a few +bits specific for xorg-x11-drv-evdev devices. +--- + src/backends/x11/meta-input-settings-x11.c | 97 +++++++++++++++++++++++------- + 1 file changed, 74 insertions(+), 23 deletions(-) + +diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c +index d38e1b454..63a8fe79e 100644 +--- a/src/backends/x11/meta-input-settings-x11.c ++++ b/src/backends/x11/meta-input-settings-x11.c +@@ -138,35 +138,35 @@ is_device_synaptics (ClutterInputDevice *device) + return TRUE; + } + ++static gboolean ++is_device_libinput (ClutterInputDevice *device) ++{ ++ guchar *has_setting; ++ ++ /* We just need looking for a synaptics-specific property */ ++ has_setting = get_property (device, "libinput Send Events Modes Available", XA_INTEGER, 8, 2); ++ if (!has_setting) ++ return FALSE; ++ ++ meta_XFree (has_setting); ++ return TRUE; ++} ++ + static void +-change_synaptics_tap_left_handed (ClutterInputDevice *device, +- gboolean tap_enabled, +- gboolean left_handed) ++change_x_device_left_handed (ClutterInputDevice *device, ++ gboolean left_handed) + { + MetaDisplay *display = meta_get_display (); + MetaBackend *backend = meta_get_backend (); + Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); + XDevice *xdevice; +- guchar *tap_action, *buttons; ++ guchar *buttons; + guint buttons_capacity = 16, n_buttons; + + xdevice = XOpenDevice(xdisplay, clutter_input_device_get_device_id (device)); + if (!xdevice) + return; + +- tap_action = get_property (device, "Synaptics Tap Action", +- XA_INTEGER, 8, 7); +- if (!tap_action) +- goto out; +- +- tap_action[4] = tap_enabled ? (left_handed ? 3 : 1) : 0; +- tap_action[5] = tap_enabled ? (left_handed ? 1 : 3) : 0; +- tap_action[6] = tap_enabled ? 2 : 0; +- +- change_property (device, "Synaptics Tap Action", +- XA_INTEGER, 8, tap_action, 7); +- meta_XFree (tap_action); +- + if (display) + meta_error_trap_push (display); + buttons = g_new (guchar, buttons_capacity); +@@ -190,17 +190,39 @@ change_synaptics_tap_left_handed (ClutterInputDevice *device, + + if (display && meta_error_trap_pop_with_return (display)) + { +- g_warning ("Could not set synaptics touchpad left-handed for %s", ++ g_warning ("Could not set left-handed for %s", + clutter_input_device_get_device_name (device)); + } + +- out: + XCloseDevice (xdisplay, xdevice); + } + + static void +-change_synaptics_speed (ClutterInputDevice *device, +- gdouble speed) ++change_synaptics_tap_left_handed (ClutterInputDevice *device, ++ gboolean tap_enabled, ++ gboolean left_handed) ++{ ++ guchar *tap_action; ++ ++ tap_action = get_property (device, "Synaptics Tap Action", ++ XA_INTEGER, 8, 7); ++ if (!tap_action) ++ return; ++ ++ tap_action[4] = tap_enabled ? (left_handed ? 3 : 1) : 0; ++ tap_action[5] = tap_enabled ? (left_handed ? 1 : 3) : 0; ++ tap_action[6] = tap_enabled ? 2 : 0; ++ ++ change_property (device, "Synaptics Tap Action", ++ XA_INTEGER, 8, tap_action, 7); ++ meta_XFree (tap_action); ++ ++ change_x_device_left_handed (device, left_handed); ++} ++ ++static void ++change_x_device_speed (ClutterInputDevice *device, ++ gdouble speed) + { + MetaDisplay *display = meta_get_display (); + MetaBackend *backend = meta_get_backend (); +@@ -296,6 +318,23 @@ change_synaptics_speed (ClutterInputDevice *device, + XCloseDevice (xdisplay, xdevice); + } + ++static void ++change_x_device_scroll_button (ClutterInputDevice *device, ++ guint button) ++{ ++ guchar value; ++ ++ value = button > 0 ? 1 : 0; ++ change_property (device, "Evdev Wheel Emulation", ++ XA_INTEGER, 8, &value, 1); ++ if (button > 0) ++ { ++ value = button; ++ change_property (device, "Evdev Wheel Emulation Button", ++ XA_INTEGER, 8, &value, 1); ++ } ++} ++ + /* Ensure that syndaemon dies together with us, to avoid running several of + * them */ + static void +@@ -465,9 +504,10 @@ meta_input_settings_x11_set_speed (MetaInputSettings *settings, + Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); + gfloat value = speed; + +- if (is_device_synaptics (device)) ++ if (is_device_synaptics (device) || ++ !is_device_libinput (device)) + { +- change_synaptics_speed (device, speed); ++ change_x_device_speed (device, speed); + return; + } + +@@ -494,6 +534,11 @@ meta_input_settings_x11_set_left_handed (MetaInputSettings *settings, + g_object_unref (settings); + return; + } ++ else if (!is_device_libinput (device)) ++ { ++ change_x_device_left_handed (device, enabled); ++ return; ++ } + + change_property (device, "libinput Left Handed Enabled", + XA_INTEGER, 8, &value, 1); +@@ -678,6 +723,12 @@ meta_input_settings_x11_set_scroll_button (MetaInputSettings *settings, + ClutterInputDevice *device, + guint button) + { ++ if (!is_device_libinput (device)) ++ { ++ change_x_device_scroll_button (device, button); ++ return; ++ } ++ + change_property (device, "libinput Button Scrolling Button", + XA_INTEGER, 32, &button, 1); + } +-- +2.13.5 + diff --git a/SOURCES/deal-more-gracefully-with-oversized-windows.patch b/SOURCES/deal-more-gracefully-with-oversized-windows.patch new file mode 100644 index 0000000..b91bd6f --- /dev/null +++ b/SOURCES/deal-more-gracefully-with-oversized-windows.patch @@ -0,0 +1,85 @@ +From 196f9e68c5c95989225870a8554eac7f61e974f2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 12 Mar 2014 02:04:13 +0100 +Subject: [PATCH] constraints: Enforce X11 size limits + +X11 limits windows to a maximum of 32767x32767, enforce that restriction +to keep insanely huge windows from crashing the WM. +--- + src/core/constraints.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +diff --git a/src/core/constraints.c b/src/core/constraints.c +index e7dcacd84..67b52c994 100644 +--- a/src/core/constraints.c ++++ b/src/core/constraints.c +@@ -103,6 +103,7 @@ typedef enum + PRIORITY_TITLEBAR_VISIBLE = 4, + PRIORITY_PARTIALLY_VISIBLE_ON_WORKAREA = 4, + PRIORITY_CUSTOM_RULE = 4, ++ PRIORITY_XLIMITS = 4, + PRIORITY_MAXIMUM = 4 /* Dummy value used for loop end = max(all priorities) */ + } ConstraintPriority; + +@@ -193,6 +194,10 @@ static gboolean constrain_partially_onscreen (MetaWindow *window, + ConstraintInfo *info, + ConstraintPriority priority, + gboolean check_only); ++static gboolean constrain_xlimits (MetaWindow *window, ++ ConstraintInfo *info, ++ ConstraintPriority priority, ++ gboolean check_only); + + static void setup_constraint_info (ConstraintInfo *info, + MetaWindow *window, +@@ -228,6 +233,7 @@ static const Constraint all_constraints[] = { + {constrain_fully_onscreen, "constrain_fully_onscreen"}, + {constrain_titlebar_visible, "constrain_titlebar_visible"}, + {constrain_partially_onscreen, "constrain_partially_onscreen"}, ++ {constrain_xlimits, "constrain_xlimits"}, + {NULL, NULL} + }; + +@@ -1659,3 +1665,39 @@ constrain_partially_onscreen (MetaWindow *window, + + return retval; + } ++ ++ ++#define MAX_WINDOW_SIZE 32767 ++ ++static gboolean ++constrain_xlimits (MetaWindow *window, ++ ConstraintInfo *info, ++ ConstraintPriority priority, ++ gboolean check_only) ++{ ++ int max_w, max_h; ++ gboolean constraint_already_satisfied; ++ ++ if (priority > PRIORITY_XLIMITS) ++ return TRUE; ++ ++ max_w = max_h = MAX_WINDOW_SIZE; ++ ++ if (window->frame) ++ { ++ MetaFrameBorders borders; ++ meta_frame_calc_borders (window->frame, &borders); ++ ++ max_w -= (borders.total.left + borders.total.right); ++ max_h -= (borders.total.top + borders.total.bottom); ++ } ++ ++ constraint_already_satisfied = info->current.width < max_w && info->current.height < max_h; ++ if (check_only || constraint_already_satisfied) ++ return constraint_already_satisfied; ++ ++ info->current.width = MIN (info->current.width, max_w); ++ info->current.height = MIN (info->current.height, max_h); ++ ++ return TRUE; ++} +-- +2.12.0 + diff --git a/SOURCES/fall-back-to-xorg-on-hybrid-gpus.patch b/SOURCES/fall-back-to-xorg-on-hybrid-gpus.patch new file mode 100644 index 0000000..0e26bc3 --- /dev/null +++ b/SOURCES/fall-back-to-xorg-on-hybrid-gpus.patch @@ -0,0 +1,596 @@ +From 5bea406b353f39867eb86307b1c8b4093f22968e Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 18 Oct 2016 16:40:14 -0400 +Subject: [PATCH 1/4] native: only match drm subsystem devices + +Despite g_udev_client_new taking a list of subsystems, it doesn't +implicitly filter results to those subsystems. + +This commit explicitly adds a subsystem match to make sure sound cards +don't end up in the resulting list of video cards. + +https://bugzilla.gnome.org/show_bug.cgi?id=771442 +--- + src/backends/native/meta-launcher.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/backends/native/meta-launcher.c b/src/backends/native/meta-launcher.c +index ea28e5a..03a928a 100644 +--- a/src/backends/native/meta-launcher.c ++++ b/src/backends/native/meta-launcher.c +@@ -268,60 +268,65 @@ sync_active (MetaLauncher *self) + self->session_active = active; + + if (active) + session_unpause (); + else + session_pause (); + } + + static void + on_active_changed (Login1Session *session, + GParamSpec *pspec, + gpointer user_data) + { + MetaLauncher *self = user_data; + sync_active (self); + } + + static gchar * + get_primary_gpu_path (const gchar *seat_name) + { + const gchar *subsystems[] = {"drm", NULL}; + gchar *path = NULL; + GList *devices, *tmp; + + g_autoptr (GUdevClient) gudev_client = g_udev_client_new (subsystems); + g_autoptr (GUdevEnumerator) enumerator = g_udev_enumerator_new (gudev_client); + + g_udev_enumerator_add_match_name (enumerator, "card*"); + g_udev_enumerator_add_match_tag (enumerator, "seat"); + ++ /* We need to explicitly match the subsystem for now. ++ * https://bugzilla.gnome.org/show_bug.cgi?id=773224 ++ */ ++ g_udev_enumerator_add_match_subsystem (enumerator, "drm"); ++ + devices = g_udev_enumerator_execute (enumerator); + if (!devices) + goto out; + + for (tmp = devices; tmp != NULL; tmp = tmp->next) + { + g_autoptr (GUdevDevice) platform_device = NULL; + g_autoptr (GUdevDevice) pci_device = NULL; + GUdevDevice *dev = tmp->data; + gint boot_vga; + const gchar *device_seat; + + /* filter out devices that are not character device, like card0-VGA-1 */ + if (g_udev_device_get_device_type (dev) != G_UDEV_DEVICE_TYPE_CHAR) + continue; + + device_seat = g_udev_device_get_property (dev, "ID_SEAT"); + if (!device_seat) + { + /* when ID_SEAT is not set, it means seat0 */ + device_seat = "seat0"; + } + else if (g_strcmp0 (device_seat, "seat0") != 0) + { + /* if the device has been explicitly assigned other seat + * than seat0, it is probably the right device to use */ + path = g_strdup (g_udev_device_get_device_file (dev)); + break; + } + +-- +2.10.1 + + +From d9dc6ac094080a4190508297e8244a8905a8dcb4 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Wed, 19 Oct 2016 10:41:14 -0400 +Subject: [PATCH 2/4] native: shore up matching of card device + +Right now we accept any character device that matches the glob card*. + +That's fine, but we can be a little more specific by checking that +the devtype is what we expect. + +This commit does that. + +https://bugzilla.gnome.org/show_bug.cgi?id=771442 +--- + src/backends/native/meta-launcher.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/backends/native/meta-launcher.c b/src/backends/native/meta-launcher.c +index 03a928a..765e5ef 100644 +--- a/src/backends/native/meta-launcher.c ++++ b/src/backends/native/meta-launcher.c +@@ -20,60 +20,62 @@ + #include "config.h" + + #include "meta-launcher.h" + + #include + + #include + #include + #include + + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + + #include "dbus-utils.h" + #include "meta-dbus-login1.h" + + #include "backends/meta-backend-private.h" + #include "meta-cursor-renderer-native.h" + #include "meta-idle-monitor-native.h" + #include "meta-renderer-native.h" + ++#define DRM_CARD_UDEV_DEVICE_TYPE "drm_minor" ++ + G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref) + G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevClient, g_object_unref) + G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevEnumerator, g_object_unref) + + struct _MetaLauncher + { + Login1Session *session_proxy; + Login1Seat *seat_proxy; + + gboolean session_active; + + int kms_fd; + }; + + static Login1Session * + get_session_proxy (GCancellable *cancellable, + GError **error) + { + g_autofree char *proxy_path = NULL; + g_autofree char *session_id = NULL; + Login1Session *session_proxy; + + if (sd_pid_get_session (getpid (), &session_id) < 0) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "Could not get session ID: %m"); + return NULL; + } +@@ -283,66 +285,71 @@ on_active_changed (Login1Session *session, + } + + static gchar * + get_primary_gpu_path (const gchar *seat_name) + { + const gchar *subsystems[] = {"drm", NULL}; + gchar *path = NULL; + GList *devices, *tmp; + + g_autoptr (GUdevClient) gudev_client = g_udev_client_new (subsystems); + g_autoptr (GUdevEnumerator) enumerator = g_udev_enumerator_new (gudev_client); + + g_udev_enumerator_add_match_name (enumerator, "card*"); + g_udev_enumerator_add_match_tag (enumerator, "seat"); + + /* We need to explicitly match the subsystem for now. + * https://bugzilla.gnome.org/show_bug.cgi?id=773224 + */ + g_udev_enumerator_add_match_subsystem (enumerator, "drm"); + + devices = g_udev_enumerator_execute (enumerator); + if (!devices) + goto out; + + for (tmp = devices; tmp != NULL; tmp = tmp->next) + { + g_autoptr (GUdevDevice) platform_device = NULL; + g_autoptr (GUdevDevice) pci_device = NULL; + GUdevDevice *dev = tmp->data; + gint boot_vga; ++ const gchar *device_type; + const gchar *device_seat; + + /* filter out devices that are not character device, like card0-VGA-1 */ + if (g_udev_device_get_device_type (dev) != G_UDEV_DEVICE_TYPE_CHAR) + continue; + ++ device_type = g_udev_device_get_property (dev, "DEVTYPE"); ++ if (g_strcmp0 (device_type, DRM_CARD_UDEV_DEVICE_TYPE) != 0) ++ continue; ++ + device_seat = g_udev_device_get_property (dev, "ID_SEAT"); + if (!device_seat) + { + /* when ID_SEAT is not set, it means seat0 */ + device_seat = "seat0"; + } + else if (g_strcmp0 (device_seat, "seat0") != 0) + { + /* if the device has been explicitly assigned other seat + * than seat0, it is probably the right device to use */ + path = g_strdup (g_udev_device_get_device_file (dev)); + break; + } + + /* skip devices that do not belong to our seat */ + if (g_strcmp0 (seat_name, device_seat)) + continue; + + platform_device = g_udev_device_get_parent_with_subsystem (dev, "platform", NULL); + if (platform_device != NULL) + { + path = g_strdup (g_udev_device_get_device_file (dev)); + break; + } + + pci_device = g_udev_device_get_parent_with_subsystem (dev, "pci", NULL); + if (pci_device != NULL) + { + /* get value of boot_vga attribute or 0 if the device has no boot_vga */ + boot_vga = g_udev_device_get_sysfs_attr_as_int (pci_device, "boot_vga"); +-- +2.10.1 + + +From 54ceafff8c8b0b02cd9124eae56a05da4f117033 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 18 Oct 2016 16:43:04 -0400 +Subject: [PATCH 3/4] native: fail on systems with connectors spread across + multiple gpus + +We don't support using more than one GPU for output yet, so we should fail +if we encounter that situation, so GDM will fall back to X. + +https://bugzilla.gnome.org/show_bug.cgi?id=771442 +--- + src/backends/native/meta-launcher.c | 63 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 62 insertions(+), 1 deletion(-) + +diff --git a/src/backends/native/meta-launcher.c b/src/backends/native/meta-launcher.c +index 765e5ef..a2885a1 100644 +--- a/src/backends/native/meta-launcher.c ++++ b/src/backends/native/meta-launcher.c +@@ -257,141 +257,202 @@ on_evdev_device_close (int fd, + + out: + close (fd); + } + + static void + sync_active (MetaLauncher *self) + { + gboolean active = login1_session_get_active (LOGIN1_SESSION (self->session_proxy)); + + if (active == self->session_active) + return; + + self->session_active = active; + + if (active) + session_unpause (); + else + session_pause (); + } + + static void + on_active_changed (Login1Session *session, + GParamSpec *pspec, + gpointer user_data) + { + MetaLauncher *self = user_data; + sync_active (self); + } + ++static guint ++count_devices_with_connectors (const gchar *seat_name, ++ GList *devices) ++{ ++ g_autoptr (GHashTable) cards = NULL; ++ GList *tmp; ++ ++ cards = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); ++ for (tmp = devices; tmp != NULL; tmp = tmp->next) ++ { ++ GUdevDevice *device = tmp->data; ++ g_autoptr (GUdevDevice) parent_device = NULL; ++ const gchar *parent_device_type = NULL; ++ const gchar *card_seat; ++ ++ /* filter out the real card devices, we only care about the connectors */ ++ if (g_udev_device_get_device_type (device) != G_UDEV_DEVICE_TYPE_NONE) ++ continue; ++ ++ /* only connectors have a modes attribute */ ++ if (!g_udev_device_has_sysfs_attr (device, "modes")) ++ continue; ++ ++ parent_device = g_udev_device_get_parent (device); ++ ++ if (g_udev_device_get_device_type (parent_device) == G_UDEV_DEVICE_TYPE_CHAR) ++ parent_device_type = g_udev_device_get_property (parent_device, "DEVTYPE"); ++ ++ if (g_strcmp0 (parent_device_type, DRM_CARD_UDEV_DEVICE_TYPE) != 0) ++ continue; ++ ++ card_seat = g_udev_device_get_property (parent_device, "ID_SEAT"); ++ ++ if (!card_seat) ++ card_seat = "seat0"; ++ ++ if (g_strcmp0 (seat_name, card_seat) != 0) ++ continue; ++ ++ g_hash_table_insert (cards, ++ (gpointer) g_udev_device_get_name (parent_device), ++ g_steal_pointer (&parent_device)); ++ } ++ ++ return g_hash_table_size (cards); ++} ++ + static gchar * + get_primary_gpu_path (const gchar *seat_name) + { + const gchar *subsystems[] = {"drm", NULL}; + gchar *path = NULL; + GList *devices, *tmp; + + g_autoptr (GUdevClient) gudev_client = g_udev_client_new (subsystems); + g_autoptr (GUdevEnumerator) enumerator = g_udev_enumerator_new (gudev_client); + + g_udev_enumerator_add_match_name (enumerator, "card*"); + g_udev_enumerator_add_match_tag (enumerator, "seat"); + + /* We need to explicitly match the subsystem for now. + * https://bugzilla.gnome.org/show_bug.cgi?id=773224 + */ + g_udev_enumerator_add_match_subsystem (enumerator, "drm"); + + devices = g_udev_enumerator_execute (enumerator); + if (!devices) + goto out; + ++ /* For now, fail on systems where some of the connectors ++ * are connected to secondary gpus. ++ * ++ * https://bugzilla.gnome.org/show_bug.cgi?id=771442 ++ */ ++ if (g_getenv ("MUTTER_ALLOW_HYBRID_GPUS") == NULL) ++ { ++ guint num_devices; ++ ++ num_devices = count_devices_with_connectors (seat_name, devices); ++ if (num_devices != 1) ++ goto out; ++ } ++ + for (tmp = devices; tmp != NULL; tmp = tmp->next) + { + g_autoptr (GUdevDevice) platform_device = NULL; + g_autoptr (GUdevDevice) pci_device = NULL; + GUdevDevice *dev = tmp->data; + gint boot_vga; + const gchar *device_type; + const gchar *device_seat; + + /* filter out devices that are not character device, like card0-VGA-1 */ + if (g_udev_device_get_device_type (dev) != G_UDEV_DEVICE_TYPE_CHAR) + continue; + + device_type = g_udev_device_get_property (dev, "DEVTYPE"); + if (g_strcmp0 (device_type, DRM_CARD_UDEV_DEVICE_TYPE) != 0) + continue; + + device_seat = g_udev_device_get_property (dev, "ID_SEAT"); + if (!device_seat) + { + /* when ID_SEAT is not set, it means seat0 */ + device_seat = "seat0"; + } + else if (g_strcmp0 (device_seat, "seat0") != 0) + { + /* if the device has been explicitly assigned other seat + * than seat0, it is probably the right device to use */ + path = g_strdup (g_udev_device_get_device_file (dev)); + break; + } + + /* skip devices that do not belong to our seat */ + if (g_strcmp0 (seat_name, device_seat)) + continue; + + platform_device = g_udev_device_get_parent_with_subsystem (dev, "platform", NULL); + if (platform_device != NULL) + { + path = g_strdup (g_udev_device_get_device_file (dev)); + break; + } + + pci_device = g_udev_device_get_parent_with_subsystem (dev, "pci", NULL); + if (pci_device != NULL) + { + /* get value of boot_vga attribute or 0 if the device has no boot_vga */ + boot_vga = g_udev_device_get_sysfs_attr_as_int (pci_device, "boot_vga"); + if (boot_vga == 1) + { + /* found the boot_vga device */ + path = g_strdup (g_udev_device_get_device_file (dev)); + break; + } + } + } + ++out: + g_list_free_full (devices, g_object_unref); + +-out: + return path; + } + + static gboolean + get_kms_fd (Login1Session *session_proxy, + const gchar *seat_id, + int *fd_out, + GError **error) + { + int major, minor; + int fd; + + g_autofree gchar *path = get_primary_gpu_path (seat_id); + if (!path) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "could not find drm kms device"); + return FALSE; + } + + if (!get_device_info_from_path (path, &major, &minor)) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "Could not get device info for path %s: %m", path); + return FALSE; + } +-- +2.10.1 + + +From 0d87baa029329c409646e04bcf40bea5da67b5f7 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Wed, 19 Oct 2016 14:27:24 -0400 +Subject: [PATCH 4/4] native: don't call steal_pointer prematurely + +commit e2bfaf07514ed633f8721b5f521577685b6cccc0 does this: + +g_hash_table_insert (cards, + g_udev_device_get_name (parent_device), + g_steal_pointer (&parent_device)); + +The problem is the g_steal_pointer call may happen before the +g_udev_device_get_name call leading to a crash. + +This commit does the get_name call on an earlier line + +https://bugzilla.gnome.org/show_bug.cgi?id=771442 +--- + src/backends/native/meta-launcher.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/backends/native/meta-launcher.c b/src/backends/native/meta-launcher.c +index a2885a1..ddb7080 100644 +--- a/src/backends/native/meta-launcher.c ++++ b/src/backends/native/meta-launcher.c +@@ -270,88 +270,90 @@ sync_active (MetaLauncher *self) + self->session_active = active; + + if (active) + session_unpause (); + else + session_pause (); + } + + static void + on_active_changed (Login1Session *session, + GParamSpec *pspec, + gpointer user_data) + { + MetaLauncher *self = user_data; + sync_active (self); + } + + static guint + count_devices_with_connectors (const gchar *seat_name, + GList *devices) + { + g_autoptr (GHashTable) cards = NULL; + GList *tmp; + + cards = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + for (tmp = devices; tmp != NULL; tmp = tmp->next) + { + GUdevDevice *device = tmp->data; + g_autoptr (GUdevDevice) parent_device = NULL; + const gchar *parent_device_type = NULL; ++ const gchar *parent_device_name = NULL; + const gchar *card_seat; + + /* filter out the real card devices, we only care about the connectors */ + if (g_udev_device_get_device_type (device) != G_UDEV_DEVICE_TYPE_NONE) + continue; + + /* only connectors have a modes attribute */ + if (!g_udev_device_has_sysfs_attr (device, "modes")) + continue; + + parent_device = g_udev_device_get_parent (device); + + if (g_udev_device_get_device_type (parent_device) == G_UDEV_DEVICE_TYPE_CHAR) + parent_device_type = g_udev_device_get_property (parent_device, "DEVTYPE"); + + if (g_strcmp0 (parent_device_type, DRM_CARD_UDEV_DEVICE_TYPE) != 0) + continue; + + card_seat = g_udev_device_get_property (parent_device, "ID_SEAT"); + + if (!card_seat) + card_seat = "seat0"; + + if (g_strcmp0 (seat_name, card_seat) != 0) + continue; + ++ parent_device_name = g_udev_device_get_name (parent_device); + g_hash_table_insert (cards, +- (gpointer) g_udev_device_get_name (parent_device), ++ (gpointer) parent_device_name , + g_steal_pointer (&parent_device)); + } + + return g_hash_table_size (cards); + } + + static gchar * + get_primary_gpu_path (const gchar *seat_name) + { + const gchar *subsystems[] = {"drm", NULL}; + gchar *path = NULL; + GList *devices, *tmp; + + g_autoptr (GUdevClient) gudev_client = g_udev_client_new (subsystems); + g_autoptr (GUdevEnumerator) enumerator = g_udev_enumerator_new (gudev_client); + + g_udev_enumerator_add_match_name (enumerator, "card*"); + g_udev_enumerator_add_match_tag (enumerator, "seat"); + + /* We need to explicitly match the subsystem for now. + * https://bugzilla.gnome.org/show_bug.cgi?id=773224 + */ + g_udev_enumerator_add_match_subsystem (enumerator, "drm"); + + devices = g_udev_enumerator_execute (enumerator); + if (!devices) + goto out; + + /* For now, fail on systems where some of the connectors + * are connected to secondary gpus. +-- +2.10.1 + diff --git a/SOURCES/startup-notification.patch b/SOURCES/startup-notification.patch new file mode 100644 index 0000000..1a4dd0b --- /dev/null +++ b/SOURCES/startup-notification.patch @@ -0,0 +1,45 @@ +From 4ed430b4ef3013c96fa56cdc57b925b42d20ead9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 20 Oct 2016 18:00:04 +0200 +Subject: [PATCH] gtk-shell: Work around non-working startup notifications + +GNOME Shell relies on the MetaScreen::startup-sequence-changed signal, +which is tied to (lib)startup-notification and therefore X11. As a result, +when we remove the startup sequence of a wayland client, GNOME Shell will +not be notified about this until startup-notification's timeout is hit. +As a temporary stop-gap, go through XWayland even for wayland clients, +so that the signal is emitted when expected. + +https://bugzilla.gnome.org/show_bug.cgi?id=768531 +--- + src/wayland/meta-wayland-gtk-shell.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/src/wayland/meta-wayland-gtk-shell.c b/src/wayland/meta-wayland-gtk-shell.c +index d6e249f..9d1a19e 100644 +--- a/src/wayland/meta-wayland-gtk-shell.c ++++ b/src/wayland/meta-wayland-gtk-shell.c +@@ -219,11 +219,21 @@ gtk_shell_set_startup_id (struct wl_client *client, + struct wl_resource *resource, + const char *startup_id) + { ++#if 0 + MetaDisplay *display; + + display = meta_get_display (); + meta_startup_notification_remove_sequence (display->startup_notification, + startup_id); ++#else ++ /* HACK: MetaScreen::startup-sequence-changed is currently tied to ++ (lib)startup-notification, which means it only works on X11; ++ so for now, always go through XWayland, even for wayland clients */ ++ gdk_x11_display_broadcast_startup_message (gdk_display_get_default (), ++ "remove", ++ "ID", startup_id, ++ NULL); ++#endif + } + + static void +-- +2.9.3 diff --git a/SOURCES/support-headless-mode.patch b/SOURCES/support-headless-mode.patch new file mode 100644 index 0000000..57245e4 --- /dev/null +++ b/SOURCES/support-headless-mode.patch @@ -0,0 +1,481 @@ +From 0826616da1dacf29e3e08dae6d2ffe4116e5bdff Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 16 Jul 2015 15:07:38 +0200 +Subject: [PATCH 1/2] barrier: Guard against X errors + +--- + src/backends/x11/meta-barrier-x11.c | 22 +++++++++++++++------- + 1 file changed, 15 insertions(+), 7 deletions(-) + +diff --git a/src/backends/x11/meta-barrier-x11.c b/src/backends/x11/meta-barrier-x11.c +index 054e5cdc6..1fc3fd8cc 100644 +--- a/src/backends/x11/meta-barrier-x11.c ++++ b/src/backends/x11/meta-barrier-x11.c +@@ -38,6 +38,7 @@ + #include + #include + #include ++#include + #include "backends/x11/meta-barrier-x11.h" + #include "display-private.h" + +@@ -107,6 +108,7 @@ meta_barrier_impl_x11_new (MetaBarrier *barrier) + MetaDisplay *display = barrier->priv->display; + Display *dpy; + Window root; ++ PointerBarrier xbarrier; + unsigned int allowed_motion_dirs; + + if (display == NULL) +@@ -119,18 +121,24 @@ meta_barrier_impl_x11_new (MetaBarrier *barrier) + priv = meta_barrier_impl_x11_get_instance_private (self); + priv->barrier = barrier; + ++ meta_error_trap_push (display); + dpy = display->xdisplay; + root = DefaultRootWindow (dpy); + + allowed_motion_dirs = + meta_border_get_allows_directions (&barrier->priv->border); +- priv->xbarrier = XFixesCreatePointerBarrier (dpy, root, +- barrier->priv->border.line.a.x, +- barrier->priv->border.line.a.y, +- barrier->priv->border.line.b.x, +- barrier->priv->border.line.b.y, +- allowed_motion_dirs, +- 0, NULL); ++ xbarrier = XFixesCreatePointerBarrier (dpy, root, ++ barrier->priv->border.line.a.x, ++ barrier->priv->border.line.a.y, ++ barrier->priv->border.line.b.x, ++ barrier->priv->border.line.b.y, ++ allowed_motion_dirs, ++ 0, NULL); ++ ++ if (meta_error_trap_pop_with_return (display) != Success) ++ return NULL; ++ ++ priv->xbarrier = xbarrier; + + g_hash_table_insert (display->xids, &priv->xbarrier, barrier); + +-- +2.12.0 + + +From 2da829399dc79b5c51ca55ab6e633c4a4769c15a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 16 Jul 2015 15:12:55 +0200 +Subject: [PATCH 2/2] Do not crash when starting up with no monitor connected + +Some parts of Mutter currently assume there's always a monitor connected +to the screen. This assumption can be incorrect - e.g. a desktop +computer can be powered on and a monitor only plugged in after the +desktop session - or the GDM login - has already been reached. + +Fix the various places that assume so, making the code robust to the +above use case. + +Based on an initial patch by Cosimo Cecchi. +--- + src/backends/x11/meta-monitor-manager-xrandr.c | 4 +- + src/compositor/meta-window-actor.c | 2 +- + src/core/constraints.c | 71 +++++++++++++++----------- + src/core/place.c | 4 ++ + src/core/screen.c | 10 +++- + src/core/window.c | 57 ++++++++++++++------- + src/core/workspace.c | 3 ++ + src/x11/window-x11.c | 3 +- + 8 files changed, 100 insertions(+), 54 deletions(-) + +diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c +index b0a77dadb..b82120af9 100644 +--- a/src/backends/x11/meta-monitor-manager-xrandr.c ++++ b/src/backends/x11/meta-monitor-manager-xrandr.c +@@ -1141,7 +1141,9 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager, + crtc->current_mode = NULL; + } + +- g_assert (width > 0 && height > 0); ++ if (width == 0 || height == 0) ++ return; ++ + /* The 'physical size' of an X screen is meaningless if that screen + * can consist of many monitors. So just pick a size that make the + * dpi 96. +diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c +index 9395caac5..fb29ca1c9 100644 +--- a/src/compositor/meta-window-actor.c ++++ b/src/compositor/meta-window-actor.c +@@ -959,7 +959,7 @@ queue_send_frame_messages_timeout (MetaWindowActor *self) + outputs = meta_monitor_manager_get_outputs (monitor_manager, &n_outputs); + for (i = 0; i < n_outputs; i++) + { +- if (outputs[i].winsys_id == window->monitor->winsys_id && outputs[i].crtc) ++ if (window->monitor && outputs[i].winsys_id == window->monitor->winsys_id && outputs[i].crtc) + { + refresh_rate = outputs[i].crtc->current_mode->refresh_rate; + break; +diff --git a/src/core/constraints.c b/src/core/constraints.c +index 67b52c994..3d1701e88 100644 +--- a/src/core/constraints.c ++++ b/src/core/constraints.c +@@ -29,6 +29,7 @@ + #include + + #include ++#include + #include + + #if 0 +@@ -337,6 +338,8 @@ setup_constraint_info (ConstraintInfo *info, + const MetaMonitorInfo *monitor_info; + MetaWorkspace *cur_workspace; + ++ memset (info, 0, sizeof (ConstraintInfo)); ++ + info->orig = *orig; + info->current = *new; + +@@ -382,40 +385,43 @@ setup_constraint_info (ConstraintInfo *info, + if (!info->is_user_action) + info->fixed_directions = FIXED_DIRECTION_NONE; + ++ cur_workspace = window->screen->active_workspace; + monitor_info = + meta_screen_get_monitor_for_rect (window->screen, &info->current); +- meta_window_get_work_area_for_monitor (window, +- monitor_info->number, +- &info->work_area_monitor); + +- if (!window->fullscreen || window->fullscreen_monitors[0] == -1) ++ if (monitor_info) + { +- info->entire_monitor = monitor_info->rect; +- } +- else +- { +- int i = 0; +- long monitor; ++ meta_window_get_work_area_for_monitor (window, ++ monitor_info->number, ++ &info->work_area_monitor); + +- monitor = window->fullscreen_monitors[i]; +- info->entire_monitor = +- window->screen->monitor_infos[monitor].rect; +- for (i = 1; i <= 3; i++) ++ if (!window->fullscreen || window->fullscreen_monitors[0] == -1) ++ { ++ info->entire_monitor = monitor_info->rect; ++ } ++ else + { ++ int i = 0; ++ long monitor; ++ + monitor = window->fullscreen_monitors[i]; +- meta_rectangle_union (&info->entire_monitor, +- &window->screen->monitor_infos[monitor].rect, +- &info->entire_monitor); ++ info->entire_monitor = ++ window->screen->monitor_infos[monitor].rect; ++ for (i = 1; i <= 3; i++) ++ { ++ monitor = window->fullscreen_monitors[i]; ++ meta_rectangle_union (&info->entire_monitor, ++ &window->screen->monitor_infos[monitor].rect, ++ &info->entire_monitor); ++ } + } ++ info->usable_screen_region = ++ meta_workspace_get_onscreen_region (cur_workspace); ++ info->usable_monitor_region = ++ meta_workspace_get_onmonitor_region (cur_workspace, ++ monitor_info->number); + } + +- cur_workspace = window->screen->active_workspace; +- info->usable_screen_region = +- meta_workspace_get_onscreen_region (cur_workspace); +- info->usable_monitor_region = +- meta_workspace_get_onmonitor_region (cur_workspace, +- monitor_info->number); +- + /* Log all this information for debugging */ + meta_topic (META_DEBUG_GEOMETRY, + "Setting up constraint info:\n" +@@ -489,14 +495,17 @@ place_window_if_needed(MetaWindow *window, + */ + monitor_info = + meta_screen_get_monitor_for_rect (window->screen, &placed_rect); +- info->entire_monitor = monitor_info->rect; +- meta_window_get_work_area_for_monitor (window, +- monitor_info->number, +- &info->work_area_monitor); + cur_workspace = window->screen->active_workspace; +- info->usable_monitor_region = +- meta_workspace_get_onmonitor_region (cur_workspace, +- monitor_info->number); ++ if (monitor_info) ++ { ++ info->entire_monitor = monitor_info->rect; ++ meta_window_get_work_area_for_monitor (window, ++ monitor_info->number, ++ &info->work_area_monitor); ++ info->usable_monitor_region = ++ meta_workspace_get_onmonitor_region (cur_workspace, ++ monitor_info->number); ++ } + + info->current.x = placed_rect.x; + info->current.y = placed_rect.y; +diff --git a/src/core/place.c b/src/core/place.c +index db71b83ce..0f046f046 100644 +--- a/src/core/place.c ++++ b/src/core/place.c +@@ -811,6 +811,8 @@ meta_window_place (MetaWindow *window, + + /* Warning, this function is a round trip! */ + xi = meta_screen_get_current_monitor_info (window->screen); ++ if (!xi) ++ goto done; + + w = xi->rect.width; + h = xi->rect.height; +@@ -856,6 +858,8 @@ meta_window_place (MetaWindow *window, + + /* Warning, this is a round trip! */ + xi = meta_screen_get_current_monitor_info (window->screen); ++ if (!xi) ++ goto done; + + /* Maximize windows if they are too big for their work area (bit of + * a hack here). Assume undecorated windows probably don't intend to +diff --git a/src/core/screen.c b/src/core/screen.c +index b8ac22f76..54a0b0aba 100644 +--- a/src/core/screen.c ++++ b/src/core/screen.c +@@ -381,7 +381,10 @@ meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen, + + meta_screen_ensure_xinerama_indices (screen); + +- return screen->monitor_infos[index].xinerama_index; ++ if (index >= 0 && index < screen->n_monitor_infos) ++ return screen->monitor_infos[index].xinerama_index; ++ ++ return -1; + } + + int +@@ -1395,6 +1398,9 @@ meta_screen_get_monitor_for_rect (MetaScreen *screen, + int i; + int best_monitor, monitor_score, rect_area; + ++ if (screen->n_monitor_infos == 0) ++ return NULL; ++ + if (screen->n_monitor_infos == 1) + return &screen->monitor_infos[0]; + +@@ -1448,7 +1454,7 @@ meta_screen_get_monitor_index_for_rect (MetaScreen *screen, + MetaRectangle *rect) + { + const MetaMonitorInfo *monitor = meta_screen_get_monitor_for_rect (screen, rect); +- return monitor->number; ++ return monitor ? monitor->number : -1; + } + + const MetaMonitorInfo * +diff --git a/src/core/window.c b/src/core/window.c +index e3e15cf26..9745b42e0 100644 +--- a/src/core/window.c ++++ b/src/core/window.c +@@ -1029,7 +1029,8 @@ _meta_window_shared_new (MetaDisplay *display, + + window->monitor = meta_screen_calculate_monitor_for_window (window->screen, + window); +- window->preferred_output_winsys_id = window->monitor->winsys_id; ++ window->preferred_output_winsys_id = window->monitor ? window->monitor->winsys_id ++ : -1; + + window->tile_match = NULL; + +@@ -2280,7 +2281,10 @@ meta_window_show (MetaWindow *window) + if (meta_prefs_get_auto_maximize() && window->showing_for_first_time && window->has_maximize_func) + { + MetaRectangle work_area; +- meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area); ++ if (window->monitor) ++ meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area); ++ else ++ meta_window_get_work_area_current_monitor (window, &work_area); + /* Automaximize windows that map with a size > MAX_UNMAXIMIZED_WINDOW_AREA of the work area */ + if (window->rect.width * window->rect.height > work_area.width * work_area.height * MAX_UNMAXIMIZED_WINDOW_AREA) + { +@@ -2677,7 +2681,7 @@ meta_window_maximize_internal (MetaWindow *window, + meta_window_recalc_features (window); + set_net_wm_state (window); + +- if (window->monitor->in_fullscreen) ++ if (window->monitor && window->monitor->in_fullscreen) + meta_screen_queue_check_fullscreen (window->screen); + + g_object_freeze_notify (G_OBJECT (window)); +@@ -2863,6 +2867,9 @@ meta_window_is_monitor_sized (MetaWindow *window) + if (meta_window_is_screen_sized (window)) + return TRUE; + ++ if (!window->monitor) ++ return FALSE; ++ + if (window->override_redirect) + { + MetaRectangle window_rect, monitor_rect; +@@ -2886,7 +2893,7 @@ meta_window_is_monitor_sized (MetaWindow *window) + gboolean + meta_window_is_on_primary_monitor (MetaWindow *window) + { +- return window->monitor->is_primary; ++ return window->monitor ? window->monitor->is_primary : FALSE; + } + + /** +@@ -3027,7 +3034,10 @@ meta_window_unmaximize (MetaWindow *window, + MetaRectangle work_area; + MetaRectangle old_frame_rect, old_buffer_rect; + +- meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area); ++ if (window->monitor) ++ meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area); ++ else ++ meta_window_get_work_area_current_monitor (window, &work_area); + meta_window_get_frame_rect (window, &old_frame_rect); + meta_window_get_buffer_rect (window, &old_buffer_rect); + +@@ -3123,7 +3133,7 @@ meta_window_unmaximize (MetaWindow *window, + + meta_window_recalc_features (window); + set_net_wm_state (window); +- if (!window->monitor->in_fullscreen) ++ if (window->monitor && !window->monitor->in_fullscreen) + meta_screen_queue_check_fullscreen (window->screen); + } + +@@ -3522,7 +3532,7 @@ maybe_move_attached_dialog (MetaWindow *window, + int + meta_window_get_monitor (MetaWindow *window) + { +- return window->monitor->number; ++ return window->monitor ? window->monitor->number : -1; + } + + static MetaMonitorInfo * +@@ -3549,14 +3559,15 @@ meta_window_update_for_monitors_changed (MetaWindow *window) + { + const MetaMonitorInfo *old, *new; + +- if (window->override_redirect || window->type == META_WINDOW_DESKTOP) ++ old = window->monitor; ++ ++ if (!old || window->screen->n_monitor_infos == 0 || ++ window->override_redirect || window->type == META_WINDOW_DESKTOP) + { + meta_window_update_monitor (window, FALSE); + return; + } + +- old = window->monitor; +- + /* Try the preferred output first */ + new = find_monitor_by_winsys_id (window, window->preferred_output_winsys_id); + +@@ -3643,7 +3654,7 @@ meta_window_move_resize_internal (MetaWindow *window, + */ + + gboolean did_placement; +- guint old_output_winsys_id; ++ guint old_output_winsys_id, new_output_winsys_id; + MetaRectangle unconstrained_rect; + MetaRectangle constrained_rect; + MetaMoveResizeResultFlags result = 0; +@@ -3737,13 +3748,15 @@ meta_window_move_resize_internal (MetaWindow *window, + did_placement); + } + +- old_output_winsys_id = window->monitor->winsys_id; ++ old_output_winsys_id = window->monitor ? window->monitor->winsys_id : -1; + + meta_window_update_monitor (window, flags & META_MOVE_RESIZE_USER_ACTION); + +- if (old_output_winsys_id != window->monitor->winsys_id && ++ new_output_winsys_id = window->monitor ? window->monitor->winsys_id : -1; ++ ++ if (old_output_winsys_id != new_output_winsys_id && + flags & META_MOVE_RESIZE_MOVE_ACTION && flags & META_MOVE_RESIZE_USER_ACTION) +- window->preferred_output_winsys_id = window->monitor->winsys_id; ++ window->preferred_output_winsys_id = new_output_winsys_id; + + if ((result & META_MOVE_RESIZE_RESULT_FRAME_SHAPE_CHANGED) && window->frame_bounds) + { +@@ -3849,7 +3862,7 @@ meta_window_move_to_monitor (MetaWindow *window, + { + MetaRectangle old_area, new_area; + +- if (monitor == window->monitor->number) ++ if (!window->monitor || monitor == window->monitor->number) + return; + + meta_window_get_work_area_for_monitor (window, +@@ -6104,9 +6117,17 @@ void + meta_window_get_work_area_current_monitor (MetaWindow *window, + MetaRectangle *area) + { +- meta_window_get_work_area_for_monitor (window, +- window->monitor->number, +- area); ++ if (window->monitor) ++ { ++ meta_window_get_work_area_for_monitor (window, ++ window->monitor->number, ++ area); ++ } ++ else if (area) ++ { ++ MetaRectangle empty = { 0, 0, 0, 0 }; ++ *area = empty; ++ } + } + + /** +diff --git a/src/core/workspace.c b/src/core/workspace.c +index cfac7dc48..a73ac6bb7 100644 +--- a/src/core/workspace.c ++++ b/src/core/workspace.c +@@ -765,6 +765,9 @@ ensure_work_areas_validated (MetaWorkspace *workspace) + g_assert (workspace->screen_edges == NULL); + g_assert (workspace->monitor_edges == NULL); + ++ if (workspace->screen->n_monitor_infos == 0) ++ return; ++ + /* STEP 1: Get the list of struts */ + + workspace->all_struts = copy_strut_list (workspace->builtin_struts); +diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c +index 376d73c78..9b102e589 100644 +--- a/src/x11/window-x11.c ++++ b/src/x11/window-x11.c +@@ -2032,7 +2032,8 @@ meta_window_move_resize_request (MetaWindow *window, + rect.width = width; + rect.height = height; + +- meta_screen_get_monitor_geometry (window->screen, window->monitor->number, &monitor_rect); ++ if (window->monitor) ++ meta_screen_get_monitor_geometry (window->screen, window->monitor->number, &monitor_rect); + + /* Workaround braindead legacy apps that don't know how to + * fullscreen themselves properly - don't get fooled by +-- +2.12.0 + diff --git a/SPECS/mutter.spec b/SPECS/mutter.spec new file mode 100644 index 0000000..6e09914 --- /dev/null +++ b/SPECS/mutter.spec @@ -0,0 +1,785 @@ +%global gtk3_version 3.19.8 +%global gsettings_desktop_schemas_version 3.21.4 +%global json_glib_version 0.12.0 + +Name: mutter +Version: 3.22.3 +Release: 12%{?dist} +Summary: Window and compositing manager based on Clutter + +License: GPLv2+ +#VCS: git:git://git.gnome.org/mutter +URL: http://www.gnome.org +Source0: http://download.gnome.org/sources/%{name}/3.22/%{name}-%{version}.tar.xz + +# https://bugzilla.gnome.org/show_bug.cgi?id=771442 +Patch0: fall-back-to-xorg-on-hybrid-gpus.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1331382 +Patch1: 0001-Revert-backend-x11-Ensure-the-Xkb-group-index-remain.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1390607 +Patch2: 0001-wayland-xdg-shell-Handle-the-wl_output-on-the-set_fu.patch + +Patch3: startup-notification.patch + +Patch4: deal-more-gracefully-with-oversized-windows.patch +Patch5: support-headless-mode.patch + +Patch6: 0001-monitor-manager-xrandr-Work-around-spurious-hotplugs.patch +Patch7: 0001-monitor-manager-xrandr-Force-an-update-when-resuming.patch +Patch8: 0001-monitor-config-Consider-external-layout-before-defau.patch + +Patch9: Enable-threeaded-swap-wait.patch + +Patch10: 0001-events-Don-t-move-sloppy-focus-while-buttons-are-pre.patch +Patch11: 0001-backends-x11-Support-synaptics-configuration.patch + +Patch12: 0001-display-Check-we-have-a-screen-before-freeing-it.patch + +Patch13: 0001-cogl-Prefer-swizzling-to-convert-BGRA-buffers.patch + +Patch14: 0001-cally-Fix-translation-to-screen-coordinates.patch + +Patch15: 0001-window-actor-Special-case-shaped-Java-windows.patch + +Patch16: 0001-clutter-clone-Unset-source-when-source-actor-is-dest.patch + +Patch17: 0001-stack-tracker-Keep-override-redirect-windows-on-top.patch + +Patch18: 0001-screen-Remove-stray-assert.patch + +# http://bugzilla.gnome.org/show_bug.cgi?id=733277 +Patch20: 0008-Add-support-for-quad-buffer-stereo.patch +Patch21: 0001-build-Lower-automake-requirement.patch + +Patch22: add-support-for-plain-old-x-device-configuration.patch + +BuildRequires: chrpath +BuildRequires: pango-devel +BuildRequires: startup-notification-devel +BuildRequires: gnome-desktop3-devel +BuildRequires: gtk3-devel >= %{gtk3_version} +BuildRequires: pkgconfig +BuildRequires: gobject-introspection-devel >= 1.41.0 +BuildRequires: libSM-devel +BuildRequires: libX11-devel +BuildRequires: libXdamage-devel +BuildRequires: libXext-devel +BuildRequires: libXfixes-devel +BuildRequires: libXi-devel +BuildRequires: libXrandr-devel +BuildRequires: libXrender-devel +BuildRequires: libXcursor-devel +BuildRequires: libXcomposite-devel +BuildRequires: libxcb-devel +BuildRequires: libxkbcommon-devel +BuildRequires: libxkbcommon-x11-devel +BuildRequires: libxkbfile-devel +BuildRequires: mesa-libGL-devel +BuildRequires: mesa-libgbm-devel +BuildRequires: pam-devel +BuildRequires: upower-devel +BuildRequires: xkeyboard-config-devel +BuildRequires: zenity +BuildRequires: desktop-file-utils +# Bootstrap requirements +BuildRequires: gtk-doc gnome-common gettext-devel +BuildRequires: libcanberra-devel +BuildRequires: gsettings-desktop-schemas-devel >= %{gsettings_desktop_schemas_version} +BuildRequires: automake, autoconf, libtool + +BuildRequires: json-glib-devel >= %{json_glib_version} +BuildRequires: libgudev1-devel + +Obsoletes: mutter-wayland < 3.13.0 +Obsoletes: mutter-wayland-devel < 3.13.0 + +# Make sure yum updates gnome-shell as well; otherwise we might end up with +# broken gnome-shell installations due to mutter ABI changes. +Conflicts: gnome-shell < 3.21.1 + +Requires: control-center-filesystem +Requires: gsettings-desktop-schemas%{?_isa} >= %{gsettings_desktop_schemas_version} +Requires: gtk3%{?_isa} >= %{gtk3_version} +Requires: startup-notification +Requires: dbus-x11 +Requires: zenity + +Requires: json-glib%{?_isa} >= %{json_glib_version} + +%description +Mutter is a window and compositing manager that displays and manages +your desktop via OpenGL. Mutter combines a sophisticated display engine +using the Clutter toolkit with solid window-management logic inherited +from the Metacity window manager. + +While Mutter can be used stand-alone, it is primarily intended to be +used as the display core of a larger system such as GNOME Shell. For +this reason, Mutter is very extensible via plugins, which are used both +to add fancy visual effects and to rework the window management +behaviors to meet the needs of the environment. + +%package devel +Summary: Development package for %{name} +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description devel +Header files and libraries for developing Mutter plugins. Also includes +utilities for testing Metacity/Mutter themes. + +%prep +%setup -q +%patch0 -p1 +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 -b .deal-with-oversized-windows +%patch5 -p1 -b .support-headless-mode +%patch6 -p1 -b .workaround-xvnc-spurious-hotplugs +%patch7 -p1 -b .force-randr-update-on-resume +%patch8 -p1 -b .support-external-monitor-layout +%patch9 -p1 -b .threaded-swap-wait +%patch10 -p1 -b .dont-move-sloppy-focus-with-button-pressed +%patch11 -p1 -b .synaptics-touchpad-configuration +%patch12 -p1 -b .fix-segfault-on-early-exit +%patch13 -p1 -b .bgra-buffer-swizzling +%patch14 -p1 -b .fix-cally-screen-coordinates +%patch15 -p1 -b .special-case-shaped-java-windows +%patch16 -p1 -b .unset-source-when-actor-is-destroyed +%patch17 -p1 -b .keep-OR-windows-on-top +%patch18 -p1 -b .drop-stray-assert + +%patch20 -p1 -b .quad-buffer-stereo +%patch21 -p1 -b .lower-automake-requirement + +%patch22 -p1 -b .add-support-for-plain-old-x-device-configuration + +%build +autoreconf +(if ! test -x configure; then NOCONFIGURE=1 ./autogen.sh; fi; + %configure --disable-static --enable-compile-warnings=maximum --disable-wayland-egl-server) + +SHOULD_HAVE_DEFINED="HAVE_SM HAVE_RANDR HAVE_STARTUP_NOTIFICATION" + +for I in $SHOULD_HAVE_DEFINED; do + if ! grep -q "define $I" config.h; then + echo "$I was not defined in config.h" + grep "$I" config.h + exit 1 + else + echo "$I was defined as it should have been" + grep "$I" config.h + fi +done + +make %{?_smp_mflags} V=1 + +%install +%make_install + +#Remove libtool archives. +rm -rf %{buildroot}/%{_libdir}/*.la + +%find_lang %{name} + +# Mutter contains a .desktop file so we just need to validate it +desktop-file-validate %{buildroot}/%{_datadir}/applications/%{name}.desktop + +%post -p /sbin/ldconfig + +%postun +/sbin/ldconfig +if [ $1 -eq 0 ]; then + glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || : +fi + +%posttrans +glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || : + +%files -f %{name}.lang +%license COPYING +%doc NEWS +%{_bindir}/mutter +%{_datadir}/applications/*.desktop +%{_libdir}/lib*.so.* +%{_libdir}/mutter/ +%{_libexecdir}/mutter-restart-helper +%{_datadir}/GConf/gsettings/mutter-schemas.convert +%{_datadir}/glib-2.0/schemas/org.gnome.mutter.gschema.xml +%{_datadir}/glib-2.0/schemas/org.gnome.mutter.wayland.gschema.xml +%{_datadir}/gnome-control-center/keybindings/50-mutter-*.xml +%{_mandir}/man1/mutter.1* + +%files devel +%{_includedir}/* +%{_libdir}/lib*.so +%{_libdir}/pkgconfig/* + +%changelog +* Tue Oct 10 2017 Rui Matos - 3.22.3-12 +- Add support for plain old X device configuration +- Resolves: #1515138 + +* Mon Jun 26 2017 Florian Müllner - 3.24.3-11 +- Prevent crash when removing workspace with on-all-workspaces windows + present (like desktop icons) +- Resolves: #1453065 + +* Wed Jun 14 2017 Florian Müllner - 3.24.3-10 +- Keep OR windows stacked on top +- Resolves: #1437203 + +* Thu Jun 08 2017 Florian Müllner - 3.24.3-9 +- Fix crash when a window closes during Alt+Tab +- Resolves: #1438722 + +* Tue May 16 2017 Florian Müllner - 3.24.3-8 +- Special-case shaped java windows to fix OpenJDK's compliance test +- Resolves: #1363784 + +* Fri Apr 28 2017 Florian Müllner - 3.24.3-7 +- Fix cally translation of screen coordinates +- Resolves: #1439194 + +* Fri Mar 17 2017 Florian Müllner - 3.22.3-6 +- Recreate build files after modifying templates with the last patch +- Resolves: #1387025 + +* Thu Mar 16 2017 Owen Taylor - 3.22.3-6 +- Add back quad-buffer stereo patches, rebased to 3.22 +- Resolves: #1387025 + +* Wed Mar 15 2017 Carlos Garnacho - 3.22.3-5 +- Swizzle BGRA buffers to avoid pixel conversions +- Resolves: #1387025 + +* Tue Mar 14 2017 Florian Müllner - 3.22.3-4 +- Don't segfault on early exit +- Resolves: #1369073 + +* Mon Mar 13 2017 Carlos Garnacho - 3.22.3-3 +- Handle synaptics settings +- Resolves: #1387025 + +* Mon Mar 13 2017 Florian Müllner - 3.22.3-2 +- Re-add downstream patches +- Resolves: #1387025 + +* Thu Feb 16 2017 Kalev Lember - 3.22.3-1 +- Update to 3.22.3 +- Resolves: #1387025 + +* Fri Feb 03 2017 Kalev Lember - 3.22.2-1 +- Update to 3.22.2 +- Resolves: #1387025 + +* Fri Sep 16 2016 Florian Müllner - 3.14.4-31 +- Make meta_window_actor_update_visibility() public + Related: #1306670 + +* Mon Aug 29 2016 Owen Taylor - 3.14.4-29 +- Allow clutter to fallback to the classic gl driver since mesa's + software driver doesn't support gl3 + Related: #1361251 + +* Thu Aug 11 2016 Rui Matos - 3.14.4-28 +- Add patch to require clutter to use the gl3 driver + Resolves: #1361251 + +* Mon Jul 18 2016 Rui Matos - 3.14.4-27 +- Require a clutter version that provides all the new APIs + Related: rhbz#1330488 + +* Thu Jun 30 2016 Owen Taylor - 3.14.4-26 +- Turn on newly added "threaded swap wait" functionality in Cogl + so that on NVIDIA cards, frame completion is handled in a proper + non-blocking fashion, fixing bugs with idles not running when + they should. + Resolves: #1305076 + +* Wed Jun 29 2016 Rui Matos - 3.14.4-25 +- Handle video memory purge errors + Resolves: #1330488 + +* Tue Jun 28 2016 Florian Müllner - 3.14.4-24 +- Update translations + Resolves: #1304233 + +* Fri Jun 17 2016 Florian Müllner - 3.14.4-23 +- Track ignored damage + Resolves: #1165840 + +* Thu May 19 2016 Florian Müllner - 3.14.4-22 +- Support external monitor layout configuration + Related: #1290448 + +* Thu May 12 2016 Florian Müllner - 3.14.4-21 +- Ignore window groups for stacking + Resolves: #1167889 + +* Tue May 10 2016 Owen Taylor - 3.14.4-20 +- Rebase and add back stereo support patch that was dropped in + update to 3.14. +- Retain the last active window for seamless restarts. + Resolves: #1305076 + +* Thu Apr 21 2016 Florian Müllner - 3.14.4-19 +- Make Cogl errors non-fatal + Related: #1326372 + +* Wed Apr 20 2016 Carlos Garnacho - 3.14.4-18 +- Fix unredirected windows being transparent to input in sloppy focus + Resolves: #1299616 + +* Mon Oct 26 2015 Rui Matos - 3.14.4-17 +- Fix a crash when plugging monitors + Resolves: #1275215 +- Avoid a critical message when unplugging monitors + Resolves: #1275220 +- Fix monitors remaining undetected on resume from suspend + Resolves: #1219476 + +* Fri Oct 16 2015 Florian Müllner - 3.14.4-16 +- Fix crash during session saving when saving sticky windows + Related: #1272106 + +* Tue Oct 6 2015 Rui Matos - 3.14.4-15 +- Fix integer sign oversight in the previous patch + Related: #1265511 + +* Tue Oct 6 2015 Rui Matos - 3.14.4-14 +- Add a couple of fixes for Xvnc resolution changes + Resolves: #1265511 + +* Thu Oct 01 2015 Florian Müllner - 3.14.4-13 +- Fix a couple more errors in headless mode + Related: #1212702 + +* Fri Sep 04 2015 Florian Müllner - 3.14.4-12 +- Fix maximum potential number of monitors + Resolves: #1260082 + +* Thu Sep 03 2015 Florian Müllner - 3.14.4-11 +- Fix screen flicking issue with propriertary NVidia drivers + Resolves: #1258842 + +* Thu Jul 30 2015 Florian Müllner - 3.14.4-10 +- Fix placement of fullscreen windows + Resolves: #1247718 + +* Fri Jul 24 2015 Florian Müllner - 3.14.4-9 +- Fix some more headless-mode warnings + Related: #1212702 + +* Fri Jul 24 2015 Florian Müllner - 3.14.4-8 +- Fix focus_serial overflow + Resolves: #1236113 + +* Tue Jul 21 2015 Matthias Clasen - 3.14.4-7 +- Fix coverity spotted bugs + Related #1174722 + +* Fri Jul 17 2015 Florian Müllner - 3.14.4-6 +- Fix oversight in headless-mode backport + Resolves: #1212702 + +* Thu Jul 16 2015 Florian Müllner - 3.14.4-5 +- Support headless mode + Resolves: #1212702 + +* Fri Jul 10 2015 Florian Müllner - 3.14.4-4 +- Don't try to focus hidden windows + Related: #1174722 + +* Thu May 21 2015 Florian Müllner - 3.14.4-3 +- support suggested output position + Resolves: rhbz#1166319 + +* Wed May 06 2015 Ray Strode 3.14.4-2 +- rebuild against new gnome-desktop3 + Related: #1174722 + +* Tue Mar 24 2015 Florian Müllner - 3.14.4-1 +- Drop obsolete patches, rebase still relevant one + +* Mon Mar 23 2015 Richard Hughes - 3.14.3-1 +- Update to 3.14.3 +- Resolves: #1174722 + +* Wed Jan 14 2015 Florian Müllner - 3.8.4.16 +- Fix window placement regression + Resolves: rhbz#1153641 + +* Thu Nov 13 2014 Florian Müllner - 3.8.4-15 +- Fix delayed mouse mode + Resolves: rhbz#1149585 + +* Thu Oct 09 2014 Florian Müllner - 3.8.4-14 +- Preserve window placement on monitor changes + Resolves: rhbz#1126754 + +* Thu Oct 09 2014 Florian Müllner - 3.8.4-13 +- Improve handling of vertical monitor layouts + Resolves: rhbz#1108322 + +* Thu Jul 17 2014 Owen Taylor 3.8.4-13 +- Add patches for quadbuffer stereo suppport + Fix a bad performance problem drawing window thumbnails + Resolves: rhbz#861507 + +* Tue Mar 11 2014 Florian Müllner - 3.8.4-10 +- Fix crash when encountering over-sized windows + Resolves: #1027832 + +* Tue Mar 11 2014 Florian Müllner - 3.8.4-10 +- Backport another minor memory leak fix + Resolves: #1067456 + +* Tue Mar 11 2014 Debarshi Ray - 3.8.4-9 +- Do not save pixbuf in user data + Resolves: #1067456 + +* Wed Feb 12 2014 Carlos Garnacho - 3.8.4-8 +- Fix window dragging on touchscreens + Resolves: #1051006 + +* Tue Feb 11 2014 Owen Taylor - 3.8.4-7 +- Add an upstream patch that fixes a bug with left-over window + shadows that show up when we add patches to Clutter to stop + redrawing the entire screen on every window move. + Resolves: rhbz#1063984 + +* Fri Jan 24 2014 Daniel Mach - 3.8.4-6 +- Mass rebuild 2014-01-24 + +* Fri Dec 27 2013 Daniel Mach - 3.8.4-5 +- Mass rebuild 2013-12-27 + +* Thu Nov 28 2013 Florian Müllner - 3.8.4-4 +- Include translation updates + Resolves: rhbz#1030369 + +* Mon Nov 11 2013 Florian Müllner - 3.8.4-3 +- Backport allowing sliced textures for large backgrounds + Resolves: rhbz#1028586 + +* Thu Oct 31 2013 Florian Müllner - 3.8.4-2 +- Backport performance improvements for software rendering from 3.10 + +* Tue Jul 30 2013 Ray Strode 3.8.4-1 +- Update to 3.8.4 + +* Tue Jul 02 2013 Florian Müllner - 3.8.3-2 +- Rebuild with (re-)fixed download URL + +* Fri Jun 07 2013 Florian Müllner - 3.8.3-1 +- Update to 3.8.3 + +* Tue May 14 2013 Florian Müllner - 3.8.2-1 +- Update to 3.8.2 + +* Tue Apr 16 2013 Florian Müllner - 3.8.1-1 +- Update to 3.8.1 + +* Tue Mar 26 2013 Florian Müllner - 3.8.0-1 +- Update to 3.8.0 + +* Tue Mar 19 2013 Florian Müllner - 3.7.92-1 +- Update to 3.7.92 + +* Mon Mar 04 2013 Florian Müllner - 3.7.91-1 +- Update to 3.7.91 + +* Wed Feb 20 2013 Florian Müllner - 3.7.90-1 +- Update to 3.7.90 + +* Tue Feb 05 2013 Florian Müllner - 3.7.5-1 +- Update to 3.7.5 + +* Fri Jan 25 2013 Peter Robinson 3.7.4-2 +- Rebuild for new cogl + +* Tue Jan 15 2013 Florian Müllner - 3.7.4-1 +- Update to 3.7.4 + +* Tue Dec 18 2012 Florian Müllner - 3.7.3-1 +- Update to 3.7.3 + +* Mon Nov 19 2012 Florian Müllner - 3.7.2-1 +- Update to 3.7.2 + +* Fri Nov 09 2012 Kalev Lember - 3.7.1-1 +- Update to 3.7.1 + +* Mon Oct 15 2012 Florian Müllner - 3.6.1-1 +- Update to 3.6.1 + +* Tue Sep 25 2012 Florian Müllner - 3.6.0-1 +- Update to 3.6.0 + +* Wed Sep 19 2012 Florian Müllner - 3.5.92-1 +- Update to 3.5.92 + +* Tue Sep 04 2012 Debarshi Ray - 3.5.91-2 +- Rebuild against new cogl + +* Tue Sep 04 2012 Debarshi Ray - 3.5.91-1 +- Update to 3.5.91 + +* Tue Aug 28 2012 Matthias Clasen - 3.5.90-2 +- Rebuild against new cogl/clutter + +* Tue Aug 21 2012 Richard Hughes - 3.5.90-1 +- Update to 3.5.90 + +* Tue Aug 07 2012 Richard Hughes - 3.5.5-1 +- Update to 3.5.5 + +* Fri Jul 27 2012 Fedora Release Engineering - 3.5.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Tue Jul 17 2012 Richard Hughes - 3.5.4-1 +- Update to 3.5.4 + +* Tue Jun 26 2012 Matthias Clasen - 3.5.3-1 +- Update to 3.5.3 + +* Fri Jun 8 2012 Matthias Clasen - 3.5.2-3 +- Make resize grip area larger + +* Thu Jun 07 2012 Matthias Clasen - 3.5.2-2 +- Don't check for Xinerama anymore - it is now mandatory + +* Thu Jun 07 2012 Richard Hughes - 3.5.2-1 +- Update to 3.5.2 +- Remove upstreamed patches + +* Wed May 09 2012 Adam Jackson 3.4.1-3 +- mutter-never-slice-shape-mask.patch, mutter-use-cogl-texrect-api.patch: + Fix window texturing on hardware without ARB_texture_non_power_of_two + (#813648) + +* Wed Apr 18 2012 Kalev Lember - 3.4.1-2 +- Silence glib-compile-schemas scriplets + +* Wed Apr 18 2012 Kalev Lember - 3.4.1-1 +- Update to 3.4.1 +- Conflict with gnome-shell versions older than 3.4.1 + +* Tue Mar 27 2012 Richard Hughes - 3.4.0-1 +- Update to 3.4.0 + +* Wed Mar 21 2012 Kalev Lember - 3.3.92-1 +- Update to 3.3.92 + +* Sat Mar 10 2012 Matthias Clasen - 3.3.90-2 +- Rebuild against new cogl + +* Sat Feb 25 2012 Matthias Clasen - 3.3.90-1 +- Update to 3.3.90 + +* Tue Feb 7 2012 Matthias Clasen - 3.3.5-1 +- Update to 3.3.5 + +* Fri Jan 20 2012 Matthias Clasen - 3.3.4-1 +- Update to 3.3.4 + +* Thu Jan 19 2012 Matthias Clasen - 3.3.3-2 +- Rebuild against new cogl + +* Thu Jan 5 2012 Matthias Clasen - 3.3.3-1 +- Update to 3.3.3 + +* Wed Nov 23 2011 Matthias Clasen - 3.3.2-2 +- Rebuild against new clutter + +* Tue Nov 22 2011 Matthias Clasen - 3.3.2-1 +- Update to 3.3.2 + +* Wed Oct 26 2011 Fedora Release Engineering - 3.2.1-2 +- Rebuilt for glibc bug#747377 + +* Wed Oct 19 2011 Matthias Clasen - 3.2.1-1 +- Update to 3.2.1 + +* Mon Sep 26 2011 Owen Taylor - 3.2.0-1 +- Update to 3.2.0 + +* Tue Sep 20 2011 Matthias Clasen - 3.1.92-1 +- Update to 3.1.92 + +* Wed Sep 14 2011 Owen Taylor - 3.1.91.1-1 +- Update to 3.1.91.1 + +* Wed Aug 31 2011 Matthias Clasen - 3.1.90.1-1 +- Update to 3.1.90.1 + +* Wed Jul 27 2011 Matthias Clasen - 3.1.4-1 +- Update to 3.1.4 + +* Wed Jul 27 2011 Matthias Clasen - 3.1.3.1-3 +- Rebuild + +* Mon Jul 4 2011 Peter Robinson - 3.1.3.1-2 +- rebuild against new clutter/cogl + +* Mon Jul 04 2011 Adam Williamson - 3.1.3.1-1 +- Update to 3.1.3.1 + +* Thu Jun 30 2011 Owen Taylor - 3.1.3-1 +- Update to 3.1.3 + +* Wed May 25 2011 Owen Taylor - 3.0.2.1-1 +- Update to 3.0.2.1 + +* Fri Apr 29 2011 Matthias Clasen - 3.0.1-3 +- Actually apply the patch for #700276 + +* Thu Apr 28 2011 Matthias Clasen - 3.0.1-2 +- Make session saving of gnome-shell work + +* Mon Apr 25 2011 Owen Taylor - 3.0.1-1 +- Update to 3.0.1 + +* Mon Apr 4 2011 Owen Taylor - 3.0.0-1 +- Update to 3.0.0 + +* Mon Mar 28 2011 Matthias Clasen - 2.91.93-1 +- Update to 2.91.93 + +* Wed Mar 23 2011 Matthias Clasen - 2.91.92-1 +- Update to 2.91.92 + +* Mon Mar 7 2011 Owen Taylor - 2.91.91-1 +- Update to 2.91.91 + +* Tue Mar 1 2011 Matthias Clasen - 2.91.90-2 +- Build against libcanberra, to enable AccessX feedback features + +* Tue Feb 22 2011 Matthias Clasen - 2.91.90-1 +- Update to 2.91.90 + +* Thu Feb 10 2011 Matthias Clasen - 2.91.6-4 +- Rebuild against newer gtk + +* Tue Feb 08 2011 Fedora Release Engineering - 2.91.6-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Wed Feb 2 2011 Matthias Clasen - 2.91.6-2 +- Rebuild against newer gtk + +* Tue Feb 1 2011 Owen Taylor - 2.91.6-1 +- Update to 2.91.6 + +* Tue Jan 11 2011 Matthias Clasen - 2.91.5-1 +- Update to 2.91.5 + +* Fri Jan 7 2011 Matthias Clasen - 2.91.4-1 +- Update to 2.91.4 + +* Fri Dec 3 2010 Matthias Clasen - 2.91.3-2 +- Rebuild against new gtk +- Drop no longer needed %%clean etc + +* Mon Nov 29 2010 Owen Taylor - 2.91.3-1 +- Update to 2.91.3 + +* Tue Nov 9 2010 Owen Taylor - 2.91.2-1 +- Update to 2.91.2 + +* Tue Nov 2 2010 Matthias Clasen - 2.91.1-2 +- Rebuild against newer gtk3 + +* Fri Oct 29 2010 Owen Taylor - 2.91.1-1 +- Update to 2.91.1 + +* Mon Oct 4 2010 Owen Taylor - 2.91.0-1 +- Update to 2.91.0 + +* Wed Sep 22 2010 Matthias Clasen - 2.31.5-4 +- Rebuild against newer gobject-introspection + +* Wed Jul 14 2010 Colin Walters - 2.31.5-3 +- Rebuild for new gobject-introspection + +* Tue Jul 13 2010 Adel Gadllah - 2.31.5-2 +- Build against gtk3 + +* Mon Jul 12 2010 Colin Walters - 2.31.5-1 +- New upstream version + +* Mon Jul 12 2010 Colin Walters - 2.31.2-5 +- Rebuild against new gobject-introspection + +* Tue Jul 6 2010 Colin Walters - 2.31.2-4 +- Changes to support snapshot builds + +* Fri Jun 25 2010 Colin Walters - 2.31.2-3 +- drop gir-repository-devel dep + +* Wed May 26 2010 Adam Miller - 2.31.2-2 +- removed "--with-clutter" as configure is claiming it to be an unknown option + +* Wed May 26 2010 Adam Miller - 2.31.2-1 +- New upstream 2.31.2 release + +* Thu Mar 25 2010 Peter Robinson 2.29.1-1 +- New upstream 2.29.1 release + +* Wed Mar 17 2010 Peter Robinson 2.29.0-1 +- New upstream 2.29.0 release + +* Tue Feb 16 2010 Adam Jackson 2.28.1-0.2 +- mutter-2.28.1-add-needed.patch: Fix FTBFS from --no-add-needed + +* Thu Feb 4 2010 Peter Robinson 2.28.1-0.1 +- Move to git snapshot + +* Wed Oct 7 2009 Owen Taylor - 2.28.0-1 +- Update to 2.28.0 + +* Tue Sep 15 2009 Owen Taylor - 2.27.5-1 +- Update to 2.27.5 + +* Fri Sep 4 2009 Owen Taylor - 2.27.4-1 +- Remove workaround for #520209 +- Update to 2.27.4 + +* Sat Aug 29 2009 Owen Taylor - 2.27.3-3 +- Fix %%preun GConf script to properly be for package removal + +* Fri Aug 28 2009 Owen Taylor - 2.27.3-2 +- Add a workaround for Red Hat bug #520209 + +* Fri Aug 28 2009 Owen Taylor - 2.27.3-1 +- Update to 2.27.3, remove mutter-metawindow.patch + +* Fri Aug 21 2009 Peter Robinson 2.27.2-2 +- Add upstream patch needed by latest mutter-moblin + +* Tue Aug 11 2009 Peter Robinson 2.27.2-1 +- New upstream 2.27.2 release. Drop upstreamed patches. + +* Wed Jul 29 2009 Peter Robinson 2.27.1-5 +- Add upstream patches for clutter 1.0 + +* Wed Jul 29 2009 Peter Robinson 2.27.1-4 +- Add patch to fix mutter --replace + +* Sat Jul 25 2009 Fedora Release Engineering - 2.27.1-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Sat Jul 18 2009 Peter Robinson 2.27.1-2 +- Updates from review request + +* Fri Jul 17 2009 Peter Robinson 2.27.1-1 +- Update to official 2.27.1 and review updates + +* Thu Jun 18 2009 Peter Robinson 2.27.0-0.2 +- Updates from initial reviews + +* Thu Jun 18 2009 Peter Robinson 2.27.0-0.1 +- Initial packaging