diff --git a/CMakeLists.txt b/CMakeLists.txt
index f9f8867..1cd1d55 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,8 +10,8 @@ set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
-set(QT Core Widgets Concurrent Quick QuickControls2 X11Extras DBus Svg LinguistTools)
-find_package(Qt5 REQUIRED ${QT})
+find_package(Qt5 CONFIG REQUIRED Widgets DBus X11Extras Concurrent Svg LinguistTools QuickControls2)
+
find_package(KF5WindowSystem REQUIRED)
find_package(dbusmenu-qt5 REQUIRED)
find_package(MeuiKit REQUIRED)
@@ -33,7 +33,7 @@ set(SRCS
src/volumemanager.cpp
src/utils.cpp
src/xwindowinterface.cpp
- src/toplevelmenu.cpp
+ src/popupwindow.cpp
src/appearance.cpp
src/fakewindow.cpp
@@ -68,7 +68,7 @@ qt5_add_dbus_adaptor(SRCS src/systemtray/org.kde.StatusNotifierWatcher.xml
src/systemtray/statusnotifierwatcher.h StatusNotifierWatcher)
add_executable(${PROJECT_NAME} ${SRCS} ${DBUS_SRCS} ${RESOURCES})
-target_link_libraries(${PROJECT_NAME}
+target_link_libraries(${PROJECT_NAME} PRIVATE
Qt5::Core
Qt5::Widgets
Qt5::Quick
diff --git a/qml/AppItem.qml b/qml/AppItem.qml
index a86bddd..0324a51 100644
--- a/qml/AppItem.qml
+++ b/qml/AppItem.qml
@@ -23,7 +23,7 @@ DockItem {
onPositionChanged: updateGeometry()
onPressed: updateGeometry()
onClicked: appModel.clicked(model.appId)
- onRightClicked: if (model.appId !== "cutefish-launcher") contextMenu.open()
+ onRightClicked: if (model.appId !== "cutefish-launcher") contextMenu.show()
dropArea.onEntered: {
if (drag.source)
@@ -37,7 +37,7 @@ DockItem {
updateGeometry()
}
- TopLevelMenu {
+ DockMenu {
id: contextMenu
MenuItem {
diff --git a/qml/DockMenu.qml b/qml/DockMenu.qml
new file mode 100644
index 0000000..c1c594d
--- /dev/null
+++ b/qml/DockMenu.qml
@@ -0,0 +1,43 @@
+import QtQuick 2.12
+import QtQuick.Layouts 1.12
+import QtQuick.Controls 2.12
+import Cutefish.Dock 1.0
+import MeuiKit 1.0 as Meui
+
+PopupWindow {
+ id: control
+
+ default property alias content : _mainLayout.data
+
+ Rectangle {
+ id: _background
+ anchors.fill: parent
+ opacity: 0.6
+ color: Meui.Theme.backgroundColor
+ radius: Meui.Theme.mediumRadius
+
+ Meui.WindowShadow {
+ view: control
+ geometry: Qt.rect(control.x, control.y, control.width, control.height)
+ radius: _background.radius
+ }
+
+ Meui.WindowBlur {
+ view: control
+ geometry: Qt.rect(control.x, control.y, control.width, control.height)
+ windowRadius: _background.radius
+ enabled: true
+ }
+ }
+
+ ColumnLayout {
+ id: _mainLayout
+ anchors.fill: parent
+ anchors.topMargin: 8
+ anchors.bottomMargin: 8
+ }
+
+ function open() {
+ control.show()
+ }
+}
diff --git a/qml/TopLevelMenu.qml b/qml/TopLevelMenu.qml
deleted file mode 100644
index 777faad..0000000
--- a/qml/TopLevelMenu.qml
+++ /dev/null
@@ -1,32 +0,0 @@
-import QtQuick 2.12
-import QtQuick.Controls 2.12
-import QtQuick.Window 2.12
-import QtQuick.Layouts 1.12
-
-Window {
- id: control
- visible: false
-
- width: _mainLayout.implicitWidth
- height: _mainLayout.implicitHeight
-
- flags: Qt.Popup
-
- onActiveChanged: {
- if (!active)
- control.close()
- }
-
- default property alias content: _mainLayout.data
-
- function open() {
- control.visible = true
- control.x = 500
- control.y = 500
- }
-
- ColumnLayout {
- id: _mainLayout
- anchors.fill: parent
- }
-}
diff --git a/resources.qrc b/resources.qrc
index a68d34f..31dbcec 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -102,6 +102,6 @@
svg/light/dark-mode.svg
svg/dark/dark-mode.svg
svg/dark/bluetooth-symbolic.svg
- qml/TopLevelMenu.qml
+ qml/DockMenu.qml
diff --git a/src/main.cpp b/src/main.cpp
index 63e9c1c..24d8ef1 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -33,6 +33,7 @@
#include "systemtray/systemtraymodel.h"
#include "appearance.h"
#include "iconitem.h"
+#include "popupwindow.h"
int main(int argc, char *argv[])
{
@@ -47,6 +48,7 @@ int main(int argc, char *argv[])
qmlRegisterType("Cutefish.Dock", 1, 0, "SystemTrayModel");
qmlRegisterType("Cutefish.Dock", 1, 0, "Appearance");
qmlRegisterType("Cutefish.Dock", 1, 0, "IconItem");
+ qmlRegisterType("Cutefish.Dock", 1, 0, "PopupWindow");
QString qmFilePath = QString("%1/%2.qm").arg("/usr/share/cutefish-dock/translations/").arg(QLocale::system().name());
if (QFile::exists(qmFilePath)) {
diff --git a/src/popupwindow.cpp b/src/popupwindow.cpp
new file mode 100644
index 0000000..d1aeba8
--- /dev/null
+++ b/src/popupwindow.cpp
@@ -0,0 +1,129 @@
+#include "popupwindow.h"
+#include
+#include
+#include
+#include
+
+PopupWindow::PopupWindow(QQuickWindow *parent)
+ : QQuickWindow(parent)
+ , m_parentItem(0)
+ , m_contentItem(0)
+ , m_mouseMoved(false)
+ , m_dismissed(false)
+{
+ setFlags(Qt::Popup);
+ setColor(Qt::transparent);
+ connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
+ this, SLOT(applicationStateChanged(Qt::ApplicationState)));
+}
+
+void PopupWindow::applicationStateChanged(Qt::ApplicationState state)
+{
+ if (state != Qt::ApplicationActive)
+ dismissPopup();
+}
+
+void PopupWindow::show()
+{
+ QPoint pos = QCursor::pos();
+ int w = m_contentItem->implicitWidth();
+ int h = m_contentItem->implicitHeight() + 16;
+ int posx = pos.x();
+ int posy = pos.y();
+
+ QWindow *pw = transientParent();
+ if (!pw && parentItem())
+ pw = parentItem()->window();
+ if (!pw)
+ pw = this;
+
+ QRect g = pw->screen()->availableGeometry();
+
+ if (posx + w > g.right()) {
+ if (qobject_cast(transientParent())) {
+ // reposition submenu window on the parent menu's left side
+ int submenuOverlap = pw->x() + pw->width() - posx;
+ posx -= pw->width() + w - 2 * submenuOverlap;
+ } else {
+ posx = g.right() - w;
+ }
+ } else {
+ posx = qMax(posx, g.left());
+ }
+
+ posy = qBound(g.top(), posy, g.bottom() - h);
+
+ setGeometry(posx, posy, w, h);
+
+ QQuickWindow::show();
+ setMouseGrabEnabled(true);
+ setKeyboardGrabEnabled(true);
+}
+
+void PopupWindow::setParentItem(QQuickItem *item)
+{
+ m_parentItem = item;
+ if (m_parentItem)
+ setTransientParent(m_parentItem->window());
+}
+
+void PopupWindow::setPopupContentItem(QQuickItem *contentItem)
+{
+ if (!contentItem)
+ return;
+
+ contentItem->setParentItem(this->contentItem());
+ m_contentItem = contentItem;
+}
+
+void PopupWindow::dismissPopup()
+{
+ m_dismissed = true;
+ emit popupDismissed();
+ hide();
+}
+
+void PopupWindow::mouseMoveEvent(QMouseEvent *e)
+{
+ QQuickWindow::mouseMoveEvent(e);
+}
+
+void PopupWindow::mousePressEvent(QMouseEvent *e)
+{
+ QRect rect = QRect(QPoint(), size());
+ if (rect.contains(e->pos())) {
+ QQuickWindow::mousePressEvent(e);
+ } else {
+ dismissPopup();
+ }
+}
+
+void PopupWindow::mouseReleaseEvent(QMouseEvent *e)
+{
+ QQuickWindow::mouseReleaseEvent(e);
+ dismissPopup();
+}
+
+bool PopupWindow::event(QEvent *event)
+{
+ //QTBUG-45079
+ //This is a workaround for popup menu not being closed when using touch input.
+ //Currently mouse synthesized events are not created for touch events which are
+ //outside the qquickwindow.
+
+ if (event->type() == QEvent::TouchBegin && !qobject_cast(transientParent())) {
+ QRect rect = QRect(QPoint(), size());
+ QTouchEvent *touch = static_cast(event);
+ QTouchEvent::TouchPoint point = touch->touchPoints().first();
+ if ((point.state() == Qt::TouchPointPressed) && !rect.contains(point.pos().toPoint())) {
+ //first default handling
+ bool result = QQuickWindow::event(event);
+ //now specific broken case
+ if (!m_dismissed)
+ dismissPopup();
+ return result;
+ }
+ }
+
+ return QQuickWindow::event(event);
+}
diff --git a/src/popupwindow.h b/src/popupwindow.h
new file mode 100644
index 0000000..e18658d
--- /dev/null
+++ b/src/popupwindow.h
@@ -0,0 +1,46 @@
+#ifndef TOPLEVELMENU_H
+#define TOPLEVELMENU_H
+
+#include
+
+class PopupWindow : public QQuickWindow
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickItem *popupContentItem READ popupContentItem WRITE setPopupContentItem)
+ Q_CLASSINFO("DefaultProperty", "popupContentItem")
+ Q_PROPERTY(QQuickItem *parentItem READ parentItem WRITE setParentItem)
+
+public:
+ PopupWindow(QQuickWindow *parent = nullptr);
+
+ QQuickItem *popupContentItem() const { return m_contentItem; }
+ void setPopupContentItem(QQuickItem *popupContentItem);
+
+ QQuickItem *parentItem() const { return m_parentItem; }
+ virtual void setParentItem(QQuickItem *);
+
+public slots:
+ void show();
+ void dismissPopup();
+
+signals:
+ void popupDismissed();
+ void geometryChanged();
+
+protected:
+ void mousePressEvent(QMouseEvent *) override;
+ void mouseReleaseEvent(QMouseEvent *) override;
+ void mouseMoveEvent(QMouseEvent *) override;
+ bool event(QEvent *) override;
+
+protected slots:
+ void applicationStateChanged(Qt::ApplicationState state);
+
+private:
+ QQuickItem *m_parentItem;
+ QPointer m_contentItem;
+ bool m_mouseMoved;
+ bool m_dismissed;
+};
+
+#endif // POPUPWINDOW_H
diff --git a/src/toplevelmenu.cpp b/src/toplevelmenu.cpp
deleted file mode 100644
index 8486119..0000000
--- a/src/toplevelmenu.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "toplevelmenu.h"
-
-TopLevelMenu::TopLevelMenu(QQuickView *parent)
- : QQuickView(parent)
-{
- setFlags(Qt::Popup);
-}
diff --git a/src/toplevelmenu.h b/src/toplevelmenu.h
deleted file mode 100644
index c7e5fa4..0000000
--- a/src/toplevelmenu.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef TOPLEVELMENU_H
-#define TOPLEVELMENU_H
-
-#include
-
-class TopLevelMenu : public QQuickView
-{
- Q_OBJECT
-
-public:
- explicit TopLevelMenu(QQuickView *parent = nullptr);
-
-signals:
-
-};
-
-#endif // TOPLEVELMENU_H