From 2210c30cbae29a8c43e6992a61de259ee52e666a Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Sat, 1 Feb 2014 17:21:11 -0500 Subject: [PATCH] window-actor: Split into two subclasses of MetaSurfaceActor The rendering logic before was somewhat complex. We had three independent cases to take into account when doing rendering: * X11 compositor. In this case, we're a traditional X11 compositor, not a Wayland compositor. We use XCompositeNameWindowPixmap to get the backing pixmap for the window, and deal with the COMPOSITE extension messiness. In this case, meta_is_wayland_compositor() is FALSE. * Wayland clients. In this case, we're a Wayland compositor managing Wayland surfaces. The rendering for this is fairly straightforward, as Cogl handles most of the complexity with EGL and SHM buffers... Wayland clients give us the input and opaque regions through wl_surface. In this case, meta_is_wayland_compositor() is TRUE and priv->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND. * XWayland clients. In this case, we're a Wayland compositor, like above, and XWayland hands us Wayland surfaces. XWayland handles the COMPOSITE extension messiness for us, and hands us a buffer like any other Wayland client. We have to fetch the input and opaque regions from the X11 window ourselves. In this case, meta_is_wayland_compositor() is TRUE and priv->window->client_type == META_WINDOW_CLIENT_TYPE_X11. We now split the rendering logic into two subclasses, which are: * MetaSurfaceActorX11, which handles the X11 compositor case, in that it uses XCompositeNameWindowPixmap to get the backing pixmap, and deal with all the COMPOSITE extension messiness. * MetaSurfaceActorWayland, which handles the Wayland compositor case for both native Wayland clients and XWayland clients. XWayland handles COMPOSITE for us, and handles pushing a surface over through the xf86-video-wayland DDX. Frame sync is still in MetaWindowActor, as it needs to work for both the X11 compositor and XWayland client cases. When Wayland's video display protocol lands, this will need to be significantly overhauled, as it would have to work for any wl_surface, including subsurfaces, so we would need surface-level discretion. https://bugzilla.gnome.org/show_bug.cgi?id=720631 --- src/Makefile.am | 4 + src/compositor/meta-surface-actor-wayland.c | 153 ++++++ src/compositor/meta-surface-actor-wayland.h | 66 +++ src/compositor/meta-surface-actor-x11.c | 453 +++++++++++++++++ src/compositor/meta-surface-actor-x11.h | 69 +++ src/compositor/meta-surface-actor.c | 194 ++++--- src/compositor/meta-surface-actor.h | 43 +- src/compositor/meta-window-actor.c | 537 ++++---------------- src/core/display.c | 5 +- src/wayland/meta-wayland-seat.c | 5 +- src/wayland/meta-wayland-surface.c | 13 +- 11 files changed, 986 insertions(+), 556 deletions(-) create mode 100644 src/compositor/meta-surface-actor-wayland.c create mode 100644 src/compositor/meta-surface-actor-wayland.h create mode 100644 src/compositor/meta-surface-actor-x11.c create mode 100644 src/compositor/meta-surface-actor-x11.h diff --git a/src/Makefile.am b/src/Makefile.am index ae8f7c130..dcf94e53b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -80,6 +80,10 @@ libmutter_wayland_la_SOURCES = \ compositor/meta-shaped-texture-private.h \ compositor/meta-surface-actor.c \ compositor/meta-surface-actor.h \ + compositor/meta-surface-actor-x11.c \ + compositor/meta-surface-actor-x11.h \ + compositor/meta-surface-actor-wayland.c \ + compositor/meta-surface-actor-wayland.h \ compositor/meta-texture-rectangle.c \ compositor/meta-texture-rectangle.h \ compositor/meta-texture-tower.c \ diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c new file mode 100644 index 000000000..9fe1e8220 --- /dev/null +++ b/src/compositor/meta-surface-actor-wayland.c @@ -0,0 +1,153 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2013 Red Hat + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jasper St. Pierre + */ + +#include "config.h" + +#include "meta-surface-actor-wayland.h" + +#include +#include "meta-shaped-texture-private.h" + +struct _MetaSurfaceActorWaylandPrivate +{ + MetaWaylandSurface *surface; + MetaWaylandBuffer *buffer; +}; +typedef struct _MetaSurfaceActorWaylandPrivate MetaSurfaceActorWaylandPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (MetaSurfaceActorWayland, meta_surface_actor_wayland, META_TYPE_SURFACE_ACTOR) + +static void +meta_surface_actor_wayland_process_damage (MetaSurfaceActor *actor, + int x, int y, int width, int height) +{ + MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (actor); + MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self); + + struct wl_resource *resource = priv->buffer->resource; + struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (resource); + + if (shm_buffer) + { + CoglTexture2D *texture = COGL_TEXTURE_2D (priv->buffer->texture); + cogl_wayland_texture_set_region_from_shm_buffer (texture, x, y, width, height, shm_buffer, x, y, 0, NULL); + } + + meta_surface_actor_update_area (META_SURFACE_ACTOR (self), x, y, width, height); +} + +static void +meta_surface_actor_wayland_pre_paint (MetaSurfaceActor *actor) +{ +} + +static gboolean +meta_surface_actor_wayland_is_argb32 (MetaSurfaceActor *actor) +{ + /* XXX -- look at the SHM buffer format. */ + return TRUE; +} + +static gboolean +meta_surface_actor_wayland_is_visible (MetaSurfaceActor *actor) +{ + /* TODO: ensure that the buffer isn't NULL, implement + * wayland mapping semantics */ + return TRUE; +} + +static gboolean +meta_surface_actor_wayland_should_unredirect (MetaSurfaceActor *actor) +{ + return FALSE; +} + +static void +meta_surface_actor_wayland_set_unredirected (MetaSurfaceActor *actor, + gboolean unredirected) +{ + /* Do nothing. In the future, we'll use KMS to set this + * up as a hardware overlay or something. */ +} + +static gboolean +meta_surface_actor_wayland_is_unredirected (MetaSurfaceActor *actor) +{ + return FALSE; +} + +static void +meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass) +{ + MetaSurfaceActorClass *surface_actor_class = META_SURFACE_ACTOR_CLASS (klass); + + surface_actor_class->process_damage = meta_surface_actor_wayland_process_damage; + surface_actor_class->pre_paint = meta_surface_actor_wayland_pre_paint; + surface_actor_class->is_argb32 = meta_surface_actor_wayland_is_argb32; + surface_actor_class->is_visible = meta_surface_actor_wayland_is_visible; + + surface_actor_class->should_unredirect = meta_surface_actor_wayland_should_unredirect; + surface_actor_class->set_unredirected = meta_surface_actor_wayland_set_unredirected; + surface_actor_class->is_unredirected = meta_surface_actor_wayland_is_unredirected; +} + +static void +meta_surface_actor_wayland_init (MetaSurfaceActorWayland *self) +{ +} + +MetaSurfaceActor * +meta_surface_actor_wayland_new (MetaWaylandSurface *surface) +{ + MetaSurfaceActorWayland *self = g_object_new (META_TYPE_SURFACE_ACTOR_WAYLAND, NULL); + MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self); + + g_assert (meta_is_wayland_compositor ()); + + priv->surface = surface; + + return META_SURFACE_ACTOR (self); +} + +void +meta_surface_actor_wayland_set_buffer (MetaSurfaceActorWayland *self, + MetaWaylandBuffer *buffer) +{ + MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self); + MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); + + priv->buffer = buffer; + + if (buffer) + meta_shaped_texture_set_texture (stex, buffer->texture); + else + meta_shaped_texture_set_texture (stex, NULL); +} + +MetaWaylandSurface * +meta_surface_actor_wayland_get_surface (MetaSurfaceActorWayland *self) +{ + MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self); + return priv->surface; +} diff --git a/src/compositor/meta-surface-actor-wayland.h b/src/compositor/meta-surface-actor-wayland.h new file mode 100644 index 000000000..89c6b300f --- /dev/null +++ b/src/compositor/meta-surface-actor-wayland.h @@ -0,0 +1,66 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2013 Red Hat + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jasper St. Pierre + */ + +#ifndef __META_SURFACE_ACTOR_WAYLAND_H__ +#define __META_SURFACE_ACTOR_WAYLAND_H__ + +#include + +#include "meta-surface-actor.h" + +#include "meta-wayland-private.h" + +G_BEGIN_DECLS + +#define META_TYPE_SURFACE_ACTOR_WAYLAND (meta_surface_actor_wayland_get_type ()) +#define META_SURFACE_ACTOR_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SURFACE_ACTOR_WAYLAND, MetaSurfaceActorWayland)) +#define META_SURFACE_ACTOR_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SURFACE_ACTOR_WAYLAND, MetaSurfaceActorWaylandClass)) +#define META_IS_SURFACE_ACTOR_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SURFACE_ACTOR_WAYLAND)) +#define META_IS_SURFACE_ACTOR_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SURFACE_ACTOR_WAYLAND)) +#define META_SURFACE_ACTOR_WAYLAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SURFACE_ACTOR_WAYLAND, MetaSurfaceActorWaylandClass)) + +typedef struct _MetaSurfaceActorWayland MetaSurfaceActorWayland; +typedef struct _MetaSurfaceActorWaylandClass MetaSurfaceActorWaylandClass; + +struct _MetaSurfaceActorWayland +{ + MetaSurfaceActor parent; +}; + +struct _MetaSurfaceActorWaylandClass +{ + MetaSurfaceActorClass parent_class; +}; + +GType meta_surface_actor_wayland_get_type (void); + +MetaSurfaceActor * meta_surface_actor_wayland_new (MetaWaylandSurface *surface); +MetaWaylandSurface * meta_surface_actor_wayland_get_surface (MetaSurfaceActorWayland *self); + +void meta_surface_actor_wayland_set_buffer (MetaSurfaceActorWayland *self, + MetaWaylandBuffer *buffer); + +G_END_DECLS + +#endif /* __META_SURFACE_ACTOR_WAYLAND_H__ */ diff --git a/src/compositor/meta-surface-actor-x11.c b/src/compositor/meta-surface-actor-x11.c new file mode 100644 index 000000000..3eea2c31b --- /dev/null +++ b/src/compositor/meta-surface-actor-x11.c @@ -0,0 +1,453 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2013 Red Hat + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Owen Taylor + * Jasper St. Pierre + */ + +#include "config.h" + +#include "meta-surface-actor-x11.h" + +#include +#include +#include + +#include +#include "window-private.h" +#include "meta-shaped-texture-private.h" +#include "meta-cullable.h" + +struct _MetaSurfaceActorX11Private +{ + MetaWindow *window; + + MetaDisplay *display; + + CoglTexture *texture; + Pixmap pixmap; + Damage damage; + + int last_width; + int last_height; + + /* This is used to detect fullscreen windows that need to be unredirected */ + guint full_damage_frames_count; + guint does_full_damage : 1; + + /* Other state... */ + guint argb32 : 1; + guint received_damage : 1; + guint size_changed : 1; + + guint unredirected : 1; +}; +typedef struct _MetaSurfaceActorX11Private MetaSurfaceActorX11Private; + +G_DEFINE_TYPE_WITH_PRIVATE (MetaSurfaceActorX11, meta_surface_actor_x11, META_TYPE_SURFACE_ACTOR) + +static void +free_damage (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = priv->display; + Display *xdisplay = meta_display_get_xdisplay (display); + + if (priv->damage == None) + return; + + meta_error_trap_push (display); + XDamageDestroy (xdisplay, priv->damage); + priv->damage = None; + meta_error_trap_pop (display); +} + +static void +detach_pixmap (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = priv->display; + Display *xdisplay = meta_display_get_xdisplay (display); + MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); + + if (priv->pixmap == None) + return; + + /* Get rid of all references to the pixmap before freeing it; it's unclear whether + * 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); + cogl_flush (); + + meta_error_trap_push (display); + XFreePixmap (xdisplay, priv->pixmap); + priv->pixmap = None; + meta_error_trap_pop (display); + + cogl_object_unref (priv->texture); + priv->texture = NULL; +} + +static void +set_pixmap (MetaSurfaceActorX11 *self, + Pixmap pixmap) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); + CoglTexture *texture; + + g_assert (priv->pixmap == None); + priv->pixmap = pixmap; + + texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->pixmap, FALSE, NULL)); + + if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture)))) + g_warning ("NOTE: Not using GLX TFP!\n"); + + priv->texture = texture; + meta_shaped_texture_set_texture (stex, texture); +} + +static void +update_pixmap (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = priv->display; + Display *xdisplay = meta_display_get_xdisplay (display); + + if (priv->size_changed) + { + detach_pixmap (self); + priv->size_changed = FALSE; + } + + if (priv->pixmap == None) + { + Pixmap new_pixmap; + Window xwindow = meta_window_get_toplevel_xwindow (priv->window); + + meta_error_trap_push (display); + new_pixmap = XCompositeNameWindowPixmap (xdisplay, xwindow); + + if (meta_error_trap_pop_with_return (display) != Success) + { + /* Probably a BadMatch if the window isn't viewable; we could + * GrabServer/GetWindowAttributes/NameWindowPixmap/UngrabServer/Sync + * to avoid this, but there's no reason to take two round trips + * when one will do. (We need that Sync if we want to handle failures + * for any reason other than !viewable. That's unlikely, but maybe + * we'll BadAlloc or something.) + */ + new_pixmap = None; + } + + if (new_pixmap == None) + { + meta_verbose ("Unable to get named pixmap for %s\n", + meta_window_get_description (priv->window)); + return; + } + + set_pixmap (self, new_pixmap); + } +} + +static gboolean +is_visible (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + return (priv->pixmap != None) && !priv->unredirected; +} + +static void +damage_area (MetaSurfaceActorX11 *self, + int x, int y, int width, int height) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + if (!is_visible (self)) + return; + + cogl_texture_pixmap_x11_update_area (priv->texture, x, y, width, height); + meta_surface_actor_update_area (META_SURFACE_ACTOR (self), x, y, width, height); +} + +static void +meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor, + int x, int y, int width, int height) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + priv->received_damage = TRUE; + + if (meta_window_is_fullscreen (priv->window) && !priv->unredirected && !priv->does_full_damage) + { + MetaRectangle window_rect; + meta_window_get_frame_rect (priv->window, &window_rect); + + if (window_rect.x == x && + window_rect.y == y && + window_rect.width == width && + window_rect.height == height) + priv->full_damage_frames_count++; + else + priv->full_damage_frames_count = 0; + + if (priv->full_damage_frames_count >= 100) + priv->does_full_damage = TRUE; + } + + /* Drop damage event for unredirected windows */ + if (priv->unredirected) + return; + + damage_area (self, x, y, width, height); +} + +static void +meta_surface_actor_x11_pre_paint (MetaSurfaceActor *actor) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = priv->display; + Display *xdisplay = meta_display_get_xdisplay (display); + + if (priv->received_damage) + { + meta_error_trap_push (display); + XDamageSubtract (xdisplay, priv->damage, None, None); + meta_error_trap_pop (display); + + /* We need to make sure that any X drawing that happens before the + * XDamageSubtract() above is visible to subsequent GL rendering; + * the only standardized way to do this is EXT_x11_sync_object, + * which isn't yet widely available. For now, we count on details + * of Xorg and the open source drivers, and hope for the best + * otherwise. + * + * Xorg and open source driver specifics: + * + * The X server makes sure to flush drawing to the kernel before + * sending out damage events, but since we use DamageReportBoundingBox + * there may be drawing between the last damage event and the + * XDamageSubtract() that needs to be flushed as well. + * + * Xorg always makes sure that drawing is flushed to the kernel + * before writing events or responses to the client, so any round trip + * request at this point is sufficient to flush the GLX buffers. + */ + XSync (xdisplay, False); + + priv->received_damage = FALSE; + } + + update_pixmap (self); +} + +static void +update_is_argb32 (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = priv->display; + Display *xdisplay = meta_display_get_xdisplay (display); + + XRenderPictFormat *format; + format = XRenderFindVisualFormat (xdisplay, priv->window->xvisual); + + priv->argb32 = (format && format->type == PictTypeDirect && format->direct.alphaMask); +} + +static gboolean +meta_surface_actor_x11_is_argb32 (MetaSurfaceActor *actor) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + return priv->argb32; +} + +static gboolean +meta_surface_actor_x11_is_visible (MetaSurfaceActor *actor) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + return is_visible (self); +} + +static gboolean +meta_surface_actor_x11_should_unredirect (MetaSurfaceActor *actor) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + MetaWindow *window = priv->window; + + if (meta_window_requested_dont_bypass_compositor (window)) + return FALSE; + + if (window->opacity != 0xFF) + return FALSE; + + if (window->shape_region != NULL) + return FALSE; + + if (priv->argb32 && !meta_window_requested_bypass_compositor (window)) + return FALSE; + + if (!meta_window_is_monitor_sized (window)) + return FALSE; + + if (meta_window_requested_bypass_compositor (window)) + return TRUE; + + if (meta_window_is_override_redirect (window)) + return TRUE; + + if (priv->does_full_damage) + return TRUE; + + return FALSE; +} + +static void +sync_unredirected (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = priv->display; + Display *xdisplay = meta_display_get_xdisplay (display); + Window xwindow = meta_window_get_toplevel_xwindow (priv->window); + + meta_error_trap_push (display); + + if (priv->unredirected) + { + detach_pixmap (self); + XCompositeUnredirectWindow (xdisplay, xwindow, CompositeRedirectManual); + } + else + { + XCompositeRedirectWindow (xdisplay, xwindow, CompositeRedirectManual); + } + + meta_error_trap_pop (display); +} + +static void +meta_surface_actor_x11_set_unredirected (MetaSurfaceActor *actor, + gboolean unredirected) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + if (priv->unredirected == unredirected) + return; + + priv->unredirected = unredirected; + sync_unredirected (self); +} + +static gboolean +meta_surface_actor_x11_is_unredirected (MetaSurfaceActor *actor) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + return priv->unredirected; +} + +static void +meta_surface_actor_x11_dispose (GObject *object) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (object); + + detach_pixmap (self); + free_damage (self); + + G_OBJECT_CLASS (meta_surface_actor_x11_parent_class)->dispose (object); +} + +static void +meta_surface_actor_x11_class_init (MetaSurfaceActorX11Class *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MetaSurfaceActorClass *surface_actor_class = META_SURFACE_ACTOR_CLASS (klass); + + object_class->dispose = meta_surface_actor_x11_dispose; + + surface_actor_class->process_damage = meta_surface_actor_x11_process_damage; + surface_actor_class->pre_paint = meta_surface_actor_x11_pre_paint; + surface_actor_class->is_argb32 = meta_surface_actor_x11_is_argb32; + surface_actor_class->is_visible = meta_surface_actor_x11_is_visible; + + surface_actor_class->should_unredirect = meta_surface_actor_x11_should_unredirect; + surface_actor_class->set_unredirected = meta_surface_actor_x11_set_unredirected; + surface_actor_class->is_unredirected = meta_surface_actor_x11_is_unredirected; +} + +static void +meta_surface_actor_x11_init (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + priv->last_width = -1; + priv->last_height = -1; +} + +MetaSurfaceActor * +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); + Display *xdisplay = meta_display_get_xdisplay (display); + Window xwindow = meta_window_get_toplevel_xwindow (window); + + g_assert (!meta_is_wayland_compositor ()); + + priv->window = window; + priv->display = display; + + priv->damage = XDamageCreate (xdisplay, xwindow, XDamageReportBoundingBox); + update_is_argb32 (self); + + priv->unredirected = FALSE; + sync_unredirected (self); + + return META_SURFACE_ACTOR (self); +} + +void +meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self, + int width, int height) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + if (priv->last_width == width && + priv->last_height == height) + return; + + priv->size_changed = TRUE; + priv->last_width = width; + priv->last_height = height; +} diff --git a/src/compositor/meta-surface-actor-x11.h b/src/compositor/meta-surface-actor-x11.h new file mode 100644 index 000000000..0e692ee0f --- /dev/null +++ b/src/compositor/meta-surface-actor-x11.h @@ -0,0 +1,69 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2013 Red Hat + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Owen Taylor + * Jasper St. Pierre + */ + +#ifndef __META_SURFACE_ACTOR_X11_H__ +#define __META_SURFACE_ACTOR_X11_H__ + +#include + +#include "meta-surface-actor.h" + +#include + +#include +#include + +G_BEGIN_DECLS + +#define META_TYPE_SURFACE_ACTOR_X11 (meta_surface_actor_x11_get_type ()) +#define META_SURFACE_ACTOR_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SURFACE_ACTOR_X11, MetaSurfaceActorX11)) +#define META_SURFACE_ACTOR_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SURFACE_ACTOR_X11, MetaSurfaceActorX11Class)) +#define META_IS_SURFACE_ACTOR_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SURFACE_ACTOR_X11)) +#define META_IS_SURFACE_ACTOR_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SURFACE_ACTOR_X11)) +#define META_SURFACE_ACTOR_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SURFACE_ACTOR_X11, MetaSurfaceActorX11Class)) + +typedef struct _MetaSurfaceActorX11 MetaSurfaceActorX11; +typedef struct _MetaSurfaceActorX11Class MetaSurfaceActorX11Class; + +struct _MetaSurfaceActorX11 +{ + MetaSurfaceActor parent; +}; + +struct _MetaSurfaceActorX11Class +{ + MetaSurfaceActorClass parent_class; +}; + +GType meta_surface_actor_x11_get_type (void); + +MetaSurfaceActor * meta_surface_actor_x11_new (MetaWindow *window); + +void meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self, + int width, int height); + +G_END_DECLS + +#endif /* __META_SURFACE_ACTOR_X11_H__ */ diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c index 5afa4d70f..734629a79 100644 --- a/src/compositor/meta-surface-actor.c +++ b/src/compositor/meta-surface-actor.c @@ -10,30 +10,30 @@ */ #include -#include -#include -#include -#include + #include "meta-surface-actor.h" + +#include +#include #include "meta-wayland-private.h" #include "meta-cullable.h" - #include "meta-shaped-texture-private.h" struct _MetaSurfaceActorPrivate { - MetaWaylandSurface *surface; - MetaShapedTexture *texture; - MetaWaylandBuffer *buffer; cairo_region_t *input_region; + + /* Freeze/thaw accounting */ + guint freeze_count; + guint needs_damage_all : 1; }; static void cullable_iface_init (MetaCullableInterface *iface); -G_DEFINE_TYPE_WITH_CODE (MetaSurfaceActor, meta_surface_actor, CLUTTER_TYPE_ACTOR, - G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init)); +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaSurfaceActor, meta_surface_actor, CLUTTER_TYPE_ACTOR, + G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init)); gboolean meta_surface_actor_get_unobscured_bounds (MetaSurfaceActor *self, @@ -164,50 +164,11 @@ meta_surface_actor_get_texture (MetaSurfaceActor *self) return self->priv->texture; } -static void -update_area (MetaSurfaceActor *self, - int x, int y, int width, int height) -{ - MetaSurfaceActorPrivate *priv = self->priv; - - if (meta_is_wayland_compositor ()) - { - struct wl_resource *resource = priv->buffer->resource; - struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (resource); - - if (shm_buffer) - { - CoglTexture2D *texture = COGL_TEXTURE_2D (priv->buffer->texture); - cogl_wayland_texture_set_region_from_shm_buffer (texture, x, y, width, height, shm_buffer, x, y, 0, NULL); - } - } - else - { - CoglTexturePixmapX11 *texture = COGL_TEXTURE_PIXMAP_X11 (meta_shaped_texture_get_texture (priv->texture)); - cogl_texture_pixmap_x11_update_area (texture, x, y, width, height); - } -} - gboolean -meta_surface_actor_damage_all (MetaSurfaceActor *self) +meta_surface_actor_update_area (MetaSurfaceActor *self, + int x, int y, int width, int height) { MetaSurfaceActorPrivate *priv = self->priv; - CoglTexture *texture = meta_shaped_texture_get_texture (priv->texture); - - update_area (self, 0, 0, cogl_texture_get_width (texture), cogl_texture_get_height (texture)); - return meta_shaped_texture_update_area (priv->texture, 0, 0, cogl_texture_get_width (texture), cogl_texture_get_height (texture)); -} - -gboolean -meta_surface_actor_damage_area (MetaSurfaceActor *self, - int x, - int y, - int width, - int height) -{ - MetaSurfaceActorPrivate *priv = self->priv; - - update_area (self, x, y, width, height); return meta_shaped_texture_update_area (priv->texture, x, y, width, height); } @@ -218,27 +179,6 @@ meta_surface_actor_is_obscured (MetaSurfaceActor *self) return meta_shaped_texture_is_obscured (priv->texture); } -void -meta_surface_actor_attach_wayland_buffer (MetaSurfaceActor *self, - MetaWaylandBuffer *buffer) -{ - MetaSurfaceActorPrivate *priv = self->priv; - priv->buffer = buffer; - - if (buffer) - meta_shaped_texture_set_texture (priv->texture, buffer->texture); - else - meta_shaped_texture_set_texture (priv->texture, NULL); -} - -void -meta_surface_actor_set_texture (MetaSurfaceActor *self, - CoglTexture *texture) -{ - MetaSurfaceActorPrivate *priv = self->priv; - meta_shaped_texture_set_texture (priv->texture, texture); -} - void meta_surface_actor_set_input_region (MetaSurfaceActor *self, cairo_region_t *region) @@ -262,20 +202,114 @@ meta_surface_actor_set_opaque_region (MetaSurfaceActor *self, meta_shaped_texture_set_opaque_region (priv->texture, region); } -MetaWaylandSurface * -meta_surface_actor_get_surface (MetaSurfaceActor *self) +static gboolean +is_frozen (MetaSurfaceActor *self) { MetaSurfaceActorPrivate *priv = self->priv; - return priv->surface; + return (priv->freeze_count > 0); } -MetaSurfaceActor * -meta_surface_actor_new (MetaWaylandSurface *surface) +void +meta_surface_actor_process_damage (MetaSurfaceActor *self, + int x, int y, int width, int height) { - MetaSurfaceActor *self = g_object_new (META_TYPE_SURFACE_ACTOR, NULL); MetaSurfaceActorPrivate *priv = self->priv; - priv->surface = surface; + if (is_frozen (self)) + { + /* The window is frozen due to an effect in progress: we ignore damage + * here on the off chance that this will stop the corresponding + * texture_from_pixmap from being update. + * + * needs_damage_all tracks that some unknown damage happened while the + * window was frozen so that when the window becomes unfrozen we can + * issue a full window update to cover any lost damage. + * + * It should be noted that this is an unreliable mechanism since it's + * quite likely that drivers will aim to provide a zero-copy + * implementation of the texture_from_pixmap extension and in those cases + * any drawing done to the window is always immediately reflected in the + * texture regardless of damage event handling. + */ + priv->needs_damage_all = TRUE; + return; + } - return self; + META_SURFACE_ACTOR_GET_CLASS (self)->process_damage (self, x, y, width, height); +} + +void +meta_surface_actor_pre_paint (MetaSurfaceActor *self) +{ + META_SURFACE_ACTOR_GET_CLASS (self)->pre_paint (self); +} + +gboolean +meta_surface_actor_is_argb32 (MetaSurfaceActor *self) +{ + return META_SURFACE_ACTOR_GET_CLASS (self)->is_argb32 (self); +} + +gboolean +meta_surface_actor_is_visible (MetaSurfaceActor *self) +{ + return META_SURFACE_ACTOR_GET_CLASS (self)->is_visible (self); +} + +void +meta_surface_actor_freeze (MetaSurfaceActor *self) +{ + MetaSurfaceActorPrivate *priv = self->priv; + + priv->freeze_count ++; +} + +void +meta_surface_actor_thaw (MetaSurfaceActor *self) +{ + MetaSurfaceActorPrivate *priv = self->priv; + + if (priv->freeze_count == 0) + { + g_critical ("Error in freeze/thaw accounting."); + return; + } + + priv->freeze_count --; + + /* Since we ignore damage events while a window is frozen for certain effects + * we may need to issue an update_area() covering the whole pixmap if we + * don't know what real damage has happened. */ + if (priv->needs_damage_all) + { + meta_surface_actor_process_damage (self, 0, 0, + clutter_actor_get_width (CLUTTER_ACTOR (priv->texture)), + clutter_actor_get_height (CLUTTER_ACTOR (priv->texture))); + priv->needs_damage_all = FALSE; + } +} + +gboolean +meta_surface_actor_is_frozen (MetaSurfaceActor *self) +{ + return is_frozen (self); +} + +gboolean +meta_surface_actor_should_unredirect (MetaSurfaceActor *self) +{ + return META_SURFACE_ACTOR_GET_CLASS (self)->should_unredirect (self); +} + +void +meta_surface_actor_set_unredirected (MetaSurfaceActor *self, + gboolean unredirected) +{ + META_SURFACE_ACTOR_GET_CLASS (self)->set_unredirected (self, unredirected); +} + +gboolean +meta_surface_actor_is_unredirected (MetaSurfaceActor *self) +{ + return META_SURFACE_ACTOR_GET_CLASS (self)->is_unredirected (self); } diff --git a/src/compositor/meta-surface-actor.h b/src/compositor/meta-surface-actor.h index e42deb42f..c3182a626 100644 --- a/src/compositor/meta-surface-actor.h +++ b/src/compositor/meta-surface-actor.h @@ -6,7 +6,6 @@ #include #include -#include "meta-wayland-types.h" G_BEGIN_DECLS @@ -25,6 +24,17 @@ struct _MetaSurfaceActorClass { /*< private >*/ ClutterActorClass parent_class; + + void (* process_damage) (MetaSurfaceActor *actor, + int x, int y, int width, int height); + void (* pre_paint) (MetaSurfaceActor *actor); + gboolean (* is_argb32) (MetaSurfaceActor *actor); + gboolean (* is_visible) (MetaSurfaceActor *actor); + + gboolean (* should_unredirect) (MetaSurfaceActor *actor); + void (* set_unredirected) (MetaSurfaceActor *actor, + gboolean unredirected); + gboolean (* is_unredirected) (MetaSurfaceActor *actor); }; struct _MetaSurfaceActor @@ -36,34 +46,37 @@ struct _MetaSurfaceActor GType meta_surface_actor_get_type (void); -MetaSurfaceActor *meta_surface_actor_new (MetaWaylandSurface *surface); - cairo_surface_t *meta_surface_actor_get_image (MetaSurfaceActor *self, cairo_rectangle_int_t *clip); MetaShapedTexture *meta_surface_actor_get_texture (MetaSurfaceActor *self); -gboolean meta_surface_actor_damage_all (MetaSurfaceActor *self); -gboolean meta_surface_actor_damage_area (MetaSurfaceActor *self, - int x, - int y, - int width, - int height); - gboolean meta_surface_actor_is_obscured (MetaSurfaceActor *self); gboolean meta_surface_actor_get_unobscured_bounds (MetaSurfaceActor *self, cairo_rectangle_int_t *unobscured_bounds); -void meta_surface_actor_set_texture (MetaSurfaceActor *self, - CoglTexture *texture); -void meta_surface_actor_attach_wayland_buffer (MetaSurfaceActor *self, - MetaWaylandBuffer *buffer); void meta_surface_actor_set_input_region (MetaSurfaceActor *self, cairo_region_t *region); void meta_surface_actor_set_opaque_region (MetaSurfaceActor *self, cairo_region_t *region); -MetaWaylandSurface *meta_surface_actor_get_surface (MetaSurfaceActor *surface); +gboolean meta_surface_actor_update_area (MetaSurfaceActor *actor, + int x, int y, int width, int height); + +void meta_surface_actor_process_damage (MetaSurfaceActor *actor, + int x, int y, int width, int height); +void meta_surface_actor_pre_paint (MetaSurfaceActor *actor); +gboolean meta_surface_actor_is_argb32 (MetaSurfaceActor *actor); +gboolean meta_surface_actor_is_visible (MetaSurfaceActor *actor); + +void meta_surface_actor_freeze (MetaSurfaceActor *actor); +void meta_surface_actor_thaw (MetaSurfaceActor *actor); +gboolean meta_surface_actor_is_frozen (MetaSurfaceActor *actor); + +gboolean meta_surface_actor_should_unredirect (MetaSurfaceActor *actor); +void meta_surface_actor_set_unredirected (MetaSurfaceActor *actor, + gboolean unredirected); +gboolean meta_surface_actor_is_unredirected (MetaSurfaceActor *actor); G_END_DECLS diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index 1ffc51251..ba6f3f14f 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -10,10 +10,6 @@ #include -#include -#include -#include - #include #include #include /* for gdk_rectangle_union() */ @@ -30,13 +26,15 @@ #include "meta-shaped-texture-private.h" #include "meta-shadow-factory-private.h" #include "meta-window-actor-private.h" -#include "meta-surface-actor.h" #include "meta-texture-rectangle.h" #include "region-utils.h" #include "meta-wayland-private.h" #include "monitor-private.h" #include "meta-cullable.h" +#include "meta-surface-actor.h" +#include "meta-surface-actor-x11.h" + struct _MetaWindowActorPrivate { MetaWindow *window; @@ -63,19 +61,13 @@ struct _MetaWindowActorPrivate /* The region we should clip to when painting the shadow */ cairo_region_t *shadow_clip; - guint send_frame_messages_timer; - gint64 frame_drawn_time; - /* Extracted size-invariant shape used for shadows */ MetaWindowShape *shadow_shape; - - gint last_width; - gint last_height; - - gint freeze_count; - char * shadow_class; + guint send_frame_messages_timer; + gint64 frame_drawn_time; + /* * These need to be counters rather than flags, since more plugins * can implement same effect; the practicality of stacking effects @@ -90,11 +82,7 @@ struct _MetaWindowActorPrivate /* List of FrameData for recent frames */ GList *frames; - Pixmap back_pixmap; /* Not used in wayland compositor mode */ - Damage damage; /* Not used in wayland compositor mode */ - guint visible : 1; - guint argb32 : 1; guint disposed : 1; guint redecorating : 1; @@ -111,22 +99,7 @@ struct _MetaWindowActorPrivate guint no_shadow : 1; - - /* - * None of these are used in wayland compositor mode... - */ - - guint needs_damage_all : 1; - guint received_x11_damage : 1; - - guint x11_size_changed : 1; guint updates_frozen : 1; - - guint unredirected : 1; - - /* This is used to detect fullscreen windows that need to be unredirected */ - guint full_damage_frames_count; - guint does_full_damage : 1; }; typedef struct _FrameData FrameData; @@ -163,7 +136,6 @@ static gboolean meta_window_actor_get_paint_volume (ClutterActor *actor, ClutterPaintVolume *volume); -static void meta_window_actor_detach_x11_pixmap (MetaWindowActor *self); static gboolean meta_window_actor_has_shadow (MetaWindowActor *self); static void meta_window_actor_handle_updates (MetaWindowActor *self); @@ -254,9 +226,6 @@ window_decorated_notify (MetaWindow *mw, { MetaWindowActor *self = META_WINDOW_ACTOR (data); MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); /* * Basically, we have to reconstruct the the internals of this object @@ -264,23 +233,6 @@ window_decorated_notify (MetaWindow *mw, */ priv->redecorating = TRUE; - if (!meta_is_wayland_compositor ()) - { - meta_window_actor_detach_x11_pixmap (self); - - /* - * First of all, clean up any resources we are currently using and will - * be replacing. - */ - if (priv->damage != None) - { - meta_error_trap_push (display); - XDamageDestroy (xdisplay, priv->damage); - meta_error_trap_pop (display); - priv->damage = None; - } - } - /* * Recreate the contents. */ @@ -305,13 +257,52 @@ surface_allocation_changed_notify (ClutterActor *actor, meta_window_actor_update_shape (self); } +static gboolean +is_argb32 (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv = self->priv; + return meta_surface_actor_is_argb32 (priv->surface); +} + static gboolean is_non_opaque (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; MetaWindow *window = priv->window; - return priv->argb32 || (window->opacity != 0xFF); + return is_argb32 (self) || (window->opacity != 0xFF); +} + +static gboolean +is_frozen (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv = self->priv; + return meta_surface_actor_is_frozen (priv->surface); +} + +static void +meta_window_actor_freeze (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv = self->priv; + meta_surface_actor_freeze (priv->surface); +} + +static void +meta_window_actor_thaw (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv = self->priv; + + meta_surface_actor_thaw (priv->surface); + + if (is_frozen (self)) + return; + + /* We sometimes ignore moves and resizes on frozen windows */ + meta_window_actor_sync_actor_geometry (self, FALSE); + + /* We do this now since we might be going right back into the + * frozen state */ + meta_window_actor_handle_updates (self); } static void @@ -320,38 +311,15 @@ meta_window_actor_constructed (GObject *object) MetaWindowActor *self = META_WINDOW_ACTOR (object); MetaWindowActorPrivate *priv = self->priv; MetaWindow *window = priv->window; - Window xwindow = meta_window_get_toplevel_xwindow (window); - MetaScreen *screen = meta_window_get_screen (window); - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - priv->screen = screen; - - if (!meta_is_wayland_compositor ()) - priv->damage = XDamageCreate (xdisplay, xwindow, - XDamageReportBoundingBox); - - if (window->client_type == META_WINDOW_CLIENT_TYPE_X11) - { - XRenderPictFormat *format; - - format = XRenderFindVisualFormat (xdisplay, window->xvisual); - - if (format && format->type == PictTypeDirect && format->direct.alphaMask) - priv->argb32 = TRUE; - } - else - { - /* XXX: parse shm formats to determine argb32 */ - priv->argb32 = TRUE; - } + priv->screen = window->screen; if (!priv->surface) { if (window->surface) priv->surface = window->surface->surface_actor; else - priv->surface = meta_surface_actor_new (NULL); + priv->surface = meta_surface_actor_x11_new (window); g_object_ref_sink (priv->surface); clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface)); @@ -374,8 +342,6 @@ meta_window_actor_dispose (GObject *object) MetaWindowActor *self = META_WINDOW_ACTOR (object); MetaWindowActorPrivate *priv = self->priv; MetaScreen *screen; - MetaDisplay *display; - Display *xdisplay; MetaCompScreen *info; if (priv->disposed) @@ -386,9 +352,6 @@ meta_window_actor_dispose (GObject *object) screen = priv->screen; info = meta_screen_get_compositor_data (screen); - if (!meta_is_wayland_compositor ()) - meta_window_actor_detach_x11_pixmap (self); - if (priv->send_frame_messages_timer != 0) { g_source_remove (priv->send_frame_messages_timer); @@ -403,18 +366,6 @@ meta_window_actor_dispose (GObject *object) g_clear_pointer (&priv->unfocused_shadow, meta_shadow_unref); g_clear_pointer (&priv->shadow_shape, meta_window_shape_unref); - if (!meta_is_wayland_compositor () && priv->damage != None) - { - display = meta_screen_get_display (screen); - xdisplay = meta_display_get_xdisplay (display); - - meta_error_trap_push (display); - XDamageDestroy (xdisplay, priv->damage); - meta_error_trap_pop (display); - - priv->damage = None; - } - info->windows = g_list_remove (info->windows, (gconstpointer) self); g_clear_object (&priv->window); @@ -825,13 +776,6 @@ meta_window_actor_is_destroyed (MetaWindowActor *self) return self->priv->disposed; } -static void -meta_window_actor_freeze (MetaWindowActor *self) -{ - if (!meta_is_wayland_compositor ()) - self->priv->freeze_count++; -} - static gboolean send_frame_messages_timeout (gpointer data) { @@ -886,55 +830,6 @@ queue_send_frame_messages_timeout (MetaWindowActor *self) priv->send_frame_messages_timer = g_timeout_add_full (META_PRIORITY_REDRAW, offset, send_frame_messages_timeout, self, NULL); } -static void -meta_window_actor_damage_all (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = self->priv; - gboolean redraw_queued; - - if (!priv->needs_damage_all) - return; - - if (priv->back_pixmap == None) - return; - - redraw_queued = meta_surface_actor_damage_all (priv->surface); - priv->repaint_scheduled = priv->repaint_scheduled || redraw_queued; - priv->needs_damage_all = FALSE; -} - -static void -meta_window_actor_thaw (MetaWindowActor *self) -{ - if (!meta_is_wayland_compositor ()) - { - self->priv->freeze_count--; - - if (G_UNLIKELY (self->priv->freeze_count < 0)) - { - g_warning ("Error in freeze/thaw accounting."); - self->priv->freeze_count = 0; - return; - } - - if (self->priv->freeze_count) - return; - - /* We sometimes ignore moves and resizes on frozen windows */ - meta_window_actor_sync_actor_geometry (self, FALSE); - - /* We do this now since we might be going right back into the - * frozen state */ - meta_window_actor_handle_updates (self); - - /* Since we ignore damage events while a window is frozen for certain effects - * we may need to issue an update_area() covering the whole pixmap if we - * don't know what real damage has happened. */ - if (self->priv->needs_damage_all) - meta_window_actor_damage_all (self); - } -} - void meta_window_actor_queue_frame_drawn (MetaWindowActor *self, gboolean no_delay_frame) @@ -989,12 +884,6 @@ meta_window_actor_effect_in_progress (MetaWindowActor *self) self->priv->destroy_in_progress); } -static gboolean -is_frozen (MetaWindowActor *self) -{ - return self->priv->freeze_count ? TRUE : FALSE; -} - static gboolean is_freeze_thaw_effect (gulong event) { @@ -1075,12 +964,6 @@ meta_window_actor_after_effects (MetaWindowActor *self) meta_window_actor_sync_visibility (self); meta_window_actor_sync_actor_geometry (self, FALSE); - - if (!meta_is_wayland_compositor ()) - { - if (priv->back_pixmap == None) - clutter_actor_queue_redraw (CLUTTER_ACTOR (priv->surface)); - } } void @@ -1155,93 +1038,19 @@ meta_window_actor_effect_completed (MetaWindowActor *self, meta_window_actor_after_effects (self); } -/* Called to drop our reference to a window backing pixmap that we - * previously obtained with XCompositeNameWindowPixmap. We do this - * when the window is unmapped or when we want to update to a new - * pixmap for a new size. - */ -static void -meta_window_actor_detach_x11_pixmap (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - - if (!priv->back_pixmap) - return; - - /* Get rid of all references to the pixmap before freeing it; it's unclear whether - * 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_surface_actor_set_texture (priv->surface, NULL); - cogl_flush(); - - XFreePixmap (xdisplay, priv->back_pixmap); - priv->back_pixmap = None; -} - gboolean meta_window_actor_should_unredirect (MetaWindowActor *self) { - MetaWindow *metaWindow = meta_window_actor_get_meta_window (self); MetaWindowActorPrivate *priv = self->priv; - - if (meta_is_wayland_compositor ()) - return FALSE; - - if (meta_window_requested_dont_bypass_compositor (metaWindow)) - return FALSE; - - if (metaWindow->opacity != 0xFF) - return FALSE; - - if (metaWindow->shape_region != NULL) - return FALSE; - - if (priv->argb32 && !meta_window_requested_bypass_compositor (metaWindow)) - return FALSE; - - if (!meta_window_is_monitor_sized (metaWindow)) - return FALSE; - - if (meta_window_requested_bypass_compositor (metaWindow)) - return TRUE; - - if (meta_window_is_override_redirect (metaWindow)) - return TRUE; - - if (priv->does_full_damage) - return TRUE; - - return FALSE; + return meta_surface_actor_should_unredirect (priv->surface); } void meta_window_actor_set_unredirected (MetaWindowActor *self, gboolean unredirected) { - MetaWindow *metaWindow = meta_window_actor_get_meta_window (self); - MetaDisplay *display = meta_window_get_display (metaWindow); - - Display *xdisplay = meta_display_get_xdisplay (display); - Window xwin = meta_window_get_toplevel_xwindow (metaWindow); - - meta_error_trap_push (display); - - if (unredirected) - { - XCompositeUnredirectWindow (xdisplay, xwin, CompositeRedirectManual); - } - else - { - XCompositeRedirectWindow (xdisplay, xwin, CompositeRedirectManual); - meta_window_actor_detach_x11_pixmap (self); - } - - self->priv->unredirected = unredirected; - meta_error_trap_pop (display); + MetaWindowActorPrivate *priv = self->priv; + meta_surface_actor_set_unredirected (priv->surface, unredirected); } void @@ -1301,19 +1110,11 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self, meta_window_get_input_rect (priv->window, &window_rect); - /* When running as a display server we catch size changes when new - buffers are attached */ - if (!meta_is_wayland_compositor ()) - { - if (priv->last_width != window_rect.width || - priv->last_height != window_rect.height) - { - priv->x11_size_changed = TRUE; - - priv->last_width = window_rect.width; - priv->last_height = window_rect.height; - } - } + /* When running as a Wayland compositor we catch size changes when new + * buffers are attached */ + if (META_IS_SURFACE_ACTOR_X11 (priv->surface)) + meta_surface_actor_x11_set_size (META_SURFACE_ACTOR_X11 (priv->surface), + window_rect.width, window_rect.height); /* Normally we want freezing a window to also freeze its position; this allows * windows to atomically move and resize together, either under app control, @@ -1325,15 +1126,6 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self, if (is_frozen (self) && !did_placement) return; - if (!meta_is_wayland_compositor ()) - { - if (priv->x11_size_changed) - { - meta_window_actor_detach_x11_pixmap (self); - meta_window_actor_update_shape (self); - } - } - if (meta_window_actor_effect_in_progress (self)) return; @@ -1500,20 +1292,13 @@ meta_window_actor_new (MetaWindow *window) priv = self->priv; - if (!meta_is_wayland_compositor ()) - { - priv->last_width = -1; - priv->last_height = -1; + meta_window_actor_set_updates_frozen (self, meta_window_updates_are_frozen (priv->window)); - meta_window_actor_set_updates_frozen (self, - meta_window_updates_are_frozen (priv->window)); - - /* If a window doesn't start off with updates frozen, we should - * we should send a _NET_WM_FRAME_DRAWN immediately after the first drawn. - */ - if (priv->window->extended_sync_request_counter && !priv->updates_frozen) - meta_window_actor_queue_frame_drawn (self, FALSE); - } + /* If a window doesn't start off with updates frozen, we should + * we should send a _NET_WM_FRAME_DRAWN immediately after the first drawn. + */ + if (priv->window->extended_sync_request_counter && !priv->updates_frozen) + meta_window_actor_queue_frame_drawn (self, FALSE); meta_window_actor_sync_actor_geometry (self, priv->window->placed); @@ -1622,13 +1407,6 @@ meta_window_actor_cull_out (MetaCullable *cullable, cairo_region_t *clip_region) { MetaWindowActor *self = META_WINDOW_ACTOR (cullable); - MetaWindowActorPrivate *priv = self->priv; - - meta_cullable_cull_out_children (cullable, unobscured_region, clip_region); - - /* Don't do any culling for the unredirected window */ - if (priv->unredirected) - return; meta_window_actor_set_clip_region_beneath (self, clip_region); } @@ -1651,64 +1429,6 @@ cullable_iface_init (MetaCullableInterface *iface) iface->reset_culling = meta_window_actor_reset_culling; } -/* When running as a wayland compositor we don't make requests for - * replacement pixmaps when resizing windows, we will instead be - * asked to attach replacement buffers by the clients. */ -static void -check_needs_x11_pixmap (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = self->priv; - MetaDisplay *display = meta_screen_get_display (priv->screen); - Display *xdisplay = meta_display_get_xdisplay (display); - Window xwindow = meta_window_get_toplevel_xwindow (priv->window); - - /* This can happen while we're frozen. */ - if (priv->x11_size_changed) - { - meta_window_actor_detach_x11_pixmap (self); - priv->x11_size_changed = FALSE; - } - - meta_error_trap_push (display); - - if (priv->back_pixmap == None) - { - CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - CoglTexture *texture; - - meta_error_trap_push (display); - - priv->back_pixmap = XCompositeNameWindowPixmap (xdisplay, xwindow); - - if (meta_error_trap_pop_with_return (display) != Success) - { - /* Probably a BadMatch if the window isn't viewable; we could - * GrabServer/GetWindowAttributes/NameWindowPixmap/UngrabServer/Sync - * to avoid this, but there's no reason to take two round trips - * when one will do. (We need that Sync if we want to handle failures - * for any reason other than !viewable. That's unlikely, but maybe - * we'll BadAlloc or something.) - */ - priv->back_pixmap = None; - } - - if (priv->back_pixmap == None) - { - meta_verbose ("Unable to get named pixmap for %p\n", self); - goto out; - } - - texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->back_pixmap, FALSE, NULL)); - if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture)))) - g_warning ("NOTE: Not using GLX TFP!\n"); - - meta_surface_actor_set_texture (META_SURFACE_ACTOR (priv->surface), texture); - } - - out: - meta_error_trap_pop (display); -} - static void check_needs_shadow (MetaWindowActor *self) { @@ -1776,61 +1496,12 @@ meta_window_actor_process_x11_damage (MetaWindowActor *self, XDamageNotifyEvent *event) { MetaWindowActorPrivate *priv = self->priv; - MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen); - gboolean redraw_queued; - priv->received_x11_damage = TRUE; - - if (meta_window_is_fullscreen (priv->window) && g_list_last (info->windows)->data == self && !priv->unredirected) - { - MetaRectangle window_rect; - meta_window_get_frame_rect (priv->window, &window_rect); - - if (window_rect.x == event->area.x && - window_rect.y == event->area.y && - window_rect.width == event->area.width && - window_rect.height == event->area.height) - priv->full_damage_frames_count++; - else - priv->full_damage_frames_count = 0; - - if (priv->full_damage_frames_count >= 100) - priv->does_full_damage = TRUE; - } - - /* Drop damage event for unredirected windows */ - if (priv->unredirected) - return; - - if (is_frozen (self)) - { - /* The window is frozen due to an effect in progress: we ignore damage - * here on the off chance that this will stop the corresponding - * texture_from_pixmap from being update. - * - * needs_damage_all tracks that some unknown damage happened while the - * window was frozen so that when the window becomes unfrozen we can - * issue a full window update to cover any lost damage. - * - * It should be noted that this is an unreliable mechanism since it's - * quite likely that drivers will aim to provide a zero-copy - * implementation of the texture_from_pixmap extension and in those cases - * any drawing done to the window is always immediately reflected in the - * texture regardless of damage event handling. - */ - priv->needs_damage_all = TRUE; - return; - } - - if (priv->back_pixmap == None) - return; - - redraw_queued = meta_surface_actor_damage_area (priv->surface, - event->area.x, - event->area.y, - event->area.width, - event->area.height); - priv->repaint_scheduled = priv->repaint_scheduled || redraw_queued; + meta_surface_actor_process_damage (priv->surface, + event->area.x, + event->area.y, + event->area.width, + event->area.height); } void @@ -2058,8 +1729,9 @@ meta_window_actor_update_opaque_region (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; cairo_region_t *opaque_region; + gboolean argb32 = is_argb32 (self); - if (priv->argb32 && priv->window->opaque_region != NULL) + if (argb32 && priv->window->opaque_region != NULL) { MetaFrameBorders borders; @@ -2079,7 +1751,7 @@ meta_window_actor_update_opaque_region (MetaWindowActor *self) cairo_region_translate (opaque_region, borders.total.left, borders.total.top); cairo_region_intersect (opaque_region, priv->shape_region); } - else if (priv->argb32) + else if (argb32) opaque_region = NULL; else opaque_region = cairo_region_reference (priv->shape_region); @@ -2136,9 +1808,6 @@ static void meta_window_actor_handle_updates (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); if (is_frozen (self)) { @@ -2147,45 +1816,13 @@ meta_window_actor_handle_updates (MetaWindowActor *self) return; } - if (!meta_is_wayland_compositor ()) - { - if (priv->unredirected) - { - /* Nothing to do here until/if the window gets redirected again */ - return; - } + if (meta_surface_actor_is_unredirected (priv->surface)) + return; - if (priv->received_x11_damage) - { - meta_error_trap_push (display); - XDamageSubtract (xdisplay, priv->damage, None, None); - meta_error_trap_pop (display); + meta_surface_actor_pre_paint (priv->surface); - /* We need to make sure that any X drawing that happens before the - * XDamageSubtract() above is visible to subsequent GL rendering; - * the only standardized way to do this is EXT_x11_sync_object, - * which isn't yet widely available. For now, we count on details - * of Xorg and the open source drivers, and hope for the best - * otherwise. - * - * Xorg and open source driver specifics: - * - * The X server makes sure to flush drawing to the kernel before - * sending out damage events, but since we use DamageReportBoundingBox - * there may be drawing between the last damage event and the - * XDamageSubtract() that needs to be flushed as well. - * - * Xorg always makes sure that drawing is flushed to the kernel - * before writing events or responses to the client, so any round trip - * request at this point is sufficient to flush the GLX buffers. - */ - XSync (xdisplay, False); - - priv->received_x11_damage = FALSE; - } - - check_needs_x11_pixmap (self); - } + if (!meta_surface_actor_is_visible (priv->surface)) + return; check_needs_reshape (self); check_needs_shadow (self); @@ -2374,20 +2011,16 @@ void meta_window_actor_set_updates_frozen (MetaWindowActor *self, gboolean updates_frozen) { - /* On wayland we shouldn't need to ever freeze updates... */ - if (!meta_is_wayland_compositor ()) + MetaWindowActorPrivate *priv = self->priv; + + updates_frozen = updates_frozen != FALSE; + + if (priv->updates_frozen != updates_frozen) { - MetaWindowActorPrivate *priv = self->priv; - - updates_frozen = updates_frozen != FALSE; - - if (priv->updates_frozen != updates_frozen) - { - priv->updates_frozen = updates_frozen; - if (updates_frozen) - meta_window_actor_freeze (self); - else - meta_window_actor_thaw (self); - } + priv->updates_frozen = updates_frozen; + if (updates_frozen) + meta_window_actor_freeze (self); + else + meta_window_actor_thaw (self); } } diff --git a/src/core/display.c b/src/core/display.c index 907f1a597..d3a03bd77 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -73,6 +73,7 @@ #include #include "meta-xwayland-private.h" +#include "meta-surface-actor-wayland.h" #define GRAB_OP_IS_WINDOW_SWITCH(g) \ (g == META_GRAB_OP_KEYBOARD_TABBING_NORMAL || \ @@ -1682,9 +1683,9 @@ get_window_for_event (MetaDisplay *display, return display->grab_window; source = clutter_event_get_source (event); - if (META_IS_SURFACE_ACTOR (source)) + if (META_IS_SURFACE_ACTOR_WAYLAND (source)) { - MetaWaylandSurface *surface = meta_surface_actor_get_surface (META_SURFACE_ACTOR (source)); + MetaWaylandSurface *surface = meta_surface_actor_wayland_get_surface (META_SURFACE_ACTOR_WAYLAND (source)); g_assert (surface != NULL); return surface->window; } diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c index df8e7814f..d73072925 100644 --- a/src/wayland/meta-wayland-seat.c +++ b/src/wayland/meta-wayland-seat.c @@ -38,6 +38,7 @@ #include "meta-shaped-texture-private.h" #include "meta-wayland-stage.h" #include "meta-cursor-tracker-private.h" +#include "meta-surface-actor-wayland.h" #define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int (10) @@ -420,8 +421,8 @@ meta_wayland_seat_repick (MetaWaylandSeat *seat, else seat->current_stage = NULL; - if (META_IS_SURFACE_ACTOR (actor)) - surface = meta_surface_actor_get_surface (META_SURFACE_ACTOR (actor)); + if (META_IS_SURFACE_ACTOR_WAYLAND (actor)) + surface = meta_surface_actor_wayland_get_surface (META_SURFACE_ACTOR_WAYLAND (actor)); pointer->current = surface; if (surface != pointer->focus_surface) diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 7d9257367..0783316fe 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -44,11 +44,11 @@ #include "meta-wayland-private.h" #include "meta-xwayland-private.h" #include "meta-wayland-stage.h" -#include "meta-surface-actor.h" #include "meta-wayland-seat.h" #include "meta-wayland-keyboard.h" #include "meta-wayland-pointer.h" #include "meta-wayland-data-device.h" + #include "meta-cursor-tracker-private.h" #include "display-private.h" #include "window-private.h" @@ -58,6 +58,9 @@ #include "meta-idle-monitor-private.h" #include "monitor-private.h" +#include "meta-surface-actor.h" +#include "meta-surface-actor-wayland.h" + typedef enum { META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE, @@ -114,8 +117,8 @@ surface_process_damage (MetaWaylandSurface *surface, { cairo_rectangle_int_t rect; cairo_region_get_rectangle (region, i, &rect); - meta_surface_actor_damage_area (surface->surface_actor, - rect.x, rect.y, rect.width, rect.height); + meta_surface_actor_process_damage (surface->surface_actor, + rect.x, rect.y, rect.width, rect.height); } } @@ -295,7 +298,7 @@ actor_surface_commit (MetaWaylandSurface *surface, if (buffer_changed) { ensure_buffer_texture (buffer); - meta_surface_actor_attach_wayland_buffer (surface_actor, buffer); + meta_surface_actor_wayland_set_buffer (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor), buffer); } surface_process_damage (surface, pending->damage); @@ -645,7 +648,7 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor, wl_resource_set_implementation (surface->resource, &meta_wayland_surface_interface, surface, wl_surface_destructor); surface->buffer_destroy_listener.notify = surface_handle_buffer_destroy; - surface->surface_actor = g_object_ref_sink (meta_surface_actor_new (surface)); + surface->surface_actor = g_object_ref_sink (meta_surface_actor_wayland_new (surface)); clutter_actor_set_reactive (CLUTTER_ACTOR (surface->surface_actor), TRUE); double_buffered_state_init (&surface->pending);