Allow windows to specify that they should not get animated on window close

By setting the X property _KDE_NET_WM_SKIP_CLOSE_ANIMATION to 1 a window
can request to be excluded from any close animation. This property is
read in Toplevel, so that it is available to both Client and Unmanaged.

If the window has this property set the Scene suppresses the paintWindow
loop of the Deleted. Thus no effect needs to be adjusted. But an effect
using drawWindow directly would still be able to render the Deleted as
there is no suppression.

Furthermore the property is passed to the EffectWindow so that an
Effect can make use of this functionality and not start the animation
in the first place.

REVIEW: 115288
CCBUG: 279615

Backported from 9497b4ddb681ac50dbe9c015e05a3f12fd496da8
This commit is contained in:
Martin Gräßlin 2014-01-24 12:34:16 +01:00
parent 6acef12932
commit 882d55f1b5
10 changed files with 67 additions and 0 deletions

View file

@ -129,6 +129,9 @@ Atoms::Atoms()
atoms[n] = &kde_first_in_window_list;
names[n++] = (char*) "_KDE_FIRST_IN_WINDOWLIST";
atoms[n] = &kde_skip_close_animation;
names[n++] = (char*) "_KDE_NET_WM_SKIP_CLOSE_ANIMATION";
assert(n <= max);
XInternAtoms(display(), names, n, false, atoms_return);

View file

@ -65,6 +65,7 @@ public:
Atom net_wm_opaque_region;
Atom kde_net_wm_tab_group;
Atom kde_first_in_window_list;
Atom kde_skip_close_animation;
};

View file

@ -1557,6 +1557,8 @@ void Toplevel::propertyNotifyEvent(XPropertyEvent* e)
getShadow();
else if (e->atom == atoms->net_wm_opaque_region)
getWmOpaqueRegion();
else if (e->atom == atoms->kde_skip_close_animation)
getSkipCloseAnimation();
break;
}
emit propertyNotify(this, e->atom);

View file

@ -710,6 +710,7 @@ WINDOW_HELPER(bool, isDeleted, "deleted")
WINDOW_HELPER(bool, hasOwnShape, "shaped")
WINDOW_HELPER(QString, windowRole, "windowRole")
WINDOW_HELPER(QStringList, activities, "activities")
WINDOW_HELPER(bool, skipsCloseAnimation, "skipsCloseAnimation")
QString EffectWindow::windowClass() const
{

View file

@ -1440,6 +1440,13 @@ class KWIN_EXPORT EffectWindow : public QObject
* @since 4.11
**/
Q_PROPERTY(bool visible READ isVisible)
/**
* Whether the window does not want to be animated on window close.
* In case this property is @c true it is not useful to start an animation on window close.
* The window will not be visible, but the animation hooks are executed.
* @since 5.0
**/
Q_PROPERTY(bool skipsCloseAnimation READ skipsCloseAnimation)
public:
/** Flags explaining why painting should be disabled */
enum {
@ -1662,6 +1669,11 @@ public:
**/
bool isVisible() const;
/**
* @since 5.0
**/
bool skipsCloseAnimation() const;
/**
* Can be used to by effects to store arbitrary data in the EffectWindow.
*/

View file

@ -129,6 +129,7 @@ bool Client::manage(xcb_window_t w, bool isMapped)
getWmNormalHints(); // Get xSizeHint
getMotifHints();
getWmOpaqueRegion();
getSkipCloseAnimation();
// TODO: Try to obey all state information from info->state()

View file

@ -402,6 +402,10 @@ void Scene::paintWindow(Window* w, int mask, QRegion region, WindowQuadList quad
region &= QRect(0, 0, displayWidth(), displayHeight());
if (region.isEmpty()) // completely clipped
return;
if (w->window()->isDeleted() && w->window()->skipsCloseAnimation()) {
// should not get painted
return;
}
if (s_recursionCheck == w) {
return;

View file

@ -52,6 +52,7 @@ Toplevel::Toplevel()
, unredirectSuspend(false)
, m_damageReplyPending(false)
, m_screen(0)
, m_skipCloseAnimation(false)
{
connect(this, SIGNAL(damaged(KWin::Toplevel*,QRect)), SIGNAL(needsRepaint()));
connect(screens(), SIGNAL(changed()), SLOT(checkScreen()));
@ -128,6 +129,7 @@ void Toplevel::copyToDeleted(Toplevel* c)
window_role = c->windowRole();
opaque_region = c->opaqueRegion();
m_screen = c->m_screen;
m_skipCloseAnimation = c->m_skipCloseAnimation;
}
// before being deleted, remove references to everything that's now
@ -470,6 +472,34 @@ pid_t Toplevel::pid() const
return info->pid();
}
void Toplevel::getSkipCloseAnimation()
{
xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(connection(), false, window(), atoms->kde_skip_close_animation, XCB_ATOM_CARDINAL, 0, 1);
ScopedCPointer<xcb_get_property_reply_t> reply(xcb_get_property_reply(connection(), cookie, NULL));
bool newValue = false;
if (!reply.isNull()) {
if (reply->format == 32 && reply->type == XCB_ATOM_CARDINAL && reply->value_len == 1) {
const uint32_t value = *reinterpret_cast<uint32_t*>(xcb_get_property_value(reply.data()));
newValue = (value != 0);
}
}
setSkipCloseAnimation(newValue);
}
bool Toplevel::skipsCloseAnimation() const
{
return m_skipCloseAnimation;
}
void Toplevel::setSkipCloseAnimation(bool set)
{
if (set == m_skipCloseAnimation) {
return;
}
m_skipCloseAnimation = set;
emit skipCloseAnimationChanged();
}
} // namespace
#include "toplevel.moc"

View file

@ -163,6 +163,12 @@ class Toplevel
* Whether the window has an own shape
**/
Q_PROPERTY(bool shaped READ shape NOTIFY shapedChanged)
/**
* Whether the window does not want to be animated on window close.
* There are legit reasons for this like a screenshot application which does not want it's
* window being captured.
**/
Q_PROPERTY(bool skipsCloseAnimation READ skipsCloseAnimation WRITE setSkipCloseAnimation NOTIFY skipCloseAnimationChanged)
public:
explicit Toplevel();
Window frameId() const;
@ -306,6 +312,9 @@ public:
*/
void getDamageRegionReply();
bool skipsCloseAnimation() const;
void setSkipCloseAnimation(bool set);
signals:
void opacityChanged(KWin::Toplevel* toplevel, qreal oldOpacity);
void damaged(KWin::Toplevel* toplevel, const QRect& damage);
@ -333,6 +342,7 @@ signals:
* @since 4.11
**/
void screenChanged();
void skipCloseAnimationChanged();
protected Q_SLOTS:
/**
@ -367,6 +377,7 @@ protected:
void getResourceClass();
void getWindowRole();
void getSkipCloseAnimation();
virtual void debug(QDebug& stream) const = 0;
void copyToDeleted(Toplevel* c);
void disownDataPassedToDeleted();
@ -408,6 +419,7 @@ private:
QRegion opaque_region;
xcb_xfixes_fetch_region_cookie_t m_regionCookie;
int m_screen;
bool m_skipCloseAnimation;
// when adding new data members, check also copyToDeleted()
};

View file

@ -80,6 +80,7 @@ bool Unmanaged::track(Window w)
XShapeSelectInput(display(), w, ShapeNotifyMask);
detectShape(w);
getWmOpaqueRegion();
getSkipCloseAnimation();
setupCompositing();
ungrabXServer();
if (effects)