kde-workspace/libs/plasmagenericshell/panelshadows.cpp
2014-11-13 19:30:51 +02:00

238 lines
5.9 KiB
C++

/*
* Copyright 2011 by Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2,
* 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 Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "panelshadows.h"
#include <QWidget>
#include <QPainter>
#ifdef Q_WS_X11
#include <QX11Info>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <fixx11h.h>
#endif
#include <KDebug>
class PanelShadows::Private
{
public:
Private(PanelShadows *shadows)
: q(shadows),
m_managePixmaps(false),
top(0),
right(0),
bottom(0),
left(0)
{
}
~Private()
{
clearPixmaps();
}
void clearPixmaps();
void setupPixmaps();
void initPixmap(const QString &element);
void updateShadow(const QWidget *window);
void clearShadow(const QWidget *window);
void updateShadows();
void windowDestroyed(QObject *deletedObject);
PanelShadows *q;
QList<QPixmap> m_shadowPixmaps;
QVector<unsigned long> data;
QSet<const QWidget *> m_windows;
bool m_managePixmaps;
int top;
int right;
int bottom;
int left;
};
PanelShadows::PanelShadows(QObject *parent)
: Plasma::Svg(parent),
d(new Private(this))
{
setImagePath("widgets/panel-background");
connect(this, SIGNAL(repaintNeeded()), this, SLOT(updateShadows()));
}
void PanelShadows::addWindow(const QWidget *window)
{
if (!window || !window->isWindow()) {
return;
}
d->m_windows << window;
d->updateShadow(window);
connect(window, SIGNAL(destroyed(QObject*)), this, SLOT(windowDestroyed(QObject*)));
}
void PanelShadows::removeWindow(const QWidget *window)
{
if (!d->m_windows.contains(window)) {
return;
}
d->m_windows.remove(window);
disconnect(window, 0, this, 0);
d->clearShadow(window);
if (d->m_windows.isEmpty()) {
d->clearPixmaps();
}
}
void PanelShadows::Private::windowDestroyed(QObject *deletedObject)
{
m_windows.remove(static_cast<QWidget *>(deletedObject));
if (m_windows.isEmpty()) {
clearPixmaps();
}
}
void PanelShadows::Private::updateShadows()
{
setupPixmaps();
foreach (const QWidget *window, m_windows) {
updateShadow(window);
}
}
void PanelShadows::Private::initPixmap(const QString &element)
{
#ifdef Q_WS_X11
QPixmap pix = q->pixmap(element);
if (!pix.isNull() && pix.handle() == 0) {
Pixmap xPix = XCreatePixmap(QX11Info::display(), QX11Info::appRootWindow(), pix.width(), pix.height(), 32);
QPixmap tempPix = QPixmap::fromX11Pixmap(xPix, QPixmap::ExplicitlyShared);
tempPix.fill(Qt::transparent);
QPainter p(&tempPix);
p.drawPixmap(QPoint(0, 0), pix);
m_shadowPixmaps << tempPix;
m_managePixmaps = true;
} else {
m_shadowPixmaps << pix;
}
#endif
}
void PanelShadows::Private::setupPixmaps()
{
clearPixmaps();
initPixmap("shadow-top");
initPixmap("shadow-topright");
initPixmap("shadow-right");
initPixmap("shadow-bottomright");
initPixmap("shadow-bottom");
initPixmap("shadow-bottomleft");
initPixmap("shadow-left");
initPixmap("shadow-topleft");
#ifdef Q_WS_X11
foreach (const QPixmap &pixmap, m_shadowPixmaps) {
data << pixmap.handle();
}
#endif
QSize marginHint = q->elementSize("shadow-hint-top-margin");
kDebug() << "top margin hint is:" << marginHint;
if (marginHint.isValid()) {
top = marginHint.height();
} else {
top = m_shadowPixmaps[0].height(); // top
}
marginHint = q->elementSize("shadow-hint-right-margin");
kDebug() << "right margin hint is:" << marginHint;
if (marginHint.isValid()) {
right = marginHint.width();
} else {
right = m_shadowPixmaps[2].width(); // right
}
marginHint = q->elementSize("shadow-hint-bottom-margin");
if (marginHint.isValid()) {
bottom = marginHint.height();
} else {
bottom = m_shadowPixmaps[4].height(); // bottom
}
marginHint = q->elementSize("shadow-hint-left-margin");
if (marginHint.isValid()) {
left = marginHint.width();
} else {
left = m_shadowPixmaps[6].width(); // left
}
data << top << right << bottom << left;
}
void PanelShadows::getMargins(int &top, int &right, int &bottom, int &left)
{
top = d->top;
right = d->right;
bottom = d->bottom;
left = d->left;
}
void PanelShadows::Private::clearPixmaps()
{
#ifdef Q_WS_X11
if (m_managePixmaps) {
foreach (const QPixmap &pixmap, m_shadowPixmaps) {
XFreePixmap(QX11Info::display(), pixmap.handle());
}
m_managePixmaps = false;
}
#endif
m_shadowPixmaps.clear();
data.clear();
}
void PanelShadows::Private::updateShadow(const QWidget *window)
{
#ifdef Q_WS_X11
if (data.isEmpty()) {
setupPixmaps();
}
Display *dpy = QX11Info::display();
Atom atom = XInternAtom(dpy, "_KDE_NET_WM_SHADOW", False);
//kDebug() << "going to set the shadow of" << winId() << "to" << data;
XChangeProperty(dpy, window->winId(), atom, XA_CARDINAL, 32, PropModeReplace,
reinterpret_cast<const unsigned char *>(data.constData()), data.size());
#endif
}
void PanelShadows::Private::clearShadow(const QWidget *window)
{
#ifdef Q_WS_X11
Display *dpy = QX11Info::display();
Atom atom = XInternAtom(dpy, "_KDE_NET_WM_SHADOW", False);
XDeleteProperty(dpy, window->winId(), atom);
#endif
}
#include "panelshadows.moc"