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;
|
||||
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);
|
||||
|
||||
XInternAtoms(display(), names, n, false, atoms_return);
|
||||
|
|
1
atoms.h
1
atoms.h
|
@ -62,6 +62,7 @@ public:
|
|||
Atom net_wm_sync_request;
|
||||
Atom kde_net_wm_block_compositing;
|
||||
Atom kde_net_wm_shadow;
|
||||
Atom kde_net_wm_opaque_region;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1648,6 +1648,8 @@ void Toplevel::propertyNotifyEvent(XPropertyEvent* e)
|
|||
getWindowRole();
|
||||
else if (e->atom == atoms->kde_net_wm_shadow)
|
||||
getShadow();
|
||||
else if (e->atom == atoms->kde_net_wm_opaque_region)
|
||||
getWmOpaqueRegion();
|
||||
break;
|
||||
}
|
||||
emit propertyNotify(this, e->atom);
|
||||
|
|
|
@ -136,6 +136,7 @@ bool Client::manage(Window w, bool isMapped)
|
|||
getWindowProtocols();
|
||||
getWmNormalHints(); // Get xSizeHint
|
||||
getMotifHints();
|
||||
getWmOpaqueRegion();
|
||||
|
||||
// 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());
|
||||
}
|
||||
// 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();
|
||||
// preparation step
|
||||
effects->prePaintWindow(effectWindow(w), data, time_diff);
|
||||
|
@ -314,7 +322,9 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
|||
// a higher opaque window
|
||||
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
|
||||
allclips |= data->clip;
|
||||
// Paint the opaque window
|
||||
|
@ -326,7 +336,8 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
|||
data->region -= data->clip;
|
||||
// if prePaintWindow didn't change the clipping area we only have to paint
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
|
39
toplevel.cpp
39
toplevel.cpp
|
@ -131,6 +131,7 @@ void Toplevel::copyToDeleted(Toplevel* c)
|
|||
client_machine = c->wmClientMachine(false);
|
||||
wmClientLeaderWin = c->wmClientLeader();
|
||||
window_role = c->windowRole();
|
||||
opaque_region = c->opaqueRegion();
|
||||
// this needs to be done already here, otherwise 'c' could very likely
|
||||
// call discardWindowPixmap() in something called during cleanup
|
||||
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
|
||||
|
||||
#include "toplevel.moc"
|
||||
|
|
20
toplevel.h
20
toplevel.h
|
@ -156,6 +156,13 @@ public:
|
|||
**/
|
||||
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:
|
||||
void opacityChanged(KWin::Toplevel* toplevel, qreal oldOpacity);
|
||||
void damaged(KWin::Toplevel* toplevel, const QRect& damage);
|
||||
|
@ -177,6 +184,13 @@ protected:
|
|||
void addDamageFull();
|
||||
void getWmClientLeader();
|
||||
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 getWindowRole();
|
||||
virtual void debug(QDebug& stream) const = 0;
|
||||
|
@ -214,6 +228,7 @@ private:
|
|||
QByteArray window_role;
|
||||
bool unredirect;
|
||||
bool unredirectSuspend; // when unredirected, but pixmap is needed temporarily
|
||||
QRegion opaque_region;
|
||||
// when adding new data members, check also copyToDeleted()
|
||||
};
|
||||
|
||||
|
@ -397,6 +412,11 @@ inline bool Toplevel::hasAlpha() const
|
|||
return depth() == 32;
|
||||
}
|
||||
|
||||
inline const QRegion& Toplevel::opaqueRegion() const
|
||||
{
|
||||
return opaque_region;
|
||||
}
|
||||
|
||||
inline
|
||||
EffectWindowImpl* Toplevel::effectWindow()
|
||||
{
|
||||
|
|
|
@ -72,6 +72,7 @@ bool Unmanaged::track(Window w)
|
|||
if (Extensions::shapeAvailable())
|
||||
XShapeSelectInput(display(), w, ShapeNotifyMask);
|
||||
detectShape(w);
|
||||
getWmOpaqueRegion();
|
||||
setupCompositing();
|
||||
ungrabXServer();
|
||||
if (effects)
|
||||
|
|
Loading…
Reference in a new issue