Update WindowItem's visibility

With this, the WindowItem will know whether it's actually visible. As
the result, if a native wayland window has been minimized, kwin won't
try to schedule a new frame if just a frame callback has been committed.

EffectWindow::enablePainting() and EffectWindow::disablePainting() act
as a stone in the shoe. They have the final say whether the given window
is visible and they are invoked too late in the rendering process.
WindowItem needs to know whether the window is visible in advance,
before compositing starts.

This change replaces EffectWindow::enablePainting() and
EffectWindow::disablePainting() with EffectWindow::refVisible() and
EffectWindow::unrefVisible(). If an effect calls the refVisible()
function, the window will be kept visible regardless of its state. It
should be called when a window is minimized or closed, etc. If an effect
doesn't want to paint a window, it should not call effects->paintWindow().

EffectWindow::refVisible() doesn't replace EffectWindow::refWindow() but
supplements it. refVisible() only ensures that a window will be kept
visible while refWindow() ensures that the window won't be destroyed
until the effect is done with it.
This commit is contained in:
Vlad Zahorodnii 2022-04-27 12:22:23 +03:00
parent ea0061cd03
commit def99b1a7c
30 changed files with 241 additions and 206 deletions

View file

@ -27,8 +27,8 @@ public:
QVariant data(int role) const override;
QRect decorationInnerRect() const override;
void deleteProperty(long int atom) const override;
void disablePainting(int reason) override;
void enablePainting(int reason) override;
void refVisible(int reason) override;
void unrefVisible(int reason) override;
void addRepaint(const QRect &r) override;
void addRepaint(int x, int y, int w, int h) override;
void addRepaintFull() override;
@ -37,7 +37,6 @@ public:
EffectWindow *findModal() override;
EffectWindow *transientFor() override;
const EffectWindowGroup *group() const override;
bool isPaintingEnabled() override;
EffectWindowList mainWindows() const override;
QByteArray readProperty(long int atom, long int type, int format) const override;
void refWindow() override;
@ -366,12 +365,12 @@ void MockEffectWindow::deleteProperty(long int atom) const
Q_UNUSED(atom)
}
void MockEffectWindow::disablePainting(int reason)
void MockEffectWindow::refVisible(int reason)
{
Q_UNUSED(reason)
}
void MockEffectWindow::enablePainting(int reason)
void MockEffectWindow::unrefVisible(int reason)
{
Q_UNUSED(reason)
}
@ -421,11 +420,6 @@ const EffectWindowGroup *MockEffectWindow::group() const
return nullptr;
}
bool MockEffectWindow::isPaintingEnabled()
{
return true;
}
EffectWindowList MockEffectWindow::mainWindows() const
{
return EffectWindowList();

View file

@ -49,6 +49,7 @@
#include "wayland_server.h"
#include "waylandwindow.h"
#include "window_property_notify_x11_filter.h"
#include "windowitem.h"
#include "workspace.h"
#include <Plasma/Theme>
@ -1915,19 +1916,14 @@ EffectWindowImpl::~EffectWindowImpl()
}
}
bool EffectWindowImpl::isPaintingEnabled()
void EffectWindowImpl::refVisible(int reason)
{
return sceneWindow()->isPaintingEnabled();
m_sceneWindow->windowItem()->refVisible(reason);
}
void EffectWindowImpl::enablePainting(int reason)
void EffectWindowImpl::unrefVisible(int reason)
{
sceneWindow()->enablePainting(reason);
}
void EffectWindowImpl::disablePainting(int reason)
{
sceneWindow()->disablePainting(reason);
m_sceneWindow->windowItem()->unrefVisible(reason);
}
void EffectWindowImpl::addRepaint(const QRect &r)

View file

@ -384,9 +384,8 @@ public:
explicit EffectWindowImpl(Window *window);
~EffectWindowImpl() override;
void enablePainting(int reason) override;
void disablePainting(int reason) override;
bool isPaintingEnabled() override;
void refVisible(int reason) override;
void unrefVisible(int reason) override;
void addRepaint(const QRect &r) override;
void addRepaint(int x, int y, int w, int h) override;

View file

@ -535,9 +535,6 @@ void BlurEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::
effects->prePaintWindow(w, data, presentTime);
if (!w->isPaintingEnabled()) {
return;
}
if (!m_shader || !m_shader->isValid()) {
return;
}

