File indexing completed on 2024-05-12 05:46:44
0001 /* 0002 * Copyright 2011 by Aaron Seigo <aseigo@kde.org> 0003 * 0004 * This program is free software; you can redistribute it and/or modify 0005 * it under the terms of the GNU Library General Public License version 2, 0006 * or (at your option) any later version. 0007 * 0008 * This program is distributed in the hope that it will be useful, 0009 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0011 * GNU General Public License for more details 0012 * 0013 * You should have received a copy of the GNU Library General Public 0014 * License along with this program; if not, write to the 0015 * Free Software Foundation, Inc., 0016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 0017 */ 0018 0019 #include "dialogshadows_p.h" 0020 0021 #include <QWindow> 0022 #include <QPainter> 0023 #include <config-plasma.h> 0024 0025 #include <KWindowSystem> 0026 #if HAVE_X11 0027 #include <QX11Info> 0028 #include <X11/Xatom.h> 0029 #include <X11/Xlib.h> 0030 #include <X11/Xlib-xcb.h> 0031 #include <fixx11h.h> 0032 #endif 0033 0034 #if HAVE_KWAYLAND 0035 #include <KWayland/Client/connection_thread.h> 0036 #include <KWayland/Client/registry.h> 0037 #include <KWayland/Client/shadow.h> 0038 #include <KWayland/Client/shm_pool.h> 0039 #include <KWayland/Client/surface.h> 0040 #include <KWayland/Client/plasmashell.h> 0041 #endif 0042 0043 #include <qdebug.h> 0044 0045 class DialogShadows::Private 0046 { 0047 public: 0048 Private(DialogShadows *shadows) 0049 : q(shadows) 0050 #if HAVE_X11 0051 , _connection(nullptr) 0052 , _gc(0x0) 0053 , m_isX11(KWindowSystem::isPlatformX11()) 0054 #endif 0055 { 0056 setupWaylandIntegration(); 0057 } 0058 0059 ~Private() 0060 { 0061 // Do not call clearPixmaps() from here: it creates new QPixmap(), 0062 // which causes a crash when application is stopping. 0063 freeX11Pixmaps(); 0064 } 0065 0066 void freeX11Pixmaps(); 0067 void freeWaylandBuffers(); 0068 void clearPixmaps(); 0069 void setupPixmaps(); 0070 Qt::HANDLE createPixmap(const QPixmap &source); 0071 void initPixmap(const QString &element); 0072 QPixmap initEmptyPixmap(const QSize &size); 0073 void updateShadow(const QWindow *window, Plasma::FrameSvg::EnabledBorders); 0074 void updateShadowX11(const QWindow *window, Plasma::FrameSvg::EnabledBorders); 0075 void updateShadowWayland(const QWindow *window, Plasma::FrameSvg::EnabledBorders); 0076 void clearShadow(const QWindow *window); 0077 void clearShadowX11(const QWindow *window); 0078 void clearShadowWayland(const QWindow *window); 0079 void updateShadows(); 0080 void windowDestroyed(QObject *deletedObject); 0081 void setupData(Plasma::FrameSvg::EnabledBorders enabledBorders); 0082 0083 void setupWaylandIntegration(); 0084 0085 DialogShadows *q; 0086 QList<QPixmap> m_shadowPixmaps; 0087 0088 QPixmap m_emptyCornerPix; 0089 QPixmap m_emptyCornerLeftPix; 0090 QPixmap m_emptyCornerTopPix; 0091 QPixmap m_emptyCornerRightPix; 0092 QPixmap m_emptyCornerBottomPix; 0093 QPixmap m_emptyVerticalPix; 0094 QPixmap m_emptyHorizontalPix; 0095 0096 #if HAVE_X11 0097 //! xcb connection 0098 xcb_connection_t *_connection; 0099 0100 //! graphical context 0101 xcb_gcontext_t _gc; 0102 bool m_isX11; 0103 #endif 0104 0105 #if HAVE_KWAYLAND 0106 struct Wayland { 0107 KWayland::Client::ShadowManager *manager = nullptr; 0108 KWayland::Client::ShmPool *shmPool = nullptr; 0109 KWayland::Client::PlasmaShell *plasmaShell = nullptr; 0110 0111 QList<KWayland::Client::Buffer::Ptr> shadowBuffers; 0112 }; 0113 Wayland m_wayland; 0114 #endif 0115 0116 QHash<Plasma::FrameSvg::EnabledBorders, QVector<unsigned long> > data; 0117 QHash<const QWindow *, Plasma::FrameSvg::EnabledBorders> m_windows; 0118 }; 0119 0120 class DialogShadowsSingleton 0121 { 0122 public: 0123 DialogShadowsSingleton() 0124 { 0125 } 0126 0127 DialogShadows self; 0128 }; 0129 0130 Q_GLOBAL_STATIC(DialogShadowsSingleton, privateDialogShadowsSelf) 0131 0132 DialogShadows::DialogShadows(QObject *parent, const QString &prefix) 0133 : Plasma::Svg(parent), 0134 d(new Private(this)) 0135 { 0136 setImagePath(prefix); 0137 connect(this, SIGNAL(repaintNeeded()), this, SLOT(updateShadows())); 0138 } 0139 0140 DialogShadows::~DialogShadows() 0141 { 0142 delete d; 0143 } 0144 0145 DialogShadows *DialogShadows::self() 0146 { 0147 return &privateDialogShadowsSelf->self; 0148 } 0149 0150 void DialogShadows::addWindow(const QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders) 0151 { 0152 if (!window) { 0153 return; 0154 } 0155 0156 d->m_windows[window] = enabledBorders; 0157 d->updateShadow(window, enabledBorders); 0158 connect(window, SIGNAL(destroyed(QObject*)), 0159 this, SLOT(windowDestroyed(QObject*)), Qt::UniqueConnection); 0160 } 0161 0162 void DialogShadows::removeWindow(const QWindow *window) 0163 { 0164 if (!d->m_windows.contains(window)) { 0165 return; 0166 } 0167 0168 d->m_windows.remove(window); 0169 disconnect(window, nullptr, this, nullptr); 0170 d->clearShadow(window); 0171 0172 if (d->m_windows.isEmpty()) { 0173 d->clearPixmaps(); 0174 } 0175 } 0176 0177 void DialogShadows::setEnabledBorders(const QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders) 0178 { 0179 if (!window || !d->m_windows.contains(window)) { 0180 return; 0181 } 0182 0183 d->updateShadow(window, enabledBorders); 0184 } 0185 0186 0187 void DialogShadows::Private::windowDestroyed(QObject *deletedObject) 0188 { 0189 m_windows.remove(static_cast<QWindow *>(deletedObject)); 0190 0191 if (m_windows.isEmpty()) { 0192 clearPixmaps(); 0193 } 0194 } 0195 0196 void DialogShadows::Private::updateShadows() 0197 { 0198 setupPixmaps(); 0199 QHash<const QWindow *, Plasma::FrameSvg::EnabledBorders>::const_iterator i; 0200 for (i = m_windows.constBegin(); i != m_windows.constEnd(); ++i) { 0201 updateShadow(i.key(), i.value()); 0202 } 0203 } 0204 0205 Qt::HANDLE DialogShadows::Private::createPixmap(const QPixmap &source) 0206 { 0207 0208 // do nothing for invalid pixmaps 0209 if (source.isNull()) { 0210 return nullptr; 0211 } 0212 0213 /* 0214 in some cases, pixmap handle is invalid. This is the case notably 0215 when Qt uses to RasterEngine. In this case, we create an X11 Pixmap 0216 explicitly and draw the source pixmap on it. 0217 */ 0218 0219 #if HAVE_X11 0220 if (!m_isX11) { 0221 return nullptr; 0222 } 0223 0224 // check connection 0225 if (!_connection) { 0226 _connection = QX11Info::connection(); 0227 } 0228 0229 const int width(source.width()); 0230 const int height(source.height()); 0231 0232 // create X11 pixmap 0233 Pixmap pixmap = XCreatePixmap(QX11Info::display(), QX11Info::appRootWindow(), width, height, 32); 0234 0235 // check gc 0236 if (!_gc) { 0237 _gc = xcb_generate_id(_connection); 0238 xcb_create_gc(_connection, _gc, pixmap, 0, nullptr); 0239 } 0240 0241 // // create explicitly shared QPixmap from it 0242 // QPixmap dest( QPixmap::fromX11Pixmap( pixmap, QPixmap::ExplicitlyShared ) ); 0243 // 0244 // // create surface for pixmap 0245 // { 0246 // QPainter painter( &dest ); 0247 // painter.setCompositionMode( QPainter::CompositionMode_Source ); 0248 // painter.drawPixmap( 0, 0, source ); 0249 // } 0250 // 0251 // 0252 // return pixmap; 0253 QImage image(source.toImage()); 0254 xcb_put_image( 0255 _connection, XCB_IMAGE_FORMAT_Z_PIXMAP, pixmap, _gc, 0256 image.width(), image.height(), 0, 0, 0257 0, 32, 0258 image.sizeInBytes(), image.constBits()); 0259 0260 return (Qt::HANDLE)pixmap; 0261 0262 #else 0263 return nullptr; 0264 #endif 0265 0266 } 0267 0268 void DialogShadows::Private::initPixmap(const QString &element) 0269 { 0270 m_shadowPixmaps << q->pixmap(element); 0271 } 0272 0273 QPixmap DialogShadows::Private::initEmptyPixmap(const QSize &size) 0274 { 0275 #if HAVE_X11 0276 if (!m_isX11) { 0277 return QPixmap(); 0278 } 0279 QPixmap tempEmptyPix(size); 0280 if (!size.isEmpty()) { 0281 tempEmptyPix.fill(Qt::transparent); 0282 } 0283 return tempEmptyPix; 0284 #else 0285 Q_UNUSED(size) 0286 return QPixmap(); 0287 #endif 0288 } 0289 0290 void DialogShadows::Private::setupPixmaps() 0291 { 0292 clearPixmaps(); 0293 initPixmap(QStringLiteral("shadow-top")); 0294 initPixmap(QStringLiteral("shadow-topright")); 0295 initPixmap(QStringLiteral("shadow-right")); 0296 initPixmap(QStringLiteral("shadow-bottomright")); 0297 initPixmap(QStringLiteral("shadow-bottom")); 0298 initPixmap(QStringLiteral("shadow-bottomleft")); 0299 initPixmap(QStringLiteral("shadow-left")); 0300 initPixmap(QStringLiteral("shadow-topleft")); 0301 0302 m_emptyCornerPix = initEmptyPixmap(QSize(1, 1)); 0303 m_emptyCornerLeftPix = initEmptyPixmap(QSize(q->elementSize(QStringLiteral("shadow-topleft")).width(), 1)); 0304 m_emptyCornerTopPix = initEmptyPixmap(QSize(1, q->elementSize(QStringLiteral("shadow-topleft")).height())); 0305 m_emptyCornerRightPix = initEmptyPixmap(QSize(q->elementSize(QStringLiteral("shadow-bottomright")).width(), 1)); 0306 m_emptyCornerBottomPix = initEmptyPixmap(QSize(1, q->elementSize(QStringLiteral("shadow-bottomright")).height())); 0307 m_emptyVerticalPix = initEmptyPixmap(QSize(1, q->elementSize(QStringLiteral("shadow-left")).height())); 0308 m_emptyHorizontalPix = initEmptyPixmap(QSize(q->elementSize(QStringLiteral("shadow-top")).width(), 1)); 0309 0310 #if HAVE_KWAYLAND 0311 if (m_wayland.shmPool) { 0312 for (auto it = m_shadowPixmaps.constBegin(); it != m_shadowPixmaps.constEnd(); ++it) { 0313 m_wayland.shadowBuffers << m_wayland.shmPool->createBuffer(it->toImage()); 0314 } 0315 } 0316 #endif 0317 } 0318 0319 void DialogShadows::Private::setupData(Plasma::FrameSvg::EnabledBorders enabledBorders) 0320 { 0321 #if HAVE_X11 0322 if (!m_isX11) { 0323 return; 0324 } 0325 //shadow-top 0326 if (enabledBorders & Plasma::FrameSvg::TopBorder) { 0327 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_shadowPixmaps[0])); 0328 } else { 0329 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_emptyHorizontalPix)); 0330 } 0331 0332 //shadow-topright 0333 if (enabledBorders & Plasma::FrameSvg::TopBorder && 0334 enabledBorders & Plasma::FrameSvg::RightBorder) { 0335 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_shadowPixmaps[1])); 0336 } else if (enabledBorders & Plasma::FrameSvg::TopBorder) { 0337 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_emptyCornerTopPix)); 0338 } else if (enabledBorders & Plasma::FrameSvg::RightBorder) { 0339 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_emptyCornerRightPix)); 0340 } else { 0341 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_emptyCornerPix)); 0342 } 0343 0344 //shadow-right 0345 if (enabledBorders & Plasma::FrameSvg::RightBorder) { 0346 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_shadowPixmaps[2])); 0347 } else { 0348 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_emptyVerticalPix)); 0349 } 0350 0351 //shadow-bottomright 0352 if (enabledBorders & Plasma::FrameSvg::BottomBorder && 0353 enabledBorders & Plasma::FrameSvg::RightBorder) { 0354 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_shadowPixmaps[3])); 0355 } else if (enabledBorders & Plasma::FrameSvg::BottomBorder) { 0356 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_emptyCornerBottomPix)); 0357 } else if (enabledBorders & Plasma::FrameSvg::RightBorder) { 0358 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_emptyCornerRightPix)); 0359 } else { 0360 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_emptyCornerPix)); 0361 } 0362 0363 //shadow-bottom 0364 if (enabledBorders & Plasma::FrameSvg::BottomBorder) { 0365 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_shadowPixmaps[4])); 0366 } else { 0367 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_emptyHorizontalPix)); 0368 } 0369 0370 //shadow-bottomleft 0371 if (enabledBorders & Plasma::FrameSvg::BottomBorder && 0372 enabledBorders & Plasma::FrameSvg::LeftBorder) { 0373 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_shadowPixmaps[5])); 0374 } else if (enabledBorders & Plasma::FrameSvg::BottomBorder) { 0375 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_emptyCornerBottomPix)); 0376 } else if (enabledBorders & Plasma::FrameSvg::LeftBorder) { 0377 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_emptyCornerLeftPix)); 0378 } else { 0379 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_emptyCornerPix)); 0380 } 0381 0382 //shadow-left 0383 if (enabledBorders & Plasma::FrameSvg::LeftBorder) { 0384 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_shadowPixmaps[6])); 0385 } else { 0386 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_emptyVerticalPix)); 0387 } 0388 0389 //shadow-topleft 0390 if (enabledBorders & Plasma::FrameSvg::TopBorder && 0391 enabledBorders & Plasma::FrameSvg::LeftBorder) { 0392 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_shadowPixmaps[7])); 0393 } else if (enabledBorders & Plasma::FrameSvg::TopBorder) { 0394 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_emptyCornerTopPix)); 0395 } else if (enabledBorders & Plasma::FrameSvg::LeftBorder) { 0396 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_emptyCornerLeftPix)); 0397 } else { 0398 data[enabledBorders] << reinterpret_cast<unsigned long>(createPixmap(m_emptyCornerPix)); 0399 } 0400 #endif 0401 0402 int left, top, right, bottom = 0; 0403 0404 QSize marginHint; 0405 if (enabledBorders & Plasma::FrameSvg::TopBorder) { 0406 marginHint = q->elementSize(QStringLiteral("shadow-hint-top-margin")); 0407 if (marginHint.isValid()) { 0408 top = marginHint.height(); 0409 } else { 0410 top = m_shadowPixmaps[0].height(); // top 0411 } 0412 } else { 0413 top = 1; 0414 } 0415 0416 if (enabledBorders & Plasma::FrameSvg::RightBorder) { 0417 marginHint = q->elementSize(QStringLiteral("shadow-hint-right-margin")); 0418 if (marginHint.isValid()) { 0419 right = marginHint.width(); 0420 } else { 0421 right = m_shadowPixmaps[2].width(); // right 0422 } 0423 } else { 0424 right = 1; 0425 } 0426 0427 if (enabledBorders & Plasma::FrameSvg::BottomBorder) { 0428 marginHint = q->elementSize(QStringLiteral("shadow-hint-bottom-margin")); 0429 if (marginHint.isValid()) { 0430 bottom = marginHint.height(); 0431 } else { 0432 bottom = m_shadowPixmaps[4].height(); // bottom 0433 } 0434 } else { 0435 bottom = 1; 0436 } 0437 0438 if (enabledBorders & Plasma::FrameSvg::LeftBorder) { 0439 marginHint = q->elementSize(QStringLiteral("shadow-hint-left-margin")); 0440 if (marginHint.isValid()) { 0441 left = marginHint.width(); 0442 } else { 0443 left = m_shadowPixmaps[6].width(); // left 0444 } 0445 } else { 0446 left = 1; 0447 } 0448 0449 data[enabledBorders] << top << right << bottom << left; 0450 } 0451 0452 void DialogShadows::Private::freeX11Pixmaps() 0453 { 0454 #if HAVE_X11 0455 if (!m_isX11) { 0456 return; 0457 } 0458 0459 auto *display = QX11Info::display(); 0460 if (!display) { 0461 return; 0462 } 0463 0464 foreach (const QPixmap &pixmap, m_shadowPixmaps) { 0465 if (!pixmap.isNull()) { 0466 XFreePixmap(display, reinterpret_cast<unsigned long>(createPixmap(pixmap))); 0467 } 0468 } 0469 0470 if (!m_emptyCornerPix.isNull()) { 0471 XFreePixmap(display, reinterpret_cast<unsigned long>(createPixmap(m_emptyCornerPix))); 0472 } 0473 if (!m_emptyCornerBottomPix.isNull()) { 0474 XFreePixmap(display, reinterpret_cast<unsigned long>(createPixmap(m_emptyCornerBottomPix))); 0475 } 0476 if (!m_emptyCornerLeftPix.isNull()) { 0477 XFreePixmap(display, reinterpret_cast<unsigned long>(createPixmap(m_emptyCornerLeftPix))); 0478 } 0479 if (!m_emptyCornerRightPix.isNull()) { 0480 XFreePixmap(display, reinterpret_cast<unsigned long>(createPixmap(m_emptyCornerRightPix))); 0481 } 0482 if (!m_emptyCornerTopPix.isNull()) { 0483 XFreePixmap(display, reinterpret_cast<unsigned long>(createPixmap(m_emptyCornerTopPix))); 0484 } 0485 if (!m_emptyVerticalPix.isNull()) { 0486 XFreePixmap(display, reinterpret_cast<unsigned long>(createPixmap(m_emptyVerticalPix))); 0487 } 0488 if (!m_emptyHorizontalPix.isNull()) { 0489 XFreePixmap(display, reinterpret_cast<unsigned long>(createPixmap(m_emptyHorizontalPix))); 0490 } 0491 #endif 0492 } 0493 0494 void DialogShadows::Private::clearPixmaps() 0495 { 0496 #if HAVE_X11 0497 freeX11Pixmaps(); 0498 0499 m_emptyCornerPix = QPixmap(); 0500 m_emptyCornerBottomPix = QPixmap(); 0501 m_emptyCornerLeftPix = QPixmap(); 0502 m_emptyCornerRightPix = QPixmap(); 0503 m_emptyCornerTopPix = QPixmap(); 0504 m_emptyVerticalPix = QPixmap(); 0505 m_emptyHorizontalPix = QPixmap(); 0506 #endif 0507 freeWaylandBuffers(); 0508 m_shadowPixmaps.clear(); 0509 data.clear(); 0510 } 0511 0512 void DialogShadows::Private::freeWaylandBuffers() 0513 { 0514 #if HAVE_KWAYLAND 0515 m_wayland.shadowBuffers.clear(); 0516 #endif 0517 } 0518 0519 void DialogShadows::Private::updateShadow(const QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders) 0520 { 0521 #if HAVE_X11 0522 if (m_isX11) { 0523 updateShadowX11(window, enabledBorders); 0524 } 0525 #endif 0526 #if HAVE_KWAYLAND 0527 if (m_wayland.manager) { 0528 updateShadowWayland(window, enabledBorders); 0529 } 0530 #endif 0531 } 0532 0533 void DialogShadows::Private::updateShadowX11(const QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders) 0534 { 0535 #if HAVE_X11 0536 if (m_shadowPixmaps.isEmpty()) { 0537 setupPixmaps(); 0538 } 0539 0540 if (!data.contains(enabledBorders)) { 0541 setupData(enabledBorders); 0542 } 0543 0544 Display *dpy = QX11Info::display(); 0545 Atom atom = XInternAtom(dpy, "_KDE_NET_WM_SHADOW", False); 0546 0547 //qDebug() << "going to set the shadow of" << window->winId() << "to" << data; 0548 XChangeProperty(dpy, window->winId(), atom, XA_CARDINAL, 32, PropModeReplace, 0549 reinterpret_cast<const unsigned char *>(data[enabledBorders].constData()), data[enabledBorders].size()); 0550 #endif 0551 } 0552 0553 void DialogShadows::Private::updateShadowWayland(const QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders) 0554 { 0555 #if HAVE_KWAYLAND 0556 if (!m_wayland.shmPool) { 0557 return; 0558 } 0559 if (m_wayland.shadowBuffers.isEmpty()) { 0560 setupPixmaps(); 0561 } 0562 // TODO: check whether the surface already has a shadow 0563 KWayland::Client::Surface *surface = KWayland::Client::Surface::fromWindow(const_cast<QWindow*>(window)); 0564 if (!surface) { 0565 return; 0566 } 0567 auto shadow = m_wayland.manager->createShadow(surface, surface); 0568 0569 //shadow-top 0570 if (enabledBorders & Plasma::FrameSvg::TopBorder) { 0571 shadow->attachTop(m_wayland.shadowBuffers.at(0)); 0572 } 0573 0574 //shadow-topright 0575 if (enabledBorders & Plasma::FrameSvg::TopBorder && 0576 enabledBorders & Plasma::FrameSvg::RightBorder) { 0577 shadow->attachTopRight(m_wayland.shadowBuffers.at(1)); 0578 } 0579 0580 //shadow-right 0581 if (enabledBorders & Plasma::FrameSvg::RightBorder) { 0582 shadow->attachRight(m_wayland.shadowBuffers.at(2)); 0583 } 0584 0585 //shadow-bottomright 0586 if (enabledBorders & Plasma::FrameSvg::BottomBorder && 0587 enabledBorders & Plasma::FrameSvg::RightBorder) { 0588 shadow->attachBottomRight(m_wayland.shadowBuffers.at(3)); 0589 } 0590 0591 //shadow-bottom 0592 if (enabledBorders & Plasma::FrameSvg::BottomBorder) { 0593 shadow->attachBottom(m_wayland.shadowBuffers.at(4)); 0594 } 0595 0596 //shadow-bottomleft 0597 if (enabledBorders & Plasma::FrameSvg::BottomBorder && 0598 enabledBorders & Plasma::FrameSvg::LeftBorder) { 0599 shadow->attachBottomLeft(m_wayland.shadowBuffers.at(5)); 0600 } 0601 0602 //shadow-left 0603 if (enabledBorders & Plasma::FrameSvg::LeftBorder) { 0604 shadow->attachLeft(m_wayland.shadowBuffers.at(6)); 0605 } 0606 0607 //shadow-topleft 0608 if (enabledBorders & Plasma::FrameSvg::TopBorder && 0609 enabledBorders & Plasma::FrameSvg::LeftBorder) { 0610 shadow->attachTopLeft(m_wayland.shadowBuffers.at(7)); 0611 } 0612 0613 QSize marginHint; 0614 QMarginsF margins; 0615 if (enabledBorders & Plasma::FrameSvg::TopBorder) { 0616 marginHint = q->elementSize(QStringLiteral("shadow-hint-top-margin")); 0617 if (marginHint.isValid()) { 0618 margins.setTop(marginHint.height()); 0619 } else { 0620 margins.setTop(m_shadowPixmaps[0].height()); 0621 } 0622 } 0623 0624 if (enabledBorders & Plasma::FrameSvg::RightBorder) { 0625 marginHint = q->elementSize(QStringLiteral("shadow-hint-right-margin")); 0626 if (marginHint.isValid()) { 0627 margins.setRight(marginHint.width()); 0628 } else { 0629 margins.setRight(m_shadowPixmaps[2].width()); 0630 } 0631 } 0632 0633 if (enabledBorders & Plasma::FrameSvg::BottomBorder) { 0634 marginHint = q->elementSize(QStringLiteral("shadow-hint-bottom-margin")); 0635 if (marginHint.isValid()) { 0636 margins.setBottom(marginHint.height()); 0637 } else { 0638 margins.setBottom(m_shadowPixmaps[4].height()); 0639 } 0640 } 0641 0642 if (enabledBorders & Plasma::FrameSvg::LeftBorder) { 0643 marginHint = q->elementSize(QStringLiteral("shadow-hint-left-margin")); 0644 if (marginHint.isValid()) { 0645 margins.setLeft(marginHint.width()); 0646 } else { 0647 margins.setLeft(m_shadowPixmaps[6].width()); 0648 } 0649 } 0650 0651 shadow->setOffsets(margins); 0652 shadow->commit(); 0653 surface->commit(KWayland::Client::Surface::CommitFlag::None); 0654 #endif 0655 } 0656 0657 void DialogShadows::Private::clearShadow(const QWindow *window) 0658 { 0659 if (!static_cast<const QSurface*>(window)->surfaceHandle()) { 0660 qWarning() << "Cannot clear shadow from window without native surface!"; 0661 return; 0662 } 0663 #if HAVE_X11 0664 if (m_isX11) { 0665 clearShadowX11(window); 0666 } 0667 #endif 0668 #if HAVE_KWAYLAND 0669 if (m_wayland.manager) { 0670 clearShadowWayland(window); 0671 } 0672 #endif 0673 } 0674 0675 void DialogShadows::Private::clearShadowX11(const QWindow* window) 0676 { 0677 #if HAVE_X11 0678 Display *dpy = QX11Info::display(); 0679 Atom atom = XInternAtom(dpy, "_KDE_NET_WM_SHADOW", False); 0680 XDeleteProperty(dpy, window->winId(), atom); 0681 #endif 0682 } 0683 0684 void DialogShadows::Private::clearShadowWayland(const QWindow *window) 0685 { 0686 #if HAVE_KWAYLAND 0687 KWayland::Client::Surface *surface = KWayland::Client::Surface::fromWindow(const_cast<QWindow*>(window)); 0688 if (!surface) { 0689 return; 0690 } 0691 m_wayland.manager->removeShadow(surface); 0692 surface->commit(KWayland::Client::Surface::CommitFlag::None); 0693 #endif 0694 } 0695 0696 bool DialogShadows::enabled() const 0697 { 0698 return hasElement(QStringLiteral("shadow-left")); 0699 } 0700 0701 KWayland::Client::PlasmaShell *DialogShadows::waylandPlasmaShellInterface() const 0702 { 0703 #if HAVE_KWAYLAND 0704 return d->m_wayland.plasmaShell; 0705 #else 0706 return nullptr; 0707 #endif 0708 } 0709 0710 void DialogShadows::Private::setupWaylandIntegration() 0711 { 0712 #if HAVE_KWAYLAND 0713 if (!KWindowSystem::isPlatformWayland()) { 0714 return; 0715 } 0716 using namespace KWayland::Client; 0717 ConnectionThread *connection = ConnectionThread::fromApplication(q); 0718 if (!connection) { 0719 return; 0720 } 0721 Registry *registry = new Registry(q); 0722 registry->create(connection); 0723 connect(registry, &Registry::shadowAnnounced, q, 0724 [this, registry] (quint32 name, quint32 version) { 0725 m_wayland.manager = registry->createShadowManager(name, version, q); 0726 updateShadows(); 0727 }, Qt::QueuedConnection 0728 ); 0729 connect(registry, &Registry::shmAnnounced, q, 0730 [this, registry] (quint32 name, quint32 version) { 0731 m_wayland.shmPool = registry->createShmPool(name, version, q); 0732 updateShadows(); 0733 }, Qt::QueuedConnection 0734 ); 0735 connect(registry, &Registry::plasmaShellAnnounced, q, 0736 [this, registry] (quint32 name, quint32 version) { 0737 m_wayland.plasmaShell = registry->createPlasmaShell(name, version, q); 0738 } 0739 ); 0740 registry->setup(); 0741 connection->roundtrip(); 0742 #endif 0743 } 0744 0745 #include "moc_dialogshadows_p.cpp" 0746