File indexing completed on 2024-04-21 16:17:21

0001 /*
0002 *  Copyright 2016  Smith AR <audoban@openmailbox.org>
0003 *                  Michail Vourlakos <mvourlakos@gmail.com>
0004 *
0005 *  This file is part of Latte-Dock
0006 *
0007 *  Latte-Dock is free software; you can redistribute it and/or
0008 *  modify it under the terms of the GNU General Public License as
0009 *  published by the Free Software Foundation; either version 2 of
0010 *  the License, or (at your option) any later version.
0011 *
0012 *  Latte-Dock is distributed in the hope that it will be useful,
0013 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0014 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015 *  GNU General Public License for more details.
0016 *
0017 *  You should have received a copy of the GNU General Public License
0018 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0019 */
0020 
0021 #include "waylandinterface.h"
0022 
0023 // local
0024 #include "view/screenedgeghostwindow.h"
0025 #include "view/view.h"
0026 #include "../lattecorona.h"
0027 #include "../liblatte2/extras.h"
0028 
0029 // Qt
0030 #include <QDebug>
0031 #include <QTimer>
0032 #include <QApplication>
0033 #include <QtX11Extras/QX11Info>
0034 #include <QRasterWindow>
0035 
0036 // KDE
0037 #include <KWindowSystem>
0038 #include <KWindowInfo>
0039 #include <KWayland/Client/surface.h>
0040 
0041 #if KF5_VERSION_MINOR >= 52
0042 #include <KWayland/Client/plasmavirtualdesktop.h>
0043 #endif
0044 
0045 // X11
0046 #include <NETWM>
0047 
0048 using namespace KWayland::Client;
0049 
0050 namespace Latte {
0051 
0052 class Private::GhostWindow : public QRasterWindow
0053 {
0054     Q_OBJECT
0055 
0056 public:
0057     WindowSystem::WindowId m_winId;
0058 
0059     GhostWindow(WindowSystem::WaylandInterface *waylandInterface)
0060         : m_waylandInterface(waylandInterface) {
0061         setFlags(Qt::FramelessWindowHint
0062                  | Qt::WindowStaysOnTopHint
0063                  | Qt::NoDropShadowWindowHint
0064                  | Qt::WindowDoesNotAcceptFocus);
0065 
0066         connect(m_waylandInterface, &WindowSystem::AbstractWindowInterface::latteWindowAdded, this, &GhostWindow::identifyWinId);
0067 
0068         setupWaylandIntegration();
0069         show();
0070     }
0071 
0072     ~GhostWindow() {
0073         m_waylandInterface->unregisterIgnoredWindow(m_winId);
0074         delete m_shellSurface;
0075     }
0076 
0077     void setGeometry(const QRect &rect) {
0078         if (geometry() == rect) {
0079             return;
0080         }
0081 
0082         m_validGeometry = rect;
0083 
0084         setMinimumSize(rect.size());
0085         setMaximumSize(rect.size());
0086         resize(rect.size());
0087 
0088         m_shellSurface->setPosition(rect.topLeft());
0089     }
0090 
0091     void setupWaylandIntegration() {
0092         using namespace KWayland::Client;
0093 
0094         if (m_shellSurface)
0095             return;
0096 
0097         Surface *s{Surface::fromWindow(this)};
0098 
0099         if (!s)
0100             return;
0101 
0102         m_shellSurface = m_waylandInterface->waylandCoronaInterface()->createSurface(s, this);
0103         qDebug() << "wayland ghost window surface was created...";
0104 
0105         m_shellSurface->setSkipTaskbar(true);
0106         m_shellSurface->setPanelTakesFocus(false);
0107         m_shellSurface->setRole(PlasmaShellSurface::Role::Panel);
0108         m_shellSurface->setPanelBehavior(PlasmaShellSurface::PanelBehavior::AlwaysVisible);
0109     }
0110 
0111     KWayland::Client::PlasmaShellSurface *m_shellSurface{nullptr};
0112     WindowSystem::WaylandInterface *m_waylandInterface{nullptr};
0113 
0114     //! geometry() function under wayland does not return nice results
0115     QRect m_validGeometry;
0116 
0117 public slots:
0118     void identifyWinId() {
0119         if (m_winId.isNull()) {
0120             m_winId = m_waylandInterface->winIdFor("latte-dock", m_validGeometry);
0121             m_waylandInterface->registerIgnoredWindow(m_winId);
0122         }
0123     }
0124 };
0125 
0126 namespace WindowSystem {
0127 
0128 WaylandInterface::WaylandInterface(QObject *parent)
0129     : AbstractWindowInterface(parent)
0130 {
0131     m_corona = qobject_cast<Latte::Corona *>(parent);
0132 }
0133 
0134 WaylandInterface::~WaylandInterface()
0135 {
0136 }
0137 
0138 void WaylandInterface::init()
0139 {
0140 }
0141 
0142 void WaylandInterface::initWindowManagement(KWayland::Client::PlasmaWindowManagement *windowManagement)
0143 {
0144     if (m_windowManagement == windowManagement) {
0145         return;
0146     }
0147 
0148     m_windowManagement = windowManagement;
0149 
0150     connect(m_windowManagement, &PlasmaWindowManagement::windowCreated, this, &WaylandInterface::windowCreatedProxy);
0151     connect(m_windowManagement, &PlasmaWindowManagement::activeWindowChanged, this, [&]() noexcept {
0152                 auto w = m_windowManagement->activeWindow();
0153                 if (!w || (w && (!m_ignoredWindows.contains(w->internalId() && !isPlasmaDesktop(w)))) ) {
0154                     emit activeWindowChanged(w ? w->internalId() : 0);
0155                 }
0156 
0157             }, Qt::QueuedConnection);
0158 }
0159 
0160 #if KF5_VERSION_MINOR >= 52
0161 void WaylandInterface::initVirtualDesktopManagement(KWayland::Client::PlasmaVirtualDesktopManagement *virtualDesktopManagement)
0162 {
0163     if (m_virtualDesktopManagement == virtualDesktopManagement) {
0164         return;
0165     }
0166 
0167     m_virtualDesktopManagement = virtualDesktopManagement;
0168 
0169     connect(m_virtualDesktopManagement, &KWayland::Client::PlasmaVirtualDesktopManagement::desktopCreated, this,
0170             [this](const QString &id, quint32 position) {
0171         addDesktop(id, position);
0172     });
0173 
0174     connect(m_virtualDesktopManagement, &KWayland::Client::PlasmaVirtualDesktopManagement::desktopRemoved, this,
0175             [this](const QString &id) {
0176         m_desktops.removeAll(id);
0177 
0178         if (m_currentDesktop == id) {
0179             setCurrentDesktop(QString());
0180         }
0181     });
0182 }
0183 
0184 void WaylandInterface::addDesktop(const QString &id, quint32 position)
0185 {
0186     if (m_desktops.contains(id)) {
0187         return;
0188     }
0189 
0190     m_desktops.append(id);
0191 
0192     const KWayland::Client::PlasmaVirtualDesktop *desktop = m_virtualDesktopManagement->getVirtualDesktop(id);
0193 
0194     QObject::connect(desktop, &KWayland::Client::PlasmaVirtualDesktop::activated, this,
0195                      [desktop, this]() {
0196         setCurrentDesktop(desktop->id());
0197     }
0198     );
0199 
0200     if (desktop->isActive()) {
0201         setCurrentDesktop(id);
0202     }
0203 }
0204 
0205 void WaylandInterface::setCurrentDesktop(QString desktop)
0206 {
0207     if (m_currentDesktop == desktop) {
0208         return;
0209     }
0210 
0211     m_currentDesktop = desktop;
0212     emit currentDesktopChanged();
0213 }
0214 #endif
0215 
0216 KWayland::Client::PlasmaShell *WaylandInterface::waylandCoronaInterface() const
0217 {
0218     return m_corona->waylandCoronaInterface();
0219 }
0220 
0221 //! Register Latte Ignored Windows in order to NOT be tracked
0222 void WaylandInterface::registerIgnoredWindow(WindowId wid)
0223 {
0224     if (!wid.isNull() && !m_ignoredWindows.contains(wid)) {
0225         m_ignoredWindows.append(wid);
0226 
0227         KWayland::Client::PlasmaWindow *w = windowFor(wid);
0228 
0229         if (w) {
0230             untrackWindow(w);
0231         }
0232 
0233         emit windowChanged(wid);
0234     }
0235 }
0236 
0237 void WaylandInterface::unregisterIgnoredWindow(WindowId wid)
0238 {
0239     if (m_ignoredWindows.contains(wid)) {
0240         m_ignoredWindows.removeAll(wid);
0241         emit windowRemoved(wid);
0242     }
0243 }
0244 
0245 void WaylandInterface::setViewExtraFlags(QWindow &view)
0246 {
0247     Q_UNUSED(view)
0248 }
0249 
0250 void WaylandInterface::setViewStruts(QWindow &view, const QRect &rect, Plasma::Types::Location location)
0251 {
0252     if (!m_ghostWindows.contains(view.winId())) {
0253         m_ghostWindows[view.winId()] = new Private::GhostWindow(this);
0254     }
0255 
0256     auto w = m_ghostWindows[view.winId()];
0257 
0258     switch (location) {
0259     case Plasma::Types::TopEdge:
0260     case Plasma::Types::BottomEdge:
0261         w->setGeometry({rect.x() + rect.width() / 2, rect.y(), 1, rect.height()});
0262         break;
0263 
0264     case Plasma::Types::LeftEdge:
0265     case Plasma::Types::RightEdge:
0266         w->setGeometry({rect.x(), rect.y() + rect.height() / 2, rect.width(), 1});
0267         break;
0268 
0269     default:
0270         break;
0271     }
0272 }
0273 
0274 void WaylandInterface::switchToNextVirtualDesktop() const
0275 {
0276 #if KF5_VERSION_MINOR >= 52
0277     if (!m_virtualDesktopManagement || m_desktops.count() <= 1) {
0278         return;
0279     }
0280 
0281     int curPos = m_desktops.indexOf(m_currentDesktop);
0282     int nextPos = curPos + 1;
0283 
0284     if (curPos == m_desktops.count()-1) {
0285         nextPos = 0;
0286     }
0287 
0288     KWayland::Client::PlasmaVirtualDesktop *desktopObj = m_virtualDesktopManagement->getVirtualDesktop(m_desktops[nextPos]);
0289 
0290     if (desktopObj) {
0291         desktopObj->requestActivate();
0292     }
0293 #endif
0294 }
0295 
0296 void WaylandInterface::switchToPreviousVirtualDesktop() const
0297 {
0298 #if KF5_VERSION_MINOR >= 52
0299     if (!m_virtualDesktopManagement || m_desktops.count() <= 1) {
0300         return;
0301     }
0302 
0303     int curPos = m_desktops.indexOf(m_currentDesktop);
0304     int nextPos = curPos - 1;
0305 
0306     if (curPos == 0) {
0307         nextPos = m_desktops.count()-1;
0308     }
0309 
0310     KWayland::Client::PlasmaVirtualDesktop *desktopObj = m_virtualDesktopManagement->getVirtualDesktop(m_desktops[nextPos]);
0311 
0312     if (desktopObj) {
0313         desktopObj->requestActivate();
0314     }
0315 #endif
0316 }
0317 
0318 void WaylandInterface::setWindowOnActivities(QWindow &window, const QStringList &activities)
0319 {
0320     //! needs to updated to wayland case
0321     // KWindowSystem::setOnActivities(view.winId(), activities);
0322 }
0323 
0324 void WaylandInterface::removeViewStruts(QWindow &view) const
0325 {
0326     delete m_ghostWindows.take(view.winId());
0327 }
0328 
0329 WindowId WaylandInterface::activeWindow() const
0330 {
0331     if (!m_windowManagement) {
0332         return 0;
0333     }
0334 
0335     auto wid = m_windowManagement->activeWindow();
0336 
0337     return wid ? wid->internalId() : 0;
0338 }
0339 
0340 void WaylandInterface::setKeepAbove(const QDialog &dialog, bool above) const
0341 {
0342     if (above) {
0343         KWindowSystem::setState(dialog.winId(), NET::KeepAbove);
0344     } else {
0345         KWindowSystem::clearState(dialog.winId(), NET::KeepAbove);
0346     }
0347 }
0348 
0349 void WaylandInterface::skipTaskBar(const QDialog &dialog) const
0350 {
0351     KWindowSystem::setState(dialog.winId(), NET::SkipTaskbar);
0352 }
0353 
0354 void WaylandInterface::slideWindow(QWindow &view, AbstractWindowInterface::Slide location) const
0355 {
0356     auto slideLocation = KWindowEffects::NoEdge;
0357 
0358     switch (location) {
0359     case Slide::Top:
0360         slideLocation = KWindowEffects::TopEdge;
0361         break;
0362 
0363     case Slide::Bottom:
0364         slideLocation = KWindowEffects::BottomEdge;
0365         break;
0366 
0367     case Slide::Left:
0368         slideLocation = KWindowEffects::LeftEdge;
0369         break;
0370 
0371     case Slide::Right:
0372         slideLocation = KWindowEffects::RightEdge;
0373         break;
0374 
0375     default:
0376         break;
0377     }
0378 
0379     KWindowEffects::slideWindow(view.winId(), slideLocation, -1);
0380 }
0381 
0382 void WaylandInterface::enableBlurBehind(QWindow &view) const
0383 {
0384     KWindowEffects::enableBlurBehind(view.winId());
0385 }
0386 
0387 void WaylandInterface::setActiveEdge(QWindow *view, bool active) const
0388 {
0389     ViewPart::ScreenEdgeGhostWindow *window = qobject_cast<ViewPart::ScreenEdgeGhostWindow *>(view);
0390 
0391     if (!window) {
0392         return;
0393     }
0394 
0395     if (window->parentView()->surface() && window->parentView()->visibility()
0396             && (window->parentView()->visibility()->mode() == Types::DodgeActive
0397                 || window->parentView()->visibility()->mode() == Types::DodgeMaximized
0398                 || window->parentView()->visibility()->mode() == Types::DodgeAllWindows
0399                 || window->parentView()->visibility()->mode() == Types::AutoHide)) {
0400         if (active) {
0401             window->showWithMask();
0402             window->surface()->requestHideAutoHidingPanel();
0403         } else {
0404             window->hideWithMask();
0405             window->surface()->requestShowAutoHidingPanel();
0406         }
0407     }
0408 }
0409 
0410 WindowInfoWrap WaylandInterface::requestInfoActive() const
0411 {
0412     if (!m_windowManagement) {
0413         return {};
0414     }
0415 
0416     auto w = m_windowManagement->activeWindow();
0417 
0418     if (!w) return {};
0419 
0420     return requestInfo(w->internalId());
0421 }
0422 
0423 WindowInfoWrap WaylandInterface::requestInfo(WindowId wid) const
0424 {
0425     WindowInfoWrap winfoWrap;
0426 
0427     auto w = windowFor(wid);
0428 
0429     if (w) {
0430         if (isPlasmaDesktop(w)) {
0431             winfoWrap.setIsValid(true);
0432             winfoWrap.setIsPlasmaDesktop(true);
0433             winfoWrap.setWid(wid);
0434 
0435             //! Window Abilities
0436             winfoWrap.setIsClosable(false);
0437             winfoWrap.setIsFullScreenable(false);
0438             winfoWrap.setIsGroupable(false);
0439             winfoWrap.setIsMaximizable(false);
0440             winfoWrap.setIsMinimizable(false);
0441             winfoWrap.setIsMovable(false);
0442             winfoWrap.setIsResizable(false);
0443             winfoWrap.setIsShadeable(false);
0444             winfoWrap.setIsVirtualDesktopsChangeable(false);
0445             //! Window Abilities
0446 
0447         } else if (isValidWindow(w)) {
0448             winfoWrap.setIsValid(true);
0449             winfoWrap.setWid(wid);
0450             winfoWrap.setParentId(w->parentWindow() ? w->parentWindow()->internalId() : 0);
0451             winfoWrap.setIsActive(w->isActive());
0452             winfoWrap.setIsMinimized(w->isMinimized());
0453             winfoWrap.setIsMaxVert(w->isMaximized());
0454             winfoWrap.setIsMaxHoriz(w->isMaximized());
0455             winfoWrap.setIsFullscreen(w->isFullscreen());
0456             winfoWrap.setIsShaded(w->isShaded());
0457             winfoWrap.setIsOnAllDesktops(w->isOnAllDesktops());
0458             winfoWrap.setIsOnAllActivities(true);
0459             winfoWrap.setGeometry(w->geometry());
0460             winfoWrap.setHasSkipTaskbar(w->skipTaskbar());
0461 
0462             //! Window Abilities
0463             winfoWrap.setIsClosable(w->isCloseable());
0464             winfoWrap.setIsFullScreenable(w->isFullscreenable());
0465             winfoWrap.setIsMaximizable(w->isMaximizeable());
0466             winfoWrap.setIsMinimizable(w->isMinimizeable());
0467             winfoWrap.setIsMovable(w->isMovable());
0468             winfoWrap.setIsResizable(w->isResizable());
0469             winfoWrap.setIsShadeable(w->isShadeable());
0470             winfoWrap.setIsVirtualDesktopsChangeable(w->isVirtualDesktopChangeable());
0471             //! Window Abilities
0472 
0473             winfoWrap.setDisplay(w->title());
0474 #if KF5_VERSION_MINOR >= 52
0475             winfoWrap.setDesktops(w->plasmaVirtualDesktops());
0476 #endif
0477             winfoWrap.setActivities(QStringList());
0478         }
0479     } else {
0480         winfoWrap.setIsValid(false);
0481     }
0482 
0483     return winfoWrap;
0484 }
0485 
0486 AppData WaylandInterface::appDataFor(WindowId wid) const
0487 {
0488     auto window = windowFor(wid);
0489 
0490     if (window) {
0491         const AppData &data = appDataFromUrl(windowUrlFromMetadata(window->appId(),
0492                                                                    window->pid(), rulesConfig));
0493 
0494         return data;
0495     }
0496 
0497     AppData empty;
0498 
0499     return empty;
0500 }
0501 
0502 KWayland::Client::PlasmaWindow *WaylandInterface::windowFor(WindowId wid) const
0503 {
0504     auto it = std::find_if(m_windowManagement->windows().constBegin(), m_windowManagement->windows().constEnd(), [&wid](PlasmaWindow * w) noexcept {
0505             return w->isValid() && w->internalId() == wid;
0506 });
0507 
0508     if (it == m_windowManagement->windows().constEnd()) {
0509         return nullptr;
0510     }
0511 
0512     return *it;
0513 }
0514 
0515 QIcon WaylandInterface::iconFor(WindowId wid) const
0516 {
0517     auto window = windowFor(wid);
0518 
0519     if (window) {
0520         return window->icon();
0521     }
0522 
0523 
0524     return QIcon();
0525 }
0526 
0527 WindowId WaylandInterface::winIdFor(QString appId, QRect geometry) const
0528 {
0529     auto it = std::find_if(m_windowManagement->windows().constBegin(), m_windowManagement->windows().constEnd(), [&appId, &geometry](PlasmaWindow * w) noexcept {
0530         return w->isValid() && w->appId() == appId && w->geometry() == geometry;
0531     });
0532 
0533     if (it == m_windowManagement->windows().constEnd()) {
0534         return QVariant();
0535     }
0536 
0537     return (*it)->internalId();
0538 }
0539 
0540 
0541 bool WaylandInterface::windowCanBeDragged(WindowId wid) const
0542 {
0543     auto w = windowFor(wid);
0544 
0545     if (w && isValidWindow(w)) {
0546         WindowInfoWrap winfo = requestInfo(wid);
0547         return (winfo.isValid()
0548                 && w->isMovable()
0549                 && !winfo.isMinimized()
0550                 && inCurrentDesktopActivity(winfo)
0551                 && !winfo.isPlasmaDesktop());
0552     }
0553 
0554     return false;
0555 }
0556 
0557 bool WaylandInterface::windowCanBeMaximized(WindowId wid) const
0558 {
0559     auto w = windowFor(wid);
0560 
0561     if (w && isValidWindow(w)) {
0562         WindowInfoWrap winfo = requestInfo(wid);
0563         return (winfo.isValid()
0564                 && w->isMaximizeable()
0565                 && !winfo.isMinimized()
0566                 && inCurrentDesktopActivity(winfo)
0567                 && !winfo.isPlasmaDesktop());
0568     }
0569 
0570     return false;
0571 }
0572 
0573 void WaylandInterface::requestActivate(WindowId wid) const
0574 {
0575     auto w = windowFor(wid);
0576 
0577     if (w) {
0578         w->requestActivate();
0579     }
0580 }
0581 
0582 void WaylandInterface::requestClose(WindowId wid) const
0583 {
0584     auto w = windowFor(wid);
0585 
0586     if (w) {
0587         w->requestClose();
0588     }
0589 }
0590 
0591 
0592 void WaylandInterface::requestMoveWindow(WindowId wid, QPoint from) const
0593 {
0594     WindowInfoWrap wInfo = requestInfo(wid);
0595 
0596     if (windowCanBeDragged(wid) && inCurrentDesktopActivity(wInfo)) {
0597         auto w = windowFor(wid);
0598 
0599         if (w && isValidWindow(w)) {
0600             w->requestMove();
0601         }
0602     }
0603 }
0604 
0605 void WaylandInterface::requestToggleIsOnAllDesktops(WindowId wid) const
0606 {
0607 #if KF5_VERSION_MINOR >= 52
0608     auto w = windowFor(wid);
0609 
0610     if (w && isValidWindow(w) && m_desktops.count() > 1) {
0611         if (w->isOnAllDesktops()) {
0612             w->requestEnterVirtualDesktop(m_currentDesktop);
0613         } else {
0614             const QStringList &now = w->plasmaVirtualDesktops();
0615 
0616             foreach (const QString &desktop, now) {
0617                 w->requestLeaveVirtualDesktop(desktop);
0618             }
0619         }
0620     }
0621 #endif
0622 }
0623 
0624 void WaylandInterface::requestToggleKeepAbove(WindowId wid) const
0625 {
0626     auto w = windowFor(wid);
0627 
0628     if (w) {
0629         w->requestToggleKeepAbove();
0630     }
0631 }
0632 
0633 void WaylandInterface::requestToggleMinimized(WindowId wid) const
0634 {
0635     auto w = windowFor(wid);
0636     WindowInfoWrap wInfo = requestInfo(wid);
0637 
0638     if (w && isValidWindow(w) && inCurrentDesktopActivity(wInfo)) {
0639 #if KF5_VERSION_MINOR >= 52
0640         if (!m_currentDesktop.isEmpty()) {
0641             w->requestEnterVirtualDesktop(m_currentDesktop);
0642         }
0643 #endif
0644         w->requestToggleMinimized();
0645     }
0646 }
0647 
0648 void WaylandInterface::requestToggleMaximized(WindowId wid) const
0649 {
0650     auto w = windowFor(wid);
0651     WindowInfoWrap wInfo = requestInfo(wid);
0652 
0653     if (w && isValidWindow(w) && windowCanBeMaximized(wid) && inCurrentDesktopActivity(wInfo)) {
0654 #if KF5_VERSION_MINOR >= 52
0655         if (!m_currentDesktop.isEmpty()) {
0656             w->requestEnterVirtualDesktop(m_currentDesktop);
0657         }
0658 #endif
0659         w->requestToggleMaximized();
0660     }
0661 }
0662 
0663 bool WaylandInterface::isPlasmaDesktop(const KWayland::Client::PlasmaWindow *w) const
0664 {
0665     if (!w || (w->appId() != QLatin1String("org.kde.plasmashell"))) {
0666         return false;
0667     }
0668 
0669     return AbstractWindowInterface::isPlasmaDesktop(w->geometry());
0670 }
0671 
0672 bool WaylandInterface::isPlasmaPanel(const KWayland::Client::PlasmaWindow *w) const
0673 {
0674     if (!w || (w->appId() != QLatin1String("org.kde.plasmashell"))) {
0675         return false;
0676     }
0677 
0678     return AbstractWindowInterface::isPlasmaPanel(w->geometry());
0679 }
0680 
0681 bool WaylandInterface::isValidWindow(const KWayland::Client::PlasmaWindow *w) const
0682 {
0683     //! DEPRECATED comment is case we must reenable this
0684     //! because wayland does not have any way yet to identify the window type
0685     //! a trick is to just consider windows as valid when they can be shown in the
0686     //! taskbar. Of course that creates issues with plasma native dialogs
0687     //! e.g. widgets explorer, Activities etc. that are not used to hide
0688     //! the dodge views appropriately
0689 
0690     bool hasSkipTaskbar = w->skipTaskbar();
0691     bool isSkipped = hasSkipTaskbar;
0692 
0693 #if KF5_VERSION_MINOR >= 47
0694     bool hasSkipSwitcher = w->skipSwitcher();
0695     isSkipped = hasSkipTaskbar && hasSkipSwitcher;
0696 #endif
0697 
0698     return w->isValid() && !isPlasmaDesktop(w) && !isSkipped && !m_plasmaPanels.contains(w->internalId()) && !m_ignoredWindows.contains(w->internalId());
0699 }
0700 
0701 void WaylandInterface::updateWindow()
0702 {
0703     PlasmaWindow *pW = qobject_cast<PlasmaWindow*>(QObject::sender());
0704 
0705     if (pW && !m_ignoredWindows.contains(pW->internalId() && !isPlasmaDesktop(pW) )) {
0706         if (pW->appId() == QLatin1String("org.kde.plasmashell")) {
0707             if (isPlasmaDesktop(pW)) {
0708                 return;
0709             } else if (isPlasmaPanel(pW)) {
0710                 registerIgnoredWindow(pW->internalId());
0711             }
0712         }
0713 
0714         considerWindowChanged(pW->internalId());
0715     }
0716 }
0717 
0718 void WaylandInterface::windowUnmapped()
0719 {
0720     PlasmaWindow *pW = qobject_cast<PlasmaWindow*>(QObject::sender());
0721 
0722     if (pW) {
0723         untrackWindow(pW);
0724         emit windowRemoved(pW->internalId());
0725     }
0726 }
0727 
0728 void WaylandInterface::trackWindow(KWayland::Client::PlasmaWindow *w)
0729 {
0730     if (!w) {
0731         return;
0732     }
0733 
0734     connect(w, &PlasmaWindow::activeChanged, this, &WaylandInterface::updateWindow);
0735     connect(w, &PlasmaWindow::titleChanged, this, &WaylandInterface::updateWindow);
0736     connect(w, &PlasmaWindow::fullscreenChanged, this, &WaylandInterface::updateWindow);
0737     connect(w, &PlasmaWindow::geometryChanged, this, &WaylandInterface::updateWindow);
0738     connect(w, &PlasmaWindow::maximizedChanged, this, &WaylandInterface::updateWindow);
0739     connect(w, &PlasmaWindow::minimizedChanged, this, &WaylandInterface::updateWindow);
0740     connect(w, &PlasmaWindow::shadedChanged, this, &WaylandInterface::updateWindow);
0741     connect(w, &PlasmaWindow::skipTaskbarChanged, this, &WaylandInterface::updateWindow);
0742     connect(w, &PlasmaWindow::onAllDesktopsChanged, this, &WaylandInterface::updateWindow);
0743     connect(w, &PlasmaWindow::parentWindowChanged, this, &WaylandInterface::updateWindow);
0744 
0745 #if KF5_VERSION_MINOR >= 52
0746     connect(w, &PlasmaWindow::plasmaVirtualDesktopEntered, this, &WaylandInterface::updateWindow);
0747     connect(w, &PlasmaWindow::plasmaVirtualDesktopLeft, this, &WaylandInterface::updateWindow);
0748 #else
0749     connect(w, &PlasmaWindow::virtualDesktopChanged, this, &WaylandInterface::updateWindow);
0750 #endif
0751 
0752     connect(w, &PlasmaWindow::unmapped, this, &WaylandInterface::windowUnmapped);
0753 }
0754 
0755 void WaylandInterface::untrackWindow(KWayland::Client::PlasmaWindow *w)
0756 {
0757     if (!w) {
0758         return;
0759     }
0760 
0761     disconnect(w, &PlasmaWindow::activeChanged, this, &WaylandInterface::updateWindow);
0762     disconnect(w, &PlasmaWindow::titleChanged, this, &WaylandInterface::updateWindow);
0763     disconnect(w, &PlasmaWindow::fullscreenChanged, this, &WaylandInterface::updateWindow);
0764     disconnect(w, &PlasmaWindow::geometryChanged, this, &WaylandInterface::updateWindow);
0765     disconnect(w, &PlasmaWindow::maximizedChanged, this, &WaylandInterface::updateWindow);
0766     disconnect(w, &PlasmaWindow::minimizedChanged, this, &WaylandInterface::updateWindow);
0767     disconnect(w, &PlasmaWindow::shadedChanged, this, &WaylandInterface::updateWindow);
0768     disconnect(w, &PlasmaWindow::skipTaskbarChanged, this, &WaylandInterface::updateWindow);
0769     disconnect(w, &PlasmaWindow::onAllDesktopsChanged, this, &WaylandInterface::updateWindow);
0770     disconnect(w, &PlasmaWindow::parentWindowChanged, this, &WaylandInterface::updateWindow);
0771 
0772 #if KF5_VERSION_MINOR >= 52
0773     disconnect(w, &PlasmaWindow::plasmaVirtualDesktopEntered, this, &WaylandInterface::updateWindow);
0774     disconnect(w, &PlasmaWindow::plasmaVirtualDesktopLeft, this, &WaylandInterface::updateWindow);
0775 #else
0776     disconnect(w, &PlasmaWindow::virtualDesktopChanged, this, &WaylandInterface::updateWindow);
0777 #endif
0778 
0779     disconnect(w, &PlasmaWindow::unmapped, this, &WaylandInterface::windowUnmapped);
0780 }
0781 
0782 
0783 void WaylandInterface::windowCreatedProxy(KWayland::Client::PlasmaWindow *w)
0784 {
0785     if (!isValidWindow(w)) {
0786         return;
0787     }
0788 
0789     if ((w->appId() == QLatin1String("org.kde.plasmashell")) && isPlasmaPanel(w)) {
0790         registerPlasmaPanel(w->internalId());
0791     } else {
0792         trackWindow(w);
0793         emit windowAdded(w->internalId());
0794     }
0795 
0796     if (w->appId() == "latte-dock") {
0797         emit latteWindowAdded();
0798     }
0799 }
0800 
0801 }
0802 }
0803 
0804 #include "waylandinterface.moc"