diff -ruN a/src/events.cpp b/src/events.cpp --- a/src/events.cpp 2026-04-08 10:00:41.000000000 -0300 +++ b/src/events.cpp 2026-07-03 20:48:53.648591796 -0300 @@ -398,7 +398,7 @@ } if ((dirtyProperties & NET::WMStrut) != 0 || (dirtyProperties2 & NET::WM2ExtendedStrut) != 0) { - workspace()->rearrange(); + workspace()->scheduleRearrange(); } if ((dirtyProperties & NET::WMIcon) != 0) { getIcons(); diff -ruN a/src/plugins/backgroundcontrast/contrast.cpp b/src/plugins/backgroundcontrast/contrast.cpp --- a/src/plugins/backgroundcontrast/contrast.cpp 2026-04-08 10:00:41.000000000 -0300 +++ b/src/plugins/backgroundcontrast/contrast.cpp 2026-07-03 20:52:36.464290127 -0300 @@ -28,6 +28,7 @@ { static const QByteArray s_contrastAtomName = QByteArrayLiteral("_KDE_NET_WM_BACKGROUND_CONTRAST_REGION"); +static const QByteArray s_panelAnimatingAtomName = QByteArrayLiteral("_SONIC_WM_PANEL_ANIMATING"); ContrastManagerInterface *ContrastEffect::s_contrastManager = nullptr; QTimer *ContrastEffect::s_contrastManagerRemoveTimer = nullptr; @@ -42,6 +43,12 @@ if (m_shader && m_shader->isValid()) { if (effects->xcbConnection()) { m_net_wm_contrast_region = effects->announceSupportProperty(s_contrastAtomName, this); + xcb_connection_t *c = effects->xcbConnection(); + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(c, xcb_intern_atom_unchecked(c, false, s_panelAnimatingAtomName.length(), s_panelAnimatingAtomName.constData()), nullptr); + if (reply) { + m_panelAnimatingAtom = reply->atom; + free(reply); + } } } @@ -53,6 +60,14 @@ connect(effects, &EffectsHandler::xcbConnectionChanged, this, [this]() { if (m_shader && m_shader->isValid()) { m_net_wm_contrast_region = effects->announceSupportProperty(s_contrastAtomName, this); + if (effects->xcbConnection()) { + xcb_connection_t *c = effects->xcbConnection(); + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(c, xcb_intern_atom_unchecked(c, false, s_panelAnimatingAtomName.length(), s_panelAnimatingAtomName.constData()), nullptr); + if (reply) { + m_panelAnimatingAtom = reply->atom; + free(reply); + } + } } }); @@ -182,11 +197,36 @@ void ContrastEffect::slotPropertyNotify(EffectWindow *w, long atom) { - if (w && atom == m_net_wm_contrast_region && m_net_wm_contrast_region != XCB_ATOM_NONE) { + if (!w) { + return; + } + if (atom == m_panelAnimatingAtom && m_panelAnimatingAtom != XCB_ATOM_NONE) { + if (!isPanelAnimating(w)) { + updateContrastRegion(w); + } + return; + } + if (atom == m_net_wm_contrast_region && m_net_wm_contrast_region != XCB_ATOM_NONE) { + if (isPanelAnimating(w)) { + return; + } updateContrastRegion(w); } } +bool ContrastEffect::isPanelAnimating(EffectWindow *w) const +{ + if (m_panelAnimatingAtom == XCB_ATOM_NONE) { + return false; + } + const QByteArray value = w->readProperty(m_panelAnimatingAtom, XCB_ATOM_CARDINAL, 32); + if (value.size() < static_cast(sizeof(uint32_t))) { + return false; + } + const uint32_t *cardinals = reinterpret_cast(value.constData()); + return cardinals[0] != 0; +} + QMatrix4x4 ContrastEffect::colorMatrix(qreal contrast, qreal intensity, qreal saturation) { QMatrix4x4 satMatrix; // saturation diff -ruN a/src/plugins/backgroundcontrast/contrast.h b/src/plugins/backgroundcontrast/contrast.h --- a/src/plugins/backgroundcontrast/contrast.h 2026-04-08 10:00:41.000000000 -0300 +++ b/src/plugins/backgroundcontrast/contrast.h 2026-07-03 20:52:02.805738497 -0300 @@ -57,6 +57,7 @@ QRegion contrastRegion(const EffectWindow *w) const; bool shouldContrast(const EffectWindow *w, int mask, const WindowPaintData &data) const; void updateContrastRegion(EffectWindow *w); + bool isPanelAnimating(EffectWindow *w) const; void doContrast(const RenderTarget &renderTarget, const RenderViewport &viewport, EffectWindow *w, const QRegion &shape, const float opacity, const QMatrix4x4 &screenProjection); void uploadRegion(std::span map, const QRegion ®ion, qreal scale); Q_REQUIRED_RESULT bool uploadGeometry(GLVertexBuffer *vbo, const QRegion ®ion, qreal scale); @@ -65,6 +66,7 @@ std::unique_ptr m_shader; long m_net_wm_contrast_region = 0; + long m_panelAnimatingAtom = 0; QHash m_contrastChangedConnections; // used only in Wayland to keep track of effect changed struct Data { diff -ruN a/src/plugins/blur/blur.cpp b/src/plugins/blur/blur.cpp --- a/src/plugins/blur/blur.cpp 2026-04-08 10:00:41.000000000 -0300 +++ b/src/plugins/blur/blur.cpp 2026-07-03 20:52:27.003135068 -0300 @@ -48,6 +48,7 @@ { static const QByteArray s_blurAtomName = QByteArrayLiteral("_KDE_NET_WM_BLUR_BEHIND_REGION"); +static const QByteArray s_panelAnimatingAtomName = QByteArrayLiteral("_SONIC_WM_PANEL_ANIMATING"); BlurManagerInterface *BlurEffect::s_blurManager = nullptr; QTimer *BlurEffect::s_blurManagerRemoveTimer = nullptr; @@ -125,6 +126,12 @@ if (effects->xcbConnection()) { net_wm_blur_region = effects->announceSupportProperty(s_blurAtomName, this); + xcb_connection_t *c = effects->xcbConnection(); + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(c, xcb_intern_atom_unchecked(c, false, s_panelAnimatingAtomName.length(), s_panelAnimatingAtomName.constData()), nullptr); + if (reply) { + m_panelAnimatingAtom = reply->atom; + free(reply); + } } connect(effects, &EffectsHandler::windowAdded, this, &BlurEffect::slotWindowAdded); @@ -132,6 +139,14 @@ connect(effects, &EffectsHandler::propertyNotify, this, &BlurEffect::slotPropertyNotify); connect(effects, &EffectsHandler::xcbConnectionChanged, this, [this]() { net_wm_blur_region = effects->announceSupportProperty(s_blurAtomName, this); + if (effects->xcbConnection()) { + xcb_connection_t *c = effects->xcbConnection(); + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(c, xcb_intern_atom_unchecked(c, false, s_panelAnimatingAtomName.length(), s_panelAnimatingAtomName.constData()), nullptr); + if (reply) { + m_panelAnimatingAtom = reply->atom; + free(reply); + } + } }); // Fetch the blur regions for all windows @@ -292,11 +307,38 @@ void BlurEffect::slotPropertyNotify(EffectWindow *w, long atom) { - if (w && atom == net_wm_blur_region && net_wm_blur_region != XCB_ATOM_NONE) { + if (!w) { + return; + } + if (atom == m_panelAnimatingAtom && m_panelAnimatingAtom != XCB_ATOM_NONE) { + // When the panel stops animating, apply any blur region updates we deferred. + if (!isPanelAnimating(w)) { + updateBlurRegion(w); + } + return; + } + if (atom == net_wm_blur_region && net_wm_blur_region != XCB_ATOM_NONE) { + if (isPanelAnimating(w)) { + // Defer blur region updates until the panel finishes its animation. + return; + } updateBlurRegion(w); } } +bool BlurEffect::isPanelAnimating(EffectWindow *w) const +{ + if (m_panelAnimatingAtom == XCB_ATOM_NONE) { + return false; + } + const QByteArray value = w->readProperty(m_panelAnimatingAtom, XCB_ATOM_CARDINAL, 32); + if (value.size() < static_cast(sizeof(uint32_t))) { + return false; + } + const uint32_t *cardinals = reinterpret_cast(value.constData()); + return cardinals[0] != 0; +} + void BlurEffect::setupDecorationConnections(EffectWindow *w) { if (!w->decoration()) { diff -ruN a/src/plugins/blur/blur.h b/src/plugins/blur/blur.h --- a/src/plugins/blur/blur.h 2026-04-08 10:00:41.000000000 -0300 +++ b/src/plugins/blur/blur.h 2026-07-03 20:51:43.097415496 -0300 @@ -83,6 +83,7 @@ bool decorationSupportsBlurBehind(const EffectWindow *w) const; bool shouldBlur(const EffectWindow *w, int mask, const WindowPaintData &data) const; void updateBlurRegion(EffectWindow *w); + bool isPanelAnimating(EffectWindow *w) const; void blur(const RenderTarget &renderTarget, const RenderViewport &viewport, EffectWindow *w, int mask, const QRegion ®ion, WindowPaintData &data); GLTexture *ensureNoiseTexture(); @@ -136,6 +137,7 @@ bool m_valid = false; long net_wm_blur_region = 0; + long m_panelAnimatingAtom = 0; QRegion m_paintedArea; // keeps track of all painted areas (from bottom to top) QRegion m_currentBlur; // keeps track of the currently blured area of the windows(from bottom to top) diff -ruN a/src/workspace.cpp b/src/workspace.cpp --- a/src/workspace.cpp 2026-04-08 10:00:41.000000000 -0300 +++ b/src/workspace.cpp 2026-07-03 20:48:53.649393515 -0300 @@ -2178,7 +2178,7 @@ void Workspace::scheduleRearrange() { - m_rearrangeTimer.start(0); + m_rearrangeTimer.start(50); } void Workspace::rearrange()