diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h
index 90dc63b82..23f639fd2 100644
--- a/src/compositor/compositor-private.h
+++ b/src/compositor/compositor-private.h
@@ -8,6 +8,7 @@
#include
#include
#include "meta-plugin-manager.h"
+#include "meta-window-actor-private.h"
#include
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 68425d8f1..9c85c7d97 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 79aafb63e..97e314049 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 c41dae9d7..11bd6aba1 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 cd42e69ad..16232199a 100644
--- a/src/compositor/meta-window-group.c
+++ b/src/compositor/meta-window-group.c
@@ -7,6 +7,7 @@
#include /* 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 4b7b78479..5be1f0e17 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