View file

@ -257,11 +257,6 @@ void DesktopGridEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::mi
// so with normal screen painting second screen paint would erase parts of the first paint
data.mask |= PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_BACKGROUND_FIRST;
const EffectWindowList windows = effects->stackingOrder();
for (auto *w : windows) {
w->setData(WindowForceBlurRole, QVariant(true));
}
effects->prePaintScreen(data, presentTime);
}
@ -360,10 +355,6 @@ void DesktopGridEffect::postPaintScreen()
lastPresentTime = std::chrono::milliseconds::zero();
}
for (auto &w : effects->stackingOrder()) {
w->setData(WindowForceBlurRole, QVariant());
}
effects->postPaintScreen();
}
@ -372,19 +363,18 @@ void DesktopGridEffect::postPaintScreen()
void DesktopGridEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime)
{
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
if (w->isMinimized() && isUsingPresentWindows()) {
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE);
}
if (windowMove && wasWindowMove && windowMove->findModal() == w) {
w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
}
data.setTransformed();
effects->prePaintWindow(w, data, presentTime);
}
void DesktopGridEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data)
{
if (w->isMinimized() && !isUsingPresentWindows()) {
return;
}
if (windowMove && wasWindowMove && windowMove->findModal() == w) {
return;
}
if (!w->isOnDesktop(paintingDesktop)) {
return;
}
@ -1152,6 +1142,12 @@ void DesktopGridEffect::setup()
}
setHighlightedDesktop(effects->currentDesktop());
const EffectWindowList windows = effects->stackingOrder();
for (auto *w : windows) {
w->refVisible(EffectWindow::PAINT_DISABLED_BY_MINIMIZE | EffectWindow::PAINT_DISABLED_BY_DESKTOP);
w->setData(WindowForceBlurRole, QVariant(true));
}
// Soft highlighting
qDeleteAll(hoverTimeline);
hoverTimeline.clear();
@ -1350,6 +1346,11 @@ void DesktopGridEffect::finish()
m_proxy = nullptr;
}
for (auto &w : effects->stackingOrder()) {
w->unrefVisible(EffectWindow::PAINT_DISABLED_BY_MINIMIZE | EffectWindow::PAINT_DISABLED_BY_DESKTOP);
w->setData(WindowForceBlurRole, QVariant());
}
effects->addRepaintFull();
}

View file

@ -59,7 +59,6 @@ void FallApartEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data,
animationIt->progress += time / animationTime(1000.);
data.setTransformed();
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE);
} else {
unredirect(w);
windows.remove(w);
@ -181,6 +180,7 @@ void FallApartEffect::slotWindowClosed(EffectWindow *c)
FallApartAnimation &animation = windows[c];
animation.progress = 0;
animation.deletedRef = EffectWindowDeletedRef(c);
animation.visibleRef = EffectWindowVisibleRef(c, EffectWindow::PAINT_DISABLED_BY_DELETE);
redirect(c);
}

View file

@ -18,6 +18,7 @@ namespace KWin
struct FallApartAnimation
{
EffectWindowDeletedRef deletedRef;
EffectWindowVisibleRef visibleRef;
std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero();
qreal progress = 0;
};

View file

@ -89,7 +89,6 @@ void GlideEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std:
{
if (m_animations.contains(w)) {
data.setTransformed();
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE);
}
effects->prePaintWindow(w, data, presentTime);
@ -245,6 +244,7 @@ void GlideEffect::windowClosed(EffectWindow *w)
GlideAnimation &animation = m_animations[w];
animation.deletedRef = EffectWindowDeletedRef(w);
animation.visibleRef = EffectWindowVisibleRef(w, EffectWindow::PAINT_DISABLED_BY_DELETE);
animation.timeLine.reset();
animation.timeLine.setDirection(TimeLine::Forward);
animation.timeLine.setDuration(m_duration);

View file

@ -22,6 +22,7 @@ namespace KWin
struct GlideAnimation
{
EffectWindowDeletedRef deletedRef;
EffectWindowVisibleRef visibleRef;
TimeLine timeLine;
std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero();
};

View file

