diff --git a/doc/reference/meta-sections.txt b/doc/reference/meta-sections.txt index 22d435034..7aa893177 100644 --- a/doc/reference/meta-sections.txt +++ b/doc/reference/meta-sections.txt @@ -96,6 +96,8 @@ meta_compositor_hide_window meta_compositor_switch_workspace meta_compositor_maximize_window meta_compositor_unmaximize_window +meta_compositor_window_mapped +meta_compositor_window_unmapped meta_compositor_sync_window_geometry meta_compositor_set_updates_frozen meta_compositor_queue_frame_drawn diff --git a/src/Makefile.am b/src/Makefile.am index 991c1aea4..b81c6ec51 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -83,10 +83,6 @@ 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/compositor-private.h b/src/compositor/compositor-private.h index 18bcff6f9..2e8d85fd9 100644 --- a/src/compositor/compositor-private.h +++ b/src/compositor/compositor-private.h @@ -46,8 +46,11 @@ struct _MetaCompScreen CoglFrameClosure *frame_closure; /* Used for unredirecting fullscreen windows */ - guint disable_unredirect_count; - MetaWindow *unredirected_window; + guint disable_unredirect_count; + MetaWindowActor *unredirected_window; + + /* Before we create the output window */ + XserverRegion pending_input_region; gint switch_workspace_in_progress; diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 0fb8df9e3..d2598f48b 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -42,6 +42,15 @@ * the call, so it may be necessary to readjust the display based on the * old_rect to start the animation. * + * meta_compositor_window_mapped() and meta_compositor_window_unmapped() are + * notifications when the toplevel window (frame or client window) is mapped or + * unmapped. That is, when the result of meta_window_toplevel_is_mapped() + * changes. The main use of this is to drop resources when a window is unmapped. + * A window will always be mapped before meta_compositor_show_window() + * is called and will not be unmapped until after meta_compositor_hide_window() + * is called. If the live_hidden_windows preference is set, windows will never + * be unmapped. + * * # Containers # * * There's two containers in the stage that are used to place window actors, here @@ -274,6 +283,25 @@ meta_get_window_actors (MetaScreen *screen) return info->windows; } +static void +do_set_stage_input_region (MetaScreen *screen, + XserverRegion region) +{ + MetaCompScreen *info = meta_screen_get_compositor_data (screen); + MetaDisplay *display = meta_screen_get_display (screen); + Display *xdpy = meta_display_get_xdisplay (display); + Window xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)); + + XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region); + + /* It's generally a good heuristic that when a crossing event is generated because + * we reshape the overlay, we don't want it to affect focus-follows-mouse focus - + * it's not the user doing something, it's the environment changing under the user. + */ + meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy)); + XFixesSetWindowShapeRegion (xdpy, info->output, ShapeInput, 0, 0, region); +} + void meta_set_stage_input_region (MetaScreen *screen, XserverRegion region) @@ -285,19 +313,29 @@ meta_set_stage_input_region (MetaScreen *screen, */ if (!meta_is_wayland_compositor ()) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdpy = meta_display_get_xdisplay (display); - Window xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)); + MetaCompScreen *info = meta_screen_get_compositor_data (screen); + MetaDisplay *display = meta_screen_get_display (screen); + Display *xdpy = meta_display_get_xdisplay (display); - XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region); - - /* It's generally a good heuristic that when a crossing event is generated because - * we reshape the overlay, we don't want it to affect focus-follows-mouse focus - - * it's not the user doing something, it's the environment changing under the user. - */ - meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy)); - XFixesSetWindowShapeRegion (xdpy, info->output, ShapeInput, 0, 0, region); + if (info->stage && info->output) + { + do_set_stage_input_region (screen, region); + } + else + { + /* Reset info->pending_input_region if one existed before and set the new + * one to use it later. */ + if (info->pending_input_region) + { + XFixesDestroyRegion (xdpy, info->pending_input_region); + info->pending_input_region = None; + } + if (region != None) + { + info->pending_input_region = XFixesCreateRegion (xdpy, NULL, 0); + XFixesCopyRegion (xdpy, info->pending_input_region, region); + } + } } } @@ -639,6 +677,21 @@ meta_compositor_manage_screen (MetaCompositor *compositor, return; info = g_new0 (MetaCompScreen, 1); + /* + * We use an empty input region for Clutter as a default because that allows + * the user to interact with all the windows displayed on the screen. + * We have to initialize info->pending_input_region to an empty region explicitly, + * because None value is used to mean that the whole screen is an input region. + */ + if (!meta_is_wayland_compositor ()) + info->pending_input_region = XFixesCreateRegion (xdisplay, NULL, 0); + else + { + /* Stage input region trickery isn't needed when we're running as a + * wayland compositor. */ + info->pending_input_region = None; + } + info->screen = screen; meta_screen_set_compositor_data (screen, info); @@ -724,8 +777,6 @@ meta_compositor_manage_screen (MetaCompositor *compositor, info->output = get_output_window (screen); XReparentWindow (xdisplay, xwin, info->output, 0, 0); - meta_empty_stage_input_region (screen); - /* Make sure there isn't any left-over output shape on the * overlay window by setting the whole screen to be an * output region. @@ -736,6 +787,13 @@ meta_compositor_manage_screen (MetaCompositor *compositor, */ XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None); + do_set_stage_input_region (screen, info->pending_input_region); + if (info->pending_input_region != None) + { + XFixesDestroyRegion (xdisplay, info->pending_input_region); + info->pending_input_region = None; + } + /* Map overlay window before redirecting windows offscreen so we catch their * contents until we show the stage. */ @@ -805,30 +863,6 @@ meta_shape_cow_for_window (MetaScreen *screen, } } -static void -set_unredirected_window (MetaCompScreen *info, - MetaWindow *window) -{ - if (info->unredirected_window == window) - return; - - if (info->unredirected_window != NULL) - { - MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (info->unredirected_window)); - meta_window_actor_set_unredirected (window_actor, FALSE); - } - - info->unredirected_window = window; - - if (info->unredirected_window != NULL) - { - MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (info->unredirected_window)); - meta_window_actor_set_unredirected (window_actor, TRUE); - } - - meta_shape_cow_for_window (info->screen, info->unredirected_window); -} - void meta_compositor_add_window (MetaCompositor *compositor, MetaWindow *window) @@ -857,11 +891,19 @@ meta_compositor_remove_window (MetaCompositor *compositor, if (!window_actor) return; - screen = meta_window_get_screen (window); - info = meta_screen_get_compositor_data (screen); + if (!meta_is_wayland_compositor ()) + { + screen = meta_window_get_screen (window); + info = meta_screen_get_compositor_data (screen); - if (info->unredirected_window == window) - set_unredirected_window (info, NULL); + 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)), + NULL); + info->unredirected_window = NULL; + } + } meta_window_actor_destroy (window_actor); } @@ -1360,6 +1402,30 @@ meta_compositor_sync_stack (MetaCompositor *compositor, sync_actor_stacking (info); } +void +meta_compositor_window_mapped (MetaCompositor *compositor, + MetaWindow *window) +{ + MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); + DEBUG_TRACE ("meta_compositor_window_mapped\n"); + if (!window_actor) + return; + + meta_window_actor_mapped (window_actor); +} + +void +meta_compositor_window_unmapped (MetaCompositor *compositor, + MetaWindow *window) +{ + MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); + DEBUG_TRACE ("meta_compositor_window_unmapped\n"); + if (!window_actor) + return; + + meta_window_actor_unmapped (window_actor); +} + void meta_compositor_sync_window_geometry (MetaCompositor *compositor, MetaWindow *window, @@ -1467,6 +1533,7 @@ pre_paint_windows (MetaCompScreen *info) { GList *l; MetaWindowActor *top_window; + MetaWindowActor *expected_unredirected_window = NULL; if (info->onscreen == NULL) { @@ -1480,13 +1547,33 @@ pre_paint_windows (MetaCompScreen *info) if (info->windows == NULL) return; - top_window = g_list_last (info->windows)->data; + if (!meta_is_wayland_compositor ()) + { + top_window = g_list_last (info->windows)->data; - if (meta_window_actor_should_unredirect (top_window) && - info->disable_unredirect_count == 0) - set_unredirected_window (info, meta_window_actor_get_meta_window (top_window)); - else - set_unredirected_window (info, NULL); + 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)), + NULL); + } + + 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_meta_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); diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c deleted file mode 100644 index 95ebc9020..000000000 --- a/src/compositor/meta-surface-actor-wayland.c +++ /dev/null @@ -1,159 +0,0 @@ -/* -*- 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_redraw_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) -{ - /* TODO: look at the SHM buffer pixel 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 void -meta_surface_actor_wayland_freeze (MetaSurfaceActor *actor) -{ -} - -static void -meta_surface_actor_wayland_thaw (MetaSurfaceActor *actor) -{ -} - -static gboolean -meta_surface_actor_wayland_is_frozen (MetaSurfaceActor *actor) -{ - return FALSE; -} - -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 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->freeze = meta_surface_actor_wayland_freeze; - surface_actor_class->thaw = meta_surface_actor_wayland_thaw; - surface_actor_class->is_frozen = meta_surface_actor_wayland_is_frozen; - - surface_actor_class->should_unredirect = meta_surface_actor_wayland_should_unredirect; - surface_actor_class->set_unredirected = meta_surface_actor_wayland_set_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); -} diff --git a/src/compositor/meta-surface-actor-wayland.h b/src/compositor/meta-surface-actor-wayland.h deleted file mode 100644 index 2712f9dbf..000000000 --- a/src/compositor/meta-surface-actor-wayland.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- 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); - -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 deleted file mode 100644 index 8f707d7a8..000000000 --- a/src/compositor/meta-surface-actor-x11.c +++ /dev/null @@ -1,551 +0,0 @@ -/* -*- 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; - - /* Freeze/thaw accounting */ - guint freeze_count; - - /* 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 needs_damage_all : 1; - - guint unredirected : 1; -}; -typedef struct _MetaSurfaceActorX11Private MetaSurfaceActorX11Private; - -static void cullable_iface_init (MetaCullableInterface *iface); - -G_DEFINE_TYPE_WITH_CODE (MetaSurfaceActorX11, meta_surface_actor_x11, META_TYPE_SURFACE_ACTOR, - G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init) - G_ADD_PRIVATE (MetaSurfaceActorX11)) - -static MetaCullableInterface *parent_cullable_iface; - -static void -meta_surface_actor_x11_cull_out (MetaCullable *cullable, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region) -{ - MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (cullable); - MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); - - /* Don't do any culling for the unredirected window */ - if (priv->unredirected) - return; - - parent_cullable_iface->cull_out (cullable, unobscured_region, clip_region); -} - -static void -cullable_iface_init (MetaCullableInterface *iface) -{ - parent_cullable_iface = g_type_interface_peek_parent (iface); - iface->cull_out = meta_surface_actor_x11_cull_out; -} - -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; - - meta_error_trap_push (display); - XFreePixmap (xdisplay, priv->pixmap); - priv->pixmap = None; - meta_error_trap_pop (display); - - meta_shaped_texture_set_texture (stex, NULL); - - 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_frozen (MetaSurfaceActorX11 *self) -{ - MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); - return (priv->freeze_count > 0); -} - -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_redraw_area (META_SURFACE_ACTOR (self), x, y, width, height); -} - -static void -damage_all (MetaSurfaceActorX11 *self) -{ - MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); - - if (!is_visible (self)) - return; - - damage_area (self, 0, 0, cogl_texture_get_width (priv->texture), cogl_texture_get_height (priv->texture)); -} - -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 (!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; - } - - 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; - } - - 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 (is_frozen (self)) - return; - - 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 -meta_surface_actor_x11_freeze (MetaSurfaceActor *actor) -{ - MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); - MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); - - priv->freeze_count ++; -} - -static void -meta_surface_actor_x11_thaw (MetaSurfaceActor *actor) -{ - MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); - MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); - - 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) - { - damage_all (self); - priv->needs_damage_all = FALSE; - } -} - -static gboolean -meta_surface_actor_x11_is_frozen (MetaSurfaceActor *actor) -{ - MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); - return is_frozen (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 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->freeze = meta_surface_actor_x11_freeze; - surface_actor_class->thaw = meta_surface_actor_x11_thaw; - surface_actor_class->is_frozen = meta_surface_actor_x11_is_frozen; - - surface_actor_class->should_unredirect = meta_surface_actor_x11_should_unredirect; - surface_actor_class->set_unredirected = meta_surface_actor_x11_set_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 deleted file mode 100644 index 0e692ee0f..000000000 --- a/src/compositor/meta-surface-actor-x11.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -*- 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 9d21c749d..37b87b03a 100644 --- a/src/compositor/meta-surface-actor.c +++ b/src/compositor/meta-surface-actor.c @@ -10,118 +10,44 @@ */ #include - -#include "meta-surface-actor.h" - #include +#include +#include #include +#include "meta-surface-actor.h" #include "meta-wayland-private.h" #include "meta-cullable.h" + #include "meta-shaped-texture-private.h" struct _MetaSurfaceActorPrivate { MetaShapedTexture *texture; - - /* The region that is visible, used to optimize out redraws */ - cairo_region_t *unobscured_region; + MetaWaylandBuffer *buffer; }; static void cullable_iface_init (MetaCullableInterface *iface); -G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaSurfaceActor, meta_surface_actor, CLUTTER_TYPE_ACTOR, - G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init)); - -static gboolean -meta_surface_actor_get_paint_volume (ClutterActor *actor, - ClutterPaintVolume *volume) -{ - MetaSurfaceActor *self = META_SURFACE_ACTOR (actor); - MetaSurfaceActorPrivate *priv = self->priv; - - if (!CLUTTER_ACTOR_CLASS (meta_surface_actor_parent_class)->get_paint_volume (actor, volume)) - return FALSE; - - if (priv->unobscured_region) - { - ClutterVertex origin; - cairo_rectangle_int_t bounds, unobscured_bounds; - - /* I hate ClutterPaintVolume so much... */ - clutter_paint_volume_get_origin (volume, &origin); - bounds.x = origin.x; - bounds.y = origin.y; - bounds.width = clutter_paint_volume_get_width (volume); - bounds.height = clutter_paint_volume_get_height (volume); - - cairo_region_get_extents (priv->unobscured_region, &unobscured_bounds); - gdk_rectangle_intersect (&bounds, &unobscured_bounds, &bounds); - - origin.x = bounds.x; - origin.y = bounds.y; - clutter_paint_volume_set_origin (volume, &origin); - clutter_paint_volume_set_width (volume, bounds.width); - clutter_paint_volume_set_height (volume, bounds.height); - } - - return TRUE; -} - -static void -meta_surface_actor_dispose (GObject *object) -{ - MetaSurfaceActor *self = META_SURFACE_ACTOR (object); - MetaSurfaceActorPrivate *priv = self->priv; - - g_clear_pointer (&priv->unobscured_region, cairo_region_destroy); - - G_OBJECT_CLASS (meta_surface_actor_parent_class)->dispose (object); -} +G_DEFINE_TYPE_WITH_CODE (MetaSurfaceActor, meta_surface_actor, CLUTTER_TYPE_ACTOR, + G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init)); static void meta_surface_actor_class_init (MetaSurfaceActorClass *klass) { - ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - actor_class->get_paint_volume = meta_surface_actor_get_paint_volume; - object_class->dispose = meta_surface_actor_dispose; - g_type_class_add_private (klass, sizeof (MetaSurfaceActorPrivate)); } -static void -set_unobscured_region (MetaSurfaceActor *self, - cairo_region_t *unobscured_region) -{ - MetaSurfaceActorPrivate *priv = self->priv; - - if (priv->unobscured_region) - cairo_region_destroy (priv->unobscured_region); - - if (unobscured_region) - priv->unobscured_region = cairo_region_copy (unobscured_region); - else - priv->unobscured_region = NULL; -} - static void meta_surface_actor_cull_out (MetaCullable *cullable, cairo_region_t *unobscured_region, cairo_region_t *clip_region) { - MetaSurfaceActor *self = META_SURFACE_ACTOR (cullable); - - set_unobscured_region (self, unobscured_region); meta_cullable_cull_out_children (cullable, unobscured_region, clip_region); } static void meta_surface_actor_reset_culling (MetaCullable *cullable) { - MetaSurfaceActor *self = META_SURFACE_ACTOR (cullable); - - set_unobscured_region (self, NULL); meta_cullable_reset_culling_children (cullable); } @@ -158,34 +84,80 @@ meta_surface_actor_get_texture (MetaSurfaceActor *self) return self->priv->texture; } -static cairo_region_t * -effective_unobscured_region (MetaSurfaceActor *self) +static void +update_area (MetaSurfaceActor *self, + int x, int y, int width, int height) { MetaSurfaceActorPrivate *priv = self->priv; - return clutter_actor_has_mapped_clones (CLUTTER_ACTOR (self)) ? NULL : priv->unobscured_region; + 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_redraw_area (MetaSurfaceActor *self, - int x, int y, int width, int height) +meta_surface_actor_damage_all (MetaSurfaceActor *self, + cairo_region_t *unobscured_region) +{ + 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), + unobscured_region); +} + +gboolean +meta_surface_actor_damage_area (MetaSurfaceActor *self, + int x, + int y, + int width, + int height, + cairo_region_t *unobscured_region) { MetaSurfaceActorPrivate *priv = self->priv; + update_area (self, x, y, width, height); return meta_shaped_texture_update_area (priv->texture, x, y, width, height, - effective_unobscured_region (self)); + unobscured_region); } -gboolean -meta_surface_actor_is_obscured (MetaSurfaceActor *self) +void +meta_surface_actor_attach_wayland_buffer (MetaSurfaceActor *self, + MetaWaylandBuffer *buffer) { MetaSurfaceActorPrivate *priv = self->priv; + priv->buffer = buffer; - if (priv->unobscured_region) - return cairo_region_is_empty (priv->unobscured_region); + if (buffer) + meta_shaped_texture_set_texture (priv->texture, buffer->texture); else - return FALSE; + 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 @@ -204,58 +176,8 @@ meta_surface_actor_set_opaque_region (MetaSurfaceActor *self, meta_shaped_texture_set_opaque_region (priv->texture, region); } -void -meta_surface_actor_process_damage (MetaSurfaceActor *actor, - int x, int y, int width, int height) +MetaSurfaceActor * +meta_surface_actor_new (void) { - META_SURFACE_ACTOR_GET_CLASS (actor)->process_damage (actor, x, y, width, height); -} - -void -meta_surface_actor_pre_paint (MetaSurfaceActor *actor) -{ - META_SURFACE_ACTOR_GET_CLASS (actor)->pre_paint (actor); -} - -gboolean -meta_surface_actor_is_argb32 (MetaSurfaceActor *actor) -{ - return META_SURFACE_ACTOR_GET_CLASS (actor)->is_argb32 (actor); -} - -gboolean -meta_surface_actor_is_visible (MetaSurfaceActor *actor) -{ - return META_SURFACE_ACTOR_GET_CLASS (actor)->is_visible (actor); -} - -void -meta_surface_actor_freeze (MetaSurfaceActor *actor) -{ - META_SURFACE_ACTOR_GET_CLASS (actor)->freeze (actor); -} - -void -meta_surface_actor_thaw (MetaSurfaceActor *actor) -{ - META_SURFACE_ACTOR_GET_CLASS (actor)->thaw (actor); -} - -gboolean -meta_surface_actor_is_frozen (MetaSurfaceActor *actor) -{ - return META_SURFACE_ACTOR_GET_CLASS (actor)->is_frozen (actor); -} - -gboolean -meta_surface_actor_should_unredirect (MetaSurfaceActor *actor) -{ - return META_SURFACE_ACTOR_GET_CLASS (actor)->should_unredirect (actor); -} - -void -meta_surface_actor_set_unredirected (MetaSurfaceActor *actor, - gboolean unredirected) -{ - META_SURFACE_ACTOR_GET_CLASS (actor)->set_unredirected (actor, unredirected); + return g_object_new (META_TYPE_SURFACE_ACTOR, NULL); } diff --git a/src/compositor/meta-surface-actor.h b/src/compositor/meta-surface-actor.h index f9d458c53..484877b73 100644 --- a/src/compositor/meta-surface-actor.h +++ b/src/compositor/meta-surface-actor.h @@ -6,6 +6,7 @@ #include #include +#include "meta-wayland-types.h" G_BEGIN_DECLS @@ -24,20 +25,6 @@ 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); - - void (* freeze) (MetaSurfaceActor *actor); - void (* thaw) (MetaSurfaceActor *actor); - gboolean (* is_frozen) (MetaSurfaceActor *actor); - - gboolean (* should_unredirect) (MetaSurfaceActor *actor); - void (* set_unredirected) (MetaSurfaceActor *actor, - gboolean unredirected); }; struct _MetaSurfaceActor @@ -49,35 +36,32 @@ struct _MetaSurfaceActor GType meta_surface_actor_get_type (void); +MetaSurfaceActor *meta_surface_actor_new (void); + 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_is_obscured (MetaSurfaceActor *self); +gboolean meta_surface_actor_damage_all (MetaSurfaceActor *self, + cairo_region_t *unobscured_region); +gboolean meta_surface_actor_damage_area (MetaSurfaceActor *self, + int x, + int y, + int width, + int height, + cairo_region_t *unobscured_region); + +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); -gboolean meta_surface_actor_redraw_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); - G_END_DECLS #endif /* META_SURFACE_ACTOR_PRIVATE_H */ diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h index 9c6a8476e..82326d29b 100644 --- a/src/compositor/meta-window-actor-private.h +++ b/src/compositor/meta-window-actor-private.h @@ -39,13 +39,13 @@ void meta_window_actor_frame_complete (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_should_unredirect (MetaWindowActor *self); -void meta_window_actor_set_unredirected (MetaWindowActor *self, - gboolean unredirected); - gboolean meta_window_actor_effect_in_progress (MetaWindowActor *self); void meta_window_actor_sync_actor_geometry (MetaWindowActor *self, gboolean did_placement); @@ -59,6 +59,9 @@ void meta_window_actor_set_updates_frozen (MetaWindowActor *self, void meta_window_actor_queue_frame_drawn (MetaWindowActor *self, gboolean no_delay_frame); +void meta_window_actor_set_unobscured_region (MetaWindowActor *self, + cairo_region_t *unobscured_region); + void meta_window_actor_effect_completed (MetaWindowActor *actor, gulong event); diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index 4745d96ac..e7a922025 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -10,6 +10,10 @@ #include +#include +#include +#include + #include #include #include /* for gdk_rectangle_union() */ @@ -26,14 +30,21 @@ #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" +enum { + POSITION_CHANGED, + SIZE_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = {0}; + struct _MetaWindowActorPrivate { @@ -61,13 +72,22 @@ struct _MetaWindowActorPrivate /* The region we should clip to when painting the shadow */ cairo_region_t *shadow_clip; - /* Extracted size-invariant shape used for shadows */ - MetaWindowShape *shadow_shape; - char * shadow_class; + /* The region that is visible, used to optimize out redraws */ + cairo_region_t *unobscured_region; 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; + /* * These need to be counters rather than flags, since more plugins * can implement same effect; the practicality of stacking effects @@ -82,7 +102,12 @@ 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 mapped : 1; + guint argb32 : 1; guint disposed : 1; guint redecorating : 1; @@ -99,7 +124,24 @@ 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 needs_pixmap : 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; @@ -136,6 +178,7 @@ 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); @@ -206,6 +249,19 @@ meta_window_actor_class_init (MetaWindowActorClass *klass) g_object_class_install_property (object_class, PROP_SHADOW_CLASS, pspec); + + signals[POSITION_CHANGED] = + g_signal_new ("position-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); + signals[SIZE_CHANGED] = + g_signal_new ("size-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); } static void @@ -226,6 +282,9 @@ 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 @@ -233,6 +292,23 @@ 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. */ @@ -255,13 +331,8 @@ surface_allocation_changed_notify (ClutterActor *actor, { meta_window_actor_sync_actor_geometry (self, FALSE); meta_window_actor_update_shape (self); -} -static gboolean -is_argb32 (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = self->priv; - return meta_surface_actor_is_argb32 (priv->surface); + g_signal_emit (self, signals[SIZE_CHANGED], 0); } static gboolean @@ -270,84 +341,7 @@ is_non_opaque (MetaWindowActor *self) MetaWindowActorPrivate *priv = self->priv; MetaWindow *window = priv->window; - 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 (meta_surface_actor_is_frozen (priv->surface)) - 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 -set_surface_actor (MetaWindowActor *self, - MetaSurfaceActor *surface) -{ - MetaWindowActorPrivate *priv = self->priv; - - if (priv->surface) - { - g_object_unref (priv->surface); - clutter_actor_remove_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface)); - } - - priv->surface = surface; - - if (priv->surface) - { - g_object_ref_sink (priv->surface); - clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface)); - - g_signal_connect_object (priv->surface, "allocation-changed", - G_CALLBACK (surface_allocation_changed_notify), self, 0); - } - - meta_window_actor_update_shape (self); -} - -static void -meta_window_actor_sync_surface_actor (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = self->priv; - MetaWindow *window = priv->window; - - MetaSurfaceActor *surface = NULL; - - if (window) - { - if (window->surface) - surface = window->surface->surface_actor; - else if (!meta_is_wayland_compositor ()) - surface = meta_surface_actor_x11_new (window); - } - - set_surface_actor (self, surface); + return priv->argb32 || (window->opacity != 0xFF); } static void @@ -356,10 +350,47 @@ 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 = window->screen; + 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; + } + + if (!priv->surface) + { + if (window->surface) + priv->surface = window->surface->surface_actor; + else + priv->surface = meta_surface_actor_new (); + g_object_ref_sink (priv->surface); + + clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface)); + + g_signal_connect_object (priv->surface, "allocation-changed", + G_CALLBACK (surface_allocation_changed_notify), self, 0); + meta_window_actor_update_shape (self); + } - meta_window_actor_sync_surface_actor (self); meta_window_actor_update_opacity (self); /* Start off with an empty shape region to maintain the invariant @@ -373,6 +404,8 @@ 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) @@ -383,12 +416,16 @@ 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); priv->send_frame_messages_timer = 0; } + g_clear_pointer (&priv->unobscured_region, cairo_region_destroy); g_clear_pointer (&priv->shape_region, cairo_region_destroy); g_clear_pointer (&priv->shadow_clip, cairo_region_destroy); @@ -397,11 +434,26 @@ 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); - meta_window_actor_sync_surface_actor (self); + /* + * Release the extra reference we took on the actor. + */ + g_clear_object (&priv->surface); G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object); } @@ -669,15 +721,12 @@ meta_window_actor_get_paint_volume (ClutterActor *actor, gdk_rectangle_union (&bounds, &shadow_bounds, &bounds); } - { - const ClutterPaintVolume *child_volume; - - child_volume = clutter_actor_get_transformed_paint_volume (CLUTTER_ACTOR (priv->surface), actor); - if (!child_volume) - return FALSE; - - clutter_paint_volume_union (volume, child_volume); - } + if (priv->unobscured_region) + { + cairo_rectangle_int_t unobscured_bounds; + cairo_region_get_extents (priv->unobscured_region, &unobscured_bounds); + gdk_rectangle_intersect (&bounds, &unobscured_bounds, &bounds); + } origin.x = bounds.x; origin.y = bounds.y; @@ -811,6 +860,66 @@ meta_window_actor_is_destroyed (MetaWindowActor *self) return self->priv->disposed; } +gboolean +meta_window_actor_is_override_redirect (MetaWindowActor *self) +{ + return meta_window_is_override_redirect (self->priv->window); +} + +/** + * meta_window_actor_get_workspace: + * @self: #MetaWindowActor + * + * Returns the index of workspace on which this window is located; if the + * window is sticky, or is not currently located on any workspace, returns -1. + * This function is deprecated and should not be used in newly written code; + * meta_window_get_workspace() instead. + * + * Return value: (transfer none): index of workspace on which this window is + * located. + */ +gint +meta_window_actor_get_workspace (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv; + MetaWorkspace *workspace; + + if (!self) + return -1; + + priv = self->priv; + + if (!priv->window || meta_window_is_on_all_workspaces (priv->window)) + return -1; + + workspace = meta_window_get_workspace (priv->window); + + if (!workspace) + return -1; + + return meta_workspace_index (workspace); +} + +gboolean +meta_window_actor_showing_on_its_workspace (MetaWindowActor *self) +{ + if (!self) + return FALSE; + + /* If override redirect: */ + if (!self->priv->window) + return TRUE; + + return meta_window_showing_on_its_workspace (self->priv->window); +} + +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) { @@ -865,6 +974,61 @@ 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; + cairo_region_t *unobscured_region; + gboolean redraw_queued; + + if (!priv->needs_damage_all) + return; + + if (!priv->mapped || priv->needs_pixmap) + return; + + unobscured_region = + clutter_actor_has_mapped_clones (CLUTTER_ACTOR (priv->surface)) + ? NULL : priv->unobscured_region; + + redraw_queued = meta_surface_actor_damage_all (priv->surface, unobscured_region); + + 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) @@ -886,7 +1050,17 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self, if (!priv->repaint_scheduled) { - gboolean is_obscured = meta_surface_actor_is_obscured (priv->surface); + gboolean is_obscured = FALSE; + + /* Find out whether the window is completly obscured */ + if (priv->unobscured_region) + { + cairo_region_t *unobscured_window_region; + unobscured_window_region = cairo_region_copy (priv->shape_region); + cairo_region_intersect (unobscured_window_region, priv->unobscured_region); + is_obscured = cairo_region_is_empty (unobscured_window_region); + cairo_region_destroy (unobscured_window_region); + } /* A frame was marked by the client without actually doing any * damage or any unobscured, or while we had the window frozen @@ -900,7 +1074,7 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self, { queue_send_frame_messages_timeout (self); } - else + else if (priv->mapped && (!meta_is_wayland_compositor () || !priv->needs_pixmap)) { const cairo_rectangle_int_t clip = { 0, 0, 1, 1 }; clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (priv->surface), &clip); @@ -919,6 +1093,36 @@ 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 void +meta_window_actor_queue_create_x11_pixmap (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv = self->priv; + + priv->needs_pixmap = TRUE; + + if (!priv->mapped) + return; + + if (is_frozen (self)) + return; + + /* This will cause the compositor paint function to be run + * if the actor is visible or a clone of the actor is visible. + * if the actor isn't visible in any way, then we don't + * need to repair the window anyways, and can wait until + * the stage is redrawn for some other reason + * + * The compositor paint function repairs all windows. + */ + clutter_actor_queue_redraw (CLUTTER_ACTOR (priv->surface)); +} + static gboolean is_freeze_thaw_effect (gulong event) { @@ -999,6 +1203,15 @@ 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 (!meta_window_is_mapped (priv->window)) + meta_window_actor_detach_x11_pixmap (self); + + if (priv->needs_pixmap) + clutter_actor_queue_redraw (CLUTTER_ACTOR (priv->surface)); + } } void @@ -1073,19 +1286,95 @@ 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; + + meta_window_actor_queue_create_x11_pixmap (self); +} + gboolean meta_window_actor_should_unredirect (MetaWindowActor *self) { + MetaWindow *metaWindow = meta_window_actor_get_meta_window (self); MetaWindowActorPrivate *priv = self->priv; - return meta_surface_actor_should_unredirect (priv->surface); + + 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; } void -meta_window_actor_set_unredirected (MetaWindowActor *self, - gboolean unredirected) +meta_window_actor_set_redirected (MetaWindowActor *self, gboolean state) { - MetaWindowActorPrivate *priv = self->priv; - meta_surface_actor_set_unredirected (priv->surface, 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); + + if (state) + { + meta_error_trap_push (display); + XCompositeRedirectWindow (xdisplay, xwin, CompositeRedirectManual); + meta_error_trap_pop (display); + meta_window_actor_detach_x11_pixmap (self); + self->priv->unredirected = FALSE; + } + else + { + meta_error_trap_push (display); + XCompositeUnredirectWindow (xdisplay, xwin, CompositeRedirectManual); + meta_error_trap_pop (display); + self->priv->unredirected = TRUE; + } } void @@ -1139,11 +1428,19 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self, meta_window_get_input_rect (priv->window, &window_rect); - /* 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); + /* 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; + } + } /* Normally we want freezing a window to also freeze its position; this allows * windows to atomically move and resize together, either under app control, @@ -1155,6 +1452,15 @@ 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_queue_create_x11_pixmap (self); + meta_window_actor_update_shape (self); + } + } + if (meta_window_actor_effect_in_progress (self)) return; @@ -1162,6 +1468,8 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self, window_rect.x, window_rect.y); clutter_actor_set_size (CLUTTER_ACTOR (self), window_rect.width, window_rect.height); + + g_signal_emit (self, signals[POSITION_CHANGED], 0); } void @@ -1321,11 +1629,19 @@ meta_window_actor_new (MetaWindow *window) NULL); priv = self->priv; + priv->mapped = meta_window_toplevel_is_mapped (priv->window); - meta_window_actor_set_updates_frozen (self, meta_window_updates_are_frozen (priv->window)); - - if (META_IS_SURFACE_ACTOR_X11 (priv->surface)) + if (!meta_is_wayland_compositor ()) { + priv->last_width = -1; + priv->last_height = -1; + + if (priv->mapped) + meta_window_actor_queue_create_x11_pixmap (self); + + 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. */ @@ -1357,6 +1673,38 @@ meta_window_actor_new (MetaWindow *window) return self; } +void +meta_window_actor_mapped (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv = self->priv; + + g_return_if_fail (!priv->mapped); + + priv->mapped = TRUE; + + if (!meta_is_wayland_compositor ()) + meta_window_actor_queue_create_x11_pixmap (self); +} + +void +meta_window_actor_unmapped (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv = self->priv; + + g_return_if_fail (priv->mapped); + + priv->mapped = FALSE; + + if (meta_window_actor_effect_in_progress (self)) + return; + + if (!meta_is_wayland_compositor ()) + { + meta_window_actor_detach_x11_pixmap (self); + priv->needs_pixmap = FALSE; + } +} + #if 0 /* Print out a region; useful for debugging */ static void @@ -1398,6 +1746,30 @@ see_region (cairo_region_t *region, } #endif +/** + * meta_window_actor_set_unobscured_region: + * @self: a #MetaWindowActor + * @unobscured_region: the region of the screen that isn't completely + * obscured. + * + * Provides a hint as to what areas of the window need to queue + * redraws when damaged. Regions not in @unobscured_region are completely obscured. + */ +void +meta_window_actor_set_unobscured_region (MetaWindowActor *self, + cairo_region_t *unobscured_region) +{ + MetaWindowActorPrivate *priv = self->priv; + + if (priv->unobscured_region) + cairo_region_destroy (priv->unobscured_region); + + if (unobscured_region) + priv->unobscured_region = cairo_region_copy (unobscured_region); + else + priv->unobscured_region = NULL; +} + /** * meta_window_actor_set_clip_region_beneath: * @self: a #MetaWindowActor @@ -1437,6 +1809,16 @@ meta_window_actor_cull_out (MetaCullable *cullable, { MetaWindowActor *self = META_WINDOW_ACTOR (cullable); + if (!meta_is_wayland_compositor ()) + { + MetaCompScreen *info = meta_screen_get_compositor_data (self->priv->screen); + + /* Don't do any culling for the unredirected window */ + if (self == info->unredirected_window) + return; + } + + meta_window_actor_set_unobscured_region (self, unobscured_region); meta_cullable_cull_out_children (cullable, unobscured_region, clip_region); meta_window_actor_set_clip_region_beneath (self, clip_region); } @@ -1459,6 +1841,88 @@ 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; + MetaScreen *screen = priv->screen; + MetaDisplay *display = meta_screen_get_display (screen); + Display *xdisplay = meta_display_get_xdisplay (display); + MetaCompScreen *info = meta_screen_get_compositor_data (screen); + Window xwindow = meta_window_get_toplevel_xwindow (priv->window); + + if (!priv->needs_pixmap) + return; + + if (!priv->mapped) + return; + + if (xwindow == meta_screen_get_xroot (screen) || + xwindow == clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage))) + return; + + 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); + + /* ::size-changed is supposed to refer to meta_window_get_frame_rect(). + * Emitting it here works pretty much OK because a new value of the + * *input* rect (which is the outer rect with the addition of invisible + * borders) forces a new pixmap and we get here. In the rare case where + * a change to the window size was exactly balanced by a change to the + * invisible borders, we would miss emitting the signal. We would also + * emit spurious signals when we get a new pixmap without a new size, + * but that should be mostly harmless. + */ + g_signal_emit (self, signals[SIZE_CHANGED], 0); + } + + priv->needs_pixmap = FALSE; + + out: + meta_error_trap_pop (display); +} + static void check_needs_shadow (MetaWindowActor *self) { @@ -1469,6 +1933,9 @@ check_needs_shadow (MetaWindowActor *self) gboolean should_have_shadow; gboolean appears_focused; + if (!priv->mapped) + return; + /* Calling meta_window_actor_has_shadow() here at every pre-paint is cheap * and avoids the need to explicitly handle window type changes, which * we would do if tried to keep track of when we might be adding or removing @@ -1526,14 +1993,68 @@ 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; + cairo_region_t *unobscured_region; - g_assert (!meta_is_wayland_compositor ()); + 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->mapped || priv->needs_pixmap) + return; + + unobscured_region = + clutter_actor_has_mapped_clones (CLUTTER_ACTOR (priv->surface)) + ? NULL : priv->unobscured_region; + redraw_queued = meta_surface_actor_damage_area (priv->surface, + event->area.x, + event->area.y, + event->area.width, + event->area.height, + unobscured_region); + + 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 @@ -1761,9 +2282,8 @@ meta_window_actor_update_opaque_region (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; cairo_region_t *opaque_region; - gboolean argb32 = is_argb32 (self); - if (argb32 && priv->window->opaque_region != NULL) + if (priv->argb32 && priv->window->opaque_region != NULL) { MetaFrameBorders borders; @@ -1783,7 +2303,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 (argb32) + else if (priv->argb32) opaque_region = NULL; else opaque_region = cairo_region_reference (priv->shape_region); @@ -1799,6 +2319,9 @@ check_needs_reshape (MetaWindowActor *self) MetaFrameBorders borders; cairo_rectangle_int_t client_area; + if (!priv->mapped) + return; + if (!priv->needs_reshape) return; @@ -1840,6 +2363,9 @@ 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)) { @@ -1848,10 +2374,45 @@ meta_window_actor_handle_updates (MetaWindowActor *self) return; } - meta_surface_actor_pre_paint (priv->surface); + 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_visible (priv->surface)) - return; + if (priv->received_x11_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_x11_damage = FALSE; + } + + check_needs_x11_pixmap (self); + } check_needs_reshape (self); check_needs_shadow (self); @@ -2040,16 +2601,20 @@ void meta_window_actor_set_updates_frozen (MetaWindowActor *self, gboolean updates_frozen) { - MetaWindowActorPrivate *priv = self->priv; - - updates_frozen = updates_frozen != FALSE; - - if (priv->updates_frozen != updates_frozen) + /* On wayland we shouldn't need to ever freeze updates... */ + if (!meta_is_wayland_compositor ()) { - priv->updates_frozen = updates_frozen; - if (updates_frozen) - meta_window_actor_freeze (self); - else - meta_window_actor_thaw (self); + 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); + } } } diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c index 542060531..9554571b0 100644 --- a/src/compositor/meta-window-group.c +++ b/src/compositor/meta-window-group.c @@ -115,6 +115,8 @@ meta_window_group_paint (ClutterActor *actor) { cairo_region_t *clip_region; cairo_region_t *unobscured_region; + ClutterActorIter iter; + ClutterActor *child; cairo_rectangle_int_t visible_rect, clip_rect; int paint_x_offset, paint_y_offset; int paint_x_origin, paint_y_origin; @@ -123,6 +125,18 @@ meta_window_group_paint (ClutterActor *actor) MetaWindowGroup *window_group = META_WINDOW_GROUP (actor); ClutterActor *stage = clutter_actor_get_stage (actor); + /* Start off by treating all windows as completely unobscured, so damage anywhere + * in a window queues redraws, but confine it more below. */ + clutter_actor_iter_init (&iter, actor); + while (clutter_actor_iter_next (&iter, &child)) + { + if (META_IS_WINDOW_ACTOR (child)) + { + MetaWindowActor *window_actor = META_WINDOW_ACTOR (child); + meta_window_actor_set_unobscured_region (window_actor, NULL); + } + } + /* Normally we expect an actor to be drawn at it's position on the screen. * However, if we're inside the paint of a ClutterClone, that won't be the * case and we need to compensate. We look at the position of the window @@ -170,8 +184,9 @@ meta_window_group_paint (ClutterActor *actor) if (info->unredirected_window != NULL) { cairo_rectangle_int_t unredirected_rect; + MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window); - meta_window_get_frame_rect (info->unredirected_window, (MetaRectangle *)&unredirected_rect); + meta_window_get_frame_rect (window, (MetaRectangle *)&unredirected_rect); cairo_region_subtract_rectangle (unobscured_region, &unredirected_rect); cairo_region_subtract_rectangle (clip_region, &unredirected_rect); } diff --git a/src/compositor/plugins/default.c b/src/compositor/plugins/default.c index 892854b33..91b30c039 100644 --- a/src/compositor/plugins/default.c +++ b/src/compositor/plugins/default.c @@ -409,7 +409,7 @@ switch_workspace (MetaPlugin *plugin, ClutterActor *actor = CLUTTER_ACTOR (window_actor); gint win_workspace; - win_workspace = meta_window_get_workspace (meta_window_actor_get_meta_window (window_actor)); + win_workspace = meta_window_actor_get_workspace (window_actor); if (win_workspace == to || win_workspace == from) { diff --git a/src/core/display.c b/src/core/display.c index a11836c57..8a98cf5ab 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -2777,7 +2777,7 @@ handle_other_xevent (MetaDisplay *display, if (display->grab_op != META_GRAB_OP_NONE && display->grab_window == window && - window->frame == NULL) + ((window->frame == NULL) || !window->frame->mapped)) meta_display_end_grab_op (display, timestamp); if (!frame_was_receiver) diff --git a/src/core/frame.c b/src/core/frame.c index e54e86210..5fa7bee17 100644 --- a/src/core/frame.c +++ b/src/core/frame.c @@ -62,6 +62,7 @@ meta_window_ensure_frame (MetaWindow *window) frame->right_width = 0; frame->current_cursor = 0; + frame->mapped = FALSE; frame->is_flashing = FALSE; frame->borders_cached = FALSE; @@ -156,8 +157,6 @@ meta_window_ensure_frame (MetaWindow *window) /* Move keybindings to frame instead of window */ meta_window_grab_keys (window); - - meta_ui_map_frame (frame->window->screen->ui, frame->xwindow); } void diff --git a/src/core/frame.h b/src/core/frame.h index 8ac1c261e..0f1ebea4f 100644 --- a/src/core/frame.h +++ b/src/core/frame.h @@ -47,6 +47,7 @@ struct _MetaFrame int right_width; int bottom_height; + guint mapped : 1; guint need_reapply_frame_shape : 1; guint is_flashing : 1; /* used by the visual bell flash */ guint borders_cached : 1; diff --git a/src/core/window.c b/src/core/window.c index 13d8e2a92..b4a845d6a 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -215,8 +215,6 @@ enum FOCUS, RAISED, UNMANAGED, - SIZE_CHANGED, - POSITION_CHANGED, LAST_SIGNAL }; @@ -613,22 +611,6 @@ meta_window_class_init (MetaWindowClass *klass) G_STRUCT_OFFSET (MetaWindowClass, unmanaged), NULL, NULL, NULL, G_TYPE_NONE, 0); - - window_signals[POSITION_CHANGED] = - g_signal_new ("position-changed", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); - - window_signals[SIZE_CHANGED] = - g_signal_new ("size-changed", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); } static void @@ -810,35 +792,6 @@ meta_window_should_attach_to_parent (MetaWindow *window) } } -static gboolean -client_window_should_be_mapped (MetaWindow *window) -{ - return !window->shaded; -} - -static void -sync_client_window_mapped (MetaWindow *window) -{ - gboolean should_be_mapped = client_window_should_be_mapped (window); - - if (window->mapped == should_be_mapped) - return; - - window->mapped = should_be_mapped; - - meta_error_trap_push (window->display); - if (should_be_mapped) - { - XMapWindow (window->display->xdisplay, window->xwindow); - } - else - { - XUnmapWindow (window->display->xdisplay, window->xwindow); - window->unmaps_pending ++; - } - meta_error_trap_pop (window->display); -} - static MetaWindow* meta_window_new_shared (MetaDisplay *display, MetaScreen *screen, @@ -1334,6 +1287,9 @@ meta_window_new_shared (MetaDisplay *display, set_net_wm_state (window); } + if (screen->display->compositor) + meta_compositor_add_window (screen->display->compositor, window); + /* Sync stack changes */ meta_stack_thaw (window->screen->stack); @@ -1347,8 +1303,6 @@ meta_window_new_shared (MetaDisplay *display, /* disable show desktop mode unless we're a desktop component */ maybe_leave_show_desktop_mode (window); - sync_client_window_mapped (window); - meta_window_queue (window, META_QUEUE_CALC_SHOWING); /* See bug 303284; a transient of the given window can already exist, in which * case we think it should probably be shown. @@ -1613,8 +1567,7 @@ meta_window_new (MetaDisplay *display, META_WINDOW_CLIENT_TYPE_X11, NULL, xwindow, - /* XXX */ - !meta_is_wayland_compositor (), + TRUE, existing_wm_state, effect, &attrs); @@ -1807,13 +1760,10 @@ meta_window_unmanage (MetaWindow *window, if (window->display->compositor) { if (window->visible_to_compositor) - { - meta_compositor_hide_window (window->display->compositor, window, - META_COMP_EFFECT_DESTROY); + meta_compositor_hide_window (window->display->compositor, window, + META_COMP_EFFECT_DESTROY); - /* XXX - support destroy effects better */ - meta_compositor_remove_window (window->display->compositor, window); - } + meta_compositor_remove_window (window->display->compositor, window); } if (window->display->window_with_menu == window) @@ -2396,8 +2346,6 @@ implement_showing (MetaWindow *window, meta_verbose ("Implement showing = %d for window %s\n", showing, window->desc); - sync_client_window_mapped (window); - if (!showing) { /* When we manage a new window, we normally delay placing it @@ -2986,6 +2934,94 @@ window_would_be_covered (const MetaWindow *newbie) return FALSE; /* none found */ } +static gboolean +map_frame (MetaWindow *window) +{ + if (window->frame && !window->frame->mapped) + { + meta_topic (META_DEBUG_WINDOW_STATE, + "Frame actually needs map\n"); + window->frame->mapped = TRUE; + meta_ui_map_frame (window->screen->ui, window->frame->xwindow); + return TRUE; + } + else + return FALSE; +} + +static gboolean +map_client_window (MetaWindow *window) +{ + if (!window->mapped) + { + meta_topic (META_DEBUG_WINDOW_STATE, + "%s actually needs map\n", window->desc); + window->mapped = TRUE; + meta_error_trap_push (window->display); + XMapWindow (window->display->xdisplay, window->xwindow); + meta_error_trap_pop (window->display); + + return TRUE; + } + else + return FALSE; +} + +static gboolean +unmap_client_window (MetaWindow *window, + const char *reason) +{ + if (window->mapped) + { + meta_topic (META_DEBUG_WINDOW_STATE, + "%s actually needs unmap%s\n", + window->desc, reason); + meta_topic (META_DEBUG_WINDOW_STATE, + "Incrementing unmaps_pending on %s%s\n", + window->desc, reason); + window->mapped = FALSE; + window->unmaps_pending += 1; + meta_error_trap_push (window->display); + XUnmapWindow (window->display->xdisplay, window->xwindow); + meta_error_trap_pop (window->display); + + return TRUE; + } + else + return FALSE; +} + +/** + * meta_window_is_mapped: + * @window: a #MetaWindow + * + * Determines whether the X window for the MetaWindow is mapped. + */ +gboolean +meta_window_is_mapped (MetaWindow *window) +{ + return window->mapped; +} + +/** + * meta_window_toplevel_is_mapped: + * @window: a #MetaWindow + * + * Determines whether the toplevel X window for the MetaWindow is + * mapped. (The frame window is mapped even without the client window + * when a window is shaded.) + * + * Return Value: %TRUE if the toplevel is mapped. + */ +gboolean +meta_window_toplevel_is_mapped (MetaWindow *window) +{ + /* The frame is mapped but not the client window when the window + * is shaded. + */ + return window->mapped || (window->frame && window->frame->mapped); +} + static void meta_window_force_placement (MetaWindow *window) { @@ -3024,12 +3060,16 @@ meta_window_show (MetaWindow *window) gboolean place_on_top_on_map; gboolean needs_stacking_adjustment; MetaWindow *focus_window; + gboolean toplevel_was_mapped; + gboolean toplevel_now_mapped; gboolean notify_demands_attention = FALSE; meta_topic (META_DEBUG_WINDOW_STATE, "Showing window %s, shaded: %d iconic: %d placed: %d\n", window->desc, window->shaded, window->iconic, window->placed); + toplevel_was_mapped = meta_window_toplevel_is_mapped (window); + focus_window = window->display->focus_window; /* May be NULL! */ did_show = FALSE; window_state_on_map (window, &takes_focus_on_map, &place_on_top_on_map); @@ -3156,18 +3196,46 @@ meta_window_show (MetaWindow *window) } } - if (window->hidden) + /* Shaded means the frame is mapped but the window is not */ + + if (map_frame (window)) + did_show = TRUE; + + if (window->shaded) { - meta_stack_freeze (window->screen->stack); - window->hidden = FALSE; - meta_stack_thaw (window->screen->stack); - did_show = TRUE; + unmap_client_window (window, " (shading)"); + + if (!window->iconic) + { + window->iconic = TRUE; + set_wm_state (window, IconicState); + } + } + else + { + if (map_client_window (window)) + did_show = TRUE; + + if (window->hidden) + { + meta_stack_freeze (window->screen->stack); + window->hidden = FALSE; + meta_stack_thaw (window->screen->stack); + did_show = TRUE; + } + + if (window->iconic) + { + window->iconic = FALSE; + set_wm_state (window, NormalState); + } } - if (window->iconic) + toplevel_now_mapped = meta_window_toplevel_is_mapped (window); + if (toplevel_now_mapped != toplevel_was_mapped) { - window->iconic = FALSE; - set_wm_state (window, NormalState); + if (window->display->compositor) + meta_compositor_window_mapped (window->display->compositor, window); } if (!window->visible_to_compositor) @@ -3190,8 +3258,8 @@ meta_window_show (MetaWindow *window) break; } - meta_compositor_add_window (window->display->compositor, window); - meta_compositor_show_window (window->display->compositor, window, effect); + meta_compositor_show_window (window->display->compositor, + window, effect); } } @@ -3259,10 +3327,14 @@ static void meta_window_hide (MetaWindow *window) { gboolean did_hide; + gboolean toplevel_was_mapped; + gboolean toplevel_now_mapped; meta_topic (META_DEBUG_WINDOW_STATE, "Hiding window %s\n", window->desc); + toplevel_was_mapped = meta_window_toplevel_is_mapped (window); + if (window->visible_to_compositor) { window->visible_to_compositor = FALSE; @@ -3283,12 +3355,19 @@ meta_window_hide (MetaWindow *window) break; } - meta_compositor_hide_window (window->display->compositor, window, effect); + meta_compositor_hide_window (window->display->compositor, + window, effect); } } did_hide = FALSE; + /* If this is the first time that we've calculating the showing + * state of the window, the frame and client window might not + * yet be mapped, so we need to map them now */ + map_frame (window); + map_client_window (window); + if (!window->hidden) { meta_stack_freeze (window->screen->stack); @@ -3304,6 +3383,19 @@ meta_window_hide (MetaWindow *window) set_wm_state (window, IconicState); } + toplevel_now_mapped = meta_window_toplevel_is_mapped (window); + if (toplevel_now_mapped != toplevel_was_mapped) + { + if (window->display->compositor) + { + /* As above, we may be *mapping* live hidden windows */ + if (toplevel_now_mapped) + meta_compositor_window_mapped (window->display->compositor, window); + else + meta_compositor_window_unmapped (window->display->compositor, window); + } + } + set_net_wm_state (window); if (did_hide && window->struts) @@ -5396,12 +5488,6 @@ meta_window_move_resize_internal (MetaWindow *window, else if (is_user_action) save_user_window_placement (window); - if (need_move_frame) - g_signal_emit (window, window_signals[POSITION_CHANGED], 0); - - if (need_resize_client) - g_signal_emit (window, window_signals[SIZE_CHANGED], 0); - if (need_move_frame || need_resize_frame || need_move_client || need_resize_client || did_placement || is_wayland_resize) @@ -8131,7 +8217,7 @@ redraw_icon (MetaWindow *window) /* We could probably be smart and just redraw the icon here, * instead of the whole frame. */ - if (window->frame) + if (window->frame && (window->mapped || window->frame->mapped)) meta_ui_queue_frame_draw (window->screen->ui, window->frame->xwindow); } diff --git a/src/meta/compositor.h b/src/meta/compositor.h index 45c8b09dd..42ff0dd8e 100644 --- a/src/meta/compositor.h +++ b/src/meta/compositor.h @@ -75,10 +75,11 @@ gboolean meta_compositor_filter_keybinding (MetaCompositor *compositor, MetaScreen *screen, MetaKeyBinding *binding); -void meta_compositor_add_window (MetaCompositor *compositor, - MetaWindow *window); -void meta_compositor_remove_window (MetaCompositor *compositor, - MetaWindow *window); +void meta_compositor_add_window (MetaCompositor *compositor, + MetaWindow *window); +void meta_compositor_remove_window (MetaCompositor *compositor, + MetaWindow *window); + void meta_compositor_show_window (MetaCompositor *compositor, MetaWindow *window, MetaCompEffect effect); @@ -100,6 +101,10 @@ void meta_compositor_unmaximize_window (MetaCompositor *compositor, MetaRectangle *old_rect, MetaRectangle *new_rect); +void meta_compositor_window_mapped (MetaCompositor *compositor, + MetaWindow *window); +void meta_compositor_window_unmapped (MetaCompositor *compositor, + MetaWindow *window); void meta_compositor_sync_window_geometry (MetaCompositor *compositor, MetaWindow *window, gboolean did_placement); diff --git a/src/meta/meta-window-actor.h b/src/meta/meta-window-actor.h index 2055ca8fc..9f808a9ac 100644 --- a/src/meta/meta-window-actor.h +++ b/src/meta/meta-window-actor.h @@ -58,8 +58,11 @@ struct _MetaWindowActor GType meta_window_actor_get_type (void); Window meta_window_actor_get_x_window (MetaWindowActor *self); +gint meta_window_actor_get_workspace (MetaWindowActor *self); MetaWindow * meta_window_actor_get_meta_window (MetaWindowActor *self); ClutterActor * meta_window_actor_get_texture (MetaWindowActor *self); +gboolean meta_window_actor_is_override_redirect (MetaWindowActor *self); +gboolean meta_window_actor_showing_on_its_workspace (MetaWindowActor *self); gboolean meta_window_actor_is_destroyed (MetaWindowActor *self); #endif /* META_WINDOW_ACTOR_H */ diff --git a/src/meta/window.h b/src/meta/window.h index 430dc6bd9..ff2d037d3 100644 --- a/src/meta/window.h +++ b/src/meta/window.h @@ -189,6 +189,8 @@ gboolean meta_window_requested_bypass_compositor (MetaWindow *window); gboolean meta_window_requested_dont_bypass_compositor (MetaWindow *window); gint *meta_window_get_all_monitors (MetaWindow *window, gsize *length); +gboolean meta_window_is_mapped (MetaWindow *window); +gboolean meta_window_toplevel_is_mapped (MetaWindow *window); gboolean meta_window_get_icon_geometry (MetaWindow *window, MetaRectangle *rect); void meta_window_set_icon_geometry (MetaWindow *window, diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 43ed92557..1ca38e564 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,9 +58,6 @@ #include "meta-idle-monitor-private.h" #include "monitor-private.h" -#include "meta-surface-actor.h" -#include "meta-surface-actor-wayland.h" - static void surface_process_damage (MetaWaylandSurface *surface, cairo_region_t *region) @@ -71,8 +68,12 @@ surface_process_damage (MetaWaylandSurface *surface, { cairo_rectangle_int_t rect; cairo_region_get_rectangle (region, i, &rect); - meta_surface_actor_process_damage (surface->surface_actor, - rect.x, rect.y, rect.width, rect.height); + meta_surface_actor_damage_area (surface->surface_actor, + rect.x, + rect.y, + rect.width, + rect.height, + NULL); } } @@ -263,7 +264,7 @@ actor_surface_commit (MetaWaylandSurface *surface) { ensure_buffer_texture (buffer); meta_wayland_buffer_reference (&surface->buffer_ref, buffer); - meta_surface_actor_wayland_set_buffer (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor), buffer); + meta_surface_actor_attach_wayland_buffer (surface_actor, buffer); changed = TRUE; } @@ -504,7 +505,7 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor, surface_handle_pending_buffer_destroy; wl_list_init (&surface->pending.frame_callback_list); - surface->surface_actor = g_object_ref_sink (meta_surface_actor_wayland_new (surface)); + surface->surface_actor = g_object_ref_sink (meta_surface_actor_new ()); return surface; } diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c index c9be27205..02c5b7bc3 100644 --- a/src/wayland/meta-xwayland.c +++ b/src/wayland/meta-xwayland.c @@ -48,8 +48,6 @@ xserver_set_window_id (struct wl_client *client, { surface->window = window; window->surface = surface; - - meta_window_set_surface_mapped (window, TRUE); } }