[mutter] Unredirect fullscreen windows



commit d3831729a0fb35f4272bd93d4c0dfe21f9358acb
Author: Adel Gadllah <adel gadllah gmail com>
Date:   Sat Aug 27 11:43:09 2011 +0200

    Unredirect fullscreen windows
    
    Some apps that do a lot of rendering on the screen like games, mostly run in
    fullscreen where there is no need for them to be redirected doing so does add
    an overhead; while performance is critical for those apps.
    
    This can be disabled / enabled at runtime using
    meta_enable_unredirect_for_screen / meta_disable_unredirect_for_screen
    
    https://bugzilla.gnome.org/show_bug.cgi?id=597014

 src/compositor/compositor-private.h        |    5 ++
 src/compositor/compositor.c                |  103 ++++++++++++++++++++++++++++
 src/compositor/meta-window-actor-private.h |    8 ++
 src/compositor/meta-window-actor.c         |   66 +++++++++++++++++-
 src/compositor/meta-window-group.c         |   18 +++++-
 src/meta/compositor-mutter.h               |    3 +
 6 files changed, 200 insertions(+), 3 deletions(-)
---
diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h
index 90dc63b..23f639f 100644
--- a/src/compositor/compositor-private.h
+++ b/src/compositor/compositor-private.h
@@ -8,6 +8,7 @@
 #include <meta/compositor.h>
 #include <meta/display.h>
 #include "meta-plugin-manager.h"
+#include "meta-window-actor-private.h"
 #include <clutter/clutter.h>
 
 typedef struct _MetaCompScreen MetaCompScreen;
@@ -41,6 +42,10 @@ struct _MetaCompScreen
   GHashTable            *windows_by_xid;
   Window                 output;
 
+  /* Used for unredirecting fullscreen windows */
+  guint                   disable_unredirect_count;
+  MetaWindowActor             *unredirected_window;
+
   /* Before we create the output window */
   XserverRegion     pending_input_region;
 
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
index 68425d8..9c85c7d 100644
--- a/src/compositor/compositor.c
+++ b/src/compositor/compositor.c
@@ -598,6 +598,38 @@ meta_compositor_unmanage_screen (MetaCompositor *compositor,
   XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
 }
 
+/*
+ * Shapes the cow so that the given window is exposed,
+ * when xwin is None it clears the shape again
+ */
+static void
+meta_shape_cow_for_window (MetaScreen *screen,
+                           Window xwin)
+{
+  MetaCompScreen *info = meta_screen_get_compositor_data (screen);
+  Display *xdisplay = meta_display_get_xdisplay (meta_screen_get_display (screen));
+
+  if (xwin == None)
+    XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None);
+  else
+    {
+      XserverRegion output_region;
+      XRectangle screen_rect;
+      int width, height;
+
+      meta_screen_get_size (screen, &width, &height);
+      screen_rect.x = 0;
+      screen_rect.y = 0;
+      screen_rect.width = width;
+      screen_rect.height = height;
+
+      output_region = XFixesCreateRegionFromWindow (xdisplay, xwin, WindowRegionBounding);
+      XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region);
+      XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, output_region);
+      XFixesDestroyRegion (xdisplay, output_region);
+    }
+}
+
 void
 meta_compositor_add_window (MetaCompositor    *compositor,
                             MetaWindow        *window)
@@ -618,12 +650,25 @@ meta_compositor_remove_window (MetaCompositor *compositor,
                                MetaWindow     *window)
 {
   MetaWindowActor         *window_actor     = NULL;
+  MetaScreen *screen;
+  MetaCompScreen *info;
 
   DEBUG_TRACE ("meta_compositor_remove_window\n");
   window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
   if (!window_actor)
     return;
 
+  screen = meta_window_get_screen (window);
+  info = meta_screen_get_compositor_data (screen);
+
+  if (window_actor == info->unredirected_window)
+    {
+      meta_window_actor_set_redirected (window_actor, TRUE);
+      meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (info->unredirected_window)),
+                                 None);
+      info->unredirected_window = NULL;
+    }
+
   meta_window_actor_destroy (window_actor);
 }
 
