Blame SOURCES/0001-Add-a-framework-for-restarting-the-compositor-with-n.patch

68333f
From 6710b03d1ebafc15ee4e826a5281204c6441c083 Mon Sep 17 00:00:00 2001
68333f
From: "Owen W. Taylor" <otaylor@fishsoup.net>
68333f
Date: Thu, 8 May 2014 18:35:49 -0400
68333f
Subject: [PATCH 1/4] Add a framework for restarting the compositor with nice
68333f
 visuals
68333f
68333f
The current GNOME Shell Alt-F2 restart looks very messy and also
68333f
provides no indication to the user what is going on. We need to
68333f
restart the compositor to switch in and out of stereo mode, so
68333f
add a framework for doing this more cleanly:
68333f
68333f
Additions:
68333f
68333f
 meta_restart(): restarts the compositor with a message
68333f
 MetaDisplay::show-restart-message: signal the embedding
68333f
    shell to show a message
68333f
 MetaDisplay::restart: signal the embedding shell to restart
68333f
    itself.
68333f
 meta_is_restart(): indicates whether the current instance is a
68333f
                    restart so we can suppress login animations.
68333f
68333f
A helper program meta-restart-helper holds the composite overlay
68333f
window up during the restart to avoid visual artifacts.
68333f
68333f
https://bugzilla.gnome.org/show_bug.cgi?id=733026
68333f
---
68333f
 configure.ac                |   1 +
68333f
 src/Makefile.am             |   5 ++
68333f
 src/compositor/compositor.c |   5 ++
68333f
 src/core/display-private.h  |   7 ++
68333f
 src/core/display.c          |  80 +++++++++++++++++
68333f
 src/core/main.c             |   3 +
68333f
 src/core/restart-helper.c   |  82 +++++++++++++++++
68333f
 src/core/restart.c          | 212 ++++++++++++++++++++++++++++++++++++++++++++
68333f
 src/meta/main.h             |   3 +
68333f
 9 files changed, 398 insertions(+)
68333f
 create mode 100644 src/core/restart-helper.c
68333f
 create mode 100644 src/core/restart.c
68333f
68333f
diff --git a/configure.ac b/configure.ac
68333f
index 6e9ca8c..dcd8a54 100644
68333f
--- a/configure.ac
68333f
+++ b/configure.ac
68333f
@@ -69,6 +69,7 @@ CLUTTER_PACKAGE=clutter-1.0
68333f
 MUTTER_PC_MODULES="
68333f
    gtk+-3.0 >= 3.3.7
68333f
    gio-2.0 >= 2.25.10
68333f
+   gio-unix-2.0 >= 2.25.10
68333f
    pango >= 1.2.0
68333f
    cairo >= 1.10.0
68333f
    gsettings-desktop-schemas >= 3.7.3
68333f
diff --git a/src/Makefile.am b/src/Makefile.am
68333f
index e2cec91..d664b54 100644
68333f
--- a/src/Makefile.am
68333f
+++ b/src/Makefile.am
68333f
@@ -119,6 +119,7 @@ libmutter_la_SOURCES =				\
68333f
 	core/screen-private.h			\
68333f
 	meta/screen.h				\
68333f
 	meta/types.h				\
68333f
+	core/restart.c				\
68333f
 	core/session.c				\
68333f
 	core/session.h				\
68333f
 	core/stack.c				\
68333f
@@ -213,6 +214,10 @@ bin_PROGRAMS=mutter mutter-theme-viewer
68333f
 mutter_SOURCES = core/mutter.c
68333f
 mutter_LDADD = $(MUTTER_LIBS) libmutter.la
68333f
 
68333f
+libexec_PROGRAMS = mutter-restart-helper
68333f
+mutter_restart_helper_SOURCES = core/restart-helper.c
68333f
+mutter_restart_helper_LDADD = $(MUTTER_LIBS)
68333f
+
68333f
 if HAVE_INTROSPECTION
68333f
 include $(INTROSPECTION_MAKEFILE)
68333f
 
