mirror of
https://github.com/KDE/latte-dock.git
synced 2025-02-04 01:47:31 +03:00
move View::HelperWindows in their own directory
--at the same time create a base SubWindow class for all window helpers used by Views. Now ScreenEdgeGhostWindow and FloatingGapWindow use the same window implementation
This commit is contained in:
parent
a0582ac409
commit
4b1580c0bd
@ -18,6 +18,7 @@ add_subdirectory(settings/delegates)
|
|||||||
add_subdirectory(settings/tools)
|
add_subdirectory(settings/tools)
|
||||||
add_subdirectory(shortcuts)
|
add_subdirectory(shortcuts)
|
||||||
add_subdirectory(view)
|
add_subdirectory(view)
|
||||||
|
add_subdirectory(view/helpers)
|
||||||
add_subdirectory(view/indicator)
|
add_subdirectory(view/indicator)
|
||||||
add_subdirectory(view/settings)
|
add_subdirectory(view/settings)
|
||||||
add_subdirectory(view/windowstracker)
|
add_subdirectory(view/windowstracker)
|
||||||
|
@ -3,13 +3,9 @@ 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}/view.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/view.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/visibilitymanager.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/visibilitymanager.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/settings/primaryconfigview.cpp
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/settings/secondaryconfigview.cpp
|
|
||||||
PARENT_SCOPE
|
PARENT_SCOPE
|
||||||
)
|
)
|
||||||
|
7
app/view/helpers/CMakeLists.txt
Normal file
7
app/view/helpers/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
set(lattedock-app_SRCS
|
||||||
|
${lattedock-app_SRCS}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/floatinggapwindow.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/screenedgeghostwindow.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/subwindow.cpp
|
||||||
|
PARENT_SCOPE
|
||||||
|
)
|
163
app/view/helpers/floatinggapwindow.cpp
Normal file
163
app/view/helpers/floatinggapwindow.cpp
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* 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) :
|
||||||
|
SubWindow(view, QString("Floating Gap Window"))
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
//! 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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
updateGeometry();
|
||||||
|
hideWithMask();
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatingGapWindow::~FloatingGapWindow()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
emit calculatedGeometryChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FloatingGapWindow::event(QEvent *e)
|
||||||
|
{
|
||||||
|
if (e->type() == QEvent::DragEnter || e->type() == QEvent::DragMove) {
|
||||||
|
m_containsMouse = true;
|
||||||
|
|
||||||
|
} else if (e->type() == QEvent::Enter) {
|
||||||
|
m_containsMouse = true;
|
||||||
|
|
||||||
|
triggerAsyncContainsMouseSignals();
|
||||||
|
} else if (e->type() == QEvent::Leave || e->type() == QEvent::DragLeave) {
|
||||||
|
m_containsMouse = false;
|
||||||
|
|
||||||
|
if (m_inAsyncContainsMouse) {
|
||||||
|
m_asyncMouseTimer.stop();
|
||||||
|
m_inAsyncContainsMouse = false;
|
||||||
|
emit asyncContainsMouseChanged(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SubWindow::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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -21,8 +21,9 @@
|
|||||||
#define FLOATINGWINDOW_H
|
#define FLOATINGWINDOW_H
|
||||||
|
|
||||||
// local
|
// local
|
||||||
#include "../lattecorona.h"
|
#include "subwindow.h"
|
||||||
#include "../wm/windowinfowrap.h"
|
#include "../../lattecorona.h"
|
||||||
|
#include "../../wm/windowinfowrap.h"
|
||||||
|
|
||||||
// Qt
|
// Qt
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
@ -57,7 +58,7 @@ namespace ViewPart {
|
|||||||
//! is present, an FloatingGapWindow::asyncContainsMouse(contains) signal
|
//! is present, an FloatingGapWindow::asyncContainsMouse(contains) signal
|
||||||
//! is sent.
|
//! is sent.
|
||||||
|
|
||||||
class FloatingGapWindow : public QQuickView
|
class FloatingGapWindow : public SubWindow
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -65,73 +66,24 @@ public:
|
|||||||
FloatingGapWindow(Latte::View *view);
|
FloatingGapWindow(Latte::View *view);
|
||||||
~FloatingGapWindow() override;
|
~FloatingGapWindow() override;
|
||||||
|
|
||||||
int location();
|
|
||||||
int thickness() const;
|
|
||||||
|
|
||||||
void hideWithMask();
|
|
||||||
void showWithMask();
|
|
||||||
|
|
||||||
Latte::View *parentView();
|
|
||||||
|
|
||||||
KWayland::Client::PlasmaShellSurface *surface();
|
|
||||||
|
|
||||||
void callAsyncContainsMouse();
|
void callAsyncContainsMouse();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void asyncContainsMouseChanged(bool contains); //called from visibility to check if mouse is in the free sensitive floating area
|
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:
|
protected:
|
||||||
bool event(QEvent *ev) override;
|
bool event(QEvent *ev) override;
|
||||||
|
void updateGeometry() override;
|
||||||
private slots:
|
|
||||||
void startGeometryTimer();
|
|
||||||
void updateGeometry();
|
|
||||||
void fixGeometry();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool containsMouse() const;
|
|
||||||
void setContainsMouse(bool contains);
|
|
||||||
void setupWaylandIntegration();
|
|
||||||
|
|
||||||
void triggerAsyncContainsMouseSignals();
|
void triggerAsyncContainsMouseSignals();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_debugMode{false};
|
|
||||||
|
|
||||||
bool m_containsMouse{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
|
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_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};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
176
app/view/helpers/screenedgeghostwindow.cpp
Normal file
176
app/view/helpers/screenedgeghostwindow.cpp
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 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 "screenedgeghostwindow.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 {
|
||||||
|
|
||||||
|
ScreenEdgeGhostWindow::ScreenEdgeGhostWindow(Latte::View *view) :
|
||||||
|
SubWindow(view, QString("Screen Ghost Window"))
|
||||||
|
{
|
||||||
|
if (m_debugMode) {
|
||||||
|
m_showColor = QColor("purple");
|
||||||
|
m_hideColor = QColor("blue");
|
||||||
|
} else {
|
||||||
|
m_showColor = QColor(Qt::transparent);
|
||||||
|
m_hideColor = QColor(Qt::transparent);
|
||||||
|
|
||||||
|
m_showColor.setAlpha(0);
|
||||||
|
m_hideColor.setAlpha(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
setColor(m_showColor);
|
||||||
|
|
||||||
|
//! this timer is used in order to avoid fast enter/exit signals during first
|
||||||
|
//! appearing after edge activation
|
||||||
|
m_delayedMouseTimer.setSingleShot(true);
|
||||||
|
m_delayedMouseTimer.setInterval(50);
|
||||||
|
connect(&m_delayedMouseTimer, &QTimer::timeout, this, [this]() {
|
||||||
|
if (m_delayedContainsMouse) {
|
||||||
|
setContainsMouse(true);
|
||||||
|
} else {
|
||||||
|
setContainsMouse(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
updateGeometry();
|
||||||
|
hideWithMask();
|
||||||
|
}
|
||||||
|
|
||||||
|
ScreenEdgeGhostWindow::~ScreenEdgeGhostWindow()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenEdgeGhostWindow::updateGeometry()
|
||||||
|
{
|
||||||
|
if (m_latteView->positioner()->slideOffset() != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect newGeometry;
|
||||||
|
|
||||||
|
if (KWindowSystem::compositingActive()) {
|
||||||
|
m_thickness = 6;
|
||||||
|
} else {
|
||||||
|
m_thickness = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int length{30};
|
||||||
|
int lengthDifference{0};
|
||||||
|
|
||||||
|
if (m_latteView->formFactor() == Plasma::Types::Horizontal) {
|
||||||
|
//! set minimum length to be 25% of screen width
|
||||||
|
length = qMax(m_latteView->screenGeometry().width()/4,qMin(m_latteView->absoluteGeometry().width(), m_latteView->screenGeometry().width() - 1));
|
||||||
|
lengthDifference = qMax(0,length - m_latteView->absoluteGeometry().width());
|
||||||
|
} else {
|
||||||
|
//! set minimum length to be 25% of screen height
|
||||||
|
length = qMax(m_latteView->screenGeometry().height()/4,qMin(m_latteView->absoluteGeometry().height(), m_latteView->screenGeometry().height() - 1));
|
||||||
|
lengthDifference = qMax(0,length - m_latteView->absoluteGeometry().height());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_latteView->location() == Plasma::Types::BottomEdge) {
|
||||||
|
int xF = qMax(m_latteView->screenGeometry().left(), m_latteView->absoluteGeometry().left() - lengthDifference);
|
||||||
|
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() - lengthDifference);
|
||||||
|
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() - lengthDifference);
|
||||||
|
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() - lengthDifference);
|
||||||
|
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;
|
||||||
|
|
||||||
|
emit calculatedGeometryChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScreenEdgeGhostWindow::containsMouse() const
|
||||||
|
{
|
||||||
|
return m_containsMouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenEdgeGhostWindow::setContainsMouse(bool contains)
|
||||||
|
{
|
||||||
|
if (m_containsMouse == contains) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_containsMouse = contains;
|
||||||
|
emit containsMouseChanged(contains);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScreenEdgeGhostWindow::event(QEvent *e)
|
||||||
|
{
|
||||||
|
if (e->type() == QEvent::DragEnter || e->type() == QEvent::DragMove) {
|
||||||
|
if (!m_containsMouse) {
|
||||||
|
m_delayedContainsMouse = false;
|
||||||
|
m_delayedMouseTimer.stop();
|
||||||
|
setContainsMouse(true);
|
||||||
|
emit dragEntered();
|
||||||
|
}
|
||||||
|
} else if (e->type() == QEvent::Enter) {
|
||||||
|
m_delayedContainsMouse = true;
|
||||||
|
if (!m_delayedMouseTimer.isActive()) {
|
||||||
|
m_delayedMouseTimer.start();
|
||||||
|
}
|
||||||
|
} else if (e->type() == QEvent::Leave || e->type() == QEvent::DragLeave) {
|
||||||
|
m_delayedContainsMouse = false;
|
||||||
|
if (!m_delayedMouseTimer.isActive()) {
|
||||||
|
m_delayedMouseTimer.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SubWindow::event(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -21,8 +21,9 @@
|
|||||||
#define SCREENEDGEGHOSTWINDOW_H
|
#define SCREENEDGEGHOSTWINDOW_H
|
||||||
|
|
||||||
// local
|
// local
|
||||||
#include "../lattecorona.h"
|
#include "subwindow.h"
|
||||||
#include "../wm/windowinfowrap.h"
|
#include "../../lattecorona.h"
|
||||||
|
#include "../../wm/windowinfowrap.h"
|
||||||
|
|
||||||
// Qt
|
// Qt
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
@ -60,7 +61,7 @@ namespace ViewPart {
|
|||||||
//! KDE BUGS: https://bugs.kde.org/show_bug.cgi?id=382219
|
//! KDE BUGS: https://bugs.kde.org/show_bug.cgi?id=382219
|
||||||
//! https://bugs.kde.org/show_bug.cgi?id=392464
|
//! https://bugs.kde.org/show_bug.cgi?id=392464
|
||||||
|
|
||||||
class ScreenEdgeGhostWindow : public QQuickView
|
class ScreenEdgeGhostWindow : public SubWindow
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -70,59 +71,22 @@ public:
|
|||||||
|
|
||||||
bool containsMouse() const;
|
bool containsMouse() const;
|
||||||
|
|
||||||
int location();
|
|
||||||
int thickness() const;
|
|
||||||
|
|
||||||
void hideWithMask();
|
|
||||||
void showWithMask();
|
|
||||||
|
|
||||||
Latte::View *parentView();
|
|
||||||
|
|
||||||
KWayland::Client::PlasmaShellSurface *surface();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void containsMouseChanged(bool contains);
|
void containsMouseChanged(bool contains);
|
||||||
void dragEntered();
|
void dragEntered();
|
||||||
void forcedShown(); //[workaround] forced shown to avoid a KWin issue that hides windows when activities are stopped
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool event(QEvent *ev) override;
|
bool event(QEvent *ev) override;
|
||||||
|
void updateGeometry() override;
|
||||||
private slots:
|
|
||||||
void startGeometryTimer();
|
|
||||||
void updateGeometry();
|
|
||||||
void fixGeometry();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setContainsMouse(bool contains);
|
void setContainsMouse(bool contains);
|
||||||
void setupWaylandIntegration();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_delayedContainsMouse{false};
|
bool m_delayedContainsMouse{false};
|
||||||
bool m_containsMouse{false};
|
bool m_containsMouse{false};
|
||||||
bool m_inDelete{false};
|
|
||||||
|
|
||||||
int m_thickness{2};
|
|
||||||
|
|
||||||
QRect m_calculatedGeometry;
|
|
||||||
|
|
||||||
QTimer m_delayedMouseTimer;
|
QTimer m_delayedMouseTimer;
|
||||||
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};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
@ -17,10 +17,10 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "floatinggapwindow.h"
|
#include "subwindow.h"
|
||||||
|
|
||||||
// local
|
// local
|
||||||
#include "view.h"
|
#include "../view.h"
|
||||||
|
|
||||||
// Qt
|
// Qt
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
@ -39,24 +39,17 @@
|
|||||||
namespace Latte {
|
namespace Latte {
|
||||||
namespace ViewPart {
|
namespace ViewPart {
|
||||||
|
|
||||||
FloatingGapWindow::FloatingGapWindow(Latte::View *view) :
|
SubWindow::SubWindow(Latte::View *view, QString debugType) :
|
||||||
m_latteView(view)
|
m_latteView(view)
|
||||||
{
|
{
|
||||||
m_corona = qobject_cast<Latte::Corona *>(view->corona());
|
m_corona = qobject_cast<Latte::Corona *>(view->corona());
|
||||||
|
|
||||||
m_debugMode = (qApp->arguments().contains("-d") && qApp->arguments().contains("--kwinedges"));
|
m_debugMode = (qApp->arguments().contains("-d") && qApp->arguments().contains("--kwinedges"));
|
||||||
|
m_debugType = debugType;
|
||||||
|
|
||||||
if (m_debugMode) {
|
|
||||||
m_showColor = QColor("green");
|
|
||||||
m_hideColor = QColor("red");
|
|
||||||
} else {
|
|
||||||
m_showColor = QColor(Qt::transparent);
|
m_showColor = QColor(Qt::transparent);
|
||||||
m_hideColor = QColor(Qt::transparent);
|
m_hideColor = QColor(Qt::transparent);
|
||||||
|
|
||||||
m_showColor.setAlpha(0);
|
|
||||||
m_hideColor.setAlpha(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
setColor(m_showColor);
|
setColor(m_showColor);
|
||||||
setDefaultAlphaBuffer(true);
|
setDefaultAlphaBuffer(true);
|
||||||
|
|
||||||
@ -67,28 +60,18 @@ FloatingGapWindow::FloatingGapWindow(Latte::View *view) :
|
|||||||
|
|
||||||
m_fixGeometryTimer.setSingleShot(true);
|
m_fixGeometryTimer.setSingleShot(true);
|
||||||
m_fixGeometryTimer.setInterval(500);
|
m_fixGeometryTimer.setInterval(500);
|
||||||
connect(&m_fixGeometryTimer, &QTimer::timeout, this, &FloatingGapWindow::fixGeometry);
|
connect(&m_fixGeometryTimer, &QTimer::timeout, this, &SubWindow::fixGeometry);
|
||||||
|
|
||||||
//! this timer is used in order to identify if mouse is still present in sensitive floating
|
connect(this, &QQuickView::xChanged, this, &SubWindow::startGeometryTimer);
|
||||||
//! areas and in such case to prevent a real-floating view to hide itself
|
connect(this, &QQuickView::yChanged, this, &SubWindow::startGeometryTimer);
|
||||||
m_asyncMouseTimer.setSingleShot(true);
|
connect(this, &QQuickView::widthChanged, this, &SubWindow::startGeometryTimer);
|
||||||
m_asyncMouseTimer.setInterval(200);
|
connect(this, &QQuickView::heightChanged, this, &SubWindow::startGeometryTimer);
|
||||||
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, &SubWindow::calculatedGeometryChanged, this, &SubWindow::fixGeometry);
|
||||||
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::absoluteGeometryChanged, this, &SubWindow::updateGeometry);
|
||||||
connect(m_latteView, &Latte::View::screenGeometryChanged, this, &FloatingGapWindow::updateGeometry);
|
connect(m_latteView, &Latte::View::screenGeometryChanged, this, &SubWindow::updateGeometry);
|
||||||
connect(m_latteView, &Latte::View::locationChanged, this, &FloatingGapWindow::updateGeometry);
|
connect(m_latteView, &Latte::View::locationChanged, this, &SubWindow::updateGeometry);
|
||||||
connect(m_latteView, &QQuickView::screenChanged, this, [this]() {
|
connect(m_latteView, &QQuickView::screenChanged, this, [this]() {
|
||||||
setScreen(m_latteView->screen());
|
setScreen(m_latteView->screen());
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
@ -117,9 +100,9 @@ FloatingGapWindow::FloatingGapWindow(Latte::View *view) :
|
|||||||
if (!m_inDelete && m_latteView && m_latteView->layout() && !isVisible()) {
|
if (!m_inDelete && m_latteView && m_latteView->layout() && !isVisible()) {
|
||||||
show();
|
show();
|
||||||
emit forcedShown();
|
emit forcedShown();
|
||||||
//qDebug() << "Floating Gap:: Enforce reshow from timer 1...";
|
//qDebug() << m_debugType + ":: Enforce reshow from timer 1...";
|
||||||
} else {
|
} else {
|
||||||
//qDebug() << "Floating Gap:: No needed reshow from timer 1...";
|
//qDebug() << m_debugType + ":: No needed reshow from timer 1...";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -127,13 +110,13 @@ FloatingGapWindow::FloatingGapWindow(Latte::View *view) :
|
|||||||
if (!m_inDelete && m_latteView && m_latteView->layout() && !isVisible()) {
|
if (!m_inDelete && m_latteView && m_latteView->layout() && !isVisible()) {
|
||||||
show();
|
show();
|
||||||
emit forcedShown();
|
emit forcedShown();
|
||||||
//qDebug() << "Floating Gap:: Enforce reshow from timer 2...";
|
//qDebug() << m_debugType + ":: Enforce reshow from timer 2...";
|
||||||
} else {
|
} else {
|
||||||
//qDebug() << "Floating Gap:: No needed reshow from timer 2...";
|
//qDebug() << m_debugType + ":: No needed reshow from timer 2...";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connectionsHack << connect(this, &FloatingGapWindow::forcedShown, this, [&]() {
|
connectionsHack << connect(this, &SubWindow::forcedShown, this, [&]() {
|
||||||
m_corona->wm()->unregisterIgnoredWindow(m_trackedWindowId);
|
m_corona->wm()->unregisterIgnoredWindow(m_trackedWindowId);
|
||||||
m_trackedWindowId = winId();
|
m_trackedWindowId = winId();
|
||||||
m_corona->wm()->registerIgnoredWindow(m_trackedWindowId);
|
m_corona->wm()->registerIgnoredWindow(m_trackedWindowId);
|
||||||
@ -156,11 +139,10 @@ FloatingGapWindow::FloatingGapWindow(Latte::View *view) :
|
|||||||
|
|
||||||
setScreen(m_latteView->screen());
|
setScreen(m_latteView->screen());
|
||||||
show();
|
show();
|
||||||
updateGeometry();
|
|
||||||
hideWithMask();
|
hideWithMask();
|
||||||
}
|
}
|
||||||
|
|
||||||
FloatingGapWindow::~FloatingGapWindow()
|
SubWindow::~SubWindow()
|
||||||
{
|
{
|
||||||
m_inDelete = true;
|
m_inDelete = true;
|
||||||
|
|
||||||
@ -180,70 +162,27 @@ FloatingGapWindow::~FloatingGapWindow()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int FloatingGapWindow::location()
|
int SubWindow::location()
|
||||||
{
|
{
|
||||||
return (int)m_latteView->location();
|
return (int)m_latteView->location();
|
||||||
}
|
}
|
||||||
|
|
||||||
int FloatingGapWindow::thickness() const
|
int SubWindow::thickness() const
|
||||||
{
|
{
|
||||||
return m_thickness;
|
return m_thickness;
|
||||||
}
|
}
|
||||||
|
|
||||||
Latte::View *FloatingGapWindow::parentView()
|
Latte::View *SubWindow::parentView()
|
||||||
{
|
{
|
||||||
return m_latteView;
|
return m_latteView;
|
||||||
}
|
}
|
||||||
|
|
||||||
KWayland::Client::PlasmaShellSurface *FloatingGapWindow::surface()
|
KWayland::Client::PlasmaShellSurface *SubWindow::surface()
|
||||||
{
|
{
|
||||||
return m_shellSurface;
|
return m_shellSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FloatingGapWindow::updateGeometry()
|
void SubWindow::fixGeometry()
|
||||||
{
|
|
||||||
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()
|
if (!m_calculatedGeometry.isEmpty()
|
||||||
&& (m_calculatedGeometry.x() != x() || m_calculatedGeometry.y() != y()
|
&& (m_calculatedGeometry.x() != x() || m_calculatedGeometry.y() != y()
|
||||||
@ -259,12 +198,12 @@ void FloatingGapWindow::fixGeometry()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FloatingGapWindow::startGeometryTimer()
|
void SubWindow::startGeometryTimer()
|
||||||
{
|
{
|
||||||
m_fixGeometryTimer.start();
|
m_fixGeometryTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FloatingGapWindow::setupWaylandIntegration()
|
void SubWindow::setupWaylandIntegration()
|
||||||
{
|
{
|
||||||
if (m_shellSurface || !KWindowSystem::isPlatformWayland() || !m_latteView || !m_latteView->containment()) {
|
if (m_shellSurface || !KWindowSystem::isPlatformWayland() || !m_latteView || !m_latteView->containment()) {
|
||||||
// already setup
|
// already setup
|
||||||
@ -294,64 +233,20 @@ void FloatingGapWindow::setupWaylandIntegration()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FloatingGapWindow::containsMouse() const
|
bool SubWindow::event(QEvent *e)
|
||||||
{
|
{
|
||||||
return m_containsMouse;
|
if (e->type() == QEvent::Show) {
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
m_corona->wm()->setViewExtraFlags(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return QQuickView::event(e);
|
return QQuickView::event(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FloatingGapWindow::callAsyncContainsMouse()
|
|
||||||
{
|
|
||||||
m_inAsyncContainsMouse = true;
|
|
||||||
m_asyncMouseTimer.start();
|
|
||||||
showWithMask();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FloatingGapWindow::triggerAsyncContainsMouseSignals()
|
void SubWindow::hideWithMask()
|
||||||
{
|
|
||||||
if (!m_inAsyncContainsMouse) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! this function is called QEvent::Enter
|
|
||||||
m_asyncMouseTimer.stop();
|
|
||||||
hideWithMask();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FloatingGapWindow::hideWithMask()
|
|
||||||
{
|
{
|
||||||
if (m_debugMode) {
|
if (m_debugMode) {
|
||||||
qDebug() << " Floating Gap Window :: MASK HIDE...";
|
qDebug() << m_debugType + " :: MASK HIDE...";
|
||||||
}
|
}
|
||||||
|
|
||||||
//! old values: 0,0,1,1 were blocking the top-left corner of the window
|
//! old values: 0,0,1,1 were blocking the top-left corner of the window
|
||||||
@ -362,10 +257,10 @@ void FloatingGapWindow::hideWithMask()
|
|||||||
setColor(m_hideColor);
|
setColor(m_hideColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FloatingGapWindow::showWithMask()
|
void SubWindow::showWithMask()
|
||||||
{
|
{
|
||||||
if (m_debugMode) {
|
if (m_debugMode) {
|
||||||
qDebug() << " Floating Gap Window :: MAKS SHOW...";
|
qDebug() << m_debugType + " :: MASK SHOW...";
|
||||||
}
|
}
|
||||||
|
|
||||||
setMask(QRegion());
|
setMask(QRegion());
|
121
app/view/helpers/subwindow.h
Normal file
121
app/view/helpers/subwindow.h
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* 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 VIEWSUBWINDOW_H
|
||||||
|
#define VIEWSUBWINDOW_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 provide a common window base for ViewPart::Helpers
|
||||||
|
|
||||||
|
class SubWindow : public QQuickView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SubWindow(Latte::View *view, QString debugType);
|
||||||
|
~SubWindow() override;
|
||||||
|
|
||||||
|
int location();
|
||||||
|
int thickness() const;
|
||||||
|
|
||||||
|
void hideWithMask();
|
||||||
|
void showWithMask();
|
||||||
|
|
||||||
|
Latte::View *parentView();
|
||||||
|
|
||||||
|
KWayland::Client::PlasmaShellSurface *surface();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void forcedShown(); //[workaround] forced shown to avoid a KWin issue that hides windows when activities are stopped
|
||||||
|
void calculatedGeometryChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool event(QEvent *ev) override;
|
||||||
|
|
||||||
|
//! it is used to update m_calculatedGeometry correctly
|
||||||
|
virtual void updateGeometry() = 0;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void startGeometryTimer();
|
||||||
|
void fixGeometry();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupWaylandIntegration();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool m_debugMode{false};
|
||||||
|
bool m_inDelete{false};
|
||||||
|
|
||||||
|
int m_thickness{2};
|
||||||
|
|
||||||
|
QString m_debugType;
|
||||||
|
|
||||||
|
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_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
|
@ -1,356 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2018 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 "screenedgeghostwindow.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 {
|
|
||||||
|
|
||||||
ScreenEdgeGhostWindow::ScreenEdgeGhostWindow(Latte::View *view) :
|
|
||||||
m_latteView(view)
|
|
||||||
{
|
|
||||||
m_corona = qobject_cast<Latte::Corona *>(view->corona());
|
|
||||||
|
|
||||||
bool debugEdge = (qApp->arguments().contains("-d") && qApp->arguments().contains("--kwinedges"));
|
|
||||||
|
|
||||||
setColor(debugEdge ? QColor("purple") : QColor(Qt::transparent));
|
|
||||||
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, &ScreenEdgeGhostWindow::fixGeometry);
|
|
||||||
|
|
||||||
//! this timer is used in order to avoid fast enter/exit signals during first
|
|
||||||
//! appearing after edge activation
|
|
||||||
m_delayedMouseTimer.setSingleShot(true);
|
|
||||||
m_delayedMouseTimer.setInterval(50);
|
|
||||||
connect(&m_delayedMouseTimer, &QTimer::timeout, this, [this]() {
|
|
||||||
if (m_delayedContainsMouse) {
|
|
||||||
setContainsMouse(true);
|
|
||||||
} else {
|
|
||||||
setContainsMouse(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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_latteView, &Latte::View::absoluteGeometryChanged, this, &ScreenEdgeGhostWindow::updateGeometry);
|
|
||||||
connect(m_latteView, &Latte::View::screenGeometryChanged, this, &ScreenEdgeGhostWindow::updateGeometry);
|
|
||||||
connect(m_latteView, &Latte::View::locationChanged, this, &ScreenEdgeGhostWindow::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() << "Ghost Edge:: Enforce reshow from timer 1...";
|
|
||||||
} else {
|
|
||||||
//qDebug() << "Ghost Edge:: 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() << "Ghost Edge:: Enforce reshow from timer 2...";
|
|
||||||
} else {
|
|
||||||
//qDebug() << "Ghost Edge:: No needed reshow from timer 2...";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
connectionsHack << connect(this, &ScreenEdgeGhostWindow::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();
|
|
||||||
}
|
|
||||||
|
|
||||||
ScreenEdgeGhostWindow::~ScreenEdgeGhostWindow()
|
|
||||||
{
|
|
||||||
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 ScreenEdgeGhostWindow::location()
|
|
||||||
{
|
|
||||||
return (int)m_latteView->location();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ScreenEdgeGhostWindow::thickness() const
|
|
||||||
{
|
|
||||||
return m_thickness;
|
|
||||||
}
|
|
||||||
|
|
||||||
Latte::View *ScreenEdgeGhostWindow::parentView()
|
|
||||||
{
|
|
||||||
return m_latteView;
|
|
||||||
}
|
|
||||||
|
|
||||||
KWayland::Client::PlasmaShellSurface *ScreenEdgeGhostWindow::surface()
|
|
||||||
{
|
|
||||||
return m_shellSurface;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenEdgeGhostWindow::updateGeometry()
|
|
||||||
{
|
|
||||||
if (m_latteView->positioner()->slideOffset() != 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QRect newGeometry;
|
|
||||||
|
|
||||||
if (KWindowSystem::compositingActive()) {
|
|
||||||
m_thickness = 6;
|
|
||||||
} else {
|
|
||||||
m_thickness = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
int length{30};
|
|
||||||
int lengthDifference{0};
|
|
||||||
|
|
||||||
if (m_latteView->formFactor() == Plasma::Types::Horizontal) {
|
|
||||||
//! set minimum length to be 25% of screen width
|
|
||||||
length = qMax(m_latteView->screenGeometry().width()/4,qMin(m_latteView->absoluteGeometry().width(), m_latteView->screenGeometry().width() - 1));
|
|
||||||
lengthDifference = qMax(0,length - m_latteView->absoluteGeometry().width());
|
|
||||||
} else {
|
|
||||||
//! set minimum length to be 25% of screen height
|
|
||||||
length = qMax(m_latteView->screenGeometry().height()/4,qMin(m_latteView->absoluteGeometry().height(), m_latteView->screenGeometry().height() - 1));
|
|
||||||
lengthDifference = qMax(0,length - m_latteView->absoluteGeometry().height());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_latteView->location() == Plasma::Types::BottomEdge) {
|
|
||||||
int xF = qMax(m_latteView->screenGeometry().left(), m_latteView->absoluteGeometry().left() - lengthDifference);
|
|
||||||
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() - lengthDifference);
|
|
||||||
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() - lengthDifference);
|
|
||||||
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() - lengthDifference);
|
|
||||||
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 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_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 ScreenEdgeGhostWindow::containsMouse() const
|
|
||||||
{
|
|
||||||
return m_containsMouse;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenEdgeGhostWindow::setContainsMouse(bool contains)
|
|
||||||
{
|
|
||||||
if (m_containsMouse == contains) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_containsMouse = contains;
|
|
||||||
emit containsMouseChanged(contains);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ScreenEdgeGhostWindow::event(QEvent *e)
|
|
||||||
{
|
|
||||||
if (e->type() == QEvent::DragEnter || e->type() == QEvent::DragMove) {
|
|
||||||
if (!m_containsMouse) {
|
|
||||||
m_delayedContainsMouse = false;
|
|
||||||
m_delayedMouseTimer.stop();
|
|
||||||
setContainsMouse(true);
|
|
||||||
emit dragEntered();
|
|
||||||
}
|
|
||||||
} else if (e->type() == QEvent::Enter) {
|
|
||||||
m_delayedContainsMouse = true;
|
|
||||||
if (!m_delayedMouseTimer.isActive()) {
|
|
||||||
m_delayedMouseTimer.start();
|
|
||||||
}
|
|
||||||
} else if (e->type() == QEvent::Leave || e->type() == QEvent::DragLeave) {
|
|
||||||
m_delayedContainsMouse = false;
|
|
||||||
if (!m_delayedMouseTimer.isActive()) {
|
|
||||||
m_delayedMouseTimer.start();
|
|
||||||
}
|
|
||||||
} else if (e->type() == QEvent::Show) {
|
|
||||||
m_corona->wm()->setViewExtraFlags(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return QQuickView::event(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenEdgeGhostWindow::hideWithMask()
|
|
||||||
{
|
|
||||||
//! old values: 0,0,1,1 were blocking the top-left corner of the window
|
|
||||||
QRect maskGeometry{-2, 0, 1, 1};
|
|
||||||
|
|
||||||
setMask(maskGeometry);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenEdgeGhostWindow::showWithMask()
|
|
||||||
{
|
|
||||||
setMask(QRect());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -22,9 +22,9 @@
|
|||||||
|
|
||||||
// local
|
// local
|
||||||
#include "positioner.h"
|
#include "positioner.h"
|
||||||
#include "floatinggapwindow.h"
|
|
||||||
#include "screenedgeghostwindow.h"
|
|
||||||
#include "view.h"
|
#include "view.h"
|
||||||
|
#include "helpers/floatinggapwindow.h"
|
||||||
|
#include "helpers/screenedgeghostwindow.h"
|
||||||
#include "windowstracker/currentscreentracker.h"
|
#include "windowstracker/currentscreentracker.h"
|
||||||
#include "../lattecorona.h"
|
#include "../lattecorona.h"
|
||||||
#include "../screenpool.h"
|
#include "../screenpool.h"
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
|
|
||||||
// local
|
// local
|
||||||
#include "view/positioner.h"
|
#include "view/positioner.h"
|
||||||
#include "view/screenedgeghostwindow.h"
|
|
||||||
#include "view/view.h"
|
#include "view/view.h"
|
||||||
|
#include "view/helpers/screenedgeghostwindow.h"
|
||||||
#include "../lattecorona.h"
|
#include "../lattecorona.h"
|
||||||
#include "../../liblatte2/extras.h"
|
#include "../../liblatte2/extras.h"
|
||||||
#include "../../liblatte2/types.h"
|
#include "../../liblatte2/types.h"
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
|
|
||||||
// local
|
// local
|
||||||
#include "tasktools.h"
|
#include "tasktools.h"
|
||||||
#include "view/screenedgeghostwindow.h"
|
|
||||||
#include "view/view.h"
|
#include "view/view.h"
|
||||||
|
#include "view/helpers/screenedgeghostwindow.h"
|
||||||
#include "../../liblatte2/extras.h"
|
#include "../../liblatte2/extras.h"
|
||||||
#include "../../liblatte2/types.h"
|
#include "../../liblatte2/types.h"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user