@@ -1097,6 +1142,33 @@ static void
 pre_paint_windows (MetaCompScreen *info)
 {
   GList *l;
+  MetaWindowActor *top_window;
+  MetaWindowActor *expected_unredirected_window = NULL;
+
+  top_window = g_list_last (info->windows)->data;
+
+  if (meta_window_actor_should_unredirect (top_window) &&
+      info->disable_unredirect_count == 0)
+    expected_unredirected_window = top_window;
+
+  if (info->unredirected_window != expected_unredirected_window)
+    {
+      if (info->unredirected_window != NULL)
+        {
+          meta_window_actor_set_redirected (info->unredirected_window, TRUE);
+          meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (info->unredirected_window)),
+                                     None);
+        }
+
+      if (expected_unredirected_window != NULL)
+        {
+          meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (top_window)),
+                                     meta_window_actor_get_x_window (top_window));
+          meta_window_actor_set_redirected (top_window, FALSE);
+        }
+
+      info->unredirected_window = expected_unredirected_window;
+    }
 
   for (l = info->windows; l; l = l->next)
     meta_window_actor_pre_paint (l->data);
@@ -1200,6 +1272,37 @@ meta_get_overlay_window (MetaScreen *screen)
   return info->output;
 }
 
+/**
+ * meta_disable_unredirect_for_screen:
+ * @screen: a #MetaScreen
+ *
+ * Disables unredirection, can be usefull in situations where having
+ * unredirected windows is undesireable like when recording a video.
+ *
+ */
+void
+meta_disable_unredirect_for_screen (MetaScreen *screen)
+{
+  MetaCompScreen *info = meta_screen_get_compositor_data (screen);
+  if (info != NULL)
+    info->disable_unredirect_count = info->disable_unredirect_count + 1;
+}
+
+/**
+ * meta_enable_unredirect_for_screen:
+ * @screen: a #MetaScreen
+ *
+ * Enables unredirection which reduces the overhead for apps like games.
+ *
+ */
+void
+meta_enable_unredirect_for_screen (MetaScreen *screen)
+{
+  MetaCompScreen *info = meta_screen_get_compositor_data (screen);
+  if (info != NULL)
+   info->disable_unredirect_count = MAX(0, info->disable_unredirect_count - 1);
+}
+
 #define FLASH_TIME_MS 50
 
 static void
diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h
index 79aafb6..97e3140 100644
--- a/src/compositor/meta-window-actor-private.h
+++ b/src/compositor/meta-window-actor-private.h
@@ -26,10 +26,18 @@ void meta_window_actor_unmaximize (MetaWindowActor *self,
 
 void meta_window_actor_process_damage (MetaWindowActor    *self,
                                        XDamageNotifyEvent *event);
+
 void meta_window_actor_pre_paint      (MetaWindowActor    *self);
 
 void meta_window_actor_invalidate_shadow (MetaWindowActor *self);
 
+void meta_window_actor_set_redirected (MetaWindowActor *self, gboolean state);
+
+gboolean meta_window_actor_should_unredirect (MetaWindowActor *self);
+
+void meta_window_actor_get_shape_bounds (MetaWindowActor       *self,
+                                          cairo_rectangle_int_t *bounds);
+
 gboolean meta_window_actor_effect_in_progress  (MetaWindowActor *self);
 void     meta_window_actor_sync_actor_position (MetaWindowActor *self);
 void     meta_window_actor_sync_visibility     (MetaWindowActor *self);
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index c41dae9..11bd6ab 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -114,6 +114,8 @@ struct _MetaWindowActorPrivate
   guint             no_shadow              : 1;
 
   guint             no_more_x_calls        : 1;
+
+  guint             unredirected           : 1;
 };
 
 enum
@@ -575,7 +577,7 @@ meta_window_actor_get_shadow_params (MetaWindowActor  *self,
                                   params);
 }
 
-static void
+void
 meta_window_actor_get_shape_bounds (MetaWindowActor       *self,
                                     cairo_rectangle_int_t *bounds)
 {
@@ -1210,6 +1212,62 @@ meta_window_actor_detach (MetaWindowActor *self)
   meta_window_actor_queue_create_pixmap (self);
 }
 
