summarylogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.SRCINFO62
-rw-r--r--.gitignore12
-rw-r--r--PKGBUILD123
-rw-r--r--meta_clip_effect.c219
-rw-r--r--meta_clip_effect.h20
-rw-r--r--mr1441.patch2549
-rw-r--r--mutter-rounded.install13
-rw-r--r--rounded_corners.patch1900
-rw-r--r--shader.h116
-rw-r--r--shell-blur-effect.c907
-rw-r--r--shell-blur-effect.h57
-rw-r--r--shell_blur_effect.patch462
12 files changed, 19 insertions, 6421 deletions
diff --git a/.SRCINFO b/.SRCINFO
index f7c874f0ea39..0fe246e0bf4c 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,61 +1,9 @@
pkgbase = mutter-rounded
- pkgdesc = A window manager for GNOME, with rounded corners patch (integrate mr1441)
+ pkgdesc = metapackage - migrate to gnome-shell-extension-rounded-window-corners
pkgver = 42.3
- pkgrel = 1
- url = https://gitlab.gnome.org/GNOME/mutter
- install = mutter-rounded.install
- arch = x86_64
- license = GPL
- checkdepends = xorg-server-xvfb
- checkdepends = wireplumber
- checkdepends = python-dbusmock
- makedepends = gobject-introspection
- makedepends = git
- makedepends = egl-wayland
- makedepends = meson
- makedepends = xorg-server
- makedepends = wayland-protocols
- makedepends = sysprof
- makedepends = gi-docgen
- depends = dconf
- depends = gobject-introspection-runtime
- depends = gsettings-desktop-schemas
- depends = libcanberra
- depends = startup-notification
- depends = zenity
- depends = libsm
- depends = gnome-desktop
- depends = libxkbcommon-x11
- depends = gnome-settings-daemon
- depends = libgudev
- depends = libinput
- depends = pipewire
- depends = xorg-xwayland
- depends = graphene
- depends = libxkbfile
- depends = libsysprof-capture
- provides = libmutter-10.so
- provides = mutter
- conflicts = mutter
- source = mutter-rounded::git+https://gitlab.gnome.org/GNOME/mutter.git#commit=1903356b45c6c884a0451580f32494ff1288656d
- source = mutter_settings::git+https://github.com/yilozt/mutter-rounded-setting
- source = rounded_corners.patch
- source = shell_blur_effect.patch
- source = meta_clip_effect.c
- source = meta_clip_effect.h
- source = shader.h
- source = shell-blur-effect.h
- source = shell-blur-effect.c
- source = mr1441.patch
- sha256sums = SKIP
- sha256sums = SKIP
- sha256sums = 71a533c3a398068025ade421b4f28dbba46eb408068a922334a64a8e0838aefc
- sha256sums = 369390774cf8607f9033a077e0ac76113ffc1c0997627949e087c757a5f41844
- sha256sums = a78e0bdbf4d0b5c8c0f83ede60b531bf0d5d616bfee30293a1f27d32d738dbc6
- sha256sums = 2ec553a260497f0ac0180512201c9819b10159a15fcbc6d5007932d8e2a44844
- sha256sums = f818921dd63cf592663817280c7481eae0852854dd4cd8865ac5fe92423c6fd5
- sha256sums = 8fb024306843153b28db2f5347775ef7e8add1dd846345148a572ad5336e168b
- sha256sums = 5093c7afd6ad66c0ee9fa1565ef61109f5edf958d1d32789a34ab41d0112771d
- sha256sums = 484604741ae85e778c7054b855b8506e3396759f3eee7a030a5964742b8ace19
+ pkgrel = 2
+ arch = any
pkgname = mutter-rounded
+ depends = gnome-shell-extension-rounded-window-corners
+ depends = mutter
diff --git a/.gitignore b/.gitignore
index 730524f6aa0e..018a3de08144 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,4 @@
-/src
-/pkg
-/mutter-rounded
-/mutter_settings
-mutter-settings.tar
-mutter_setting
-*pkg.tar.zst
-mutter-rounded*log
+*
+!PKGBUILD
+!.SRCINFO
+!.gitignore
diff --git a/PKGBUILD b/PKGBUILD
index b4093e913e40..a82baeeb078b 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -1,118 +1,15 @@
-# Patched package:
-# Maintainer: Luo Yi <langisme_at_qq_dot_com>
-# Contributor: Joakim Soderlund <joakim.soderlund@gmail.com>
+# Maintainer:
-# Official package:
-# Maintainer: Jan Alexander Steffens (heftig) <heftig@archlinux.org>
-# Contributor: Ionut Biru <ibiru@archlinux.org>
-# Contributor: Michael Kanis <mkanis_at_gmx_dot_de>
-
-pkgname=mutter-rounded
+_newpkg='gnome-shell-extension-rounded-window-corners'
+pkgname='mutter-rounded'
pkgver=42.3
-pkgrel=1
-pkgdesc="A window manager for GNOME, with rounded corners patch (integrate mr1441)"
-url="https://gitlab.gnome.org/GNOME/mutter"
-arch=(x86_64)
-license=(GPL)
-depends=(dconf gobject-introspection-runtime gsettings-desktop-schemas
- libcanberra startup-notification zenity libsm gnome-desktop
- libxkbcommon-x11 gnome-settings-daemon libgudev libinput pipewire
- xorg-xwayland graphene libxkbfile libsysprof-capture)
-makedepends=(gobject-introspection git egl-wayland meson xorg-server
- wayland-protocols sysprof gi-docgen)
-checkdepends=(xorg-server-xvfb wireplumber python-dbusmock)
-provides=(libmutter-10.so mutter)
-conflicts=(mutter)
-install=mutter-rounded.install
-
-_commit=1903356b45c6c884a0451580f32494ff1288656d # tags/42.3^0
-_mutter_src="$pkgname::git+https://gitlab.gnome.org/GNOME/mutter.git#commit=$_commit"
-_settings_src="mutter_settings::git+https://github.com/yilozt/mutter-rounded-setting"
-
-source=("$_mutter_src"
- "$_settings_src"
- "rounded_corners.patch"
- "shell_blur_effect.patch"
- "meta_clip_effect.c"
- "meta_clip_effect.h"
- "shader.h"
- "shell-blur-effect.h" # https://gitlab.gnome.org/GNOME/gnome-shell/-/raw/${pkgver}/src/shell-blur-effect.h
- "shell-blur-effect.c" # https://gitlab.gnome.org/GNOME/gnome-shell/-/raw/${pkgver}/src/shell-blur-effect.c
- "mr1441.patch"
- )
-sha256sums=('SKIP'
- 'SKIP'
- '71a533c3a398068025ade421b4f28dbba46eb408068a922334a64a8e0838aefc'
- '369390774cf8607f9033a077e0ac76113ffc1c0997627949e087c757a5f41844'
- 'a78e0bdbf4d0b5c8c0f83ede60b531bf0d5d616bfee30293a1f27d32d738dbc6'
- '2ec553a260497f0ac0180512201c9819b10159a15fcbc6d5007932d8e2a44844'
- 'f818921dd63cf592663817280c7481eae0852854dd4cd8865ac5fe92423c6fd5'
- '8fb024306843153b28db2f5347775ef7e8add1dd846345148a572ad5336e168b'
- '5093c7afd6ad66c0ee9fa1565ef61109f5edf958d1d32789a34ab41d0112771d'
- '484604741ae85e778c7054b855b8506e3396759f3eee7a030a5964742b8ace19')
-
-pkgver() {
- cd $pkgname
- git describe --tags | sed 's/[^-]*-g/r&/;s/-/+/g'
-}
-
-prepare() {
- sed -i '1i\#!/usr/bin/gjs' mutter_settings/dist/mutter_settings.js
- mv mutter_settings/dist/mutter_settings.js mutter_settings/dist/mutter_settings
-
- cd $pkgname
-
- find -name "*.orig" -exec rm {} \;
- cp $srcdir/*.[ch] $srcdir/$pkgname/src
- patch -p1 < $srcdir/rounded_corners.patch
- patch -p1 < $srcdir/shell_blur_effect.patch
- patch -p1 < $srcdir/mr1441.patch
-}
-
-build() {
- CFLAGS="${CFLAGS/-O2/-O3} -fno-semantic-interposition"
- LDFLAGS+=" -Wl,-Bsymbolic-functions"
-
- arch-meson $pkgname build \
- -D egl_device=true \
- -D wayland_eglstream=true \
- -D installed_tests=false
- meson compile -C build
-}
-
-_check() (
- mkdir -p -m 700 "${XDG_RUNTIME_DIR:=$PWD/runtime-dir}"
- glib-compile-schemas "${GSETTINGS_SCHEMA_DIR:=$PWD/build/data}"
- export XDG_RUNTIME_DIR GSETTINGS_SCHEMA_DIR
-
- pipewire &
- _p1=$!
-
- wireplumber &
- _p2=$!
-
- trap "kill $_p1 $_p2; wait" EXIT
-
- meson test -C build --print-errorlogs -t 3
-)
-
-check() {
- dbus-run-session xvfb-run -s '-nolisten local +iglx -noreset' \
- bash -c "$(declare -f _check); _check"
-}
+pkgrel=2
+pkgdesc="metapackage - migrate to $_newpkg"
+arch=('any')
package() {
- meson install -C build --destdir "$pkgdir"
-
- install mutter_settings/dist/mutter_settings $pkgdir/usr/bin/
-
- _uuid=pickawindow@lluo.gitlab.com
- _schemas=org.gnome.shell.extensions.pickawindow.gschema.xml
-
- install -d "$pkgdir/usr/share/gnome-shell/extensions/$_uuid"
- cp -r mutter_settings/$_uuid/* "$pkgdir/usr/share/gnome-shell/extensions/$_uuid/"
-
- install -d "$pkgdir/usr/share/glib-2.0/schemas/"
- ln -s "/usr/share/gnome-shell/extensions/$_uuid/schemas/$_schemas" \
- "$pkgdir/usr/share/glib-2.0/schemas/"
+ depends=(
+ "$_newpkg"
+ "mutter"
+ )
}
diff --git a/meta_clip_effect.c b/meta_clip_effect.c
deleted file mode 100644
index 6f3f488fd13b..000000000000
--- a/meta_clip_effect.c
+++ /dev/null
@@ -1,219 +0,0 @@
-// for 40.4
-
-#include "meta_clip_effect.h"
-#include "meta/prefs.h"
-#include "shader.h"
-
-typedef struct {
- CoglPipeline *pipeline;
- ClutterActor *actor;
- cairo_rectangle_int_t bounds;
-
- int bounds_uniform;
- int clip_radius_uniform;
- int inner_bounds_uniform;
- int inner_clip_radius_uniform;
- int pixel_step_uniform;
- int skip_uniform;
- int border_width_uniform;
- int border_brightness_uniform;
-} MetaClipEffectPrivate;
-
-G_DEFINE_TYPE_WITH_PRIVATE(MetaClipEffect, meta_clip_effect, CLUTTER_TYPE_OFFSCREEN_EFFECT)
-
-static CoglPipeline *
-meta_clip_effect_class_create_pipeline(ClutterOffscreenEffect *effect,
- CoglTexture *texture)
-{
- MetaClipEffect *clip_effect = META_CLIP_EFFECT (effect);
- MetaClipEffectPrivate *priv = meta_clip_effect_get_instance_private(clip_effect);
- cogl_pipeline_set_layer_texture (priv->pipeline, 0, texture);
-
- return cogl_object_ref (priv->pipeline);
-}
-
-static void
-meta_clip_effect_set_actor(ClutterActorMeta *meta,
- ClutterActor *actor)
-{
- ClutterActorMetaClass *meta_class
- = CLUTTER_ACTOR_META_CLASS(meta_clip_effect_parent_class);
- MetaClipEffectPrivate *priv =
- meta_clip_effect_get_instance_private(META_CLIP_EFFECT(meta));
- meta_class->set_actor(meta, actor);
- priv->actor = clutter_actor_meta_get_actor(meta);
-}
-
-static gboolean
-meta_clip_effect_pre_paint (ClutterEffect *effect,
- ClutterPaintNode *node,
- ClutterPaintContext *paint_context)
-{
- gboolean res =
- CLUTTER_EFFECT_CLASS (meta_clip_effect_parent_class)->pre_paint(effect, node, paint_context);
- MetaClipEffect *clip_effect = META_CLIP_EFFECT (effect);
- MetaClipEffectPrivate *priv =
- meta_clip_effect_get_instance_private(META_CLIP_EFFECT(clip_effect));
-
- // seems CutterOffscreenEffect will set COGL_PIPELINE_FILTER_NEAREST
- // as layer filter, force set linear filter before paint now
- cogl_pipeline_set_layer_filters (priv->pipeline,
- 0,
- COGL_PIPELINE_FILTER_LINEAR,
- COGL_PIPELINE_FILTER_LINEAR);
- return res;
-}
-
-static void
-meta_clip_effect_dispose(GObject *gobject)
-{
- MetaClipEffect*effect = META_CLIP_EFFECT(gobject);
- MetaClipEffectPrivate *priv =
- meta_clip_effect_get_instance_private(META_CLIP_EFFECT(effect));
-
- if (priv->pipeline != NULL)
- {
- g_clear_pointer(&priv->pipeline, cogl_object_unref);
- }
-
- G_OBJECT_CLASS (meta_clip_effect_parent_class)->dispose (gobject);
-}
-
-static void
-meta_clip_effect_class_init(MetaClipEffectClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass);
- ClutterOffscreenEffectClass *offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
- ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS(klass);
-
- meta_class->set_actor = meta_clip_effect_set_actor;
- effect_class->pre_paint = meta_clip_effect_pre_paint;
- offscreen_class->create_pipeline = meta_clip_effect_class_create_pipeline;
- gobject_class->dispose = meta_clip_effect_dispose;
-}
-
-static void
-meta_clip_effect_init(MetaClipEffect *self)
-{
- MetaClipEffectClass *klass = META_CLIP_EFFECT_GET_CLASS (self);
- MetaClipEffectPrivate *priv = meta_clip_effect_get_instance_private(self);
-
- if (G_UNLIKELY (klass->base_pipeline == NULL))
- {
- CoglSnippet *snippet;
- CoglContext *ctx =
- clutter_backend_get_cogl_context (clutter_get_default_backend ());
-
- klass->base_pipeline = cogl_pipeline_new (ctx);
-
- snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
- ROUNDED_CLIP_FRAGMENT_SHADER_DECLARATIONS,
- ROUNDED_CLIP_FRAGMENT_SHADER_CODE);
- cogl_pipeline_add_snippet (klass->base_pipeline, snippet);
- cogl_object_unref (snippet);
-
- cogl_pipeline_set_layer_null_texture (klass->base_pipeline, 0);
- }
-
- priv->pipeline = cogl_pipeline_copy (klass->base_pipeline);
- priv->actor = NULL;
-
- // get location of uniforms from shader
- priv->bounds_uniform =
- cogl_pipeline_get_uniform_location(priv->pipeline, "bounds");
- priv->clip_radius_uniform =
- cogl_pipeline_get_uniform_location(priv->pipeline, "clip_radius");
- priv->inner_bounds_uniform =
- cogl_pipeline_get_uniform_location(priv->pipeline, "inner_bounds");
- priv->inner_clip_radius_uniform =
- cogl_pipeline_get_uniform_location(priv->pipeline, "inner_clip_radius");
- priv->pixel_step_uniform =
- cogl_pipeline_get_uniform_location(priv->pipeline, "pixel_step");
- priv->skip_uniform =
- cogl_pipeline_get_uniform_location(priv->pipeline, "skip");
- priv->border_width_uniform =
- cogl_pipeline_get_uniform_location(priv->pipeline, "border_width");
- priv->border_brightness_uniform =
- cogl_pipeline_get_uniform_location(priv->pipeline, "border_brightness");
-}
-
-MetaClipEffect *meta_clip_effect_new(void)
-{
- return g_object_new(META_TYPE_CLIP_EFFECT, NULL);
-}
-
-void
-meta_clip_effect_set_bounds(MetaClipEffect *effect,
- cairo_rectangle_int_t *_bounds,
- int padding[4])
-{
- // padding: [left, right, top, bottom]
-
- MetaClipEffectPrivate *priv = meta_clip_effect_get_instance_private(effect);
-
- g_return_if_fail(priv->pipeline && priv->actor);
- float radius = meta_prefs_get_round_corner_radius();
- float border = meta_prefs_get_border_width();
- float brightness = meta_prefs_get_border_brightness();
-
- priv->bounds.x = _bounds->x + padding[0];
- priv->bounds.y = _bounds->y + padding[2];
- priv->bounds.width = _bounds->width - padding[1] - padding[0];
- priv->bounds.height = _bounds->height - padding[2] - padding[3];
-
- float x1 = priv->bounds.x;
- float y1 = priv->bounds.y;
- float x2 = priv->bounds.width + x1;
- float y2 = priv->bounds.height + y1;
- float w, h;
-
- clutter_actor_get_size(priv->actor, &w, &h);
-
- float bounds[] = { x1, y1, x2, y2 };
-
- float inner_bounds[] = { x1 + border, y1 + border, x2 - border, y2 - border };
- float inner_radius = radius - border;
- if (inner_radius < 0.0f) {
- inner_radius = 0.0f;
- }
-
- float pixel_step[] = { 1. / w, 1. / h };
-
- cogl_pipeline_set_uniform_float(priv->pipeline,
- priv->bounds_uniform,
- 4, 1, bounds);
- cogl_pipeline_set_uniform_1f(priv->pipeline,
- priv->clip_radius_uniform,
- radius);
- cogl_pipeline_set_uniform_float(priv->pipeline,
- priv->inner_bounds_uniform,
- 4, 1, inner_bounds);
- cogl_pipeline_set_uniform_1f(priv->pipeline,
- priv->inner_clip_radius_uniform,
- inner_radius);
- cogl_pipeline_set_uniform_float(priv->pipeline,
- priv->pixel_step_uniform,
- 2, 1, pixel_step);
- cogl_pipeline_set_uniform_1i(priv->pipeline, priv->skip_uniform, 0);
- cogl_pipeline_set_uniform_1f(priv->pipeline, priv->border_width_uniform, border);
- cogl_pipeline_set_uniform_1f(priv->pipeline, priv->border_brightness_uniform, brightness);
-}
-
-void
-meta_clip_effect_skip(MetaClipEffect *effect)
-{
- MetaClipEffectPrivate *priv = meta_clip_effect_get_instance_private(effect);
-
- g_return_if_fail(priv->pipeline && priv->actor);
-
- cogl_pipeline_set_uniform_1i(priv->pipeline, priv->skip_uniform, 1);
-}
-
-void
-meta_clip_effect_get_bounds(MetaClipEffect *effect,
- cairo_rectangle_int_t *bounds)
-{
- MetaClipEffectPrivate *priv = meta_clip_effect_get_instance_private(effect);
- *bounds = priv->bounds;
-}
diff --git a/meta_clip_effect.h b/meta_clip_effect.h
deleted file mode 100644
index ab20b10871b3..000000000000
--- a/meta_clip_effect.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// for 40.4
-
-#pragma once
-
-#include <clutter/clutter.h>
-
-#define META_TYPE_CLIP_EFFECT (meta_clip_effect_get_type())
-G_DECLARE_DERIVABLE_TYPE(MetaClipEffect, meta_clip_effect, META, CLIP_EFFECT, ClutterOffscreenEffect)
-
-struct _MetaClipEffectClass {
- ClutterOffscreenEffectClass parent_class;
- CoglPipeline *base_pipeline;
- gpointer padding[12];
-};
-
-MetaClipEffect *meta_clip_effect_new(void);
-
-void meta_clip_effect_set_bounds(MetaClipEffect *effect, cairo_rectangle_int_t *bounds, int padding[4]);
-void meta_clip_effect_get_bounds(MetaClipEffect *effect, cairo_rectangle_int_t *bounds);
-void meta_clip_effect_skip(MetaClipEffect *effect); \ No newline at end of file
diff --git a/mr1441.patch b/mr1441.patch
deleted file mode 100644
index ca8a66a39475..000000000000
--- a/mr1441.patch
+++ /dev/null
@@ -1,2549 +0,0 @@
-Author: Daniel van Vugt <daniel.van.vugt@canonical.com>
-Source: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1441
-Commit: bf7030b8b898e621cd3ef535d3daae815dc98134
-Rebase: Fri May 6 16:34:46 2022 +0800
-
-diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c
-index 6fa2b2588..7a6444ec4 100644
---- a/clutter/clutter/clutter-frame-clock.c
-+++ b/clutter/clutter/clutter-frame-clock.c
-@@ -45,6 +45,8 @@ typedef struct _EstimateQueue
- int next_index;
- } EstimateQueue;
-
-+static gboolean triple_buffering_disabled = FALSE;
-+
- #define SYNC_DELAY_FALLBACK_FRACTION 0.875
-
- typedef struct _ClutterFrameListener
-@@ -65,8 +67,9 @@ typedef enum _ClutterFrameClockState
- CLUTTER_FRAME_CLOCK_STATE_INIT,
- CLUTTER_FRAME_CLOCK_STATE_IDLE,
- CLUTTER_FRAME_CLOCK_STATE_SCHEDULED,
-- CLUTTER_FRAME_CLOCK_STATE_DISPATCHING,
-- CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED,
-+ CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE,
-+ CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED,
-+ CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO,
- } ClutterFrameClockState;
-
- struct _ClutterFrameClock
-@@ -96,6 +99,8 @@ struct _ClutterFrameClock
- /* Last KMS buffer submission time. */
- int64_t last_flip_time_us;
-
-+ ClutterFrameHint last_flip_hints;
-+
- /* Last few durations between dispatch start and buffer swap. */
- EstimateQueue dispatch_to_swap_us;
- /* Last few durations between buffer swap and GPU rendering finish. */
-@@ -228,6 +233,10 @@ void
- clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
- ClutterFrameInfo *frame_info)
- {
-+ const char *debug_state =
-+ frame_clock->state == CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO ?
-+ "Triple buffering" : "Double buffering";
-+
- COGL_TRACE_BEGIN_SCOPED (ClutterFrameClockNotifyPresented,
- "Frame Clock (presented)");
-
-@@ -289,7 +298,8 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
- frame_info->cpu_time_before_buffer_swap_us;
-
- CLUTTER_NOTE (FRAME_TIMINGS,
-- "dispatch2swap %ld µs, swap2render %ld µs, swap2flip %ld µs",
-+ "%s: dispatch2swap %ld µs, swap2render %ld µs, swap2flip %ld µs",
-+ debug_state,
- dispatch_to_swap_us,
- swap_to_rendering_done_us,
- swap_to_flip_us);
-@@ -303,6 +313,10 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
-
- frame_clock->got_measurements_last_frame = TRUE;
- }
-+ else
-+ {
-+ CLUTTER_NOTE (FRAME_TIMINGS, "%s", debug_state);
-+ }
-
- if (frame_info->refresh_rate > 1)
- {
-@@ -317,11 +331,18 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
- case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
- g_warn_if_reached ();
- break;
-- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
-- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
- maybe_reschedule_update (frame_clock);
- break;
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
-+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
-+ maybe_reschedule_update (frame_clock);
-+ break;
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
-+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE;
-+ maybe_reschedule_update (frame_clock);
-+ break;
- }
- }
-
-@@ -337,11 +358,18 @@ clutter_frame_clock_notify_ready (ClutterFrameClock *frame_clock)
- case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
- g_warn_if_reached ();
- break;
-- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
-- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
- maybe_reschedule_update (frame_clock);
- break;
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
-+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
-+ maybe_reschedule_update (frame_clock);
-+ break;
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
-+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE;
-+ maybe_reschedule_update (frame_clock);
-+ break;
- }
- }
-
-@@ -353,6 +381,7 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
- int64_t max_swap_to_rendering_done_us = 0;
- int64_t max_swap_to_flip_us = 0;
- int64_t max_render_time_us;
-+ int buffer_queue_latency_frames = 0;
- int i;
-
- refresh_interval_us = frame_clock->refresh_interval_us;
-@@ -375,6 +404,27 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
- frame_clock->swap_to_flip_us.values[i]);
- }
-
-+ switch (frame_clock->state)
-+ {
-+ case CLUTTER_FRAME_CLOCK_STATE_INIT:
-+ case CLUTTER_FRAME_CLOCK_STATE_IDLE:
-+ case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
-+ buffer_queue_latency_frames = 0;
-+ break;
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
-+ buffer_queue_latency_frames = 1;
-+ break;
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
-+ g_warn_if_reached ();
-+ buffer_queue_latency_frames = 2;
-+ break;
-+ }
-+
-+ max_swap_to_flip_us -= refresh_interval_us * buffer_queue_latency_frames;
-+ if (max_swap_to_flip_us < 0)
-+ max_swap_to_flip_us = 0;
-+
- /* Max render time shows how early the frame clock needs to be dispatched
- * to make it to the predicted next presentation time. It is composed of:
- * - An estimate of duration from dispatch start to buffer swap.
-@@ -391,8 +441,6 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
- frame_clock->vblank_duration_us +
- clutter_max_render_time_constant_us;
-
-- max_render_time_us = CLAMP (max_render_time_us, 0, refresh_interval_us);
--
- return max_render_time_us;
- }
-
-@@ -558,8 +606,12 @@ clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock)
- frame_clock->pending_reschedule = TRUE;
- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
- break;
-- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
-- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
-+ frame_clock->pending_reschedule = TRUE;
-+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE;
-+ break;
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
- break;
- }
-
-@@ -595,11 +647,17 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
- case CLUTTER_FRAME_CLOCK_STATE_INIT:
- case CLUTTER_FRAME_CLOCK_STATE_IDLE:
- next_update_time_us = g_get_monotonic_time ();
-+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
- break;
- case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
- return;
-- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
-- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
-+ next_update_time_us = g_get_monotonic_time ();
-+ frame_clock->state =
-+ CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED;
-+ break;
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
- frame_clock->pending_reschedule = TRUE;
- frame_clock->pending_reschedule_now = TRUE;
- return;
-@@ -608,7 +666,6 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
- g_warn_if_fail (next_update_time_us != -1);
-
- g_source_set_ready_time (frame_clock->source, next_update_time_us);
-- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
- frame_clock->is_next_presentation_time_valid = FALSE;
- }
-
-@@ -627,6 +684,7 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
- {
- case CLUTTER_FRAME_CLOCK_STATE_INIT:
- next_update_time_us = g_get_monotonic_time ();
-+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
- break;
- case CLUTTER_FRAME_CLOCK_STATE_IDLE:
- calculate_next_update_time_us (frame_clock,
-@@ -634,11 +692,28 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
- &frame_clock->next_presentation_time_us);
- frame_clock->is_next_presentation_time_valid =
- (frame_clock->next_presentation_time_us != 0);
-+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
- break;
- case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
- return;
-- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
-- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
-+ if (frame_clock->last_flip_hints & CLUTTER_FRAME_HINT_DIRECT_SCANOUT_ATTEMPTED ||
-+ triple_buffering_disabled)
-+ {
-+ /* Force double buffering, disable triple buffering */
-+ frame_clock->pending_reschedule = TRUE;
-+ return;
-+ }
-+
-+ calculate_next_update_time_us (frame_clock,
-+ &next_update_time_us,
-+ &frame_clock->next_presentation_time_us);
-+ frame_clock->is_next_presentation_time_valid =
-+ (frame_clock->next_presentation_time_us != 0);
-+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED;
-+ break;
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
- frame_clock->pending_reschedule = TRUE;
- return;
- }
-@@ -646,7 +721,6 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
- g_warn_if_fail (next_update_time_us != -1);
-
- g_source_set_ready_time (frame_clock->source, next_update_time_us);
-- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
- }
-
- static void
-@@ -670,7 +744,7 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
- frame_clock->refresh_interval_us;
-
- lateness_us = time_us - ideal_dispatch_time_us;
-- if (lateness_us < 0 || lateness_us >= frame_clock->refresh_interval_us)
-+ if (lateness_us < 0 || lateness_us >= frame_clock->refresh_interval_us / 4)
- frame_clock->last_dispatch_lateness_us = 0;
- else
- frame_clock->last_dispatch_lateness_us = lateness_us;
-@@ -678,7 +752,21 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
- frame_clock->last_dispatch_time_us = time_us;
- g_source_set_ready_time (frame_clock->source, -1);
-
-- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHING;
-+ switch (frame_clock->state)
-+ {
-+ case CLUTTER_FRAME_CLOCK_STATE_INIT:
-+ case CLUTTER_FRAME_CLOCK_STATE_IDLE:
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
-+ g_warn_if_reached ();
-+ return;
-+ case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
-+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE;
-+ break;
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
-+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO;
-+ break;
-+ }
-
- frame_count = frame_clock->frame_count++;
-
-@@ -703,25 +791,31 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
- frame_clock->listener.user_data);
- COGL_TRACE_END (ClutterFrameClockFrame);
-
-- switch (frame_clock->state)
-+ switch (result)
- {
-- case CLUTTER_FRAME_CLOCK_STATE_INIT:
-- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
-- g_warn_if_reached ();
-+ case CLUTTER_FRAME_RESULT_PENDING_PRESENTED:
- break;
-- case CLUTTER_FRAME_CLOCK_STATE_IDLE:
-- case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
-- break;
-- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
-- switch (result)
-+ case CLUTTER_FRAME_RESULT_IDLE:
-+ /* The frame was aborted; nothing to paint/present */
-+ switch (frame_clock->state)
- {
-- case CLUTTER_FRAME_RESULT_PENDING_PRESENTED:
-- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED;
-+ case CLUTTER_FRAME_CLOCK_STATE_INIT:
-+ case CLUTTER_FRAME_CLOCK_STATE_IDLE:
-+ case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
-+ g_warn_if_reached ();
- break;
-- case CLUTTER_FRAME_RESULT_IDLE:
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
- maybe_reschedule_update (frame_clock);
- break;
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
-+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
-+ maybe_reschedule_update (frame_clock);
-+ break;
-+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
-+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE;
-+ maybe_reschedule_update (frame_clock);
-+ break;
- }
- break;
- }
-@@ -754,10 +848,12 @@ frame_clock_source_dispatch (GSource *source,
- }
-
- void
--clutter_frame_clock_record_flip_time (ClutterFrameClock *frame_clock,
-- int64_t flip_time_us)
-+clutter_frame_clock_record_flip (ClutterFrameClock *frame_clock,
-+ int64_t flip_time_us,
-+ ClutterFrameHint hints)
- {
- frame_clock->last_flip_time_us = flip_time_us;
-+ frame_clock->last_flip_hints = hints;
- }
-
- GString *
-@@ -888,6 +984,9 @@ clutter_frame_clock_class_init (ClutterFrameClockClass *klass)
- {
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-+ if (!g_strcmp0 (g_getenv ("MUTTER_DEBUG_DISABLE_TRIPLE_BUFFERING"), "1"))
-+ triple_buffering_disabled = TRUE;
-+
- object_class->dispose = clutter_frame_clock_dispose;
-
- signals[DESTROY] =
-diff --git a/clutter/clutter/clutter-frame-clock.h b/clutter/clutter/clutter-frame-clock.h
-index 91e6b3a13..d750404d5 100644
---- a/clutter/clutter/clutter-frame-clock.h
-+++ b/clutter/clutter/clutter-frame-clock.h
-@@ -34,6 +34,12 @@ typedef enum _ClutterFrameResult
- CLUTTER_FRAME_RESULT_IDLE,
- } ClutterFrameResult;
-
-+typedef enum _ClutterFrameHint
-+{
-+ CLUTTER_FRAME_HINT_NONE = 0,
-+ CLUTTER_FRAME_HINT_DIRECT_SCANOUT_ATTEMPTED = 1 << 0,
-+} ClutterFrameHint;
-+
- #define CLUTTER_TYPE_FRAME_CLOCK (clutter_frame_clock_get_type ())
- CLUTTER_EXPORT
- G_DECLARE_FINAL_TYPE (ClutterFrameClock, clutter_frame_clock,
-@@ -90,8 +96,9 @@ void clutter_frame_clock_remove_timeline (ClutterFrameClock *frame_clock,
- CLUTTER_EXPORT
- float clutter_frame_clock_get_refresh_rate (ClutterFrameClock *frame_clock);
-
--void clutter_frame_clock_record_flip_time (ClutterFrameClock *frame_clock,
-- int64_t flip_time_us);
-+void clutter_frame_clock_record_flip (ClutterFrameClock *frame_clock,
-+ int64_t flip_time_us,
-+ ClutterFrameHint hints);
-
- GString * clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clock);
-
-diff --git a/clutter/clutter/clutter-frame-private.h b/clutter/clutter/clutter-frame-private.h
-index e0088564f..06581492f 100644
---- a/clutter/clutter/clutter-frame-private.h
-+++ b/clutter/clutter/clutter-frame-private.h
-@@ -24,6 +24,7 @@ struct _ClutterFrame
- {
- gboolean has_result;
- ClutterFrameResult result;
-+ ClutterFrameHint hints;
- };
-
- #define CLUTTER_FRAME_INIT ((ClutterFrame) { 0 })
-diff --git a/clutter/clutter/clutter-frame.c b/clutter/clutter/clutter-frame.c
-index 3c708da9d..63ae302af 100644
---- a/clutter/clutter/clutter-frame.c
-+++ b/clutter/clutter/clutter-frame.c
-@@ -40,3 +40,16 @@ clutter_frame_set_result (ClutterFrame *frame,
- frame->result = result;
- frame->has_result = TRUE;
- }
-+
-+void
-+clutter_frame_set_hint (ClutterFrame *frame,
-+ ClutterFrameHint hint)
-+{
-+ frame->hints |= hint;
-+}
-+
-+ClutterFrameHint
-+clutter_frame_get_hints (ClutterFrame *frame)
-+{
-+ return frame->hints;
-+}
-diff --git a/clutter/clutter/clutter-frame.h b/clutter/clutter/clutter-frame.h
-index d3608e81c..06c5f7f28 100644
---- a/clutter/clutter/clutter-frame.h
-+++ b/clutter/clutter/clutter-frame.h
-@@ -33,4 +33,11 @@ void clutter_frame_set_result (ClutterFrame *frame,
- CLUTTER_EXPORT
- gboolean clutter_frame_has_result (ClutterFrame *frame);
-
-+CLUTTER_EXPORT
-+void clutter_frame_set_hint (ClutterFrame *frame,
-+ ClutterFrameHint hint);
-+
-+CLUTTER_EXPORT
-+ClutterFrameHint clutter_frame_get_hints (ClutterFrame *frame);
-+
- #endif /* CLUTTER_FRAME_H */
-diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
-index 2e47237f0..8f5e896d0 100644
---- a/clutter/clutter/clutter-stage-view.c
-+++ b/clutter/clutter/clutter-stage-view.c
-@@ -1191,8 +1191,9 @@ handle_frame_clock_frame (ClutterFrameClock *frame_clock,
-
- _clutter_stage_window_redraw_view (stage_window, view, &frame);
-
-- clutter_frame_clock_record_flip_time (frame_clock,
-- g_get_monotonic_time ());
-+ clutter_frame_clock_record_flip (frame_clock,
-+ g_get_monotonic_time (),
-+ clutter_frame_get_hints (&frame));
-
- clutter_stage_emit_after_paint (stage, view);
-
-diff --git a/cogl/cogl/cogl-onscreen-private.h b/cogl/cogl/cogl-onscreen-private.h
-index dffe018d2..e0215f750 100644
---- a/cogl/cogl/cogl-onscreen-private.h
-+++ b/cogl/cogl/cogl-onscreen-private.h
-@@ -97,4 +97,7 @@ cogl_onscreen_peek_tail_frame_info (CoglOnscreen *onscreen);
- COGL_EXPORT CoglFrameInfo *
- cogl_onscreen_pop_head_frame_info (CoglOnscreen *onscreen);
-
-+COGL_EXPORT unsigned int
-+cogl_onscreen_count_pending_frames (CoglOnscreen *onscreen);
-+
- #endif /* __COGL_ONSCREEN_PRIVATE_H */
-diff --git a/cogl/cogl/cogl-onscreen.c b/cogl/cogl/cogl-onscreen.c
-index ff9e1749a..b25b4af4a 100644
---- a/cogl/cogl/cogl-onscreen.c
-+++ b/cogl/cogl/cogl-onscreen.c
-@@ -510,6 +510,14 @@ cogl_onscreen_pop_head_frame_info (CoglOnscreen *onscreen)
- return g_queue_pop_head (&priv->pending_frame_infos);
- }
-
-+unsigned int
-+cogl_onscreen_count_pending_frames (CoglOnscreen *onscreen)
-+{
-+ CoglOnscreenPrivate *priv = cogl_onscreen_get_instance_private (onscreen);
-+
-+ return g_queue_get_length (&priv->pending_frame_infos);
-+}
-+
- CoglFrameClosure *
- cogl_onscreen_add_frame_callback (CoglOnscreen *onscreen,
- CoglFrameCallback callback,
-diff --git a/src/backends/meta-stage-impl.c b/src/backends/meta-stage-impl.c
-index c45aaf852..683f4ff6c 100644
---- a/src/backends/meta-stage-impl.c
-+++ b/src/backends/meta-stage-impl.c
-@@ -720,6 +720,8 @@ meta_stage_impl_redraw_view (ClutterStageWindow *stage_window,
- {
- g_autoptr (GError) error = NULL;
-
-+ clutter_frame_set_hint (frame, CLUTTER_FRAME_HINT_DIRECT_SCANOUT_ATTEMPTED);
-+
- if (meta_stage_impl_scanout_view (stage_impl,
- stage_view,
- scanout,
-diff --git a/src/backends/native/meta-crtc-kms.c b/src/backends/native/meta-crtc-kms.c
-index ad72dba64..24e9b0a6a 100644
---- a/src/backends/native/meta-crtc-kms.c
-+++ b/src/backends/native/meta-crtc-kms.c
-@@ -226,7 +226,7 @@ meta_crtc_kms_maybe_set_gamma (MetaCrtcKms *crtc_kms,
- if (!gamma)
- return;
-
-- kms_update = meta_kms_ensure_pending_update (kms, kms_device);
-+ kms_update = meta_kms_ensure_pending_update_for_crtc (kms, kms_crtc);
- meta_kms_update_set_crtc_gamma (kms_update,
- kms_crtc,
- gamma->size,
-diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c
-index 96c54baf0..f80f31a93 100644
---- a/src/backends/native/meta-cursor-renderer-native.c
-+++ b/src/backends/native/meta-cursor-renderer-native.c
-@@ -58,19 +58,6 @@
- #include "wayland/meta-wayland-buffer.h"
- #endif
-
--/* When animating a cursor, we usually call drmModeSetCursor2 once per frame.
-- * Though, testing shows that we need to triple buffer the cursor buffer in
-- * order to avoid glitches when animating the cursor, at least when running on
-- * Intel. The reason for this might be (but is not confirmed to be) due to
-- * the user space gbm_bo cache, making us reuse and overwrite the kernel side
-- * buffer content before it was scanned out. To avoid this, we keep a user space
-- * reference to each buffer we set until at least one frame after it was drawn.
-- * In effect, this means we three active cursor gbm_bo's: one that that just has
-- * been set, one that was previously set and may or may not have been scanned
-- * out, and one pending that will be replaced if the cursor sprite changes.
-- */
--#define HW_CURSOR_BUFFER_COUNT 3
--
- static GQuark quark_cursor_sprite = 0;
-
- typedef struct _CrtcCursorData
-@@ -104,19 +91,10 @@ typedef struct _MetaCursorRendererNativeGpuData
- uint64_t cursor_height;
- } MetaCursorRendererNativeGpuData;
-
--typedef enum _MetaCursorBufferState
--{
-- META_CURSOR_BUFFER_STATE_NONE,
-- META_CURSOR_BUFFER_STATE_SET,
-- META_CURSOR_BUFFER_STATE_INVALIDATED,
--} MetaCursorBufferState;
--
- typedef struct _MetaCursorNativeGpuState
- {
- MetaGpu *gpu;
-- unsigned int active_buffer_idx;
-- MetaCursorBufferState pending_buffer_state;
-- MetaDrmBuffer *buffers[HW_CURSOR_BUFFER_COUNT];
-+ MetaDrmBuffer *buffer;
- } MetaCursorNativeGpuState;
-
- typedef struct _MetaCursorNativePrivate
-@@ -197,44 +175,17 @@ meta_cursor_renderer_native_finalize (GObject *object)
- G_OBJECT_CLASS (meta_cursor_renderer_native_parent_class)->finalize (object);
- }
-
--static unsigned int
--get_pending_cursor_sprite_buffer_index (MetaCursorNativeGpuState *cursor_gpu_state)
--{
-- return (cursor_gpu_state->active_buffer_idx + 1) % HW_CURSOR_BUFFER_COUNT;
--}
--
--static MetaDrmBuffer *
--get_pending_cursor_sprite_buffer (MetaCursorNativeGpuState *cursor_gpu_state)
--{
-- unsigned int pending_buffer_idx;
--
-- pending_buffer_idx =
-- get_pending_cursor_sprite_buffer_index (cursor_gpu_state);
-- return cursor_gpu_state->buffers[pending_buffer_idx];
--}
--
--static MetaDrmBuffer *
--get_active_cursor_sprite_buffer (MetaCursorNativeGpuState *cursor_gpu_state)
--{
-- return cursor_gpu_state->buffers[cursor_gpu_state->active_buffer_idx];
--}
--
- static void
--set_pending_cursor_sprite_buffer (MetaCursorSprite *cursor_sprite,
-- MetaGpuKms *gpu_kms,
-- MetaDrmBuffer *buffer)
-+set_cursor_sprite_buffer (MetaCursorSprite *cursor_sprite,
-+ MetaGpuKms *gpu_kms,
-+ MetaDrmBuffer *buffer)
- {
- MetaCursorNativePrivate *cursor_priv;
- MetaCursorNativeGpuState *cursor_gpu_state;
-- unsigned int pending_buffer_idx;
-
- cursor_priv = ensure_cursor_priv (cursor_sprite);
- cursor_gpu_state = ensure_cursor_gpu_state (cursor_priv, gpu_kms);
--
-- pending_buffer_idx =
-- get_pending_cursor_sprite_buffer_index (cursor_gpu_state);
-- cursor_gpu_state->buffers[pending_buffer_idx] = buffer;
-- cursor_gpu_state->pending_buffer_state = META_CURSOR_BUFFER_STATE_SET;
-+ cursor_gpu_state->buffer = buffer;
- }
-
- static void
-@@ -309,10 +260,7 @@ assign_cursor_plane (MetaCursorRendererNative *native,
- MetaKmsUpdate *kms_update;
- MetaKmsPlaneAssignment *plane_assignment;
-
-- if (cursor_gpu_state->pending_buffer_state == META_CURSOR_BUFFER_STATE_SET)
-- buffer = get_pending_cursor_sprite_buffer (cursor_gpu_state);
-- else
-- buffer = get_active_cursor_sprite_buffer (cursor_gpu_state);
-+ buffer = cursor_gpu_state->buffer;
-
- kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
- kms_device = meta_kms_crtc_get_device (kms_crtc);
-@@ -341,8 +289,8 @@ assign_cursor_plane (MetaCursorRendererNative *native,
- flags |= META_KMS_ASSIGN_PLANE_FLAG_FB_UNCHANGED;
-
- kms_update =
-- meta_kms_ensure_pending_update (meta_kms_device_get_kms (kms_device),
-- meta_kms_crtc_get_device (kms_crtc));
-+ meta_kms_ensure_pending_update_for_crtc (meta_kms_device_get_kms (kms_device),
-+ kms_crtc);
- plane_assignment = meta_kms_update_assign_plane (kms_update,
- kms_crtc,
- cursor_plane,
-@@ -363,13 +311,6 @@ assign_cursor_plane (MetaCursorRendererNative *native,
- native);
-
- crtc_cursor_data->buffer = buffer;
--
-- if (cursor_gpu_state->pending_buffer_state == META_CURSOR_BUFFER_STATE_SET)
-- {
-- cursor_gpu_state->active_buffer_idx =
-- (cursor_gpu_state->active_buffer_idx + 1) % HW_CURSOR_BUFFER_COUNT;
-- cursor_gpu_state->pending_buffer_state = META_CURSOR_BUFFER_STATE_NONE;
-- }
- }
-
- static float
-@@ -497,7 +438,7 @@ unset_crtc_cursor (MetaCursorRendererNative *native,
- MetaKms *kms = meta_kms_device_get_kms (kms_device);
- MetaKmsUpdate *kms_update;
-
-- kms_update = meta_kms_ensure_pending_update (kms, kms_device);
-+ kms_update = meta_kms_ensure_pending_update_for_crtc (kms, kms_crtc);
- meta_kms_update_unassign_plane (kms_update, kms_crtc, cursor_plane);
- }
-
-@@ -597,19 +538,7 @@ has_valid_cursor_sprite_buffer (MetaCursorSprite *cursor_sprite,
- if (!cursor_gpu_state)
- return FALSE;
-
-- switch (cursor_gpu_state->pending_buffer_state)
-- {
-- case META_CURSOR_BUFFER_STATE_NONE:
-- return get_active_cursor_sprite_buffer (cursor_gpu_state) != NULL;
-- case META_CURSOR_BUFFER_STATE_SET:
-- return TRUE;
-- case META_CURSOR_BUFFER_STATE_INVALIDATED:
-- return FALSE;
-- }
--
-- g_assert_not_reached ();
--
-- return FALSE;
-+ return cursor_gpu_state->buffer != NULL;
- }
-
- static void
-@@ -1115,16 +1044,14 @@ unset_crtc_cursor_renderer_privates (MetaGpu *gpu,
- static void
- cursor_gpu_state_free (MetaCursorNativeGpuState *cursor_gpu_state)
- {
-- int i;
- MetaDrmBuffer *active_buffer;
-
-- active_buffer = get_active_cursor_sprite_buffer (cursor_gpu_state);
-+ active_buffer = cursor_gpu_state->buffer;
- if (active_buffer)
- unset_crtc_cursor_renderer_privates (cursor_gpu_state->gpu,
- active_buffer);
-
-- for (i = 0; i < HW_CURSOR_BUFFER_COUNT; i++)
-- g_clear_object (&cursor_gpu_state->buffers[i]);
-+ g_clear_object (&cursor_gpu_state->buffer);
- g_free (cursor_gpu_state);
- }
-
-@@ -1161,14 +1088,7 @@ invalidate_cursor_gpu_state (MetaCursorSprite *cursor_sprite)
-
- g_hash_table_iter_init (&iter, cursor_priv->gpu_states);
- while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cursor_gpu_state))
-- {
-- unsigned int pending_buffer_idx;
--
-- pending_buffer_idx = get_pending_cursor_sprite_buffer_index (cursor_gpu_state);
-- g_clear_object (&cursor_gpu_state->buffers[pending_buffer_idx]);
-- cursor_gpu_state->pending_buffer_state =
-- META_CURSOR_BUFFER_STATE_INVALIDATED;
-- }
-+ g_clear_object (&cursor_gpu_state->buffer);
- }
-
- static void
-@@ -1404,35 +1324,7 @@ load_cursor_sprite_gbm_buffer_for_gpu (MetaCursorRendererNative *native,
- return;
- }
-
-- set_pending_cursor_sprite_buffer (cursor_sprite, gpu_kms, buffer);
--}
--
--static gboolean
--is_cursor_hw_state_valid (MetaCursorSprite *cursor_sprite,
-- MetaGpuKms *gpu_kms)
--{
-- MetaCursorNativePrivate *cursor_priv;
-- MetaCursorNativeGpuState *cursor_gpu_state;
--
-- cursor_priv = get_cursor_priv (cursor_sprite);
-- if (!cursor_priv)
-- return FALSE;
--
-- cursor_gpu_state = get_cursor_gpu_state (cursor_priv, gpu_kms);
-- if (!cursor_gpu_state)
-- return FALSE;
--
-- switch (cursor_gpu_state->pending_buffer_state)
-- {
-- case META_CURSOR_BUFFER_STATE_SET:
-- case META_CURSOR_BUFFER_STATE_NONE:
-- return TRUE;
-- case META_CURSOR_BUFFER_STATE_INVALIDATED:
-- return FALSE;
-- }
--
-- g_assert_not_reached ();
-- return FALSE;
-+ set_cursor_sprite_buffer (cursor_sprite, gpu_kms, buffer);
- }
-
- static gboolean
-@@ -1599,7 +1491,7 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer,
- if (!cursor_renderer_gpu_data || cursor_renderer_gpu_data->hw_cursor_broken)
- return;
-
-- if (is_cursor_hw_state_valid (cursor_sprite, gpu_kms) &&
-+ if (has_valid_cursor_sprite_buffer (cursor_sprite, gpu_kms) &&
- is_cursor_scale_and_transform_valid (renderer, cursor_sprite))
- return;
-
-@@ -1744,8 +1636,8 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer,
- return;
- }
-
-- set_pending_cursor_sprite_buffer (cursor_sprite, gpu_kms,
-- META_DRM_BUFFER (buffer_gbm));
-+ set_cursor_sprite_buffer (cursor_sprite, gpu_kms,
-+ META_DRM_BUFFER (buffer_gbm));
- }
- }
- #endif
-@@ -1769,7 +1661,7 @@ realize_cursor_sprite_from_xcursor_for_gpu (MetaCursorRenderer *renderer,
- if (!cursor_renderer_gpu_data || cursor_renderer_gpu_data->hw_cursor_broken)
- return;
-
-- if (is_cursor_hw_state_valid (cursor_sprite, gpu_kms) &&
-+ if (has_valid_cursor_sprite_buffer (cursor_sprite, gpu_kms) &&
- is_cursor_scale_and_transform_valid (renderer, cursor_sprite))
- return;
-
-diff --git a/src/backends/native/meta-kms-crtc.c b/src/backends/native/meta-kms-crtc.c
-index 8c2f8d783..f5e7d28d9 100644
---- a/src/backends/native/meta-kms-crtc.c
-+++ b/src/backends/native/meta-kms-crtc.c
-@@ -32,6 +32,12 @@ typedef struct _MetaKmsCrtcPropTable
- MetaKmsProp props[META_KMS_CRTC_N_PROPS];
- } MetaKmsCrtcPropTable;
-
-+typedef struct
-+{
-+ MetaDrmBuffer *front, *back;
-+ gboolean back_is_set;
-+} PlaneState;
-+
- struct _MetaKmsCrtc
- {
- GObject parent;
-@@ -44,6 +50,8 @@ struct _MetaKmsCrtc
- MetaKmsCrtcState current_state;
-
- MetaKmsCrtcPropTable prop_table;
-+
-+ GHashTable *plane_states;
- };
-
- G_DEFINE_TYPE (MetaKmsCrtc, meta_kms_crtc, G_TYPE_OBJECT)
-@@ -460,20 +468,91 @@ meta_kms_crtc_new (MetaKmsImplDevice *impl_device,
- return crtc;
- }
-
-+void
-+meta_kms_crtc_remember_plane_buffer (MetaKmsCrtc *crtc,
-+ uint32_t plane_id,
-+ MetaDrmBuffer *buffer)
-+{
-+ gpointer key = GUINT_TO_POINTER (plane_id);
-+ PlaneState *plane_state;
-+
-+ plane_state = g_hash_table_lookup (crtc->plane_states, key);
-+ if (plane_state == NULL)
-+ {
-+ plane_state = g_new0 (PlaneState, 1);
-+ g_hash_table_insert (crtc->plane_states, key, plane_state);
-+ }
-+
-+ plane_state->back_is_set = TRUE; /* note buffer may be NULL */
-+ g_set_object (&plane_state->back, buffer);
-+}
-+
-+static void
-+swap_plane_buffers (gpointer key,
-+ gpointer value,
-+ gpointer user_data)
-+{
-+ PlaneState *plane_state = value;
-+
-+ if (plane_state->back_is_set)
-+ {
-+ g_set_object (&plane_state->front, plane_state->back);
-+ g_clear_object (&plane_state->back);
-+ plane_state->back_is_set = FALSE;
-+ }
-+}
-+
-+void
-+meta_kms_crtc_on_scanout_started (MetaKmsCrtc *crtc)
-+{
-+ g_hash_table_foreach (crtc->plane_states, swap_plane_buffers, NULL);
-+}
-+
-+void
-+meta_kms_crtc_release_buffers (MetaKmsCrtc *crtc)
-+{
-+ g_hash_table_remove_all (crtc->plane_states);
-+}
-+
-+static void
-+meta_kms_crtc_dispose (GObject *object)
-+{
-+ MetaKmsCrtc *crtc = META_KMS_CRTC (object);
-+
-+ meta_kms_crtc_release_buffers (crtc);
-+
-+ G_OBJECT_CLASS (meta_kms_crtc_parent_class)->dispose (object);
-+}
-+
- static void
- meta_kms_crtc_finalize (GObject *object)
- {
- MetaKmsCrtc *crtc = META_KMS_CRTC (object);
-
- clear_gamma_state (&crtc->current_state);
-+ g_hash_table_unref (crtc->plane_states);
-
- G_OBJECT_CLASS (meta_kms_crtc_parent_class)->finalize (object);
- }
-
-+static void
-+destroy_plane_state (gpointer data)
-+{
-+ PlaneState *plane_state = data;
-+
-+ g_clear_object (&plane_state->front);
-+ g_clear_object (&plane_state->back);
-+ g_free (plane_state);
-+}
-+
- static void
- meta_kms_crtc_init (MetaKmsCrtc *crtc)
- {
- crtc->current_state.gamma.size = 0;
-+ crtc->plane_states = g_hash_table_new_full (NULL,
-+ NULL,
-+ NULL,
-+ destroy_plane_state);
- }
-
- static void
-@@ -481,5 +560,6 @@ meta_kms_crtc_class_init (MetaKmsCrtcClass *klass)
- {
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-+ object_class->dispose = meta_kms_crtc_dispose;
- object_class->finalize = meta_kms_crtc_finalize;
- }
-diff --git a/src/backends/native/meta-kms-crtc.h b/src/backends/native/meta-kms-crtc.h
-index 54801dd96..deafeb61e 100644
---- a/src/backends/native/meta-kms-crtc.h
-+++ b/src/backends/native/meta-kms-crtc.h
-@@ -25,6 +25,7 @@
- #include <xf86drmMode.h>
-
- #include "backends/native/meta-kms-types.h"
-+#include "backends/native/meta-drm-buffer.h"
- #include "core/util-private.h"
- #include "meta/boxes.h"
-
-@@ -84,4 +85,12 @@ MetaKmsCrtcGamma * meta_kms_crtc_gamma_new (MetaKmsCrtc *crtc,
- const uint16_t *green,
- const uint16_t *blue);
-
-+void meta_kms_crtc_remember_plane_buffer (MetaKmsCrtc *crtc,
-+ uint32_t plane_id,
-+ MetaDrmBuffer *buffer);
-+
-+void meta_kms_crtc_on_scanout_started (MetaKmsCrtc *crtc);
-+
-+void meta_kms_crtc_release_buffers (MetaKmsCrtc *crtc);
-+
- #endif /* META_KMS_CRTC_H */
-diff --git a/src/backends/native/meta-kms-impl-device-atomic.c b/src/backends/native/meta-kms-impl-device-atomic.c
-index 73dd8e697..787d05acd 100644
---- a/src/backends/native/meta-kms-impl-device-atomic.c
-+++ b/src/backends/native/meta-kms-impl-device-atomic.c
-@@ -431,6 +431,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device,
- {
- MetaKmsPlaneAssignment *plane_assignment = update_entry;
- MetaKmsPlane *plane = plane_assignment->plane;
-+ MetaKmsUpdateFlag flags = (MetaKmsUpdateFlag) user_data;
- MetaDrmBuffer *buffer;
- MetaKmsFbDamage *fb_damage;
- uint32_t prop_id;
-@@ -586,6 +587,12 @@ process_plane_assignment (MetaKmsImplDevice *impl_device,
- error))
- return FALSE;
- }
-+
-+ if (!(flags & META_KMS_UPDATE_FLAG_TEST_ONLY))
-+ meta_kms_crtc_remember_plane_buffer (plane_assignment->crtc,
-+ meta_kms_plane_get_id (plane),
-+ buffer);
-+
- return TRUE;
- }
-
-@@ -963,7 +970,7 @@ meta_kms_impl_device_atomic_process_update (MetaKmsImplDevice *impl_device,
- req,
- blob_ids,
- meta_kms_update_get_plane_assignments (update),
-- NULL,
-+ GUINT_TO_POINTER (flags),
- process_plane_assignment,
- &error))
- goto err;
-diff --git a/src/backends/native/meta-kms-impl-device-simple.c b/src/backends/native/meta-kms-impl-device-simple.c
-index ca4ffe245..679dd8600 100644
---- a/src/backends/native/meta-kms-impl-device-simple.c
-+++ b/src/backends/native/meta-kms-impl-device-simple.c
-@@ -470,6 +470,8 @@ process_mode_set (MetaKmsImplDevice *impl_device,
- return FALSE;
- }
-
-+ meta_kms_crtc_on_scanout_started (crtc);
-+
- if (drm_mode)
- {
- g_hash_table_replace (impl_device_simple->cached_mode_sets,
-@@ -534,7 +536,7 @@ is_timestamp_earlier_than (uint64_t ts1,
- typedef struct _RetryPageFlipData
- {
- MetaKmsCrtc *crtc;
-- uint32_t fb_id;
-+ MetaDrmBuffer *fb;
- MetaKmsPageFlipData *page_flip_data;
- float refresh_rate;
- uint64_t retry_time_us;
-@@ -547,6 +549,7 @@ retry_page_flip_data_free (RetryPageFlipData *retry_page_flip_data)
- g_assert (!retry_page_flip_data->page_flip_data);
- g_clear_pointer (&retry_page_flip_data->custom_page_flip,
- meta_kms_custom_page_flip_free);
-+ g_clear_object (&retry_page_flip_data->fb);
- g_free (retry_page_flip_data);
- }
-
-@@ -614,16 +617,21 @@ retry_page_flips (gpointer user_data)
- }
- else
- {
-+ uint32_t fb_id =
-+ retry_page_flip_data->fb ?
-+ meta_drm_buffer_get_fb_id (retry_page_flip_data->fb) :
-+ 0;
-+
- meta_topic (META_DEBUG_KMS,
- "[simple] Retrying page flip on CRTC %u (%s) with %u",
- meta_kms_crtc_get_id (crtc),
- meta_kms_impl_device_get_path (impl_device),
-- retry_page_flip_data->fb_id);
-+ fb_id);
-
- fd = meta_kms_impl_device_get_fd (impl_device);
- ret = drmModePageFlip (fd,
- meta_kms_crtc_get_id (crtc),
-- retry_page_flip_data->fb_id,
-+ fb_id,
- DRM_MODE_PAGE_FLIP_EVENT,
- retry_page_flip_data->page_flip_data);
- }
-@@ -710,7 +718,7 @@ retry_page_flips (gpointer user_data)
- static void
- schedule_retry_page_flip (MetaKmsImplDeviceSimple *impl_device_simple,
- MetaKmsCrtc *crtc,
-- uint32_t fb_id,
-+ MetaDrmBuffer *fb,
- float refresh_rate,
- MetaKmsPageFlipData *page_flip_data,
- MetaKmsCustomPageFlip *custom_page_flip)
-@@ -725,7 +733,7 @@ schedule_retry_page_flip (MetaKmsImplDeviceSimple *impl_device_simple,
- retry_page_flip_data = g_new0 (RetryPageFlipData, 1);
- *retry_page_flip_data = (RetryPageFlipData) {
- .crtc = crtc,
-- .fb_id = fb_id,
-+ .fb = fb ? g_object_ref (fb) : NULL,
- .page_flip_data = page_flip_data,
- .refresh_rate = refresh_rate,
- .retry_time_us = retry_time_us,
-@@ -859,6 +867,8 @@ mode_set_fallback (MetaKmsImplDeviceSimple *impl_device_simple,
- return FALSE;
- }
-
-+ meta_kms_crtc_on_scanout_started (crtc);
-+
- if (!impl_device_simple->mode_set_fallback_feedback_source)
- {
- GSource *source;
-@@ -983,20 +993,20 @@ dispatch_page_flip (MetaKmsImplDevice *impl_device,
- cached_mode_set = get_cached_mode_set (impl_device_simple, crtc);
- if (cached_mode_set)
- {
-- uint32_t fb_id;
-+ MetaDrmBuffer *fb;
- drmModeModeInfo *drm_mode;
- float refresh_rate;
-
- if (plane_assignment)
-- fb_id = meta_drm_buffer_get_fb_id (plane_assignment->buffer);
-+ fb = plane_assignment->buffer;
- else
-- fb_id = 0;
-+ fb = NULL;
- drm_mode = cached_mode_set->drm_mode;
- refresh_rate = meta_calculate_drm_mode_refresh_rate (drm_mode);
- meta_kms_impl_device_hold_fd (impl_device);
- schedule_retry_page_flip (impl_device_simple,
- crtc,
-- fb_id,
-+ fb,
- refresh_rate,
- page_flip_data,
- g_steal_pointer (&custom_page_flip));
-@@ -1286,7 +1296,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device,
- {
- case META_KMS_PLANE_TYPE_PRIMARY:
- /* Handled as part of the mode-set and page flip. */
-- return TRUE;
-+ goto assigned;
- case META_KMS_PLANE_TYPE_CURSOR:
- if (!process_cursor_plane_assignment (impl_device, update,
- plane_assignment,
-@@ -1300,7 +1310,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device,
- }
- else
- {
-- return TRUE;
-+ goto assigned;
- }
- case META_KMS_PLANE_TYPE_OVERLAY:
- error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED,
-@@ -1313,6 +1323,12 @@ process_plane_assignment (MetaKmsImplDevice *impl_device,
- }
-
- g_assert_not_reached ();
-+
-+assigned:
-+ meta_kms_crtc_remember_plane_buffer (plane_assignment->crtc,
-+ meta_kms_plane_get_id (plane),
-+ plane_assignment->buffer);
-+ return TRUE;
- }
-
- static gboolean
-diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c
-index ec1a0e5a4..afea2c486 100644
---- a/src/backends/native/meta-kms-impl-device.c
-+++ b/src/backends/native/meta-kms-impl-device.c
-@@ -1028,8 +1028,12 @@ meta_kms_impl_device_init_mode_setting (MetaKmsImplDevice *impl_device,
- void
- meta_kms_impl_device_prepare_shutdown (MetaKmsImplDevice *impl_device)
- {
-+ MetaKmsImplDevicePrivate *priv =
-+ meta_kms_impl_device_get_instance_private (impl_device);
- MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device);
-
-+ g_list_foreach (priv->crtcs, (GFunc) meta_kms_crtc_release_buffers, NULL);
-+
- if (klass->prepare_shutdown)
- klass->prepare_shutdown (impl_device);
-
-diff --git a/src/backends/native/meta-kms-page-flip.c b/src/backends/native/meta-kms-page-flip.c
-index 817f4e7c8..148d23740 100644
---- a/src/backends/native/meta-kms-page-flip.c
-+++ b/src/backends/native/meta-kms-page-flip.c
-@@ -24,6 +24,7 @@
- #include "backends/native/meta-kms-impl.h"
- #include "backends/native/meta-kms-private.h"
- #include "backends/native/meta-kms-update.h"
-+#include "backends/native/meta-kms-crtc.h"
-
- typedef struct _MetaKmsPageFlipClosure
- {
-@@ -149,6 +150,8 @@ meta_kms_page_flip_data_flipped (MetaKms *kms,
-
- meta_assert_not_in_kms_impl (kms);
-
-+ meta_kms_crtc_on_scanout_started (page_flip_data->crtc);
-+
- for (l = page_flip_data->closures; l; l = l->next)
- {
- MetaKmsPageFlipClosure *closure = l->data;
-diff --git a/src/backends/native/meta-kms-update-private.h b/src/backends/native/meta-kms-update-private.h
-index a613cbc5d..1d964ff21 100644
---- a/src/backends/native/meta-kms-update-private.h
-+++ b/src/backends/native/meta-kms-update-private.h
-@@ -132,6 +132,12 @@ uint64_t meta_kms_update_get_sequence_number (MetaKmsUpdate *update);
- META_EXPORT_TEST
- MetaKmsDevice * meta_kms_update_get_device (MetaKmsUpdate *update);
-
-+gboolean meta_kms_update_includes_crtc (MetaKmsUpdate *update,
-+ MetaKmsCrtc *crtc);
-+
-+void meta_kms_update_include_crtc (MetaKmsUpdate *update,
-+ MetaKmsCrtc *crtc);
-+
- void meta_kms_plane_assignment_set_rotation (MetaKmsPlaneAssignment *plane_assignment,
- uint64_t rotation);
-
-diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c
-index 53fc92eb8..0d457c49e 100644
---- a/src/backends/native/meta-kms-update.c
-+++ b/src/backends/native/meta-kms-update.c
-@@ -25,12 +25,14 @@
- #include "backends/meta-display-config-shared.h"
- #include "backends/native/meta-kms-connector.h"
- #include "backends/native/meta-kms-crtc.h"
-+#include "backends/native/meta-kms-device.h"
- #include "backends/native/meta-kms-mode-private.h"
- #include "backends/native/meta-kms-plane.h"
-
- struct _MetaKmsUpdate
- {
- MetaKmsDevice *device;
-+ GHashTable *crtcs;
-
- gboolean is_locked;
- uint64_t sequence_number;
-@@ -149,6 +151,7 @@ static void
- meta_kms_plane_assignment_free (MetaKmsPlaneAssignment *plane_assignment)
- {
- g_clear_pointer (&plane_assignment->fb_damage, meta_kms_fb_damage_free);
-+ g_clear_object (&plane_assignment->buffer);
- g_free (plane_assignment);
- }
-
-@@ -228,7 +231,7 @@ meta_kms_update_assign_plane (MetaKmsUpdate *update,
- .update = update,
- .crtc = crtc,
- .plane = plane,
-- .buffer = buffer,
-+ .buffer = g_object_ref (buffer),
- .src_rect = src_rect,
- .dst_rect = dst_rect,
- .flags = flags,
-@@ -237,6 +240,8 @@ meta_kms_update_assign_plane (MetaKmsUpdate *update,
- update->plane_assignments = g_list_prepend (update->plane_assignments,
- plane_assignment);
-
-+ g_hash_table_add (update->crtcs, crtc);
-+
- return plane_assignment;
- }
-
-@@ -262,6 +267,8 @@ meta_kms_update_unassign_plane (MetaKmsUpdate *update,
- update->plane_assignments = g_list_prepend (update->plane_assignments,
- plane_assignment);
-
-+ g_hash_table_add (update->crtcs, crtc);
-+
- return plane_assignment;
- }
-
-@@ -284,6 +291,8 @@ meta_kms_update_mode_set (MetaKmsUpdate *update,
- };
-
- update->mode_sets = g_list_prepend (update->mode_sets, mode_set);
-+
-+ g_hash_table_add (update->crtcs, crtc);
- }
-
- static MetaKmsConnectorUpdate *
-@@ -292,6 +301,8 @@ ensure_connector_update (MetaKmsUpdate *update,
- {
- GList *l;
- MetaKmsConnectorUpdate *connector_update;
-+ MetaKmsDevice *device;
-+ const MetaKmsConnectorState *state;
-
- for (l = update->connector_updates; l; l = l->next)
- {
-@@ -306,6 +317,23 @@ ensure_connector_update (MetaKmsUpdate *update,
-
- update->connector_updates = g_list_prepend (update->connector_updates,
- connector_update);
-+ device = meta_kms_connector_get_device (connector);
-+ state = meta_kms_connector_get_current_state (connector);
-+ if (device && state && state->current_crtc_id)
-+ {
-+ GList *l;
-+
-+ for (l = meta_kms_device_get_crtcs (device); l; l = l->next)
-+ {
-+ MetaKmsCrtc *kms_crtc = l->data;
-+
-+ if (meta_kms_crtc_get_id (kms_crtc) == state->current_crtc_id)
-+ {
-+ g_hash_table_add (update->crtcs, kms_crtc);
-+ break;
-+ }
-+ }
-+ }
-
- return connector_update;
- }
-@@ -402,6 +430,8 @@ meta_kms_update_set_crtc_gamma (MetaKmsUpdate *update,
- gamma = meta_kms_crtc_gamma_new (crtc, size, red, green, blue);
-
- update->crtc_gammas = g_list_prepend (update->crtc_gammas, gamma);
-+
-+ g_hash_table_add (update->crtcs, crtc);
- }
-
- void
-@@ -665,6 +695,20 @@ meta_kms_update_get_device (MetaKmsUpdate *update)
- return update->device;
- }
-
-+gboolean
-+meta_kms_update_includes_crtc (MetaKmsUpdate *update,
-+ MetaKmsCrtc *crtc)
-+{
-+ return g_hash_table_contains (update->crtcs, crtc);
-+}
-+
-+void
-+meta_kms_update_include_crtc (MetaKmsUpdate *update,
-+ MetaKmsCrtc *crtc)
-+{
-+ g_hash_table_add (update->crtcs, crtc);
-+}
-+
- MetaKmsCustomPageFlip *
- meta_kms_update_take_custom_page_flip_func (MetaKmsUpdate *update)
- {
-@@ -693,12 +737,15 @@ meta_kms_update_new (MetaKmsDevice *device)
- update->device = device;
- update->sequence_number = sequence_number++;
-
-+ update->crtcs = g_hash_table_new (NULL, NULL);
-+
- return update;
- }
-
- void
- meta_kms_update_free (MetaKmsUpdate *update)
- {
-+ g_hash_table_destroy (update->crtcs);
- g_list_free_full (update->result_listeners,
- (GDestroyNotify) meta_kms_result_listener_free);
- g_list_free_full (update->plane_assignments,
-diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c
-index 052ec8a65..f05cbf9df 100644
---- a/src/backends/native/meta-kms.c
-+++ b/src/backends/native/meta-kms.c
-@@ -23,6 +23,7 @@
- #include "backends/native/meta-kms-private.h"
-
- #include "backends/native/meta-backend-native.h"
-+#include "backends/native/meta-kms-crtc.h"
- #include "backends/native/meta-kms-device-private.h"
- #include "backends/native/meta-kms-impl.h"
- #include "backends/native/meta-kms-update-private.h"
-@@ -177,10 +178,17 @@ struct _MetaKms
-
- GList *pending_callbacks;
- guint callback_source_id;
-+
-+ gboolean shutting_down;
- };
-
- G_DEFINE_TYPE (MetaKms, meta_kms, G_TYPE_OBJECT)
-
-+static MetaKmsFeedback *
-+meta_kms_post_update_sync (MetaKms *kms,
-+ MetaKmsUpdate *update,
-+ MetaKmsUpdateFlag flags);
-+
- void
- meta_kms_discard_pending_updates (MetaKms *kms)
- {
-@@ -247,23 +255,115 @@ meta_kms_take_pending_update (MetaKms *kms,
- return NULL;
- }
-
-+MetaKmsUpdate *
-+meta_kms_ensure_pending_update_for_crtc (MetaKms *kms,
-+ MetaKmsCrtc *crtc)
-+{
-+ MetaKmsUpdate *update;
-+
-+ update = meta_kms_get_pending_update_for_crtc (kms, crtc);
-+ if (update == NULL)
-+ {
-+ update = meta_kms_update_new (meta_kms_crtc_get_device (crtc));
-+ meta_kms_update_include_crtc (update, crtc);
-+ meta_kms_add_pending_update (kms, update);
-+ }
-+
-+ return update;
-+}
-+
-+static MetaKmsUpdate *
-+meta_kms_find_compatible_update_for_crtc (MetaKms *kms,
-+ MetaKmsCrtc *crtc,
-+ gboolean take)
-+{
-+ MetaKmsDevice *device;
-+ MetaKmsUpdate *update;
-+ GList *l;
-+
-+ for (l = kms->pending_updates; l; l = l->next)
-+ {
-+ update = l->data;
-+ if (meta_kms_update_includes_crtc (update, crtc))
-+ goto found;
-+ }
-+
-+ device = meta_kms_crtc_get_device (crtc);
-+
-+ for (l = kms->pending_updates; l; l = l->next)
-+ {
-+ update = l->data;
-+ if (meta_kms_update_get_device (update) == device &&
-+ meta_kms_update_get_mode_sets (update))
-+ goto found;
-+ }
-+
-+ return NULL;
-+
-+found:
-+ if (take)
-+ kms->pending_updates = g_list_delete_link (kms->pending_updates, l);
-+ return update;
-+}
-+
-+MetaKmsUpdate *
-+meta_kms_get_pending_update_for_crtc (MetaKms *kms,
-+ MetaKmsCrtc *crtc)
-+{
-+ return meta_kms_find_compatible_update_for_crtc (kms, crtc, FALSE);
-+}
-+
-+static MetaKmsUpdate *
-+meta_kms_take_pending_update_for_crtc (MetaKms *kms,
-+ MetaKmsCrtc *crtc)
-+{
-+ return meta_kms_find_compatible_update_for_crtc (kms, crtc, TRUE);
-+}
-+
- MetaKmsFeedback *
- meta_kms_post_pending_update_sync (MetaKms *kms,
- MetaKmsDevice *device,
- MetaKmsUpdateFlag flags)
- {
- MetaKmsUpdate *update;
-+
-+ update = meta_kms_take_pending_update (kms, device);
-+ if (!update)
-+ return NULL;
-+
-+ return meta_kms_post_update_sync (kms, update, flags);
-+}
-+
-+MetaKmsFeedback *
-+meta_kms_post_pending_update_for_crtc_sync (MetaKms *kms,
-+ MetaKmsCrtc *crtc,
-+ MetaKmsUpdateFlag flags)
-+{
-+ MetaKmsUpdate *update;
-+
-+ update = meta_kms_take_pending_update_for_crtc (kms, crtc);
-+ if (!update)
-+ return NULL;
-+
-+ return meta_kms_post_update_sync (kms, update, flags);
-+}
-+
-+static MetaKmsFeedback *
-+meta_kms_post_update_sync (MetaKms *kms,
-+ MetaKmsUpdate *update,
-+ MetaKmsUpdateFlag flags)
-+{
-+ MetaKmsDevice *device = meta_kms_update_get_device (update);
- MetaKmsFeedback *feedback;
- GList *result_listeners;
- GList *l;
-
-+ if (kms->shutting_down)
-+ return NULL;
-+
- COGL_TRACE_BEGIN_SCOPED (MetaKmsPostUpdateSync,
- "KMS (post update)");
-
-- update = meta_kms_take_pending_update (kms, device);
-- if (!update)
-- return NULL;
--
- meta_kms_update_lock (update);
-
- feedback = meta_kms_device_process_update_sync (device, update, flags);
-@@ -752,6 +852,8 @@ prepare_shutdown_in_impl (MetaKmsImpl *impl,
- void
- meta_kms_prepare_shutdown (MetaKms *kms)
- {
-+ kms->shutting_down = TRUE;
-+
- meta_kms_run_impl_task_sync (kms, prepare_shutdown_in_impl, NULL, NULL);
- flush_callbacks (kms);
- }
-diff --git a/src/backends/native/meta-kms.h b/src/backends/native/meta-kms.h
-index bd9fe5cea..84f1bed49 100644
---- a/src/backends/native/meta-kms.h
-+++ b/src/backends/native/meta-kms.h
-@@ -39,9 +39,15 @@ void meta_kms_discard_pending_updates (MetaKms *kms);
- MetaKmsUpdate * meta_kms_ensure_pending_update (MetaKms *kms,
- MetaKmsDevice *device);
-
-+MetaKmsUpdate * meta_kms_ensure_pending_update_for_crtc (MetaKms *kms,
-+ MetaKmsCrtc *crtc);
-+
- MetaKmsUpdate * meta_kms_get_pending_update (MetaKms *kms,
- MetaKmsDevice *device);
-
-+MetaKmsUpdate * meta_kms_get_pending_update_for_crtc (MetaKms *kms,
-+ MetaKmsCrtc *crtc);
-+
- MetaKmsFeedback * meta_kms_post_pending_update_sync (MetaKms *kms,
- MetaKmsDevice *device,
- MetaKmsUpdateFlag flags);
-@@ -49,6 +55,10 @@ MetaKmsFeedback * meta_kms_post_pending_update_sync (MetaKms *kms,
- MetaKmsFeedback * meta_kms_post_test_update_sync (MetaKms *kms,
- MetaKmsUpdate *update);
-
-+MetaKmsFeedback * meta_kms_post_pending_update_for_crtc_sync (MetaKms *kms,
-+ MetaKmsCrtc *device,
-+ MetaKmsUpdateFlag flags);
-+
- void meta_kms_discard_pending_page_flips (MetaKms *kms);
-
- void meta_kms_notify_modes_set (MetaKms *kms);
-diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c
-index 36d6e291e..fbe3e26ca 100644
---- a/src/backends/native/meta-onscreen-native.c
-+++ b/src/backends/native/meta-onscreen-native.c
-@@ -67,13 +67,12 @@ typedef struct _MetaOnscreenNativeSecondaryGpuState
-
- struct {
- struct gbm_surface *surface;
-- MetaDrmBuffer *current_fb;
-- MetaDrmBuffer *next_fb;
- } gbm;
-
- struct {
- MetaDrmBufferDumb *current_dumb_fb;
- MetaDrmBufferDumb *dumb_fbs[2];
-+ MetaDrmBuffer *source_fbs[2];
- } cpu;
-
- gboolean noted_primary_gpu_copy_ok;
-@@ -94,8 +93,8 @@ struct _MetaOnscreenNative
-
- struct {
- struct gbm_surface *surface;
-- MetaDrmBuffer *current_fb;
- MetaDrmBuffer *next_fb;
-+ MetaDrmBuffer *stalled_fb;
- } gbm;
-
- #ifdef HAVE_EGL_DEVICE
-@@ -107,69 +106,25 @@ struct _MetaOnscreenNative
- #endif
-
- MetaRendererView *view;
-+
-+ unsigned int swaps_pending;
-+ struct {
-+ int *rectangles; /* 4 x n_rectangles */
-+ int n_rectangles;
-+ } next_post;
- };
-
- G_DEFINE_TYPE (MetaOnscreenNative, meta_onscreen_native,
- COGL_TYPE_ONSCREEN_EGL)
-
-+static void
-+try_post_latest_swap (CoglOnscreen *onscreen);
-+
- static gboolean
- init_secondary_gpu_state (MetaRendererNative *renderer_native,
- CoglOnscreen *onscreen,
- GError **error);
-
--static void
--swap_secondary_drm_fb (CoglOnscreen *onscreen)
--{
-- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
-- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
--
-- secondary_gpu_state = onscreen_native->secondary_gpu_state;
-- if (!secondary_gpu_state)
-- return;
--
-- g_set_object (&secondary_gpu_state->gbm.current_fb,
-- secondary_gpu_state->gbm.next_fb);
-- g_clear_object (&secondary_gpu_state->gbm.next_fb);
--}
--
--static void
--free_current_secondary_bo (CoglOnscreen *onscreen)
--{
-- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
-- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
--
-- secondary_gpu_state = onscreen_native->secondary_gpu_state;
-- if (!secondary_gpu_state)
-- return;
--
-- g_clear_object (&secondary_gpu_state->gbm.current_fb);
--}
--
--static void
--free_current_bo (CoglOnscreen *onscreen)
--{
-- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
--
-- g_clear_object (&onscreen_native->gbm.current_fb);
-- free_current_secondary_bo (onscreen);
--}
--
--static void
--meta_onscreen_native_swap_drm_fb (CoglOnscreen *onscreen)
--{
-- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
--
-- if (!onscreen_native->gbm.next_fb)
-- return;
--
-- free_current_bo (onscreen);
--
-- g_set_object (&onscreen_native->gbm.current_fb, onscreen_native->gbm.next_fb);
-- g_clear_object (&onscreen_native->gbm.next_fb);
--
-- swap_secondary_drm_fb (onscreen);
--}
--
- static void
- maybe_update_frame_info (MetaCrtc *crtc,
- CoglFrameInfo *frame_info,
-@@ -205,7 +160,7 @@ meta_onscreen_native_notify_frame_complete (CoglOnscreen *onscreen)
-
- info = cogl_onscreen_pop_head_frame_info (onscreen);
-
-- g_assert (!cogl_onscreen_peek_head_frame_info (onscreen));
-+ g_assert (info);
-
- _cogl_onscreen_notify_frame_sync (onscreen, info);
- _cogl_onscreen_notify_complete (onscreen, info);
-@@ -234,7 +189,7 @@ notify_view_crtc_presented (MetaRendererView *view,
- maybe_update_frame_info (crtc, frame_info, time_us, flags, sequence);
-
- meta_onscreen_native_notify_frame_complete (onscreen);
-- meta_onscreen_native_swap_drm_fb (onscreen);
-+ try_post_latest_swap (onscreen);
- }
-
- static int64_t
-@@ -296,6 +251,7 @@ page_flip_feedback_ready (MetaKmsCrtc *kms_crtc,
- frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
-
- meta_onscreen_native_notify_frame_complete (onscreen);
-+ try_post_latest_swap (onscreen);
- }
-
- static void
-@@ -345,7 +301,7 @@ page_flip_feedback_discarded (MetaKmsCrtc *kms_crtc,
- frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
-
- meta_onscreen_native_notify_frame_complete (onscreen);
-- meta_onscreen_native_swap_drm_fb (onscreen);
-+ try_post_latest_swap (onscreen);
- }
-
- static const MetaKmsPageFlipListenerVtable page_flip_listener_vtable = {
-@@ -406,18 +362,40 @@ custom_egl_stream_page_flip (gpointer custom_page_flip_data,
- }
- #endif /* HAVE_EGL_DEVICE */
-
--void
--meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen)
-+static void
-+drop_stalled_swap (CoglOnscreen *onscreen)
- {
-+ MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
- CoglFrameInfo *frame_info;
-
-- meta_onscreen_native_swap_drm_fb (onscreen);
-+ /* Remember we can't compare stalled_fb because it's not used by
-+ * META_RENDERER_NATIVE_MODE_EGL_DEVICE. So we judge stalled to be whenever
-+ * swaps_pending > 1.
-+ */
-+ if (onscreen_native->swaps_pending <= 1)
-+ return;
-+
-+ onscreen_native->swaps_pending--;
-+
-+ g_clear_object (&onscreen_native->gbm.stalled_fb);
-
- frame_info = cogl_onscreen_peek_tail_frame_info (onscreen);
- frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
- meta_onscreen_native_notify_frame_complete (onscreen);
- }
-
-+void
-+meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen)
-+{
-+ drop_stalled_swap (onscreen);
-+
-+ /* If the monitor just woke up and the shell is fully idle (has nothing
-+ * more to swap) then we just woke to an indefinitely black screen. Let's
-+ * fix that using the last swap (which is never classified as "stalled").
-+ */
-+ try_post_latest_swap (onscreen);
-+}
-+
- static void
- meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
- MetaRendererView *view,
-@@ -436,8 +414,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
- MetaKmsDevice *kms_device;
- MetaKms *kms;
- MetaKmsUpdate *kms_update;
-- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state = NULL;
-- MetaDrmBuffer *buffer;
-+ g_autoptr (MetaDrmBuffer) buffer = NULL;
- MetaKmsPlaneAssignment *plane_assignment;
-
- COGL_TRACE_BEGIN_SCOPED (MetaOnscreenNativeFlipCrtcs,
-@@ -446,7 +423,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
- gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
- kms_device = meta_gpu_kms_get_kms_device (gpu_kms);
- kms = meta_kms_device_get_kms (kms_device);
-- kms_update = meta_kms_ensure_pending_update (kms, kms_device);
-+ kms_update = meta_kms_ensure_pending_update_for_crtc (kms, kms_crtc);
-
- g_assert (meta_gpu_kms_is_crtc_active (gpu_kms, crtc));
-
-@@ -455,15 +432,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
- switch (renderer_gpu_data->mode)
- {
- case META_RENDERER_NATIVE_MODE_GBM:
-- if (gpu_kms == render_gpu)
-- {
-- buffer = onscreen_native->gbm.next_fb;
-- }
-- else
-- {
-- secondary_gpu_state = onscreen_native->secondary_gpu_state;
-- buffer = secondary_gpu_state->gbm.next_fb;
-- }
-+ buffer = g_steal_pointer (&onscreen_native->gbm.next_fb);
-
- plane_assignment = meta_crtc_kms_assign_primary_plane (crtc_kms,
- buffer,
-@@ -509,7 +478,7 @@ meta_onscreen_native_set_crtc_mode (CoglOnscreen *onscreen,
- COGL_TRACE_BEGIN_SCOPED (MetaOnscreenNativeSetCrtcModes,
- "Onscreen (set CRTC modes)");
-
-- kms_update = meta_kms_ensure_pending_update (kms, kms_device);
-+ kms_update = meta_kms_ensure_pending_update_for_crtc (kms, kms_crtc);
-
- switch (renderer_gpu_data->mode)
- {
-@@ -535,13 +504,41 @@ meta_onscreen_native_set_crtc_mode (CoglOnscreen *onscreen,
- kms_update);
- }
-
-+static void
-+hold_primary_gpu_fb_for_secondary_gpu_scanout (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
-+ MetaDrmBuffer *primary_gpu_fb,
-+ MetaDrmBuffer *secondary_gpu_fb)
-+{
-+ if (META_IS_DRM_BUFFER_DUMB (secondary_gpu_fb))
-+ {
-+ MetaDrmBufferDumb *dumb_fb = META_DRM_BUFFER_DUMB (secondary_gpu_fb);
-+ int i;
-+ const int n = G_N_ELEMENTS (secondary_gpu_state->cpu.dumb_fbs);
-+
-+ for (i = 0; i < n; i++)
-+ {
-+ if (dumb_fb == secondary_gpu_state->cpu.dumb_fbs[i])
-+ {
-+ g_set_object (&secondary_gpu_state->cpu.source_fbs[i],
-+ primary_gpu_fb);
-+ break;
-+ }
-+ }
-+
-+ g_warn_if_fail (i < n);
-+ }
-+}
-+
- static void
- secondary_gpu_release_dumb (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
- {
- unsigned i;
-
- for (i = 0; i < G_N_ELEMENTS (secondary_gpu_state->cpu.dumb_fbs); i++)
-- g_clear_object (&secondary_gpu_state->cpu.dumb_fbs[i]);
-+ {
-+ g_clear_object (&secondary_gpu_state->cpu.dumb_fbs[i]);
-+ g_clear_object (&secondary_gpu_state->cpu.source_fbs[i]);
-+ }
- }
-
- static void
-@@ -566,8 +563,6 @@ secondary_gpu_state_free (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_sta
- NULL);
- }
-
-- g_clear_object (&secondary_gpu_state->gbm.current_fb);
-- g_clear_object (&secondary_gpu_state->gbm.next_fb);
- g_clear_pointer (&secondary_gpu_state->gbm.surface, gbm_surface_destroy);
-
- secondary_gpu_release_dumb (secondary_gpu_state);
-@@ -575,11 +570,11 @@ secondary_gpu_state_free (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_sta
- g_free (secondary_gpu_state);
- }
-
--static gboolean
-+static MetaDrmBuffer *
- import_shared_framebuffer (CoglOnscreen *onscreen,
-- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
-+ MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
-+ MetaDrmBuffer *primary_gpu_fb)
- {
-- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
- MetaRenderDevice *render_device;
- g_autoptr (GError) error = NULL;
- MetaDrmBuffer *imported_buffer;
-@@ -587,7 +582,7 @@ import_shared_framebuffer (CoglOnscreen *onscreen,
- render_device = secondary_gpu_state->renderer_gpu_data->render_device;
- imported_buffer =
- meta_render_device_import_dma_buf (render_device,
-- onscreen_native->gbm.next_fb,
-+ primary_gpu_fb,
- &error);
- if (!imported_buffer)
- {
-@@ -601,16 +596,9 @@ import_shared_framebuffer (CoglOnscreen *onscreen,
- META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE);
- secondary_gpu_state->import_status =
- META_SHARED_FRAMEBUFFER_IMPORT_STATUS_FAILED;
-- return FALSE;
-+ return NULL;
- }
-
-- /*
-- * next_fb may already contain a fallback buffer, so clear it only
-- * when we are sure to succeed.
-- */
-- g_clear_object (&secondary_gpu_state->gbm.next_fb);
-- secondary_gpu_state->gbm.next_fb = imported_buffer;
--
- if (secondary_gpu_state->import_status ==
- META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE)
- {
-@@ -627,16 +615,16 @@ import_shared_framebuffer (CoglOnscreen *onscreen,
-
- secondary_gpu_state->import_status =
- META_SHARED_FRAMEBUFFER_IMPORT_STATUS_OK;
-- return TRUE;
-+ return imported_buffer;
- }
-
--static void
-+static MetaDrmBuffer *
- copy_shared_framebuffer_gpu (CoglOnscreen *onscreen,
- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
- MetaRendererNativeGpuData *renderer_gpu_data,
-- gboolean *egl_context_changed)
-+ gboolean *egl_context_changed,
-+ MetaDrmBuffer *primary_gpu_fb)
- {
-- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
- MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
- MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
- MetaGles3 *gles3 = meta_renderer_native_get_gles3 (renderer_native);
-@@ -652,9 +640,6 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen,
- COGL_TRACE_BEGIN_SCOPED (CopySharedFramebufferSecondaryGpu,
- "FB Copy (secondary GPU)");
-
-- g_warn_if_fail (secondary_gpu_state->gbm.next_fb == NULL);
-- g_clear_object (&secondary_gpu_state->gbm.next_fb);
--
- render_device = renderer_gpu_data->render_device;
- egl_display = meta_render_device_get_egl_display (render_device);
-
-@@ -667,13 +652,13 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen,
- {
- g_warning ("Failed to make current: %s", error->message);
- g_error_free (error);
-- return;
-+ return NULL;
- }
-
- *egl_context_changed = TRUE;
-
-
-- buffer_gbm = META_DRM_BUFFER_GBM (onscreen_native->gbm.next_fb);
-+ buffer_gbm = META_DRM_BUFFER_GBM (primary_gpu_fb);
- bo = meta_drm_buffer_gbm_get_bo (buffer_gbm);
- if (!meta_renderer_native_gles3_blit_shared_bo (egl,
- gles3,
-@@ -685,7 +670,7 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen,
- {
- g_warning ("Failed to blit shared framebuffer: %s", error->message);
- g_error_free (error);
-- return;
-+ return NULL;
- }
-
- if (!meta_egl_swap_buffers (egl,
-@@ -695,7 +680,7 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen,
- {
- g_warning ("Failed to swap buffers: %s", error->message);
- g_error_free (error);
-- return;
-+ return NULL;
- }
-
- use_modifiers = meta_renderer_native_use_modifiers (renderer_native);
-@@ -715,10 +700,10 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen,
- g_warning ("meta_drm_buffer_gbm_new_lock_front failed: %s",
- error->message);
- g_error_free (error);
-- return;
-+ return NULL;
- }
-
-- secondary_gpu_state->gbm.next_fb = META_DRM_BUFFER (buffer_gbm);
-+ return META_DRM_BUFFER (buffer_gbm);
- }
-
- static MetaDrmBufferDumb *
-@@ -733,7 +718,7 @@ secondary_gpu_get_next_dumb_buffer (MetaOnscreenNativeSecondaryGpuState *seconda
- return secondary_gpu_state->cpu.dumb_fbs[0];
- }
-
--static gboolean
-+static MetaDrmBuffer *
- copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscreen,
- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
- const int *rectangles,
-@@ -759,13 +744,13 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre
-
- if (!secondary_gpu_state ||
- secondary_gpu_state->egl_surface == EGL_NO_SURFACE)
-- return FALSE;
-+ return NULL;
-
- primary_gpu = meta_renderer_native_get_primary_gpu (renderer_native);
- primary_gpu_data =
- meta_renderer_native_get_gpu_data (renderer_native, primary_gpu);
- if (!primary_gpu_data->secondary.has_EGL_EXT_image_dma_buf_import_modifiers)
-- return FALSE;
-+ return NULL;
-
- buffer_dumb = secondary_gpu_get_next_dumb_buffer (secondary_gpu_state);
- buffer = META_DRM_BUFFER (buffer_dumb);
-@@ -788,7 +773,7 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre
- {
- meta_topic (META_DEBUG_KMS,
- "Failed to create DMA buffer: %s", error->message);
-- return FALSE;
-+ return NULL;
- }
-
- dmabuf_fb =
-@@ -806,7 +791,7 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre
- meta_topic (META_DEBUG_KMS,
- "Failed to create DMA buffer for blitting: %s",
- error->message);
-- return FALSE;
-+ return NULL;
- }
- /* Limit the number of individual copies to 16 */
- #define MAX_RECTS 16
-@@ -819,7 +804,7 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre
- &error))
- {
- g_object_unref (dmabuf_fb);
-- return FALSE;
-+ return NULL;
- }
- }
- else
-@@ -836,20 +821,19 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre
- &error))
- {
- g_object_unref (dmabuf_fb);
-- return FALSE;
-+ return NULL;
- }
- }
- }
-
- g_object_unref (dmabuf_fb);
-
-- g_set_object (&secondary_gpu_state->gbm.next_fb, buffer);
- secondary_gpu_state->cpu.current_dumb_fb = buffer_dumb;
-
-- return TRUE;
-+ return g_object_ref (buffer);
- }
-
--static void
-+static MetaDrmBuffer *
- copy_shared_framebuffer_cpu (CoglOnscreen *onscreen,
- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
- MetaRendererNativeGpuData *renderer_gpu_data)
-@@ -901,17 +885,19 @@ copy_shared_framebuffer_cpu (CoglOnscreen *onscreen,
-
- cogl_object_unref (dumb_bitmap);
-
-- g_set_object (&secondary_gpu_state->gbm.next_fb, buffer);
- secondary_gpu_state->cpu.current_dumb_fb = buffer_dumb;
-+
-+ return g_object_ref (buffer);
- }
-
--static void
-+static MetaDrmBuffer *
- update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen,
- const int *rectangles,
- int n_rectangles)
- {
- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
-+ MetaDrmBuffer *copy = NULL;
-
- COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeGpuStatePreSwapBuffers,
- "Onscreen (secondary gpu pre-swap-buffers)");
-@@ -937,10 +923,11 @@ update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen,
- /* prepare fallback */
- G_GNUC_FALLTHROUGH;
- case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
-- if (!copy_shared_framebuffer_primary_gpu (onscreen,
-- secondary_gpu_state,
-- rectangles,
-- n_rectangles))
-+ copy = copy_shared_framebuffer_primary_gpu (onscreen,
-+ secondary_gpu_state,
-+ rectangles,
-+ n_rectangles);
-+ if (!copy)
- {
- if (!secondary_gpu_state->noted_primary_gpu_copy_failed)
- {
-@@ -950,9 +937,9 @@ update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen,
- secondary_gpu_state->noted_primary_gpu_copy_failed = TRUE;
- }
-
-- copy_shared_framebuffer_cpu (onscreen,
-- secondary_gpu_state,
-- renderer_gpu_data);
-+ copy = copy_shared_framebuffer_cpu (onscreen,
-+ secondary_gpu_state,
-+ renderer_gpu_data);
- }
- else if (!secondary_gpu_state->noted_primary_gpu_copy_ok)
- {
-@@ -964,11 +951,15 @@ update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen,
- break;
- }
- }
-+
-+ return copy;
- }
-
- static void
--update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen,
-- gboolean *egl_context_changed)
-+update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen,
-+ gboolean *egl_context_changed,
-+ MetaDrmBuffer *primary_gpu_fb,
-+ MetaDrmBuffer **secondary_gpu_fb)
- {
- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
- MetaRendererNative *renderer_native = onscreen_native->renderer_native;
-@@ -981,6 +972,7 @@ update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen,
- if (secondary_gpu_state)
- {
- MetaRendererNativeGpuData *renderer_gpu_data;
-+ g_autoptr (MetaDrmBuffer) next_fb = NULL;
-
- renderer_gpu_data =
- meta_renderer_native_get_gpu_data (renderer_native,
-@@ -988,23 +980,30 @@ update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen,
- switch (renderer_gpu_data->secondary.copy_mode)
- {
- case META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO:
-- if (import_shared_framebuffer (onscreen, secondary_gpu_state))
-+ next_fb = import_shared_framebuffer (onscreen,
-+ secondary_gpu_state,
-+ primary_gpu_fb);
-+ if (next_fb)
- break;
--
-- /* The fallback was prepared in pre_swap_buffers */
-+ /* The fallback was prepared in pre_swap_buffers and is currently
-+ * in secondary_gpu_fb.
-+ */
- renderer_gpu_data->secondary.copy_mode =
- META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY;
- G_GNUC_FALLTHROUGH;
- case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
-- /* Done before eglSwapBuffers. */
-+ next_fb = g_object_ref (*secondary_gpu_fb);
- break;
- case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU:
-- copy_shared_framebuffer_gpu (onscreen,
-- secondary_gpu_state,
-- renderer_gpu_data,
-- egl_context_changed);
-+ next_fb = copy_shared_framebuffer_gpu (onscreen,
-+ secondary_gpu_state,
-+ renderer_gpu_data,
-+ egl_context_changed,
-+ primary_gpu_fb);
- break;
- }
-+
-+ g_set_object (secondary_gpu_fb, next_fb);
- }
- }
-
-@@ -1038,34 +1037,39 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
- CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
- MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
- MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
-- MetaRenderer *renderer = META_RENDERER (renderer_native);
-- MetaBackend *backend = meta_renderer_get_backend (renderer);
-- MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
-- MetaMonitorManager *monitor_manager =
-- meta_backend_get_monitor_manager (backend);
-- MetaKms *kms = meta_backend_native_get_kms (backend_native);
- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
- MetaGpuKms *render_gpu = onscreen_native->render_gpu;
- MetaDeviceFile *render_device_file;
- ClutterFrame *frame = user_data;
- CoglOnscreenClass *parent_class;
- gboolean egl_context_changed = FALSE;
-- MetaPowerSave power_save_mode;
- g_autoptr (GError) error = NULL;
- MetaDrmBufferFlags buffer_flags;
- MetaDrmBufferGbm *buffer_gbm;
-- MetaKmsCrtc *kms_crtc;
-- MetaKmsDevice *kms_device;
-- MetaKmsUpdateFlag flags;
-- g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
-- const GError *feedback_error;
-+ g_autoptr (MetaDrmBuffer) primary_gpu_fb = NULL;
-+ g_autoptr (MetaDrmBuffer) secondary_gpu_fb = NULL;
-+ size_t rectangles_size;
-
- COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeSwapBuffers,
- "Onscreen (swap-buffers)");
-
-- update_secondary_gpu_state_pre_swap_buffers (onscreen,
-- rectangles,
-- n_rectangles);
-+ if (meta_is_topic_enabled (META_DEBUG_KMS))
-+ {
-+ unsigned int frames_pending =
-+ cogl_onscreen_count_pending_frames (onscreen);
-+
-+ meta_topic (META_DEBUG_KMS,
-+ "Swap buffers: %u frames pending (%s-buffering)",
-+ frames_pending,
-+ frames_pending == 1 ? "double" :
-+ frames_pending == 2 ? "triple" :
-+ "?");
-+ }
-+
-+ secondary_gpu_fb =
-+ update_secondary_gpu_state_pre_swap_buffers (onscreen,
-+ rectangles,
-+ n_rectangles);
-
- parent_class = COGL_ONSCREEN_CLASS (meta_onscreen_native_parent_class);
- parent_class->swap_buffers_with_damage (onscreen,
-@@ -1081,9 +1085,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
- switch (renderer_gpu_data->mode)
- {
- case META_RENDERER_NATIVE_MODE_GBM:
-- g_warn_if_fail (onscreen_native->gbm.next_fb == NULL);
-- g_clear_object (&onscreen_native->gbm.next_fb);
--
- buffer_flags = META_DRM_BUFFER_FLAG_NONE;
- if (!meta_renderer_native_use_modifiers (renderer_native))
- buffer_flags |= META_DRM_BUFFER_FLAG_DISABLE_MODIFIERS;
-@@ -1101,7 +1102,12 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
- return;
- }
-
-- onscreen_native->gbm.next_fb = META_DRM_BUFFER (buffer_gbm);
-+ primary_gpu_fb = META_DRM_BUFFER (g_steal_pointer (&buffer_gbm));
-+
-+ g_object_set_data_full (G_OBJECT (primary_gpu_fb),
-+ "gbm_surface owner",
-+ g_object_ref (onscreen),
-+ (GDestroyNotify) g_object_unref);
-
- break;
- case META_RENDERER_NATIVE_MODE_SURFACELESS:
-@@ -1113,7 +1119,46 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
- #endif
- }
-
-- update_secondary_gpu_state_post_swap_buffers (onscreen, &egl_context_changed);
-+ update_secondary_gpu_state_post_swap_buffers (onscreen,
-+ &egl_context_changed,
-+ primary_gpu_fb,
-+ &secondary_gpu_fb);
-+
-+ switch (renderer_gpu_data->mode)
-+ {
-+ case META_RENDERER_NATIVE_MODE_GBM:
-+ if (onscreen_native->gbm.next_fb != NULL)
-+ {
-+ g_warn_if_fail (onscreen_native->gbm.stalled_fb == NULL);
-+ drop_stalled_swap (onscreen);
-+ g_assert (onscreen_native->gbm.stalled_fb == NULL);
-+ onscreen_native->gbm.stalled_fb =
-+ g_steal_pointer (&onscreen_native->gbm.next_fb);
-+ }
-+
-+ if (onscreen_native->secondary_gpu_state)
-+ {
-+ g_set_object (&onscreen_native->gbm.next_fb, secondary_gpu_fb);
-+ hold_primary_gpu_fb_for_secondary_gpu_scanout (
-+ onscreen_native->secondary_gpu_state,
-+ primary_gpu_fb,
-+ secondary_gpu_fb);
-+ }
-+ else
-+ {
-+ g_set_object (&onscreen_native->gbm.next_fb, primary_gpu_fb);
-+ }
-+ break;
-+ case META_RENDERER_NATIVE_MODE_SURFACELESS:
-+ break;
-+#ifdef HAVE_EGL_DEVICE
-+ case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
-+ break;
-+#endif
-+ }
-+
-+ clutter_frame_set_result (frame,
-+ CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
-
- /*
- * If we changed EGL context, cogl will have the wrong idea about what is
-@@ -1124,23 +1169,71 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
- if (egl_context_changed)
- _cogl_winsys_egl_ensure_current (cogl_display);
-
-+ rectangles_size = n_rectangles * 4 * sizeof (int);
-+ onscreen_native->next_post.rectangles =
-+ g_realloc (onscreen_native->next_post.rectangles, rectangles_size);
-+ memcpy (onscreen_native->next_post.rectangles, rectangles, rectangles_size);
-+ onscreen_native->next_post.n_rectangles = n_rectangles;
-+
-+ onscreen_native->swaps_pending++;
-+ try_post_latest_swap (onscreen);
-+}
-+
-+static void
-+try_post_latest_swap (CoglOnscreen *onscreen)
-+{
-+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-+ CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
-+ CoglRenderer *cogl_renderer = cogl_context->display->renderer;
-+ CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
-+ MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
-+ MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
-+ MetaRenderer *renderer = META_RENDERER (renderer_native);
-+ MetaBackend *backend = meta_renderer_get_backend (renderer);
-+ MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
-+ MetaMonitorManager *monitor_manager =
-+ meta_backend_get_monitor_manager (backend);
-+ MetaKms *kms = meta_backend_native_get_kms (backend_native);
-+ MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
-+ MetaPowerSave power_save_mode;
-+ MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc);
-+ MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
-+ MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);
-+ MetaKmsUpdateFlag flags;
-+ g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
-+ const GError *feedback_error;
-+ unsigned int frames_pending = cogl_onscreen_count_pending_frames (onscreen);
-+
-+ if (onscreen_native->swaps_pending == 0)
-+ return;
-+
-+ g_assert (frames_pending >= onscreen_native->swaps_pending);
-+
- power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
- if (power_save_mode == META_POWER_SAVE_ON)
- {
-+ unsigned int posts_pending;
-+
-+ posts_pending = frames_pending - onscreen_native->swaps_pending;
-+ if (posts_pending > 0)
-+ return; /* wait for the next frame notification and then try again */
-+
-+ drop_stalled_swap (onscreen);
-+ g_return_if_fail (onscreen_native->swaps_pending > 0);
-+ onscreen_native->swaps_pending--;
-+
- ensure_crtc_modes (onscreen);
- meta_onscreen_native_flip_crtc (onscreen,
- onscreen_native->view,
- onscreen_native->crtc,
- META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE,
-- rectangles,
-- n_rectangles);
-+ onscreen_native->next_post.rectangles,
-+ onscreen_native->next_post.n_rectangles);
- }
- else
- {
- meta_renderer_native_queue_power_save_page_flip (renderer_native,
- onscreen);
-- clutter_frame_set_result (frame,
-- CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
- return;
- }
-
-@@ -1158,9 +1251,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
- "Postponing primary plane composite update for CRTC %u (%s)",
- meta_kms_crtc_get_id (kms_crtc),
- meta_kms_device_get_path (kms_device));
--
-- clutter_frame_set_result (frame,
-- CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
- return;
- }
- else if (meta_renderer_native_has_pending_mode_set (renderer_native))
-@@ -1170,8 +1260,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
-
- meta_renderer_native_notify_mode_sets_reset (renderer_native);
- meta_renderer_native_post_mode_set_updates (renderer_native);
-- clutter_frame_set_result (frame,
-- CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
- return;
- }
- break;
-@@ -1184,8 +1272,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
- {
- meta_renderer_native_notify_mode_sets_reset (renderer_native);
- meta_renderer_native_post_mode_set_updates (renderer_native);
-- clutter_frame_set_result (frame,
-- CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
- return;
- }
- break;
-@@ -1198,18 +1284,16 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
- meta_kms_device_get_path (kms_device));
-
- flags = META_KMS_UPDATE_FLAG_NONE;
-- kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags);
-+ kms_feedback = meta_kms_post_pending_update_for_crtc_sync (kms,
-+ kms_crtc,
-+ flags);
-+ g_return_if_fail (kms_feedback != NULL);
-
- switch (meta_kms_feedback_get_result (kms_feedback))
- {
- case META_KMS_FEEDBACK_PASSED:
-- clutter_frame_set_result (frame,
-- CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
- break;
- case META_KMS_FEEDBACK_FAILED:
-- clutter_frame_set_result (frame,
-- CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
--
- feedback_error = meta_kms_feedback_get_error (kms_feedback);
- if (!g_error_matches (feedback_error,
- G_IO_ERROR,
-@@ -1296,6 +1380,18 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
- return FALSE;
- }
-
-+ /* Our direct scanout frame counts as 1, so more than that means we would
-+ * be jumping the queue (and post would fail).
-+ */
-+ if (cogl_onscreen_count_pending_frames (onscreen) > 1)
-+ {
-+ g_set_error_literal (error,
-+ COGL_SCANOUT_ERROR,
-+ COGL_SCANOUT_ERROR_INHIBITED,
-+ "Direct scanout is inhibited during triple buffering");
-+ return FALSE;
-+ }
-+
- renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
- render_gpu);
-
-@@ -1348,7 +1444,9 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
- meta_kms_device_get_path (kms_device));
-
- flags = META_KMS_UPDATE_FLAG_PRESERVE_ON_ERROR;
-- kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags);
-+ kms_feedback = meta_kms_post_pending_update_for_crtc_sync (kms,
-+ kms_crtc,
-+ flags);
- switch (meta_kms_feedback_get_result (kms_feedback))
- {
- case META_KMS_FEEDBACK_PASSED:
-@@ -1362,7 +1460,6 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
- G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED))
- break;
-
-- g_clear_object (&onscreen_native->gbm.next_fb);
- g_propagate_error (error, g_error_copy (feedback_error));
- return FALSE;
- }
-@@ -1398,7 +1495,10 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
- g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
- const GError *error;
-
-- kms_update = meta_kms_get_pending_update (kms, kms_device);
-+ if (cogl_onscreen_count_pending_frames (onscreen) > 0)
-+ return;
-+
-+ kms_update = meta_kms_get_pending_update_for_crtc (kms, kms_crtc);
- if (!kms_update)
- {
- clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE);
-@@ -1413,9 +1513,9 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
- g_object_unref);
-
- flags = META_KMS_UPDATE_FLAG_NONE;
-- kms_feedback = meta_kms_post_pending_update_sync (kms,
-- kms_device,
-- flags);
-+ kms_feedback = meta_kms_post_pending_update_for_crtc_sync (kms,
-+ kms_crtc,
-+ flags);
- switch (meta_kms_feedback_get_result (kms_feedback))
- {
- case META_KMS_FEEDBACK_PASSED:
-@@ -1437,6 +1537,17 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
- }
- }
-
-+void
-+meta_onscreen_native_discard_pending_swaps (CoglOnscreen *onscreen)
-+{
-+ MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
-+
-+ onscreen_native->swaps_pending = 0;
-+
-+ g_clear_object (&onscreen_native->gbm.stalled_fb);
-+ g_clear_object (&onscreen_native->gbm.next_fb);
-+}
-+
- static gboolean
- should_surface_be_sharable (CoglOnscreen *onscreen)
- {
-@@ -1985,6 +2096,21 @@ pick_secondary_gpu_framebuffer_format_for_cpu (CoglOnscreen *onscreen)
- return DRM_FORMAT_INVALID;
- }
-
-+static void
-+dumb_toggle_notify (gpointer data,
-+ GObject *object,
-+ gboolean is_last_ref)
-+{
-+ MetaDrmBuffer **source_fb = data;
-+
-+ g_return_if_fail (source_fb != NULL);
-+ if (is_last_ref && *source_fb)
-+ {
-+ g_return_if_fail (META_IS_DRM_BUFFER (*source_fb));
-+ g_clear_object (source_fb);
-+ }
-+}
-+
- static gboolean
- init_secondary_gpu_state_cpu_copy_mode (MetaRendererNative *renderer_native,
- CoglOnscreen *onscreen,
-@@ -2041,6 +2167,12 @@ init_secondary_gpu_state_cpu_copy_mode (MetaRendererNative *renderer_nat
- }
-
- secondary_gpu_state->cpu.dumb_fbs[i] = META_DRM_BUFFER_DUMB (dumb_buffer);
-+ g_object_add_toggle_ref (G_OBJECT (dumb_buffer),
-+ dumb_toggle_notify,
-+ &secondary_gpu_state->cpu.source_fbs[i]);
-+
-+ /* It was incremented higher than we need by add_toggle_ref */
-+ g_object_unref (dumb_buffer);
- }
-
- /*
-@@ -2130,7 +2262,7 @@ meta_onscreen_native_new (MetaRendererNative *renderer_native,
- onscreen_native->renderer_native = renderer_native;
- onscreen_native->render_gpu = render_gpu;
- onscreen_native->output = output;
-- onscreen_native->crtc = crtc;
-+ onscreen_native->crtc = g_object_ref (crtc);
-
- return onscreen_native;
- }
-@@ -2151,7 +2283,6 @@ meta_onscreen_native_dispose (GObject *object)
- {
- case META_RENDERER_NATIVE_MODE_GBM:
- g_clear_object (&onscreen_native->gbm.next_fb);
-- free_current_bo (onscreen);
- break;
- case META_RENDERER_NATIVE_MODE_SURFACELESS:
- g_assert_not_reached ();
-@@ -2179,9 +2310,12 @@ meta_onscreen_native_dispose (GObject *object)
-
- G_OBJECT_CLASS (meta_onscreen_native_parent_class)->dispose (object);
-
-+ g_clear_object (&onscreen_native->crtc);
- g_clear_pointer (&onscreen_native->gbm.surface, gbm_surface_destroy);
- g_clear_pointer (&onscreen_native->secondary_gpu_state,
- secondary_gpu_state_free);
-+ g_clear_pointer (&onscreen_native->next_post.rectangles, g_free);
-+ onscreen_native->next_post.n_rectangles = 0;
- }
-
- static void
-diff --git a/src/backends/native/meta-onscreen-native.h b/src/backends/native/meta-onscreen-native.h
-index 3a85ace26..676c4c445 100644
---- a/src/backends/native/meta-onscreen-native.h
-+++ b/src/backends/native/meta-onscreen-native.h
-@@ -40,6 +40,8 @@ void meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
-
- void meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen);
-
-+void meta_onscreen_native_discard_pending_swaps (CoglOnscreen *onscreen);
-+
- gboolean meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen,
- MetaDrmBuffer *fb);
-
-diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
-index d538cc25a..6ad3dba3b 100644
---- a/src/backends/native/meta-renderer-native.c
-+++ b/src/backends/native/meta-renderer-native.c
-@@ -661,12 +661,18 @@ static gboolean
- dummy_power_save_page_flip_cb (gpointer user_data)
- {
- MetaRendererNative *renderer_native = user_data;
-+ GList *old_list =
-+ g_steal_pointer (&renderer_native->power_save_page_flip_onscreens);
-
-- g_list_foreach (renderer_native->power_save_page_flip_onscreens,
-+ g_list_foreach (old_list,
- (GFunc) meta_onscreen_native_dummy_power_save_page_flip,
- NULL);
-- g_clear_list (&renderer_native->power_save_page_flip_onscreens,
-+ g_clear_list (&old_list,
- g_object_unref);
-+
-+ if (renderer_native->power_save_page_flip_onscreens != NULL)
-+ return G_SOURCE_CONTINUE;
-+
- renderer_native->power_save_page_flip_source_id = 0;
-
- return G_SOURCE_REMOVE;
-@@ -678,6 +684,9 @@ meta_renderer_native_queue_power_save_page_flip (MetaRendererNative *renderer_na
- {
- const unsigned int timeout_ms = 100;
-
-+ if (g_list_find (renderer_native->power_save_page_flip_onscreens, onscreen))
-+ return;
-+
- if (!renderer_native->power_save_page_flip_source_id)
- {
- renderer_native->power_save_page_flip_source_id =
-@@ -1386,6 +1395,26 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
- return view;
- }
-
-+static void
-+discard_pending_swaps (MetaRenderer *renderer)
-+{
-+ GList *views = meta_renderer_get_views (renderer);;
-+ GList *l;
-+
-+ for (l = views; l; l = l->next)
-+ {
-+ ClutterStageView *stage_view = l->data;
-+ CoglFramebuffer *fb = clutter_stage_view_get_onscreen (stage_view);
-+ CoglOnscreen *onscreen;
-+
-+ if (!COGL_IS_ONSCREEN (fb))
-+ continue;
-+
-+ onscreen = COGL_ONSCREEN (fb);
-+ meta_onscreen_native_discard_pending_swaps (onscreen);
-+ }
-+}
-+
- static void
- keep_current_onscreens_alive (MetaRenderer *renderer)
- {
-@@ -1414,6 +1443,7 @@ meta_renderer_native_rebuild_views (MetaRenderer *renderer)
- MetaRendererClass *parent_renderer_class =
- META_RENDERER_CLASS (meta_renderer_native_parent_class);
-
-+ discard_pending_swaps (renderer);
- meta_kms_discard_pending_page_flips (kms);
- meta_kms_discard_pending_updates (kms);
- \ No newline at end of file
diff --git a/mutter-rounded.install b/mutter-rounded.install
deleted file mode 100644
index 4e2f5c19a4dc..000000000000
--- a/mutter-rounded.install
+++ /dev/null
@@ -1,13 +0,0 @@
-tip() {
- echo -e "\n"
- echo -e "\033[31m === use 'mutter_settings' command to set window rounded radius. === \033[0m"
- echo -e "\n"
-}
-
-post_install() {
- tip
-}
-
-post_upgrade() {
- tip
-}
diff --git a/rounded_corners.patch b/rounded_corners.patch
deleted file mode 100644
index 7da1f9410ac7..000000000000
--- a/rounded_corners.patch
+++ /dev/null
@@ -1,1900 +0,0 @@
-diff --git a/data/org.gnome.mutter.gschema.xml.in b/data/org.gnome.mutter.gschema.xml.in
-index c014b749f..692bd5c80 100644
---- a/data/org.gnome.mutter.gschema.xml.in
-+++ b/data/org.gnome.mutter.gschema.xml.in
-@@ -10,6 +10,92 @@
- <schema id="org.gnome.mutter" path="/org/gnome/mutter/"
- gettext-domain="@GETTEXT_DOMAIN@">
-
-+ <key name="blur-sigmal" type="i">
-+ <default>20</default>
-+ <range min="0" max="100"/>
-+ <summary>Blur sigmal</summary>
-+ </key>
-+
-+ <key name="blur-brightness" type="i">
-+ <default>100</default>
-+ <range min="0" max="100"/>
-+ <summary>Blur brightness</summary>
-+ </key>
-+
-+ <key name="blur-list" type="as">
-+ <default>[]</default>
-+ <summary>windows will enable blur effect</summary>
-+ </key>
-+
-+ <key name="blur-window-opacity" type="i">
-+ <default>80</default>
-+ <range min="0" max="100"/>
-+ <summary>Blur Window opacity</summary>
-+ </key>
-+
-+ <key name="border-width" type="i">
-+ <default>0</default>
-+ <range min="0" max="100"/>
-+ <summary>Window border</summary>
-+ </key>
-+
-+ <key name="border-brightness" type="i">
-+ <default>40</default>
-+ <range min="0" max="100"/>
-+ <summary>Window border brightness</summary>
-+ </key>
-+
-+ <key name="round-corners-radius" type="i">
-+ <default>12</default>
-+ <range min="2" max="100"/>
-+ <summary>Round Corners Radius</summary>
-+ </key>
-+
-+ <key name="clip-edge-padding" type="s">
-+ <default>"{\"global\": [0, 0, 0, 0], \"apps\": {}}"</default>
-+ <summary>padding of window will be clipped</summary>
-+ <description>
-+ A JSON string, Represents the clipping range of the window edge.
-+ The array represents the clipping range of the four sides (left,
-+ right, top, bottom) of the window.
-+
-+ The key of "apps" object represent the instance part of the window's
-+ `WM_CLASS` property, as same as the output of `xprop WM_CLASS|cut -d
-+ \" -f 2`
-+
-+ This is a example:
-+
-+ {
-+ 'global': [1, 2, 3, 4],
-+ 'apps': {
-+ 'code': [5, 6, 7, 8],
-+ 'typora': [9, 10, 11, 12]
-+ }
-+ }
-+
-+ For all window, cut the left, right, top and bottom sides by 1, 2
-+ , 3 and 4 pixels respectively. But for Visual Studio Code and
-+ Typora, we will cut different pixels.
-+ </description>
-+ </key>
-+
-+ <key name="black-list" type="as">
-+ <default>["qq.exe", "tim.exe"]</default>
-+ <summary>window here will not be rounded</summary>
-+ <description>
-+ The contents of the list represent the instance part of the window's
-+ `WM_CLASS`, as same as the output of `xprop WM_CLASS|cut -d \" -f 2`
-+ </description>
-+ </key>
-+
-+ <key name="rounded-in-maximized" type="b">
-+ <default>false</default>
-+ <summary>Enable rounded corners when windows maximized</summary>
-+ <description>
-+ When true, the windows will always be clipped when be maximized.
-+ </description>
-+ </key>
-+
- <key name="overlay-key" type="s">
- <default>'Super_L'</default>
- <summary>Modifier to use for extended window management operations</summary>
-diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h
-index d3b3145a3..e11efb9f6 100644
---- a/src/compositor/compositor-private.h
-+++ b/src/compositor/compositor-private.h
-@@ -77,6 +77,8 @@ gboolean meta_compositor_is_switching_workspace (MetaCompositor *compositor);
- void meta_compositor_grab_begin (MetaCompositor *compositor);
- void meta_compositor_grab_end (MetaCompositor *compositor);
-
-+void meta_compositor_update_blur_behind(MetaCompositor *compositor);
-+
- /*
- * This function takes a 64 bit time stamp from the monotonic clock, and clamps
- * it to the scope of the X server clock, without losing the granularity.
-diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
-index 6f4982553..ce4184776 100644
---- a/src/compositor/compositor.c
-+++ b/src/compositor/compositor.c
-@@ -85,6 +85,8 @@
- #include "wayland/meta-wayland-private.h"
- #endif
-
-+#include "core/meta-workspace-manager-private.h"
-+
- enum
- {
- PROP_0,
-@@ -513,6 +515,10 @@ meta_compositor_add_window (MetaCompositor *compositor,
- * before we first paint.
- */
- priv->windows = g_list_append (priv->windows, window_actor);
-+
-+ if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
-+ meta_window_actor_create_blur_actor(window_actor);
-+
- sync_actor_stacking (compositor);
- }
-
-@@ -559,6 +565,7 @@ meta_compositor_queue_frame_drawn (MetaCompositor *compositor,
- MetaWindowActor *window_actor = meta_window_actor_from_window (window);
-
- meta_window_actor_queue_frame_drawn (window_actor, no_delay_frame);
-+ meta_compositor_update_blur_behind(compositor);
- }
-
- void
-@@ -907,6 +914,20 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
-
- sync_actor_stacking (compositor);
-
-+ MetaWorkspaceManager *manager = priv->display->workspace_manager;
-+ MetaWorkspace *active_workspace = manager->active_workspace;
-+
-+ for (GList *l = priv->windows; l; l = l->next)
-+ {
-+ MetaWindow *window = meta_window_actor_get_meta_window(l->data);
-+ MetaWorkspace *workspace = meta_window_get_workspace(window);
-+ if (workspace == active_workspace)
-+ {
-+ meta_window_actor_set_blur_behind(l->data);
-+ meta_window_actor_update_blur_position_size(l->data);
-+ }
-+ }
-+
- update_top_window_actor (compositor);
- }
-
-@@ -923,7 +944,17 @@ meta_compositor_sync_window_geometry (MetaCompositor *compositor,
- changes = meta_window_actor_sync_actor_geometry (window_actor, did_placement);
-
- if (changes & META_WINDOW_ACTOR_CHANGE_SIZE)
-+ {
-+ if (meta_window_actor_should_clip(window_actor))
-+ meta_window_actor_update_clipped_bounds(window_actor);
- meta_plugin_manager_event_size_changed (priv->plugin_mgr, window_actor);
-+ meta_window_actor_update_blur_position_size(window_actor);
-+ }
-+
-+ if (changes & META_WINDOW_ACTOR_CHANGE_POSITION)
-+ meta_window_actor_update_blur_position_size(window_actor);
-+
-+ meta_compositor_update_blur_behind(compositor);
- }
-
- static void
-@@ -1099,6 +1130,49 @@ meta_compositor_get_property (GObject *object,
- }
- }
-
-+static void
-+prefs_changed_cb(MetaPreference pref,
-+ gpointer user_data)
-+{
-+ MetaCompositor *compositor = user_data;
-+ MetaCompositorPrivate *priv =
-+ meta_compositor_get_instance_private (compositor);
-+ GList *l;
-+
-+ for (l = priv->windows; l; l = l->next)
-+ {
-+ switch (pref)
-+ {
-+ case META_PREF_CORNER_RADIUS:
-+ case META_PREF_CLIP_EDGE_PADDING:
-+ case META_PREF_BORDER_WIDTH:
-+ case META_PREF_BORDER_BRIGHTNESS:
-+ if (pref == META_PREF_CLIP_EDGE_PADDING)
-+ meta_window_actor_update_clip_padding (l->data);
-+
-+ meta_window_actor_update_clipped_bounds (l->data);
-+ meta_window_actor_update_glsl (l->data);
-+ clutter_actor_queue_redraw (CLUTTER_ACTOR (l->data));
-+ break;
-+ case META_PREF_BLUR_SIGMAL:
-+ meta_window_actor_update_blur_sigmal (l->data);
-+ break;
-+ case META_PREF_BLUR_BRIGHTNESS:
-+ meta_window_actor_update_blur_brightness (l->data);
-+ break;
-+ case META_PREF_BLUR_WINDOW_OPACITY:
-+ meta_window_actor_update_blur_window_opacity (l->data);
-+ break;
-+ case META_PREF_ROUNDED_IN_MAXIMIZED:
-+ meta_window_actor_update_glsl (l->data);
-+ meta_window_actor_update_blur_position_size(l->data);
-+ break;
-+ default:
-+ break;
-+ }
-+ }
-+}
-+
- static void
- meta_compositor_init (MetaCompositor *compositor)
- {
-@@ -1135,6 +1209,8 @@ meta_compositor_constructed (GObject *object)
-
- priv->laters = meta_laters_new (compositor);
-
-+ meta_prefs_add_listener(prefs_changed_cb, compositor);
-+
- G_OBJECT_CLASS (meta_compositor_parent_class)->constructed (object);
- }
-
-@@ -1155,6 +1231,8 @@ meta_compositor_dispose (GObject *object)
-
- g_clear_pointer (&priv->windows, g_list_free);
-
-+ meta_prefs_remove_listener(prefs_changed_cb, compositor);
-+
- G_OBJECT_CLASS (meta_compositor_parent_class)->dispose (object);
- }
-
-@@ -1498,3 +1576,20 @@ meta_compositor_get_laters (MetaCompositor *compositor)
-
- return priv->laters;
- }
-+
-+void meta_compositor_update_blur_behind(MetaCompositor *compositor)
-+{
-+ MetaCompositorPrivate *priv =
-+ meta_compositor_get_instance_private (compositor);
-+
-+ MetaWorkspaceManager *manager = priv->display->workspace_manager;
-+ MetaWorkspace *active_workspace = manager->active_workspace;
-+
-+ for (GList *l = priv->windows; l; l = l->next)
-+ {
-+ MetaWindow *window = meta_window_actor_get_meta_window(l->data);
-+ MetaWorkspace *workspace = meta_window_get_workspace(window);
-+ if (workspace == active_workspace)
-+ meta_window_actor_set_blur_behind(l->data);
-+ }
-+}
-diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h
-index 8aa206bb8..5a8b35c19 100644
---- a/src/compositor/meta-window-actor-private.h
-+++ b/src/compositor/meta-window-actor-private.h
-@@ -106,4 +106,15 @@ void meta_window_actor_update_regions (MetaWindowActor *self);
-
- gboolean meta_window_actor_can_freeze_commits (MetaWindowActor *self);
-
-+gboolean meta_window_actor_should_clip (MetaWindowActor *self);
-+void meta_window_actor_update_clipped_bounds (MetaWindowActor *window_actor);
-+void meta_window_actor_update_glsl (MetaWindowActor *self);
-+void meta_window_actor_get_corner_rect (MetaWindowActor *self, MetaRectangle *rect);
-+void meta_window_actor_update_clip_padding (MetaWindowActor *self);
-+void meta_window_actor_create_blur_actor (MetaWindowActor *self);
-+void meta_window_actor_set_blur_behind (MetaWindowActor *self);
-+void meta_window_actor_update_blur_position_size (MetaWindowActor *self);
-+void meta_window_actor_update_blur_sigmal (MetaWindowActor *self);
-+void meta_window_actor_update_blur_brightness (MetaWindowActor *self);
-+void meta_window_actor_update_blur_window_opacity (MetaWindowActor *self);
- #endif /* META_WINDOW_ACTOR_PRIVATE_H */
-diff --git a/src/compositor/meta-window-actor-wayland.c b/src/compositor/meta-window-actor-wayland.c
-index e1f341048..ae34238a5 100644
---- a/src/compositor/meta-window-actor-wayland.c
-+++ b/src/compositor/meta-window-actor-wayland.c
-@@ -24,10 +24,36 @@
- #include "compositor/meta-window-actor-wayland.h"
- #include "meta/meta-window-actor.h"
- #include "wayland/meta-wayland-surface.h"
-+#include "meta/meta-shadow-factory.h"
-+#include "ui/frames.h"
-+#include "compositor/compositor-private.h"
-
- struct _MetaWindowActorWayland
- {
- MetaWindowActor parent;
-+
-+ /* copy from meta-window-actor-x11.c */
-+ MetaShadow *focused_shadow;
-+ MetaShadow *unfocused_shadow;
-+ gboolean recompute_focused_shadow;
-+ gboolean recompute_unfocused_shadow;
-+
-+ /* The region we should clip to when painting the shadow */
-+ cairo_region_t *shadow_clip;
-+ /* The frame region */
-+ cairo_region_t *frame_bounds;
-+ /* A region that matches the shape of the window, including frame bounds */
-+ cairo_region_t *shape_region;
-+
-+ MetaWindowShape *shadow_shape;
-+
-+ gboolean need_reshape;
-+
-+ MetaShadowFactory *shadow_factory;
-+ gulong shadow_factory_changed_handler_id;
-+ gulong size_changed_id;
-+ gulong repaint_scheduled_id;
-+
- };
-
- G_DEFINE_TYPE (MetaWindowActorWayland, meta_window_actor_wayland, META_TYPE_WINDOW_ACTOR)
-@@ -109,18 +135,54 @@ meta_window_actor_wayland_get_scanout_candidate (MetaWindowActor *actor)
- return topmost_surface_actor;
- }
-
-+static void
-+surface_size_changed (MetaSurfaceActor *actor,
-+ gpointer user_data)
-+{
-+ MetaWindowActorWayland *actor_wayland = META_WINDOW_ACTOR_WAYLAND (user_data);
-+ actor_wayland->need_reshape = TRUE;
-+}
-+
-+static void
-+surface_repaint_scheduled (MetaSurfaceActor *actor,
-+ gpointer user_data)
-+{
-+ MetaWindowActorWayland *actor_wayland = META_WINDOW_ACTOR_WAYLAND (user_data);
-+ MetaWindow *window = meta_window_actor_get_meta_window (META_WINDOW_ACTOR(actor_wayland));
-+ meta_compositor_update_blur_behind( meta_display_get_compositor (window->display));
-+}
-+
-+
- static void
- meta_window_actor_wayland_assign_surface_actor (MetaWindowActor *actor,
- MetaSurfaceActor *surface_actor)
- {
- MetaWindowActorClass *parent_class =
- META_WINDOW_ACTOR_CLASS (meta_window_actor_wayland_parent_class);
-+ MetaSurfaceActor *prev_surface_actor;
-+ MetaWindowActorWayland *actor_wayland = META_WINDOW_ACTOR_WAYLAND (actor);
-+
-
- g_warn_if_fail (!meta_window_actor_get_surface (actor));
-
-+ prev_surface_actor = meta_window_actor_get_surface (actor);
-+ if (prev_surface_actor)
-+ g_clear_signal_handler (&META_WINDOW_ACTOR_WAYLAND (actor)->size_changed_id,
-+ prev_surface_actor);
-+
- parent_class->assign_surface_actor (actor, surface_actor);
-
- meta_window_actor_wayland_rebuild_surface_tree (actor);
-+
-+ actor_wayland->size_changed_id =
-+ g_signal_connect (surface_actor, "size-changed",
-+ G_CALLBACK (surface_size_changed),
-+ actor_wayland);
-+
-+ actor_wayland->repaint_scheduled_id =
-+ g_signal_connect (surface_actor, "repaint-scheduled",
-+ G_CALLBACK (surface_repaint_scheduled),
-+ actor_wayland);
- }
-
- static void
-@@ -136,10 +198,287 @@ meta_window_actor_wayland_queue_frame_drawn (MetaWindowActor *actor,
- {
- }
-
-+static const char *
-+get_shadow_class (MetaWindowActorWayland *actor_x11)
-+{
-+ MetaWindow *window =
-+ meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11));
-+ MetaWindowType window_type;
-+
-+ window_type = meta_window_get_window_type (window);
-+ switch (window_type)
-+ {
-+ case META_WINDOW_DROPDOWN_MENU:
-+ case META_WINDOW_COMBO:
-+ return "dropdown-menu";
-+ case META_WINDOW_POPUP_MENU:
-+ return "popup-menu";
-+ default:
-+ {
-+ MetaFrameType frame_type;
-+
-+ frame_type = meta_window_get_frame_type (window);
-+ return meta_frame_type_to_string (frame_type);
-+ }
-+ }
-+}
-+
-+static void
-+invalidate_shadow (MetaWindowActorWayland *actor_wayland)
-+{
-+ actor_wayland->recompute_focused_shadow = TRUE;
-+ actor_wayland->recompute_unfocused_shadow = TRUE;
-+
-+ if (meta_window_actor_is_frozen (META_WINDOW_ACTOR (actor_wayland)))
-+ return;
-+
-+ clutter_actor_queue_redraw (CLUTTER_ACTOR (actor_wayland));
-+ clutter_actor_invalidate_paint_volume (CLUTTER_ACTOR (actor_wayland));
-+}
-+
-+static void
-+update_shape_region (MetaWindowActorWayland *actor_wayland)
-+{
-+ MetaWindow *window =
-+ meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_wayland));
-+ cairo_region_t *region = NULL;
-+ cairo_rectangle_int_t client_area;
-+
-+ if (meta_window_actor_should_clip(META_WINDOW_ACTOR(actor_wayland)) && !window->frame)
-+ {
-+ meta_window_actor_get_corner_rect(META_WINDOW_ACTOR(actor_wayland), &client_area);
-+ region = cairo_region_create_rectangle(&client_area);
-+ }
-+ else
-+ {
-+ return;
-+ }
-+
-+ g_clear_pointer (&actor_wayland->shape_region, cairo_region_destroy);
-+ actor_wayland->shape_region = region;
-+
-+ g_clear_pointer (&actor_wayland->shadow_shape, meta_window_shape_unref);
-+
-+ invalidate_shadow (actor_wayland);
-+}
-+
-+static cairo_region_t *
-+meta_window_get_clipped_frame_bounds(MetaWindow *window)
-+{
-+ g_return_val_if_fail(window, NULL);
-+
-+ MetaWindowActor *actor = meta_window_actor_from_window(window);
-+ if (actor && !window->frame_bounds)
-+ {
-+ MetaRectangle rect;
-+ meta_window_actor_get_corner_rect(actor, &rect);
-+ window->frame_bounds =
-+ meta_ui_frame_get_bounds_clipped(&rect,
-+ meta_prefs_get_round_corner_radius());
-+ }
-+ return window->frame_bounds;
-+}
-+
-+static void
-+update_frame_bounds (MetaWindowActorWayland *actor_wayland)
-+{
-+ MetaWindow *window =
-+ meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_wayland));
-+
-+ g_clear_pointer (&actor_wayland->frame_bounds, cairo_region_destroy);
-+
-+ if (meta_window_actor_should_clip(META_WINDOW_ACTOR(actor_wayland)))
-+ actor_wayland->frame_bounds =
-+ cairo_region_copy(meta_window_get_clipped_frame_bounds(window));
-+}
-+
-+static void
-+get_shape_bounds (MetaWindowActorWayland *actor_wayland,
-+ cairo_rectangle_int_t *bounds)
-+{
-+ cairo_region_get_extents (actor_wayland->shape_region, bounds);
-+}
-+
-+static void
-+check_needs_shadow (MetaWindowActorWayland *actor_wayland)
-+{
-+ MetaWindow *window =
-+ meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_wayland));
-+ MetaShadow *old_shadow = NULL;
-+ MetaShadow **shadow_location;
-+ gboolean recompute_shadow;
-+ gboolean should_have_shadow;
-+ gboolean appears_focused;
-+
-+ should_have_shadow =
-+ meta_window_actor_should_clip (META_WINDOW_ACTOR (actor_wayland));
-+ appears_focused = meta_window_appears_focused (window);
-+
-+ if (appears_focused)
-+ {
-+ recompute_shadow = actor_wayland->recompute_focused_shadow;
-+ actor_wayland->recompute_focused_shadow = FALSE;
-+ shadow_location = &actor_wayland->focused_shadow;
-+ }
-+ else
-+ {
-+ recompute_shadow = actor_wayland->recompute_unfocused_shadow;
-+ actor_wayland->recompute_unfocused_shadow = FALSE;
-+ shadow_location = &actor_wayland->unfocused_shadow;
-+ }
-+
-+ if (!should_have_shadow || recompute_shadow)
-+ {
-+ if (*shadow_location != NULL)
-+ {
-+ old_shadow = *shadow_location;
-+ *shadow_location = NULL;
-+ }
-+ }
-+
-+ if (!*shadow_location && should_have_shadow)
-+ {
-+ MetaShadowFactory *factory = actor_wayland->shadow_factory;
-+ const char *shadow_class = get_shadow_class (actor_wayland);
-+ cairo_rectangle_int_t shape_bounds;
-+
-+ if (!actor_wayland->shadow_shape)
-+ {
-+ actor_wayland->shadow_shape =
-+ meta_window_shape_new (actor_wayland->shape_region);
-+ }
-+
-+ get_shape_bounds (actor_wayland, &shape_bounds);
-+ *shadow_location =
-+ meta_shadow_factory_get_shadow (factory,
-+ actor_wayland->shadow_shape,
-+ shape_bounds.width, shape_bounds.height,
-+ shadow_class, appears_focused);
-+ }
-+
-+ if (old_shadow)
-+ meta_shadow_unref (old_shadow);
-+}
-+
-+static void
-+get_shadow_params (MetaWindowActorWayland *actor_wayland,
-+ gboolean appears_focused,
-+ MetaShadowParams *params)
-+{
-+ const char *shadow_class = get_shadow_class (actor_wayland);
-+
-+ meta_shadow_factory_get_params (actor_wayland->shadow_factory,
-+ shadow_class, appears_focused,
-+ params);
-+}
-+
-+static gboolean
-+clip_shadow_under_window (MetaWindowActorWayland *actor_wayland)
-+{
-+ return TRUE;
-+}
-+
- static void
- meta_window_actor_wayland_before_paint (MetaWindowActor *actor,
- ClutterStageView *stage_view)
- {
-+ MetaWindowActorWayland *actor_wayland = META_WINDOW_ACTOR_WAYLAND (actor);
-+
-+ if (meta_window_actor_should_clip (actor))
-+ {
-+ update_frame_bounds (actor_wayland);
-+ if (actor_wayland->need_reshape)
-+ {
-+ update_shape_region (actor_wayland);
-+ actor_wayland->need_reshape = FALSE;
-+ }
-+ check_needs_shadow (actor_wayland);
-+ }
-+}
-+
-+static void
-+get_shadow_bounds (MetaWindowActorWayland *actor_x11,
-+ gboolean appears_focused,
-+ cairo_rectangle_int_t *bounds)
-+{
-+ MetaShadow *shadow;
-+ cairo_rectangle_int_t shape_bounds;
-+ MetaShadowParams params;
-+
-+ shadow = appears_focused ? actor_x11->focused_shadow
-+ : actor_x11->unfocused_shadow;
-+
-+ get_shape_bounds (actor_x11, &shape_bounds);
-+ get_shadow_params (actor_x11, appears_focused, &params);
-+
-+ meta_shadow_get_bounds (shadow,
-+ params.x_offset + shape_bounds.x,
-+ params.y_offset + shape_bounds.y,
-+ shape_bounds.width,
-+ shape_bounds.height,
-+ bounds);
-+}
-+
-+/* Copy from ./meta-window-actor-x11.c
-+ * to draw shadows for rounded wayland clients
-+ * because oragin shadows has been cutted out
-+ */
-+static void
-+meta_window_actor_wayland_paint (ClutterActor *actor,
-+ ClutterPaintContext *paint_context)
-+{
-+ MetaWindowActorWayland *actor_wayland = META_WINDOW_ACTOR_WAYLAND (actor);
-+ MetaWindow *window;
-+ gboolean appears_focused;
-+ MetaShadow *shadow;
-+
-+ window = meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_wayland));
-+ appears_focused = meta_window_appears_focused (window);
-+ shadow = appears_focused ? actor_wayland->focused_shadow
-+ : actor_wayland->unfocused_shadow;
-+
-+ if (shadow && meta_window_actor_should_clip (META_WINDOW_ACTOR (actor_wayland)))
-+ {
-+ MetaShadowParams params;
-+ cairo_rectangle_int_t shape_bounds;
-+ cairo_region_t *clip = actor_wayland->shadow_clip;
-+ CoglFramebuffer *framebuffer;
-+
-+ meta_window_actor_get_corner_rect(META_WINDOW_ACTOR(actor_wayland), &shape_bounds);
-+ get_shadow_params (actor_wayland, appears_focused, &params);
-+
-+ /* The frame bounds are already subtracted from actor_wayland->shadow_clip
-+ * if that exists.
-+ */
-+ if (!clip && clip_shadow_under_window (actor_wayland))
-+ {
-+ cairo_rectangle_int_t bounds;
-+
-+ get_shadow_bounds (actor_wayland, appears_focused, &bounds);
-+ clip = cairo_region_create_rectangle (&bounds);
-+
-+ if (actor_wayland->frame_bounds)
-+ cairo_region_subtract (clip, actor_wayland->frame_bounds);
-+ }
-+
-+ framebuffer = clutter_paint_context_get_framebuffer (paint_context);
-+ meta_shadow_paint (shadow,
-+ framebuffer,
-+ params.x_offset + shape_bounds.x,
-+ params.y_offset + shape_bounds.y,
-+ shape_bounds.width,
-+ shape_bounds.height,
-+ (clutter_actor_get_paint_opacity (actor) *
-+ params.opacity * window->opacity) / (255 * 255),
-+ clip,
-+ clip_shadow_under_window (actor_wayland));
-+
-+ if (clip && clip != actor_wayland->shadow_clip)
-+ cairo_region_destroy (clip);
-+ }
-+
-+ CLUTTER_ACTOR_CLASS (meta_window_actor_wayland_parent_class)->paint (actor,
-+ paint_context);
- }
-
- static void
-@@ -170,12 +509,29 @@ meta_window_actor_wayland_can_freeze_commits (MetaWindowActor *actor)
- return FALSE;
- }
-
-+static void
-+meta_window_actor_wayland_constructed (GObject *object)
-+{
-+ MetaWindowActorWayland *actor_wayland = META_WINDOW_ACTOR_WAYLAND (object);
-+
-+ /*
-+ * Start off with an empty shape region to maintain the invariant that it's
-+ * always set.
-+ */
-+ actor_wayland->shape_region = cairo_region_create ();
-+
-+ G_OBJECT_CLASS (meta_window_actor_wayland_parent_class)->constructed (object);
-+}
-+
-+
- static void
- meta_window_actor_wayland_dispose (GObject *object)
- {
- MetaWindowActor *window_actor = META_WINDOW_ACTOR (object);
- MetaSurfaceActor *surface_actor =
- meta_window_actor_get_surface (window_actor);
-+ MetaWindowActorWayland *actor_wayland = META_WINDOW_ACTOR_WAYLAND (object);
-+
- g_autoptr (GList) children = NULL;
- GList *l;
-
-@@ -188,7 +544,19 @@ meta_window_actor_wayland_dispose (GObject *object)
- child_actor != CLUTTER_ACTOR (surface_actor))
- clutter_actor_remove_child (CLUTTER_ACTOR (window_actor), child_actor);
- }
--
-+
-+ g_clear_pointer (&actor_wayland->shape_region, cairo_region_destroy);
-+ g_clear_pointer (&actor_wayland->shadow_clip, cairo_region_destroy);
-+ g_clear_pointer (&actor_wayland->frame_bounds, cairo_region_destroy);
-+
-+ g_clear_pointer (&actor_wayland->focused_shadow, meta_shadow_unref);
-+ g_clear_pointer (&actor_wayland->unfocused_shadow, meta_shadow_unref);
-+ g_clear_pointer (&actor_wayland->shadow_shape, meta_window_shape_unref);
-+
-+ g_clear_signal_handler (&actor_wayland->size_changed_id, surface_actor);
-+ g_clear_signal_handler (&actor_wayland->repaint_scheduled_id, surface_actor);
-+ g_clear_signal_handler (&actor_wayland->shadow_factory_changed_handler_id,
-+ actor_wayland->shadow_factory);
- G_OBJECT_CLASS (meta_window_actor_wayland_parent_class)->dispose (object);
- }
-
-@@ -196,6 +564,7 @@ static void
- meta_window_actor_wayland_class_init (MetaWindowActorWaylandClass *klass)
- {
- MetaWindowActorClass *window_actor_class = META_WINDOW_ACTOR_CLASS (klass);
-+ ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- window_actor_class->get_scanout_candidate = meta_window_actor_wayland_get_scanout_candidate;
-@@ -209,10 +578,19 @@ meta_window_actor_wayland_class_init (MetaWindowActorWaylandClass *klass)
- window_actor_class->update_regions = meta_window_actor_wayland_update_regions;
- window_actor_class->can_freeze_commits = meta_window_actor_wayland_can_freeze_commits;
-
-+ actor_class->paint = meta_window_actor_wayland_paint;
-+
-+ object_class->constructed = meta_window_actor_wayland_constructed;
- object_class->dispose = meta_window_actor_wayland_dispose;
- }
-
- static void
- meta_window_actor_wayland_init (MetaWindowActorWayland *self)
- {
-+ self->shadow_factory = meta_shadow_factory_get_default ();
-+ self->shadow_factory_changed_handler_id =
-+ g_signal_connect_swapped (self->shadow_factory,
-+ "changed",
-+ G_CALLBACK (invalidate_shadow),
-+ self);
- }
-diff --git a/src/compositor/meta-window-actor-x11.c b/src/compositor/meta-window-actor-x11.c
-index 82eaa428b..3d3bb2178 100644
---- a/src/compositor/meta-window-actor-x11.c
-+++ b/src/compositor/meta-window-actor-x11.c
-@@ -142,7 +142,8 @@ surface_repaint_scheduled (MetaSurfaceActor *actor,
- gpointer user_data)
- {
- MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (user_data);
--
-+ MetaWindow *window = meta_window_actor_get_meta_window (META_WINDOW_ACTOR(actor_x11));
-+ meta_compositor_update_blur_behind( meta_display_get_compositor (window->display));
- actor_x11->repaint_scheduled = TRUE;
- }
-
-@@ -458,6 +459,8 @@ surface_size_changed (MetaSurfaceActor *actor,
- MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (user_data);
-
- meta_window_actor_x11_update_shape (actor_x11);
-+
-+ meta_window_actor_update_glsl(META_WINDOW_ACTOR(actor_x11));
- }
-
- static void
-@@ -596,6 +599,9 @@ has_shadow (MetaWindowActorX11 *actor_x11)
- if (meta_window_get_frame (window))
- return TRUE;
-
-+ if (meta_window_actor_should_clip(META_WINDOW_ACTOR(actor_x11)))
-+ return TRUE;
-+
- /*
- * Do not add shadows to non-opaque (ARGB32) windows, as we can't easily
- * generate shadows for them.
-@@ -752,6 +758,8 @@ clip_shadow_under_window (MetaWindowActorX11 *actor_x11)
-
- if (window->frame)
- return TRUE;
-+ if (meta_window_actor_should_clip(META_WINDOW_ACTOR(actor_x11)))
-+ return TRUE;
-
- return meta_window_actor_is_opaque (META_WINDOW_ACTOR (actor_x11));
- }
-@@ -1094,6 +1102,11 @@ update_shape_region (MetaWindowActorX11 *actor_x11)
- {
- region = cairo_region_reference (window->shape_region);
- }
-+ else if (meta_window_actor_should_clip(META_WINDOW_ACTOR(actor_x11)) && !window->frame)
-+ {
-+ meta_window_actor_get_corner_rect(META_WINDOW_ACTOR(actor_x11), &client_area);
-+ region = cairo_region_create_rectangle(&client_area);
-+ }
- else
- {
- /* If we don't have a shape on the server, that means that
-@@ -1101,7 +1114,7 @@ update_shape_region (MetaWindowActorX11 *actor_x11)
- * entire window. */
- region = cairo_region_create_rectangle (&client_area);
- }
--
-+
- if (window->shape_region || window->frame)
- build_and_scan_frame_mask (actor_x11, region);
-
-@@ -1209,6 +1222,23 @@ update_opaque_region (MetaWindowActorX11 *actor_x11)
- cairo_region_destroy (opaque_region);
- }
-
-+static cairo_region_t *
-+meta_window_get_clipped_frame_bounds(MetaWindow *window)
-+{
-+ g_return_val_if_fail(window, NULL);
-+
-+ MetaWindowActor *actor = meta_window_actor_from_window(window);
-+ if (actor && !window->frame_bounds)
-+ {
-+ MetaRectangle rect;
-+ meta_window_actor_get_corner_rect(actor, &rect);
-+ window->frame_bounds =
-+ meta_ui_frame_get_bounds_clipped(&rect,
-+ meta_prefs_get_round_corner_radius());
-+ }
-+ return window->frame_bounds;
-+}
-+
- static void
- update_frame_bounds (MetaWindowActorX11 *actor_x11)
- {
-@@ -1216,8 +1246,13 @@ update_frame_bounds (MetaWindowActorX11 *actor_x11)
- meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11));
-
- g_clear_pointer (&actor_x11->frame_bounds, cairo_region_destroy);
-- actor_x11->frame_bounds =
-- cairo_region_copy (meta_window_get_frame_bounds (window));
-+
-+ if (meta_window_actor_should_clip(META_WINDOW_ACTOR(actor_x11)))
-+ actor_x11->frame_bounds =
-+ cairo_region_copy(meta_window_get_clipped_frame_bounds(window));
-+ else
-+ actor_x11->frame_bounds =
-+ cairo_region_copy (meta_window_get_frame_bounds (window));
- }
-
- static void
-@@ -1362,7 +1397,10 @@ meta_window_actor_x11_paint (ClutterActor *actor,
- cairo_region_t *clip = actor_x11->shadow_clip;
- CoglFramebuffer *framebuffer;
-
-- get_shape_bounds (actor_x11, &shape_bounds);
-+ if (meta_window_actor_should_clip(META_WINDOW_ACTOR(actor_x11)))
-+ meta_window_actor_get_corner_rect(META_WINDOW_ACTOR(actor_x11), &shape_bounds);
-+ else
-+ get_shape_bounds (actor_x11, &shape_bounds);
- get_shadow_params (actor_x11, appears_focused, &params);
-
- /* The frame bounds are already subtracted from actor_x11->shadow_clip
-diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
-index ae1fa4d90..a5a5286fa 100644
---- a/src/compositor/meta-window-actor.c
-+++ b/src/compositor/meta-window-actor.c
-@@ -41,6 +41,9 @@
- #include "wayland/meta-wayland-surface.h"
- #endif
-
-+#include "meta_clip_effect.h"
-+#include "shell-blur-effect.h"
-+
- typedef enum
- {
- INITIALLY_FROZEN,
-@@ -55,6 +58,15 @@ typedef struct _MetaWindowActorPrivate
-
- MetaSurfaceActor *surface;
-
-+ MetaClipEffect *round_clip_effect;
-+ gboolean effect_setuped;
-+ gboolean should_clip;
-+ int clip_padding[4];
-+ ClutterActor *blur_actor;
-+ MetaShellBlurEffect *blur_effect;
-+
-+ ulong visible_changed_id;
-+ ulong wm_class_changed_id;
- int geometry_scale;
-
- /*
-@@ -121,6 +133,246 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaWindowActor, meta_window_actor, CLUTTER_TY
- G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init)
- G_IMPLEMENT_INTERFACE (META_TYPE_SCREEN_CAST_WINDOW, screen_cast_window_iface_init));
-
-+static gboolean _meta_window_actor_should_clip(MetaWindowActor *self);
-+
-+static MetaClipEffect*
-+create_clip_effect(MetaWindowActor *self)
-+{
-+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private(self);
-+ if ((priv->should_clip = _meta_window_actor_should_clip(self)))
-+ return meta_clip_effect_new();
-+ else
-+ return NULL;
-+}
-+
-+void
-+meta_window_actor_update_blur_position_size(MetaWindowActor *self)
-+{
-+ MetaWindowActorPrivate *priv =
-+ meta_window_actor_get_instance_private (self);
-+
-+ if (!priv->blur_actor)
-+ return;
-+
-+ MetaRectangle buf_rect;
-+ MetaRectangle frame_rect;
-+ meta_window_get_frame_rect (priv->window, &frame_rect);
-+ meta_window_get_buffer_rect (priv->window, &buf_rect);
-+
-+ if ((meta_window_get_maximized (priv->window) && !meta_prefs_get_rounded_in_maximized()) ||
-+ meta_window_is_fullscreen (priv->window))
-+ {
-+ clutter_actor_set_position (priv->blur_actor,
-+ frame_rect.x,
-+ frame_rect.y);
-+ clutter_actor_set_size (priv->blur_actor,
-+ frame_rect.width,
-+ frame_rect.height);
-+ meta_shell_blur_effect_set_skip (priv->blur_effect, true);
-+ }
-+ else
-+ {
-+ clutter_actor_set_position (priv->blur_actor,
-+ frame_rect.x + priv->clip_padding[0] - 1,
-+ frame_rect.y + priv->clip_padding[2] - 1);
-+ clutter_actor_set_size (priv->blur_actor,
-+ frame_rect.width - priv->clip_padding[0] - priv->clip_padding[1] + 1,
-+ frame_rect.height - priv->clip_padding[2] - priv->clip_padding[3] + 1);
-+ meta_shell_blur_effect_set_skip (priv->blur_effect, false);
-+ }
-+}
-+
-+void
-+meta_window_actor_set_blur_behind (MetaWindowActor *self)
-+{
-+ MetaWindowActorPrivate *priv =
-+ meta_window_actor_get_instance_private (self);
-+
-+ if (!priv->blur_actor)
-+ return;
-+
-+ ClutterActor *parent = clutter_actor_get_parent (CLUTTER_ACTOR(self));
-+ clutter_actor_set_child_below_sibling (parent, priv->blur_actor, CLUTTER_ACTOR(self));
-+}
-+
-+static gboolean
-+meta_window_is_normal (MetaWindowActor *actor)
-+{
-+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (actor);
-+ MetaWindowType type = meta_window_get_window_type (priv->window);
-+
-+switch (type)
-+ {
-+ case META_WINDOW_NORMAL:
-+ case META_WINDOW_DIALOG:
-+ case META_WINDOW_MODAL_DIALOG:
-+ case META_WINDOW_SPLASHSCREEN:
-+ return TRUE;
-+ default:
-+ return FALSE;
-+ }
-+}
-+
-+
-+/*
-+ * in xwayland, `res-name` property of MetaWindow (WM_CLASS_INSTANCE property)
-+ * is empty when MetaWindow has been added to MetaWindowActor. So we have to
-+ * create create blur actor in on_wm_class_changed callback.
-+ *
-+ * in xorg, `res-name` property of MetaWindow has been setted when MetaWindow,
-+ * so we can create blur actor when window actor be created.
-+ */
-+void
-+meta_window_actor_create_blur_actor (MetaWindowActor *self)
-+{
-+ MetaWindowActorPrivate *priv =
-+ meta_window_actor_get_instance_private (self);
-+
-+ if (!meta_window_is_normal (self))
-+ return;
-+ if (!meta_prefs_in_blur_list (priv->window->res_name))
-+ return;
-+ if (priv->blur_actor != NULL)
-+ return;
-+
-+ priv->blur_actor = clutter_actor_new ();
-+ priv->blur_effect = meta_shell_blur_effect_new ();
-+
-+ meta_shell_blur_effect_set_brightness (priv->blur_effect,
-+ meta_prefs_get_blur_brightness());
-+ meta_shell_blur_effect_set_sigma (priv->blur_effect,
-+ meta_prefs_get_blur_sigmal());
-+ meta_shell_blur_effect_set_mode (priv->blur_effect, SHELL_BLUR_MODE_BACKGROUND);
-+ clutter_actor_add_effect_with_name (priv->blur_actor,
-+ "ShellBlurEffect",
-+ CLUTTER_EFFECT(priv->blur_effect));
-+
-+ ClutterActor *parent = clutter_actor_get_parent (CLUTTER_ACTOR(self));
-+ clutter_actor_insert_child_below (parent, priv->blur_actor, CLUTTER_ACTOR(self));
-+ int opa = meta_prefs_get_blur_window_opacity();
-+ meta_window_set_opacity(priv->window, opa);
-+}
-+
-+static void
-+check_meta_window_surface_actor(MetaWindowActor *self)
-+{
-+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private(self);
-+ MetaSurfaceActor *surface = meta_window_actor_get_surface(self);
-+
-+ if (!priv->effect_setuped && surface && priv->round_clip_effect)
-+ {
-+ clutter_actor_add_effect_with_name(CLUTTER_ACTOR(surface),
-+ "Rounded Corners Effect(Surface)",
-+ CLUTTER_EFFECT(priv->round_clip_effect));
-+ priv->effect_setuped = true;
-+ }
-+}
-+
-+void
-+meta_window_actor_update_glsl(MetaWindowActor *self)
-+{
-+ MetaRectangle frame_rect;
-+ MetaRectangle buf_rect;
-+ MetaWindow *window = meta_window_actor_get_meta_window(self);
-+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private(self);
-+
-+ if(!priv->round_clip_effect)
-+ return;
-+
-+ check_meta_window_surface_actor(self);
-+
-+ if (!meta_window_actor_should_clip(self))
-+ {
-+ meta_clip_effect_skip(priv->round_clip_effect);
-+ return;
-+ }
-+
-+ meta_window_get_frame_rect(window, &frame_rect);
-+ meta_window_get_buffer_rect(window, &buf_rect);
-+
-+ cairo_rectangle_int_t bounds;
-+ bounds.x = frame_rect.x - buf_rect.x;
-+ bounds.y = frame_rect.y - buf_rect.y;
-+ bounds.width = frame_rect.width;
-+ bounds.height = frame_rect.height;
-+
-+ if (bounds.width <= 0 || bounds.height <= 0)
-+ return;
-+
-+ if (priv->clip_padding[0] == -1 && window->res_name)
-+ meta_prefs_get_clip_edge_padding(window->res_name, priv->clip_padding);
-+
-+ meta_clip_effect_set_bounds(priv->round_clip_effect, &bounds, priv->clip_padding);
-+}
-+
-+static gboolean
-+_meta_window_actor_should_clip(MetaWindowActor *self)
-+{
-+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self);
-+ MetaWindow *window = priv->window;
-+
-+ if (meta_prefs_in_black_list(window->res_name))
-+ {
-+ return FALSE;
-+ }
-+
-+ return meta_window_is_normal(self);
-+}
-+
-+gboolean
-+meta_window_actor_should_clip(MetaWindowActor *self)
-+{
-+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self);
-+
-+ return priv->should_clip &&
-+ !((meta_window_get_maximized(priv->window) && !meta_prefs_get_rounded_in_maximized())
-+ || meta_window_is_fullscreen(priv->window));
-+}
-+
-+void
-+meta_window_actor_get_corner_rect(MetaWindowActor *self,
-+ MetaRectangle *rect)
-+{
-+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private(self);
-+ g_return_if_fail(priv->round_clip_effect);
-+ meta_clip_effect_get_bounds(priv->round_clip_effect, rect);
-+}
-+
-+void meta_window_actor_update_clip_padding(MetaWindowActor *self)
-+{
-+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private(self);
-+ if(priv->round_clip_effect)
-+ meta_prefs_get_clip_edge_padding(priv->window->res_name,
-+ priv->clip_padding);
-+}
-+
-+void
-+meta_window_actor_update_blur_sigmal (MetaWindowActor *self)
-+{
-+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private(self);
-+ if (priv->blur_actor)
-+ meta_shell_blur_effect_set_sigma (priv->blur_effect,
-+ meta_prefs_get_blur_sigmal());
-+}
-+
-+void
-+meta_window_actor_update_blur_brightness (MetaWindowActor *self)
-+{
-+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private(self);
-+ if (priv->blur_actor)
-+ meta_shell_blur_effect_set_brightness (priv->blur_effect,
-+ meta_prefs_get_blur_brightness());
-+}
-+
-+void
-+meta_window_actor_update_blur_window_opacity (MetaWindowActor *self)
-+{
-+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private(self);
-+ if (priv->blur_actor)
-+ meta_window_set_opacity (priv->window,
-+ meta_prefs_get_blur_window_opacity());
-+}
-+
- static void
- meta_window_actor_class_init (MetaWindowActorClass *klass)
- {
-@@ -219,6 +471,11 @@ meta_window_actor_init (MetaWindowActor *self)
- meta_window_actor_get_instance_private (self);
-
- priv->geometry_scale = 1;
-+ priv->effect_setuped = FALSE;
-+ priv->clip_padding[0] = -1;
-+
-+ priv->blur_actor = NULL;
-+ priv->blur_effect = NULL;
- }
-
- static void
-@@ -371,6 +628,11 @@ meta_window_actor_real_assign_surface_actor (MetaWindowActor *self,
- meta_window_actor_set_frozen (self, TRUE);
- else
- meta_window_actor_sync_thawed_state (self);
-+
-+ if (priv->blur_actor)
-+ {
-+ meta_window_actor_update_opacity (self);
-+ }
- }
-
- void
-@@ -402,6 +664,32 @@ init_surface_actor (MetaWindowActor *self)
- meta_window_actor_assign_surface_actor (self, surface_actor);
- }
-
-+static void
-+on_visible_changed (MetaWindowActor *self)
-+{
-+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self);
-+
-+ if (!priv->blur_actor)
-+ return;
-+
-+ if (priv->visible && !meta_window_actor_effect_in_progress (self))
-+ clutter_actor_show(priv->blur_actor);
-+ else
-+ clutter_actor_hide(priv->blur_actor);
-+}
-+
-+static void
-+on_wm_class_changed (MetaWindow *self,
-+ gpointer user_data)
-+{
-+ MetaWindowActor *actor = meta_window_actor_from_window (self);
-+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (actor);
-+
-+ priv->round_clip_effect = create_clip_effect(actor);
-+ meta_window_actor_create_blur_actor(actor);
-+ g_clear_signal_handler(&priv->wm_class_changed_id, self);
-+}
-+
- static void
- meta_window_actor_constructed (GObject *object)
- {
-@@ -409,6 +697,7 @@ meta_window_actor_constructed (GObject *object)
- MetaWindowActorPrivate *priv =
- meta_window_actor_get_instance_private (self);
- MetaWindow *window = priv->window;
-+ MetaWindowClientType type = meta_window_get_client_type (window);
-
- priv->compositor = window->display->compositor;
-
-@@ -427,6 +716,15 @@ meta_window_actor_constructed (GObject *object)
- priv->first_frame_state = DRAWING_FIRST_FRAME;
-
- meta_window_actor_sync_actor_geometry (self, priv->window->placed);
-+
-+ if (type == META_WINDOW_CLIENT_TYPE_WAYLAND)
-+ {
-+ priv->wm_class_changed_id =
-+ g_signal_connect (window, "notify::wm-class", G_CALLBACK (on_wm_class_changed), object);
-+ }
-+
-+ priv->visible_changed_id =
-+ g_signal_connect (object, "notify::visible", G_CALLBACK (on_visible_changed), NULL);
- }
-
- static void
-@@ -445,6 +743,7 @@ meta_window_actor_dispose (GObject *object)
-
- priv->disposed = TRUE;
-
-+ g_clear_signal_handler(&priv->visible_changed_id, object);
- meta_compositor_remove_window_actor (compositor, self);
-
- g_clear_object (&priv->window);
-@@ -473,6 +772,8 @@ meta_window_actor_set_property (GObject *object,
- {
- case PROP_META_WINDOW:
- priv->window = g_value_dup_object (value);
-+ if (priv->window->client_type == META_WINDOW_CLIENT_TYPE_X11)
-+ priv->round_clip_effect = create_clip_effect(self);
- g_signal_connect_object (priv->window, "notify::appears-focused",
- G_CALLBACK (window_appears_focused_notify), self, 0);
- break;
-@@ -603,6 +904,7 @@ meta_window_actor_effect_in_progress (MetaWindowActor *self)
- meta_window_actor_get_instance_private (self);
-
- return (priv->minimize_in_progress ||
-+ priv->unminimize_in_progress ||
- priv->size_change_in_progress ||
- priv->map_in_progress ||
- priv->destroy_in_progress);
-@@ -621,6 +923,47 @@ is_freeze_thaw_effect (MetaPluginEffect event)
- }
- }
-
-+static void
-+meta_window_actor_remove_blur (MetaWindowActor *self)
-+{
-+ MetaWindowActorPrivate *priv =
-+ meta_window_actor_get_instance_private (self);
-+
-+ if (!priv->blur_actor)
-+ return;
-+
-+ ClutterActor *parent = clutter_actor_get_parent (CLUTTER_ACTOR (self));
-+ clutter_actor_remove_effect (priv->blur_actor, CLUTTER_EFFECT (priv->blur_effect));
-+ clutter_actor_remove_child (parent, priv->blur_actor);
-+}
-+
-+static void
-+meta_window_actor_hide_blur (MetaWindowActor *self)
-+{
-+ MetaWindowActorPrivate *priv =
-+ meta_window_actor_get_instance_private (self);
-+
-+ if (!priv->blur_actor)
-+ return;
-+
-+ clutter_actor_hide(priv->blur_actor);
-+}
-+
-+static void
-+meta_window_actor_show_blur (MetaWindowActor *self)
-+{
-+ MetaWindowActorPrivate *priv =
-+ meta_window_actor_get_instance_private (self);
-+
-+ if (!priv->blur_actor)
-+ return;
-+
-+ if (priv->visible && !meta_window_actor_effect_in_progress (self))
-+ clutter_actor_show(priv->blur_actor);
-+ else
-+ clutter_actor_hide(priv->blur_actor);
-+}
-+
- static gboolean
- start_simple_effect (MetaWindowActor *self,
- MetaPluginEffect event)
-@@ -640,15 +983,33 @@ start_simple_effect (MetaWindowActor *self,
- case META_PLUGIN_NONE:
- return FALSE;
- case META_PLUGIN_MINIMIZE:
-+ if (priv->round_clip_effect)
-+ {
-+ meta_window_actor_hide_blur(self);
-+ }
- counter = &priv->minimize_in_progress;
- break;
- case META_PLUGIN_UNMINIMIZE:
-+ if (priv->round_clip_effect)
-+ {
-+ meta_window_actor_hide_blur(self);
-+ }
- counter = &priv->unminimize_in_progress;
- break;
- case META_PLUGIN_MAP:
-+ if (priv->round_clip_effect)
-+ {
-+ meta_window_actor_hide_blur(self);
-+ }
- counter = &priv->map_in_progress;
- break;
- case META_PLUGIN_DESTROY:
-+ if (priv->round_clip_effect)
-+ {
-+ clutter_actor_remove_effect (CLUTTER_ACTOR(self),
-+ CLUTTER_EFFECT(priv->round_clip_effect));
-+ meta_window_actor_remove_blur(self);
-+ }
- counter = &priv->destroy_in_progress;
- break;
- case META_PLUGIN_SIZE_CHANGE:
-@@ -697,6 +1058,7 @@ meta_window_actor_after_effects (MetaWindowActor *self)
- g_signal_emit (self, signals[EFFECTS_COMPLETED], 0);
- meta_window_actor_sync_visibility (self);
- meta_window_actor_sync_actor_geometry (self, FALSE);
-+ meta_window_actor_show_blur(self);
- }
-
- clutter_stage_repick_device (stage, clutter_seat_get_pointer (seat));
-@@ -818,6 +1180,19 @@ meta_window_actor_queue_destroy (MetaWindowActor *self)
- clutter_actor_destroy (CLUTTER_ACTOR (self));
- }
-
-+void
-+meta_window_actor_update_clipped_bounds(MetaWindowActor *window_actor)
-+{
-+ MetaWindowActorPrivate *priv =
-+ meta_window_actor_get_instance_private(window_actor);
-+ MetaWindow *window = priv->window;
-+
-+ if (window && window->frame_bounds) {
-+ cairo_region_destroy(window->frame_bounds);
-+ window->frame_bounds = NULL;
-+ }
-+}
-+
- MetaWindowActorChanges
- meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
- gboolean did_placement)
-@@ -1046,7 +1421,7 @@ meta_window_actor_sync_visibility (MetaWindowActor *self)
-
- if (CLUTTER_ACTOR_IS_VISIBLE (self) != priv->visible)
- {
-- if (priv->visible)
-+ if (priv->visible && !priv->unminimize_in_progress)
- clutter_actor_show (CLUTTER_ACTOR (self));
- else
- clutter_actor_hide (CLUTTER_ACTOR (self));
-diff --git a/src/core/prefs.c b/src/core/prefs.c
-index 536d9dd57..1889b27a7 100644
---- a/src/core/prefs.c
-+++ b/src/core/prefs.c
-@@ -33,6 +33,8 @@
- #include <string.h>
- #include <stdlib.h>
-
-+#include <json-glib/json-glib.h>
-+
- #include "compositor/meta-plugin-manager.h"
- #include "core/keybindings-private.h"
- #include "core/meta-accel-parse.h"
-@@ -120,6 +122,18 @@ static gboolean show_fallback_app_menu = TRUE;
- static GDesktopVisualBellType visual_bell_type = G_DESKTOP_VISUAL_BELL_FULLSCREEN_FLASH;
- static MetaButtonLayout button_layout;
-
-+static int round_corner_radius = 8;
-+static int border_width = 0;
-+static int border_brightness = 40;
-+static int blur_sigmal = 20;
-+static int blur_window_opacity = 80;
-+static int blur_brightness = 100;
-+static gboolean rounded_in_maximized = FALSE;
-+static JsonNode *clip_edge_padding = NULL;
-+/* NULL-terminated array */
-+static char **black_list = NULL;
-+static char **blur_list = NULL;
-+
- /* NULL-terminated array */
- static char **workspace_names = NULL;
-
-@@ -150,6 +164,7 @@ static gboolean mouse_button_mods_handler (GVariant*, gpointer*, gpointer);
- static gboolean button_layout_handler (GVariant*, gpointer*, gpointer);
- static gboolean overlay_key_handler (GVariant*, gpointer*, gpointer);
- static gboolean locate_pointer_key_handler (GVariant*, gpointer*, gpointer);
-+static gboolean clip_edge_padding_handler (GVariant*, gpointer*, gpointer);
-
- static gboolean iso_next_group_handler (GVariant*, gpointer*, gpointer);
-
-@@ -401,6 +416,13 @@ static MetaBoolPreference preferences_bool[] =
- },
- &locate_pointer_is_enabled,
- },
-+ {
-+ { "rounded-in-maximized",
-+ SCHEMA_MUTTER,
-+ META_PREF_ROUNDED_IN_MAXIMIZED,
-+ },
-+ &rounded_in_maximized,
-+ },
- { { NULL, 0, 0 }, NULL },
- };
-
-@@ -454,6 +476,15 @@ static MetaStringPreference preferences_string[] =
- locate_pointer_key_handler,
- NULL,
- },
-+ {
-+ {
-+ "clip-edge-padding",
-+ SCHEMA_MUTTER,
-+ META_PREF_CLIP_EDGE_PADDING,
-+ },
-+ clip_edge_padding_handler,
-+ NULL,
-+ },
- { { NULL, 0, 0 }, NULL },
- };
-
-@@ -475,6 +506,22 @@ static MetaStringArrayPreference preferences_string_array[] =
- iso_next_group_handler,
- NULL,
- },
-+ {
-+ { "black-list",
-+ SCHEMA_MUTTER,
-+ META_PREF_BLACK_LIST,
-+ },
-+ NULL,
-+ &black_list,
-+ },
-+ {
-+ { "blur-list",
-+ SCHEMA_MUTTER,
-+ META_PREF_BLUR_LIST,
-+ },
-+ NULL,
-+ &blur_list,
-+ },
- { { NULL, 0, 0 }, NULL },
- };
-
-@@ -515,6 +562,54 @@ static MetaIntPreference preferences_int[] =
- },
- &cursor_size
- },
-+ {
-+ {
-+ "round-corners-radius",
-+ SCHEMA_MUTTER,
-+ META_PREF_CORNER_RADIUS,
-+ },
-+ &round_corner_radius,
-+ },
-+ {
-+ {
-+ "border-width",
-+ SCHEMA_MUTTER,
-+ META_PREF_BORDER_WIDTH,
-+ },
-+ &border_width,
-+ },
-+ {
-+ {
-+ "border-brightness",
-+ SCHEMA_MUTTER,
-+ META_PREF_BORDER_BRIGHTNESS,
-+ },
-+ &border_brightness,
-+ },
-+ {
-+ {
-+ "blur-sigmal",
-+ SCHEMA_MUTTER,
-+ META_PREF_BLUR_SIGMAL,
-+ },
-+ &blur_sigmal,
-+ },
-+ {
-+ {
-+ "blur-brightness",
-+ SCHEMA_MUTTER,
-+ META_PREF_BLUR_BRIGHTNESS,
-+ },
-+ &blur_brightness,
-+ },
-+ {
-+ {
-+ "blur-window-opacity",
-+ SCHEMA_MUTTER,
-+ META_PREF_BLUR_WINDOW_OPACITY,
-+ },
-+ &blur_window_opacity,
-+ },
- { { NULL, 0, 0 }, NULL },
- };
-
-@@ -1588,6 +1683,81 @@ locate_pointer_key_handler (GVariant *value,
- return TRUE;
- }
-
-+static gboolean
-+clip_edge_padding_handler (GVariant *value,
-+ gpointer *result,
-+ gpointer data)
-+{
-+ /* json string looks like this:
-+ *
-+ * {
-+ * // array represent the clip padding of window: [left, right, top, bottom]
-+ * "global": [1, 1, 1, 1],
-+ * // special app settings,
-+ * "apps": {
-+ * // second part in `WM_CLASS` property of a window
-+ * "Typora": [0, 0, 0, 0],
-+ * ...
-+ * }
-+ * }
-+ */
-+
-+ JsonNode *json;
-+ JsonObject *obj;
-+ JsonArray *arr;
-+ JsonNode *element;
-+ JsonObject *apps_obj;
-+ GList *app_names;
-+
-+ const char *string_value;
-+ GError *error = NULL;
-+
-+ *result = NULL;
-+ string_value = g_variant_get_string(value, NULL);
-+ json = json_from_string(string_value, &error);
-+
-+ if (error)
-+ {
-+ meta_topic(META_DEBUG_PREFS, "Failed to parse value for clip-edge-padding: %s", error->message);
-+ g_error_free(error);
-+ return FALSE;
-+ }
-+
-+ if (!JSON_NODE_HOLDS_OBJECT(json))
-+ goto failed;
-+
-+ obj = json_node_get_object(json);
-+ arr = json_object_get_array_member(obj, "global");
-+ if (!arr || json_array_get_length(arr) != 4)
-+ goto failed;
-+
-+ if (!(element = json_object_get_member(obj, "apps")))
-+ goto failed;
-+ if (!JSON_NODE_HOLDS_OBJECT(element))
-+ goto failed;
-+ apps_obj = json_node_get_object(element);
-+
-+ app_names = json_object_get_members(apps_obj);
-+ for (GList *l = app_names; l != NULL; l = l->next)
-+ {
-+ arr = json_object_get_array_member(apps_obj, l->data);
-+ if (!arr || json_array_get_length(arr) != 4)
-+ goto failed;
-+ }
-+
-+ if (clip_edge_padding != NULL)
-+ json_node_unref(clip_edge_padding);
-+ clip_edge_padding = json;
-+ queue_changed(META_PREF_CLIP_EDGE_PADDING);
-+
-+ return TRUE;
-+
-+failed:
-+ meta_topic(META_DEBUG_PREFS, "Failed to parse value for clip-edge-padding");
-+ json_node_unref(json);
-+ return FALSE;
-+}
-+
- static gboolean
- iso_next_group_handler (GVariant *value,
- gpointer *result,
-@@ -1759,6 +1929,36 @@ meta_preference_to_string (MetaPreference pref)
-
- case META_PREF_CHECK_ALIVE_TIMEOUT:
- return "CHECK_ALIVE_TIMEOUT";
-+
-+ case META_PREF_CORNER_RADIUS:
-+ return "CORNER_RADIUS";
-+
-+ case META_PREF_CLIP_EDGE_PADDING:
-+ return "CLIP_EDGE_PADDING";
-+
-+ case META_PREF_BLACK_LIST:
-+ return "BLACK_LIST";
-+
-+ case META_PREF_BORDER_WIDTH:
-+ return "BORDER_WIDTH";
-+
-+ case META_PREF_BORDER_BRIGHTNESS:
-+ return "BORDER_BRIGHTNESS";
-+
-+ case META_PREF_BLUR_SIGMAL:
-+ return "BLUR_SIGMAL";
-+
-+ case META_PREF_BLUR_BRIGHTNESS:
-+ return "BLUR_BRIGHTNESS";
-+
-+ case META_PREF_BLUR_LIST:
-+ return "BLUR_LIST";
-+
-+ case META_PREF_BLUR_WINDOW_OPACITY:
-+ return "BLUR_WINDOW_OPACITY";
-+
-+ case META_PREF_ROUNDED_IN_MAXIMIZED:
-+ return "ROUNDED_IN_MAXIMIZED";
- }
-
- return "(unknown)";
-@@ -2227,3 +2427,100 @@ meta_prefs_set_force_fullscreen (gboolean whether)
- {
- force_fullscreen = whether;
- }
-+
-+int
-+meta_prefs_get_round_corner_radius (void)
-+{
-+ return round_corner_radius;
-+}
-+
-+#define SET_PADDING(arr, v0, v1, v2, v3) \
-+ { (arr)[0] = (v0); (arr)[1] = (v1); (arr)[2] = (v2); (arr)[3] = (v3); }
-+
-+void
-+meta_prefs_get_clip_edge_padding (const char *name, int padding[4])
-+{
-+ JsonObject *obj;
-+ JsonArray *arr;
-+
-+ if (!clip_edge_padding || !name) {
-+ SET_PADDING(padding, 0, 0, 0, 0);
-+ return;
-+ }
-+
-+ obj = json_node_get_object(clip_edge_padding);
-+ arr = json_object_get_array_member(obj, "global");
-+ obj = json_object_get_object_member(obj, "apps");
-+
-+ if (json_object_has_member(obj, name))
-+ arr = json_object_get_array_member(obj, name);
-+
-+ // array: { left, right, top, bottom }
-+ SET_PADDING(padding,
-+ json_array_get_int_element(arr, 0) + 1,
-+ json_array_get_int_element(arr, 1),
-+ json_array_get_int_element(arr, 2) + 1,
-+ json_array_get_int_element(arr, 3));
-+}
-+
-+gboolean
-+meta_prefs_in_black_list(const char *name)
-+{
-+ g_return_val_if_fail(black_list, FALSE);
-+
-+ int len = g_strv_length(black_list);
-+
-+ for (int i = 0; i < len; i++)
-+ if (g_strcmp0(name, black_list[i]) == 0)
-+ return TRUE;
-+ return FALSE;
-+}
-+
-+int
-+meta_prefs_get_border_width(void)
-+{
-+ return border_width;
-+}
-+
-+double
-+meta_prefs_get_border_brightness(void)
-+{
-+ return (double) border_brightness * 0.01;
-+}
-+
-+int
-+meta_prefs_get_blur_sigmal(void)
-+{
-+ return blur_sigmal;
-+}
-+
-+double
-+meta_prefs_get_blur_brightness(void)
-+{
-+ return (double) blur_brightness * 0.01;
-+}
-+
-+int
-+meta_prefs_get_blur_window_opacity(void)
-+{
-+ return blur_window_opacity * 255 * 0.01;
-+}
-+
-+gboolean
-+meta_prefs_get_rounded_in_maximized(void)
-+{
-+ return rounded_in_maximized;
-+}
-+
-+gboolean
-+meta_prefs_in_blur_list(const char *name)
-+{
-+ g_return_val_if_fail(blur_list, FALSE);
-+
-+ int len = g_strv_length(blur_list);
-+
-+ for (int i = 0; i < len; i++)
-+ if (g_strcmp0(name, blur_list[i]) == 0)
-+ return TRUE;
-+ return FALSE;
-+}
-diff --git a/src/meson.build b/src/meson.build
-index 13a69c1a6..10e29db76 100644
---- a/src/meson.build
-+++ b/src/meson.build
-@@ -173,6 +173,18 @@ if get_option('verbose')
- ]
- endif
-
-+libshell_enums = gnome.mkenums_simple('shell-enum-types',
-+ sources: [
-+ 'shell-blur-effect.h',
-+ ]
-+)
-+
-+libshell_src = [
-+ libshell_enums,
-+ 'shell-blur-effect.h',
-+ 'shell-blur-effect.c',
-+]
-+
- mutter_sources = [
- 'backends/edid.h',
- 'backends/edid-parse.c',
-@@ -462,6 +474,8 @@ mutter_sources = [
- 'x11/window-x11-private.h',
- 'x11/xprops.c',
- 'x11/xprops.h',
-+ 'meta_clip_effect.c',
-+ 'meta_clip_effect.h',
- ]
-
- if have_egl_device
-@@ -1016,7 +1030,8 @@ subdir('meta')
- mutter_built_sources += mutter_enum_types
-
- libmutter = shared_library(libmutter_name,
-- mutter_sources,
-+ # mutter_sources,
-+ mutter_sources + libshell_src,
- mutter_built_sources,
- version: '0.0.0',
- soversion: 0,
-diff --git a/src/meta/prefs.h b/src/meta/prefs.h
-index 227de68bf..f005f47e8 100644
---- a/src/meta/prefs.h
-+++ b/src/meta/prefs.h
-@@ -106,6 +106,17 @@ typedef enum
- META_PREF_DRAG_THRESHOLD,
- META_PREF_LOCATE_POINTER,
- META_PREF_CHECK_ALIVE_TIMEOUT,
-+
-+ META_PREF_CORNER_RADIUS,
-+ META_PREF_CLIP_EDGE_PADDING,
-+ META_PREF_BLACK_LIST,
-+ META_PREF_BORDER_WIDTH,
-+ META_PREF_BORDER_BRIGHTNESS,
-+ META_PREF_BLUR_SIGMAL,
-+ META_PREF_BLUR_BRIGHTNESS,
-+ META_PREF_BLUR_LIST,
-+ META_PREF_BLUR_WINDOW_OPACITY,
-+ META_PREF_ROUNDED_IN_MAXIMIZED,
- } MetaPreference;
-
- typedef void (* MetaPrefsChangedFunc) (MetaPreference pref,
-@@ -233,6 +244,36 @@ int meta_prefs_get_draggable_border_width (void);
- META_EXPORT
- int meta_prefs_get_drag_threshold (void);
-
-+META_EXPORT
-+int meta_prefs_get_round_corner_radius (void);
-+
-+META_EXPORT
-+void meta_prefs_get_clip_edge_padding (const char *name, int padding[4]);
-+
-+META_EXPORT
-+gboolean meta_prefs_in_black_list(const char *name);
-+
-+META_EXPORT
-+int meta_prefs_get_border_width(void);
-+
-+META_EXPORT
-+double meta_prefs_get_border_brightness(void);
-+
-+META_EXPORT
-+int meta_prefs_get_blur_sigmal(void);
-+
-+META_EXPORT
-+double meta_prefs_get_blur_brightness(void);
-+
-+META_EXPORT
-+int meta_prefs_get_blur_window_opacity(void);
-+
-+META_EXPORT
-+gboolean meta_prefs_get_rounded_in_maximized(void);
-+
-+META_EXPORT
-+gboolean meta_prefs_in_blur_list(const char *name);
-+
- /**
- * MetaKeyBindingAction:
- * @META_KEYBINDING_ACTION_NONE: FILLME
-diff --git a/src/ui/frames.c b/src/ui/frames.c
-index cf90d477b..f82d653fd 100644
---- a/src/ui/frames.c
-+++ b/src/ui/frames.c
-@@ -711,6 +711,27 @@ meta_ui_frame_get_bounds (MetaUIFrame *frame)
- return get_visible_region (frame, &fgeom);
- }
-
-+cairo_region_t *
-+meta_ui_frame_get_bounds_clipped (const MetaRectangle *bounds,
-+ float radius)
-+{
-+ MetaFrameGeometry fgeom;
-+
-+ fgeom.borders.invisible.left = bounds->x;
-+ fgeom.borders.invisible.top = bounds->y;
-+ fgeom.borders.invisible.bottom = 0;
-+ fgeom.borders.invisible.right = 0;
-+ fgeom.width = bounds->width + bounds->x;
-+ fgeom.height = bounds->height + bounds->y;
-+
-+ fgeom.top_left_corner_rounded_radius = radius;
-+ fgeom.top_right_corner_rounded_radius = radius;
-+ fgeom.bottom_left_corner_rounded_radius = radius;
-+ fgeom.bottom_right_corner_rounded_radius = radius;
-+
-+ return get_visible_region (NULL, &fgeom);
-+}
-+
- void
- meta_ui_frame_move_resize (MetaUIFrame *frame,
- int x, int y, int width, int height)
-diff --git a/src/ui/frames.h b/src/ui/frames.h
-index 89b399265..8262f0446 100644
---- a/src/ui/frames.h
-+++ b/src/ui/frames.h
-@@ -139,6 +139,10 @@ void meta_ui_frame_get_borders (MetaUIFrame *frame,
-
- cairo_region_t * meta_ui_frame_get_bounds (MetaUIFrame *frame);
-
-+cairo_region_t *
-+meta_ui_frame_get_bounds_clipped (const MetaRectangle *bounds,
-+ float radius);
-+
- void meta_ui_frame_get_mask (MetaUIFrame *frame,
- cairo_rectangle_int_t *frame_rect,
- cairo_t *cr);
-diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c
-index 2b389bfbf..cbd04cc41 100644
---- a/src/wayland/meta-window-wayland.c
-+++ b/src/wayland/meta-window-wayland.c
-@@ -1073,6 +1073,9 @@ meta_window_wayland_finish_move_resize (MetaWindow *window,
- gravity = META_GRAVITY_STATIC;
- meta_window_move_resize_internal (window, flags, gravity, rect);
-
-+ if (flags & META_MOVE_RESIZE_RESIZE_ACTION)
-+ meta_window_actor_update_glsl(meta_window_actor_from_window(window));
-+
- g_clear_pointer (&acked_configuration, meta_wayland_window_configuration_free);
- }
-
diff --git a/shader.h b/shader.h
deleted file mode 100644
index 6a3340fcce69..000000000000
--- a/shader.h
+++ /dev/null
@@ -1,116 +0,0 @@
-#pragma once
-
-/*
- * copied from src/compositor/meta-background-content.c
- * see: https://gitlab.gnome.org/GNOME/mutter/-/blob/858b5c12b1f55043964c2e2bd30de8cf112e76d2/src/compositor/meta-background-content.c#L138
- */
-#define ROUNDED_CLIP_FRAGMENT_SHADER_FUNCS \
-"float \n"\
-"rounded_rect_coverage (vec2 p, vec4 bounds, float clip_radius) \n"\
-"{ \n"\
-" // Outside the bounds \n"\
-" if (p.x < bounds.x || p.x > bounds.z \n"\
-" || p.y < bounds.y || p.y > bounds.w ) { \n"\
-" return 0.0; \n"\
-" } \n"\
-" float center_left = bounds.x + clip_radius; \n"\
-" float center_right = bounds.z - clip_radius; \n"\
-" float center_x; \n"\
-" \n"\
-" if (p.x < center_left) \n"\
-" center_x = center_left; \n"\
-" else if (p.x > center_right) \n"\
-" center_x = center_right; \n"\
-" else \n"\
-" return 1.0; // The vast majority of pixels exit early here \n"\
-" \n"\
-" float center_top = bounds.y + clip_radius; \n"\
-" float center_bottom = bounds.w - clip_radius; \n"\
-" float center_y; \n"\
-" \n"\
-" if (p.y < center_top) \n"\
-" center_y = center_top; \n"\
-" else if (p.y > center_bottom) \n"\
-" center_y = center_bottom; \n"\
-" else \n"\
-" return 1.0; \n"\
-" \n"\
-" vec2 delta = p - vec2 (center_x, center_y); \n"\
-" float dist_squared = dot (delta, delta); \n"\
-" \n"\
-" // Fully outside the circle \n"\
-" float outer_radius = clip_radius + 0.5; \n"\
-" if (dist_squared >= (outer_radius * outer_radius)) \n"\
-" return 0.0; \n"\
-" \n"\
-" // Fully inside the circle \n"\
-" float inner_radius = clip_radius - 0.5; \n"\
-" if (dist_squared <= (inner_radius * inner_radius)) \n"\
-" return 1.0; \n"\
-" \n"\
-" \n"\
-" // Only pixels on the edge of the curve need expensive antialiasing \n"\
-" return outer_radius - sqrt (dist_squared); \n"\
-"} \n"
-
-#define ROUNDED_CLIP_FRAGMENT_SHADER_VARS \
-"uniform vec4 bounds; // x, y: top left; z, w: bottom right \n"\
-"uniform float clip_radius; \n"\
-"uniform vec4 inner_bounds; \n"\
-"uniform float inner_clip_radius; \n"\
-"uniform vec2 pixel_step; \n"\
-"uniform int skip; \n"\
-"uniform float border_width; \n"\
-"uniform float border_brightness; \n"
-
-/* used by src/meta_clip_effect.c */
-#define ROUNDED_CLIP_FRAGMENT_SHADER_DECLARATIONS \
-ROUNDED_CLIP_FRAGMENT_SHADER_VARS \
-ROUNDED_CLIP_FRAGMENT_SHADER_FUNCS
-
-/* used by src/meta_clip_effect.c */
-#define ROUNDED_CLIP_FRAGMENT_SHADER_CODE \
-"if (skip == 0) { \n"\
-" vec2 texture_coord = cogl_tex_coord0_in.xy / pixel_step; \n"\
-" \n"\
-" float outer_alpha = rounded_rect_coverage (texture_coord, \n"\
-" bounds, \n"\
-" clip_radius); \n"\
-" if (border_width > 0.0) { \n"\
-" float inner_alpha = rounded_rect_coverage (texture_coord, \n"\
-" inner_bounds, \n"\
-" inner_clip_radius); \n"\
-" float border_alpha = clamp (outer_alpha - inner_alpha, 0.0, 1.0) \n"\
-" * cogl_color_out.a; \n"\
-" \n"\
-" cogl_color_out *= smoothstep (0.0, 0.6, inner_alpha); \n"\
-" cogl_color_out = mix (cogl_color_out, \n"\
-" vec4(vec3(border_brightness), 1.0), \n"\
-" border_alpha); \n"\
-" } else { \n"\
-" cogl_color_out = cogl_color_out * outer_alpha; \n"\
-" } \n"\
-"} \n"
-
-#define ROUNDED_CLIP_FRAGMENT_SHADER_VARS_BLUR \
-"uniform vec4 bounds; // x, y: top left; w, v: bottom right \n"\
-"uniform float clip_radius; \n"\
-"uniform vec2 pixel_step; \n"\
-"uniform int skip; \n"\
-"uniform float brightness; \n"
-
-/* used by shell-blur-effect.c */
-#define ROUNDED_CLIP_FRAGMENT_SHADER_DECLARATIONS_BLUR \
-ROUNDED_CLIP_FRAGMENT_SHADER_VARS_BLUR \
-ROUNDED_CLIP_FRAGMENT_SHADER_FUNCS
-
-/* used by shell-blur-effect.c */
-#define ROUNDED_CLIP_FRAGMENT_SHADER_CODE_BLUR \
-"if (skip == 0) { \n"\
-" vec2 texture_coord = cogl_tex_coord0_in.xy / pixel_step; \n"\
-" \n"\
-" cogl_color_out *= rounded_rect_coverage (texture_coord, \n"\
-" bounds, \n"\
-" clip_radius); \n"\
-"} \n"\
-"cogl_color_out.rgb *= brightness; \n"
diff --git a/shell-blur-effect.c b/shell-blur-effect.c
deleted file mode 100644
index 0d4bb458a87d..000000000000
--- a/shell-blur-effect.c
+++ /dev/null
@@ -1,907 +0,0 @@
-/* shell-blur-effect.c
- *
- * Copyright 2019 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#include "shell-blur-effect.h"
-
-#include "shell-enum-types.h"
-
-/**
- * SECTION:shell-blur-effect
- * @short_description: Blur effect for actors
- *
- * #ShellBlurEffect is a blur implementation based on Clutter. It also has
- * an optional brightness property.
- *
- * # Modes
- *
- * #ShellBlurEffect can work in @SHELL_BLUR_MODE_BACKGROUND and @SHELL_BLUR_MODE_ACTOR
- * modes. The actor mode blurs the actor itself, and all of its children. The
- * background mode blurs the pixels beneath the actor, but not the actor itself.
- *
- * @SHELL_BLUR_MODE_BACKGROUND can be computationally expensive, since the contents
- * beneath the actor cannot be cached, so beware of the performance implications
- * of using this blur mode.
- */
-
-static const gchar *brightness_glsl_declarations =
-"uniform float brightness; \n";
-
-static const gchar *brightness_glsl =
-" cogl_color_out.rgb *= brightness; \n";
-
-#define MIN_DOWNSCALE_SIZE 256.f
-#define MAX_SIGMA 6.f
-
-typedef enum
-{
- ACTOR_PAINTED = 1 << 0,
- BLUR_APPLIED = 1 << 1,
-} CacheFlags;
-
-typedef struct
-{
- CoglFramebuffer *framebuffer;
- CoglPipeline *pipeline;
- CoglTexture *texture;
-} FramebufferData;
-
-struct _ShellBlurEffect
-{
- ClutterEffect parent_instance;
-
- ClutterActor *actor;
-
- unsigned int tex_width;
- unsigned int tex_height;
-
- /* The cached contents */
- FramebufferData actor_fb;
- CacheFlags cache_flags;
-
- FramebufferData background_fb;
- FramebufferData brightness_fb;
- int brightness_uniform;
-
- ShellBlurMode mode;
- float downscale_factor;
- float brightness;
- int sigma;
-};
-
-G_DEFINE_TYPE (ShellBlurEffect, shell_blur_effect, CLUTTER_TYPE_EFFECT)
-
-enum {
- PROP_0,
- PROP_SIGMA,
- PROP_BRIGHTNESS,
- PROP_MODE,
- N_PROPS
-};
-
-static GParamSpec *properties [N_PROPS] = { NULL, };
-
-static CoglPipeline*
-create_base_pipeline (void)
-{
- static CoglPipeline *base_pipeline = NULL;
-
- if (G_UNLIKELY (base_pipeline == NULL))
- {
- CoglContext *ctx =
- clutter_backend_get_cogl_context (clutter_get_default_backend ());
-
- base_pipeline = cogl_pipeline_new (ctx);
- cogl_pipeline_set_layer_null_texture (base_pipeline, 0);
- cogl_pipeline_set_layer_filters (base_pipeline,
- 0,
- COGL_PIPELINE_FILTER_LINEAR,
- COGL_PIPELINE_FILTER_LINEAR);
- cogl_pipeline_set_layer_wrap_mode (base_pipeline,
- 0,
- COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
- }
-
- return cogl_pipeline_copy (base_pipeline);
-}
-
-static CoglPipeline*
-create_brightness_pipeline (void)
-{
- static CoglPipeline *brightness_pipeline = NULL;
-
- if (G_UNLIKELY (brightness_pipeline == NULL))
- {
- CoglSnippet *snippet;
-
- brightness_pipeline = create_base_pipeline ();
-
- snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
- brightness_glsl_declarations,
- brightness_glsl);
- cogl_pipeline_add_snippet (brightness_pipeline, snippet);
- cogl_object_unref (snippet);
- }
-
- return cogl_pipeline_copy (brightness_pipeline);
-}
-
-
-static void
-update_brightness (ShellBlurEffect *self,
- uint8_t paint_opacity)
-{
- cogl_pipeline_set_color4ub (self->brightness_fb.pipeline,
- paint_opacity,
- paint_opacity,
- paint_opacity,
- paint_opacity);
-
- if (self->brightness_uniform > -1)
- {
- cogl_pipeline_set_uniform_1f (self->brightness_fb.pipeline,
- self->brightness_uniform,
- self->brightness);
- }
-}
-
-static void
-setup_projection_matrix (CoglFramebuffer *framebuffer,
- float width,
- float height)
-{
- graphene_matrix_t projection;
-
- graphene_matrix_init_translate (&projection,
- &GRAPHENE_POINT3D_INIT (-width / 2.0,
- -height / 2.0,
- 0.f));
- graphene_matrix_scale (&projection, 2.0 / width, -2.0 / height, 1.f);
-
- cogl_framebuffer_set_projection_matrix (framebuffer, &projection);
-}
-
-static gboolean
-update_fbo (FramebufferData *data,
- unsigned int width,
- unsigned int height,
- float downscale_factor)
-{
- CoglContext *ctx =
- clutter_backend_get_cogl_context (clutter_get_default_backend ());
-
- g_clear_pointer (&data->texture, cogl_object_unref);
- g_clear_object (&data->framebuffer);
-
- float new_width = floorf (width / downscale_factor);
- float new_height = floorf (height / downscale_factor);
-
- data->texture = cogl_texture_2d_new_with_size (ctx, new_width, new_height);
- if (!data->texture)
- return FALSE;
-
- cogl_pipeline_set_layer_texture (data->pipeline, 0, data->texture);
-
- data->framebuffer =
- COGL_FRAMEBUFFER (cogl_offscreen_new_with_texture (data->texture));
- if (!data->framebuffer)
- {
- g_warning ("%s: Unable to create an Offscreen buffer", G_STRLOC);
- return FALSE;
- }
-
- setup_projection_matrix (data->framebuffer, new_width, new_height);
-
- return TRUE;
-}
-
-static gboolean
-update_actor_fbo (ShellBlurEffect *self,
- unsigned int width,
- unsigned int height,
- float downscale_factor)
-{
- if (self->tex_width == width &&
- self->tex_height == height &&
- self->downscale_factor == downscale_factor &&
- self->actor_fb.framebuffer)
- {
- return TRUE;
- }
-
- self->cache_flags &= ~ACTOR_PAINTED;
-
- return update_fbo (&self->actor_fb, width, height, downscale_factor);
-}
-
-static gboolean
-update_brightness_fbo (ShellBlurEffect *self,
- unsigned int width,
- unsigned int height,
- float downscale_factor)
-{
- if (self->tex_width == width &&
- self->tex_height == height &&
- self->downscale_factor == downscale_factor &&
- self->brightness_fb.framebuffer)
- {
- return TRUE;
- }
-
- return update_fbo (&self->brightness_fb,
- width, height,
- downscale_factor);
-}
-
-static gboolean
-update_background_fbo (ShellBlurEffect *self,
- unsigned int width,
- unsigned int height)
-{
- if (self->tex_width == width &&
- self->tex_height == height &&
- self->background_fb.framebuffer)
- {
- return TRUE;
- }
-
- return update_fbo (&self->background_fb, width, height, 1.0);
-}
-
-static void
-clear_framebuffer_data (FramebufferData *fb_data)
-{
- g_clear_pointer (&fb_data->texture, cogl_object_unref);
- g_clear_object (&fb_data->framebuffer);
-}
-
-static float
-calculate_downscale_factor (float width,
- float height,
- float sigma)
-{
- float downscale_factor = 1.0;
- float scaled_width = width;
- float scaled_height = height;
- float scaled_sigma = sigma;
-
- /* This is the algorithm used by Firefox; keep downscaling until either the
- * blur radius is lower than the threshold, or the downscaled texture is too
- * small.
- */
- while (scaled_sigma > MAX_SIGMA &&
- scaled_width > MIN_DOWNSCALE_SIZE &&
- scaled_height > MIN_DOWNSCALE_SIZE)
- {
- downscale_factor *= 2.f;
-
- scaled_width = width / downscale_factor;
- scaled_height = height / downscale_factor;
- scaled_sigma = sigma / downscale_factor;
- }
-
- return downscale_factor;
-}
-
-static void
-shell_blur_effect_set_actor (ClutterActorMeta *meta,
- ClutterActor *actor)
-{
- ShellBlurEffect *self = SHELL_BLUR_EFFECT (meta);
- ClutterActorMetaClass *meta_class;
-
- meta_class = CLUTTER_ACTOR_META_CLASS (shell_blur_effect_parent_class);
- meta_class->set_actor (meta, actor);
-
- /* clear out the previous state */
- clear_framebuffer_data (&self->actor_fb);
- clear_framebuffer_data (&self->background_fb);
- clear_framebuffer_data (&self->brightness_fb);
-
- /* we keep a back pointer here, to avoid going through the ActorMeta */
- self->actor = clutter_actor_meta_get_actor (meta);
-}
-
-static void
-update_actor_box (ShellBlurEffect *self,
- ClutterPaintContext *paint_context,
- ClutterActorBox *source_actor_box)
-{
- ClutterStageView *stage_view;
- float box_scale_factor = 1.0f;
- float origin_x, origin_y;
- float width, height;
-
- switch (self->mode)
- {
- case SHELL_BLUR_MODE_ACTOR:
- clutter_actor_get_allocation_box (self->actor, source_actor_box);
- break;
-
- case SHELL_BLUR_MODE_BACKGROUND:
- stage_view = clutter_paint_context_get_stage_view (paint_context);
-
- clutter_actor_get_transformed_position (self->actor, &origin_x, &origin_y);
- clutter_actor_get_transformed_size (self->actor, &width, &height);
-
- if (stage_view)
- {
- cairo_rectangle_int_t stage_view_layout;
-
- box_scale_factor = clutter_stage_view_get_scale (stage_view);
- clutter_stage_view_get_layout (stage_view, &stage_view_layout);
-
- origin_x -= stage_view_layout.x;
- origin_y -= stage_view_layout.y;
- }
- else
- {
- /* If we're drawing off stage, just assume scale = 1, this won't work
- * with stage-view scaling though.
- */
- }
-
- clutter_actor_box_set_origin (source_actor_box, origin_x, origin_y);
- clutter_actor_box_set_size (source_actor_box, width, height);
-
- clutter_actor_box_scale (source_actor_box, box_scale_factor);
- break;
- }
-
- clutter_actor_box_clamp_to_pixel (source_actor_box);
-}
-
-static void
-add_blurred_pipeline (ShellBlurEffect *self,
- ClutterPaintNode *node,
- uint8_t paint_opacity)
-{
- g_autoptr (ClutterPaintNode) pipeline_node = NULL;
- float width, height;
-
- /* Use the untransformed actor size here, since the framebuffer itself already
- * has the actor transform matrix applied.
- */
- clutter_actor_get_size (self->actor, &width, &height);
-
- update_brightness (self, paint_opacity);
-
- pipeline_node = clutter_pipeline_node_new (self->brightness_fb.pipeline);
- clutter_paint_node_set_static_name (pipeline_node, "ShellBlurEffect (final)");
- clutter_paint_node_add_child (node, pipeline_node);
-
- clutter_paint_node_add_rectangle (pipeline_node,
- &(ClutterActorBox) {
- 0.f, 0.f,
- width,
- height,
- });
-}
-
-static ClutterPaintNode *
-create_blur_nodes (ShellBlurEffect *self,
- ClutterPaintNode *node,
- uint8_t paint_opacity)
-{
- g_autoptr (ClutterPaintNode) brightness_node = NULL;
- g_autoptr (ClutterPaintNode) blur_node = NULL;
- float width;
- float height;
-
- clutter_actor_get_size (self->actor, &width, &height);
-
- update_brightness (self, paint_opacity);
- brightness_node = clutter_layer_node_new_to_framebuffer (self->brightness_fb.framebuffer,
- self->brightness_fb.pipeline);
- clutter_paint_node_set_static_name (brightness_node, "ShellBlurEffect (brightness)");
- clutter_paint_node_add_child (node, brightness_node);
- clutter_paint_node_add_rectangle (brightness_node,
- &(ClutterActorBox) {
- 0.f, 0.f,
- width, height,
- });
-
- blur_node = clutter_blur_node_new (self->tex_width / self->downscale_factor,
- self->tex_height / self->downscale_factor,
- self->sigma / self->downscale_factor);
- clutter_paint_node_set_static_name (blur_node, "ShellBlurEffect (blur)");
- clutter_paint_node_add_child (brightness_node, blur_node);
- clutter_paint_node_add_rectangle (blur_node,
- &(ClutterActorBox) {
- 0.f, 0.f,
- cogl_texture_get_width (self->brightness_fb.texture),
- cogl_texture_get_height (self->brightness_fb.texture),
- });
-
- self->cache_flags |= BLUR_APPLIED;
-
- return g_steal_pointer (&blur_node);
-}
-
-static void
-paint_background (ShellBlurEffect *self,
- ClutterPaintNode *node,
- ClutterPaintContext *paint_context,
- ClutterActorBox *source_actor_box)
-{
- g_autoptr (ClutterPaintNode) background_node = NULL;
- g_autoptr (ClutterPaintNode) blit_node = NULL;
- CoglFramebuffer *src;
- float transformed_x;
- float transformed_y;
- float transformed_width;
- float transformed_height;
-
- clutter_actor_box_get_origin (source_actor_box,
- &transformed_x,
- &transformed_y);
- clutter_actor_box_get_size (source_actor_box,
- &transformed_width,
- &transformed_height);
-
- /* Background layer node */
- background_node =
- clutter_layer_node_new_to_framebuffer (self->background_fb.framebuffer,
- self->background_fb.pipeline);
- clutter_paint_node_set_static_name (background_node, "ShellBlurEffect (background)");
- clutter_paint_node_add_child (node, background_node);
- clutter_paint_node_add_rectangle (background_node,
- &(ClutterActorBox) {
- 0.f, 0.f,
- self->tex_width / self->downscale_factor,
- self->tex_height / self->downscale_factor,
- });
-
- /* Blit node */
- src = clutter_paint_context_get_framebuffer (paint_context);
- blit_node = clutter_blit_node_new (src);
- clutter_paint_node_set_static_name (blit_node, "ShellBlurEffect (blit)");
- clutter_paint_node_add_child (background_node, blit_node);
- clutter_blit_node_add_blit_rectangle (CLUTTER_BLIT_NODE (blit_node),
- transformed_x,
- transformed_y,
- 0, 0,
- transformed_width,
- transformed_height);
-}
-
-static gboolean
-update_framebuffers (ShellBlurEffect *self,
- ClutterPaintContext *paint_context,
- ClutterActorBox *source_actor_box)
-{
- gboolean updated = FALSE;
- float downscale_factor;
- float height = -1;
- float width = -1;
-
- clutter_actor_box_get_size (source_actor_box, &width, &height);
-
- downscale_factor = calculate_downscale_factor (width, height, self->sigma);
-
- updated = update_actor_fbo (self, width, height, downscale_factor) &&
- update_brightness_fbo (self, width, height, downscale_factor);
-
- if (self->mode == SHELL_BLUR_MODE_BACKGROUND)
- updated = updated && update_background_fbo (self, width, height);
-
- self->tex_width = width;
- self->tex_height = height;
- self->downscale_factor = downscale_factor;
-
- return updated;
-}
-
-static void
-add_actor_node (ShellBlurEffect *self,
- ClutterPaintNode *node,
- int opacity)
-{
- g_autoptr (ClutterPaintNode) actor_node = NULL;
-
- actor_node = clutter_actor_node_new (self->actor, opacity);
- clutter_paint_node_add_child (node, actor_node);
-}
-
-static void
-paint_actor_offscreen (ShellBlurEffect *self,
- ClutterPaintNode *node,
- ClutterEffectPaintFlags flags)
-{
- gboolean actor_dirty;
-
- actor_dirty = (flags & CLUTTER_EFFECT_PAINT_ACTOR_DIRTY) != 0;
-
- /* The actor offscreen framebuffer is updated already */
- if (actor_dirty || !(self->cache_flags & ACTOR_PAINTED))
- {
- g_autoptr (ClutterPaintNode) transform_node = NULL;
- g_autoptr (ClutterPaintNode) layer_node = NULL;
- graphene_matrix_t transform;
-
- /* Layer node */
- layer_node = clutter_layer_node_new_to_framebuffer (self->actor_fb.framebuffer,
- self->actor_fb.pipeline);
- clutter_paint_node_set_static_name (layer_node, "ShellBlurEffect (actor offscreen)");
- clutter_paint_node_add_child (node, layer_node);
- clutter_paint_node_add_rectangle (layer_node,
- &(ClutterActorBox) {
- 0.f, 0.f,
- self->tex_width / self->downscale_factor,
- self->tex_height / self->downscale_factor,
- });
-
- /* Transform node */
- graphene_matrix_init_scale (&transform,
- 1.f / self->downscale_factor,
- 1.f / self->downscale_factor,
- 1.f);
- transform_node = clutter_transform_node_new (&transform);
- clutter_paint_node_set_static_name (transform_node, "ShellBlurEffect (downscale)");
- clutter_paint_node_add_child (layer_node, transform_node);
-
- /* Actor node */
- add_actor_node (self, transform_node, 255);
-
- self->cache_flags |= ACTOR_PAINTED;
- }
- else
- {
- g_autoptr (ClutterPaintNode) pipeline_node = NULL;
-
- pipeline_node = clutter_pipeline_node_new (self->actor_fb.pipeline);
- clutter_paint_node_set_static_name (pipeline_node,
- "ShellBlurEffect (actor texture)");
- clutter_paint_node_add_child (node, pipeline_node);
- clutter_paint_node_add_rectangle (pipeline_node,
- &(ClutterActorBox) {
- 0.f, 0.f,
- self->tex_width / self->downscale_factor,
- self->tex_height / self->downscale_factor,
- });
- }
-}
-
-static gboolean
-needs_repaint (ShellBlurEffect *self,
- ClutterEffectPaintFlags flags)
-{
- gboolean actor_cached;
- gboolean blur_cached;
- gboolean actor_dirty;
-
- actor_dirty = (flags & CLUTTER_EFFECT_PAINT_ACTOR_DIRTY) != 0;
- blur_cached = (self->cache_flags & BLUR_APPLIED) != 0;
- actor_cached = (self->cache_flags & ACTOR_PAINTED) != 0;
-
- switch (self->mode)
- {
- case SHELL_BLUR_MODE_ACTOR:
- return actor_dirty || !blur_cached || !actor_cached;
-
- case SHELL_BLUR_MODE_BACKGROUND:
- return TRUE;
- }
-
- return TRUE;
-}
-
-static void
-shell_blur_effect_paint_node (ClutterEffect *effect,
- ClutterPaintNode *node,
- ClutterPaintContext *paint_context,
- ClutterEffectPaintFlags flags)
-{
- ShellBlurEffect *self = SHELL_BLUR_EFFECT (effect);
- uint8_t paint_opacity;
-
- g_assert (self->actor != NULL);
-
- if (self->sigma > 0)
- {
- g_autoptr (ClutterPaintNode) blur_node = NULL;
-
- switch (self->mode)
- {
- case SHELL_BLUR_MODE_ACTOR:
- paint_opacity = clutter_actor_get_paint_opacity (self->actor);
- break;
-
- case SHELL_BLUR_MODE_BACKGROUND:
- paint_opacity = 255;
- break;
-
- default:
- g_assert_not_reached();
- break;
- }
-
- if (needs_repaint (self, flags))
- {
- ClutterActorBox source_actor_box;
-
- update_actor_box (self, paint_context, &source_actor_box);
-
- /* Failing to create or update the offscreen framebuffers prevents
- * the entire effect to be applied.
- */
- if (!update_framebuffers (self, paint_context, &source_actor_box))
- goto fail;
-
- blur_node = create_blur_nodes (self, node, paint_opacity);
-
- switch (self->mode)
- {
- case SHELL_BLUR_MODE_ACTOR:
- paint_actor_offscreen (self, blur_node, flags);
- break;
-
- case SHELL_BLUR_MODE_BACKGROUND:
- paint_background (self, blur_node, paint_context, &source_actor_box);
- break;
- }
- }
- else
- {
- /* Use the cached pipeline if no repaint is needed */
- add_blurred_pipeline (self, node, paint_opacity);
- }
-
- /* Background blur needs to paint the actor after painting the blurred
- * background.
- */
- switch (self->mode)
- {
- case SHELL_BLUR_MODE_ACTOR:
- break;
-
- case SHELL_BLUR_MODE_BACKGROUND:
- add_actor_node (self, node, -1);
- break;
- }
-
- return;
- }
-
-fail:
- /* When no blur is applied, or the offscreen framebuffers
- * couldn't be created, fallback to simply painting the actor.
- */
- add_actor_node (self, node, -1);
-}
-
-static void
-shell_blur_effect_finalize (GObject *object)
-{
- ShellBlurEffect *self = (ShellBlurEffect *)object;
-
- clear_framebuffer_data (&self->actor_fb);
- clear_framebuffer_data (&self->background_fb);
- clear_framebuffer_data (&self->brightness_fb);
-
- g_clear_pointer (&self->actor_fb.pipeline, cogl_object_unref);
- g_clear_pointer (&self->background_fb.pipeline, cogl_object_unref);
- g_clear_pointer (&self->brightness_fb.pipeline, cogl_object_unref);
-
- G_OBJECT_CLASS (shell_blur_effect_parent_class)->finalize (object);
-}
-
-static void
-shell_blur_effect_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- ShellBlurEffect *self = SHELL_BLUR_EFFECT (object);
-
- switch (prop_id)
- {
- case PROP_SIGMA:
- g_value_set_int (value, self->sigma);
- break;
-
- case PROP_BRIGHTNESS:
- g_value_set_float (value, self->brightness);
- break;
-
- case PROP_MODE:
- g_value_set_enum (value, self->mode);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-shell_blur_effect_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- ShellBlurEffect *self = SHELL_BLUR_EFFECT (object);
-
- switch (prop_id)
- {
- case PROP_SIGMA:
- shell_blur_effect_set_sigma (self, g_value_get_int (value));
- break;
-
- case PROP_BRIGHTNESS:
- shell_blur_effect_set_brightness (self, g_value_get_float (value));
- break;
-
- case PROP_MODE:
- shell_blur_effect_set_mode (self, g_value_get_enum (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-shell_blur_effect_class_init (ShellBlurEffectClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
- ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass);
-
- object_class->finalize = shell_blur_effect_finalize;
- object_class->get_property = shell_blur_effect_get_property;
- object_class->set_property = shell_blur_effect_set_property;
-
- meta_class->set_actor = shell_blur_effect_set_actor;
-
- effect_class->paint_node = shell_blur_effect_paint_node;
-
- properties[PROP_SIGMA] =
- g_param_spec_int ("sigma",
- "Sigma",
- "Sigma",
- 0, G_MAXINT, 0,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
-
- properties[PROP_BRIGHTNESS] =
- g_param_spec_float ("brightness",
- "Brightness",
- "Brightness",
- 0.f, 1.f, 1.f,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
-
- properties[PROP_MODE] =
- g_param_spec_enum ("mode",
- "Blur mode",
- "Blur mode",
- SHELL_TYPE_BLUR_MODE,
- SHELL_BLUR_MODE_ACTOR,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-}
-
-static void
-shell_blur_effect_init (ShellBlurEffect *self)
-{
- self->mode = SHELL_BLUR_MODE_ACTOR;
- self->sigma = 0;
- self->brightness = 1.f;
-
- self->actor_fb.pipeline = create_base_pipeline ();
- self->background_fb.pipeline = create_base_pipeline ();
- self->brightness_fb.pipeline = create_brightness_pipeline ();
- self->brightness_uniform =
- cogl_pipeline_get_uniform_location (self->brightness_fb.pipeline, "brightness");
-}
-
-ShellBlurEffect *
-shell_blur_effect_new (void)
-{
- return g_object_new (SHELL_TYPE_BLUR_EFFECT, NULL);
-}
-
-int
-shell_blur_effect_get_sigma (ShellBlurEffect *self)
-{
- g_return_val_if_fail (SHELL_IS_BLUR_EFFECT (self), -1);
-
- return self->sigma;
-}
-
-void
-shell_blur_effect_set_sigma (ShellBlurEffect *self,
- int sigma)
-{
- g_return_if_fail (SHELL_IS_BLUR_EFFECT (self));
-
- if (self->sigma == sigma)
- return;
-
- self->sigma = sigma;
- self->cache_flags &= ~BLUR_APPLIED;
-
- if (self->actor)
- clutter_effect_queue_repaint (CLUTTER_EFFECT (self));
-
- g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SIGMA]);
-}
-
-float
-shell_blur_effect_get_brightness (ShellBlurEffect *self)
-{
- g_return_val_if_fail (SHELL_IS_BLUR_EFFECT (self), FALSE);
-
- return self->brightness;
-}
-
-void
-shell_blur_effect_set_brightness (ShellBlurEffect *self,
- float brightness)
-{
- g_return_if_fail (SHELL_IS_BLUR_EFFECT (self));
-
- if (self->brightness == brightness)
- return;
-
- self->brightness = brightness;
- self->cache_flags &= ~BLUR_APPLIED;
-
- if (self->actor)
- clutter_effect_queue_repaint (CLUTTER_EFFECT (self));
-
- g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BRIGHTNESS]);
-}
-
-ShellBlurMode
-shell_blur_effect_get_mode (ShellBlurEffect *self)
-{
- g_return_val_if_fail (SHELL_IS_BLUR_EFFECT (self), -1);
-
- return self->mode;
-}
-
-void
-shell_blur_effect_set_mode (ShellBlurEffect *self,
- ShellBlurMode mode)
-{
- g_return_if_fail (SHELL_IS_BLUR_EFFECT (self));
-
- if (self->mode == mode)
- return;
-
- self->mode = mode;
- self->cache_flags &= ~BLUR_APPLIED;
-
- switch (mode)
- {
- case SHELL_BLUR_MODE_ACTOR:
- clear_framebuffer_data (&self->background_fb);
- break;
-
- case SHELL_BLUR_MODE_BACKGROUND:
- default:
- /* Do nothing */
- break;
- }
-
- if (self->actor)
- clutter_effect_queue_repaint (CLUTTER_EFFECT (self));
-
- g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODE]);
-}
diff --git a/shell-blur-effect.h b/shell-blur-effect.h
deleted file mode 100644
index a7486ccde09b..000000000000
--- a/shell-blur-effect.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* shell-blur-effect.h
- *
- * Copyright 2019 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include <clutter/clutter.h>
-
-G_BEGIN_DECLS
-
-/**
- * ShellBlurMode:
- * @SHELL_BLUR_MODE_ACTOR: blur the actor contents, and its children
- * @SHELL_BLUR_MODE_BACKGROUND: blur what's beneath the actor
- *
- * The mode of blurring of the effect.
- */
-typedef enum
-{
- SHELL_BLUR_MODE_ACTOR,
- SHELL_BLUR_MODE_BACKGROUND,
-} ShellBlurMode;
-
-#define SHELL_TYPE_BLUR_EFFECT (shell_blur_effect_get_type())
-G_DECLARE_FINAL_TYPE (ShellBlurEffect, shell_blur_effect, SHELL, BLUR_EFFECT, ClutterEffect)
-
-ShellBlurEffect *shell_blur_effect_new (void);
-
-int shell_blur_effect_get_sigma (ShellBlurEffect *self);
-void shell_blur_effect_set_sigma (ShellBlurEffect *self,
- int sigma);
-
-float shell_blur_effect_get_brightness (ShellBlurEffect *self);
-void shell_blur_effect_set_brightness (ShellBlurEffect *self,
- float brightness);
-
-ShellBlurMode shell_blur_effect_get_mode (ShellBlurEffect *self);
-void shell_blur_effect_set_mode (ShellBlurEffect *self,
- ShellBlurMode mode);
-
-G_END_DECLS
diff --git a/shell_blur_effect.patch b/shell_blur_effect.patch
deleted file mode 100644
index e2ed3edfae0b..000000000000
--- a/shell_blur_effect.patch
+++ /dev/null
@@ -1,462 +0,0 @@
-diff -Narup a/src/shell-blur-effect.c b/src/shell-blur-effect.c
---- a/src/shell-blur-effect.c 2022-03-31 10:47:02.847618301 +0800
-+++ b/src/shell-blur-effect.c 2022-03-31 10:47:02.847618301 +0800
-@@ -22,6 +22,9 @@
-
- #include "shell-enum-types.h"
-
-+#include "meta/prefs.h"
-+#include "shader.h"
-+
- /**
- * SECTION:shell-blur-effect
- * @short_description: Blur effect for actors
-@@ -40,12 +43,6 @@
- * of using this blur mode.
- */
-
--static const gchar *brightness_glsl_declarations =
--"uniform float brightness; \n";
--
--static const gchar *brightness_glsl =
--" cogl_color_out.rgb *= brightness; \n";
--
- #define MIN_DOWNSCALE_SIZE 256.f
- #define MAX_SIGMA 6.f
-
-@@ -62,7 +59,7 @@ typedef struct
- CoglTexture *texture;
- } FramebufferData;
-
--struct _ShellBlurEffect
-+struct _MetaShellBlurEffect
- {
- ClutterEffect parent_instance;
-
-@@ -78,6 +75,11 @@ struct _ShellBlurEffect
- FramebufferData background_fb;
- FramebufferData brightness_fb;
- int brightness_uniform;
-+ int bounds_uniform;
-+ int clip_radius_uniform;
-+ int pixel_step_uniform;
-+ int skip_uniform;
-+ gboolean skip;
-
- ShellBlurMode mode;
- float downscale_factor;
-@@ -85,7 +87,7 @@ struct _ShellBlurEffect
- int sigma;
- };
-
--G_DEFINE_TYPE (ShellBlurEffect, shell_blur_effect, CLUTTER_TYPE_EFFECT)
-+G_DEFINE_TYPE (MetaShellBlurEffect, meta_shell_blur_effect, CLUTTER_TYPE_EFFECT)
-
- enum {
- PROP_0,
-@@ -133,8 +135,8 @@ create_brightness_pipeline (void)
- brightness_pipeline = create_base_pipeline ();
-
- snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
-- brightness_glsl_declarations,
-- brightness_glsl);
-+ ROUNDED_CLIP_FRAGMENT_SHADER_DECLARATIONS_BLUR,
-+ ROUNDED_CLIP_FRAGMENT_SHADER_CODE_BLUR);
- cogl_pipeline_add_snippet (brightness_pipeline, snippet);
- cogl_object_unref (snippet);
- }
-@@ -144,7 +146,7 @@ create_brightness_pipeline (void)
-
-
- static void
--update_brightness (ShellBlurEffect *self,
-+update_brightness (MetaShellBlurEffect *self,
- uint8_t paint_opacity)
- {
- cogl_pipeline_set_color4ub (self->brightness_fb.pipeline,
-@@ -155,9 +157,29 @@ update_brightness (ShellBlurEffect *self
-
- if (self->brightness_uniform > -1)
- {
-+ cogl_pipeline_set_uniform_1i (self->brightness_fb.pipeline,
-+ self->skip_uniform, self->skip);
- cogl_pipeline_set_uniform_1f (self->brightness_fb.pipeline,
- self->brightness_uniform,
- self->brightness);
-+ if (self->skip)
-+ return;
-+
-+ float width = self->tex_width;
-+ float height = self->tex_height;
-+ float radius = meta_prefs_get_round_corner_radius();
-+ float bounds[] = { 0.0, 0.0, width, height };
-+ float pixel_step[] = { 1.0 / width, 1.0 / height };
-+
-+ cogl_pipeline_set_uniform_float (self->brightness_fb.pipeline,
-+ self->bounds_uniform,
-+ 4, 1, bounds);
-+ cogl_pipeline_set_uniform_1f (self->brightness_fb.pipeline,
-+ self->clip_radius_uniform,
-+ radius);
-+ cogl_pipeline_set_uniform_float (self->brightness_fb.pipeline,
-+ self->pixel_step_uniform,
-+ 2, 1, pixel_step);
- }
- }
-
-@@ -212,7 +234,7 @@ update_fbo (FramebufferData *data,
- }
-
- static gboolean
--update_actor_fbo (ShellBlurEffect *self,
-+update_actor_fbo (MetaShellBlurEffect *self,
- unsigned int width,
- unsigned int height,
- float downscale_factor)
-@@ -231,7 +253,7 @@ update_actor_fbo (ShellBlurEffect *self,
- }
-
- static gboolean
--update_brightness_fbo (ShellBlurEffect *self,
-+update_brightness_fbo (MetaShellBlurEffect *self,
- unsigned int width,
- unsigned int height,
- float downscale_factor)
-@@ -250,7 +272,7 @@ update_brightness_fbo (ShellBlurEffect *
- }
-
- static gboolean
--update_background_fbo (ShellBlurEffect *self,
-+update_background_fbo (MetaShellBlurEffect *self,
- unsigned int width,
- unsigned int height)
- {
-@@ -303,10 +325,10 @@ static void
- shell_blur_effect_set_actor (ClutterActorMeta *meta,
- ClutterActor *actor)
- {
-- ShellBlurEffect *self = SHELL_BLUR_EFFECT (meta);
-+ MetaShellBlurEffect *self = META_SHELL_BLUR_EFFECT (meta);
- ClutterActorMetaClass *meta_class;
-
-- meta_class = CLUTTER_ACTOR_META_CLASS (shell_blur_effect_parent_class);
-+ meta_class = CLUTTER_ACTOR_META_CLASS (meta_shell_blur_effect_parent_class);
- meta_class->set_actor (meta, actor);
-
- /* clear out the previous state */
-@@ -319,7 +341,7 @@ shell_blur_effect_set_actor (ClutterActo
- }
-
- static void
--update_actor_box (ShellBlurEffect *self,
-+update_actor_box (MetaShellBlurEffect *self,
- ClutterPaintContext *paint_context,
- ClutterActorBox *source_actor_box)
- {
-@@ -368,7 +390,7 @@ update_actor_box (ShellBlurEffect *s
- }
-
- static void
--add_blurred_pipeline (ShellBlurEffect *self,
-+add_blurred_pipeline (MetaShellBlurEffect *self,
- ClutterPaintNode *node,
- uint8_t paint_opacity)
- {
-@@ -395,7 +417,7 @@ add_blurred_pipeline (ShellBlurEffect *
- }
-
- static ClutterPaintNode *
--create_blur_nodes (ShellBlurEffect *self,
-+create_blur_nodes (MetaShellBlurEffect *self,
- ClutterPaintNode *node,
- uint8_t paint_opacity)
- {
-@@ -435,7 +457,7 @@ create_blur_nodes (ShellBlurEffect *sel
- }
-
- static void
--paint_background (ShellBlurEffect *self,
-+paint_background (MetaShellBlurEffect *self,
- ClutterPaintNode *node,
- ClutterPaintContext *paint_context,
- ClutterActorBox *source_actor_box)
-@@ -482,7 +504,7 @@ paint_background (ShellBlurEffect *s
- }
-
- static gboolean
--update_framebuffers (ShellBlurEffect *self,
-+update_framebuffers (MetaShellBlurEffect *self,
- ClutterPaintContext *paint_context,
- ClutterActorBox *source_actor_box)
- {
-@@ -509,7 +531,7 @@ update_framebuffers (ShellBlurEffect
- }
-
- static void
--add_actor_node (ShellBlurEffect *self,
-+add_actor_node (MetaShellBlurEffect *self,
- ClutterPaintNode *node,
- int opacity)
- {
-@@ -520,7 +542,7 @@ add_actor_node (ShellBlurEffect *self,
- }
-
- static void
--paint_actor_offscreen (ShellBlurEffect *self,
-+paint_actor_offscreen (MetaShellBlurEffect *self,
- ClutterPaintNode *node,
- ClutterEffectPaintFlags flags)
- {
-@@ -579,7 +601,7 @@ paint_actor_offscreen (ShellBlurEffect
- }
-
- static gboolean
--needs_repaint (ShellBlurEffect *self,
-+needs_repaint (MetaShellBlurEffect *self,
- ClutterEffectPaintFlags flags)
- {
- gboolean actor_cached;
-@@ -608,7 +630,7 @@ shell_blur_effect_paint_node (ClutterEff
- ClutterPaintContext *paint_context,
- ClutterEffectPaintFlags flags)
- {
-- ShellBlurEffect *self = SHELL_BLUR_EFFECT (effect);
-+ MetaShellBlurEffect *self = META_SHELL_BLUR_EFFECT (effect);
- uint8_t paint_opacity;
-
- g_assert (self->actor != NULL);
-@@ -689,7 +711,7 @@ fail:
- static void
- shell_blur_effect_finalize (GObject *object)
- {
-- ShellBlurEffect *self = (ShellBlurEffect *)object;
-+ MetaShellBlurEffect *self = (MetaShellBlurEffect *)object;
-
- clear_framebuffer_data (&self->actor_fb);
- clear_framebuffer_data (&self->background_fb);
-@@ -699,7 +721,7 @@ shell_blur_effect_finalize (GObject *obj
- g_clear_pointer (&self->background_fb.pipeline, cogl_object_unref);
- g_clear_pointer (&self->brightness_fb.pipeline, cogl_object_unref);
-
-- G_OBJECT_CLASS (shell_blur_effect_parent_class)->finalize (object);
-+ G_OBJECT_CLASS (meta_shell_blur_effect_parent_class)->finalize (object);
- }
-
- static void
-@@ -708,7 +730,7 @@ shell_blur_effect_get_property (GObject
- GValue *value,
- GParamSpec *pspec)
- {
-- ShellBlurEffect *self = SHELL_BLUR_EFFECT (object);
-+ MetaShellBlurEffect *self = META_SHELL_BLUR_EFFECT (object);
-
- switch (prop_id)
- {
-@@ -735,20 +757,20 @@ shell_blur_effect_set_property (GObject
- const GValue *value,
- GParamSpec *pspec)
- {
-- ShellBlurEffect *self = SHELL_BLUR_EFFECT (object);
-+ MetaShellBlurEffect *self = META_SHELL_BLUR_EFFECT (object);
-
- switch (prop_id)
- {
- case PROP_SIGMA:
-- shell_blur_effect_set_sigma (self, g_value_get_int (value));
-+ meta_shell_blur_effect_set_sigma (self, g_value_get_int (value));
- break;
-
- case PROP_BRIGHTNESS:
-- shell_blur_effect_set_brightness (self, g_value_get_float (value));
-+ meta_shell_blur_effect_set_brightness (self, g_value_get_float (value));
- break;
-
- case PROP_MODE:
-- shell_blur_effect_set_mode (self, g_value_get_enum (value));
-+ meta_shell_blur_effect_set_mode (self, g_value_get_enum (value));
- break;
-
- default:
-@@ -757,7 +779,7 @@ shell_blur_effect_set_property (GObject
- }
-
- static void
--shell_blur_effect_class_init (ShellBlurEffectClass *klass)
-+meta_shell_blur_effect_class_init (MetaShellBlurEffectClass *klass)
- {
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
-@@ -797,38 +819,48 @@ shell_blur_effect_class_init (ShellBlurE
- }
-
- static void
--shell_blur_effect_init (ShellBlurEffect *self)
-+meta_shell_blur_effect_init (MetaShellBlurEffect *self)
- {
- self->mode = SHELL_BLUR_MODE_ACTOR;
- self->sigma = 0;
- self->brightness = 1.f;
-+ self->skip = false;
-
- self->actor_fb.pipeline = create_base_pipeline ();
- self->background_fb.pipeline = create_base_pipeline ();
- self->brightness_fb.pipeline = create_brightness_pipeline ();
- self->brightness_uniform =
- cogl_pipeline_get_uniform_location (self->brightness_fb.pipeline, "brightness");
-+ self->bounds_uniform =
-+ cogl_pipeline_get_uniform_location (self->brightness_fb.pipeline, "bounds");
-+ self->clip_radius_uniform =
-+ cogl_pipeline_get_uniform_location (self->brightness_fb.pipeline, "clip_radius");
-+ self->pixel_step_uniform =
-+ cogl_pipeline_get_uniform_location (self->brightness_fb.pipeline, "pixel_step");
-+ self->skip_uniform =
-+ cogl_pipeline_get_uniform_location (self->brightness_fb.pipeline, "skip");
-+
- }
-
--ShellBlurEffect *
--shell_blur_effect_new (void)
-+MetaShellBlurEffect *
-+meta_shell_blur_effect_new (void)
- {
-- return g_object_new (SHELL_TYPE_BLUR_EFFECT, NULL);
-+ return g_object_new (META_SHELL_TYPE_BLUR_EFFECT, NULL);
- }
-
- int
--shell_blur_effect_get_sigma (ShellBlurEffect *self)
-+meta_shell_blur_effect_get_sigma (MetaShellBlurEffect *self)
- {
-- g_return_val_if_fail (SHELL_IS_BLUR_EFFECT (self), -1);
-+ g_return_val_if_fail (META_IS_SHELL_BLUR_EFFECT (self), -1);
-
- return self->sigma;
- }
-
- void
--shell_blur_effect_set_sigma (ShellBlurEffect *self,
-+meta_shell_blur_effect_set_sigma (MetaShellBlurEffect *self,
- int sigma)
- {
-- g_return_if_fail (SHELL_IS_BLUR_EFFECT (self));
-+ g_return_if_fail (META_IS_SHELL_BLUR_EFFECT (self));
-
- if (self->sigma == sigma)
- return;
-@@ -843,18 +875,18 @@ shell_blur_effect_set_sigma (ShellBlurEf
- }
-
- float
--shell_blur_effect_get_brightness (ShellBlurEffect *self)
-+meta_shell_blur_effect_get_brightness (MetaShellBlurEffect *self)
- {
-- g_return_val_if_fail (SHELL_IS_BLUR_EFFECT (self), FALSE);
-+ g_return_val_if_fail (META_IS_SHELL_BLUR_EFFECT (self), FALSE);
-
- return self->brightness;
- }
-
- void
--shell_blur_effect_set_brightness (ShellBlurEffect *self,
-+meta_shell_blur_effect_set_brightness (MetaShellBlurEffect *self,
- float brightness)
- {
-- g_return_if_fail (SHELL_IS_BLUR_EFFECT (self));
-+ g_return_if_fail (META_IS_SHELL_BLUR_EFFECT (self));
-
- if (self->brightness == brightness)
- return;
-@@ -869,18 +901,18 @@ shell_blur_effect_set_brightness (ShellB
- }
-
- ShellBlurMode
--shell_blur_effect_get_mode (ShellBlurEffect *self)
-+meta_shell_blur_effect_get_mode (MetaShellBlurEffect *self)
- {
-- g_return_val_if_fail (SHELL_IS_BLUR_EFFECT (self), -1);
-+ g_return_val_if_fail (META_IS_SHELL_BLUR_EFFECT (self), -1);
-
- return self->mode;
- }
-
- void
--shell_blur_effect_set_mode (ShellBlurEffect *self,
-+meta_shell_blur_effect_set_mode (MetaShellBlurEffect *self,
- ShellBlurMode mode)
- {
-- g_return_if_fail (SHELL_IS_BLUR_EFFECT (self));
-+ g_return_if_fail (META_IS_SHELL_BLUR_EFFECT (self));
-
- if (self->mode == mode)
- return;
-@@ -905,3 +937,17 @@ shell_blur_effect_set_mode (ShellBlurEff
-
- g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODE]);
- }
-+
-+void meta_shell_blur_effect_set_skip (MetaShellBlurEffect *self,
-+ gboolean skip)
-+{
-+ g_return_if_fail (META_IS_SHELL_BLUR_EFFECT (self));
-+
-+ if (self->skip == skip)
-+ return;
-+
-+ self->skip = skip;
-+
-+ if (self->actor)
-+ clutter_effect_queue_repaint (CLUTTER_EFFECT (self));
-+}
-diff -Narup a/src/shell-blur-effect.h b/src/shell-blur-effect.h
---- a/src/shell-blur-effect.h 2022-03-31 10:47:02.847618301 +0800
-+++ b/src/shell-blur-effect.h 2022-03-31 10:47:02.847618301 +0800
-@@ -20,6 +20,10 @@
-
- #pragma once
-
-+/*
-+ * have to rename the type, to avoide conflicts with gnome shell
-+ */
-+
- #include <clutter/clutter.h>
-
- G_BEGIN_DECLS
-@@ -37,21 +41,24 @@ typedef enum
- SHELL_BLUR_MODE_BACKGROUND,
- } ShellBlurMode;
-
--#define SHELL_TYPE_BLUR_EFFECT (shell_blur_effect_get_type())
--G_DECLARE_FINAL_TYPE (ShellBlurEffect, shell_blur_effect, SHELL, BLUR_EFFECT, ClutterEffect)
-+#define META_SHELL_TYPE_BLUR_EFFECT (meta_shell_blur_effect_get_type())
-+G_DECLARE_FINAL_TYPE (MetaShellBlurEffect, meta_shell_blur_effect, META, SHELL_BLUR_EFFECT, ClutterEffect)
-+
-+MetaShellBlurEffect *meta_shell_blur_effect_new (void);
-+
-+int meta_shell_blur_effect_get_sigma (MetaShellBlurEffect *self);
-+void meta_shell_blur_effect_set_sigma (MetaShellBlurEffect *self,
-+ int sigma);
-+
-+float meta_shell_blur_effect_get_brightness (MetaShellBlurEffect *self);
-+void meta_shell_blur_effect_set_brightness (MetaShellBlurEffect *self,
-+ float brightness);
-
--ShellBlurEffect *shell_blur_effect_new (void);
-+ShellBlurMode meta_shell_blur_effect_get_mode (MetaShellBlurEffect *self);
-+void meta_shell_blur_effect_set_mode (MetaShellBlurEffect *self,
-+ ShellBlurMode mode);
-
--int shell_blur_effect_get_sigma (ShellBlurEffect *self);
--void shell_blur_effect_set_sigma (ShellBlurEffect *self,
-- int sigma);
--
--float shell_blur_effect_get_brightness (ShellBlurEffect *self);
--void shell_blur_effect_set_brightness (ShellBlurEffect *self,
-- float brightness);
--
--ShellBlurMode shell_blur_effect_get_mode (ShellBlurEffect *self);
--void shell_blur_effect_set_mode (ShellBlurEffect *self,
-- ShellBlurMode mode);
-+void meta_shell_blur_effect_set_skip (MetaShellBlurEffect *self,
-+ gboolean skip);
-
- G_END_DECLS