Merge branch 'oxygen-shadows'
This commit is contained in:
commit
6264370237
20 changed files with 764 additions and 64 deletions
|
@ -98,6 +98,7 @@ set(kwin_KDEINIT_SRCS
|
|||
events.cpp
|
||||
killwindow.cpp
|
||||
geometrytip.cpp
|
||||
shadow.cpp
|
||||
sm.cpp
|
||||
group.cpp
|
||||
bridge.cpp
|
||||
|
|
|
@ -117,6 +117,9 @@ Atoms::Atoms()
|
|||
atoms[n] = &kde_net_wm_block_compositing;
|
||||
names[n++] = (char*) "_KDE_NET_WM_BLOCK_COMPOSITING";
|
||||
|
||||
atoms[n] = &kde_net_wm_shadow;
|
||||
names[n++] = (char*) "_KDE_NET_WM_SHADOW";
|
||||
|
||||
assert(n <= max);
|
||||
|
||||
XInternAtoms(display(), names, n, false, atoms_return);
|
||||
|
|
1
atoms.h
1
atoms.h
|
@ -61,6 +61,7 @@ public:
|
|||
Atom net_wm_sync_request_counter;
|
||||
Atom net_wm_sync_request;
|
||||
Atom kde_net_wm_block_compositing;
|
||||
Atom kde_net_wm_shadow;
|
||||
};
|
||||
|
||||
|
||||
|
|
16
client.cpp
16
client.cpp
|
@ -44,6 +44,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "notifications.h"
|
||||
#include "rules.h"
|
||||
#include "scene.h"
|
||||
#include "shadow.h"
|
||||
#include "deleted.h"
|
||||
#include "paintredirector.h"
|
||||
#include "tabbox.h"
|
||||
|
@ -195,6 +196,10 @@ Client::Client(Workspace* ws)
|
|||
ready_for_painting = false; // wait for first damage or sync reply
|
||||
#endif
|
||||
|
||||
connect(this, SIGNAL(clientGeometryShapeChanged(KWin::Client*,QRect)), SIGNAL(geometryChanged()));
|
||||
connect(this, SIGNAL(clientMaximizedStateChanged(KWin::Client*,KDecorationDefines::MaximizeMode)), SIGNAL(geometryChanged()));
|
||||
connect(this, SIGNAL(clientStepUserMovedResized(KWin::Client*,QRect)), SIGNAL(geometryChanged()));
|
||||
|
||||
// SELI TODO: Initialize xsizehints??
|
||||
}
|
||||
|
||||
|
@ -2235,6 +2240,17 @@ void Client::setSessionInteract(bool needed)
|
|||
needsSessionInteract = needed;
|
||||
}
|
||||
|
||||
QRect Client::decorationRect() const
|
||||
{
|
||||
if (decoration && decoration->widget()) {
|
||||
return decoration->widget()->rect().translated(-padding_left, -padding_top);
|
||||
} else if (hasShadow()) {
|
||||
return shadow()->shadowRegion().boundingRect();
|
||||
} else {
|
||||
return QRect(0, 0, width(), height());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#include "client.moc"
|
||||
|
|
8
client.h
8
client.h
|
@ -401,11 +401,7 @@ public:
|
|||
bool decorationPixmapRequiresRepaint();
|
||||
void ensureDecorationPixmapsPainted();
|
||||
|
||||
QRect decorationRect() const {
|
||||
return (decoration && decoration->widget()) ?
|
||||
decoration->widget()->rect().translated(-padding_left, -padding_top) :
|
||||
QRect(0, 0, width(), height());
|
||||
}
|
||||
QRect decorationRect() const;
|
||||
|
||||
QRect transparentRect() const;
|
||||
|
||||
|
@ -967,7 +963,7 @@ inline QSize Client::clientSize() const
|
|||
|
||||
inline QRect Client::visibleRect() const
|
||||
{
|
||||
return geometry().adjusted(-padding_left, -padding_top, padding_right, padding_bottom);
|
||||
return Toplevel::visibleRect().adjusted(-padding_left, -padding_top, padding_right, padding_bottom);
|
||||
}
|
||||
|
||||
inline void Client::setGeometry(const QRect& r, ForceGeometry_t force, bool emitJs)
|
||||
|
|
|
@ -42,8 +42,12 @@
|
|||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QBitmap>
|
||||
#include <QtGui/QX11Info>
|
||||
#include <QtCore/QObjectList>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
namespace Oxygen
|
||||
{
|
||||
|
||||
|
@ -59,7 +63,8 @@ namespace Oxygen
|
|||
_forceActive( false ),
|
||||
_mouseButton( Qt::NoButton ),
|
||||
_itemData( this ),
|
||||
_sourceItem( -1 )
|
||||
_sourceItem( -1 ),
|
||||
_shadowAtom( 0 )
|
||||
{}
|
||||
|
||||
//___________________________________________
|
||||
|
@ -167,6 +172,9 @@ namespace Oxygen
|
|||
|
||||
} else if( hasSizeGrip() ) deleteSizeGrip();
|
||||
|
||||
// needs to remove shadow property on window since shadows are handled by the decoration
|
||||
removeShadowHint();
|
||||
|
||||
}
|
||||
|
||||
//___________________________________________
|
||||
|
@ -1827,4 +1835,18 @@ namespace Oxygen
|
|||
_sizeGrip = 0;
|
||||
}
|
||||
|
||||
//_________________________________________________________________
|
||||
void Client::removeShadowHint( void )
|
||||
{
|
||||
|
||||
// do nothing if no window id
|
||||
if( !windowId() ) return;
|
||||
|
||||
// create atom
|
||||
if( !_shadowAtom )
|
||||
{ _shadowAtom = XInternAtom( QX11Info::display(), "_KDE_NET_WM_SHADOW", False); }
|
||||
|
||||
XDeleteProperty(QX11Info::display(), windowId(), _shadowAtom);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <QtCore/QTextStream>
|
||||
#include <QtCore/QTimerEvent>
|
||||
|
||||
#include <X11/Xdefs.h>
|
||||
|
||||
namespace Oxygen
|
||||
{
|
||||
|
@ -398,6 +399,9 @@ namespace Oxygen
|
|||
|
||||
//@}
|
||||
|
||||
//! remove shadow hint
|
||||
void removeShadowHint( void );
|
||||
|
||||
protected slots:
|
||||
|
||||
//! set target item to -1
|
||||
|
@ -459,6 +463,9 @@ namespace Oxygen
|
|||
*/
|
||||
QBasicTimer _dragStartTimer;
|
||||
|
||||
//! shadow atom
|
||||
Atom _shadowAtom;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Oxygen
|
||||
|
|
|
@ -51,6 +51,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "scene_basic.h"
|
||||
#include "scene_xrender.h"
|
||||
#include "scene_opengl.h"
|
||||
#include "shadow.h"
|
||||
#include "compositingprefs.h"
|
||||
#include "notifications.h"
|
||||
|
||||
|
@ -409,6 +410,9 @@ void Workspace::performCompositing()
|
|||
repaints_region |= c->repaints().translated(c->pos());
|
||||
repaints_region |= c->decorationPendingRegion();
|
||||
c->resetRepaints(c->decorationRect());
|
||||
if (c->hasShadow()) {
|
||||
c->resetRepaints(c->shadow()->shadowRegion().boundingRect());
|
||||
}
|
||||
}
|
||||
QRegion repaints = repaints_region;
|
||||
// clear all repaints, so that post-pass can add repaints for the next repaint
|
||||
|
@ -883,6 +887,9 @@ void Toplevel::addRepaint(int x, int y, int w, int h)
|
|||
void Toplevel::addRepaintFull()
|
||||
{
|
||||
repaints_region = rect();
|
||||
if (hasShadow()) {
|
||||
repaints_region = repaints_region.united(shadow()->shadowRegion());
|
||||
}
|
||||
workspace()->checkCompositeTimer();
|
||||
}
|
||||
|
||||
|
@ -973,6 +980,9 @@ bool Client::shouldUnredirect() const
|
|||
void Client::addRepaintFull()
|
||||
{
|
||||
repaints_region = decorationRect();
|
||||
if (hasShadow()) {
|
||||
repaints_region = repaints_region.united(shadow()->shadowRegion());
|
||||
}
|
||||
workspace()->checkCompositeTimer();
|
||||
}
|
||||
|
||||
|
@ -1016,6 +1026,9 @@ bool Deleted::shouldUnredirect() const
|
|||
void Deleted::addRepaintFull()
|
||||
{
|
||||
repaints_region = decorationRect();
|
||||
if (hasShadow()) {
|
||||
repaints_region = repaints_region.united(shadow()->shadowRegion());
|
||||
}
|
||||
workspace()->checkCompositeTimer();
|
||||
}
|
||||
|
||||
|
|
|
@ -1642,7 +1642,7 @@ void Unmanaged::configureNotifyEvent(XConfigureEvent* e)
|
|||
static_cast<EffectsHandlerImpl*>(effects)->checkInputWindowStacking(); // keep them on top
|
||||
QRect newgeom(e->x, e->y, e->width, e->height);
|
||||
if (newgeom != geom) {
|
||||
addWorkspaceRepaint(geometry()); // damage old area
|
||||
addWorkspaceRepaint(visibleRect()); // damage old area
|
||||
QRect old = geom;
|
||||
geom = newgeom;
|
||||
addRepaintFull();
|
||||
|
@ -1668,6 +1668,8 @@ void Toplevel::propertyNotifyEvent(XPropertyEvent* e)
|
|||
getWmClientLeader();
|
||||
else if (e->atom == atoms->wm_window_role)
|
||||
getWindowRole();
|
||||
else if (e->atom == atoms->kde_net_wm_shadow)
|
||||
getShadow();
|
||||
break;
|
||||
}
|
||||
emit propertyNotify(this, e->atom);
|
||||
|
|
|
@ -174,6 +174,15 @@ enum WindowQuadType {
|
|||
WindowQuadError, // for the stupid default ctor
|
||||
WindowQuadContents,
|
||||
WindowQuadDecoration,
|
||||
// Shadow Quad types
|
||||
WindowQuadShadowTop,
|
||||
WindowQuadShadowTopRight,
|
||||
WindowQuadShadowRight,
|
||||
WindowQuadShadowBottomRight,
|
||||
WindowQuadShadowBottom,
|
||||
WindowQuadShadowBottomLeft,
|
||||
WindowQuadShadowLeft,
|
||||
WindowQuadShadowTopLeft,
|
||||
EFFECT_QUAD_TYPE_START = 100 ///< @internal
|
||||
};
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "deleted.h"
|
||||
#include "effects.h"
|
||||
#include "lanczosfilter.h"
|
||||
#include "shadow.h"
|
||||
|
||||
#include <kephal/screens.h>
|
||||
|
||||
|
@ -352,6 +353,7 @@ QRegion Scene::selfCheckRegion() const
|
|||
Scene::Window::Window(Toplevel * c)
|
||||
: toplevel(c)
|
||||
, filter(ImageFilterFast)
|
||||
, m_shadow(NULL)
|
||||
, disable_painting(0)
|
||||
, shape_valid(false)
|
||||
, cached_quad_list(NULL)
|
||||
|
@ -361,6 +363,7 @@ Scene::Window::Window(Toplevel * c)
|
|||
Scene::Window::~Window()
|
||||
{
|
||||
delete cached_quad_list;
|
||||
delete m_shadow;
|
||||
}
|
||||
|
||||
void Scene::Window::discardShape()
|
||||
|
@ -493,6 +496,9 @@ WindowQuadList Scene::Window::buildQuads(bool force) const
|
|||
ret += makeQuads(WindowQuadDecoration, right);
|
||||
}
|
||||
}
|
||||
if (m_shadow) {
|
||||
ret << m_shadow->shadowQuads();
|
||||
}
|
||||
effects->buildQuads(static_cast<Client*>(toplevel)->effectWindow(), ret);
|
||||
cached_quad_list = new WindowQuadList(ret);
|
||||
return ret;
|
||||
|
|
23
scene.h
23
scene.h
|
@ -35,6 +35,7 @@ class Deleted;
|
|||
class EffectFrameImpl;
|
||||
class EffectWindowImpl;
|
||||
class LanczosFilter;
|
||||
class Shadow;
|
||||
|
||||
// The base class for compositing backends.
|
||||
class Scene
|
||||
|
@ -210,10 +211,14 @@ public:
|
|||
// creates initial quad list for the window
|
||||
virtual WindowQuadList buildQuads(bool force = false) const;
|
||||
void suspendUnredirect(bool suspend);
|
||||
void updateShadow(Shadow* shadow);
|
||||
const Shadow* shadow() const;
|
||||
Shadow* shadow();
|
||||
protected:
|
||||
WindowQuadList makeQuads(WindowQuadType type, const QRegion& reg) const;
|
||||
Toplevel* toplevel;
|
||||
ImageFilterType filter;
|
||||
Shadow *m_shadow;
|
||||
private:
|
||||
int disable_painting;
|
||||
mutable QRegion shape_region;
|
||||
|
@ -319,6 +324,24 @@ void Scene::Window::suspendUnredirect(bool suspend)
|
|||
toplevel->suspendUnredirect(suspend);
|
||||
}
|
||||
|
||||
inline
|
||||
void Scene::Window::updateShadow(Shadow* shadow)
|
||||
{
|
||||
m_shadow = shadow;
|
||||
}
|
||||
|
||||
inline
|
||||
const Shadow* Scene::Window::shadow() const
|
||||
{
|
||||
return m_shadow;
|
||||
}
|
||||
|
||||
inline
|
||||
Shadow* Scene::Window::shadow()
|
||||
{
|
||||
return m_shadow;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
|
242
scene_opengl.cpp
242
scene_opengl.cpp
|
@ -3,6 +3,7 @@
|
|||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
|
||||
Copyright (C) 2009, 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
Based on glcompmgr code by Felix Bellaby.
|
||||
Using code from Compiz and Beryl.
|
||||
|
@ -234,6 +235,8 @@ void SceneOpenGL::windowAdded(Toplevel* c)
|
|||
assert(!windows.contains(c));
|
||||
windows[ c ] = new Window(c);
|
||||
c->effectWindow()->setSceneWindow(windows[ c ]);
|
||||
c->getShadow();
|
||||
windows[ c ]->updateShadow(c->shadow());
|
||||
}
|
||||
|
||||
void SceneOpenGL::windowClosed(Toplevel* c, Deleted* deleted)
|
||||
|
@ -243,6 +246,9 @@ void SceneOpenGL::windowClosed(Toplevel* c, Deleted* deleted)
|
|||
// replace c with deleted
|
||||
Window* w = windows.take(c);
|
||||
w->updateToplevel(deleted);
|
||||
if (w->shadow()) {
|
||||
w->shadow()->setToplevel(deleted);
|
||||
}
|
||||
windows[ deleted ] = w;
|
||||
} else {
|
||||
delete windows.take(c);
|
||||
|
@ -511,6 +517,17 @@ void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData
|
|||
GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer();
|
||||
vbo->reset();
|
||||
|
||||
// shadow
|
||||
if (m_shadow) {
|
||||
paintShadow(WindowQuadShadowTop, region, data);
|
||||
paintShadow(WindowQuadShadowTopRight, region, data);
|
||||
paintShadow(WindowQuadShadowRight, region, data);
|
||||
paintShadow(WindowQuadShadowBottomRight, region, data);
|
||||
paintShadow(WindowQuadShadowBottom, region, data);
|
||||
paintShadow(WindowQuadShadowBottomLeft, region, data);
|
||||
paintShadow(WindowQuadShadowLeft, region, data);
|
||||
paintShadow(WindowQuadShadowTopLeft, region, data);
|
||||
}
|
||||
// decorations
|
||||
Client *client = dynamic_cast<Client*>(toplevel);
|
||||
Deleted *deleted = dynamic_cast<Deleted*>(toplevel);
|
||||
|
@ -654,6 +671,36 @@ void SceneOpenGL::Window::paintDecoration(const QPixmap* decoration, TextureType
|
|||
#endif
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::paintShadow(WindowQuadType type, const QRegion ®ion, const WindowPaintData &data)
|
||||
{
|
||||
WindowQuadList quads = data.quads.select(type);
|
||||
Texture *texture = static_cast<SceneOpenGLShadow*>(m_shadow)->textureForQuadType(type);
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
if (filter == ImageFilterGood)
|
||||
texture->setFilter(GL_LINEAR);
|
||||
else
|
||||
texture->setFilter(GL_NEAREST);
|
||||
texture->setWrapMode(GL_CLAMP_TO_EDGE);
|
||||
texture->bind();
|
||||
prepareStates(Shadow, data.opacity, data.brightness, data.saturation, data.shader, texture);
|
||||
if (data.shader) {
|
||||
data.shader->setUniform(GLShader::TextureWidth, 1.0f);
|
||||
data.shader->setUniform(GLShader::TextureHeight, 1.0f);
|
||||
}
|
||||
renderQuads(0, region, quads);
|
||||
restoreStates(Shadow, data.opacity, data.brightness, data.saturation, data.shader, texture);
|
||||
texture->unbind();
|
||||
#ifndef KWIN_HAVE_OPENGLES
|
||||
if (static_cast<SceneOpenGL*>(scene)->debug) {
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
renderQuads(0, region, quads);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::makeDecorationArrays(const WindowQuadList& quads, const QRect& rect) const
|
||||
{
|
||||
QVector<float> vertices;
|
||||
|
@ -710,8 +757,38 @@ void SceneOpenGL::Window::prepareStates(TextureType type, double opacity, double
|
|||
{
|
||||
if (shader)
|
||||
prepareShaderRenderStates(type, opacity, brightness, saturation, shader);
|
||||
else
|
||||
prepareRenderStates(type, opacity, brightness, saturation);
|
||||
else {
|
||||
Texture *tex = NULL;
|
||||
switch(type) {
|
||||
case Content:
|
||||
tex = &texture;
|
||||
break;
|
||||
case DecorationTop:
|
||||
tex = &topTexture;
|
||||
break;
|
||||
case DecorationLeft:
|
||||
tex = &leftTexture;
|
||||
break;
|
||||
case DecorationRight:
|
||||
tex = &rightTexture;
|
||||
break;
|
||||
case DecorationBottom:
|
||||
tex = &bottomTexture;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
prepareStates(type, opacity, brightness, saturation, shader, tex);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, Texture *texture)
|
||||
{
|
||||
if (shader) {
|
||||
prepareShaderRenderStates(type, opacity, brightness, saturation, shader);
|
||||
} else {
|
||||
prepareRenderStates(type, opacity, brightness, saturation, texture);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::prepareShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader)
|
||||
|
@ -750,45 +827,23 @@ void SceneOpenGL::Window::prepareShaderRenderStates(TextureType type, double opa
|
|||
shader->setUniform(GLShader::TextureHeight, texh >= 0.0 ? texh : toplevel->height());
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::prepareRenderStates(TextureType type, double opacity, double brightness, double saturation)
|
||||
void SceneOpenGL::Window::prepareRenderStates(TextureType type, double opacity, double brightness, double saturation, Texture *tex)
|
||||
{
|
||||
#ifdef KWIN_HAVE_OPENGLES
|
||||
Q_UNUSED(type)
|
||||
Q_UNUSED(opacity)
|
||||
Q_UNUSED(brightness)
|
||||
Q_UNUSED(saturation)
|
||||
Q_UNUSED(tex)
|
||||
#else
|
||||
Texture* tex;
|
||||
bool alpha = false;
|
||||
bool opaque = true;
|
||||
switch(type) {
|
||||
case Content:
|
||||
tex = &texture;
|
||||
if (type == Content) {
|
||||
alpha = toplevel->hasAlpha();
|
||||
opaque = isOpaque() && opacity == 1.0;
|
||||
break;
|
||||
case DecorationTop:
|
||||
tex = &topTexture;
|
||||
} else {
|
||||
alpha = true;
|
||||
opaque = false;
|
||||
break;
|
||||
case DecorationLeft:
|
||||
tex = &leftTexture;
|
||||
alpha = true;
|
||||
opaque = false;
|
||||
break;
|
||||
case DecorationRight:
|
||||
tex = &rightTexture;
|
||||
alpha = true;
|
||||
opaque = false;
|
||||
break;
|
||||
case DecorationBottom:
|
||||
tex = &bottomTexture;
|
||||
alpha = true;
|
||||
opaque = false;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
// setup blending of transparent windows
|
||||
glPushAttrib(GL_ENABLE_BIT);
|
||||
|
@ -912,8 +967,38 @@ void SceneOpenGL::Window::restoreStates(TextureType type, double opacity, double
|
|||
{
|
||||
if (shader)
|
||||
restoreShaderRenderStates(type, opacity, brightness, saturation, shader);
|
||||
else
|
||||
restoreRenderStates(type, opacity, brightness, saturation);
|
||||
else {
|
||||
Texture *tex = NULL;
|
||||
switch(type) {
|
||||
case Content:
|
||||
tex = &texture;
|
||||
break;
|
||||
case DecorationTop:
|
||||
tex = &topTexture;
|
||||
break;
|
||||
case DecorationLeft:
|
||||
tex = &leftTexture;
|
||||
break;
|
||||
case DecorationRight:
|
||||
tex = &rightTexture;
|
||||
break;
|
||||
case DecorationBottom:
|
||||
tex = &bottomTexture;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
restoreStates(type, opacity, brightness, saturation, shader, tex);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::restoreStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, Texture *texture)
|
||||
{
|
||||
if (shader) {
|
||||
restoreShaderRenderStates(type, opacity, brightness, saturation, shader);
|
||||
} else {
|
||||
restoreRenderStates(type, opacity, brightness, saturation, texture);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::restoreShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader)
|
||||
|
@ -933,34 +1018,15 @@ void SceneOpenGL::Window::restoreShaderRenderStates(TextureType type, double opa
|
|||
#endif
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::restoreRenderStates(TextureType type, double opacity, double brightness, double saturation)
|
||||
void SceneOpenGL::Window::restoreRenderStates(TextureType type, double opacity, double brightness, double saturation, Texture *tex)
|
||||
{
|
||||
#ifdef KWIN_HAVE_OPENGLES
|
||||
Q_UNUSED(type)
|
||||
#ifdef KWIN_HAVE_OPENGLES
|
||||
Q_UNUSED(opacity)
|
||||
Q_UNUSED(brightness)
|
||||
Q_UNUSED(saturation)
|
||||
Q_UNUSED(tex)
|
||||
#else
|
||||
Texture* tex;
|
||||
switch(type) {
|
||||
case Content:
|
||||
tex = &texture;
|
||||
break;
|
||||
case DecorationTop:
|
||||
tex = &topTexture;
|
||||
break;
|
||||
case DecorationLeft:
|
||||
tex = &leftTexture;
|
||||
break;
|
||||
case DecorationRight:
|
||||
tex = &rightTexture;
|
||||
break;
|
||||
case DecorationBottom:
|
||||
tex = &bottomTexture;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if (opacity != 1.0 || saturation != 1.0 || brightness != 1.0f) {
|
||||
if (saturation != 1.0 && tex->saturationSupported()) {
|
||||
glActiveTexture(GL_TEXTURE3);
|
||||
|
@ -1449,6 +1515,78 @@ void SceneOpenGL::EffectFrame::cleanup()
|
|||
m_unstyledPixmap = NULL;
|
||||
}
|
||||
|
||||
//****************************************
|
||||
// SceneOpenGL::Shadow
|
||||
//****************************************
|
||||
SceneOpenGLShadow::SceneOpenGLShadow(Toplevel *toplevel)
|
||||
: Shadow(toplevel)
|
||||
{
|
||||
}
|
||||
|
||||
SceneOpenGLShadow::~SceneOpenGLShadow()
|
||||
{
|
||||
for (int i=0; i<ShadowElementsCount; ++i) {
|
||||
m_shadowTextures[i].discard();
|
||||
}
|
||||
}
|
||||
|
||||
SceneOpenGL::Texture *SceneOpenGLShadow::textureForQuadType(WindowQuadType type)
|
||||
{
|
||||
SceneOpenGL::Texture *texture = NULL;
|
||||
QPixmap pixmap;
|
||||
switch (type) {
|
||||
case WindowQuadShadowTop:
|
||||
texture = &m_shadowTextures[ShadowElementTop];
|
||||
pixmap = shadowPixmap(ShadowElementTop);
|
||||
break;
|
||||
case WindowQuadShadowTopRight:
|
||||
texture = &m_shadowTextures[ShadowElementTopRight];
|
||||
pixmap = shadowPixmap(ShadowElementTopRight);
|
||||
break;
|
||||
case WindowQuadShadowRight:
|
||||
texture = &m_shadowTextures[ShadowElementRight];
|
||||
pixmap = shadowPixmap(ShadowElementRight);
|
||||
break;
|
||||
case WindowQuadShadowBottomRight:
|
||||
texture = &m_shadowTextures[ShadowElementBottomRight];
|
||||
pixmap = shadowPixmap(ShadowElementBottomRight);
|
||||
break;
|
||||
case WindowQuadShadowBottom:
|
||||
texture = &m_shadowTextures[ShadowElementBottom];
|
||||
pixmap = shadowPixmap(ShadowElementBottom);
|
||||
break;
|
||||
case WindowQuadShadowBottomLeft:
|
||||
texture = &m_shadowTextures[ShadowElementBottomLeft];
|
||||
pixmap = shadowPixmap(ShadowElementBottomLeft);
|
||||
break;
|
||||
case WindowQuadShadowLeft:
|
||||
texture = &m_shadowTextures[ShadowElementLeft];
|
||||
pixmap = shadowPixmap(ShadowElementLeft);
|
||||
break;
|
||||
case WindowQuadShadowTopLeft:
|
||||
texture = &m_shadowTextures[ShadowElementTopLeft];
|
||||
pixmap = shadowPixmap(ShadowElementTopLeft);
|
||||
break;
|
||||
default:
|
||||
// nothing
|
||||
break;
|
||||
}
|
||||
if (texture) {
|
||||
if (texture->texture() != None) {
|
||||
glBindTexture(texture->target(), texture->texture());
|
||||
} else if (!pixmap.isNull()) {
|
||||
const bool success = texture->load(pixmap.handle(), pixmap.size(), pixmap.depth());
|
||||
if (!success) {
|
||||
kDebug(1212) << "Failed to bind shadow pixmap";
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
|
||||
Copyright (C) 2009, 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -22,6 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#define KWIN_SCENE_OPENGL_H
|
||||
|
||||
#include "scene.h"
|
||||
#include "shadow.h"
|
||||
|
||||
#include "kwinglutils.h"
|
||||
|
||||
|
@ -156,18 +158,22 @@ protected:
|
|||
DecorationTop,
|
||||
DecorationLeft,
|
||||
DecorationRight,
|
||||
DecorationBottom
|
||||
DecorationBottom,
|
||||
Shadow
|
||||
};
|
||||
|
||||
QMatrix4x4 transformation(int mask, const WindowPaintData &data) const;
|
||||
void paintDecoration(const QPixmap* decoration, TextureType decorationType, const QRegion& region, const QRect& rect, const WindowPaintData& data, const WindowQuadList& quads, bool updateDeco);
|
||||
void paintShadow(WindowQuadType type, const QRegion ®ion, const WindowPaintData &data);
|
||||
void makeDecorationArrays(const WindowQuadList& quads, const QRect& rect) const;
|
||||
void renderQuads(int mask, const QRegion& region, const WindowQuadList& quads);
|
||||
void prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader);
|
||||
void prepareRenderStates(TextureType type, double opacity, double brightness, double saturation);
|
||||
void prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, Texture *texture);
|
||||
void prepareRenderStates(TextureType type, double opacity, double brightness, double saturation, Texture *tex);
|
||||
void prepareShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader);
|
||||
void restoreStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader);
|
||||
void restoreRenderStates(TextureType type, double opacity, double brightness, double saturation);
|
||||
void restoreStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, Texture *texture);
|
||||
void restoreRenderStates(TextureType type, double opacity, double brightness, double saturation, Texture *tex);
|
||||
void restoreShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader);
|
||||
|
||||
private:
|
||||
|
@ -215,6 +221,31 @@ private:
|
|||
static void updateUnstyledTexture(); // Update OpenGL unstyled frame texture
|
||||
};
|
||||
|
||||
/**
|
||||
* @short OpenGL implementation of Shadow.
|
||||
*
|
||||
* This class extends Shadow by the Elements required for OpenGL rendering.
|
||||
* @author Martin Gräßlin <mgraesslin@kde.org>
|
||||
**/
|
||||
class SceneOpenGLShadow
|
||||
: public Shadow
|
||||
{
|
||||
public:
|
||||
SceneOpenGLShadow(Toplevel *toplevel);
|
||||
virtual ~SceneOpenGLShadow();
|
||||
|
||||
/**
|
||||
* Returns the Texture for a specific ShadowQuad. The method takes care of performing
|
||||
* the Texture from Pixmap operation. The calling method can use the returned Texture
|
||||
* directly.
|
||||
* In error case the method returns @c NULL.
|
||||
* @return OpenGL Texture for the Shadow Quad. May be @c NULL.
|
||||
**/
|
||||
SceneOpenGL::Texture *textureForQuadType(WindowQuadType type);
|
||||
private:
|
||||
SceneOpenGL::Texture m_shadowTextures[ShadowElementsCount];
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
|
213
shadow.cpp
Normal file
213
shadow.cpp
Normal file
|
@ -0,0 +1,213 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#include "shadow.h"
|
||||
// kwin
|
||||
#include "atoms.h"
|
||||
#include "effects.h"
|
||||
#include "toplevel.h"
|
||||
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
|
||||
#include "scene_opengl.h"
|
||||
#endif
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
Shadow::Shadow(Toplevel *toplevel)
|
||||
: m_topLevel(toplevel)
|
||||
, m_cachedSize(toplevel->geometry().size())
|
||||
{
|
||||
connect(m_topLevel, SIGNAL(geometryChanged()), SLOT(geometryChanged()));
|
||||
}
|
||||
|
||||
Shadow::~Shadow()
|
||||
{
|
||||
}
|
||||
|
||||
Shadow *Shadow::createShadow(Toplevel *toplevel)
|
||||
{
|
||||
if (!effects) {
|
||||
return NULL;
|
||||
}
|
||||
QVector<long> data = Shadow::readX11ShadowProperty(toplevel->window());
|
||||
if (!data.isEmpty()) {
|
||||
Shadow *shadow = NULL;
|
||||
if (effects->compositingType() == OpenGLCompositing) {
|
||||
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
|
||||
shadow = new SceneOpenGLShadow(toplevel);
|
||||
#endif
|
||||
}
|
||||
if (shadow) {
|
||||
if (!shadow->init(data)) {
|
||||
delete shadow;
|
||||
return NULL;
|
||||
}
|
||||
if (toplevel->effectWindow() && toplevel->effectWindow()->sceneWindow()) {
|
||||
toplevel->effectWindow()->sceneWindow()->updateShadow(shadow);
|
||||
}
|
||||
}
|
||||
return shadow;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
QVector< long > Shadow::readX11ShadowProperty(WId id)
|
||||
{
|
||||
QVector<long> ret;
|
||||
Atom type;
|
||||
int format, status;
|
||||
unsigned long nitems = 0;
|
||||
unsigned long extra = 0;
|
||||
unsigned char *data = 0;
|
||||
status = XGetWindowProperty(display(), id, atoms->kde_net_wm_shadow, 0, 12, false, XA_CARDINAL, &type, &format, &nitems, &extra, &data);
|
||||
if (status == Success && type == XA_CARDINAL && format == 32 && nitems == 12) {
|
||||
long* shadow = reinterpret_cast< long* >(data);
|
||||
ret.reserve(12);
|
||||
for (int i=0; i<12; ++i) {
|
||||
ret << shadow[i];
|
||||
}
|
||||
XFree(data);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Shadow::init(const QVector< long > &data)
|
||||
{
|
||||
for (int i=0; i<ShadowElementsCount; ++i) {
|
||||
QPixmap pix = QPixmap::fromX11Pixmap(data[i]);
|
||||
if (pix.isNull()) {
|
||||
return false;
|
||||
}
|
||||
m_shadowElements[i] = pix.copy(0, 0, pix.width(), pix.height());
|
||||
}
|
||||
m_topOffset = data[ShadowElementsCount];
|
||||
m_rightOffset = data[ShadowElementsCount+1];
|
||||
m_bottomOffset = data[ShadowElementsCount+2];
|
||||
m_leftOffset = data[ShadowElementsCount+3];
|
||||
updateShadowRegion();
|
||||
buildQuads();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Shadow::updateShadowRegion()
|
||||
{
|
||||
const QRect topRect(0, - m_topOffset, m_topLevel->width(), m_topOffset);
|
||||
const QRect rightRect(m_topLevel->width(), - m_topOffset, m_rightOffset, m_topLevel->height() + m_topOffset + m_bottomOffset);
|
||||
const QRect bottomRect(0, m_topLevel->height(), m_topLevel->width(), m_bottomOffset);
|
||||
const QRect leftRect(- m_leftOffset, - m_topOffset, m_leftOffset, m_topLevel->height() + m_topOffset + m_bottomOffset);
|
||||
m_shadowRegion = QRegion(topRect).united(rightRect).united(bottomRect).united(leftRect);
|
||||
}
|
||||
|
||||
void Shadow::buildQuads()
|
||||
{
|
||||
// prepare window quads
|
||||
m_shadowQuads.clear();
|
||||
const QRect topRect(QPoint(0, 0), m_shadowElements[ShadowElementTop].size());
|
||||
const QRect topRightRect(QPoint(0, 0), m_shadowElements[ShadowElementTopRight].size());
|
||||
const QRect rightRect(QPoint(0, 0), m_shadowElements[ShadowElementRight].size());
|
||||
const QRect bottomRightRect(QPoint(0, 0), m_shadowElements[ShadowElementBottomRight].size());
|
||||
const QRect bottomRect(QPoint(0, 0), m_shadowElements[ShadowElementBottom].size());
|
||||
const QRect bottomLeftRect(QPoint(0, 0), m_shadowElements[ShadowElementBottomLeft].size());
|
||||
const QRect leftRect(QPoint(0, 0), m_shadowElements[ShadowElementLeft].size());
|
||||
const QRect topLeftRect(QPoint(0, 0), m_shadowElements[ShadowElementTopLeft].size());
|
||||
if ((leftRect.width() - m_leftOffset > m_topLevel->width()) ||
|
||||
(rightRect.width() - m_rightOffset > m_topLevel->width()) ||
|
||||
(topRect.height() - m_topOffset > m_topLevel->height()) ||
|
||||
(bottomRect.height() - m_bottomOffset > m_topLevel->height())) {
|
||||
// if our shadow is bigger than the window, we don't render the shadow
|
||||
m_shadowRegion = QRegion();
|
||||
return;
|
||||
}
|
||||
WindowQuad topLeftQuad(WindowQuadShadowTopLeft);
|
||||
topLeftQuad[ 0 ] = WindowVertex(-m_leftOffset, -m_topOffset, 0.0, 0.0);
|
||||
topLeftQuad[ 1 ] = WindowVertex(-m_leftOffset + topLeftRect.width(), -m_topOffset, 1.0, 0.0);
|
||||
topLeftQuad[ 2 ] = WindowVertex(-m_leftOffset + topLeftRect.width(), -m_topOffset + topLeftRect.height(), 1.0, 1.0);
|
||||
topLeftQuad[ 3 ] = WindowVertex(-m_leftOffset, -m_topOffset + topLeftRect.height(), 0.0, 1.0);
|
||||
m_shadowQuads.append(topLeftQuad);
|
||||
WindowQuad topQuad(WindowQuadShadowTop);
|
||||
topQuad[ 0 ] = WindowVertex(-m_leftOffset + topLeftRect.width(), -m_topOffset, 0.0, 0.0);
|
||||
topQuad[ 1 ] = WindowVertex(m_topLevel->width() + m_rightOffset - topRightRect.width(), -m_topOffset, 1.0, 0.0);
|
||||
topQuad[ 2 ] = WindowVertex(m_topLevel->width() + m_rightOffset - topRightRect.width(), -m_topOffset + topRect.height(), 1.0, 1.0);
|
||||
topQuad[ 3 ] = WindowVertex(-m_leftOffset + topLeftRect.width(), -m_topOffset + topRect.height(), 0.0, 1.0);
|
||||
m_shadowQuads.append(topQuad);
|
||||
WindowQuad topRightQuad(WindowQuadShadowTopRight);
|
||||
topRightQuad[ 0 ] = WindowVertex(m_topLevel->width() + m_rightOffset - topRightRect.width(), -m_topOffset, 0.0, 0.0);
|
||||
topRightQuad[ 1 ] = WindowVertex(m_topLevel->width() + m_rightOffset, -m_topOffset, 1.0, 0.0);
|
||||
topRightQuad[ 2 ] = WindowVertex(m_topLevel->width() + m_rightOffset, -m_topOffset + topRightRect.height(), 1.0, 1.0);
|
||||
topRightQuad[ 3 ] = WindowVertex(m_topLevel->width() + m_rightOffset - topRightRect.width(), -m_topOffset + topRightRect.height(), 0.0, 1.0);
|
||||
m_shadowQuads.append(topRightQuad);
|
||||
WindowQuad rightQuad(WindowQuadShadowRight);
|
||||
rightQuad[ 0 ] = WindowVertex(m_topLevel->width() + m_rightOffset - rightRect.width(), -m_topOffset + topRightRect.height(), 0.0, 0.0);
|
||||
rightQuad[ 1 ] = WindowVertex(m_topLevel->width() + m_rightOffset, -m_topOffset + topRightRect.height(), 1.0, 0.0);
|
||||
rightQuad[ 2 ] = WindowVertex(m_topLevel->width() + m_rightOffset, m_topLevel->height() + m_bottomOffset - bottomRightRect.height(), 1.0, 1.0);
|
||||
rightQuad[ 3 ] = WindowVertex(m_topLevel->width() + m_rightOffset - rightRect.width(), m_topLevel->height() + m_bottomOffset - bottomRightRect.height(), 0.0, 1.0);
|
||||
m_shadowQuads.append(rightQuad);
|
||||
WindowQuad bottomRightQuad(WindowQuadShadowBottomRight);
|
||||
bottomRightQuad[ 0 ] = WindowVertex(m_topLevel->width() + m_rightOffset - bottomRightRect.width(), m_topLevel->height() + m_bottomOffset - bottomRightRect.height(), 0.0, 0.0);
|
||||
bottomRightQuad[ 1 ] = WindowVertex(m_topLevel->width() + m_rightOffset, m_topLevel->height() + m_bottomOffset - bottomRightRect.height(), 1.0, 0.0);
|
||||
bottomRightQuad[ 2 ] = WindowVertex(m_topLevel->width() + m_rightOffset, m_topLevel->height() + m_bottomOffset, 1.0, 1.0);
|
||||
bottomRightQuad[ 3 ] = WindowVertex(m_topLevel->width() + m_rightOffset - bottomRightRect.width(), m_topLevel->height() + m_bottomOffset, 0.0, 1.0);
|
||||
m_shadowQuads.append(bottomRightQuad);
|
||||
WindowQuad bottomQuad(WindowQuadShadowBottom);
|
||||
bottomQuad[ 0 ] = WindowVertex(-m_leftOffset + bottomLeftRect.width(), m_topLevel->height() + m_bottomOffset - bottomRect.height(), 0.0, 0.0);
|
||||
bottomQuad[ 1 ] = WindowVertex(m_topLevel->width() + m_rightOffset - bottomRightRect.width(), m_topLevel->height() + m_bottomOffset - bottomRect.height(), 1.0, 0.0);
|
||||
bottomQuad[ 2 ] = WindowVertex(m_topLevel->width() + m_rightOffset - bottomRightRect.width(), m_topLevel->height() + m_bottomOffset, 1.0, 1.0);
|
||||
bottomQuad[ 3 ] = WindowVertex(-m_leftOffset + bottomLeftRect.width(), m_topLevel->height() + m_bottomOffset, 0.0, 1.0);
|
||||
m_shadowQuads.append(bottomQuad);
|
||||
WindowQuad bottomLeftQuad(WindowQuadShadowBottomLeft);
|
||||
bottomLeftQuad[ 0 ] = WindowVertex(-m_leftOffset, m_topLevel->height() + m_bottomOffset - bottomLeftRect.height(), 0.0, 0.0);
|
||||
bottomLeftQuad[ 1 ] = WindowVertex(-m_leftOffset + bottomLeftRect.width(), m_topLevel->height() + m_bottomOffset - bottomLeftRect.height(), 1.0, 0.0);
|
||||
bottomLeftQuad[ 2 ] = WindowVertex(-m_leftOffset + bottomLeftRect.width(), m_topLevel->height() + m_bottomOffset, 1.0, 1.0);
|
||||
bottomLeftQuad[ 3 ] = WindowVertex(-m_leftOffset, m_topLevel->height() + m_bottomOffset, 0.0, 1.0);
|
||||
m_shadowQuads.append(bottomLeftQuad);
|
||||
WindowQuad leftQuad(WindowQuadShadowLeft);
|
||||
leftQuad[ 0 ] = WindowVertex(-m_leftOffset, -m_topOffset + topLeftRect.height(), 0.0, 0.0);
|
||||
leftQuad[ 1 ] = WindowVertex(-m_leftOffset + leftRect.width(), -m_topOffset + topLeftRect.height(), 1.0, 0.0);
|
||||
leftQuad[ 2 ] = WindowVertex(-m_leftOffset + leftRect.width(), m_topLevel->height() + m_bottomOffset - bottomLeftRect.height(), 1.0, 1.0);
|
||||
leftQuad[ 3 ] = WindowVertex(-m_leftOffset, m_topLevel->height() + m_bottomOffset - bottomLeftRect.height(), 0.0, 1.0);
|
||||
m_shadowQuads.append(leftQuad);
|
||||
}
|
||||
|
||||
bool Shadow::updateShadow()
|
||||
{
|
||||
QVector<long> data = Shadow::readX11ShadowProperty(m_topLevel->window());
|
||||
if (data.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
init(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Shadow::setToplevel(Toplevel *topLevel)
|
||||
{
|
||||
m_topLevel = topLevel;
|
||||
connect(m_topLevel, SIGNAL(geometryChanged()), SLOT(geometryChanged()));
|
||||
}
|
||||
void Shadow::geometryChanged()
|
||||
{
|
||||
if (m_cachedSize == m_topLevel->geometry().size()) {
|
||||
return;
|
||||
}
|
||||
m_cachedSize = m_topLevel->geometry().size();
|
||||
updateShadowRegion();
|
||||
buildQuads();
|
||||
}
|
||||
|
||||
} // namespace
|
148
shadow.h
Normal file
148
shadow.h
Normal file
|
@ -0,0 +1,148 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#ifndef KWIN_SHADOW_H
|
||||
#define KWIN_SHADOW_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtGui/QPixmap>
|
||||
#include <kwineffects.h>
|
||||
|
||||
namespace KWin {
|
||||
|
||||
class Toplevel;
|
||||
|
||||
/**
|
||||
* @short Class representing a Window's Shadow to be rendered by the Compositor.
|
||||
*
|
||||
* This class holds all information about the Shadow to be rendered together with the
|
||||
* window during the Compositing stage. The Shadow consists of several pixmaps and offsets.
|
||||
* For a complete description please refer to http://community.kde.org/KWin/Shadow
|
||||
*
|
||||
* To create a Shadow instance use the static factory method @link createShadow which will
|
||||
* create an instance for the currently used Compositing Backend. It will read the X11 Property
|
||||
* and create the Shadow and all required data (such as WindowQuads). If there is no Shadow
|
||||
* defined for the Toplevel the factory method returns @c NULL.
|
||||
*
|
||||
* @author Martin Gräßlin <mgraesslin@kde.org>
|
||||
* @todo React on Toplevel size changes.
|
||||
**/
|
||||
class Shadow : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
virtual ~Shadow();
|
||||
|
||||
/**
|
||||
* @return Region of the shadow.
|
||||
**/
|
||||
const QRegion &shadowRegion() const {
|
||||
return m_shadowRegion;
|
||||
};
|
||||
/**
|
||||
* @return Cached Shadow Quads
|
||||
**/
|
||||
const WindowQuadList &shadowQuads() {
|
||||
return m_shadowQuads;
|
||||
};
|
||||
|
||||
/**
|
||||
* This method updates the Shadow when the property has been changed.
|
||||
* It is the responsibility of the owner of the Shadow to call this method
|
||||
* whenever the owner receives a PropertyNotify event.
|
||||
* This method will invoke a re-read of the Property. In case the Property has
|
||||
* been withdrawn the method returns @c false. In that case the owner should
|
||||
* delete the Shadow.
|
||||
* @returns @c true when the shadow has been updated, @c false if the property is not set anymore.
|
||||
**/
|
||||
virtual bool updateShadow();
|
||||
|
||||
/**
|
||||
* Factory Method to create the shadow from the property.
|
||||
* This method takes care of creating an instance of the
|
||||
* Shadow class for the current Compositing Backend.
|
||||
*
|
||||
* If there is no shadow defined for @p toplevel this method
|
||||
* will return @c NULL.
|
||||
* @param toplevel The Toplevel for which the shadow should be created
|
||||
* @return Created Shadow or @c NULL in case there is no shadow defined.
|
||||
**/
|
||||
static Shadow *createShadow(Toplevel *toplevel);
|
||||
|
||||
/**
|
||||
* Reparents the shadow to @p toplevel.
|
||||
* Used when a window is deleted.
|
||||
* @param toplevel The new parent
|
||||
**/
|
||||
void setToplevel(Toplevel *toplevel);
|
||||
|
||||
public Q_SLOTS:
|
||||
void geometryChanged();
|
||||
|
||||
protected:
|
||||
Shadow(Toplevel *toplevel);
|
||||
enum ShadowElements {
|
||||
ShadowElementTop,
|
||||
ShadowElementTopRight,
|
||||
ShadowElementRight,
|
||||
ShadowElementBottomRight,
|
||||
ShadowElementBottom,
|
||||
ShadowElementBottomLeft,
|
||||
ShadowElementLeft,
|
||||
ShadowElementTopLeft,
|
||||
ShadowElementsCount
|
||||
};
|
||||
const QPixmap &shadowPixmap(ShadowElements element) const {
|
||||
return m_shadowElements[element];
|
||||
};
|
||||
int topOffset() const {
|
||||
return m_topOffset;
|
||||
};
|
||||
int rightOffset() const {
|
||||
return m_rightOffset;
|
||||
};
|
||||
int bottomOffset() const {
|
||||
return m_bottomOffset;
|
||||
};
|
||||
int leftOffset() const {
|
||||
return m_leftOffset;
|
||||
};
|
||||
virtual void buildQuads();
|
||||
void updateShadowRegion();
|
||||
|
||||
private:
|
||||
static QVector<long> readX11ShadowProperty(WId id);
|
||||
bool init(const QVector<long> &data);
|
||||
Toplevel *m_topLevel;
|
||||
// shadow pixmaps
|
||||
QPixmap m_shadowElements[ShadowElementsCount];
|
||||
// shadow offsets
|
||||
int m_topOffset;
|
||||
int m_rightOffset;
|
||||
int m_bottomOffset;
|
||||
int m_leftOffset;
|
||||
// caches
|
||||
QRegion m_shadowRegion;
|
||||
WindowQuadList m_shadowQuads;
|
||||
QSize m_cachedSize;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // KWIN_SHADOW_H
|
39
toplevel.cpp
39
toplevel.cpp
|
@ -25,6 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "atoms.h"
|
||||
#include "client.h"
|
||||
#include "effects.h"
|
||||
#include "shadow.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -142,6 +143,9 @@ void Toplevel::disownDataPassedToDeleted()
|
|||
|
||||
QRect Toplevel::visibleRect() const
|
||||
{
|
||||
if (hasShadow()) {
|
||||
return shadow()->shadowRegion().boundingRect().translated(geometry().topLeft());
|
||||
}
|
||||
return geometry();
|
||||
}
|
||||
|
||||
|
@ -348,6 +352,41 @@ bool Toplevel::isOnScreen(int screen) const
|
|||
return workspace()->screenGeometry(screen).intersects(geometry());
|
||||
}
|
||||
|
||||
void Toplevel::getShadow()
|
||||
{
|
||||
if (hasShadow()) {
|
||||
effectWindow()->sceneWindow()->shadow()->updateShadow();
|
||||
} else {
|
||||
Shadow::createShadow(this);
|
||||
addRepaintFull();
|
||||
}
|
||||
}
|
||||
|
||||
bool Toplevel::hasShadow() const
|
||||
{
|
||||
if (effectWindow() && effectWindow()->sceneWindow()) {
|
||||
return effectWindow()->sceneWindow()->shadow() != NULL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Shadow *Toplevel::shadow()
|
||||
{
|
||||
if (effectWindow() && effectWindow()->sceneWindow()) {
|
||||
return effectWindow()->sceneWindow()->shadow();
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const Shadow *Toplevel::shadow() const
|
||||
{
|
||||
if (effectWindow() && effectWindow()->sceneWindow()) {
|
||||
return effectWindow()->sceneWindow()->shadow();
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
|
30
toplevel.h
30
toplevel.h
|
@ -44,6 +44,7 @@ namespace KWin
|
|||
|
||||
class Workspace;
|
||||
class EffectWindowImpl;
|
||||
class Shadow;
|
||||
|
||||
class Toplevel
|
||||
: public QObject, public KDecorationDefines
|
||||
|
@ -134,11 +135,34 @@ public:
|
|||
QRegion damage() const;
|
||||
void resetDamage(const QRect& r);
|
||||
EffectWindowImpl* effectWindow();
|
||||
const EffectWindowImpl* effectWindow() const;
|
||||
|
||||
/**
|
||||
* @returns Whether the Toplevel has a Shadow or not
|
||||
* @see shadow
|
||||
**/
|
||||
bool hasShadow() const;
|
||||
/**
|
||||
* Returns the pointer to the Toplevel's Shadow. A Shadow
|
||||
* is only available if Compositing is enabled and the corresponding X window
|
||||
* has the Shadow property set.
|
||||
* If a shadow is available @link hasShadow returns @c true.
|
||||
* @returns The Shadow belonging to this Toplevel, may be @c NULL.
|
||||
* @see hasShadow
|
||||
**/
|
||||
const Shadow *shadow() const;
|
||||
Shadow *shadow();
|
||||
/**
|
||||
* Updates the Shadow associated with this Toplevel from X11 Property.
|
||||
* Call this method when the Property changes or Compositing is started.
|
||||
**/
|
||||
void getShadow();
|
||||
|
||||
signals:
|
||||
void opacityChanged(KWin::Toplevel* toplevel, qreal oldOpacity);
|
||||
void damaged(KWin::Toplevel* toplevel, const QRect& damage);
|
||||
void propertyNotify(KWin::Toplevel* toplevel, long a);
|
||||
void geometryChanged();
|
||||
|
||||
protected:
|
||||
virtual ~Toplevel();
|
||||
|
@ -392,6 +416,12 @@ EffectWindowImpl* Toplevel::effectWindow()
|
|||
return effect_window;
|
||||
}
|
||||
|
||||
inline
|
||||
const EffectWindowImpl* Toplevel::effectWindow() const
|
||||
{
|
||||
return effect_window;
|
||||
}
|
||||
|
||||
inline bool Toplevel::isOnAllDesktops() const
|
||||
{
|
||||
return desktop() == NET::OnAllDesktops;
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace KWin
|
|||
Unmanaged::Unmanaged(Workspace* ws)
|
||||
: Toplevel(ws)
|
||||
{
|
||||
connect(this, SIGNAL(unmanagedGeometryShapeChanged(KWin::Unmanaged*,QRect)), SIGNAL(geometryChanged()));
|
||||
}
|
||||
|
||||
Unmanaged::~Unmanaged()
|
||||
|
@ -92,7 +93,7 @@ void Unmanaged::release()
|
|||
XShapeSelectInput(display(), window(), NoEventMask);
|
||||
XSelectInput(display(), window(), NoEventMask);
|
||||
}
|
||||
addWorkspaceRepaint(geometry());
|
||||
addWorkspaceRepaint(del->visibleRect());
|
||||
disownDataPassedToDeleted();
|
||||
del->unrefWindow();
|
||||
deleteUnmanaged(this, Allowed);
|
||||
|
|
|
@ -336,6 +336,7 @@ void Workspace::init()
|
|||
NET::WM2DesktopLayout |
|
||||
NET::WM2FullPlacement |
|
||||
NET::WM2FullscreenMonitors |
|
||||
NET::WM2KDEShadow |
|
||||
0
|
||||
,
|
||||
NET::ActionMove |
|
||||
|
|
Loading…
Reference in a new issue