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