@ -70,7 +70,6 @@ void MagicLampEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data,
if (m_animations.contains(w)) {
// We'll transform this window
data.setTransformed();
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE);
}
effects->prePaintWindow(w, data, presentTime);
@ -342,6 +341,7 @@ void MagicLampEffect::slotWindowMinimized(EffectWindow *w)
if (animation.timeLine.running()) {
animation.timeLine.toggleDirection();
} else {
animation.visibleRef = EffectWindowVisibleRef(w, EffectWindow::PAINT_DISABLED_BY_MINIMIZE);
animation.timeLine.setDirection(TimeLine::Forward);
animation.timeLine.setDuration(m_duration);
animation.timeLine.setEasingCurve(QEasingCurve::Linear);

View file

@ -17,6 +17,7 @@ namespace KWin
struct MagicLampAnimation
{
EffectWindowVisibleRef visibleRef;
TimeLine timeLine;
std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero();
};

View file

@ -332,8 +332,6 @@ void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &d
effects->prePaintWindow(w, data, presentTime);
return;
}
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE); // Display always
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
// The animation code assumes that the time diff cannot be 0, let's work around it.
int time;
@ -357,15 +355,6 @@ void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &d
winData->opacity = qMax(0.0, winData->opacity - time / m_fadeDuration);
}
if (winData->opacity <= 0.0) {
// don't disable painting for panels if show panel is set
if (!(m_showPanel && w->isDock())) {
w->disablePainting(EffectWindow::PAINT_DISABLED);
}
} else if (winData->opacity != 1.0) {
data.setTranslucent();
}
const bool isInMotion = m_motionManager.isManaging(w);
// Calculate window's brightness
if (w == m_highlightedWindow || !m_activated) {
@ -383,19 +372,15 @@ void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &d
// it's possible that another effect has referenced the window
// we have to keep the window in the list to prevent flickering
winData->deletedRef = EffectWindowDeletedRef{};
} else {
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE);
}
}
// desktop windows on other desktops (Plasma activity per desktop) should not be painted
if (w->isDesktop() && !w->isOnCurrentDesktop()) {
w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
}
if (isInMotion) {
data.setTransformed(); // We will be moving this window
}
if (winData->opacity != 1.0) {
data.setTranslucent();
}
}
effects->prePaintWindow(w, data, presentTime);
}
@ -403,6 +388,11 @@ void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &d
void PresentWindowsEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data)
{
if (m_activated || m_motionManager.areWindowsMoving()) {
// desktop windows on other desktops (Plasma activity per desktop) should not be painted
if (w->isDesktop() && !w->isOnCurrentDesktop()) {
return;
}
DataHash::const_iterator winData = m_windowData.constFind(w);
if (winData == m_windowData.constEnd() || (w->isDock() && m_showPanel)) {
// we are darkening the panel to communicate that it's not interactive
@ -1702,6 +1692,8 @@ void PresentWindowsEffect::setActive(bool active)
winData->opacity = 1.0;
}
winData->visibleRef = EffectWindowVisibleRef(w, EffectWindow::PAINT_DISABLED_BY_DESKTOP | EffectWindow::PAINT_DISABLED_BY_MINIMIZE);
winData->highlight = 1.0;
winData->textFrame = effects->effectFrame(EffectFrameUnstyled, false);

View file

@ -67,6 +67,7 @@ private:
struct WindowData
{
EffectWindowDeletedRef deletedRef;
EffectWindowVisibleRef visibleRef;
std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero();
bool visible;
bool deleted;

View file

@ -67,7 +67,6 @@ void SheetEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std:
{
if (m_animations.contains(w)) {
data.setTransformed();
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE);
}
effects->prePaintWindow(w, data, presentTime);
@ -185,6 +184,7 @@ void SheetEffect::slotWindowClosed(EffectWindow *w)
Animation &animation = m_animations[w];
animation.deletedRef = EffectWindowDeletedRef(w);
animation.visibleRef = EffectWindowVisibleRef(w, EffectWindow::PAINT_DISABLED_BY_DELETE);
animation.timeLine.reset();
animation.parentY = 0;
animation.timeLine.setDuration(m_duration);

View file

@ -54,6 +54,7 @@ private:
struct Animation
{
EffectWindowDeletedRef deletedRef;
EffectWindowVisibleRef visibleRef;
TimeLine timeLine;
int parentY;
std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero();

View file

@ -271,14 +271,7 @@ bool SlideEffect::isPainted(const EffectWindow *w) const
void SlideEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime)
{
for (const auto &desktop : std::as_const(m_paintCtx.visibleDesktops)) {
if (w->isOnDesktop(desktop)) {
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
data.setTransformed();
break;
}
}
data.setTransformed();
effects->prePaintWindow(w, data, presentTime);
}
@ -380,6 +373,7 @@ void SlideEffect::prepareSwitching()
effects->setElevatedWindow(w, true);
m_elevatedWindows << w;
}
w->refVisible(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
w->setData(WindowForceBackgroundContrastRole, QVariant(true));
w->setData(WindowForceBlurRole, QVariant(true));
}
@ -392,6 +386,7 @@ void SlideEffect::finishedSwitching()
}
const EffectWindowList windows = effects->stackingOrder();
for (EffectWindow *w : windows) {
w->unrefVisible(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
w->setData(WindowForceBackgroundContrastRole, QVariant());
w->setData(WindowForceBlurRole, QVariant());
}
@ -482,6 +477,7 @@ void SlideEffect::windowAdded(EffectWindow *w)
effects->setElevatedWindow(w, true);
m_elevatedWindows << w;
}
w->refVisible(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
w->setData(WindowForceBackgroundContrastRole, QVariant(true));
w->setData(WindowForceBlurRole, QVariant(true));
}

View file

@ -296,8 +296,7 @@ void SlideBackEffect::slotTabBoxClosed()
bool SlideBackEffect::isWindowUsable(EffectWindow *w)
{
return w && (w->isNormalWindow() || w->isDialog()) && !w->keepAbove() && !w->isDeleted() && !w->isMinimized()
&& w->isPaintingEnabled();
return w && (w->isNormalWindow() || w->isDialog()) && !w->keepAbove() && !w->isDeleted() && !w->isMinimized();
}
bool SlideBackEffect::intersects(EffectWindow *windowUnder, const QRect &windowOverGeometry)

View file

@ -131,7 +131,6 @@ void SlidingPopupsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &da
(*animationIt).timeLine.update(delta);
data.setTransformed();
w->enablePainting(EffectWindow::PAINT_DISABLED | EffectWindow::PAINT_DISABLED_BY_DELETE);
effects->prePaintWindow(w, data, presentTime);
}
@ -544,7 +543,10 @@ void SlidingPopupsEffect::slideOut(EffectWindow *w)
}
Animation &animation = m_animations[w];
animation.deletedRef = EffectWindowDeletedRef(w);
if (w->isDeleted()) {
animation.deletedRef = EffectWindowDeletedRef(w);
}
animation.visibleRef = EffectWindowVisibleRef(w, EffectWindow::PAINT_DISABLED | EffectWindow::PAINT_DISABLED_BY_DELETE);
animation.kind = AnimationKind::Out;
animation.timeLine.setDirection(TimeLine::Backward);
animation.timeLine.setDuration((*dataIt).slideOutDuration);