68333f
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
68333f
index 91b477f..539a7a6 100644
68333f
--- a/src/compositor/compositor.c
68333f
+++ b/src/compositor/compositor.c
68333f
@@ -86,6 +86,7 @@
68333f
 #include "meta-window-group.h"
68333f
 #include "window-private.h" /* to check window->hidden */
68333f
 #include "display-private.h" /* for meta_display_lookup_x_window() */
68333f
+#include "util-private.h"
68333f
 #include <X11/extensions/shape.h>
68333f
 #include <X11/extensions/Xcomposite.h>
68333f
 
68333f
@@ -216,6 +217,10 @@ get_output_window (MetaScreen *screen)
68333f
   xroot = meta_screen_get_xroot (screen);
68333f
   output = XCompositeGetOverlayWindow (xdisplay, xroot);
68333f
 
68333f
+  /* Now that we've gotten taken a reference count on the COW, we
68333f
+   * can close the helper that is holding on to it */
68333f
+  meta_restart_finish ();
68333f
+
68333f
   meta_core_add_old_event_mask (xdisplay, output, &mask);
68333f
 
68333f
   XISetMask (mask.mask, XI_KeyPress);
68333f
diff --git a/src/core/display-private.h b/src/core/display-private.h
68333f
index 3423fb1..d227492 100644
68333f
--- a/src/core/display-private.h
68333f
+++ b/src/core/display-private.h
68333f
@@ -470,4 +470,11 @@ gboolean meta_display_process_barrier_event (MetaDisplay    *display,
68333f
                                              XIBarrierEvent *event);
68333f
 #endif /* HAVE_XI23 */
68333f
 
68333f
+gboolean meta_display_show_restart_message (MetaDisplay *display,
68333f
+                                            const char  *message);
68333f
+gboolean meta_display_request_restart      (MetaDisplay *display);
68333f
+
68333f
+void meta_restart_init (void);
68333f
+void meta_restart_finish (void);
68333f
+
68333f
 #endif
68333f
diff --git a/src/core/display.c b/src/core/display.c
68333f
index d611314..9ed0f6e 100644
68333f
--- a/src/core/display.c
68333f
+++ b/src/core/display.c
68333f
@@ -146,6 +146,8 @@ enum
68333f
   WINDOW_MARKED_URGENT,
68333f
   GRAB_OP_BEGIN,
68333f
   GRAB_OP_END,
68333f
+  SHOW_RESTART_MESSAGE,
68333f
+  RESTART,
68333f
   LAST_SIGNAL
68333f
 };
68333f
 
68333f
@@ -322,6 +324,59 @@ meta_display_class_init (MetaDisplayClass *klass)
68333f
                   META_TYPE_WINDOW,
68333f
                   META_TYPE_GRAB_OP);
68333f
 
