Warning, file /plasma/oxygen/kstyle/oxygenmdiwindowshadow.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 ////////////////////////////////////////////////////////////////////////////// 0002 // oxygenmdiwindowshadow.cpp 0003 // handle MDI windows' shadows 0004 // ------------------- 0005 // 0006 // SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr> 0007 // 0008 // Largely inspired from skulpture widget style 0009 // SPDX-FileCopyrightText: 2007-2009 Christoph Feck <christoph@maxiom.de> 0010 // 0011 // SPDX-License-Identifier: MIT 0012 ////////////////////////////////////////////////////////////////////////////// 0013 0014 #include "oxygenmdiwindowshadow.h" 0015 #include "oxygenshadowcache.h" 0016 0017 #include <QMdiArea> 0018 #include <QMdiSubWindow> 0019 #include <QPainter> 0020 #include <QTextStream> 0021 0022 namespace Oxygen 0023 { 0024 0025 //____________________________________________________________________ 0026 MdiWindowShadow::MdiWindowShadow(QWidget *parent, TileSet shadowTiles) 0027 : QWidget(parent) 0028 , _shadowTiles(shadowTiles) 0029 { 0030 setAttribute(Qt::WA_OpaquePaintEvent, false); 0031 setAttribute(Qt::WA_TransparentForMouseEvents, true); 0032 setFocusPolicy(Qt::NoFocus); 0033 } 0034 0035 //____________________________________________________________________ 0036 void MdiWindowShadow::updateGeometry(void) 0037 { 0038 if (!_widget) 0039 return; 0040 0041 // get tileSet rect 0042 auto hole = _widget->frameGeometry().adjusted(1, 1, -1, -1); 0043 _shadowTilesRect = _widget->frameGeometry().adjusted(-ShadowSize, -ShadowSize, ShadowSize, ShadowSize); 0044 0045 // get parent MDI area's viewport 0046 auto parent(parentWidget()); 0047 if (parent && !qobject_cast<QMdiArea *>(parent) && qobject_cast<QMdiArea *>(parent->parentWidget())) { 0048 parent = parent->parentWidget(); 0049 } 0050 0051 if (qobject_cast<QAbstractScrollArea *>(parent)) { 0052 parent = qobject_cast<QAbstractScrollArea *>(parent)->viewport(); 0053 } 0054 0055 // set geometry 0056 QRect geometry(_shadowTilesRect); 0057 if (parent) { 0058 geometry &= parent->rect(); 0059 hole &= parent->rect(); 0060 } 0061 0062 // update geometry and mask 0063 const QRegion mask = QRegion(geometry) - hole; 0064 if (mask.isEmpty()) 0065 hide(); 0066 else { 0067 setGeometry(geometry); 0068 setMask(mask.translated(-geometry.topLeft())); 0069 show(); 0070 } 0071 0072 // translate rendering rect 0073 _shadowTilesRect.translate(-geometry.topLeft()); 0074 } 0075 0076 //____________________________________________________________________ 0077 void MdiWindowShadow::updateZOrder(void) 0078 { 0079 stackUnder(_widget); 0080 } 0081 0082 //____________________________________________________________________ 0083 void MdiWindowShadow::paintEvent(QPaintEvent *event) 0084 { 0085 if (!_shadowTiles.isValid()) 0086 return; 0087 0088 QPainter painter(this); 0089 painter.setRenderHints(QPainter::Antialiasing); 0090 painter.setClipRegion(event->region()); 0091 _shadowTiles.render(_shadowTilesRect, &painter); 0092 } 0093 0094 //____________________________________________________________________ 0095 MdiWindowShadowFactory::MdiWindowShadowFactory(QObject *parent, StyleHelper &helper) 0096 : QObject(parent) 0097 { 0098 // create shadow cache 0099 ShadowCache cache(helper); 0100 cache.setShadowSize(QPalette::Inactive, MdiWindowShadow::ShadowSize); 0101 cache.setShadowSize(QPalette::Active, MdiWindowShadow::ShadowSize); 0102 0103 // get tileset 0104 _shadowTiles = cache.tileSet(ShadowCache::Key()); 0105 } 0106 0107 //____________________________________________________________________________________ 0108 bool MdiWindowShadowFactory::registerWidget(QWidget *widget) 0109 { 0110 // check widget type 0111 auto subwindow(qobject_cast<QMdiSubWindow *>(widget)); 0112 if (!subwindow) 0113 return false; 0114 if (subwindow->widget() && subwindow->widget()->inherits("KMainWindow")) 0115 return false; 0116 0117 // make sure widget is not already registered 0118 if (isRegistered(widget)) 0119 return false; 0120 0121 // store in set 0122 _registeredWidgets.insert(widget); 0123 0124 // create shadow immediatly if widget is already visible 0125 if (widget->isVisible()) { 0126 installShadow(widget); 0127 updateShadowGeometry(widget); 0128 updateShadowZOrder(widget); 0129 } 0130 0131 widget->installEventFilter(this); 0132 0133 // catch object destruction 0134 connect(widget, SIGNAL(destroyed(QObject *)), SLOT(widgetDestroyed(QObject *))); 0135 0136 return true; 0137 } 0138 0139 //____________________________________________________________________________________ 0140 void MdiWindowShadowFactory::unregisterWidget(QWidget *widget) 0141 { 0142 if (!isRegistered(widget)) 0143 return; 0144 widget->removeEventFilter(this); 0145 _registeredWidgets.remove(widget); 0146 removeShadow(widget); 0147 } 0148 0149 //____________________________________________________________________________________ 0150 bool MdiWindowShadowFactory::eventFilter(QObject *object, QEvent *event) 0151 { 0152 switch (event->type()) { 0153 // TODO: possibly implement ZOrderChange event, to make sure that 0154 // the shadow is always painted on top 0155 case QEvent::ZOrderChange: 0156 updateShadowZOrder(object); 0157 break; 0158 0159 case QEvent::Destroy: 0160 if (isRegistered(object)) { 0161 _registeredWidgets.remove(object); 0162 removeShadow(object); 0163 } 0164 break; 0165 0166 case QEvent::Hide: 0167 hideShadows(object); 0168 break; 0169 0170 case QEvent::Show: 0171 installShadow(object); 0172 updateShadowGeometry(object); 0173 updateShadowZOrder(object); 0174 break; 0175 0176 case QEvent::Move: 0177 case QEvent::Resize: 0178 updateShadowGeometry(object); 0179 break; 0180 0181 default: 0182 break; 0183 } 0184 0185 return QObject::eventFilter(object, event); 0186 } 0187 0188 //____________________________________________________________________________________ 0189 MdiWindowShadow *MdiWindowShadowFactory::findShadow(QObject *object) const 0190 { 0191 // check object, 0192 if (!object->parent()) 0193 return nullptr; 0194 0195 // find existing window shadows 0196 const auto children = object->parent()->children(); 0197 for (QObject *child : children) { 0198 if (MdiWindowShadow *shadow = qobject_cast<MdiWindowShadow *>(child)) { 0199 if (shadow->widget() == object) 0200 return shadow; 0201 } 0202 } 0203 0204 return nullptr; 0205 } 0206 0207 //____________________________________________________________________________________ 0208 void MdiWindowShadowFactory::installShadow(QObject *object) 0209 { 0210 // cast 0211 auto widget(static_cast<QWidget *>(object)); 0212 if (!widget->parentWidget()) 0213 return; 0214 0215 // make sure shadow is not already installed 0216 if (findShadow(object)) 0217 return; 0218 0219 // create new shadow 0220 auto windowShadow(new MdiWindowShadow(widget->parentWidget(), _shadowTiles)); 0221 windowShadow->setWidget(widget); 0222 return; 0223 } 0224 0225 //____________________________________________________________________________________ 0226 void MdiWindowShadowFactory::removeShadow(QObject *object) 0227 { 0228 if (MdiWindowShadow *windowShadow = findShadow(object)) { 0229 windowShadow->hide(); 0230 windowShadow->deleteLater(); 0231 } 0232 } 0233 0234 //____________________________________________________________________________________ 0235 void MdiWindowShadowFactory::widgetDestroyed(QObject *object) 0236 { 0237 _registeredWidgets.remove(object); 0238 } 0239 }