1
0
mirror of https://github.com/KDE/latte-dock.git synced 2024-12-23 01:33:50 +03:00

introduce floating gap window

--this window responsibility is to check
if the mouse is still inside the real floating
gap and in such case to prevent the dock from
hiding
This commit is contained in:
Michail Vourlakos 2020-01-22 00:11:37 +02:00
parent 35ce0496ec
commit 3f68665300
7 changed files with 618 additions and 46 deletions

View File

@ -3,6 +3,7 @@ set(lattedock-app_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/containmentinterface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/containmentinterface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/contextmenu.cpp ${CMAKE_CURRENT_SOURCE_DIR}/contextmenu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/effects.cpp ${CMAKE_CURRENT_SOURCE_DIR}/effects.cpp
${CMAKE_CURRENT_SOURCE_DIR}/floatinggapwindow.cpp
${CMAKE_CURRENT_SOURCE_DIR}/panelshadows.cpp ${CMAKE_CURRENT_SOURCE_DIR}/panelshadows.cpp
${CMAKE_CURRENT_SOURCE_DIR}/positioner.cpp ${CMAKE_CURRENT_SOURCE_DIR}/positioner.cpp
${CMAKE_CURRENT_SOURCE_DIR}/screenedgeghostwindow.cpp ${CMAKE_CURRENT_SOURCE_DIR}/screenedgeghostwindow.cpp

View File

@ -0,0 +1,378 @@
/*
* Copyright 2020 Michail Vourlakos <mvourlakos@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "floatinggapwindow.h"
// local
#include "view.h"
// Qt
#include <QDebug>
#include <QSurfaceFormat>
#include <QQuickView>
#include <QTimer>
// KDE
#include <KWayland/Client/plasmashell.h>
#include <KWayland/Client/surface.h>
#include <KWindowSystem>
// X11
#include <NETWM>
namespace Latte {
namespace ViewPart {
FloatingGapWindow::FloatingGapWindow(Latte::View *view) :
m_latteView(view)
{
m_corona = qobject_cast<Latte::Corona *>(view->corona());
m_debugMode = (qApp->arguments().contains("-d") && qApp->arguments().contains("--kwinedges"));
if (m_debugMode) {
m_showColor = QColor("green");
m_hideColor = QColor("red");
} else {
m_showColor = QColor(Qt::transparent);
m_hideColor = QColor(Qt::transparent);
m_showColor.setAlpha(0);
m_hideColor.setAlpha(1);
}
setColor(m_showColor);
setDefaultAlphaBuffer(true);
setFlags(Qt::FramelessWindowHint
| Qt::WindowStaysOnTopHint
| Qt::NoDropShadowWindowHint
| Qt::WindowDoesNotAcceptFocus);
m_fixGeometryTimer.setSingleShot(true);
m_fixGeometryTimer.setInterval(500);
connect(&m_fixGeometryTimer, &QTimer::timeout, this, &FloatingGapWindow::fixGeometry);
//! this timer is used in order to identify if mouse is still present in sensitive floating
//! areas and in such case to prevent a real-floating view to hide itself
m_asyncMouseTimer.setSingleShot(true);
m_asyncMouseTimer.setInterval(200);
connect(&m_asyncMouseTimer, &QTimer::timeout, this, [this]() {
if (m_inAsyncContainsMouse && !m_containsMouse) {
emit asyncContainsMouseChanged(false);
hideWithMask();
m_inAsyncContainsMouse = false;
}
});
connect(this, &QQuickView::xChanged, this, &FloatingGapWindow::startGeometryTimer);
connect(this, &QQuickView::yChanged, this, &FloatingGapWindow::startGeometryTimer);
connect(this, &QQuickView::widthChanged, this, &FloatingGapWindow::startGeometryTimer);
connect(this, &QQuickView::heightChanged, this, &FloatingGapWindow::startGeometryTimer);
connect(m_latteView, &Latte::View::absoluteGeometryChanged, this, &FloatingGapWindow::updateGeometry);
connect(m_latteView, &Latte::View::screenGeometryChanged, this, &FloatingGapWindow::updateGeometry);
connect(m_latteView, &Latte::View::locationChanged, this, &FloatingGapWindow::updateGeometry);
connect(m_latteView, &QQuickView::screenChanged, this, [this]() {
setScreen(m_latteView->screen());
updateGeometry();
});
if (!KWindowSystem::isPlatformWayland()) {
//! IMPORTANT!!! ::: This fixes a bug when closing an Activity all views from all Activities are
//! disappearing! With this code parts they reappear!!!
m_visibleHackTimer1.setInterval(400);
m_visibleHackTimer2.setInterval(2500);
m_visibleHackTimer1.setSingleShot(true);
m_visibleHackTimer2.setSingleShot(true);
connectionsHack << connect(this, &QWindow::visibleChanged, this, [&]() {
if (!m_inDelete && m_latteView && m_latteView->layout() && !isVisible()) {
m_visibleHackTimer1.start();
m_visibleHackTimer2.start();
} else if (!m_inDelete) {
//! For some reason when the window is hidden in the edge under X11 afterwards
//! is losing its window flags
m_corona->wm()->setViewExtraFlags(this);
}
});
connectionsHack << connect(&m_visibleHackTimer1, &QTimer::timeout, this, [&]() {
if (!m_inDelete && m_latteView && m_latteView->layout() && !isVisible()) {
show();
emit forcedShown();
//qDebug() << "Floating Gap:: Enforce reshow from timer 1...";
} else {
//qDebug() << "Floating Gap:: No needed reshow from timer 1...";
}
});
connectionsHack << connect(&m_visibleHackTimer2, &QTimer::timeout, this, [&]() {
if (!m_inDelete && m_latteView && m_latteView->layout() && !isVisible()) {
show();
emit forcedShown();
//qDebug() << "Floating Gap:: Enforce reshow from timer 2...";
} else {
//qDebug() << "Floating Gap:: No needed reshow from timer 2...";
}
});
connectionsHack << connect(this, &FloatingGapWindow::forcedShown, this, [&]() {
m_corona->wm()->unregisterIgnoredWindow(m_trackedWindowId);
m_trackedWindowId = winId();
m_corona->wm()->registerIgnoredWindow(m_trackedWindowId);
});
}
setupWaylandIntegration();
if (KWindowSystem::isPlatformX11()) {
m_trackedWindowId = winId();
m_corona->wm()->registerIgnoredWindow(m_trackedWindowId);
} else {
connect(m_corona->wm(), &WindowSystem::AbstractWindowInterface::latteWindowAdded, this, [&]() {
if (m_trackedWindowId.isNull()) {
m_trackedWindowId = m_corona->wm()->winIdFor("latte-dock", geometry());
m_corona->wm()->registerIgnoredWindow(m_trackedWindowId);
}
});
}
setScreen(m_latteView->screen());
show();
updateGeometry();
hideWithMask();
}
FloatingGapWindow::~FloatingGapWindow()
{
m_inDelete = true;
m_corona->wm()->unregisterIgnoredWindow(KWindowSystem::isPlatformX11() ? winId() : m_trackedWindowId);
m_latteView = nullptr;
// clear mode
m_visibleHackTimer1.stop();
m_visibleHackTimer2.stop();
for (auto &c : connectionsHack) {
disconnect(c);
}
if (m_shellSurface) {
delete m_shellSurface;
}
}
int FloatingGapWindow::location()
{
return (int)m_latteView->location();
}
int FloatingGapWindow::thickness() const
{
return m_thickness;
}
Latte::View *FloatingGapWindow::parentView()
{
return m_latteView;
}
KWayland::Client::PlasmaShellSurface *FloatingGapWindow::surface()
{
return m_shellSurface;
}
void FloatingGapWindow::updateGeometry()
{
if (m_latteView->positioner()->slideOffset() != 0) {
return;
}
QRect newGeometry;
m_thickness = m_latteView->screenEdgeMargin();
int length = m_latteView->formFactor() == Plasma::Types::Horizontal ? m_latteView->absoluteGeometry().width() : m_latteView->absoluteGeometry().height();
if (m_latteView->location() == Plasma::Types::BottomEdge) {
int xF = qMax(m_latteView->screenGeometry().left(), m_latteView->absoluteGeometry().left());
newGeometry.setX(xF);
newGeometry.setY(m_latteView->screenGeometry().bottom() - m_thickness);
} else if (m_latteView->location() == Plasma::Types::TopEdge) {
int xF = qMax(m_latteView->screenGeometry().left(), m_latteView->absoluteGeometry().left());
newGeometry.setX(xF);
newGeometry.setY(m_latteView->screenGeometry().top());
} else if (m_latteView->location() == Plasma::Types::LeftEdge) {
int yF = qMax(m_latteView->screenGeometry().top(), m_latteView->absoluteGeometry().top());
newGeometry.setX(m_latteView->screenGeometry().left());
newGeometry.setY(yF);
} else if (m_latteView->location() == Plasma::Types::RightEdge) {
int yF = qMax(m_latteView->screenGeometry().top(), m_latteView->absoluteGeometry().top());
newGeometry.setX(m_latteView->screenGeometry().right() - m_thickness);
newGeometry.setY(yF);
}
if (m_latteView->formFactor() == Plasma::Types::Horizontal) {
newGeometry.setWidth(length);
newGeometry.setHeight(m_thickness + 1);
} else {
newGeometry.setWidth(m_thickness + 1);
newGeometry.setHeight(length);
}
m_calculatedGeometry = newGeometry;
fixGeometry();
}
void FloatingGapWindow::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 FloatingGapWindow::startGeometryTimer()
{
m_fixGeometryTimer.start();
}
void FloatingGapWindow::setupWaylandIntegration()
{
if (m_shellSurface || !KWindowSystem::isPlatformWayland() || !m_latteView || !m_latteView->containment()) {
// already setup
return;
}
if (m_corona) {
using namespace KWayland::Client;
PlasmaShell *interface = m_corona->waylandCoronaInterface();
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_corona->wm()->setViewExtraFlags(m_shellSurface);
m_shellSurface->setPanelTakesFocus(false);
}
}
bool FloatingGapWindow::containsMouse() const
{
return m_containsMouse;
}
void FloatingGapWindow::setContainsMouse(bool contains)
{
if (m_containsMouse == contains) {
return;
}
m_containsMouse = contains;
}
bool FloatingGapWindow::event(QEvent *e)
{
if (e->type() == QEvent::DragEnter || e->type() == QEvent::DragMove) {
setContainsMouse(true);
emit dragEntered();
} else if (e->type() == QEvent::Enter) {
setContainsMouse(true);
triggerAsyncContainsMouseSignals();
} else if (e->type() == QEvent::Leave || e->type() == QEvent::DragLeave) {
setContainsMouse(false);
if (m_inAsyncContainsMouse) {
m_asyncMouseTimer.stop();
m_inAsyncContainsMouse = false;
emit asyncContainsMouseChanged(true);
}
} else if (e->type() == QEvent::Show) {
m_corona->wm()->setViewExtraFlags(this);
}
return QQuickView::event(e);
}
void FloatingGapWindow::callAsyncContainsMouse()
{
m_inAsyncContainsMouse = true;
m_asyncMouseTimer.start();
showWithMask();
}
void FloatingGapWindow::triggerAsyncContainsMouseSignals()
{
if (!m_inAsyncContainsMouse) {
return;
}
//! this function is called QEvent::Enter
m_asyncMouseTimer.stop();
hideWithMask();
}
void FloatingGapWindow::hideWithMask()
{
if (m_debugMode) {
qDebug() << " Floating Gap Window :: MASK HIDE...";
}
//! old values: 0,0,1,1 were blocking the top-left corner of the window
QRect maskGeometry{-2, 0, 1, 1};
setMask(maskGeometry);
//! repaint in order to update mask immediately
setColor(m_hideColor);
}
void FloatingGapWindow::showWithMask()
{
if (m_debugMode) {
qDebug() << " Floating Gap Window :: MAKS SHOW...";
}
setMask(QRegion());
//! repaint in order to update mask immediately
setColor(m_showColor);
}
}
}

View File

@ -0,0 +1,139 @@
/*
* Copyright 2020 Michail Vourlakos <mvourlakos@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef FLOATINGGAPWINDOW_H
#define FLOATINGWINDOW_H
// local
#include "../lattecorona.h"
#include "../wm/windowinfowrap.h"
// Qt
#include <QObject>
#include <QQuickView>
#include <QTimer>
namespace KWayland {
namespace Client {
class PlasmaShellSurface;
}
}
namespace Latte {
class Corona;
class View;
}
namespace Latte {
namespace ViewPart {
//! What is the importance of this class?
//!
//! This window is responsible to identify if the mouse is still present
//! in the REAL FLOATING GAP between the VIEW and the SCREEN EDGE.
//! When VIEWS are REAL FLOATING then the VIEW Window is really placed
//! as it is shown to the user. In that case we need a way to check
//! where the mouse is even though it is OUTSIDE the VIEW or the
//! SCREENEDGEGHOSTWINDOW. The main functionality of FloatingGapWindow
//! is that it is TEMPORARILY shown/draw after a MUSTHIDE signal of
//! VisibilityManager was sent; in order to check if the mouse is still
//! inside the FLOATINGGAP. After it has really identified where mouse
//! is present, an FloatingGapWindow::asyncContainsMouse(contains) signal
//! is sent.
class FloatingGapWindow : public QQuickView
{
Q_OBJECT
public:
FloatingGapWindow(Latte::View *view);
~FloatingGapWindow() override;
int location();
int thickness() const;
void hideWithMask();
void showWithMask();
Latte::View *parentView();
KWayland::Client::PlasmaShellSurface *surface();
void callAsyncContainsMouse();
signals:
void asyncContainsMouseChanged(bool contains); //called from visibility to check if mouse is in the free sensitive floating area
void dragEntered();
void forcedShown(); //[workaround] forced shown to avoid a KWin issue that hides windows when activities are stopped
protected:
bool event(QEvent *ev) override;
private slots:
void startGeometryTimer();
void updateGeometry();
void fixGeometry();
private:
bool containsMouse() const;
void setContainsMouse(bool contains);
void setupWaylandIntegration();
void triggerAsyncContainsMouseSignals();
private:
bool m_debugMode{false};
bool m_containsMouse{false};
bool m_inDelete{false};
bool m_inAsyncContainsMouse{false}; //called from visibility to check if mouse is in the free sensitive floating area
int m_thickness{2};
QRect m_calculatedGeometry;
//! [workaround] colors in order to help masking to apply immediately
//! for some reason when the window in with no content the mask is not
//! update immediately
QColor m_hideColor;
QColor m_showColor;
QTimer m_asyncMouseTimer; //called from visibility to check if mouse is in the free sensitive floating area
QTimer m_fixGeometryTimer;
//! HACK: Timers in order to handle KWin faulty
//! behavior that hides Views when closing Activities
//! with no actual reason
QTimer m_visibleHackTimer1;
QTimer m_visibleHackTimer2;
//! Connections for the KWin visibility hack
QList<QMetaObject::Connection> connectionsHack;
Latte::View *m_latteView{nullptr};
QPointer<Latte::Corona> m_corona;
Latte::WindowSystem::WindowId m_trackedWindowId;
KWayland::Client::PlasmaShellSurface *m_shellSurface{nullptr};
};
}
}
#endif

View File

@ -197,10 +197,7 @@ void ScreenEdgeGhostWindow::updateGeometry()
QRect newGeometry; QRect newGeometry;
if (m_latteView->screenEdgeMargin()>0 && m_latteView->behaveAsPlasmaPanel()) { if (KWindowSystem::compositingActive()) {
//real floating
m_thickness = m_latteView->screenEdgeMargin();
} else if (KWindowSystem::compositingActive()) {
m_thickness = 6; m_thickness = 6;
} else { } else {
m_thickness = 2; m_thickness = 2;

View File

@ -480,6 +480,18 @@ void View::updateAbsoluteGeometry(bool bypassChecks)
QRect absGeometry {x() + m_localGeometry.x(), y() + m_localGeometry.y() QRect absGeometry {x() + m_localGeometry.x(), y() + m_localGeometry.y()
, m_localGeometry.width(), m_localGeometry.height()}; , m_localGeometry.width(), m_localGeometry.height()};
if (isFloatingWindow()) {
if (location() == Plasma::Types::BottomEdge) {
absGeometry.setY(screenGeometry().bottom() - m_screenEdgeMargin - m_normalThickness);
} else if (location() == Plasma::Types::TopEdge) {
absGeometry.setY(screenGeometry().top() + m_screenEdgeMargin);
} else if (location() == Plasma::Types::LeftEdge) {
absGeometry.setX(screenGeometry().left() + m_screenEdgeMargin);
} else if (location() == Plasma::Types::RightEdge) {
absGeometry.setX(screenGeometry().right() - m_screenEdgeMargin - m_normalThickness);
}
}
if (m_absoluteGeometry == absGeometry && !bypassChecks) { if (m_absoluteGeometry == absGeometry && !bypassChecks) {
return; return;
} }

View File

@ -22,6 +22,7 @@
// local // local
#include "positioner.h" #include "positioner.h"
#include "floatinggapwindow.h"
#include "screenedgeghostwindow.h" #include "screenedgeghostwindow.h"
#include "view.h" #include "view.h"
#include "windowstracker/currentscreentracker.h" #include "windowstracker/currentscreentracker.h"
@ -58,25 +59,11 @@ VisibilityManager::VisibilityManager(PlasmaQuick::ContainmentView *view)
m_wm = m_corona->wm(); m_wm = m_corona->wm();
connect(this, &VisibilityManager::slideOutFinished, this, &VisibilityManager::updateHiddenState); connect(this, &VisibilityManager::slideOutFinished, this, &VisibilityManager::updateHiddenState);
connect(this, &VisibilityManager::slideInFinished, this, [&]() { connect(this, &VisibilityManager::slideInFinished, this, &VisibilityManager::updateHiddenState);
if (m_latteView && !m_latteView->screenEdgeMarginEnabled()) {
//! after slide-out the real floating windows should ignore their criteria
//! until containsMouse from view has been set to true and false to afterwards
updateHiddenState();
} else {
m_timerHide.stop();
}
});
connect(this, &VisibilityManager::enableKWinEdgesChanged, this, &VisibilityManager::updateKWinEdgesSupport); connect(this, &VisibilityManager::enableKWinEdgesChanged, this, &VisibilityManager::updateKWinEdgesSupport);
connect(this, &VisibilityManager::modeChanged, this, &VisibilityManager::updateKWinEdgesSupport); connect(this, &VisibilityManager::modeChanged, this, &VisibilityManager::updateKWinEdgesSupport);
connect(this, &VisibilityManager::mustBeHide, this, [&]() {
if (supportsKWinEdges() && m_latteView->screenEdgeMargin()>0 && m_latteView->behaveAsPlasmaPanel()) {
m_edgeGhostWindow->showWithMask();
}
});
if (m_latteView) { if (m_latteView) {
connect(m_latteView, &Latte::View::eventTriggered, this, &VisibilityManager::viewEventManager); connect(m_latteView, &Latte::View::eventTriggered, this, &VisibilityManager::viewEventManager);
connect(m_latteView, &Latte::View::byPassWMChanged, this, &VisibilityManager::updateKWinEdgesSupport); connect(m_latteView, &Latte::View::byPassWMChanged, this, &VisibilityManager::updateKWinEdgesSupport);
@ -107,8 +94,13 @@ VisibilityManager::VisibilityManager(PlasmaQuick::ContainmentView *view)
}); });
connect(&m_timerHide, &QTimer::timeout, this, [&]() { connect(&m_timerHide, &QTimer::timeout, this, [&]() {
if (!m_blockHiding && !m_isHidden && !m_isBelowLayer && !m_dragEnter) { if (!m_blockHiding && !m_isHidden && !m_isBelowLayer && !m_dragEnter) {
// qDebug() << "must be hide"; if (m_latteView->isFloatingWindow()) {
emit mustBeHide(); //! first check if mouse is inside the floating gap
checkMouseInFloatingArea();
} else {
//! immediate call
emit mustBeHide();
}
} }
}); });
@ -123,6 +115,10 @@ VisibilityManager::~VisibilityManager()
if (m_edgeGhostWindow) { if (m_edgeGhostWindow) {
m_edgeGhostWindow->deleteLater(); m_edgeGhostWindow->deleteLater();
} }
if (m_floatingGapWindow) {
m_floatingGapWindow->deleteLater();
}
} }
Types::Visibility VisibilityManager::mode() const Types::Visibility VisibilityManager::mode() const
@ -491,13 +487,7 @@ void VisibilityManager::updateGhostWindowState()
if (m_mode == Latte::Types::WindowsCanCover) { if (m_mode == Latte::Types::WindowsCanCover) {
m_wm->setActiveEdge(m_edgeGhostWindow, m_isBelowLayer && !m_containsMouse); m_wm->setActiveEdge(m_edgeGhostWindow, m_isBelowLayer && !m_containsMouse);
} else { } else {
/* bool viewIsFloatingAndContainsMouse = bool activated = (m_isHidden && !windowContainsMouse());
m_latteView->behaveAsPlasmaPanel()
&& m_latteView->screenEdgeMarginEnabled()
&& m_latteView->screenEdgeMargin()>0
&& (m_edgeGhostWindow->containsMouse() || m_containsMouse);*/
bool activated = (m_isHidden && !m_containsMouse && !m_edgeGhostWindow->containsMouse());
m_wm->setActiveEdge(m_edgeGhostWindow, activated); m_wm->setActiveEdge(m_edgeGhostWindow, activated);
} }
@ -572,7 +562,7 @@ void VisibilityManager::updateHiddenState()
switch (m_mode) { switch (m_mode) {
case Types::AutoHide: case Types::AutoHide:
case Types::WindowsCanCover: case Types::WindowsCanCover:
raiseView(m_containsMouse || (m_edgeGhostWindow && m_edgeGhostWindow->containsMouse())); raiseView(m_containsMouse);
break; break;
case Types::DodgeActive: case Types::DodgeActive:
@ -597,6 +587,10 @@ void VisibilityManager::applyActivitiesToHiddenWindows(const QStringList &activi
if (m_edgeGhostWindow) { if (m_edgeGhostWindow) {
m_wm->setWindowOnActivities(*m_edgeGhostWindow, activities); m_wm->setWindowOnActivities(*m_edgeGhostWindow, activities);
} }
if (m_floatingGapWindow) {
m_wm->setWindowOnActivities(*m_floatingGapWindow, activities);
}
} }
void VisibilityManager::dodgeActive() void VisibilityManager::dodgeActive()
@ -634,6 +628,7 @@ void VisibilityManager::dodgeAllWindows()
if (m_containsMouse) { if (m_containsMouse) {
raiseView(true); raiseView(true);
return;
} }
bool windowIntersects{m_latteView->windowsTracker()->currentScreen()->activeWindowTouching() || m_latteView->windowsTracker()->currentScreen()->existsWindowTouching()}; bool windowIntersects{m_latteView->windowsTracker()->currentScreen()->activeWindowTouching() || m_latteView->windowsTracker()->currentScreen()->existsWindowTouching()};
@ -720,9 +715,17 @@ void VisibilityManager::setContainsMouse(bool contains)
m_containsMouse = contains; m_containsMouse = contains;
emit containsMouseChanged(); emit containsMouseChanged();
}
if (contains && m_mode != Types::AlwaysVisible) { bool VisibilityManager::windowContainsMouse()
raiseView(true); {
return m_containsMouse || (m_edgeGhostWindow && m_edgeGhostWindow->containsMouse());
}
void VisibilityManager::checkMouseInFloatingArea()
{
if (m_floatingGapWindow && m_latteView->isFloatingWindow()) {
m_floatingGapWindow->callAsyncContainsMouse();
} }
} }
@ -785,14 +788,19 @@ void VisibilityManager::updateKWinEdgesSupport()
if (m_enableKWinEdgesFromUser) { if (m_enableKWinEdgesFromUser) {
createEdgeGhostWindow(); createEdgeGhostWindow();
if (m_latteView->isFloatingWindow()) {
createFloatingGapWindow();
}
} else if (!m_enableKWinEdgesFromUser) { } else if (!m_enableKWinEdgesFromUser) {
deleteEdgeGhostWindow(); deleteEdgeGhostWindow();
deleteFloatingGapWindow();
} }
} else if (m_mode == Types::WindowsCanCover) { } else if (m_mode == Types::WindowsCanCover) {
createEdgeGhostWindow(); createEdgeGhostWindow();
} else { } else {
deleteEdgeGhostWindow(); deleteEdgeGhostWindow();
deleteFloatingGapWindow();
} }
} }
@ -801,23 +809,12 @@ void VisibilityManager::createEdgeGhostWindow()
if (!m_edgeGhostWindow) { if (!m_edgeGhostWindow) {
m_edgeGhostWindow = new ScreenEdgeGhostWindow(m_latteView); m_edgeGhostWindow = new ScreenEdgeGhostWindow(m_latteView);
connect(m_edgeGhostWindow, &ScreenEdgeGhostWindow::containsMouseChanged, this, [ = ](bool contains) { connect(m_edgeGhostWindow, &ScreenEdgeGhostWindow::containsMouseChanged, this, [ = ](bool contains) {
if (contains) { if (contains) {
if (!m_isHidden) { raiseView(true);
//! immediate call
m_edgeGhostWindow->hideWithMask();
emit mustBeShown();
} else {
raiseView(true);
}
} else { } else {
if (!m_isHidden) { m_timerShow.stop();
//! immediate call updateGhostWindowState();
updateHiddenState();
} else {
m_timerShow.stop();
updateGhostWindowState();
}
} }
}); });
@ -861,6 +858,41 @@ void VisibilityManager::deleteEdgeGhostWindow()
} }
} }
void VisibilityManager::createFloatingGapWindow()
{
if (!m_floatingGapWindow) {
m_floatingGapWindow = new FloatingGapWindow(m_latteView);
connect(m_floatingGapWindow, &FloatingGapWindow::asyncContainsMouseChanged, this, [ = ](bool contains) {
if (contains) {
if (m_latteView->isFloatingWindow() && !m_isHidden) {
//! immediate call after contains mouse checks for mouse in sensitive floating areas
updateHiddenState();
}
} else {
if (m_latteView->isFloatingWindow() && !m_isHidden) {
//! immediate call after contains mouse checks for mouse in sensitive floating areas
emit mustBeHide();
}
}
});
}
}
void VisibilityManager::deleteFloatingGapWindow()
{
if (m_floatingGapWindow) {
m_floatingGapWindow->deleteLater();
m_floatingGapWindow = nullptr;
}
}
bool VisibilityManager::supportsFloatingGap() const
{
return (m_floatingGapWindow != nullptr);
}
//! END: VisibilityManager implementation //! END: VisibilityManager implementation
} }

