File indexing completed on 2025-03-16 11:22:51
0001 /* 0002 SPDX-FileCopyrightText: 2020 Michail Vourlakos <mvourlakos@gmail.com> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "subwindow.h" 0007 0008 // local 0009 #include "../view.h" 0010 #include "../visibilitymanager.h" 0011 0012 // Qt 0013 #include <QDebug> 0014 #include <QSurfaceFormat> 0015 #include <QQuickView> 0016 #include <QTimer> 0017 0018 // KDE 0019 #include <KWayland/Client/plasmashell.h> 0020 #include <KWayland/Client/surface.h> 0021 #include <KWindowSystem> 0022 0023 // X11 0024 #include <NETWM> 0025 0026 namespace Latte { 0027 namespace ViewPart { 0028 0029 SubWindow::SubWindow(Latte::View *view, QString debugType) : 0030 m_latteView(view) 0031 { 0032 m_corona = qobject_cast<Latte::Corona *>(view->corona()); 0033 0034 m_debugMode = (qApp->arguments().contains("-d") && qApp->arguments().contains("--kwinedges")); 0035 m_debugType = debugType; 0036 0037 m_showColor = QColor(Qt::transparent); 0038 m_hideColor = QColor(Qt::transparent); 0039 0040 setTitle(validTitle()); 0041 setColor(m_showColor); 0042 setDefaultAlphaBuffer(true); 0043 0044 setFlags(Qt::FramelessWindowHint 0045 | Qt::WindowStaysOnTopHint 0046 | Qt::NoDropShadowWindowHint 0047 | Qt::WindowDoesNotAcceptFocus); 0048 0049 m_fixGeometryTimer.setSingleShot(true); 0050 m_fixGeometryTimer.setInterval(500); 0051 connect(&m_fixGeometryTimer, &QTimer::timeout, this, &SubWindow::fixGeometry); 0052 0053 connect(this, &QQuickView::xChanged, this, &SubWindow::startGeometryTimer); 0054 connect(this, &QQuickView::yChanged, this, &SubWindow::startGeometryTimer); 0055 connect(this, &QQuickView::widthChanged, this, &SubWindow::startGeometryTimer); 0056 connect(this, &QQuickView::heightChanged, this, &SubWindow::startGeometryTimer); 0057 0058 connect(this, &SubWindow::calculatedGeometryChanged, this, &SubWindow::fixGeometry); 0059 0060 connect(m_latteView, &Latte::View::absoluteGeometryChanged, this, &SubWindow::updateGeometry); 0061 connect(m_latteView, &Latte::View::screenGeometryChanged, this, &SubWindow::updateGeometry); 0062 connect(m_latteView, &Latte::View::locationChanged, this, &SubWindow::updateGeometry); 0063 connect(m_latteView, &QQuickView::screenChanged, this, [this]() { 0064 setScreen(m_latteView->screen()); 0065 updateGeometry(); 0066 }); 0067 0068 if (!KWindowSystem::isPlatformWayland()) { 0069 //! IMPORTANT!!! ::: This fixes a bug when closing an Activity all views from all Activities are 0070 //! disappearing! With this code parts they reappear!!! 0071 m_visibleHackTimer1.setInterval(400); 0072 m_visibleHackTimer2.setInterval(2500); 0073 m_visibleHackTimer1.setSingleShot(true); 0074 m_visibleHackTimer2.setSingleShot(true); 0075 0076 connectionsHack << connect(this, &QWindow::visibleChanged, this, [&]() { 0077 if (!m_inDelete && m_latteView && m_latteView->layout() && !isVisible()) { 0078 m_visibleHackTimer1.start(); 0079 m_visibleHackTimer2.start(); 0080 } else if (!m_inDelete) { 0081 //! For some reason when the window is hidden in the edge under X11 afterwards 0082 //! is losing its window flags 0083 m_corona->wm()->setViewExtraFlags(this); 0084 } 0085 }); 0086 0087 connectionsHack << connect(&m_visibleHackTimer1, &QTimer::timeout, this, [&]() { 0088 if (!m_inDelete && m_latteView && m_latteView->layout() && !isVisible()) { 0089 show(); 0090 emit forcedShown(); 0091 //qDebug() << m_debugType + ":: Enforce reshow from timer 1..."; 0092 } else { 0093 //qDebug() << m_debugType + ":: No needed reshow from timer 1..."; 0094 } 0095 }); 0096 0097 connectionsHack << connect(&m_visibleHackTimer2, &QTimer::timeout, this, [&]() { 0098 if (!m_inDelete && m_latteView && m_latteView->layout() && !isVisible()) { 0099 show(); 0100 emit forcedShown(); 0101 //qDebug() << m_debugType + ":: Enforce reshow from timer 2..."; 0102 } else { 0103 //qDebug() << m_debugType + ":: No needed reshow from timer 2..."; 0104 } 0105 }); 0106 0107 connectionsHack << connect(this, &SubWindow::forcedShown, this, [&]() { 0108 m_corona->wm()->unregisterIgnoredWindow(m_trackedWindowId); 0109 m_trackedWindowId = winId(); 0110 m_corona->wm()->registerIgnoredWindow(m_trackedWindowId); 0111 }); 0112 } 0113 0114 setupWaylandIntegration(); 0115 0116 if (KWindowSystem::isPlatformX11()) { 0117 m_trackedWindowId = winId(); 0118 m_corona->wm()->registerIgnoredWindow(m_trackedWindowId); 0119 } else { 0120 connect(m_corona->wm(), &WindowSystem::AbstractWindowInterface::latteWindowAdded, this, &SubWindow::updateWaylandId); 0121 } 0122 0123 setScreen(m_latteView->screen()); 0124 show(); 0125 hideWithMask(); 0126 } 0127 0128 SubWindow::~SubWindow() 0129 { 0130 m_inDelete = true; 0131 0132 m_corona->wm()->unregisterIgnoredWindow(KWindowSystem::isPlatformX11() ? winId() : m_trackedWindowId); 0133 0134 m_latteView = nullptr; 0135 0136 // clear mode 0137 m_visibleHackTimer1.stop(); 0138 m_visibleHackTimer2.stop(); 0139 for (auto &c : connectionsHack) { 0140 disconnect(c); 0141 } 0142 0143 if (m_shellSurface) { 0144 delete m_shellSurface; 0145 } 0146 } 0147 0148 int SubWindow::location() 0149 { 0150 return (int)m_latteView->location(); 0151 } 0152 0153 int SubWindow::thickness() const 0154 { 0155 return m_thickness; 0156 } 0157 0158 QString SubWindow::validTitlePrefix() const 0159 { 0160 return QString("#subwindow#"); 0161 } 0162 0163 QString SubWindow::validTitle() const 0164 { 0165 return QString(validTitlePrefix() + QString::number(m_latteView->containment()->id())); 0166 } 0167 0168 Latte::View *SubWindow::parentView() 0169 { 0170 return m_latteView; 0171 } 0172 0173 Latte::WindowSystem::WindowId SubWindow::trackedWindowId() 0174 { 0175 if (KWindowSystem::isPlatformWayland() && m_trackedWindowId.toInt() <= 0) { 0176 updateWaylandId(); 0177 } 0178 0179 return m_trackedWindowId; 0180 } 0181 0182 KWayland::Client::PlasmaShellSurface *SubWindow::surface() 0183 { 0184 return m_shellSurface; 0185 } 0186 0187 void SubWindow::fixGeometry() 0188 { 0189 if (!m_calculatedGeometry.isEmpty() 0190 && (m_calculatedGeometry.x() != x() || m_calculatedGeometry.y() != y() 0191 || m_calculatedGeometry.width() != width() || m_calculatedGeometry.height() != height())) { 0192 setMinimumSize(m_calculatedGeometry.size()); 0193 setMaximumSize(m_calculatedGeometry.size()); 0194 resize(m_calculatedGeometry.size()); 0195 setPosition(m_calculatedGeometry.x(), m_calculatedGeometry.y()); 0196 0197 if (m_shellSurface) { 0198 m_shellSurface->setPosition(m_calculatedGeometry.topLeft()); 0199 } 0200 } 0201 } 0202 0203 void SubWindow::updateWaylandId() 0204 { 0205 Latte::WindowSystem::WindowId newId = m_corona->wm()->winIdFor("latte-dock", validTitle()); 0206 0207 if (m_trackedWindowId != newId) { 0208 if (!m_trackedWindowId.isNull()) { 0209 m_corona->wm()->unregisterIgnoredWindow(m_trackedWindowId); 0210 } 0211 0212 m_trackedWindowId = newId; 0213 m_corona->wm()->registerIgnoredWindow(m_trackedWindowId); 0214 } 0215 } 0216 0217 void SubWindow::startGeometryTimer() 0218 { 0219 m_fixGeometryTimer.start(); 0220 } 0221 0222 void SubWindow::setupWaylandIntegration() 0223 { 0224 if (m_shellSurface || !KWindowSystem::isPlatformWayland() || !m_latteView || !m_latteView->containment()) { 0225 // already setup 0226 return; 0227 } 0228 0229 if (m_corona) { 0230 using namespace KWayland::Client; 0231 0232 PlasmaShell *interface = m_corona->waylandCoronaInterface(); 0233 0234 if (!interface) { 0235 return; 0236 } 0237 0238 Surface *s = Surface::fromWindow(this); 0239 0240 if (!s) { 0241 return; 0242 } 0243 0244 qDebug() << "wayland screen edge ghost window surface was created..."; 0245 m_shellSurface = interface->createSurface(s, this); 0246 m_corona->wm()->setViewExtraFlags(m_shellSurface); 0247 0248 m_shellSurface->setPanelTakesFocus(false); 0249 } 0250 } 0251 0252 bool SubWindow::event(QEvent *e) 0253 { 0254 if (e->type() == QEvent::Show) { 0255 m_corona->wm()->setViewExtraFlags(this); 0256 } 0257 0258 return QQuickView::event(e); 0259 } 0260 0261 0262 void SubWindow::hideWithMask() 0263 { 0264 if (m_debugMode) { 0265 qDebug() << m_debugType + " :: MASK HIDE..."; 0266 } 0267 0268 setMask(VisibilityManager::ISHIDDENMASK); 0269 0270 //! repaint in order to update mask immediately 0271 setColor(m_hideColor); 0272 } 0273 0274 void SubWindow::showWithMask() 0275 { 0276 if (m_debugMode) { 0277 qDebug() << m_debugType + " :: MASK SHOW..."; 0278 } 0279 0280 setMask(QRegion()); 0281 0282 //! repaint in order to update mask immediately 0283 setColor(m_showColor); 0284 } 0285 0286 } 0287 }