kwin: implement _KDE_NET_WM_OPAQUE_REGION
This patch implements an XProperty named _KDE_NET_WM_OPAQUE_REGION which gives the compositor the information which part of a window is opaque although it is an ARGB visual. The basic ideas are from http://www.mail-archive.com/wm-spec-list@gnome.org/msg00715.html Additionally the patch makes kwin use this information to do a better clipping in Scene::paintSimpleScreen which should result in a higher performance. REVIEW: 102933
This commit is contained in:
parent
f76c40c424
commit
2c08a14ff4
8 changed files with 81 additions and 3 deletions
|
@ -120,6 +120,9 @@ Atoms::Atoms()
|
||||||
atoms[n] = &kde_net_wm_shadow;
|
atoms[n] = &kde_net_wm_shadow;
|
||||||
names[n++] = (char*) "_KDE_NET_WM_SHADOW";
|
names[n++] = (char*) "_KDE_NET_WM_SHADOW";
|
||||||
|
|
||||||
|
atoms[n] = &kde_net_wm_opaque_region;
|
||||||
|
names[n++] = (char*) "_KDE_NET_WM_OPAQUE_REGION";
|
||||||
|
|
||||||
assert(n <= max);
|
assert(n <= max);
|
||||||
|
|
||||||
XInternAtoms(display(), names, n, false, atoms_return);
|
XInternAtoms(display(), names, n, false, atoms_return);
|
||||||
|
|
1
atoms.h
1
atoms.h
|
@ -62,6 +62,7 @@ public:
|
||||||
Atom net_wm_sync_request;
|
Atom net_wm_sync_request;
|
||||||
Atom kde_net_wm_block_compositing;
|
Atom kde_net_wm_block_compositing;
|
||||||
Atom kde_net_wm_shadow;
|
Atom kde_net_wm_shadow;
|
||||||
|
Atom kde_net_wm_opaque_region;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1648,6 +1648,8 @@ void Toplevel::propertyNotifyEvent(XPropertyEvent* e)
|
||||||
getWindowRole();
|
getWindowRole();
|
||||||
else if (e->atom == atoms->kde_net_wm_shadow)
|
else if (e->atom == atoms->kde_net_wm_shadow)
|
||||||
getShadow();
|
getShadow();
|
||||||
|
else if (e->atom == atoms->kde_net_wm_opaque_region)
|
||||||
|
getWmOpaqueRegion();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
emit propertyNotify(this, e->atom);
|
emit propertyNotify(this, e->atom);
|
||||||
|
|
|
@ -136,6 +136,7 @@ bool Client::manage(Window w, bool isMapped)
|
||||||
getWindowProtocols();
|
getWindowProtocols();
|
||||||
getWmNormalHints(); // Get xSizeHint
|
getWmNormalHints(); // Get xSizeHint
|
||||||
getMotifHints();
|
getMotifHints();
|
||||||
|
getWmOpaqueRegion();
|
||||||
|
|
||||||
// TODO: Try to obey all state information from info->state()
|
// TODO: Try to obey all state information from info->state()
|
||||||
|
|
||||||
|
|
17
scene.cpp
17
scene.cpp
|
@ -273,7 +273,15 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
||||||
topw->resetRepaints(topw->shadow()->shadowRegion().boundingRect());
|
topw->resetRepaints(topw->shadow()->shadowRegion().boundingRect());
|
||||||
}
|
}
|
||||||
// Clip out the decoration for opaque windows; the decoration is drawn in the second pass
|
// Clip out the decoration for opaque windows; the decoration is drawn in the second pass
|
||||||
data.clip = w->isOpaque() ? w->clientShape().translated(w->x(), w->y()) : QRegion();
|
if (w->isOpaque()) {
|
||||||
|
// the window is fully opaque
|
||||||
|
data.clip = w->clientShape().translated(w->x(), w->y());
|
||||||
|
} else if (topw->hasAlpha() && topw->opacity() == 1.0) {
|
||||||
|
// the window is partially opaque
|
||||||
|
data.clip = (w->clientShape() & topw->opaqueRegion()).translated(w->x(), w->y());
|
||||||
|
} else {
|
||||||
|
data.clip = QRegion();
|
||||||
|
}
|
||||||
data.quads = w->buildQuads();
|
data.quads = w->buildQuads();
|
||||||
// preparation step
|
// preparation step
|
||||||
effects->prePaintWindow(effectWindow(w), data, time_diff);
|
effects->prePaintWindow(effectWindow(w), data, time_diff);
|
||||||
|
@ -314,7 +322,9 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
||||||
// a higher opaque window
|
// a higher opaque window
|
||||||
data->region -= allclips;
|
data->region -= allclips;
|
||||||
|
|
||||||
if (!(data->mask & PAINT_WINDOW_TRANSLUCENT)) {
|
// Here we rely on WindowPrePaintData::setTranslucent() to remove
|
||||||
|
// the clip if needed.
|
||||||
|
if (!data->clip.isEmpty()) {
|
||||||
// clip away this region for all windows below this one
|
// clip away this region for all windows below this one
|
||||||
allclips |= data->clip;
|
allclips |= data->clip;
|
||||||
// Paint the opaque window
|
// Paint the opaque window
|
||||||
|
@ -326,7 +336,8 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
||||||
data->region -= data->clip;
|
data->region -= data->clip;
|
||||||
// if prePaintWindow didn't change the clipping area we only have to paint
|
// if prePaintWindow didn't change the clipping area we only have to paint
|
||||||
// the decoration
|
// the decoration
|
||||||
if (data-> clip == data.key()->clientShape().translated(data.key()->x(), data.key()->y())) {
|
if ((data-> clip ^
|
||||||
|
data.key()->clientShape().translated(data.key()->x(), data.key()->y())).isEmpty()) {
|
||||||
data->mask |= PAINT_DECORATION_ONLY;
|
data->mask |= PAINT_DECORATION_ONLY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
39
toplevel.cpp
39
toplevel.cpp
|
@ -131,6 +131,7 @@ void Toplevel::copyToDeleted(Toplevel* c)
|
||||||
client_machine = c->wmClientMachine(false);
|
client_machine = c->wmClientMachine(false);
|
||||||
wmClientLeaderWin = c->wmClientLeader();
|
wmClientLeaderWin = c->wmClientLeader();
|
||||||
window_role = c->windowRole();
|
window_role = c->windowRole();
|
||||||
|
opaque_region = c->opaqueRegion();
|
||||||
// this needs to be done already here, otherwise 'c' could very likely
|
// this needs to be done already here, otherwise 'c' could very likely
|
||||||
// call discardWindowPixmap() in something called during cleanup
|
// call discardWindowPixmap() in something called during cleanup
|
||||||
c->window_pix = None;
|
c->window_pix = None;
|
||||||
|
@ -396,6 +397,44 @@ const Shadow *Toplevel::shadow() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Toplevel::getWmOpaqueRegion()
|
||||||
|
{
|
||||||
|
const int length=32768;
|
||||||
|
unsigned long bytes_after_return=0;
|
||||||
|
QRegion new_opaque_region;
|
||||||
|
do {
|
||||||
|
unsigned long* data;
|
||||||
|
Atom type;
|
||||||
|
int rformat;
|
||||||
|
unsigned long nitems;
|
||||||
|
if (XGetWindowProperty(display(), client,
|
||||||
|
atoms->kde_net_wm_opaque_region, 0, length, false, XA_CARDINAL,
|
||||||
|
&type, &rformat, &nitems, &bytes_after_return,
|
||||||
|
reinterpret_cast< unsigned char** >(&data)) == Success) {
|
||||||
|
if (type != XA_CARDINAL || rformat != 32 || nitems%4) {
|
||||||
|
// it can happen, that the window does not provide this property
|
||||||
|
XFree(data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < nitems;) {
|
||||||
|
const int x = data[i++];
|
||||||
|
const int y = data[i++];
|
||||||
|
const int w = data[i++];
|
||||||
|
const int h = data[i++];
|
||||||
|
|
||||||
|
new_opaque_region += QRect(x,y,w,h);
|
||||||
|
}
|
||||||
|
XFree(data);
|
||||||
|
} else {
|
||||||
|
kWarning(1212) << "XGetWindowProperty failed";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (bytes_after_return > 0);
|
||||||
|
|
||||||
|
opaque_region = new_opaque_region;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
#include "toplevel.moc"
|
#include "toplevel.moc"
|
||||||
|
|
20
toplevel.h
20
toplevel.h
|
@ -156,6 +156,13 @@ public:
|
||||||
**/
|
**/
|
||||||
void getShadow();
|
void getShadow();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the area that the Toplevel window reports to be opaque.
|
||||||
|
* It is supposed to only provide valueable information if @link hasAlpha is @c true .
|
||||||
|
* @see hasAlpha
|
||||||
|
**/
|
||||||
|
const QRegion& opaqueRegion() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void opacityChanged(KWin::Toplevel* toplevel, qreal oldOpacity);
|
void opacityChanged(KWin::Toplevel* toplevel, qreal oldOpacity);
|
||||||
void damaged(KWin::Toplevel* toplevel, const QRect& damage);
|
void damaged(KWin::Toplevel* toplevel, const QRect& damage);
|
||||||
|
@ -177,6 +184,13 @@ protected:
|
||||||
void addDamageFull();
|
void addDamageFull();
|
||||||
void getWmClientLeader();
|
void getWmClientLeader();
|
||||||
void getWmClientMachine();
|
void getWmClientMachine();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function fetches the opaque region from this Toplevel.
|
||||||
|
* Will only be called on corresponding property changes and for initialization.
|
||||||
|
**/
|
||||||
|
void getWmOpaqueRegion();
|
||||||
|
|
||||||
void getResourceClass();
|
void getResourceClass();
|
||||||
void getWindowRole();
|
void getWindowRole();
|
||||||
virtual void debug(QDebug& stream) const = 0;
|
virtual void debug(QDebug& stream) const = 0;
|
||||||
|
@ -214,6 +228,7 @@ private:
|
||||||
QByteArray window_role;
|
QByteArray window_role;
|
||||||
bool unredirect;
|
bool unredirect;
|
||||||
bool unredirectSuspend; // when unredirected, but pixmap is needed temporarily
|
bool unredirectSuspend; // when unredirected, but pixmap is needed temporarily
|
||||||
|
QRegion opaque_region;
|
||||||
// when adding new data members, check also copyToDeleted()
|
// when adding new data members, check also copyToDeleted()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -397,6 +412,11 @@ inline bool Toplevel::hasAlpha() const
|
||||||
return depth() == 32;
|
return depth() == 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const QRegion& Toplevel::opaqueRegion() const
|
||||||
|
{
|
||||||
|
return opaque_region;
|
||||||
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
EffectWindowImpl* Toplevel::effectWindow()
|
EffectWindowImpl* Toplevel::effectWindow()
|
||||||
{
|
{
|
||||||
|
|
|
@ -72,6 +72,7 @@ bool Unmanaged::track(Window w)
|
||||||
if (Extensions::shapeAvailable())
|
if (Extensions::shapeAvailable())
|
||||||
XShapeSelectInput(display(), w, ShapeNotifyMask);
|
XShapeSelectInput(display(), w, ShapeNotifyMask);
|
||||||
detectShape(w);
|
detectShape(w);
|
||||||
|
getWmOpaqueRegion();
|
||||||
setupCompositing();
|
setupCompositing();
|
||||||
ungrabXServer();
|
ungrabXServer();
|
||||||
if (effects)
|
if (effects)
|
||||||
|
|
Loading…
Reference in a new issue