68333f
+  /**
68333f
+   * MetaDisplay::show-restart-message:
68333f
+   * @display: the #MetaDisplay instance
68333f
+   * @message: (allow-none): The message to display, or %NULL
68333f
+   *  to clear a previous restart message.
68333f
+   *
68333f
+   * The ::show-restart-message signal will be emitted to indicate
68333f
+   * that the compositor should show a message during restart. This is
68333f
+   * emitted when meta_restart() is called, either by Mutter
68333f
+   * internally or by the embedding compositor.  The message should be
68333f
+   * immediately added to the Clutter stage in its final form -
68333f
+   * ::restart will be emitted to exit the application and leave the
68333f
+   * stage contents frozen as soon as the the stage is painted again.
68333f
+   *
68333f
+   * On case of failure to restart, this signal will be emitted again
68333f
+   * with %NULL for @message.
68333f
+   *
68333f
+   * Returns: %TRUE means the message was added to the stage; %FALSE
68333f
+   *   indicates that the compositor did not show the message.
68333f
+   */
68333f
+  display_signals[SHOW_RESTART_MESSAGE] =
68333f
+    g_signal_new ("show-restart-message",
68333f
+                  G_TYPE_FROM_CLASS (klass),
68333f
+                  G_SIGNAL_RUN_LAST,
68333f
+                  0,
68333f
+                  g_signal_accumulator_true_handled,
68333f
+                  NULL, NULL,
68333f
+                  G_TYPE_BOOLEAN, 1,
68333f
+                  G_TYPE_STRING);
68333f
+
68333f
+  /**
68333f
+   * MetaDisplay::restart:
68333f
+   * @display: the #MetaDisplay instance
68333f
+   *
68333f
+   * The ::restart signal is emitted to indicate that compositor
68333f
+   * should reexec the process. This is
68333f
+   * emitted when meta_restart() is called, either by Mutter
68333f
+   * internally or by the embedding compositor. See also
68333f
+   * ::show-restart-message.
68333f
+   *
68333f
+   * Returns: %FALSE to indicate that the compositor could not
68333f
+   *  be restarted. When the compositor is restarted, the signal
68333f
+   *  should not return.
68333f
+   */
68333f
+  display_signals[RESTART] =
68333f
+    g_signal_new ("restart",
68333f
+                  G_TYPE_FROM_CLASS (klass),
68333f
+                  G_SIGNAL_RUN_LAST,
68333f
+                  0,
68333f
+                  g_signal_accumulator_true_handled,
68333f
+                  NULL, NULL,
68333f
+                  G_TYPE_BOOLEAN, 0);
68333f
+
68333f
   g_object_class_install_property (object_class,
68333f
                                    PROP_FOCUS_WINDOW,
68333f
                                    g_param_spec_object ("focus-window",
68333f
@@ -5856,3 +5911,28 @@ meta_display_clear_mouse_mode (MetaDisplay *display)
68333f
 {
68333f
   display->mouse_mode = FALSE;
68333f
 }
68333f
+
68333f
+gboolean
68333f
+meta_display_show_restart_message (MetaDisplay *display,
68333f
+                                   const char  *message)
68333f
+{
68333f
+  gboolean result = FALSE;
68333f
+
68333f
+  g_signal_emit (display,
68333f
+                 display_signals[SHOW_RESTART_MESSAGE], 0,
68333f
+                 message, &result);
68333f
+
68333f
+  return result;
68333f
+}
68333f
+
68333f
+gboolean
68333f
+meta_display_request_restart (MetaDisplay *display)
68333f
+{
68333f
+  gboolean result = FALSE;
68333f
+
68333f
+  g_signal_emit (display,
68333f
+                 display_signals[RESTART], 0,
68333f
+                 &result);
68333f
+
68333f
+  return result;
68333f
+}
68333f
diff --git a/src/core/main.c b/src/core/main.c
68333f
index 4bec3d2..d5bde44 100644
68333f
--- a/src/core/main.c
68333f
+++ b/src/core/main.c
68333f
@@ -53,6 +53,7 @@
68333f
 #include <meta/errors.h>
68333f
 #include "ui.h"
68333f
 #include "session.h"
68333f
+#include "stereo.h"
68333f
 #include <meta/prefs.h>
68333f
 #include <meta/compositor.h>
68333f
 
68333f
@@ -441,6 +442,8 @@ meta_init (void)
68333f
   
68333f
   meta_ui_init ();
68333f
 
68333f
+  meta_restart_init ();
68333f
+
68333f
   /*
68333f
    * Clutter can only be initialized after the UI.
68333f
    */
68333f
diff --git a/src/core/restart-helper.c b/src/core/restart-helper.c
68333f
new file mode 100644
68333f
index 0000000..57a19fb
68333f
--- /dev/null
68333f
+++ b/src/core/restart-helper.c
68333f
@@ -0,0 +1,82 @@
68333f
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
68333f
+
68333f
+/*
68333f
+ * SECTION:restart-helper
68333f
+ * @short_description: helper program during a restart
68333f
+ *
68333f
+ * To smoothly restart Mutter, we want to keep the composite
68333f
+ * overlay window enabled during the restart. This is done by
68333f
+ * spawning this program, which keeps a reference to the the composite
68333f
+ * overlay window until Mutter picks it back up.
68333f
+ */
68333f
+
68333f
+/*
68333f
+ * Copyright (C) 2014 Red Hat, Inc.
68333f
+ *
68333f
+ * This program is free software; you can redistribute it and/or
68333f
+ * modify it under the terms of the GNU General Public License as
68333f
+ * published by the Free Software Foundation; either version 2 of the
68333f
+ * License, or (at your option) any later version.
68333f
+ *
68333f
+ * This program is distributed in the hope that it will be useful, but
68333f
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
68333f
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
68333f
+ * General Public License for more details.
68333f
+ *
68333f
+ * You should have received a copy of the GNU General Public License
68333f
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
68333f
+ */
68333f
+
68333f
+#include <stdlib.h>
68333f
+#include <stdio.h>
68333f
+#include <X11/Xlib.h>
68333f
+#include <X11/extensions/Xcomposite.h>
68333f
+
68333f
+int
68333f
+main (int    argc,
68333f
+      char **argv)
68333f
+{
68333f
+  Display *display = XOpenDisplay (NULL);
68333f
+  Window selection_window;
68333f
+  XSetWindowAttributes xwa;
68333f
+  unsigned long mask = 0;
68333f
+
68333f
+  xwa.override_redirect = True;
68333f
+  mask |= CWOverrideRedirect;
68333f
+
68333f
+
68333f
+  XCompositeGetOverlayWindow (display, DefaultRootWindow (display));
68333f
+
68333f
+  selection_window = XCreateWindow (display,
68333f
+				    DefaultRootWindow (display),
68333f
+				    -100, -100, 1, 1, 0,
68333f
+				    0,
68333f
+				    InputOnly,
68333f
+				    DefaultVisual (display, DefaultScreen (display)),
68333f
+				    mask, &xwa;;
68333f
+
68333f
+  XSetSelectionOwner (display,
68333f
+		      XInternAtom (display, "_MUTTER_RESTART_HELPER", False),
68333f
+		      selection_window,
68333f
+		      CurrentTime);
68333f
+
68333f
+  /* Mutter looks for an (arbitrary) line printed to stdout to know that
68333f
+   * we have started and have a reference to the COW. XSync() so that
68333f
+   * everything is set on the X server before Mutter starts restarting.
68333f
+   */
68333f
+  XSync (display, False);
68333f
+
68333f
+  printf ("STARTED\n");
68333f
+  fflush (stdout);
68333f
+
68333f
+  while (True)
68333f
+    {
68333f
+      XEvent xev;
68333f
+
68333f
+      XNextEvent (display, &xev);
68333f
+      /* Mutter restarted and unset the selection to indicate that
68333f
+       * it has a reference on the COW again */
68333f
+      if (xev.xany.type == SelectionClear)
68333f
+	return 0;
68333f
+    }
68333f
+}
68333f
diff --git a/src/core/restart.c b/src/core/restart.c
68333f
new file mode 100644
68333f
index 0000000..04ef7d5
68333f
--- /dev/null
68333f
+++ b/src/core/restart.c
68333f
@@ -0,0 +1,212 @@
68333f
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
68333f
+
68333f
+/*
68333f
+ * Copyright (C) 2014 Red Hat, Inc.
68333f
+ *
68333f
+ * This program is free software; you can redistribute it and/or
68333f
+ * modify it under the terms of the GNU General Public License as
68333f
+ * published by the Free Software Foundation; either version 2 of the
68333f
+ * License, or (at your option) any later version.
68333f
+ *
68333f
+ * This program is distributed in the hope that it will be useful, but
68333f
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
68333f
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
68333f
+ * General Public License for more details.
68333f
+ *
68333f
+ * You should have received a copy of the GNU General Public License
68333f
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
68333f
+ */
68333f
+
68333f
+/*
68333f
+ * SECTION:restart
68333f
+ * @short_description: Smoothly restart the compositor
68333f
+ *
68333f
+ * There are some cases where we need to restart Mutter in order
68333f
+ * to deal with changes in state - the particular case inspiring
68333f
+ * this is enabling or disabling stereo output. To make this
68333f
+ * fairly smooth for the user, we need to do two things:
68333f
+ *
68333f
+ *  - Display a message to the user and make sure that it is
68333f
+ *    actually painted before we exit.
68333f
+ *  - Use a helper program so that the Composite Overlay Window
68333f
+ *    isn't unmapped and mapped.
68333f
+ *
68333f
+ * This handles both of these.
68333f
+ */
68333f
+
68333f
+#include <config.h>
68333f
+
68333f
+#include <clutter/clutter.h>
68333f
+#include <gio/gunixinputstream.h>
68333f
+
68333f
+#include <meta/main.h>
68333f
+#include <meta/util.h>
68333f
+#include "ui.h"
68333f
+#include "display-private.h"
68333f
+
68333f
+static gboolean restart_helper_started = FALSE;
68333f
+static gboolean restart_message_shown = FALSE;
68333f
+static gboolean is_restart = FALSE;
68333f
+
68333f
+void
68333f
+meta_restart_init (void)
68333f
+{
68333f
+  Display *xdisplay = meta_ui_get_display ();
68333f
+  Atom atom_restart_helper = XInternAtom (xdisplay, "_MUTTER_RESTART_HELPER", False);
68333f
+  Window restart_helper_window = NULL;
68333f
+
68333f
+  restart_helper_window = XGetSelectionOwner (xdisplay, atom_restart_helper);
68333f
+  if (restart_helper_window)
68333f
+    is_restart = TRUE;
68333f
+}
68333f
+
68333f
+static void
68333f
+restart_check_ready (void)
68333f
+{
68333f
+  if (restart_helper_started && restart_message_shown)
68333f
+    meta_display_request_restart (meta_get_display ());
68333f
+}
68333f
+
68333f
+static void
68333f
+restart_helper_read_line_callback (GObject      *source_object,
68333f
+                                   GAsyncResult *res,
68333f
+                                   gpointer      user_data)
68333f
+{
68333f
+  GError *error = NULL;
68333f
+  gsize length;
68333f
+  char *line = g_data_input_stream_read_line_finish_utf8 (G_DATA_INPUT_STREAM (source_object),
68333f
+                                                          res,
68333f
+                                                          &length, &error);
68333f
+  if (line == NULL)
68333f
+    {
68333f
+      meta_warning ("Failed to read output from restart helper%s%s\n",
68333f
+                    error ? ": " : NULL,
68333f
+                    error ? error->message : NULL);
68333f
+    }
68333f
+  else
68333f
+    g_free (line); /* We don't actually care what the restart helper outputs */
68333f
+
68333f
+  g_object_unref (source_object);
68333f
+
68333f
+  restart_helper_started = TRUE;
68333f
+  restart_check_ready ();
68333f
+}
68333f
+
68333f
+static gboolean
68333f
+restart_message_painted (gpointer data)
68333f
+{
68333f
+  restart_message_shown = TRUE;
68333f
+  restart_check_ready ();
68333f
+
68333f
+  return FALSE;
68333f
+}
68333f
+
68333f
+/**
68333f
+ * meta_restart:
68333f
+ * @message: message to display to the user.
68333f
+ *
68333f
+ * Starts the process of restarting the compositor. Note that Mutter's
68333f
+ * involvement here is to make the restart visually smooth for the
68333f
+ * user - it cannot itself safely reexec a program that embeds libmuttter.
68333f
+ * So in order for this to work, the compositor must handle two
68333f
+ * signals -  MetaDisplay::show-restart-message, to display the
68333f
+ * message passed here on the Clutter stage, and ::restart to actually
68333f
+ * reexec the compositor.
68333f
+ */
68333f
+void
68333f
+meta_restart (const char *message)
68333f
+{
68333f
+  MetaDisplay *display = meta_get_display();
68333f
+  GInputStream *unix_stream;
68333f
+  GDataInputStream *data_stream;
68333f
+  GError *error = NULL;
68333f
+  int helper_out_fd;
68333f
+
68333f
+  static const char * const helper_argv[] = {
68333f
+    MUTTER_LIBEXECDIR "/mutter-restart-helper", NULL
68333f
+  };
68333f
+
68333f
+  if (meta_display_show_restart_message (display, message))
68333f
+    {
68333f
+      /* Wait until the stage was painted */
68333f
+      clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
68333f
+                                             restart_message_painted,
68333f
+                                             NULL, NULL);
68333f
+    }
68333f
+  else
68333f
+    {
68333f
+      /* Can't show the message, show the message as soon as the
68333f
+       * restart helper starts
68333f
+       */
68333f
+      restart_message_painted (NULL);
68333f
+    }
68333f
+
68333f
+  /* We also need to wait for the restart helper to get its
68333f
+   * reference to the Composite Overlay Window.
68333f
+   */
68333f
+  if (!g_spawn_async_with_pipes (NULL, /* working directory */
68333f
+                                 (char **)helper_argv,
68333f
+                                 NULL, /* envp */
68333f
+                                 0, /* G_SPAWN_DEFAULT */
68333f
+                                 NULL, NULL, /* child_setup */
68333f
+                                 NULL, /* child_pid */
68333f
+                                 NULL, /* standard_input */
68333f
+                                 &helper_out_fd,
68333f
+                                 NULL, /* standard_error */
68333f
+                                 &error))
68333f
+    {
68333f
+      meta_warning ("Failed to start restart helper: %s\n", error->message);
68333f
+      goto error;
68333f
+    }
68333f
+
68333f
+  unix_stream = g_unix_input_stream_new (helper_out_fd, TRUE);
68333f
+  data_stream = g_data_input_stream_new (unix_stream);
68333f
+  g_object_unref (unix_stream);
68333f
+
68333f
+  g_data_input_stream_read_line_async (data_stream, G_PRIORITY_DEFAULT,
68333f
+                                       NULL, restart_helper_read_line_callback,
68333f
+                                       &error);
68333f
+  if (error != NULL)
68333f
+    {
68333f
+      meta_warning ("Failed to read from restart helper: %s\n", error->message);
68333f
+      g_object_unref (data_stream);
68333f
+      goto error;
68333f
+    }
68333f
+
68333f
+  return;
68333f
+
68333f
+ error:
68333f
+  /* If starting the restart helper fails, then we just go ahead and restart
68333f
+   * immediately. We won't get a smooth transition, since the overlay window
68333f
+   * will be destroyed and recreated, but otherwise it will work fine.
68333f
+   */
68333f
+  restart_helper_started = TRUE;
68333f
+  restart_check_ready ();
68333f
+
68333f
+  return;
68333f
+}
68333f
+
68333f
+void
68333f
+meta_restart_finish (void)
68333f
+{
68333f
+  if (is_restart)
68333f
+    {
68333f
+      Display *xdisplay = meta_display_get_xdisplay (meta_get_display ());
68333f
+      Atom atom_restart_helper = XInternAtom (xdisplay, "_MUTTER_RESTART_HELPER", False);
68333f
+      XSetSelectionOwner (xdisplay, atom_restart_helper, None, CurrentTime);
68333f
+    }
68333f
+}
68333f
+
68333f
+/**
68333f
+ * meta_is_restart:
68333f
+ *
68333f
+ * Returns %TRUE if this instance of Mutter comes from Mutter
68333f
+ * restarting itself (for example to enable/disable stereo.)
68333f
+ * See meta_restart(). If this is the case, any startup visuals
68333f
+ * or animations should be suppressed.
68333f
+ */
68333f
+gboolean
68333f
+meta_is_restart (void)
68333f
+{
68333f
+  return is_restart;
68333f
+}
68333f
diff --git a/src/meta/main.h b/src/meta/main.h
68333f
index dd4e7f1..af7a2c9 100644
68333f
--- a/src/meta/main.h
68333f
+++ b/src/meta/main.h
68333f
@@ -35,6 +35,9 @@ gboolean        meta_get_replace_current_wm (void);  /* Actually defined in util
68333f
 void            meta_set_wm_name              (const char *wm_name);
68333f
 void            meta_set_gnome_wm_keybindings (const char *wm_keybindings);
68333f
 
68333f
+void            meta_restart                (const char *message);
68333f
+gboolean        meta_is_restart             (void);
68333f
+
68333f
 /**
68333f
  * MetaExitCode:
68333f
  * @META_EXIT_SUCCESS: Success
68333f
-- 
68333f
1.9.3
68333f