Blob Blame History Raw
From d20f20c9d4c52b7a96d5c879df5fe322a0ca356c Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Sat, 12 Jan 2019 12:38:01 -0500
Subject: [PATCH 4/9] wayland: force X clients to redraw on resume

On nvidia, the textures backing Xwayland client window contents get
corrupted on suspend.  Xwayland currently doesn't handle this situation
itself.

For now, in order to work around this issue, send an empty output
change event to Xwayland.  This will cause it to force Expose events
to get sent to all clients and get them to redraw.
---
 .../native/meta-monitor-manager-kms.c         |  7 +++
 src/wayland/meta-wayland-outputs.c            | 47 +++++++++++++++++++
 src/wayland/meta-wayland-outputs.h            |  1 +
 3 files changed, 55 insertions(+)

diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c
index 438069110..f9a9e1c6d 100644
--- a/src/backends/native/meta-monitor-manager-kms.c
+++ b/src/backends/native/meta-monitor-manager-kms.c
@@ -7,60 +7,61 @@
  * 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, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  * 02111-1307, USA.
  *
  * Author: Giovanni Campagna <gcampagn@redhat.com>
  */
 
 #include "config.h"
 
 #include "meta-monitor-manager-kms.h"
 #include "meta-monitor-config-manager.h"
 #include "meta-backend-native.h"
 #include "meta-crtc.h"
 #include "meta-launcher.h"
 #include "meta-output.h"
 #include "meta-backend-private.h"
 #include "meta-renderer-native.h"
 #include "meta-crtc-kms.h"
 #include "meta-gpu-kms.h"
 #include "meta-output-kms.h"
