From a9cc94809936c08790f8143bf7518e0e4102db51 Mon Sep 17 00:00:00 2001 From: Martchus Date: Fri, 6 Oct 2023 17:02:40 +0200 Subject: [PATCH] Allow resizing/moving tray widget This might be useful on Wayland where positioning the popup is otherwise not possible at all. Combined with a session restoration mechanism this might actually be a feasible workaround. The user just needed to position the popup once wherever it is wanted to show up and then the compositor could remember that position. Especially the resizing would also be useful on other platforms (and is by the way also already possible when using the Plasmoid showing it as part of the system tray Plasmoid). --- tray/gui/traymenu.cpp | 42 +++++++++++++++++++++++++++++++++++++++--- tray/gui/traymenu.h | 1 + 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/tray/gui/traymenu.cpp b/tray/gui/traymenu.cpp index 0ce31a4..00b524d 100644 --- a/tray/gui/traymenu.cpp +++ b/tray/gui/traymenu.cpp @@ -12,14 +12,21 @@ #include #include +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) +#define QT_SUPPORTS_SYSTEM_WINDOW_COMMANDS +#endif + using namespace QtUtilities; namespace QtGui { +static constexpr auto border = 10; + TrayMenu::TrayMenu(TrayIcon *trayIcon, QWidget *parent) : QMenu(parent) , m_trayIcon(trayIcon) , m_windowType(WindowType::Popup) + , m_startedSystemWindowCommand(false) { setObjectName(QStringLiteral("QtGui::TrayMenu")); auto *const menuLayout = new QHBoxLayout; @@ -41,7 +48,7 @@ QSize TrayMenu::sizeHint() const * \brief Moves the specified \a innerRect at the specified \a point into the specified \a outerRect * by altering \a point. */ -void moveInside(QPoint &point, const QSize &innerRect, const QRect &outerRect) +static void moveInside(QPoint &point, const QSize &innerRect, const QRect &outerRect) { if (point.y() < outerRect.top()) { point.setY(outerRect.top()); @@ -97,14 +104,43 @@ void TrayMenu::setWindowType(WindowType windowType) void TrayMenu::mousePressEvent(QMouseEvent *event) { - if (m_windowType != TrayMenu::WindowType::NormalWindow) { + // skip any special behavior if the tray menu is shown as a regular window + if (m_windowType == TrayMenu::WindowType::NormalWindow) { + return; + } + + // try starting a system window resize/move to allow resizing/moving the borderless window +#ifdef QT_SUPPORTS_SYSTEM_WINDOW_COMMANDS + if (auto *const window = this->windowHandle()) { + const auto pos = event->pos(); + auto edges = Qt::Edges(); + if (pos.x() < border) + edges |= Qt::LeftEdge; + if (pos.x() >= width() - border) + edges |= Qt::RightEdge; + if (pos.y() < border) + edges |= Qt::TopEdge; + if (pos.y() >= height() - border) + edges |= Qt::BottomEdge; + m_startedSystemWindowCommand = edges ? window->startSystemResize(edges) : window->startSystemMove(); + } +#endif + + // fallback to the default behavior for the current window type if system window resize/move is not possible + if (!m_startedSystemWindowCommand) { QMenu::mousePressEvent(event); } } void TrayMenu::mouseReleaseEvent(QMouseEvent *event) { - if (m_windowType != TrayMenu::WindowType::NormalWindow) { + // cover cases analogous to TrayMenu::mousePressEvent() + if (m_windowType == TrayMenu::WindowType::NormalWindow) { + return; + } + if (m_startedSystemWindowCommand) { + m_startedSystemWindowCommand = false; + } else { QMenu::mouseReleaseEvent(event); } } diff --git a/tray/gui/traymenu.h b/tray/gui/traymenu.h index ba835be..70bfa01 100644 --- a/tray/gui/traymenu.h +++ b/tray/gui/traymenu.h @@ -41,6 +41,7 @@ private: TrayWidget *m_trayWidget; TrayIcon *m_trayIcon; WindowType m_windowType; + bool m_startedSystemWindowCommand; }; inline TrayWidget &TrayMenu::widget()