File indexing completed on 2024-04-21 05:31:05

0001 /*
0002     SPDX-FileCopyrightText: 2020 Michail Vourlakos <mvourlakos@gmail.com>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "subconfigview.h"
0007 
0008 //local
0009 #include <config-latte.h>
0010 #include "../view.h"
0011 #include "../../lattecorona.h"
0012 #include "../../layouts/manager.h"
0013 #include "../../plasma/extended/theme.h"
0014 #include "../../settings/universalsettings.h"
0015 #include "../../shortcuts/globalshortcuts.h"
0016 #include "../../shortcuts/shortcutstracker.h"
0017 #include "../../wm/abstractwindowinterface.h"
0018 
0019 // KDE
0020 #include <KLocalizedContext>
0021 #include <KDeclarative/KDeclarative>
0022 #include <KWayland/Client/plasmashell.h>
0023 #include <KWayland/Client/surface.h>
0024 #include <KWindowSystem>
0025 
0026 namespace Latte {
0027 namespace ViewPart {
0028 
0029 SubConfigView::SubConfigView(Latte::View *view, const QString &title, const bool &isNormalWindow)
0030     : QQuickView(nullptr),
0031       m_isNormalWindow(isNormalWindow)
0032 {
0033     m_corona = qobject_cast<Latte::Corona *>(view->containment()->corona());
0034 
0035     setupWaylandIntegration();
0036 
0037     if (KWindowSystem::isPlatformX11()) {
0038         m_corona->wm()->registerIgnoredWindow(winId());
0039     } else {
0040         connect(this, &QWindow::windowTitleChanged, this, &SubConfigView::updateWaylandId);
0041         connect(m_corona->wm(), &WindowSystem::AbstractWindowInterface::latteWindowAdded, this, &SubConfigView::updateWaylandId);
0042     }
0043 
0044     m_validTitle = title;
0045     setTitle(m_validTitle);
0046 
0047     setScreen(view->screen());
0048     setIcon(qGuiApp->windowIcon());
0049 
0050     if (!m_isNormalWindow) {
0051         setFlags(wFlags());
0052         m_corona->wm()->setViewExtraFlags(this, true);
0053     }
0054 
0055     m_screenSyncTimer.setSingleShot(true);
0056     m_screenSyncTimer.setInterval(100);
0057 
0058     connections << connect(&m_screenSyncTimer, &QTimer::timeout, this, [this]() {
0059         if (!m_latteView) {
0060             return;
0061         }
0062 
0063         setScreen(m_latteView->screen());
0064 
0065         if (KWindowSystem::isPlatformX11()) {
0066             if (m_isNormalWindow) {
0067                 setFlags(wFlags());
0068                 m_corona->wm()->setViewExtraFlags(this, false, Latte::Types::NormalWindow);
0069             }
0070         }
0071 
0072         syncGeometry();
0073     });
0074 
0075     m_showTimer.setSingleShot(true);
0076     m_showTimer.setInterval(0);
0077 
0078     connections << connect(&m_showTimer, &QTimer::timeout, this, [this]() {
0079         syncSlideEffect();
0080         show();
0081     });
0082 }
0083 
0084 SubConfigView::~SubConfigView()
0085 {
0086     qDebug() << validTitle() << " deleting...";
0087 
0088     m_corona->dialogShadows()->removeWindow(this);
0089 
0090     m_corona->wm()->unregisterIgnoredWindow(KWindowSystem::isPlatformX11() ? winId() : m_waylandWindowId);
0091 
0092     for (const auto &var : connections) {
0093         QObject::disconnect(var);
0094     }
0095 
0096     for (const auto &var : viewconnections) {
0097         QObject::disconnect(var);
0098     }
0099 }
0100 
0101 void SubConfigView::init()
0102 {
0103     qDebug() << validTitle() << " : initialization started...";
0104 
0105     setDefaultAlphaBuffer(true);
0106     setColor(Qt::transparent);
0107 
0108     rootContext()->setContextProperty(QStringLiteral("viewConfig"), this);
0109     rootContext()->setContextProperty(QStringLiteral("shortcutsEngine"), m_corona->globalShortcuts()->shortcutsTracker());
0110 
0111     if (m_corona) {
0112         rootContext()->setContextProperty(QStringLiteral("universalSettings"), m_corona->universalSettings());
0113         rootContext()->setContextProperty(QStringLiteral("layoutsManager"), m_corona->layoutsManager());
0114         rootContext()->setContextProperty(QStringLiteral("themeExtended"), m_corona->themeExtended());
0115     }
0116 
0117     KDeclarative::KDeclarative kdeclarative;
0118     kdeclarative.setDeclarativeEngine(engine());
0119     kdeclarative.setTranslationDomain(QStringLiteral("latte-dock"));
0120     kdeclarative.setupContext();
0121     kdeclarative.setupEngine(engine());
0122 
0123 }
0124 
0125 Qt::WindowFlags SubConfigView::wFlags() const
0126 {
0127     return (flags() | Qt::FramelessWindowHint) & ~Qt::WindowDoesNotAcceptFocus;
0128 }
0129 
0130 QString SubConfigView::validTitle() const
0131 {
0132     return m_validTitle;
0133 }
0134 
0135 Latte::WindowSystem::WindowId SubConfigView::trackedWindowId()
0136 {
0137     if (KWindowSystem::isPlatformWayland() && m_waylandWindowId.toInt() <= 0) {
0138         updateWaylandId();
0139     }
0140 
0141     return !KWindowSystem::isPlatformWayland() ? winId() :  m_waylandWindowId;
0142 }
0143 
0144 Latte::Corona *SubConfigView::corona() const
0145 {
0146     return m_corona;
0147 }
0148 
0149 Latte::View *SubConfigView::parentView() const
0150 {
0151     return m_latteView;
0152 }
0153 
0154 void SubConfigView::setParentView(Latte::View *view, const bool &immediate)
0155 {
0156     if (m_latteView == view) {
0157         return;
0158     }
0159 
0160     initParentView(view);
0161 }
0162 
0163 void SubConfigView::initParentView(Latte::View *view)
0164 {
0165     for (const auto &var : viewconnections) {
0166         QObject::disconnect(var);
0167     }
0168 
0169     m_latteView = view;
0170 
0171     viewconnections << connect(m_latteView->positioner(), &ViewPart::Positioner::canvasGeometryChanged, this, &SubConfigView::syncGeometry);
0172 
0173     //! Assign app interfaces in be accessible through containment graphic item
0174     QQuickItem *containmentGraphicItem = qobject_cast<QQuickItem *>(m_latteView->containment()->property("_plasma_graphicObject").value<QObject *>());
0175     rootContext()->setContextProperty(QStringLiteral("plasmoid"), containmentGraphicItem);
0176     rootContext()->setContextProperty(QStringLiteral("latteView"), m_latteView);
0177 }
0178 
0179 void SubConfigView::requestActivate()
0180 {
0181     if (KWindowSystem::isPlatformWayland() && m_shellSurface) {
0182         updateWaylandId();
0183         m_corona->wm()->requestActivate(m_waylandWindowId);
0184     } else {
0185         QQuickView::requestActivate();
0186     }
0187 }
0188 
0189 void SubConfigView::showAfter(int msecs)
0190 {
0191     if (isVisible()) {
0192         return;
0193     }
0194 
0195     m_showTimer.setInterval(msecs);
0196     m_showTimer.start();
0197 
0198 }
0199 
0200 void SubConfigView::syncSlideEffect()
0201 {
0202     if (!m_latteView || !m_latteView->containment()) {
0203         return;
0204     }
0205 
0206     auto slideLocation = WindowSystem::AbstractWindowInterface::Slide::None;
0207 
0208     switch (m_latteView->containment()->location()) {
0209     case Plasma::Types::TopEdge:
0210         slideLocation = WindowSystem::AbstractWindowInterface::Slide::Top;
0211         break;
0212 
0213     case Plasma::Types::RightEdge:
0214         slideLocation = WindowSystem::AbstractWindowInterface::Slide::Right;
0215         break;
0216 
0217     case Plasma::Types::BottomEdge:
0218         slideLocation = WindowSystem::AbstractWindowInterface::Slide::Bottom;
0219         break;
0220 
0221     case Plasma::Types::LeftEdge:
0222         slideLocation = WindowSystem::AbstractWindowInterface::Slide::Left;
0223         break;
0224 
0225     default:
0226         qDebug() << staticMetaObject.className() << "wrong location";
0227         break;
0228     }
0229 
0230     m_corona->wm()->slideWindow(*this, slideLocation);
0231 }
0232 
0233 KWayland::Client::PlasmaShellSurface *SubConfigView::surface()
0234 {
0235     return m_shellSurface;
0236 }
0237 
0238 void SubConfigView::setupWaylandIntegration()
0239 {
0240     if (m_shellSurface || !KWindowSystem::isPlatformWayland() || !m_latteView || !m_latteView->containment()) {
0241         // already setup
0242         return;
0243     }
0244 
0245     if (m_corona) {
0246         using namespace KWayland::Client;
0247         PlasmaShell *interface = m_corona->waylandCoronaInterface();
0248 
0249         if (!interface) {
0250             return;
0251         }
0252 
0253         Surface *s = Surface::fromWindow(this);
0254 
0255         if (!s) {
0256             return;
0257         }
0258 
0259         qDebug() << "wayland " << title() <<  " surface was created...";
0260 
0261         m_shellSurface = interface->createSurface(s, this);
0262 
0263         if (m_isNormalWindow) {
0264             m_corona->wm()->setViewExtraFlags(m_shellSurface, false);
0265         } else {
0266             m_corona->wm()->setViewExtraFlags(m_shellSurface, true);
0267         }
0268 
0269         updateWaylandId();
0270         syncGeometry();
0271     }
0272 }
0273 
0274 void SubConfigView::showEvent(QShowEvent *ev)
0275 {
0276     QQuickView::showEvent(ev);
0277 
0278     if (m_shellSurface) {
0279         //! readd shadows after hiding because the window shadows are not shown again after first showing
0280         m_corona->dialogShadows()->addWindow(this, m_enabledBorders);
0281     }
0282 }
0283 
0284 bool SubConfigView::event(QEvent *e)
0285 {
0286     if (e->type() == QEvent::PlatformSurface) {
0287         if (auto pe = dynamic_cast<QPlatformSurfaceEvent *>(e)) {
0288             switch (pe->surfaceEventType()) {
0289             case QPlatformSurfaceEvent::SurfaceCreated:
0290 
0291                 if (m_shellSurface) {
0292                     break;
0293                 }
0294 
0295                 setupWaylandIntegration();
0296                 break;
0297 
0298             case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed:
0299                 if (m_shellSurface) {
0300                     delete m_shellSurface;
0301                     m_shellSurface = nullptr;
0302                     qDebug() << "WAYLAND " << title() <<  " window surface was deleted...";
0303                 }
0304 
0305                 break;
0306             }
0307         }
0308     }
0309 
0310     return QQuickView::event(e);
0311 }
0312 
0313 void SubConfigView::updateWaylandId()
0314 {
0315     Latte::WindowSystem::WindowId newId = m_corona->wm()->winIdFor("latte-dock", validTitle());
0316 
0317     if (m_waylandWindowId != newId) {
0318         if (!m_waylandWindowId.isNull()) {
0319             m_corona->wm()->unregisterIgnoredWindow(m_waylandWindowId);
0320         }
0321 
0322         m_waylandWindowId = newId;
0323         m_corona->wm()->registerIgnoredWindow(m_waylandWindowId);
0324     }
0325 }
0326 
0327 Plasma::FrameSvg::EnabledBorders SubConfigView::enabledBorders() const
0328 {
0329     return m_enabledBorders;
0330 }
0331 
0332 }
0333 }