+#include "wayland/meta-wayland-outputs.h"
 
 #include <string.h>
 #include <stdlib.h>
 #include <clutter/clutter.h>
 
 #include <drm.h>
 #include <errno.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <unistd.h>
 
 #include <meta/main.h>
 #include <meta/errors.h>
 
 #include <gudev/gudev.h>
 
 #define DRM_CARD_UDEV_DEVICE_TYPE "drm_minor"
 
 typedef struct
 {
   GSource source;
 
   gpointer fd_tag;
   MetaMonitorManagerKms *manager_kms;
 } MetaKmsSource;
 
 struct _MetaMonitorManagerKms
 {
   MetaMonitorManager parent_instance;
 
@@ -388,63 +389,69 @@ on_uevent (GUdevClient *client,
   handle_hotplug_event (manager);
 }
 
 static void
 meta_monitor_manager_kms_connect_uevent_handler (MetaMonitorManagerKms *manager_kms)
 {
   manager_kms->uevent_handler_id = g_signal_connect (manager_kms->udev,
                                                      "uevent",
                                                      G_CALLBACK (on_uevent),
                                                      manager_kms);
 }
 
 static void
 meta_monitor_manager_kms_disconnect_uevent_handler (MetaMonitorManagerKms *manager_kms)
 {
   g_signal_handler_disconnect (manager_kms->udev,
                                manager_kms->uevent_handler_id);
   manager_kms->uevent_handler_id = 0;
 }
 
 void
 meta_monitor_manager_kms_pause (MetaMonitorManagerKms *manager_kms)
 {
   meta_monitor_manager_kms_disconnect_uevent_handler (manager_kms);
 }
 
 void
 meta_monitor_manager_kms_resume (MetaMonitorManagerKms *manager_kms)
 {
   MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
+  ClutterBackend *clutter_backend = clutter_get_default_backend ();
+  CoglContext *cogl_context =
+    clutter_backend_get_cogl_context (clutter_backend);
 
   meta_monitor_manager_kms_connect_uevent_handler (manager_kms);
   handle_hotplug_event (manager);
+
+  if (cogl_has_feature (cogl_context, COGL_FEATURE_ID_UNSTABLE_TEXTURES))
+    meta_wayland_outputs_redraw (meta_wayland_compositor_get_default ());
 }
 
 static gboolean
 meta_monitor_manager_kms_is_transform_handled (MetaMonitorManager  *manager,
                                                MetaCrtc            *crtc,
                                                MetaMonitorTransform transform)
 {
   return meta_crtc_kms_is_transform_handled (crtc, transform);
 }
 
 static float
 meta_monitor_manager_kms_calculate_monitor_mode_scale (MetaMonitorManager *manager,
                                                        MetaMonitor        *monitor,
                                                        MetaMonitorMode    *monitor_mode)
 {
   return meta_monitor_calculate_mode_scale (monitor, monitor_mode);
 }
 
 static float *
 meta_monitor_manager_kms_calculate_supported_scales (MetaMonitorManager          *manager,
                                                      MetaLogicalMonitorLayoutMode layout_mode,
                                                      MetaMonitor                 *monitor,
                                                      MetaMonitorMode             *monitor_mode,
                                                      int                         *n_supported_scales)
 {
   MetaMonitorScalesConstraint constraints =
     META_MONITOR_SCALES_CONSTRAINT_NONE;
 
   switch (layout_mode)
     {
diff --git a/src/wayland/meta-wayland-outputs.c b/src/wayland/meta-wayland-outputs.c
index 1f99a163d..450f5e484 100644
--- a/src/wayland/meta-wayland-outputs.c
+++ b/src/wayland/meta-wayland-outputs.c
@@ -425,60 +425,107 @@ meta_wayland_compositor_update_outputs (MetaWaylandCompositor *compositor,
 
       if (logical_monitor->winsys_id == 0)
         continue;
 
       wayland_output =
         g_hash_table_lookup (compositor->outputs,
                              GSIZE_TO_POINTER (logical_monitor->winsys_id));
 
       if (wayland_output)
         {
           g_hash_table_steal (compositor->outputs,
                               GSIZE_TO_POINTER (logical_monitor->winsys_id));
         }
       else
         {
           wayland_output = meta_wayland_output_new (compositor, logical_monitor);
         }
 
       wayland_output_update_for_output (wayland_output, logical_monitor);
       g_hash_table_insert (new_table,
                            GSIZE_TO_POINTER (logical_monitor->winsys_id),
                            wayland_output);
     }
 
   g_hash_table_foreach (compositor->outputs, make_output_inert, NULL);
   g_timeout_add_seconds (10, delayed_destroy_outputs, compositor->outputs);
 
   return new_table;
 }
 
+void
+meta_wayland_outputs_redraw (MetaWaylandCompositor *compositor)
+{
+  MetaMonitorManager *monitor_manager;
+  GList *logical_monitors, *l;
+
+  monitor_manager = meta_monitor_manager_get ();
+
+  logical_monitors =
+    meta_monitor_manager_get_logical_monitors (monitor_manager);
+
+  for (l = logical_monitors; l; l = l->next)
+    {
+      MetaLogicalMonitor *logical_monitor = l->data;
+      MetaWaylandOutput *wayland_output;
+      GList *iter;
+
+      if (logical_monitor->winsys_id == 0)
+        continue;
+
+      wayland_output =
+        g_hash_table_lookup (compositor->outputs,
+                             GSIZE_TO_POINTER (logical_monitor->winsys_id));
+
+      if (wayland_output == NULL)
+        continue;
+
+      /* Just output a "changes done" event for one of the outputs, with no actual changes.
+       * xwayland takes this as a cue to send expose events to all X clients.
+       */
+      for (iter = wayland_output->resources; iter; iter = iter->next)
+        {
+          struct wl_resource *resource = iter->data;
+          if (wl_resource_get_version (resource) >= WL_OUTPUT_DONE_SINCE_VERSION)
+            wl_output_send_done (resource);
+        }
+
+      for (iter = wayland_output->xdg_output_resources; iter; iter = iter->next)
+        {
+          struct wl_resource *xdg_output = iter->data;
+          zxdg_output_v1_send_done (xdg_output);
+        }
+
+      break;
+    }
+}
+
 static void
 on_monitors_changed (MetaMonitorManager    *monitors,
                      MetaWaylandCompositor *compositor)
 {
   compositor->outputs = meta_wayland_compositor_update_outputs (compositor, monitors);
 }
 
 static void
 meta_wayland_output_init (MetaWaylandOutput *wayland_output)
 {
 }
 
 static void
 meta_wayland_output_finalize (GObject *object)
 {
   MetaWaylandOutput *wayland_output = META_WAYLAND_OUTPUT (object);
   GList *l;
 
   wl_global_destroy (wayland_output->global);
 
   /* Make sure the wl_output destructor doesn't try to access MetaWaylandOutput
    * after we have freed it.
    */
   make_output_resources_inert (wayland_output);
 
   G_OBJECT_CLASS (meta_wayland_output_parent_class)->finalize (object);
 }
 
 static void
 meta_wayland_output_class_init (MetaWaylandOutputClass *klass)
diff --git a/src/wayland/meta-wayland-outputs.h b/src/wayland/meta-wayland-outputs.h
index e6b60d5fa..d8c648174 100644
--- a/src/wayland/meta-wayland-outputs.h
+++ b/src/wayland/meta-wayland-outputs.h
@@ -20,32 +20,33 @@
  *
  * Written by:
  *     Jasper St. Pierre <jstpierre@mecheye.net>
  */
 
 #ifndef META_WAYLAND_OUTPUTS_H
 #define META_WAYLAND_OUTPUTS_H
 
 #include "backends/meta-monitor-manager-private.h"
 #include "meta-wayland-private.h"
 
 #define META_TYPE_WAYLAND_OUTPUT (meta_wayland_output_get_type ())
 G_DECLARE_FINAL_TYPE (MetaWaylandOutput, meta_wayland_output,
                       META, WAYLAND_OUTPUT, GObject)
 
 struct _MetaWaylandOutput
 {
   GObject                   parent;
 
   struct wl_global         *global;
   MetaLogicalMonitor       *logical_monitor;
   guint                     mode_flags;
   float                     refresh_rate;
   gint                      scale;
 
   GList                    *resources;
   GList                    *xdg_output_resources;
 };
 
 void meta_wayland_outputs_init (MetaWaylandCompositor *compositor);
+void meta_wayland_outputs_redraw (MetaWaylandCompositor *compositor);
 
 #endif /* META_WAYLAND_OUTPUTS_H */
-- 
2.18.1