diff --git a/app/dock/screenedgeghostwindow.cpp b/app/dock/screenedgeghostwindow.cpp index 3e744f99..6dad72d8 100644 --- a/app/dock/screenedgeghostwindow.cpp +++ b/app/dock/screenedgeghostwindow.cpp @@ -1,224 +1,235 @@ /* * Copyright 2018 Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "screenedgeghostwindow.h" #include "../dockcorona.h" #include "dockview.h" #include #include #include +#include #include #include #include #include namespace Latte { ScreenEdgeGhostWindow::ScreenEdgeGhostWindow(DockView *view) : m_dockView(view) { setColor(QColor(Qt::transparent)); setDefaultAlphaBuffer(true); setFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::NoDropShadowWindowHint | Qt::WindowDoesNotAcceptFocus); - connect(this, &QQuickView::xChanged, this, &ScreenEdgeGhostWindow::fixGeometry); - connect(this, &QQuickView::yChanged, this, &ScreenEdgeGhostWindow::fixGeometry); - connect(this, &QQuickView::widthChanged, this, &ScreenEdgeGhostWindow::fixGeometry); - connect(this, &QQuickView::heightChanged, this, &ScreenEdgeGhostWindow::fixGeometry); + m_fixGeometryTimer.setSingleShot(true); + m_fixGeometryTimer.setInterval(500); + connect(&m_fixGeometryTimer, &QTimer::timeout, this, &ScreenEdgeGhostWindow::fixGeometry); + + connect(this, &QQuickView::xChanged, this, &ScreenEdgeGhostWindow::startGeometryTimer); + connect(this, &QQuickView::yChanged, this, &ScreenEdgeGhostWindow::startGeometryTimer); + connect(this, &QQuickView::widthChanged, this, &ScreenEdgeGhostWindow::startGeometryTimer); + connect(this, &QQuickView::heightChanged, this, &ScreenEdgeGhostWindow::startGeometryTimer); connect(m_dockView, &DockView::absGeometryChanged, this, &ScreenEdgeGhostWindow::updateGeometry); connect(m_dockView, &DockView::screenGeometryChanged, this, &ScreenEdgeGhostWindow::updateGeometry); connect(m_dockView, &DockView::locationChanged, this, &ScreenEdgeGhostWindow::updateGeometry); connect(m_dockView, &QQuickView::screenChanged, this, [this]() { setScreen(m_dockView->screen()); + updateGeometry(); }); if (!KWindowSystem::isPlatformWayland()) { connect(this, &QWindow::visibleChanged, this, [&]() { //! IMPORTANT!!! ::: This fixes a bug when closing an Activity all docks from all Activities are //! disappearing! With this they reappear!!! if (m_dockView && m_dockView->managedLayout()) { if (!isVisible()) { QTimer::singleShot(100, [this]() { if (!m_inDelete && m_dockView && m_dockView->managedLayout() && !isVisible()) { setVisible(true); } }); QTimer::singleShot(1500, [this]() { if (!m_inDelete && m_dockView && m_dockView->managedLayout() && !isVisible()) { setVisible(true); } }); } else { //! For some reason when the window is hidden in the edge under X11 afterwards //! is losing its window flags if (!m_inDelete) { KWindowSystem::setType(winId(), NET::Dock); KWindowSystem::setState(winId(), NET::SkipTaskbar | NET::SkipPager); KWindowSystem::setOnAllDesktops(winId(), true); } } } }); } setupWaylandIntegration(); setScreen(m_dockView->screen()); setVisible(true); updateGeometry(); hideWithMask(); } ScreenEdgeGhostWindow::~ScreenEdgeGhostWindow() { m_inDelete = true; m_dockView = nullptr; if (m_shellSurface) { delete m_shellSurface; } } int ScreenEdgeGhostWindow::location() { return (int)m_dockView->location(); } DockView *ScreenEdgeGhostWindow::parentDock() { return m_dockView; } KWayland::Client::PlasmaShellSurface *ScreenEdgeGhostWindow::surface() { return m_shellSurface; } void ScreenEdgeGhostWindow::updateGeometry() { QRect newGeometry; int thickness{1}; if (m_dockView->location() == Plasma::Types::BottomEdge) { newGeometry.setX(m_dockView->absGeometry().left()); newGeometry.setY(m_dockView->screenGeometry().bottom() - thickness); } else if (m_dockView->location() == Plasma::Types::TopEdge) { newGeometry.setX(m_dockView->absGeometry().left()); newGeometry.setY(m_dockView->screenGeometry().top()); } else if (m_dockView->location() == Plasma::Types::LeftEdge) { newGeometry.setX(m_dockView->screenGeometry().left()); newGeometry.setY(m_dockView->absGeometry().top()); } else if (m_dockView->location() == Plasma::Types::RightEdge) { newGeometry.setX(m_dockView->screenGeometry().right() - thickness); newGeometry.setY(m_dockView->absGeometry().top()); } if (m_dockView->formFactor() == Plasma::Types::Horizontal) { newGeometry.setWidth(qMin(m_dockView->absGeometry().width(), m_dockView->screenGeometry().width() - 1)); newGeometry.setHeight(thickness + 1); } else { newGeometry.setWidth(thickness + 1); newGeometry.setHeight(qMin(m_dockView->absGeometry().height(), m_dockView->screenGeometry().height() - 1)); } m_calculatedGeometry = newGeometry; fixGeometry(); } void ScreenEdgeGhostWindow::fixGeometry() { if (!m_calculatedGeometry.isEmpty() && (m_calculatedGeometry.x() != x() || m_calculatedGeometry.y() != y() || m_calculatedGeometry.width() != width() || m_calculatedGeometry.height() != height())) { setMinimumSize(m_calculatedGeometry.size()); setMaximumSize(m_calculatedGeometry.size()); resize(m_calculatedGeometry.size()); setPosition(m_calculatedGeometry.x(), m_calculatedGeometry.y()); if (m_shellSurface) { m_shellSurface->setPosition(m_calculatedGeometry.topLeft()); } } } +void ScreenEdgeGhostWindow::startGeometryTimer() +{ + m_fixGeometryTimer.start(); +} + void ScreenEdgeGhostWindow::setupWaylandIntegration() { if (m_shellSurface || !KWindowSystem::isPlatformWayland() || !m_dockView || !m_dockView->containment()) { // already setup return; } if (DockCorona *c = qobject_cast(m_dockView->containment()->corona())) { using namespace KWayland::Client; PlasmaShell *interface = c->waylandDockCoronaInterface(); if (!interface) { return; } Surface *s = Surface::fromWindow(this); if (!s) { return; } qDebug() << "wayland screen edge ghost window surface was created..."; m_shellSurface = interface->createSurface(s, this); m_shellSurface->setSkipTaskbar(true); m_shellSurface->setPanelTakesFocus(false); m_shellSurface->setRole(PlasmaShellSurface::Role::Panel); m_shellSurface->setPanelBehavior(PlasmaShellSurface::PanelBehavior::AutoHide); } } bool ScreenEdgeGhostWindow::event(QEvent *e) { if (e->type() == QEvent::Enter || e->type() == QEvent::DragEnter) { emit edgeTriggered(); } return QQuickView::event(e); } void ScreenEdgeGhostWindow::hideWithMask() { QRect maskGeometry{0, 0, 1, 1}; setMask(maskGeometry); } void ScreenEdgeGhostWindow::showWithMask() { setMask(QRect()); } } diff --git a/app/dock/screenedgeghostwindow.h b/app/dock/screenedgeghostwindow.h index 5403d9d4..c78595bd 100644 --- a/app/dock/screenedgeghostwindow.h +++ b/app/dock/screenedgeghostwindow.h @@ -1,95 +1,99 @@ /* * Copyright 2018 Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SCREENEDGEGHOSTWINDOW_H #define SCREENEDGEGHOSTWINDOW_H #include #include +#include namespace KWayland { namespace Client { class PlasmaShellSurface; } } namespace Latte { class DockView; } namespace Latte { //! What is the importance of this class? //! //! Plasma is activating the screen edges for the main panel window //! unfortunately this isnt possible for the Latte case. //! When a window is hidden at an edge it becomes NOT visible //! unfortunately that means that all the animations are //! stopped (Qt behaviour) and that creates confusion to the user after the window //! reappears because various animations are played (adding-removing tasks/launchers) //! that arent relevant any more. //! //! In order to workaround the above behaviour Latte is using a //! fake window to communicate with KWin and the MAIN dock window //! continues to use only mask technique to hide //! //! KDE BUGS: https://bugs.kde.org/show_bug.cgi?id=382219 //! https://bugs.kde.org/show_bug.cgi?id=392464 class ScreenEdgeGhostWindow : public QQuickView { Q_OBJECT public: ScreenEdgeGhostWindow(DockView *view); ~ScreenEdgeGhostWindow() override; int location(); void hideWithMask(); void showWithMask(); DockView *parentDock(); KWayland::Client::PlasmaShellSurface *surface(); signals: void edgeTriggered(); protected: bool event(QEvent *ev) override; private slots: + void startGeometryTimer(); void updateGeometry(); void fixGeometry(); private: void setupWaylandIntegration(); private: bool m_inDelete{false}; QRect m_calculatedGeometry; + QTimer m_fixGeometryTimer; + DockView *m_dockView{nullptr}; KWayland::Client::PlasmaShellSurface *m_shellSurface{nullptr}; }; } #endif