View file

@ -83,6 +83,7 @@ private:
struct Animation
{
EffectWindowDeletedRef deletedRef;
EffectWindowVisibleRef visibleRef;
AnimationKind kind;
TimeLine timeLine;
std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero();

View file

@ -1281,8 +1281,6 @@ bool Unmanaged::windowEvent(xcb_generic_event_t *e)
default: {
if (eventType == Xcb::Extensions::self()->shapeNotifyEvent()) {
detectShape(window());
addRepaintFull();
addWorkspaceRepaint(frameGeometry()); // in case shape change removes part of this window
Q_EMIT geometryShapeChanged(this, frameGeometry());
}
if (eventType == Xcb::Extensions::self()->damageNotifyEvent()) {

View file

@ -76,6 +76,7 @@ public:
bool waitAtSource;
bool keepAlive;
EffectWindowDeletedRef deletedRef;
EffectWindowVisibleRef visibleRef;
PreviousWindowPixmapLockPtr previousWindowPixmapLock;
AnimationEffect::TerminationFlags terminationFlags;
std::chrono::milliseconds lastPresentTime;

View file

@ -258,6 +258,7 @@ quint64 AnimationEffect::p_animate(EffectWindow *w, Attribute a, uint meta, int
AniData &animation = it->first.last();
animation.id = ret_id;
animation.visibleRef = EffectWindowVisibleRef(w, EffectWindow::PAINT_DISABLED_BY_MINIMIZE | EffectWindow::PAINT_DISABLED_BY_DESKTOP | EffectWindow::PAINT_DISABLED_BY_DELETE);
animation.timeLine.setDirection(TimeLine::Forward);
animation.timeLine.setDuration(std::chrono::milliseconds(ms));
animation.timeLine.setEasingCurve(curve);
@ -504,32 +505,16 @@ void AnimationEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data,
Q_D(AnimationEffect);
AniMap::const_iterator entry = d->m_animations.constFind(w);
if (entry != d->m_animations.constEnd()) {
bool isUsed = false;
bool paintDeleted = false;
for (QList<AniData>::const_iterator anim = entry->first.constBegin(); anim != entry->first.constEnd(); ++anim) {
if (anim->startTime > clock() && !anim->waitAtSource) {
continue;
}
isUsed = true;
if (anim->attribute == Opacity || anim->attribute == CrossFadePrevious) {
data.setTranslucent();
} else if (!(anim->attribute == Brightness || anim->attribute == Saturation)) {
data.setTransformed();
}
paintDeleted |= anim->keepAlive;
}
if (isUsed) {
if (w->isMinimized()) {
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE);
} else if (w->isDeleted() && paintDeleted) {
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE);
} else if (!w->isOnCurrentDesktop()) {
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
}
// if( !w->isPaintingEnabled() && !effects->activeFullScreenEffect() )
// effects->addLayerRepaint(w->expandedGeometry());
}
}
effects->prePaintWindow(w, data, presentTime);

View file

@ -2354,9 +2354,6 @@ public:
explicit EffectWindow(QObject *parent = nullptr);
~EffectWindow() override;
virtual void enablePainting(int reason) = 0;
virtual void disablePainting(int reason) = 0;
virtual bool isPaintingEnabled() = 0;
Q_SCRIPTABLE virtual void addRepaint(const QRect &r) = 0;
Q_SCRIPTABLE virtual void addRepaint(int x, int y, int w, int h) = 0;
Q_SCRIPTABLE virtual void addRepaintFull() = 0;
@ -2366,6 +2363,9 @@ public:
virtual void refWindow() = 0;
virtual void unrefWindow() = 0;
virtual void refVisible(int reason) = 0;
virtual void unrefVisible(int reason) = 0;
virtual bool isDeleted() const = 0;
virtual bool isMinimized() const = 0;
@ -2774,6 +2774,64 @@ private:
EffectWindow *m_window;
};
/**
* The EffectWindowVisibleRef provides a convenient way to force the visible status of a
* window until an effect is finished animating it.
*/
class KWINEFFECTS_EXPORT EffectWindowVisibleRef
{
public:
EffectWindowVisibleRef()
: m_window(nullptr)
{
}
explicit EffectWindowVisibleRef(EffectWindow *window, int reason)
: m_window(window)
, m_reason(reason)
{
m_window->refVisible(reason);
}
EffectWindowVisibleRef(const EffectWindowVisibleRef &other)
: m_window(other.m_window)
, m_reason(other.m_reason)
{
if (m_window) {
m_window->refVisible(m_reason);
}
}
~EffectWindowVisibleRef()
{
if (m_window) {
m_window->unrefVisible(m_reason);
}
}
EffectWindowVisibleRef &operator=(const EffectWindowVisibleRef &other)
{
if (other.m_window) {
other.m_window->refVisible(other.m_reason);
}
if (m_window) {
m_window->unrefVisible(m_reason);
}
m_window = other.m_window;
m_reason = other.m_reason;
return *this;
}
bool isNull() const
{
return m_window == nullptr;
}
private:
EffectWindow *m_window;
int m_reason;
};
class KWINEFFECTS_EXPORT EffectWindowGroup
{
public:

View file

@ -232,7 +232,7 @@ SurfaceItem *Scene::scanoutCandidate() const
for (int i = stacking_order.count() - 1; i >= 0; i--) {
SceneWindow *sceneWindow = stacking_order[i];
Window *window = sceneWindow->window();
if (window->isOnOutput(painted_screen) && sceneWindow->isVisible() && window->opacity() > 0) {
if (window->isOnOutput(painted_screen) && window->opacity() > 0) {
if (!window->isClient() || !window->isFullScreen() || window->opacity() != 1.0) {
break;
}
@ -338,16 +338,13 @@ void Scene::preparePaintGenericScreen()
data.mask = m_paintContext.mask;
data.paint = infiniteRegion(); // no clipping, so doesn't really matter
sceneWindow->resetPaintingEnabled();
effects->prePaintWindow(effectWindow(sceneWindow), data, m_expectedPresentTimestamp);
if (sceneWindow->isPaintingEnabled()) {
m_paintContext.phase2Data.append(Phase2Data{
.window = sceneWindow,
.region = infiniteRegion(),
.opaque = data.opaque,
.mask = data.mask,
});
}
m_paintContext.phase2Data.append(Phase2Data{
.window = sceneWindow,
.region = infiniteRegion(),
.opaque = data.opaque,
.mask = data.mask,
});
}
m_paintContext.damage = renderTargetRect();
@ -373,16 +370,13 @@ void Scene::preparePaintSimpleScreen()
}
}
sceneWindow->resetPaintingEnabled();
effects->prePaintWindow(effectWindow(sceneWindow), data, m_expectedPresentTimestamp);
if (sceneWindow->isPaintingEnabled()) {
m_paintContext.phase2Data.append(Phase2Data{
.window = sceneWindow,
.region = data.paint,
.opaque = data.opaque,
.mask = data.mask,
});
}
m_paintContext.phase2Data.append(Phase2Data{
.window = sceneWindow,
.region = data.paint,
.opaque = data.opaque,
.mask = data.mask,
});
}
// Perform an occlusion cull pass, remove surface damage occluded by opaque windows.
@ -664,7 +658,6 @@ SurfaceTexture *Scene::createSurfaceTextureWayland(SurfacePixmapWayland *pixmap)
SceneWindow::SceneWindow(Window *client, QObject *parent)
: QObject(parent)
, m_window(client)
, disable_painting(0)
{
if (qobject_cast<WaylandWindow *>(client)) {
m_windowItem.reset(new WindowItemWayland(m_window));
@ -729,60 +722,6 @@ QRegion SceneWindow::decorationShape() const
return QRegion(m_window->rect()) - decorationInnerRect;
}
bool SceneWindow::isVisible() const
{
if (m_window->isDeleted()) {
return false;
}
if (!m_window->isOnCurrentDesktop()) {
return false;
}
if (!m_window->isOnCurrentActivity()) {
return false;
}
if (m_window->isClient()) {
return m_window->isShown();
}
return true; // Unmanaged is always visible
}
bool SceneWindow::isPaintingEnabled() const
{
return !disable_painting;
}
void SceneWindow::resetPaintingEnabled()
{
disable_painting = 0;
if (m_window->isDeleted()) {
disable_painting |= PAINT_DISABLED_BY_DELETE;
}
if (!m_window->isOnCurrentDesktop()) {
disable_painting |= PAINT_DISABLED_BY_DESKTOP;
}
if (!m_window->isOnCurrentActivity()) {
disable_painting |= PAINT_DISABLED_BY_ACTIVITY;
}
if (m_window->isClient()) {
if (m_window->isMinimized()) {
disable_painting |= PAINT_DISABLED_BY_MINIMIZE;
}
if (m_window->isHiddenInternal()) {
disable_painting |= PAINT_DISABLED;
}
}
}
void SceneWindow::enablePainting(int reason)
{
disable_painting &= ~reason;
}
void SceneWindow::disablePainting(int reason)
{
disable_painting |= reason;
}
WindowItem *SceneWindow::windowItem() const
{
return m_windowItem.data();

View file

@ -295,26 +295,6 @@ public:
// access to the internal window class
// TODO eventually get rid of this
Window *window() const;
// should the window be painted
bool isPaintingEnabled() const;
void resetPaintingEnabled();
// Flags explaining why painting should be disabled
enum {
// SceneWindow will not be painted
PAINT_DISABLED = 1 << 0,
// SceneWindow will not be painted because it is deleted
PAINT_DISABLED_BY_DELETE = 1 << 1,
// SceneWindow will not be painted because of which desktop it's on
PAINT_DISABLED_BY_DESKTOP = 1 << 2,
// SceneWindow will not be painted because it is minimized
PAINT_DISABLED_BY_MINIMIZE = 1 << 3,
// SceneWindow will not be painted because it's not on the current activity
PAINT_DISABLED_BY_ACTIVITY = 1 << 5
};
void enablePainting(int reason);
void disablePainting(int reason);
// is the window visible at all
bool isVisible() const;
QRegion decorationShape() const;
void setWindow(Window *window);
void referencePreviousPixmap();
@ -332,7 +312,6 @@ private:
void updateWindowPosition();
int disable_painting;
QScopedPointer<WindowItem> m_windowItem;
Q_DISABLE_COPY(SceneWindow)
};

View file

@ -259,7 +259,6 @@ void WaylandWindow::showClient()
return;
}
m_isHidden = false;
addRepaintFull();
Q_EMIT windowShown(this);
}
@ -272,7 +271,6 @@ void WaylandWindow::hideClient()
leaveInteractiveMoveResize();
}
m_isHidden = true;
addWorkspaceRepaint(visibleGeometry());
workspace()->windowHidden(this);
Q_EMIT windowHidden(this);
}

