diff --git a/CMakeLists.txt b/CMakeLists.txt index 982c5902b..674550d87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,6 +133,7 @@ set(plasma_LIB_SRCS private/dataengineconsumer.cpp private/dataengineservice.cpp private/denyallauthorization.cpp + private/dialogshadows.cpp private/effectwatcher.cpp private/extenderapplet.cpp private/extenderitemmimedata.cpp diff --git a/dialog.cpp b/dialog.cpp index a8ee8ba5b..03d0361d8 100644 --- a/dialog.cpp +++ b/dialog.cpp @@ -51,6 +51,7 @@ #include "plasma/corona.h" #include "plasma/extenders/extender.h" #include "plasma/private/extender_p.h" +#include "plasma/private/dialogshadows_p.h" #include "plasma/framesvg.h" #include "plasma/theme.h" #include "plasma/widgets/scrollwidget.h" @@ -99,6 +100,7 @@ void DialogPrivate::themeChanged() // WA_NoSystemBackground is going to fail combined with sliding popups, but is needed // when we aren't compositing q->setAttribute(Qt::WA_NoSystemBackground, !translucency); + WindowEffects::overrideShadow(q->winId(), !DialogShadows::self()->hasElement("shadow-left")); updateMask(); q->update(); } @@ -241,6 +243,7 @@ void DialogPrivate::checkBorders(bool updateMaskIfNeeded) } background->setEnabledBorders(borders); + DialogShadows::self()->addWindow(q, borders); if (extender) { FrameSvg::EnabledBorders disabledBorders = FrameSvg::NoBorder; @@ -397,7 +400,7 @@ Dialog::Dialog(QWidget *parent, Qt::WindowFlags f) QPalette pal = palette(); pal.setColor(backgroundRole(), Qt::transparent); setPalette(pal); - WindowEffects::overrideShadow(winId(), true); + WindowEffects::overrideShadow(winId(), !DialogShadows::self()->hasElement("shadow-left")); d->adjustViewTimer = new QTimer(this); d->adjustViewTimer->setSingleShot(true); @@ -726,7 +729,8 @@ void Dialog::showEvent(QShowEvent * event) } emit dialogVisible(true); - WindowEffects::overrideShadow(winId(), true); + // WindowEffects::overrideShadow(winId(), true); + DialogShadows::self()->addWindow(this, d->background->enabledBorders()); } void Dialog::focusInEvent(QFocusEvent *event) diff --git a/private/dialogshadows.cpp b/private/dialogshadows.cpp new file mode 100644 index 000000000..25ad6ae07 --- /dev/null +++ b/private/dialogshadows.cpp @@ -0,0 +1,343 @@ +/* +* Copyright 2011 by Aaron Seigo +* +* 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 "dialogshadows_p.h" + +#include +#include + +#ifdef Q_WS_X11 +#include +#include +#include +#include +#endif + +#include +#include + +class DialogShadows::Private +{ +public: + Private(DialogShadows *shadows) + : q(shadows), + m_managePixmaps(false) + { + } + + ~Private() + { + clearPixmaps(); + } + + void clearPixmaps(); + void setupPixmaps(); + void initPixmap(const QString &element); + void updateShadow(const QWidget *window, Plasma::FrameSvg::EnabledBorders); + void clearShadow(const QWidget *window); + void updateShadows(); + void windowDestroyed(QObject *deletedObject); + void setupData(Plasma::FrameSvg::EnabledBorders enabledBorders); + + DialogShadows *q; + QList m_shadowPixmaps; + QList m_emptyShadowPixmaps; + QHash > data; + QHash m_windows; + bool m_managePixmaps; +}; + +class DialogShadowsSingleton +{ +public: + DialogShadowsSingleton() + { + } + + DialogShadows self; +}; + +K_GLOBAL_STATIC(DialogShadowsSingleton, privateDialogShadowsSelf) + +DialogShadows::DialogShadows(QObject *parent) + : Plasma::Svg(parent), + d(new Private(this)) +{ + setImagePath("dialogs/background"); + connect(this, SIGNAL(repaintNeeded()), this, SLOT(updateShadows())); +} + +DialogShadows *DialogShadows::self() +{ + return &privateDialogShadowsSelf->self; +} + +void DialogShadows::addWindow(const QWidget *window, Plasma::FrameSvg::EnabledBorders enabledBorders) +{ + if (!window || !window->isWindow()) { + return; + } + + d->m_windows[window] = enabledBorders; + d->updateShadow(window, enabledBorders); + connect(window, SIGNAL(destroyed(QObject*)), + this, SLOT(windowDestroyed(QObject*)), Qt::UniqueConnection); +} + +void DialogShadows::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 DialogShadows::Private::windowDestroyed(QObject *deletedObject) +{ + m_windows.remove(static_cast(deletedObject)); + + if (m_windows.isEmpty()) { + clearPixmaps(); + } +} + +void DialogShadows::Private::updateShadows() +{ + setupPixmaps(); + QHash::const_iterator i; + for (i = m_windows.constBegin(); i != m_windows.constEnd(); ++i) { + updateShadow(i.key(), i.value()); + } +} + +void DialogShadows::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; + + //make an empty pixmap for when the border is sisabled + QSize size = q->elementSize(element); + xPix = XCreatePixmap(QX11Info::display(), QX11Info::appRootWindow(), size.width(), size.height(), 32); + tempPix = QPixmap::fromX11Pixmap(xPix, QPixmap::ExplicitlyShared); + tempPix.fill(Qt::transparent); + m_emptyShadowPixmaps << tempPix; + } else { + m_shadowPixmaps << pix; + m_emptyShadowPixmaps << pix; + } +#endif +} + +void DialogShadows::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"); +} + + +void DialogShadows::Private::setupData(Plasma::FrameSvg::EnabledBorders enabledBorders) +{ +#ifdef Q_WS_X11 + /*foreach (const QPixmap &pixmap, m_shadowPixmaps) { + data[enabledBorders] << pixmap.handle(); + }*/ + + //shadow-top + if (enabledBorders & Plasma::FrameSvg::TopBorder) { + data[enabledBorders] << m_shadowPixmaps[0].handle(); + } else { + data[enabledBorders] << m_emptyShadowPixmaps[0].handle(); + } + + //shadow-topright + if (enabledBorders & Plasma::FrameSvg::TopBorder && + enabledBorders & Plasma::FrameSvg::RightBorder) { + data[enabledBorders] << m_shadowPixmaps[1].handle(); + } else { + data[enabledBorders] << m_emptyShadowPixmaps[1].handle(); + } + + //shadow-right + if (enabledBorders & Plasma::FrameSvg::RightBorder) { + data[enabledBorders] << m_shadowPixmaps[2].handle(); + } else { + data[enabledBorders] << m_emptyShadowPixmaps[2].handle(); + } + + //shadow-bottomright + if (enabledBorders & Plasma::FrameSvg::BottomBorder && + enabledBorders & Plasma::FrameSvg::RightBorder) { + data[enabledBorders] << m_shadowPixmaps[3].handle(); + } else { + data[enabledBorders] << m_emptyShadowPixmaps[3].handle(); + } + + //shadow-bottom + if (enabledBorders & Plasma::FrameSvg::BottomBorder) { + data[enabledBorders] << m_shadowPixmaps[4].handle(); + } else { + data[enabledBorders] << m_emptyShadowPixmaps[4].handle(); + } + + //shadow-bottomleft + if (enabledBorders & Plasma::FrameSvg::BottomBorder && + enabledBorders & Plasma::FrameSvg::LeftBorder) { + data[enabledBorders] << m_shadowPixmaps[5].handle(); + } else { + data[enabledBorders] << m_emptyShadowPixmaps[5].handle(); + } + + //shadow-left + if (enabledBorders & Plasma::FrameSvg::LeftBorder) { + data[enabledBorders] << m_shadowPixmaps[6].handle(); + } else { + data[enabledBorders] << m_emptyShadowPixmaps[6].handle(); + } + + //shadow-topleft + if (enabledBorders & Plasma::FrameSvg::TopBorder && + enabledBorders & Plasma::FrameSvg::LeftBorder) { + data[enabledBorders] << m_shadowPixmaps[7].handle(); + } else { + data[enabledBorders] << m_emptyShadowPixmaps[7].handle(); + } +#endif + + int left, top, right, bottom = 0; + + QSize marginHint; + if (enabledBorders & Plasma::FrameSvg::TopBorder) { + 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 + } + } else { + top = m_shadowPixmaps[7].height(); // topleft + } + + if (enabledBorders & Plasma::FrameSvg::RightBorder) { + 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 + } + } else { + right = m_shadowPixmaps[1].width(); // topright + } + + if (enabledBorders & Plasma::FrameSvg::BottomBorder) { + marginHint = q->elementSize("shadow-hint-bottom-margin"); + if (marginHint.isValid()) { + bottom = marginHint.height(); + } else { + bottom = m_shadowPixmaps[4].height(); // bottom + } + } else { + bottom = m_shadowPixmaps[5].height(); // bottomleft + } + + if (enabledBorders & Plasma::FrameSvg::LeftBorder) { + marginHint = q->elementSize("shadow-hint-left-margin"); + if (marginHint.isValid()) { + left = marginHint.width(); + } else { + left = m_shadowPixmaps[6].width(); // left + } + } else { + left = m_shadowPixmaps[7].width(); // topleft + } + + data[enabledBorders] << top << right << bottom << left; +} + +void DialogShadows::Private::clearPixmaps() +{ +#ifdef Q_WS_X11 + if (m_managePixmaps) { + foreach (const QPixmap &pixmap, m_shadowPixmaps) { + XFreePixmap(QX11Info::display(), pixmap.handle()); + } + foreach (const QPixmap &pixmap, m_emptyShadowPixmaps) { + XFreePixmap(QX11Info::display(), pixmap.handle()); + } + m_managePixmaps = false; + } +#endif + m_shadowPixmaps.clear(); + m_emptyShadowPixmaps.clear(); + data.clear(); +} + +void DialogShadows::Private::updateShadow(const QWidget *window, Plasma::FrameSvg::EnabledBorders enabledBorders) +{ +#ifdef Q_WS_X11 + if (m_shadowPixmaps.size() == 0) { + setupPixmaps(); + } + + if (!data.contains(enabledBorders)) { + setupData(enabledBorders); + } + + 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(data[enabledBorders].constData()), data[enabledBorders].size()); +#endif +} + +void DialogShadows::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 "dialogshadows_p.moc" + diff --git a/private/dialogshadows_p.h b/private/dialogshadows_p.h new file mode 100644 index 000000000..3225c1041 --- /dev/null +++ b/private/dialogshadows_p.h @@ -0,0 +1,51 @@ +/* +* Copyright 2011 by Aaron Seigo +* +* 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. +*/ + +#ifndef PLASMA_DIALOGSHADOWS_H +#define PLASMA_DIALOGSHADOWS_H + +#include + +#include "plasma/framesvg.h" +#include "plasma/svg.h" + + +class DialogShadows : public Plasma::Svg +{ + Q_OBJECT + +public: + explicit DialogShadows(QObject *parent = 0); + + static DialogShadows *self(); + + void addWindow(const QWidget *window, Plasma::FrameSvg::EnabledBorders enabledBorders = Plasma::FrameSvg::AllBorders); + void removeWindow(const QWidget *window); + +private Q_SLOTS: + +private: + class Private; + Private * const d; + + Q_PRIVATE_SLOT(d, void updateShadows()) + Q_PRIVATE_SLOT(d, void windowDestroyed(QObject *deletedObject)) +}; + +#endif + diff --git a/private/tooltip.cpp b/private/tooltip.cpp index 299fcc1da..e1068eed9 100644 --- a/private/tooltip.cpp +++ b/private/tooltip.cpp @@ -20,6 +20,7 @@ #include "tooltip_p.h" #include "windowpreview_p.h" +#include "dialogshadows_p.h" #include #include @@ -196,6 +197,9 @@ ToolTip::ToolTip(QWidget *parent) mainLayout->addLayout(iconTextHBoxLayout); setLayout(mainLayout); + DialogShadows *shadow = new DialogShadows(this); + shadow->setImagePath("widgets/tooltip"); + shadow->addWindow(this); } ToolTip::~ToolTip()