View File

@ -38,6 +38,7 @@ namespace Latte {
class Corona; class Corona;
class View; class View;
namespace ViewPart { namespace ViewPart {
class FloatingGapWindow;
class ScreenEdgeGhostWindow; class ScreenEdgeGhostWindow;
} }
namespace WindowSystem { namespace WindowSystem {
@ -154,9 +155,18 @@ private:
void deleteEdgeGhostWindow(); void deleteEdgeGhostWindow();
void updateGhostWindowState(); void updateGhostWindowState();
//! Floating Gap Support functions
void createFloatingGapWindow();
void deleteFloatingGapWindow();
bool supportsFloatingGap() const;
void updateStrutsBasedOnLayoutsAndActivities(bool forceUpdate = false); void updateStrutsBasedOnLayoutsAndActivities(bool forceUpdate = false);
void viewEventManager(QEvent *ev); void viewEventManager(QEvent *ev);
void checkMouseInFloatingArea();
bool windowContainsMouse();
QRect acceptableStruts(); QRect acceptableStruts();
private slots: private slots:
@ -191,6 +201,9 @@ private:
std::array<QMetaObject::Connection, 1> m_connectionsKWinEdges; std::array<QMetaObject::Connection, 1> m_connectionsKWinEdges;
ScreenEdgeGhostWindow *m_edgeGhostWindow{nullptr}; ScreenEdgeGhostWindow *m_edgeGhostWindow{nullptr};
//! Floating Gap
FloatingGapWindow *m_floatingGapWindow{nullptr};
Latte::Corona *m_corona{nullptr}; Latte::Corona *m_corona{nullptr};
Latte::View *m_latteView{nullptr}; Latte::View *m_latteView{nullptr};