+gboolean
+meta_window_actor_should_unredirect (MetaWindowActor *self)
+{
+  MetaWindow *metaWindow = meta_window_actor_get_meta_window (self);
+  MetaScreen *screen = meta_window_get_screen (metaWindow);
+
+  if (meta_window_is_override_redirect (metaWindow))
+    {
+      int screen_width, screen_height;
+      MetaRectangle window_rect;
+      meta_screen_get_size (screen, &screen_width, &screen_height);
+      meta_window_get_outer_rect (metaWindow, &window_rect);
+
+      if (window_rect.x == 0 && window_rect.y == 0 &&
+          window_rect.width == screen_width && window_rect.height == screen_height)
+           return TRUE;
+      else
+        {
+          int num_monitors = meta_screen_get_n_monitors (screen);
+          int i;
+          MetaRectangle monitor_rect;
+
+          for (i = 0; i < num_monitors; i++)
+            {
+              meta_screen_get_monitor_geometry (screen , i, &monitor_rect);
+              if (monitor_rect.x == window_rect.x && monitor_rect.y == window_rect.y &&
+                  monitor_rect.width == window_rect.width && monitor_rect.height == window_rect.height)
+                    return TRUE;
+            }
+        }
+    }
+
+  return FALSE;
+}
+
+void
+meta_window_actor_set_redirected (MetaWindowActor *self, gboolean state)
+{
+  MetaWindow *metaWindow = meta_window_actor_get_meta_window (self);
+
+  Display *xdisplay = meta_display_get_xdisplay (meta_window_get_display (metaWindow));
+  Window  xwin = meta_window_actor_get_x_window (self);
+
+  if (state)
+    {
+      XCompositeRedirectWindow (xdisplay, xwin, CompositeRedirectManual);
+      meta_window_actor_queue_create_pixmap (self);
+      self->priv->unredirected = FALSE;
+    }
+  else
+    {
+      XCompositeUnredirectWindow (xdisplay, xwin, CompositeRedirectManual);
+      self->priv->unredirected = TRUE;
+    }
+}
+
 void
 meta_window_actor_destroy (MetaWindowActor *self)
 {
@@ -1945,6 +2003,10 @@ meta_window_actor_process_damage (MetaWindowActor    *self,
 
   priv->received_damage = TRUE;
 
+  /* Drop damage event for unredirected windows */
+  if (self->priv->unredirected)
+    return;
+
   if (is_frozen (self))
     {
       /* The window is frozen due to an effect in progress: we ignore damage
@@ -2226,7 +2288,7 @@ meta_window_actor_pre_paint (MetaWindowActor *self)
       return;
     }
 
-  if (priv->received_damage)
+  if (priv->received_damage && !self->unredirected)
     {
       meta_error_trap_push (display);
       XDamageSubtract (xdisplay, priv->damage, None, None);
diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c
index cd42e69..1623219 100644
--- a/src/compositor/meta-window-group.c
+++ b/src/compositor/meta-window-group.c
@@ -7,6 +7,7 @@
 
 #include <gdk/gdk.h> /* for gdk_rectangle_intersect() */
 
+#include "compositor-private.h"
 #include "meta-window-actor-private.h"
 #include "meta-window-group.h"
 #include "meta-background-actor-private.h"
@@ -104,10 +105,19 @@ static void
 meta_window_group_paint (ClutterActor *actor)
 {
   cairo_region_t *visible_region;
+  cairo_region_t *unredirected_window_region = NULL;
   ClutterActor *stage;
-  cairo_rectangle_int_t visible_rect;
+  cairo_rectangle_int_t visible_rect, unredirected_rect;
   GList *children, *l;
 
+  MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
+  MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen);
+  if (info->unredirected_window != NULL)
+    {
+      meta_window_actor_get_shape_bounds (META_WINDOW_ACTOR (info->unredirected_window), &unredirected_rect);
+      unredirected_window_region = cairo_region_create_rectangle (&unredirected_rect);
+    }
+
   /* We walk the list from top to bottom (opposite of painting order),
    * and subtract the opaque area of each window out of the visible
    * region that we pass to the windows below.
@@ -127,6 +137,9 @@ meta_window_group_paint (ClutterActor *actor)
 
   visible_region = cairo_region_create_rectangle (&visible_rect);
 
+  if (unredirected_window_region)
+    cairo_region_subtract (visible_region, unredirected_window_region);
+
   for (l = children; l; l = l->next)
     {
       if (!CLUTTER_ACTOR_IS_VISIBLE (l->data))
@@ -164,6 +177,9 @@ meta_window_group_paint (ClutterActor *actor)
 
   cairo_region_destroy (visible_region);
 
+  if (unredirected_window_region)
+    cairo_region_destroy (unredirected_window_region);
+
   CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);
 
   /* Now that we are done painting, unset the visible regions (they will
diff --git a/src/meta/compositor-mutter.h b/src/meta/compositor-mutter.h
index 4b7b784..5be1f0e 100644
--- a/src/meta/compositor-mutter.h
+++ b/src/meta/compositor-mutter.h
@@ -39,6 +39,9 @@ Window        meta_get_overlay_window           (MetaScreen *screen);
 GList        *meta_get_window_actors            (MetaScreen *screen);
 ClutterActor *meta_get_window_group_for_screen  (MetaScreen *screen);
 
+void        meta_disable_unredirect_for_screen  (MetaScreen *screen);
+void        meta_enable_unredirect_for_screen   (MetaScreen *screen);
+
 ClutterActor *meta_get_background_actor_for_screen (MetaScreen *screen);
 
 #endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]