[vlc-commits] [Git][videolan/vlc][master] 5 commits: qt: implement System Menu Button in CSDButtonModel
Steve Lhomme (@robUx4)
gitlab at videolan.org
Thu Jan 26 15:40:23 UTC 2023
Steve Lhomme pushed to branch master at VideoLAN / VLC
Commits:
dff96634 by Prince Gupta at 2023-01-26T15:15:53+00:00
qt: implement System Menu Button in CSDButtonModel
- - - - -
cc82771e by Prince Gupta at 2023-01-26T15:15:53+00:00
qt: provide CSD system menu button on windows
- - - - -
6afdbe34 by Prince Gupta at 2023-01-26T15:15:53+00:00
qml: implement BannerCone
- - - - -
139dc4cd by Prince Gupta at 2023-01-26T15:15:53+00:00
qml: use BannerCone widget in main view banner
widget handles sys menu button with CSD
- - - - -
a17b8d5b by Prince Gupta at 2023-01-26T15:15:53+00:00
qml: use BannerCone widget in TopBar
widget handles sys menu button with CSD
- - - - -
8 changed files:
- modules/gui/qt/Makefile.am
- modules/gui/qt/maininterface/mainctx_win32.cpp
- modules/gui/qt/maininterface/qml/BannerSources.qml
- modules/gui/qt/player/qml/TopBar.qml
- modules/gui/qt/util/csdbuttonmodel.cpp
- modules/gui/qt/util/csdbuttonmodel.hpp
- modules/gui/qt/vlc.qrc
- + modules/gui/qt/widgets/qml/BannerCone.qml
Changes:
=====================================
modules/gui/qt/Makefile.am
=====================================
@@ -982,6 +982,7 @@ libqt_plugin_la_QML = \
gui/qt/widgets/qml/ActionButtonOverlay.qml \
gui/qt/widgets/qml/ActionButtonPrimary.qml \
gui/qt/widgets/qml/BannerTabButton.qml \
+ gui/qt/widgets/qml/BannerCone.qml \
gui/qt/widgets/qml/BusyIndicatorExt.qml \
gui/qt/widgets/qml/CaptionLabel.qml \
gui/qt/widgets/qml/CheckButton.qml \
=====================================
modules/gui/qt/maininterface/mainctx_win32.cpp
=====================================
@@ -35,6 +35,7 @@
#include "util/csdbuttonmodel.hpp"
#include <QBitmap>
+#include <QTimer>
#include <assert.h>
@@ -114,6 +115,103 @@ HWND WinId( QWindow *windowHandle )
return 0;
}
+
+bool isWindowFixedSize(const QWindow *window)
+{
+ if (window->flags() & Qt::MSWindowsFixedSizeDialogHint)
+ return true;
+
+ const auto minSize = window->minimumSize();
+ const auto maxSize = window->maximumSize();
+
+ return minSize.isValid() && maxSize.isValid() && minSize == maxSize;
+}
+
+
+class WinSystemMenuButton : public SystemMenuButton
+{
+public:
+ WinSystemMenuButton(QWindow *window, QObject *parent)
+ : SystemMenuButton {parent}
+ , m_window {window}
+ {
+ connect(this, &CSDButton::clicked, this, &WinSystemMenuButton::handleClick);
+ connect(this, &CSDButton::doubleClicked, this, &WinSystemMenuButton::handleDoubleClick);
+ }
+
+ void showSystemMenu() override
+ {
+ HWND hwnd = (HWND)m_window->winId();
+ HMENU hmenu = ::GetSystemMenu(hwnd, FALSE);
+ if (!hmenu)
+ return;
+
+ // Tweak the menu items according to the current window status.
+ const auto winState = m_window->windowStates();
+ const bool maxOrFull = (winState.testFlag(Qt::WindowMaximized) || winState.testFlag(Qt::WindowFullScreen));
+ const bool fixedSize = isWindowFixedSize(m_window);
+
+ EnableMenuItem(hmenu, SC_MOVE, (MF_BYCOMMAND | (!maxOrFull ? MFS_ENABLED : MFS_DISABLED)));
+ EnableMenuItem(hmenu, SC_SIZE, (MF_BYCOMMAND | ((!maxOrFull && !fixedSize) ? MFS_ENABLED : MFS_DISABLED)));
+
+ EnableMenuItem(hmenu, SC_RESTORE, (MF_BYCOMMAND | ((maxOrFull && !fixedSize) ? MFS_ENABLED : MFS_DISABLED)));
+ EnableMenuItem(hmenu, SC_MINIMIZE, (MF_BYCOMMAND | MFS_ENABLED));
+ EnableMenuItem(hmenu, SC_MAXIMIZE, (MF_BYCOMMAND | ((!maxOrFull && !fixedSize) ? MFS_ENABLED : MFS_DISABLED)));
+ EnableMenuItem(hmenu, SC_CLOSE, (MF_BYCOMMAND | MFS_ENABLED));
+
+ // calculate screen point 'margin' down from system menu button's rect
+ const QPoint margin {0, 4};
+ const auto bottomLeft = rect().bottomLeft();
+ const auto screenPoints = m_window->mapToGlobal(bottomLeft) + margin;
+
+ const auto alignment = (QGuiApplication::isRightToLeft() ? TPM_RIGHTALIGN : TPM_LEFTALIGN);
+
+ // show menu
+ emit systemMenuVisibilityChanged(true);
+
+ const int action = TrackPopupMenu(hmenu, (TPM_RETURNCMD | alignment)
+ , screenPoints.x(), screenPoints.y()
+ , NULL, hwnd, 0);
+
+ // unlike native system menu which sends WM_SYSCOMMAND, TrackPopupMenu sends WM_COMMAND
+ // imitate native system menu by sending the action manually as WM_SYSCOMMAND
+ PostMessageW(hwnd, WM_SYSCOMMAND, action, 0);
+
+ emit systemMenuVisibilityChanged(false);
+ }
+
+private:
+ // target window
+ QWindow *m_window = {};
+
+ // used to reject click() incase a doubleClick() is followed
+ bool m_triggerSystemMenu = false;
+
+ void handleClick()
+ {
+ // delay the show of sytem menu to check if this 'click' is
+ // a double click, 'm_triggerSystemMenu' is used to reject the
+ // queued 'showSystemMenu' call in case this is a double click
+
+ m_triggerSystemMenu = true;
+ QTimer::singleShot(100, this, [this]()
+ {
+ if (!m_triggerSystemMenu)
+ return;
+
+ showSystemMenu();
+ });
+ }
+
+ void handleDoubleClick()
+ {
+ // reject any queued showSystemMenu call
+ m_triggerSystemMenu = false;
+
+ m_window->close();
+ }
+};
+
class CSDWin32EventHandler : public QObject, public QAbstractNativeEventFilter
{
public:
@@ -654,6 +752,9 @@ InterfaceWindowHandlerWin32::InterfaceWindowHandlerWin32(qt_intf_t *_p_intf, Mai
#endif
{
+ auto systemMenuButton = std::make_shared<WinSystemMenuButton>(mainCtx->intfMainWindow(), nullptr);
+ mainCtx->csdButtonModel()->setSystemMenuButton(systemMenuButton);
+
QApplication::instance()->installNativeEventFilter(this);
}
=====================================
modules/gui/qt/maininterface/qml/BannerSources.qml
=====================================
@@ -160,17 +160,11 @@ FocusScope {
Navigation.parentItem: root
Navigation.rightItem: globalMenuGroup
Navigation.downItem: localMenuGroup.visible ? localMenuGroup : localToolbarBg
- }
-
- Image {
- sourceSize.width: VLCStyle.icon_normal
- sourceSize.height: VLCStyle.icon_normal
- source: SVGColorImage.colorize("qrc:///misc/cone.svg")
- .accent(VLCStyle.colors.accent)
- .uri()
- enabled: false
}
+ Widgets.BannerCone {
+
+ }
}
/* Button for the sources */
=====================================
modules/gui/qt/player/qml/TopBar.qml
=====================================
@@ -226,19 +226,20 @@ FocusScope{
onHoveredChanged: root.requestLockUnlockAutoHide(hovered)
}
- Image {
+ Widgets.BannerCone {
id: logo
anchors.verticalCenter: parent.verticalCenter
anchors.left: backBtn.right
anchors.leftMargin: VLCStyle.margin_xxsmall
- sourceSize.width: VLCStyle.icon_normal
- sourceSize.height: VLCStyle.icon_normal
- source: SVGColorImage.colorize("qrc:///misc/cone.svg")
- .accent(root.colors.accent)
- .uri()
- enabled: false
+ Connections {
+ target: logo.button
+
+ onSystemMenuVisibilityChanged: {
+ root.requestLockUnlockAutoHide(visible)
+ }
+ }
}
}
=====================================
modules/gui/qt/util/csdbuttonmodel.cpp
=====================================
@@ -67,6 +67,11 @@ void CSDButton::click()
emit clicked();
}
+void CSDButton::doubleClick()
+{
+ emit doubleClicked();
+}
+
CSDButtonModel::CSDButtonModel(MainCtx *mainCtx, QObject *parent)
: QObject {parent}
, m_mainCtx {mainCtx}
@@ -88,6 +93,17 @@ QList<CSDButton *> CSDButtonModel::windowCSDButtons() const
return m_windowCSDButtons;
}
+CSDButton *CSDButtonModel::systemMenuButton() const
+{
+ return m_systemMenuButton.get();
+}
+
+void CSDButtonModel::setSystemMenuButton(std::shared_ptr<SystemMenuButton> button)
+{
+ m_systemMenuButton = std::move(button);
+}
+
+
void CSDButtonModel::minimizeButtonClicked()
{
emit m_mainCtx->requestInterfaceMinimized();
=====================================
modules/gui/qt/util/csdbuttonmodel.hpp
=====================================
@@ -23,6 +23,7 @@
#include <QObject>
#include <QRect>
+#include <memory>
class CSDButton : public QObject
{
@@ -37,6 +38,7 @@ public:
Minimize,
MaximizeRestore,
Close,
+ SystemMenu,
TypeCount
};
@@ -61,12 +63,15 @@ public:
public slots:
// signals to perfrom action associated with button
+ // actions are dependent on implmentation
void click();
+ void doubleClick();
signals:
void showHoveredChanged();
void rectChanged();
void clicked();
+ void doubleClicked();
private:
const ButtonType m_type;
@@ -75,17 +80,39 @@ private:
};
+class SystemMenuButton : public CSDButton
+{
+ Q_OBJECT
+
+public:
+ SystemMenuButton(QObject *parent = nullptr) : CSDButton {SystemMenuButton::SystemMenu, parent} {}
+
+ virtual void showSystemMenu() = 0;
+
+signals:
+ void systemMenuVisibilityChanged(bool visible);
+};
+
+
class MainCtx;
+
class CSDButtonModel : public QObject
{
Q_OBJECT
Q_PROPERTY(QList<CSDButton *> windowCSDButtons READ windowCSDButtons CONSTANT)
+ Q_PROPERTY(CSDButton *systemMenuButton READ systemMenuButton CONSTANT)
+
public:
CSDButtonModel(MainCtx *mainCtx, QObject *parent = nullptr);
QList<CSDButton *> windowCSDButtons() const;
+ CSDButton *systemMenuButton() const;
+
+ // set by internal implmentation
+ // all the actions are also handled by implementation
+ void setSystemMenuButton(std::shared_ptr<SystemMenuButton> button);
private slots:
void minimizeButtonClicked();
@@ -94,7 +121,12 @@ private slots:
private:
MainCtx *m_mainCtx;
+
+ // CSD window action buttons i.e minimize, maximize, close
QList<CSDButton *> m_windowCSDButtons;
+
+ // sysmenu button, available on windows only
+ std::shared_ptr<SystemMenuButton> m_systemMenuButton = nullptr;
};
=====================================
modules/gui/qt/vlc.qrc
=====================================
@@ -155,6 +155,7 @@
<qresource prefix="/widgets">
<file alias="ActionButtonOverlay.qml">widgets/qml/ActionButtonOverlay.qml</file>
<file alias="ActionButtonPrimary.qml">widgets/qml/ActionButtonPrimary.qml</file>
+ <file alias="BannerCone.qml">widgets/qml/BannerCone.qml</file>
<file alias="BannerTabButton.qml">widgets/qml/BannerTabButton.qml</file>
<file alias="BusyIndicatorExt.qml">widgets/qml/BusyIndicatorExt.qml</file>
<file alias="AcrylicBackground.qml">widgets/qml/AcrylicBackground.qml</file>
=====================================
modules/gui/qt/widgets/qml/BannerCone.qml
=====================================
@@ -0,0 +1,76 @@
+/*****************************************************************************
+ * Copyright (C) 2023 VLC authors and VideoLAN
+ *
+ * This program 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.
+ *
+ * This program 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+import QtQuick 2.11
+
+import org.videolan.vlc 0.1
+
+import "qrc:///widgets/" as Widgets
+import "qrc:///style/"
+
+Image {
+ id: root
+
+ property var button: MainCtx.csdButtonModel.systemMenuButton
+
+ sourceSize.width: VLCStyle.icon_normal
+ sourceSize.height: VLCStyle.icon_normal
+ source: SVGColorImage.colorize("qrc:///misc/cone.svg")
+ .accent(VLCStyle.colors.accent)
+ .uri()
+
+ focus: false
+
+ Loader {
+ anchors.fill: root
+ enabled: MainCtx.clientSideDecoration && root.button
+
+ sourceComponent: MouseArea {
+ onClicked: { root.button.click() }
+ onDoubleClicked: { root.button.doubleClick() }
+
+ Connections {
+ // don't target MouseArea for position since we
+ // need position updates of cone, inresepect of BannerSources
+ // to correctly track cone's global position
+ target: root
+
+ // handles VLCStyle.scale changes
+ onXChanged: Qt.callLater(root.updateRect)
+ onYChanged: Qt.callLater(root.updateRect)
+ onWidthChanged: Qt.callLater(root.updateRect)
+ onHeightChanged: Qt.callLater(root.updateRect)
+ }
+
+ Connections {
+ target: VLCStyle
+
+ // handle window resize
+ onAppWidthChanged: Qt.callLater(root.updateRect)
+ onAppHeightChanged: Qt.callLater(root.updateRect)
+ }
+ }
+ }
+
+ function updateRect() {
+ var rect = root.mapToItem(null, 0, 0, width, height)
+
+ if (button)
+ button.rect = rect
+ }
+}
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/dda6d04f76de934b1caf4d40d634f58a3d08dd09...a17b8d5be1dc3b0845401be8fffbd17877fa04e5
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/dda6d04f76de934b1caf4d40d634f58a3d08dd09...a17b8d5be1dc3b0845401be8fffbd17877fa04e5
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list