View file

@ -432,7 +432,6 @@ void Window::setReadyForPainting()
if (!ready_for_painting) {
ready_for_painting = true;
if (Compositor::compositing()) {
addRepaintFull();
Q_EMIT windowShown(this);
}
}
@ -1200,7 +1199,6 @@ void Window::setDesktops(QVector<VirtualDesktop *> desktops)
Q_EMIT desktopChanged();
if (wasOnCurrentDesktop != isOnCurrentDesktop()) {
addWorkspaceRepaint(visibleGeometry());
Q_EMIT desktopPresenceChanged(this, was_desk);
}
Q_EMIT x11DesktopIdsChanged();
@ -1443,7 +1441,6 @@ void Window::minimize(bool avoid_animation)
}
// TODO: merge signal with s_minimized
addWorkspaceRepaint(visibleGeometry());
Q_EMIT clientMinimized(this, !avoid_animation);
Q_EMIT minimizedChanged();
}

View file

@ -13,6 +13,7 @@
#include "surfaceitem_wayland.h"
#include "surfaceitem_x11.h"
#include "window.h"
#include "workspace.h"
namespace KWin
{
@ -27,6 +28,14 @@ WindowItem::WindowItem(Window *window, Item *parent)
connect(window, &Window::shadowChanged, this, &WindowItem::updateShadowItem);
updateShadowItem();
connect(window, &Window::minimizedChanged, this, &WindowItem::updateVisibility);
connect(window, &Window::hiddenChanged, this, &WindowItem::updateVisibility);
connect(window, &Window::activitiesChanged, this, &WindowItem::updateVisibility);
connect(window, &Window::desktopChanged, this, &WindowItem::updateVisibility);
connect(workspace(), &Workspace::currentActivityChanged, this, &WindowItem::updateVisibility);
connect(workspace(), &Workspace::currentDesktopChanged, this, &WindowItem::updateVisibility);
updateVisibility();
connect(window, &Window::windowClosed, this, &WindowItem::handleWindowClosed);
}
@ -50,12 +59,92 @@ Window *WindowItem::window() const
return m_window;
}
void WindowItem::refVisible(int reason)
{
if (reason & PAINT_DISABLED_BY_HIDDEN) {
m_forceVisibleByHiddenCount++;
}
if (reason & PAINT_DISABLED_BY_DELETE) {
m_forceVisibleByDeleteCount++;
}
if (reason & PAINT_DISABLED_BY_DESKTOP) {
m_forceVisibleByDesktopCount++;
}
if (reason & PAINT_DISABLED_BY_MINIMIZE) {
m_forceVisibleByMinimizeCount++;
}
if (reason & PAINT_DISABLED_BY_ACTIVITY) {
m_forceVisibleByActivityCount++;
}
updateVisibility();
}
void WindowItem::unrefVisible(int reason)
{
if (reason & PAINT_DISABLED_BY_HIDDEN) {
Q_ASSERT(m_forceVisibleByHiddenCount > 0);
m_forceVisibleByHiddenCount--;
}
if (reason & PAINT_DISABLED_BY_DELETE) {
Q_ASSERT(m_forceVisibleByDeleteCount > 0);
m_forceVisibleByDeleteCount--;
}
if (reason & PAINT_DISABLED_BY_DESKTOP) {
Q_ASSERT(m_forceVisibleByDesktopCount > 0);
m_forceVisibleByDesktopCount--;
}
if (reason & PAINT_DISABLED_BY_MINIMIZE) {
Q_ASSERT(m_forceVisibleByMinimizeCount > 0);
m_forceVisibleByMinimizeCount--;
}
if (reason & PAINT_DISABLED_BY_ACTIVITY) {
Q_ASSERT(m_forceVisibleByActivityCount > 0);
m_forceVisibleByActivityCount--;
}
updateVisibility();
}
void WindowItem::handleWindowClosed(Window *original, Deleted *deleted)
{
Q_UNUSED(original)
m_window = deleted;
}
bool WindowItem::computeVisibility() const
{
if (m_window->isDeleted()) {
if (m_forceVisibleByDeleteCount == 0) {
return false;
}
}
if (!m_window->isOnCurrentDesktop()) {
if (m_forceVisibleByDesktopCount == 0) {
return false;
}
}
if (!m_window->isOnCurrentActivity()) {
if (m_forceVisibleByActivityCount == 0) {
return false;
}
}
if (m_window->isMinimized()) {
if (m_forceVisibleByMinimizeCount == 0) {
return false;
}
}
if (m_window->isHiddenInternal()) {
if (m_forceVisibleByHiddenCount == 0) {
return false;
}
}
return true;
}
void WindowItem::updateVisibility()
{
setVisible(computeVisibility());
}
void WindowItem::updateSurfaceItem(SurfaceItem *surfaceItem)
{
m_surfaceItem.reset(surfaceItem);

View file

@ -34,11 +34,22 @@ class KWIN_EXPORT WindowItem : public Item
Q_OBJECT
public:
enum {
PAINT_DISABLED_BY_HIDDEN = 1 << 0,
PAINT_DISABLED_BY_DELETE = 1 << 1,
PAINT_DISABLED_BY_DESKTOP = 1 << 2,
PAINT_DISABLED_BY_MINIMIZE = 1 << 3,
PAINT_DISABLED_BY_ACTIVITY = 1 << 5
};
SurfaceItem *surfaceItem() const;
DecorationItem *decorationItem() const;
ShadowItem *shadowItem() const;
Window *window() const;
void refVisible(int reason);
void unrefVisible(int reason);
protected:
explicit WindowItem(Window *window, Item *parent = nullptr);
void updateSurfaceItem(SurfaceItem *surfaceItem);
@ -51,10 +62,18 @@ private Q_SLOTS:
void updateSurfaceVisibility();
private:
bool computeVisibility() const;
void updateVisibility();
Window *m_window;
QScopedPointer<SurfaceItem> m_surfaceItem;
QScopedPointer<DecorationItem> m_decorationItem;
QScopedPointer<ShadowItem> m_shadowItem;
int m_forceVisibleByHiddenCount = 0;
int m_forceVisibleByDeleteCount = 0;
int m_forceVisibleByDesktopCount = 0;
int m_forceVisibleByMinimizeCount = 0;
int m_forceVisibleByActivityCount = 0;
};
/**

View file

@ -1351,10 +1351,6 @@ void X11Window::updateShape()
// Decoration mask (i.e. 'else' here) setting is done in setMask()
// when the decoration calls it or when the decoration is created/destroyed
updateInputShape();
if (Compositor::compositing()) {
addRepaintFull();
addWorkspaceRepaint(visibleGeometry()); // In case shape change removes part of this window
}
Q_EMIT geometryShapeChanged(this, frameGeometry());
}
@ -1518,9 +1514,6 @@ void X11Window::doSetShade(ShadeMode previousShadeMode)
{
// TODO: All this unmapping, resizing etc. feels too much duplicated from elsewhere
if (isShade()) {
// shade_mode == ShadeNormal
addWorkspaceRepaint(visibleGeometry());
// Shade
shade_geometry_change = true;
QSize s(implicitSize());
s.setHeight(borderTop() + borderBottom());
@ -1679,7 +1672,6 @@ void X11Window::internalHide()
if (old == Kept) {
updateHiddenPreview();
}
addWorkspaceRepaint(visibleGeometry());
workspace()->windowHidden(this);
Q_EMIT windowHidden(this);
}
@ -1700,7 +1692,6 @@ void X11Window::internalKeep()
workspace()->focusToNull(); // get rid of input focus, bug #317484
}
updateHiddenPreview();
addWorkspaceRepaint(visibleGeometry());
workspace()->windowHidden(this);
}
@ -1726,7 +1717,6 @@ void X11Window::map()
} else {
exportMappingState(XCB_ICCCM_WM_STATE_ICONIC);
}
addLayerRepaint(visibleGeometry());
}
/**