forked from github_mirror/framelesshelper
win implementation is mostly settled now
Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
parent
389a342a81
commit
d4e711d679
|
@ -45,7 +45,6 @@ int main(int argc, char *argv[])
|
|||
QApplication application(argc, argv);
|
||||
|
||||
MainWindow mainWindow;
|
||||
mainWindow.moveToDesktopCenter();
|
||||
mainWindow.show();
|
||||
|
||||
return QCoreApplication::exec();
|
||||
|
|
|
@ -29,14 +29,11 @@ import org.wangwenx190.FramelessHelper 1.0
|
|||
|
||||
FramelessWindow {
|
||||
id: window
|
||||
visible: true
|
||||
width: 800
|
||||
height: 600
|
||||
title: qsTr("Hello, World! - Qt Quick")
|
||||
color: FramelessUtils.darkModeEnabled ? FramelessUtils.defaultSystemDarkColor : FramelessUtils.defaultSystemLightColor
|
||||
Component.onCompleted: {
|
||||
window.moveToDesktopCenter();
|
||||
window.visible = true;
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 500
|
||||
|
|
|
@ -45,7 +45,6 @@ int main(int argc, char *argv[])
|
|||
QApplication application(argc, argv);
|
||||
|
||||
Widget widget;
|
||||
widget.moveToDesktopCenter();
|
||||
widget.show();
|
||||
|
||||
return QCoreApplication::exec();
|
||||
|
|
|
@ -32,7 +32,19 @@ FRAMELESSHELPER_USE_NAMESPACE
|
|||
|
||||
using namespace Global;
|
||||
|
||||
Widget::Widget(QWidget *parent) : FramelessWidget(parent, {Option::UseStandardWindowLayout})
|
||||
static const UserSettings settings =
|
||||
{
|
||||
/* startupPosition */ QPoint(),
|
||||
/* startupSize */ QSize(),
|
||||
/* startupState */ Qt::WindowNoState,
|
||||
/* options */ { Option::UseStandardWindowLayout },
|
||||
/* systemMenuOffset */ QPoint(),
|
||||
/* minimizeButton */ nullptr,
|
||||
/* maximizeButton */ nullptr,
|
||||
/* closeButton */ nullptr
|
||||
};
|
||||
|
||||
Widget::Widget(QWidget *parent) : FramelessWidget(parent, settings)
|
||||
{
|
||||
setupUi();
|
||||
startTimer(500);
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
explicit FramelessHelperQt(QObject *parent = nullptr);
|
||||
~FramelessHelperQt() override;
|
||||
|
||||
static void addWindow(const Global::FramelessHelperParams ¶ms);
|
||||
static void addWindow(const Global::UserSettings &settings, const Global::SystemParameters ¶ms);
|
||||
|
||||
protected:
|
||||
Q_NODISCARD bool eventFilter(QObject *object, QEvent *event) override;
|
||||
|
|
|
@ -37,7 +37,7 @@ public:
|
|||
explicit FramelessHelperWin();
|
||||
~FramelessHelperWin() override;
|
||||
|
||||
static void addWindow(const Global::FramelessHelperParams ¶ms);
|
||||
static void addWindow(const Global::UserSettings &settings, const Global::SystemParameters ¶ms);
|
||||
|
||||
Q_NODISCARD bool nativeEventFilter(const QByteArray &eventType, void *message, NATIVE_EVENT_RESULT_TYPE *result) override;
|
||||
};
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qpoint.h>
|
||||
#include <QtCore/qsize.h>
|
||||
#include <QtCore/qpointer.h>
|
||||
#include <QtGui/qcolor.h>
|
||||
#include <QtGui/qwindowdefs.h>
|
||||
|
||||
|
@ -181,10 +182,11 @@ enum class SystemButtonType : int
|
|||
{
|
||||
Unknown = -1,
|
||||
WindowIcon = 0,
|
||||
Minimize = 1,
|
||||
Maximize = 2,
|
||||
Restore = 3,
|
||||
Close = 4
|
||||
Help = 1,
|
||||
Minimize = 2,
|
||||
Maximize = 3,
|
||||
Restore = 4,
|
||||
Close = 5
|
||||
};
|
||||
Q_ENUM_NS(SystemButtonType)
|
||||
|
||||
|
@ -224,30 +226,65 @@ using SetWindowStateCallback = std::function<void(const Qt::WindowState)>;
|
|||
|
||||
using GetWindowHandleCallback = std::function<QWindow *()>;
|
||||
|
||||
struct FramelessHelperParams
|
||||
using WindowToScreenCallback = std::function<QPoint(const QPoint &)>;
|
||||
using ScreenToWindowCallback = std::function<QPoint(const QPoint &)>;
|
||||
|
||||
using IsInsideSystemButtonsCallback = std::function<bool(const QPoint &, SystemButtonType *)>;
|
||||
using IsInsideTitleBarDraggableAreaCallback = std::function<bool(const QPoint &)>;
|
||||
|
||||
using GetWindowDevicePixelRatioCallback = std::function<qreal()>;
|
||||
|
||||
struct UserSettings
|
||||
{
|
||||
WId windowId = 0;
|
||||
QPoint startupPosition = {};
|
||||
QSize startupSize = {};
|
||||
Qt::WindowState startupState = Qt::WindowNoState;
|
||||
Options options = {};
|
||||
QPoint systemMenuOffset = {};
|
||||
QPointer<QObject> minimizeButton = nullptr;
|
||||
QPointer<QObject> maximizeButton = nullptr;
|
||||
QPointer<QObject> closeButton = nullptr;
|
||||
};
|
||||
|
||||
struct SystemParameters
|
||||
{
|
||||
WId windowId = 0;
|
||||
|
||||
GetWindowFlagsCallback getWindowFlags = nullptr;
|
||||
SetWindowFlagsCallback setWindowFlags = nullptr;
|
||||
|
||||
GetWindowSizeCallback getWindowSize = nullptr;
|
||||
SetWindowSizeCallback setWindowSize = nullptr;
|
||||
|
||||
GetWindowPositionCallback getWindowPosition = nullptr;
|
||||
SetWindowPositionCallback setWindowPosition = nullptr;
|
||||
|
||||
GetWindowScreenCallback getWindowScreen = nullptr;
|
||||
|
||||
IsWindowFixedSizeCallback isWindowFixedSize = nullptr;
|
||||
SetWindowFixedSizeCallback setWindowFixedSize = nullptr;
|
||||
|
||||
GetWindowStateCallback getWindowState = nullptr;
|
||||
SetWindowStateCallback setWindowState = nullptr;
|
||||
|
||||
GetWindowHandleCallback getWindowHandle = nullptr;
|
||||
|
||||
WindowToScreenCallback windowToScreen = nullptr;
|
||||
ScreenToWindowCallback screenToWindow = nullptr;
|
||||
|
||||
IsInsideSystemButtonsCallback isInsideSystemButtons = nullptr;
|
||||
IsInsideTitleBarDraggableAreaCallback isInsideTitleBarDraggableArea = nullptr;
|
||||
|
||||
GetWindowDevicePixelRatioCallback getWindowDevicePixelRatio = nullptr;
|
||||
|
||||
[[nodiscard]] inline bool isValid() const
|
||||
{
|
||||
return (windowId && getWindowFlags && setWindowFlags && getWindowSize
|
||||
&& setWindowSize && getWindowPosition && setWindowPosition
|
||||
&& isWindowFixedSize && setWindowFixedSize && getWindowState
|
||||
&& setWindowState && getWindowHandle);
|
||||
&& setWindowState && getWindowHandle && windowToScreen && screenToWindow
|
||||
&& isInsideSystemButtons && isInsideTitleBarDraggableArea
|
||||
&& getWindowDevicePixelRatio);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -255,4 +292,5 @@ struct FramelessHelperParams
|
|||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(Global::FramelessHelperParams))
|
||||
Q_DECLARE_METATYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(Global::UserSettings))
|
||||
Q_DECLARE_METATYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(Global::SystemParameters))
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
Q_NODISCARD static Global::SystemTheme systemTheme();
|
||||
|
||||
public Q_SLOTS:
|
||||
static void addWindow(const Global::FramelessHelperParams ¶ms);
|
||||
static void addWindow(const Global::UserSettings &settings, const Global::SystemParameters ¶ms);
|
||||
|
||||
Q_SIGNALS:
|
||||
void systemThemeChanged();
|
||||
|
|
|
@ -43,7 +43,7 @@ getSystemButtonIconResource(const Global::SystemButtonType button,
|
|||
const Global::SystemTheme theme,
|
||||
const Global::ResourceType type);
|
||||
FRAMELESSHELPER_CORE_API void sendMouseReleaseEvent();
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QWindow *findWindow(const WId winId);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QWindow *findWindow(const WId windowId);
|
||||
FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter(
|
||||
const Global::GetWindowScreenCallback &getWindowScreen,
|
||||
const Global::GetWindowSizeCallback &getWindowSize,
|
||||
|
@ -60,15 +60,15 @@ FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter(
|
|||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWin101809OrGreater();
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWin11OrGreater();
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isDwmCompositionEnabled();
|
||||
FRAMELESSHELPER_CORE_API void triggerFrameChange(const WId winId);
|
||||
FRAMELESSHELPER_CORE_API void updateWindowFrameMargins(const WId winId, const bool reset);
|
||||
FRAMELESSHELPER_CORE_API void triggerFrameChange(const WId windowId);
|
||||
FRAMELESSHELPER_CORE_API void updateWindowFrameMargins(const WId windowId, const bool reset);
|
||||
FRAMELESSHELPER_CORE_API void updateInternalWindowFrameMargins(QWindow *window, const bool enable);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QString getSystemErrorMessage(const QString &function);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isFullScreen(const WId winId);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowNoState(const WId winId);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isFullScreen(const WId windowId);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowNoState(const WId windowId);
|
||||
FRAMELESSHELPER_CORE_API void syncWmPaintWithDwm();
|
||||
FRAMELESSHELPER_CORE_API void showSystemMenu(
|
||||
const WId winId,
|
||||
const WId windowId,
|
||||
const QPoint &pos,
|
||||
const Global::Options options,
|
||||
const QPoint &offset,
|
||||
|
@ -78,32 +78,32 @@ FRAMELESSHELPER_CORE_API void showSystemMenu(
|
|||
[[nodiscard]] FRAMELESSHELPER_CORE_API Global::DwmColorizationArea getDwmColorizationArea();
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isHighContrastModeEnabled();
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getPrimaryScreenDpi(const bool horizontal);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getWindowDpi(const WId winId, const bool horizontal);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getResizeBorderThickness(const WId winId,
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getWindowDpi(const WId windowId, const bool horizontal);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getResizeBorderThickness(const WId windowId,
|
||||
const bool horizontal,
|
||||
const bool scaled);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getCaptionHeight(const WId winId, const bool scaled);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getTitleBarHeight(const WId winId, const bool scaled);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getFrameBorderThickness(const WId winId,
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getCaptionHeight(const WId windowId, const bool scaled);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getTitleBarHeight(const WId windowId, const bool scaled);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getFrameBorderThickness(const WId windowId,
|
||||
const bool scaled);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getFrameBorderColor(const bool active);
|
||||
FRAMELESSHELPER_CORE_API void updateWindowFrameBorderColor(const WId winId, const bool dark);
|
||||
FRAMELESSHELPER_CORE_API void fixupQtInternals(const WId winId);
|
||||
FRAMELESSHELPER_CORE_API void updateWindowFrameBorderColor(const WId windowId, const bool dark);
|
||||
FRAMELESSHELPER_CORE_API void fixupQtInternals(const WId windowId);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowFrameBorderVisible();
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isTitleBarColorized();
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isFrameBorderColorized();
|
||||
FRAMELESSHELPER_CORE_API void installSystemMenuHook(
|
||||
const WId winId,
|
||||
const WId windowId,
|
||||
const Global::Options options,
|
||||
const QPoint &offset,
|
||||
const Global::IsWindowFixedSizeCallback &isWindowFixedSize);
|
||||
FRAMELESSHELPER_CORE_API void uninstallSystemMenuHook(const WId winId);
|
||||
FRAMELESSHELPER_CORE_API void uninstallSystemMenuHook(const WId windowId);
|
||||
FRAMELESSHELPER_CORE_API void tryToBeCompatibleWithQtFramelessWindowHint(
|
||||
const WId winId,
|
||||
const WId windowId,
|
||||
const Global::GetWindowFlagsCallback &getWindowFlags,
|
||||
const Global::SetWindowFlagsCallback &setWindowFlags,
|
||||
const bool enable);
|
||||
FRAMELESSHELPER_CORE_API void setAeroSnappingEnabled(const WId winId, const bool enable);
|
||||
FRAMELESSHELPER_CORE_API void setAeroSnappingEnabled(const WId windowId, const bool enable);
|
||||
FRAMELESSHELPER_CORE_API void tryToEnableHighestDpiAwarenessLevel();
|
||||
#endif // Q_OS_WINDOWS
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
#include <framelessquickeventfilter.h>
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framelesshelperquick_global.h"
|
||||
#include <QtCore/qobject.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QQuickWindow;
|
||||
class QQuickItem;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
class FRAMELESSHELPER_QUICK_API FramelessQuickEventFilter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(FramelessQuickEventFilter)
|
||||
|
||||
public:
|
||||
explicit FramelessQuickEventFilter(QObject *parent = nullptr);
|
||||
~FramelessQuickEventFilter() override;
|
||||
|
||||
static void addWindow(const Global::FramelessHelperParams ¶ms);
|
||||
static void setTitleBarItem(QQuickWindow *window, QQuickItem *item);
|
||||
static void setHitTestVisible(QQuickWindow *window, QQuickItem *item);
|
||||
|
||||
protected:
|
||||
Q_NODISCARD bool eventFilter(QObject *object, QEvent *event) override;
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
|
@ -40,15 +40,23 @@ class FRAMELESSHELPER_QUICK_API FramelessQuickWindow : public QQuickWindow
|
|||
#endif
|
||||
Q_DECLARE_PRIVATE(FramelessQuickWindow)
|
||||
Q_DISABLE_COPY_MOVE(FramelessQuickWindow)
|
||||
Q_PROPERTY(bool zoomed READ zoomed NOTIFY zoomedChanged FINAL)
|
||||
Q_PROPERTY(bool hidden READ isHidden NOTIFY hiddenChanged FINAL)
|
||||
Q_PROPERTY(bool normal READ isNormal NOTIFY normalChanged FINAL)
|
||||
Q_PROPERTY(bool minimized READ isMinimized NOTIFY minimizedChanged FINAL)
|
||||
Q_PROPERTY(bool zoomed READ isZoomed NOTIFY zoomedChanged FINAL)
|
||||
Q_PROPERTY(bool fullScreen READ isFullScreen NOTIFY fullScreenChanged FINAL)
|
||||
Q_PROPERTY(bool fixedSize READ fixedSize WRITE setFixedSize NOTIFY fixedSizeChanged FINAL)
|
||||
Q_PROPERTY(QColor frameBorderColor READ frameBorderColor NOTIFY frameBorderColorChanged FINAL)
|
||||
|
||||
public:
|
||||
explicit FramelessQuickWindow(QWindow *parent = nullptr, const Global::Options options = {});
|
||||
explicit FramelessQuickWindow(QWindow *parent = nullptr, const Global::UserSettings &settings = {});
|
||||
~FramelessQuickWindow() override;
|
||||
|
||||
Q_NODISCARD bool zoomed() const;
|
||||
Q_NODISCARD bool isHidden() const;
|
||||
Q_NODISCARD bool isNormal() const;
|
||||
Q_NODISCARD bool isMinimized() const;
|
||||
Q_NODISCARD bool isZoomed() const;
|
||||
Q_NODISCARD bool isFullScreen() const;
|
||||
|
||||
Q_NODISCARD bool fixedSize() const;
|
||||
void setFixedSize(const bool value);
|
||||
|
@ -65,9 +73,20 @@ public Q_SLOTS:
|
|||
void setTitleBarItem(QQuickItem *item);
|
||||
void setHitTestVisible(QQuickItem *item);
|
||||
void moveToDesktopCenter();
|
||||
void bringToFront();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void hiddenChanged();
|
||||
void normalChanged();
|
||||
void minimizedChanged();
|
||||
void zoomedChanged();
|
||||
void fullScreenChanged();
|
||||
void fixedSizeChanged();
|
||||
void frameBorderColorChanged();
|
||||
|
||||
|
|
|
@ -35,16 +35,17 @@ class FRAMELESSHELPER_WIDGETS_API FramelessMainWindow : public QMainWindow
|
|||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(FramelessMainWindow)
|
||||
Q_PROPERTY(bool hidden READ isHidden NOTIFY hiddenChanged FINAL)
|
||||
Q_PROPERTY(bool normal READ isNormal NOTIFY normalChanged FINAL)
|
||||
Q_PROPERTY(bool zoomed READ isZoomed NOTIFY zoomedChanged FINAL)
|
||||
Q_PROPERTY(bool fixedSize READ isFixedSize WRITE setFixedSize NOTIFY fixedSizeChanged FINAL)
|
||||
Q_PROPERTY(QWidget* titleBarWidget READ titleBarWidget WRITE setTitleBarWidget NOTIFY titleBarWidgetChanged FINAL)
|
||||
|
||||
public:
|
||||
explicit FramelessMainWindow(QWidget *parent = nullptr, const Qt::WindowFlags flags = {}, const Global::Options options = {});
|
||||
explicit FramelessMainWindow(QWidget *parent = nullptr, const Qt::WindowFlags flags = {}, const Global::UserSettings &settings = {});
|
||||
~FramelessMainWindow() override;
|
||||
|
||||
Q_NODISCARD Q_INVOKABLE bool isNormal() const;
|
||||
|
||||
Q_NODISCARD bool isNormal() const;
|
||||
Q_NODISCARD bool isZoomed() const;
|
||||
|
||||
Q_NODISCARD bool isFixedSize() const;
|
||||
|
@ -58,8 +59,13 @@ public Q_SLOTS:
|
|||
void toggleMaximized();
|
||||
void toggleFullScreen();
|
||||
void moveToDesktopCenter();
|
||||
void bringToFront();
|
||||
void showSystemMenu(const QPoint &pos);
|
||||
void startSystemMove2();
|
||||
void startSystemResize2(const Qt::Edges edges);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void changeEvent(QEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
@ -67,6 +73,8 @@ protected:
|
|||
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void hiddenChanged();
|
||||
void normalChanged();
|
||||
void zoomedChanged();
|
||||
void fixedSizeChanged();
|
||||
void titleBarWidgetChanged();
|
||||
|
|
|
@ -35,17 +35,18 @@ class FRAMELESSHELPER_WIDGETS_API FramelessWidget : public QWidget
|
|||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(FramelessWidget)
|
||||
Q_PROPERTY(bool hidden READ isHidden NOTIFY hiddenChanged FINAL)
|
||||
Q_PROPERTY(bool normal READ isNormal NOTIFY normalChanged FINAL)
|
||||
Q_PROPERTY(bool zoomed READ isZoomed NOTIFY zoomedChanged FINAL)
|
||||
Q_PROPERTY(bool fixedSize READ isFixedSize WRITE setFixedSize NOTIFY fixedSizeChanged FINAL)
|
||||
Q_PROPERTY(QWidget* titleBarWidget READ titleBarWidget WRITE setTitleBarWidget NOTIFY titleBarWidgetChanged FINAL)
|
||||
Q_PROPERTY(QWidget* contentWidget READ contentWidget WRITE setContentWidget NOTIFY contentWidgetChanged FINAL)
|
||||
|
||||
public:
|
||||
explicit FramelessWidget(QWidget *parent = nullptr, const Global::Options options = {});
|
||||
explicit FramelessWidget(QWidget *parent = nullptr, const Global::UserSettings &settings = {});
|
||||
~FramelessWidget() override;
|
||||
|
||||
Q_NODISCARD Q_INVOKABLE bool isNormal() const;
|
||||
|
||||
Q_NODISCARD bool isNormal() const;
|
||||
Q_NODISCARD bool isZoomed() const;
|
||||
|
||||
Q_NODISCARD bool isFixedSize() const;
|
||||
|
@ -62,8 +63,13 @@ public Q_SLOTS:
|
|||
void toggleMaximized();
|
||||
void toggleFullScreen();
|
||||
void moveToDesktopCenter();
|
||||
void bringToFront();
|
||||
void showSystemMenu(const QPoint &pos);
|
||||
void startSystemMove2();
|
||||
void startSystemResize2(const Qt::Edges edges);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void changeEvent(QEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
@ -71,6 +77,8 @@ protected:
|
|||
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void hiddenChanged();
|
||||
void normalChanged();
|
||||
void zoomedChanged();
|
||||
void fixedSizeChanged();
|
||||
void titleBarWidgetChanged();
|
||||
|
|
|
@ -32,6 +32,7 @@ QT_BEGIN_NAMESPACE
|
|||
class QLabel;
|
||||
class QPushButton;
|
||||
class QVBoxLayout;
|
||||
class QShowEvent;
|
||||
class QPaintEvent;
|
||||
class QMouseEvent;
|
||||
QT_END_NAMESPACE
|
||||
|
@ -44,7 +45,7 @@ class FRAMELESSHELPER_WIDGETS_API FramelessWidgetsHelper : public QObject
|
|||
Q_DISABLE_COPY_MOVE(FramelessWidgetsHelper)
|
||||
|
||||
public:
|
||||
explicit FramelessWidgetsHelper(QWidget *q, const Global::Options options = {});
|
||||
explicit FramelessWidgetsHelper(QWidget *q, const Global::UserSettings &settings = {});
|
||||
~FramelessWidgetsHelper() override;
|
||||
|
||||
Q_NODISCARD Q_INVOKABLE bool isNormal() const;
|
||||
|
@ -58,6 +59,7 @@ public:
|
|||
Q_INVOKABLE void setContentWidget(QWidget *widget);
|
||||
Q_NODISCARD Q_INVOKABLE QWidget *getContentWidget() const;
|
||||
|
||||
Q_INVOKABLE void showEventHandler(QShowEvent *event);
|
||||
Q_INVOKABLE void changeEventHandler(QEvent *event);
|
||||
Q_INVOKABLE void paintEventHandler(QPaintEvent *event);
|
||||
Q_INVOKABLE void mousePressEventHandler(QMouseEvent *event);
|
||||
|
@ -69,12 +71,18 @@ public Q_SLOTS:
|
|||
void toggleMaximized();
|
||||
void toggleFullScreen();
|
||||
void moveToDesktopCenter();
|
||||
void bringToFront();
|
||||
void showSystemMenu(const QPoint &pos);
|
||||
void startSystemMove2();
|
||||
void startSystemResize2(const Qt::Edges edges);
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
void createSystemTitleBar();
|
||||
void createUserContentContainer();
|
||||
void setupInitialUi();
|
||||
Q_NODISCARD QRect mapWidgetGeometryToScene(const QWidget * const widget) const;
|
||||
Q_NODISCARD bool isInSystemButtons(const QPoint &pos, Global::SystemButtonType *button) const;
|
||||
Q_NODISCARD bool isInTitleBarDraggableArea(const QPoint &pos) const;
|
||||
Q_NODISCARD bool shouldDrawFrameBorder() const;
|
||||
Q_NODISCARD bool shouldIgnoreMouseEvents(const QPoint &pos) const;
|
||||
|
@ -100,7 +108,9 @@ private:
|
|||
QVBoxLayout *m_userContentContainerLayout = nullptr;
|
||||
Qt::WindowState m_savedWindowState = {};
|
||||
QWindow *m_window = nullptr;
|
||||
Global::FramelessHelperParams m_params = {};
|
||||
Global::UserSettings m_settings = {};
|
||||
Global::SystemParameters m_params = {};
|
||||
bool m_windowExposed = false;
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -32,16 +32,17 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
|
||||
using namespace Global;
|
||||
|
||||
struct QtHelperInternalData
|
||||
struct QtHelperData
|
||||
{
|
||||
FramelessHelperParams params = {};
|
||||
FramelessHelperQt *framelessHelper = nullptr;
|
||||
UserSettings settings = {};
|
||||
SystemParameters params = {};
|
||||
FramelessHelperQt *eventFilter = nullptr;
|
||||
};
|
||||
|
||||
struct QtHelper
|
||||
{
|
||||
QMutex mutex = {};
|
||||
QHash<WId, QtHelperInternalData> data = {};
|
||||
QHash<WId, QtHelperData> data = {};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(QtHelper, g_qtHelper)
|
||||
|
@ -50,7 +51,7 @@ FramelessHelperQt::FramelessHelperQt(QObject *parent) : QObject(parent) {}
|
|||
|
||||
FramelessHelperQt::~FramelessHelperQt() = default;
|
||||
|
||||
void FramelessHelperQt::addWindow(const FramelessHelperParams ¶ms)
|
||||
void FramelessHelperQt::addWindow(const UserSettings &settings, const SystemParameters ¶ms)
|
||||
{
|
||||
Q_ASSERT(params.isValid());
|
||||
if (!params.isValid()) {
|
||||
|
@ -61,15 +62,16 @@ void FramelessHelperQt::addWindow(const FramelessHelperParams ¶ms)
|
|||
g_qtHelper()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
QtHelperInternalData data = {};
|
||||
QtHelperData data = {};
|
||||
data.settings = settings;
|
||||
data.params = params;
|
||||
QWindow *window = params.getWindowHandle();
|
||||
// Give it a parent so that it can be deleted even if we forget to do so.
|
||||
data.framelessHelper = new FramelessHelperQt(window);
|
||||
data.eventFilter = new FramelessHelperQt(window);
|
||||
g_qtHelper()->data.insert(params.windowId, data);
|
||||
g_qtHelper()->mutex.unlock();
|
||||
window->setFlags(window->flags() | Qt::FramelessWindowHint);
|
||||
window->installEventFilter(data.framelessHelper);
|
||||
params.setWindowFlags(params.getWindowFlags() | Qt::FramelessWindowHint);
|
||||
window->installEventFilter(data.eventFilter);
|
||||
}
|
||||
|
||||
bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
|
||||
|
@ -95,7 +97,7 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
|
|||
g_qtHelper()->mutex.unlock();
|
||||
return false;
|
||||
}
|
||||
const QtHelperInternalData data = g_qtHelper()->data.value(windowId);
|
||||
const QtHelperData data = g_qtHelper()->data.value(windowId);
|
||||
g_qtHelper()->mutex.unlock();
|
||||
if (data.params.isWindowFixedSize()) {
|
||||
return false;
|
||||
|
@ -108,7 +110,7 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
|
|||
#endif
|
||||
switch (type) {
|
||||
case QEvent::MouseMove: {
|
||||
if (data.params.options & Option::DontTouchCursorShape) {
|
||||
if (data.settings.options & Option::DontTouchCursorShape) {
|
||||
return false;
|
||||
}
|
||||
const Qt::CursorShape cs = Utils::calculateCursorShape(window, scenePos);
|
||||
|
|
|
@ -37,11 +37,17 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
|
||||
using namespace Global;
|
||||
|
||||
struct Win32HelperData
|
||||
{
|
||||
UserSettings settings = {};
|
||||
SystemParameters params = {};
|
||||
};
|
||||
|
||||
struct Win32Helper
|
||||
{
|
||||
QMutex mutex = {};
|
||||
QScopedPointer<FramelessHelperWin> nativeEventFilter;
|
||||
QHash<WId, FramelessHelperParams> data = {};
|
||||
QHash<WId, Win32HelperData> data = {};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(Win32Helper, g_win32Helper)
|
||||
|
@ -50,7 +56,7 @@ FramelessHelperWin::FramelessHelperWin() : QAbstractNativeEventFilter() {}
|
|||
|
||||
FramelessHelperWin::~FramelessHelperWin() = default;
|
||||
|
||||
void FramelessHelperWin::addWindow(const FramelessHelperParams ¶ms)
|
||||
void FramelessHelperWin::addWindow(const UserSettings &settings, const SystemParameters ¶ms)
|
||||
{
|
||||
Q_ASSERT(params.isValid());
|
||||
if (!params.isValid()) {
|
||||
|
@ -61,27 +67,29 @@ void FramelessHelperWin::addWindow(const FramelessHelperParams ¶ms)
|
|||
g_win32Helper()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
FramelessHelperParams localParams = params;
|
||||
if ((localParams.options & Option::ForceHideWindowFrameBorder)
|
||||
&& (localParams.options & Option::ForceShowWindowFrameBorder)) {
|
||||
localParams.options &= ~(Option::ForceHideWindowFrameBorder | Option::ForceShowWindowFrameBorder);
|
||||
Win32HelperData data = {};
|
||||
data.settings = settings;
|
||||
data.params = params;
|
||||
if ((settings.options & Option::ForceHideWindowFrameBorder)
|
||||
&& (settings.options & Option::ForceShowWindowFrameBorder)) {
|
||||
data.settings.options &= ~(Option::ForceHideWindowFrameBorder | Option::ForceShowWindowFrameBorder);
|
||||
qWarning() << "You can't use both \"Option::ForceHideWindowFrameBorder\" and "
|
||||
"\"Option::ForceShowWindowFrameBorder\" at the same time.";
|
||||
}
|
||||
g_win32Helper()->data.insert(localParams.windowId, localParams);
|
||||
g_win32Helper()->data.insert(params.windowId, data);
|
||||
if (g_win32Helper()->nativeEventFilter.isNull()) {
|
||||
g_win32Helper()->nativeEventFilter.reset(new FramelessHelperWin);
|
||||
qApp->installNativeEventFilter(g_win32Helper()->nativeEventFilter.data());
|
||||
}
|
||||
g_win32Helper()->mutex.unlock();
|
||||
if (!(localParams.options & Option::DontTouchQtInternals)) {
|
||||
Utils::fixupQtInternals(localParams.windowId);
|
||||
if (!(settings.options & Option::DontTouchQtInternals)) {
|
||||
Utils::fixupQtInternals(params.windowId);
|
||||
}
|
||||
Utils::updateInternalWindowFrameMargins(localParams.getWindowHandle(), true);
|
||||
Utils::updateWindowFrameMargins(localParams.windowId, false);
|
||||
if (!(localParams.options & Option::DontTouchWindowFrameBorderColor)) {
|
||||
Utils::updateInternalWindowFrameMargins(params.getWindowHandle(), true);
|
||||
Utils::updateWindowFrameMargins(params.windowId, false);
|
||||
if (!(settings.options & Option::DontTouchWindowFrameBorderColor)) {
|
||||
const bool dark = Utils::shouldAppsUseDarkMode();
|
||||
Utils::updateWindowFrameBorderColor(localParams.windowId, dark);
|
||||
Utils::updateWindowFrameBorderColor(params.windowId, dark);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,30 +104,33 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
#else
|
||||
const auto msg = static_cast<LPMSG>(message);
|
||||
#endif
|
||||
if (!msg->hwnd) {
|
||||
const HWND hWnd = msg->hwnd;
|
||||
if (!hWnd) {
|
||||
// Why sometimes the window handle is null? Is it designed to be like this?
|
||||
// Anyway, we should skip the entire processing in this case.
|
||||
return false;
|
||||
}
|
||||
const auto winId = reinterpret_cast<WId>(msg->hwnd);
|
||||
const auto windowId = reinterpret_cast<WId>(hWnd);
|
||||
g_win32Helper()->mutex.lock();
|
||||
if (!g_win32Helper()->data.contains(winId)) {
|
||||
if (!g_win32Helper()->data.contains(windowId)) {
|
||||
g_win32Helper()->mutex.unlock();
|
||||
return false;
|
||||
}
|
||||
const FramelessHelperParams params = g_win32Helper()->data.value(winId);
|
||||
const Win32HelperData data = g_win32Helper()->data.value(windowId);
|
||||
g_win32Helper()->mutex.unlock();
|
||||
const bool frameBorderVisible = [¶ms]() -> bool {
|
||||
if (params.options & Option::ForceShowWindowFrameBorder) {
|
||||
const bool frameBorderVisible = [&data]() -> bool {
|
||||
if (data.settings.options & Option::ForceShowWindowFrameBorder) {
|
||||
return true;
|
||||
}
|
||||
if (params.options & Option::ForceHideWindowFrameBorder) {
|
||||
if (data.settings.options & Option::ForceHideWindowFrameBorder) {
|
||||
return false;
|
||||
}
|
||||
return Utils::isWindowFrameBorderVisible();
|
||||
}();
|
||||
const bool fixedSize = params.isWindowFixedSize();
|
||||
switch (msg->message) {
|
||||
const UINT uMsg = msg->message;
|
||||
const WPARAM wParam = msg->wParam;
|
||||
const LPARAM lParam = msg->lParam;
|
||||
switch (uMsg) {
|
||||
case WM_NCCALCSIZE: {
|
||||
// Windows是根据这个消息的返回值来设置窗口的客户区(窗口中真正显示的内容)
|
||||
// 和非客户区(标题栏、窗口边框、菜单栏和状态栏等Windows系统自行提供的部分
|
||||
|
@ -208,14 +219,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// implement an elaborate client-area preservation technique, and
|
||||
// simply return 0, which means "preserve the entire old client area
|
||||
// and align it with the upper-left corner of our new client area".
|
||||
const auto clientRect = ((static_cast<BOOL>(msg->wParam) == FALSE)
|
||||
? reinterpret_cast<LPRECT>(msg->lParam)
|
||||
: &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(msg->lParam))->rgrc[0]);
|
||||
const auto clientRect = ((static_cast<BOOL>(wParam) == FALSE)
|
||||
? reinterpret_cast<LPRECT>(lParam)
|
||||
: &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(lParam))->rgrc[0]);
|
||||
if (frameBorderVisible) {
|
||||
// Store the original top before the default window proc applies the default frame.
|
||||
const LONG originalTop = clientRect->top;
|
||||
// Apply the default frame.
|
||||
const LRESULT ret = DefWindowProcW(msg->hwnd, WM_NCCALCSIZE, msg->wParam, msg->lParam);
|
||||
const LRESULT ret = DefWindowProcW(hWnd, WM_NCCALCSIZE, wParam, lParam);
|
||||
if (ret != 0) {
|
||||
*result = ret;
|
||||
return true;
|
||||
|
@ -223,8 +234,8 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// Re-apply the original top from before the size of the default frame was applied.
|
||||
clientRect->top = originalTop;
|
||||
}
|
||||
const bool max = IsMaximized(msg->hwnd);
|
||||
const bool full = Utils::isFullScreen(winId);
|
||||
const bool max = IsMaximized(hWnd);
|
||||
const bool full = Utils::isFullScreen(windowId);
|
||||
// We don't need this correction when we're fullscreen. We will
|
||||
// have the WS_POPUP size, so we don't have to worry about
|
||||
// borders, and the default frame will be fine.
|
||||
|
@ -235,11 +246,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// then the window is clipped to the monitor so that the resize handle
|
||||
// do not appear because you don't need them (because you can't resize
|
||||
// a window when it's maximized unless you restore it).
|
||||
const int frameSizeY = Utils::getResizeBorderThickness(winId, false, true);
|
||||
const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true);
|
||||
clientRect->top += frameSizeY;
|
||||
if (!frameBorderVisible) {
|
||||
clientRect->bottom -= frameSizeY;
|
||||
const int frameSizeX = Utils::getResizeBorderThickness(winId, true, true);
|
||||
const int frameSizeX = Utils::getResizeBorderThickness(windowId, true, true);
|
||||
clientRect->left += frameSizeX;
|
||||
clientRect->right -= frameSizeX;
|
||||
}
|
||||
|
@ -265,7 +276,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
MONITORINFO monitorInfo;
|
||||
SecureZeroMemory(&monitorInfo, sizeof(monitorInfo));
|
||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
const HMONITOR monitor = MonitorFromWindow(msg->hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
const HMONITOR monitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (!monitor) {
|
||||
qWarning() << Utils::getSystemErrorMessage(QStringLiteral("MonitorFromWindow"));
|
||||
break;
|
||||
|
@ -297,7 +308,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
_abd.cbSize = sizeof(_abd);
|
||||
_abd.hWnd = FindWindowW(L"Shell_TrayWnd", nullptr);
|
||||
if (_abd.hWnd) {
|
||||
const HMONITOR windowMonitor = MonitorFromWindow(msg->hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
const HMONITOR windowMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (!windowMonitor) {
|
||||
qWarning() << Utils::getSystemErrorMessage(QStringLiteral("MonitorFromWindow"));
|
||||
break;
|
||||
|
@ -367,7 +378,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// of the upper-left non-client area. It's confirmed that this issue exists
|
||||
// from Windows 7 to Windows 10. Not tested on Windows 11 yet. Don't know
|
||||
// whether it exists on Windows XP to Windows Vista or not.
|
||||
*result = ((static_cast<BOOL>(msg->wParam) == FALSE) ? 0 : WVR_REDRAW);
|
||||
*result = ((static_cast<BOOL>(wParam) == FALSE) ? 0 : WVR_REDRAW);
|
||||
return true;
|
||||
}
|
||||
case WM_NCHITTEST: {
|
||||
|
@ -436,25 +447,51 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// another branch, if you are interested in it, you can give it a
|
||||
// try.
|
||||
|
||||
if (fixedSize) {
|
||||
if (data.params.isWindowFixedSize()) {
|
||||
*result = HTCLIENT;
|
||||
return true;
|
||||
}
|
||||
const POINT globalPos = {GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)};
|
||||
const POINT globalPos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
|
||||
POINT localPos = globalPos;
|
||||
if (ScreenToClient(msg->hwnd, &localPos) == FALSE) {
|
||||
if (ScreenToClient(hWnd, &localPos) == FALSE) {
|
||||
qWarning() << Utils::getSystemErrorMessage(QStringLiteral("ScreenToClient"));
|
||||
break;
|
||||
}
|
||||
const bool max = IsMaximized(msg->hwnd);
|
||||
const bool full = Utils::isFullScreen(winId);
|
||||
const int frameSizeY = Utils::getResizeBorderThickness(winId, false, true);
|
||||
if (data.settings.options & Option::MaximizeButtonDocking) {
|
||||
const QPoint scenePos = QPointF(QPointF(qreal(localPos.x), qreal(localPos.y))
|
||||
/ data.params.getWindowDevicePixelRatio()).toPoint();
|
||||
SystemButtonType systemButton = SystemButtonType::Unknown;
|
||||
if (data.params.isInsideSystemButtons(scenePos, &systemButton)) {
|
||||
switch (systemButton) {
|
||||
case SystemButtonType::Help:
|
||||
*result = HTHELP;
|
||||
break;
|
||||
case SystemButtonType::Minimize:
|
||||
*result = HTREDUCE;
|
||||
break;
|
||||
case SystemButtonType::Maximize:
|
||||
case SystemButtonType::Restore:
|
||||
*result = HTZOOM;
|
||||
break;
|
||||
case SystemButtonType::Close:
|
||||
*result = HTCLOSE;
|
||||
break;
|
||||
default:
|
||||
*result = HTCAPTION;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const bool max = IsMaximized(hWnd);
|
||||
const bool full = Utils::isFullScreen(windowId);
|
||||
const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true);
|
||||
const bool isTop = (localPos.y < frameSizeY);
|
||||
const bool isTitleBar = (false && !(params.options & Option::DisableDragging));
|
||||
const bool isTitleBar = (false && !(data.settings.options & Option::DisableDragging));
|
||||
if (frameBorderVisible) {
|
||||
// This will handle the left, right and bottom parts of the frame
|
||||
// because we didn't change them.
|
||||
const LRESULT originalRet = DefWindowProcW(msg->hwnd, WM_NCHITTEST, 0, msg->lParam);
|
||||
const LRESULT originalRet = DefWindowProcW(hWnd, WM_NCHITTEST, 0, lParam);
|
||||
if (originalRet != HTCLIENT) {
|
||||
*result = originalRet;
|
||||
return true;
|
||||
|
@ -492,7 +529,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
return true;
|
||||
}
|
||||
RECT clientRect = {0, 0, 0, 0};
|
||||
if (GetClientRect(msg->hwnd, &clientRect) == FALSE) {
|
||||
if (GetClientRect(hWnd, &clientRect) == FALSE) {
|
||||
qWarning() << Utils::getSystemErrorMessage(QStringLiteral("GetClientRect"));
|
||||
break;
|
||||
}
|
||||
|
@ -501,7 +538,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
const bool isBottom = (localPos.y >= (height - frameSizeY));
|
||||
// Make the border a little wider to let the user easy to resize on corners.
|
||||
const qreal scaleFactor = ((isTop || isBottom) ? 2.0 : 1.0);
|
||||
const int frameSizeX = Utils::getResizeBorderThickness(winId, true, true);
|
||||
const int frameSizeX = Utils::getResizeBorderThickness(windowId, true, true);
|
||||
const auto scaledFrameSizeX = static_cast<int>(qRound(qreal(frameSizeX) * scaleFactor));
|
||||
const bool isLeft = (localPos.x < scaledFrameSizeX);
|
||||
const bool isRight = (localPos.x >= (width - scaledFrameSizeX));
|
||||
|
@ -549,23 +586,23 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
case WM_WINDOWPOSCHANGING: {
|
||||
// Tell Windows to discard the entire contents of the client area, as re-using
|
||||
// parts of the client area would lead to jitter during resize.
|
||||
const auto windowPos = reinterpret_cast<LPWINDOWPOS>(msg->lParam);
|
||||
const auto windowPos = reinterpret_cast<LPWINDOWPOS>(lParam);
|
||||
windowPos->flags |= SWP_NOCOPYBITS;
|
||||
} break;
|
||||
#endif
|
||||
case WM_DPICHANGED: {
|
||||
// Sync the internal window frame margins with the latest DPI.
|
||||
Utils::updateInternalWindowFrameMargins(params.getWindowHandle(), true);
|
||||
Utils::updateInternalWindowFrameMargins(data.params.getWindowHandle(), true);
|
||||
} break;
|
||||
case WM_DWMCOMPOSITIONCHANGED: {
|
||||
// Re-apply the custom window frame if recovered from the basic theme.
|
||||
Utils::updateWindowFrameMargins(winId, false);
|
||||
Utils::updateWindowFrameMargins(windowId, false);
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!frameBorderVisible) {
|
||||
switch (msg->message) {
|
||||
switch (uMsg) {
|
||||
case WM_NCUAHDRAWCAPTION:
|
||||
case WM_NCUAHDRAWFRAME: {
|
||||
// These undocumented messages are sent to draw themed window
|
||||
|
@ -594,9 +631,9 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-ncactivate
|
||||
// Don't use "*result = 0" here, otherwise the window won't respond to the
|
||||
// window activation state change.
|
||||
*result = DefWindowProcW(msg->hwnd, WM_NCACTIVATE, msg->wParam, -1);
|
||||
*result = DefWindowProcW(hWnd, WM_NCACTIVATE, wParam, -1);
|
||||
} else {
|
||||
if (static_cast<BOOL>(msg->wParam) == FALSE) {
|
||||
if (static_cast<BOOL>(wParam) == FALSE) {
|
||||
*result = TRUE;
|
||||
} else {
|
||||
*result = FALSE;
|
||||
|
@ -610,26 +647,27 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// Disable painting while these messages are handled to prevent them
|
||||
// from drawing a window caption over the client area.
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
const LONG_PTR oldStyle = GetWindowLongPtrW(msg->hwnd, GWL_STYLE);
|
||||
const auto oldStyle = static_cast<DWORD>(GetWindowLongPtrW(hWnd, GWL_STYLE));
|
||||
if (oldStyle == 0) {
|
||||
qWarning() << Utils::getSystemErrorMessage(QStringLiteral("GetWindowLongPtrW"));
|
||||
break;
|
||||
}
|
||||
// Prevent Windows from drawing the default title bar by temporarily
|
||||
// toggling the WS_VISIBLE style.
|
||||
const DWORD newStyle = (oldStyle & ~WS_VISIBLE);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
if (SetWindowLongPtrW(msg->hwnd, GWL_STYLE, static_cast<LONG_PTR>(oldStyle & ~WS_VISIBLE)) == 0) {
|
||||
if (SetWindowLongPtrW(hWnd, GWL_STYLE, static_cast<LONG_PTR>(newStyle)) == 0) {
|
||||
qWarning() << Utils::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
|
||||
break;
|
||||
}
|
||||
Utils::triggerFrameChange(winId);
|
||||
const LRESULT ret = DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam);
|
||||
Utils::triggerFrameChange(windowId);
|
||||
const LRESULT ret = DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
if (SetWindowLongPtrW(msg->hwnd, GWL_STYLE, oldStyle) == 0) {
|
||||
if (SetWindowLongPtrW(hWnd, GWL_STYLE, static_cast<LONG_PTR>(oldStyle)) == 0) {
|
||||
qWarning() << Utils::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
|
||||
break;
|
||||
}
|
||||
Utils::triggerFrameChange(winId);
|
||||
Utils::triggerFrameChange(windowId);
|
||||
*result = ret;
|
||||
return true;
|
||||
}
|
||||
|
@ -638,10 +676,10 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
break;
|
||||
}
|
||||
}
|
||||
const bool themeSettingChanged = [&msg]() -> bool {
|
||||
const bool themeSettingChanged = [uMsg, wParam, lParam]() -> bool {
|
||||
if (Utils::isWin10OrGreater()) {
|
||||
if (msg->message == WM_SETTINGCHANGE) {
|
||||
if ((msg->wParam == 0) && (QString::fromWCharArray(reinterpret_cast<LPCWSTR>(msg->lParam))
|
||||
if (uMsg == WM_SETTINGCHANGE) {
|
||||
if ((wParam == 0) && (QString::fromWCharArray(reinterpret_cast<LPCWSTR>(lParam))
|
||||
.compare(QU8Str(kThemeSettingChangeEventName), Qt::CaseInsensitive) == 0)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -650,13 +688,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
return false;
|
||||
}();
|
||||
if (themeSettingChanged) {
|
||||
if (!(params.options & Option::DontTouchWindowFrameBorderColor)) {
|
||||
if (!(data.settings.options & Option::DontTouchWindowFrameBorderColor)) {
|
||||
const bool dark = Utils::shouldAppsUseDarkMode();
|
||||
Utils::updateWindowFrameBorderColor(winId, dark);
|
||||
Utils::updateWindowFrameBorderColor(windowId, dark);
|
||||
}
|
||||
}
|
||||
if (themeSettingChanged || (msg->message == WM_THEMECHANGED)
|
||||
|| (msg->message == WM_DWMCOLORIZATIONCOLORCHANGED)) {
|
||||
if (themeSettingChanged || (uMsg == WM_THEMECHANGED)
|
||||
|| (uMsg == WM_DWMCOLORIZATIONCOLORCHANGED)) {
|
||||
Q_EMIT FramelessWindowsManager::instance()->systemThemeChanged();
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -39,13 +39,13 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
|
||||
using namespace Global;
|
||||
|
||||
struct FramelessWindowsManagerData
|
||||
struct FramelessWindowsManagerHelper
|
||||
{
|
||||
QMutex mutex = {};
|
||||
QList<WId> windowIds = {};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(FramelessWindowsManagerData, g_data)
|
||||
Q_GLOBAL_STATIC(FramelessWindowsManagerHelper, g_helper)
|
||||
|
||||
Q_GLOBAL_STATIC(FramelessWindowsManager, g_manager)
|
||||
|
||||
|
@ -54,6 +54,8 @@ FramelessWindowsManager::FramelessWindowsManager(QObject *parent) : QObject(pare
|
|||
if (!QCoreApplication::testAttribute(Qt::AA_DontCreateNativeWidgetSiblings)) {
|
||||
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
|
||||
}
|
||||
qRegisterMetaType<UserSettings>();
|
||||
qRegisterMetaType<SystemParameters>();
|
||||
}
|
||||
|
||||
FramelessWindowsManager::~FramelessWindowsManager() = default;
|
||||
|
@ -89,19 +91,19 @@ SystemTheme FramelessWindowsManager::systemTheme()
|
|||
#endif
|
||||
}
|
||||
|
||||
void FramelessWindowsManager::addWindow(const FramelessHelperParams ¶ms)
|
||||
void FramelessWindowsManager::addWindow(const UserSettings &settings, const SystemParameters ¶ms)
|
||||
{
|
||||
Q_ASSERT(params.isValid());
|
||||
if (!params.isValid()) {
|
||||
return;
|
||||
}
|
||||
g_data()->mutex.lock();
|
||||
if (g_data()->windowIds.contains(params.windowId)) {
|
||||
g_data()->mutex.unlock();
|
||||
g_helper()->mutex.lock();
|
||||
if (g_helper()->windowIds.contains(params.windowId)) {
|
||||
g_helper()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
g_data()->windowIds.append(params.windowId);
|
||||
g_data()->mutex.unlock();
|
||||
g_helper()->windowIds.append(params.windowId);
|
||||
g_helper()->mutex.unlock();
|
||||
static const bool pureQt = usePureQtImplementation();
|
||||
QWindow *window = params.getWindowHandle();
|
||||
#ifdef Q_OS_WINDOWS
|
||||
|
@ -121,15 +123,15 @@ void FramelessWindowsManager::addWindow(const FramelessHelperParams ¶ms)
|
|||
}
|
||||
#endif
|
||||
if (pureQt) {
|
||||
FramelessHelperQt::addWindow(params);
|
||||
FramelessHelperQt::addWindow(settings, params);
|
||||
}
|
||||
#ifdef Q_OS_WINDOWS
|
||||
if (!pureQt) {
|
||||
FramelessHelperWin::addWindow(params);
|
||||
FramelessHelperWin::addWindow(settings, params);
|
||||
}
|
||||
if (!(params.options & Option::DontInstallSystemMenuHook)) {
|
||||
Utils::installSystemMenuHook(params.windowId, params.options,
|
||||
params.systemMenuOffset, params.isWindowFixedSize);
|
||||
if (!(settings.options & Option::DontInstallSystemMenuHook)) {
|
||||
Utils::installSystemMenuHook(params.windowId, settings.options,
|
||||
settings.systemMenuOffset, params.isWindowFixedSize);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -103,7 +103,9 @@ QVariant Utils::getSystemButtonIconResource
|
|||
case SystemButtonType::Unknown:
|
||||
return {};
|
||||
case SystemButtonType::WindowIcon:
|
||||
return QStringLiteral("windowIcon");
|
||||
return QStringLiteral("windowicon");
|
||||
case SystemButtonType::Help:
|
||||
return QStringLiteral("help");
|
||||
case SystemButtonType::Minimize:
|
||||
return QStringLiteral("minimize");
|
||||
case SystemButtonType::Maximize:
|
||||
|
@ -142,10 +144,10 @@ QVariant Utils::getSystemButtonIconResource
|
|||
return {};
|
||||
}
|
||||
|
||||
QWindow *Utils::findWindow(const WId winId)
|
||||
QWindow *Utils::findWindow(const WId windowId)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
if (!winId) {
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return nullptr;
|
||||
}
|
||||
const QWindowList windows = QGuiApplication::topLevelWindows();
|
||||
|
@ -154,7 +156,7 @@ QWindow *Utils::findWindow(const WId winId)
|
|||
}
|
||||
for (auto &&window : qAsConst(windows)) {
|
||||
if (window && window->handle()) {
|
||||
if (window->winId() == winId) {
|
||||
if (window->winId() == windowId) {
|
||||
return window;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
|
||||
using namespace Global;
|
||||
|
||||
struct Win32UtilsInternalData
|
||||
struct Win32UtilsHelperData
|
||||
{
|
||||
WNDPROC originalWindowProc = nullptr;
|
||||
Options options = {};
|
||||
|
@ -65,7 +65,7 @@ struct Win32UtilsInternalData
|
|||
struct Win32UtilsHelper
|
||||
{
|
||||
QMutex mutex = {};
|
||||
QHash<WId, Win32UtilsInternalData> data = {};
|
||||
QHash<WId, Win32UtilsHelperData> data = {};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(Win32UtilsHelper, g_utilsHelper)
|
||||
|
@ -127,14 +127,14 @@ static const QString successErrorText = QStringLiteral("The operation completed
|
|||
return __getSystemErrorMessage(function, dwError);
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline int getSystemMetrics2(const WId winId, const int index,
|
||||
[[nodiscard]] static inline int getSystemMetrics2(const WId windowId, const int index,
|
||||
const bool horizontal, const bool scaled)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
if (!winId) {
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return 0;
|
||||
}
|
||||
const UINT windowDpi = Utils::getWindowDpi(winId, horizontal);
|
||||
const UINT windowDpi = Utils::getWindowDpi(windowId, horizontal);
|
||||
static const auto pGetSystemMetricsForDpi =
|
||||
reinterpret_cast<decltype(&GetSystemMetricsForDpi)>(
|
||||
QSystemLibrary::resolve(QStringLiteral("user32"), "GetSystemMetricsForDpi"));
|
||||
|
@ -189,7 +189,7 @@ static const QString successErrorText = QStringLiteral("The operation completed
|
|||
g_utilsHelper()->mutex.unlock();
|
||||
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
const Win32UtilsInternalData data = g_utilsHelper()->data.value(windowId);
|
||||
const Win32UtilsHelperData data = g_utilsHelper()->data.value(windowId);
|
||||
g_utilsHelper()->mutex.unlock();
|
||||
const auto getGlobalPosFromMouse = [lParam]() -> QPoint {
|
||||
return {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
|
||||
|
@ -331,23 +331,23 @@ bool Utils::isDwmCompositionEnabled()
|
|||
return (enabled != FALSE);
|
||||
}
|
||||
|
||||
void Utils::triggerFrameChange(const WId winId)
|
||||
void Utils::triggerFrameChange(const WId windowId)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
if (!winId) {
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(winId);
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
static constexpr const UINT flags = (SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER);
|
||||
if (SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, flags) == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(QStringLiteral("SetWindowPos"));
|
||||
}
|
||||
}
|
||||
|
||||
void Utils::updateWindowFrameMargins(const WId winId, const bool reset)
|
||||
void Utils::updateWindowFrameMargins(const WId windowId, const bool reset)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
if (!winId) {
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return;
|
||||
}
|
||||
// We can't extend the window frame when DWM composition is disabled.
|
||||
|
@ -368,13 +368,13 @@ void Utils::updateWindowFrameMargins(const WId winId, const bool reset)
|
|||
return {1, 1, 1, 1};
|
||||
}
|
||||
}();
|
||||
const auto hwnd = reinterpret_cast<HWND>(winId);
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
const HRESULT hr = pDwmExtendFrameIntoClientArea(hwnd, &margins);
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << __getSystemErrorMessage(QStringLiteral("DwmExtendFrameIntoClientArea"), hr);
|
||||
return;
|
||||
}
|
||||
triggerFrameChange(winId);
|
||||
triggerFrameChange(windowId);
|
||||
}
|
||||
|
||||
void Utils::updateInternalWindowFrameMargins(QWindow *window, const bool enable)
|
||||
|
@ -383,17 +383,17 @@ void Utils::updateInternalWindowFrameMargins(QWindow *window, const bool enable)
|
|||
if (!window) {
|
||||
return;
|
||||
}
|
||||
const WId winId = window->winId();
|
||||
const QMargins margins = [enable, winId]() -> QMargins {
|
||||
const WId windowId = window->winId();
|
||||
const QMargins margins = [enable, windowId]() -> QMargins {
|
||||
if (!enable) {
|
||||
return {};
|
||||
}
|
||||
const int titleBarHeight = getTitleBarHeight(winId, true);
|
||||
const int titleBarHeight = getTitleBarHeight(windowId, true);
|
||||
if (isWindowFrameBorderVisible()) {
|
||||
return {0, -titleBarHeight, 0, 0};
|
||||
} else {
|
||||
const int frameSizeX = getResizeBorderThickness(winId, true, true);
|
||||
const int frameSizeY = getResizeBorderThickness(winId, false, true);
|
||||
const int frameSizeX = getResizeBorderThickness(windowId, true, true);
|
||||
const int frameSizeY = getResizeBorderThickness(windowId, false, true);
|
||||
return {-frameSizeX, -titleBarHeight, -frameSizeX, -frameSizeY};
|
||||
}
|
||||
}();
|
||||
|
@ -414,7 +414,7 @@ void Utils::updateInternalWindowFrameMargins(QWindow *window, const bool enable)
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
triggerFrameChange(winId);
|
||||
triggerFrameChange(windowId);
|
||||
}
|
||||
|
||||
QString Utils::getSystemErrorMessage(const QString &function)
|
||||
|
@ -493,15 +493,15 @@ DwmColorizationArea Utils::getDwmColorizationArea()
|
|||
return DwmColorizationArea::None;
|
||||
}
|
||||
|
||||
void Utils::showSystemMenu(const WId winId, const QPoint &pos, const Options options,
|
||||
void Utils::showSystemMenu(const WId windowId, const QPoint &pos, const Options options,
|
||||
const QPoint &offset, const IsWindowFixedSizeCallback &isWindowFixedSize)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
Q_ASSERT(windowId);
|
||||
Q_ASSERT(isWindowFixedSize);
|
||||
if (!winId || !isWindowFixedSize) {
|
||||
if (!windowId || !isWindowFixedSize) {
|
||||
return;
|
||||
}
|
||||
const auto hWnd = reinterpret_cast<HWND>(winId);
|
||||
const auto hWnd = reinterpret_cast<HWND>(windowId);
|
||||
const HMENU menu = GetSystemMenu(hWnd, FALSE);
|
||||
if (!menu) {
|
||||
// The corresponding window doesn't have a menu, this isn't an error,
|
||||
|
@ -522,7 +522,7 @@ void Utils::showSystemMenu(const WId winId, const QPoint &pos, const Options opt
|
|||
return true;
|
||||
};
|
||||
const bool maxOrFull = (IsMaximized(hWnd) ||
|
||||
((options & Option::DontTreatFullScreenAsZoomed) ? false : isFullScreen(winId)));
|
||||
((options & Option::DontTreatFullScreenAsZoomed) ? false : isFullScreen(windowId)));
|
||||
const bool fixedSize = isWindowFixedSize();
|
||||
if (!setState(SC_RESTORE, (maxOrFull && !fixedSize), true)) {
|
||||
return;
|
||||
|
@ -558,13 +558,13 @@ void Utils::showSystemMenu(const WId winId, const QPoint &pos, const Options opt
|
|||
}
|
||||
}
|
||||
|
||||
bool Utils::isFullScreen(const WId winId)
|
||||
bool Utils::isFullScreen(const WId windowId)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
if (!winId) {
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return false;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(winId);
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
RECT wndRect = {};
|
||||
if (GetWindowRect(hwnd, &wndRect) == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(QStringLiteral("GetWindowRect"));
|
||||
|
@ -590,13 +590,13 @@ bool Utils::isFullScreen(const WId winId)
|
|||
&& (wndRect.right == scrRect.right) && (wndRect.bottom == scrRect.bottom));
|
||||
}
|
||||
|
||||
bool Utils::isWindowNoState(const WId winId)
|
||||
bool Utils::isWindowNoState(const WId windowId)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
if (!winId) {
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return false;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(winId);
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
WINDOWPLACEMENT wp;
|
||||
SecureZeroMemory(&wp, sizeof(wp));
|
||||
wp.length = sizeof(wp); // This line is important! Don't miss it!
|
||||
|
@ -755,13 +755,13 @@ QT_WARNING_POP
|
|||
return USER_DEFAULT_SCREEN_DPI;
|
||||
}
|
||||
|
||||
quint32 Utils::getWindowDpi(const WId winId, const bool horizontal)
|
||||
quint32 Utils::getWindowDpi(const WId windowId, const bool horizontal)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
if (!winId) {
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return USER_DEFAULT_SCREEN_DPI;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(winId);
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
QSystemLibrary user32Lib(QStringLiteral("user32"));
|
||||
static const auto pGetDpiForWindow =
|
||||
reinterpret_cast<decltype(&GetDpiForWindow)>(user32Lib.resolve("GetDpiForWindow"));
|
||||
|
@ -793,43 +793,43 @@ quint32 Utils::getWindowDpi(const WId winId, const bool horizontal)
|
|||
return getPrimaryScreenDpi(horizontal);
|
||||
}
|
||||
|
||||
quint32 Utils::getResizeBorderThickness(const WId winId, const bool horizontal, const bool scaled)
|
||||
quint32 Utils::getResizeBorderThickness(const WId windowId, const bool horizontal, const bool scaled)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
if (!winId) {
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return 0;
|
||||
}
|
||||
if (horizontal) {
|
||||
return (getSystemMetrics2(winId, SM_CXSIZEFRAME, true, scaled)
|
||||
+ getSystemMetrics2(winId, SM_CXPADDEDBORDER, true, scaled));
|
||||
return (getSystemMetrics2(windowId, SM_CXSIZEFRAME, true, scaled)
|
||||
+ getSystemMetrics2(windowId, SM_CXPADDEDBORDER, true, scaled));
|
||||
} else {
|
||||
return (getSystemMetrics2(winId, SM_CYSIZEFRAME, false, scaled)
|
||||
+ getSystemMetrics2(winId, SM_CYPADDEDBORDER, false, scaled));
|
||||
return (getSystemMetrics2(windowId, SM_CYSIZEFRAME, false, scaled)
|
||||
+ getSystemMetrics2(windowId, SM_CYPADDEDBORDER, false, scaled));
|
||||
}
|
||||
}
|
||||
|
||||
quint32 Utils::getCaptionHeight(const WId winId, const bool scaled)
|
||||
quint32 Utils::getCaptionHeight(const WId windowId, const bool scaled)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
if (!winId) {
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return 0;
|
||||
}
|
||||
return getSystemMetrics2(winId, SM_CYCAPTION, false, scaled);
|
||||
return getSystemMetrics2(windowId, SM_CYCAPTION, false, scaled);
|
||||
}
|
||||
|
||||
quint32 Utils::getTitleBarHeight(const WId winId, const bool scaled)
|
||||
quint32 Utils::getTitleBarHeight(const WId windowId, const bool scaled)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
if (!winId) {
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return 0;
|
||||
}
|
||||
return (getCaptionHeight(winId, scaled) + getResizeBorderThickness(winId, false, scaled));
|
||||
return (getCaptionHeight(windowId, scaled) + getResizeBorderThickness(windowId, false, scaled));
|
||||
}
|
||||
|
||||
quint32 Utils::getFrameBorderThickness(const WId winId, const bool scaled)
|
||||
quint32 Utils::getFrameBorderThickness(const WId windowId, const bool scaled)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
if (!winId) {
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return 0;
|
||||
}
|
||||
// There's no window frame border before Windows 10.
|
||||
|
@ -842,9 +842,9 @@ quint32 Utils::getFrameBorderThickness(const WId winId, const bool scaled)
|
|||
if (!pDwmGetWindowAttribute) {
|
||||
return 0;
|
||||
}
|
||||
const UINT dpi = getWindowDpi(winId, true);
|
||||
const UINT dpi = getWindowDpi(windowId, true);
|
||||
const qreal scaleFactor = (qreal(dpi) / qreal(USER_DEFAULT_SCREEN_DPI));
|
||||
const auto hwnd = reinterpret_cast<HWND>(winId);
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
UINT value = 0;
|
||||
if (SUCCEEDED(pDwmGetWindowAttribute(hwnd, _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &value, sizeof(value)))) {
|
||||
const qreal dpr = (scaled ? 1.0 : scaleFactor);
|
||||
|
@ -874,10 +874,10 @@ QColor Utils::getFrameBorderColor(const bool active)
|
|||
}
|
||||
}
|
||||
|
||||
void Utils::updateWindowFrameBorderColor(const WId winId, const bool dark)
|
||||
void Utils::updateWindowFrameBorderColor(const WId windowId, const bool dark)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
if (!winId) {
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return;
|
||||
}
|
||||
// There's no global dark theme before Win10 1809.
|
||||
|
@ -890,7 +890,7 @@ void Utils::updateWindowFrameBorderColor(const WId winId, const bool dark)
|
|||
if (!pDwmSetWindowAttribute) {
|
||||
return;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(winId);
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
const BOOL value = (dark ? TRUE : FALSE);
|
||||
// Whether dark window frame is available or not depends on the runtime system version,
|
||||
// it's totally OK if it's not available, so just ignore the errors.
|
||||
|
@ -898,13 +898,13 @@ void Utils::updateWindowFrameBorderColor(const WId winId, const bool dark)
|
|||
pDwmSetWindowAttribute(hwnd, _DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
|
||||
}
|
||||
|
||||
void Utils::fixupQtInternals(const WId winId)
|
||||
void Utils::fixupQtInternals(const WId windowId)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
if (!winId) {
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(winId);
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
const auto oldClassStyle = static_cast<DWORD>(GetClassLongPtrW(hwnd, GCL_STYLE));
|
||||
if (oldClassStyle == 0) {
|
||||
|
@ -929,7 +929,7 @@ void Utils::fixupQtInternals(const WId winId)
|
|||
qWarning() << getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
|
||||
return;
|
||||
}
|
||||
triggerFrameChange(winId);
|
||||
triggerFrameChange(windowId);
|
||||
}
|
||||
|
||||
void Utils::startSystemMove(QWindow *window)
|
||||
|
@ -1013,19 +1013,19 @@ bool Utils::isFrameBorderColorized()
|
|||
return isTitleBarColorized();
|
||||
}
|
||||
|
||||
void Utils::installSystemMenuHook(const WId winId, const Options options, const QPoint &offset,
|
||||
void Utils::installSystemMenuHook(const WId windowId, const Options options, const QPoint &offset,
|
||||
const IsWindowFixedSizeCallback &isWindowFixedSize)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
Q_ASSERT(windowId);
|
||||
Q_ASSERT(isWindowFixedSize);
|
||||
if (!winId || !isWindowFixedSize) {
|
||||
if (!windowId || !isWindowFixedSize) {
|
||||
return;
|
||||
}
|
||||
QMutexLocker locker(&g_utilsHelper()->mutex);
|
||||
if (g_utilsHelper()->data.contains(winId)) {
|
||||
if (g_utilsHelper()->data.contains(windowId)) {
|
||||
return;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(winId);
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
const auto originalWindowProc = reinterpret_cast<WNDPROC>(GetWindowLongPtrW(hwnd, GWLP_WNDPROC));
|
||||
Q_ASSERT(originalWindowProc);
|
||||
|
@ -1038,38 +1038,38 @@ void Utils::installSystemMenuHook(const WId winId, const Options options, const
|
|||
qWarning() << getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
|
||||
return;
|
||||
}
|
||||
//triggerFrameChange(winId);
|
||||
Win32UtilsInternalData data = {};
|
||||
//triggerFrameChange(windowId);
|
||||
Win32UtilsHelperData data = {};
|
||||
data.originalWindowProc = originalWindowProc;
|
||||
data.options = options;
|
||||
data.offset = offset;
|
||||
data.isWindowFixedSize = isWindowFixedSize;
|
||||
g_utilsHelper()->data.insert(winId, data);
|
||||
g_utilsHelper()->data.insert(windowId, data);
|
||||
}
|
||||
|
||||
void Utils::uninstallSystemMenuHook(const WId winId)
|
||||
void Utils::uninstallSystemMenuHook(const WId windowId)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
if (!winId) {
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return;
|
||||
}
|
||||
QMutexLocker locker(&g_utilsHelper()->mutex);
|
||||
if (!g_utilsHelper()->data.contains(winId)) {
|
||||
if (!g_utilsHelper()->data.contains(windowId)) {
|
||||
return;
|
||||
}
|
||||
const Win32UtilsInternalData data = g_utilsHelper()->data.value(winId);
|
||||
const Win32UtilsHelperData data = g_utilsHelper()->data.value(windowId);
|
||||
Q_ASSERT(data.originalWindowProc);
|
||||
if (!data.originalWindowProc) {
|
||||
return;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(winId);
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
if (SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(data.originalWindowProc)) == 0) {
|
||||
qWarning() << getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
|
||||
return;
|
||||
}
|
||||
//triggerFrameChange(winId);
|
||||
g_utilsHelper()->data.remove(winId);
|
||||
//triggerFrameChange(windowId);
|
||||
g_utilsHelper()->data.remove(windowId);
|
||||
}
|
||||
|
||||
void Utils::sendMouseReleaseEvent()
|
||||
|
@ -1079,18 +1079,18 @@ void Utils::sendMouseReleaseEvent()
|
|||
}
|
||||
}
|
||||
|
||||
void Utils::tryToBeCompatibleWithQtFramelessWindowHint(const WId winId,
|
||||
void Utils::tryToBeCompatibleWithQtFramelessWindowHint(const WId windowId,
|
||||
const GetWindowFlagsCallback &getWindowFlags,
|
||||
const SetWindowFlagsCallback &setWindowFlags,
|
||||
const bool enable)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
Q_ASSERT(windowId);
|
||||
Q_ASSERT(getWindowFlags);
|
||||
Q_ASSERT(setWindowFlags);
|
||||
if (!winId || !getWindowFlags || !setWindowFlags) {
|
||||
if (!windowId || !getWindowFlags || !setWindowFlags) {
|
||||
return;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(winId);
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
const LONG_PTR originalWindowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE);
|
||||
if (originalWindowStyle == 0) {
|
||||
|
@ -1106,16 +1106,16 @@ void Utils::tryToBeCompatibleWithQtFramelessWindowHint(const WId winId,
|
|||
qWarning() << getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
|
||||
return;
|
||||
}
|
||||
triggerFrameChange(winId);
|
||||
triggerFrameChange(windowId);
|
||||
}
|
||||
|
||||
void Utils::setAeroSnappingEnabled(const WId winId, const bool enable)
|
||||
void Utils::setAeroSnappingEnabled(const WId windowId, const bool enable)
|
||||
{
|
||||
Q_ASSERT(winId);
|
||||
if (!winId) {
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(winId);
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
const auto oldWindowStyle = static_cast<DWORD>(GetWindowLongPtrW(hwnd, GWL_STYLE));
|
||||
if (oldWindowStyle == 0) {
|
||||
|
@ -1134,7 +1134,7 @@ void Utils::setAeroSnappingEnabled(const WId winId, const bool enable)
|
|||
qWarning() << getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
|
||||
return;
|
||||
}
|
||||
triggerFrameChange(winId);
|
||||
triggerFrameChange(windowId);
|
||||
}
|
||||
|
||||
void Utils::tryToEnableHighestDpiAwarenessLevel()
|
||||
|
|
|
@ -6,7 +6,6 @@ set(SOURCES
|
|||
${INCLUDE_PREFIX}/framelesshelperquick_global.h
|
||||
${INCLUDE_PREFIX}/framelessquickutils.h
|
||||
${INCLUDE_PREFIX}/framelesshelperimageprovider.h
|
||||
${INCLUDE_PREFIX}/framelessquickeventfilter.h
|
||||
${INCLUDE_PREFIX}/framelesshelper_quick.h
|
||||
${INCLUDE_PREFIX}/framelessquickwindow.h
|
||||
framelessquickwindow_p.h
|
||||
|
@ -14,7 +13,6 @@ set(SOURCES
|
|||
framelesshelper_quick.cpp
|
||||
framelessquickutils.cpp
|
||||
framelesshelperimageprovider.cpp
|
||||
framelessquickeventfilter.cpp
|
||||
framelessquickwindow.cpp
|
||||
)
|
||||
|
||||
|
|
|
@ -28,6 +28,11 @@
|
|||
#include "framelessquickutils.h"
|
||||
#include "framelessquickwindow.h"
|
||||
|
||||
#ifndef QML_URL_EXPAND
|
||||
# define QML_URL_EXPAND(fileName) \
|
||||
QUrl(QStringLiteral("qrc:///org.wangwenx190.FramelessHelper/qml/%1.qml").arg(fileName))
|
||||
#endif
|
||||
|
||||
// The "Q_INIT_RESOURCE()" macro can't be used inside a namespace,
|
||||
// the official workaround is to wrap it into a global function
|
||||
// and call the wrapper function inside the namespace.
|
||||
|
@ -38,15 +43,6 @@ static inline void initResource()
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
[[nodiscard]] static inline QUrl getQmlFileUrl(const QString &qml)
|
||||
{
|
||||
Q_ASSERT(!qml.isEmpty());
|
||||
if (qml.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
return QUrl(QStringLiteral("qrc:///org.wangwenx190.FramelessHelper/qml/%1.qml").arg(qml));
|
||||
}
|
||||
|
||||
void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
|
||||
{
|
||||
Q_ASSERT(engine);
|
||||
|
@ -66,10 +62,10 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
|
|||
qmlRegisterAnonymousType<QWindow>(FRAMELESSHELPER_QUICK_URI, 1);
|
||||
#endif
|
||||
initResource();
|
||||
qmlRegisterType(getQmlFileUrl(QStringLiteral("MinimizeButton")), FRAMELESSHELPER_QUICK_URI, 1, 0, "MinimizeButton");
|
||||
qmlRegisterType(getQmlFileUrl(QStringLiteral("MaximizeButton")), FRAMELESSHELPER_QUICK_URI, 1, 0, "MaximizeButton");
|
||||
qmlRegisterType(getQmlFileUrl(QStringLiteral("CloseButton")), FRAMELESSHELPER_QUICK_URI, 1, 0, "CloseButton");
|
||||
qmlRegisterType(getQmlFileUrl(QStringLiteral("StandardTitleBar")), FRAMELESSHELPER_QUICK_URI, 1, 0, "StandardTitleBar");
|
||||
qmlRegisterType(QML_URL_EXPAND(QStringLiteral("MinimizeButton")), FRAMELESSHELPER_QUICK_URI, 1, 0, "MinimizeButton");
|
||||
qmlRegisterType(QML_URL_EXPAND(QStringLiteral("MaximizeButton")), FRAMELESSHELPER_QUICK_URI, 1, 0, "MaximizeButton");
|
||||
qmlRegisterType(QML_URL_EXPAND(QStringLiteral("CloseButton")), FRAMELESSHELPER_QUICK_URI, 1, 0, "CloseButton");
|
||||
qmlRegisterType(QML_URL_EXPAND(QStringLiteral("StandardTitleBar")), FRAMELESSHELPER_QUICK_URI, 1, 0, "StandardTitleBar");
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -56,6 +56,9 @@ using namespace Global;
|
|||
if (str.compare(QStringLiteral("windowicon"), Qt::CaseInsensitive) == 0) {
|
||||
return SystemButtonType::WindowIcon;
|
||||
}
|
||||
if (str.compare(QStringLiteral("help"), Qt::CaseInsensitive) == 0) {
|
||||
return SystemButtonType::Help;
|
||||
}
|
||||
if (str.compare(QStringLiteral("minimize"), Qt::CaseInsensitive) == 0) {
|
||||
return SystemButtonType::Minimize;
|
||||
}
|
||||
|
|
|
@ -1,257 +0,0 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "framelessquickeventfilter.h"
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qlist.h>
|
||||
#include <QtQuick/qquickwindow.h>
|
||||
#include <QtQuick/qquickitem.h>
|
||||
#include <utils.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
using namespace Global;
|
||||
|
||||
struct EventFilterDataInternal
|
||||
{
|
||||
FramelessQuickEventFilter *eventFilter = nullptr;
|
||||
QQuickItem *titleBarItem = nullptr;
|
||||
QList<QQuickItem *> hitTestVisibleItems = {};
|
||||
FramelessHelperParams params = {};
|
||||
};
|
||||
|
||||
struct EventFilterData
|
||||
{
|
||||
QMutex mutex = {};
|
||||
QHash<WId, EventFilterDataInternal> data = {};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(EventFilterData, g_data)
|
||||
|
||||
[[nodiscard]] static inline bool isInTitleBarDraggableArea(QQuickWindow *window, const QPoint &pos)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
const WId windowId = window->winId();
|
||||
g_data()->mutex.lock();
|
||||
if (!g_data()->data.contains(windowId)) {
|
||||
g_data()->mutex.unlock();
|
||||
return false;
|
||||
}
|
||||
const EventFilterDataInternal data = g_data()->data.value(windowId);
|
||||
g_data()->mutex.unlock();
|
||||
if (!data.titleBarItem) {
|
||||
return false;
|
||||
}
|
||||
const auto mapGeometryToScene = [](const QQuickItem * const item) -> QRect {
|
||||
Q_ASSERT(item);
|
||||
if (!item) {
|
||||
return {};
|
||||
}
|
||||
return QRect(item->mapToScene(QPointF(0.0, 0.0)).toPoint(), item->size().toSize());
|
||||
};
|
||||
QRegion region = mapGeometryToScene(data.titleBarItem);
|
||||
if (!data.hitTestVisibleItems.isEmpty()) {
|
||||
for (auto &&item : qAsConst(data.hitTestVisibleItems)) {
|
||||
Q_ASSERT(item);
|
||||
if (item) {
|
||||
region -= mapGeometryToScene(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return region.contains(pos);
|
||||
}
|
||||
|
||||
FramelessQuickEventFilter::FramelessQuickEventFilter(QObject *parent) : QObject(parent) {}
|
||||
|
||||
FramelessQuickEventFilter::~FramelessQuickEventFilter() = default;
|
||||
|
||||
void FramelessQuickEventFilter::addWindow(const FramelessHelperParams ¶ms)
|
||||
{
|
||||
Q_ASSERT(params.isValid());
|
||||
if (!params.isValid()) {
|
||||
return;
|
||||
}
|
||||
g_data()->mutex.lock();
|
||||
if (g_data()->data.contains(params.windowId)) {
|
||||
g_data()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
auto data = EventFilterDataInternal{};
|
||||
data.params = params;
|
||||
const auto window = qobject_cast<QQuickWindow *>(params.getWindowHandle());
|
||||
// Give it a parent so that it can be deleted even if we forget to do so.
|
||||
data.eventFilter = new FramelessQuickEventFilter(window);
|
||||
g_data()->data.insert(params.windowId, data);
|
||||
g_data()->mutex.unlock();
|
||||
window->installEventFilter(data.eventFilter);
|
||||
}
|
||||
|
||||
void FramelessQuickEventFilter::setTitleBarItem(QQuickWindow *window, QQuickItem *item)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
Q_ASSERT(item);
|
||||
if (!window || !item) {
|
||||
return;
|
||||
}
|
||||
const WId windowId = window->winId();
|
||||
QMutexLocker locker(&g_data()->mutex);
|
||||
if (!g_data()->data.contains(windowId)) {
|
||||
return;
|
||||
}
|
||||
g_data()->data[windowId].titleBarItem = item;
|
||||
}
|
||||
|
||||
void FramelessQuickEventFilter::setHitTestVisible(QQuickWindow *window, QQuickItem *item)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
Q_ASSERT(item);
|
||||
if (!window || !item) {
|
||||
return;
|
||||
}
|
||||
const WId windowId = window->winId();
|
||||
QMutexLocker locker(&g_data()->mutex);
|
||||
if (!g_data()->data.contains(windowId)) {
|
||||
return;
|
||||
}
|
||||
auto &items = g_data()->data[windowId].hitTestVisibleItems;
|
||||
static constexpr const bool visible = true;
|
||||
const bool exists = items.contains(item);
|
||||
if (visible && !exists) {
|
||||
items.append(item);
|
||||
}
|
||||
if constexpr (!visible && exists) {
|
||||
items.removeAll(item);
|
||||
}
|
||||
}
|
||||
|
||||
bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event)
|
||||
{
|
||||
Q_ASSERT(object);
|
||||
Q_ASSERT(event);
|
||||
if (!object || !event) {
|
||||
return false;
|
||||
}
|
||||
if (!object->isWindowType()) {
|
||||
return false;
|
||||
}
|
||||
const auto window = qobject_cast<QQuickWindow *>(object);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
const WId windowId = window->winId();
|
||||
g_data()->mutex.lock();
|
||||
if (!g_data()->data.contains(windowId)) {
|
||||
g_data()->mutex.unlock();
|
||||
return false;
|
||||
}
|
||||
const EventFilterDataInternal data = g_data()->data.value(windowId);
|
||||
g_data()->mutex.unlock();
|
||||
const QEvent::Type eventType = event->type();
|
||||
if ((eventType != QEvent::MouseButtonPress) && (eventType != QEvent::MouseButtonRelease)
|
||||
&& (eventType != QEvent::MouseButtonDblClick)) {
|
||||
return false;
|
||||
}
|
||||
const auto mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
const Qt::MouseButton button = mouseEvent->button();
|
||||
if ((button != Qt::LeftButton) && (button != Qt::RightButton)) {
|
||||
return false;
|
||||
}
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
const QPoint scenePos = mouseEvent->scenePosition().toPoint();
|
||||
#else
|
||||
const QPoint scenePos = mouseEvent->windowPos().toPoint();
|
||||
#endif
|
||||
const QQuickWindow::Visibility visibility = window->visibility();
|
||||
if ((visibility == QQuickWindow::Windowed)
|
||||
&& ((scenePos.x() < kDefaultResizeBorderThickness)
|
||||
|| (scenePos.x() >= (window->width() - kDefaultResizeBorderThickness))
|
||||
|| (scenePos.y() < kDefaultResizeBorderThickness))) {
|
||||
return false;
|
||||
}
|
||||
const bool titleBar = isInTitleBarDraggableArea(window, scenePos);
|
||||
const bool isFixedSize = data.params.isWindowFixedSize();
|
||||
switch (eventType) {
|
||||
case QEvent::MouseButtonPress: {
|
||||
if (data.params.options & Option::DisableDragging) {
|
||||
return false;
|
||||
}
|
||||
if (button != Qt::LeftButton) {
|
||||
return false;
|
||||
}
|
||||
if (!titleBar) {
|
||||
return false;
|
||||
}
|
||||
Utils::startSystemMove(window);
|
||||
return true;
|
||||
}
|
||||
case QEvent::MouseButtonRelease: {
|
||||
if (data.params.options & Option::DisableSystemMenu) {
|
||||
return false;
|
||||
}
|
||||
if (button != Qt::RightButton) {
|
||||
return false;
|
||||
}
|
||||
if (!titleBar) {
|
||||
return false;
|
||||
}
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
const QPoint globalPos = mouseEvent->globalPosition().toPoint();
|
||||
#else
|
||||
const QPoint globalPos = mouseEvent->globalPos();
|
||||
#endif
|
||||
const QPoint nativePos = QPointF(QPointF(globalPos) * window->effectiveDevicePixelRatio()).toPoint();
|
||||
Utils::showSystemMenu(windowId, nativePos, data.params.options,
|
||||
data.params.systemMenuOffset, data.params.isWindowFixedSize);
|
||||
return true;
|
||||
}
|
||||
case QEvent::MouseButtonDblClick: {
|
||||
if ((data.params.options & Option::NoDoubleClickMaximizeToggle) || isFixedSize) {
|
||||
return false;
|
||||
}
|
||||
if (button != Qt::LeftButton) {
|
||||
return false;
|
||||
}
|
||||
if (!titleBar) {
|
||||
return false;
|
||||
}
|
||||
if ((visibility == QQuickWindow::Maximized)
|
||||
|| ((data.params.options & Option::DontTreatFullScreenAsZoomed)
|
||||
? false : (visibility == QQuickWindow::FullScreen))) {
|
||||
window->showNormal();
|
||||
} else {
|
||||
window->showMaximized();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "../../include/FramelessHelper/Quick/framelessquickeventfilter.h"
|
|
@ -29,37 +29,62 @@
|
|||
#include <QtQuick/private/qquickanchors_p.h>
|
||||
#include <framelesswindowsmanager.h>
|
||||
#include <utils.h>
|
||||
#include "framelessquickeventfilter.h"
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
using namespace Global;
|
||||
|
||||
FramelessQuickWindowPrivate::FramelessQuickWindowPrivate(FramelessQuickWindow *q, const Options options) : QObject(q)
|
||||
static constexpr const char QT_QUICKITEM_CLASS_NAME[] = "QQuickItem";
|
||||
|
||||
FramelessQuickWindowPrivate::FramelessQuickWindowPrivate(FramelessQuickWindow *q, const UserSettings &settings) : QObject(q)
|
||||
{
|
||||
Q_ASSERT(q);
|
||||
if (!q) {
|
||||
return;
|
||||
}
|
||||
q_ptr = q;
|
||||
m_params.options = options;
|
||||
m_settings = settings;
|
||||
initialize();
|
||||
}
|
||||
|
||||
FramelessQuickWindowPrivate::~FramelessQuickWindowPrivate() = default;
|
||||
|
||||
bool FramelessQuickWindowPrivate::isHidden() const
|
||||
{
|
||||
Q_Q(const FramelessQuickWindow);
|
||||
return (q->visibility() == FramelessQuickWindow::Hidden);
|
||||
}
|
||||
|
||||
bool FramelessQuickWindowPrivate::isNormal() const
|
||||
{
|
||||
Q_Q(const FramelessQuickWindow);
|
||||
return (q->visibility() == FramelessQuickWindow::Windowed);
|
||||
}
|
||||
|
||||
bool FramelessQuickWindowPrivate::isMinimized() const
|
||||
{
|
||||
Q_Q(const FramelessQuickWindow);
|
||||
return (q->visibility() == FramelessQuickWindow::Minimized);
|
||||
}
|
||||
|
||||
bool FramelessQuickWindowPrivate::isZoomed() const
|
||||
{
|
||||
Q_Q(const FramelessQuickWindow);
|
||||
const FramelessQuickWindow::Visibility visibility = q->visibility();
|
||||
return ((visibility == FramelessQuickWindow::Maximized) ||
|
||||
((m_params.options & Option::DontTreatFullScreenAsZoomed)
|
||||
((m_settings.options & Option::DontTreatFullScreenAsZoomed)
|
||||
? false : (visibility == FramelessQuickWindow::FullScreen)));
|
||||
}
|
||||
|
||||
bool FramelessQuickWindowPrivate::isFullScreen() const
|
||||
{
|
||||
Q_Q(const FramelessQuickWindow);
|
||||
return (q->visibility() == FramelessQuickWindow::FullScreen);
|
||||
}
|
||||
|
||||
bool FramelessQuickWindowPrivate::isFixedSize() const
|
||||
{
|
||||
if (m_params.options & Option::DisableResizing) {
|
||||
if (m_settings.options & Option::DisableResizing) {
|
||||
return true;
|
||||
}
|
||||
Q_Q(const FramelessQuickWindow);
|
||||
|
@ -90,8 +115,10 @@ void FramelessQuickWindowPrivate::setTitleBarItem(QQuickItem *item)
|
|||
if (!item) {
|
||||
return;
|
||||
}
|
||||
Q_Q(FramelessQuickWindow);
|
||||
FramelessQuickEventFilter::setTitleBarItem(q, item);
|
||||
if (m_titleBarItem == item) {
|
||||
return;
|
||||
}
|
||||
m_titleBarItem = item;
|
||||
}
|
||||
|
||||
void FramelessQuickWindowPrivate::setHitTestVisible(QQuickItem *item)
|
||||
|
@ -100,8 +127,14 @@ void FramelessQuickWindowPrivate::setHitTestVisible(QQuickItem *item)
|
|||
if (!item) {
|
||||
return;
|
||||
}
|
||||
Q_Q(FramelessQuickWindow);
|
||||
FramelessQuickEventFilter::setHitTestVisible(q, item);
|
||||
static constexpr const bool visible = true;
|
||||
const bool exists = m_hitTestVisibleItems.contains(item);
|
||||
if (visible && !exists) {
|
||||
m_hitTestVisibleItems.append(item);
|
||||
}
|
||||
if constexpr (!visible && exists) {
|
||||
m_hitTestVisibleItems.removeAll(item);
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessQuickWindowPrivate::moveToDesktopCenter()
|
||||
|
@ -132,6 +165,19 @@ void FramelessQuickWindowPrivate::setFixedSize(const bool value, const bool forc
|
|||
Q_EMIT q->fixedSizeChanged();
|
||||
}
|
||||
|
||||
void FramelessQuickWindowPrivate::bringToFront()
|
||||
{
|
||||
Q_Q(FramelessQuickWindow);
|
||||
if (isHidden()) {
|
||||
q->show();
|
||||
}
|
||||
if (isMinimized()) {
|
||||
q->showNormal(); // ### FIXME !!!
|
||||
}
|
||||
q->raise();
|
||||
q->requestActivate();
|
||||
}
|
||||
|
||||
void FramelessQuickWindowPrivate::showMinimized2()
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
|
@ -165,11 +211,10 @@ void FramelessQuickWindowPrivate::toggleFullScreen()
|
|||
return;
|
||||
}
|
||||
Q_Q(FramelessQuickWindow);
|
||||
const QWindow::Visibility visibility = q->visibility();
|
||||
if (visibility == QWindow::FullScreen) {
|
||||
if (isFullScreen()) {
|
||||
q->setVisibility(m_savedVisibility);
|
||||
} else {
|
||||
m_savedVisibility = visibility;
|
||||
m_savedVisibility = q->visibility();
|
||||
q->showFullScreen();
|
||||
}
|
||||
}
|
||||
|
@ -178,14 +223,10 @@ void FramelessQuickWindowPrivate::showSystemMenu(const QPoint &pos)
|
|||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
Q_Q(FramelessQuickWindow);
|
||||
# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
const QPoint globalPos = q->mapToGlobal(pos);
|
||||
# else
|
||||
const QPoint globalPos = q->mapToGlobal(pos);
|
||||
# endif
|
||||
const QPoint nativePos = QPointF(QPointF(globalPos) * q->effectiveDevicePixelRatio()).toPoint();
|
||||
Utils::showSystemMenu(m_params.windowId, nativePos, m_params.options,
|
||||
m_params.systemMenuOffset, m_params.isWindowFixedSize);
|
||||
Utils::showSystemMenu(m_params.windowId, nativePos, m_settings.options,
|
||||
m_settings.systemMenuOffset, m_params.isWindowFixedSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -240,76 +281,285 @@ void FramelessQuickWindowPrivate::initialize()
|
|||
m_params.getWindowState = [q]() -> Qt::WindowState { return q->windowState(); };
|
||||
m_params.setWindowState = [q](const Qt::WindowState state) -> void { q->setWindowState(state); };
|
||||
m_params.getWindowHandle = [q]() -> QWindow * { return q; };
|
||||
m_params.windowToScreen = [q](const QPoint &pos) -> QPoint { return q->mapToGlobal(pos); };
|
||||
m_params.screenToWindow = [q](const QPoint &pos) -> QPoint { return q->mapFromGlobal(pos); };
|
||||
m_params.isInsideSystemButtons = [this](const QPoint &pos, SystemButtonType *button) -> bool { return isInSystemButtons(pos, button); };
|
||||
m_params.isInsideTitleBarDraggableArea = [this](const QPoint &pos) -> bool { return isInTitleBarDraggableArea(pos); };
|
||||
m_params.getWindowDevicePixelRatio = [q]() -> qreal { return q->effectiveDevicePixelRatio(); };
|
||||
FramelessWindowsManager * const manager = FramelessWindowsManager::instance();
|
||||
manager->addWindow(m_params);
|
||||
FramelessQuickEventFilter::addWindow(m_params);
|
||||
#ifdef Q_OS_WINDOWS
|
||||
if (isFrameBorderVisible()) {
|
||||
QQuickItem * const rootItem = q->contentItem();
|
||||
const QQuickItemPrivate * const rootItemPrivate = QQuickItemPrivate::get(rootItem);
|
||||
m_topBorderRectangle.reset(new QQuickRectangle(rootItem));
|
||||
manager->addWindow(m_settings, m_params);
|
||||
QQuickItem * const rootItem = q->contentItem();
|
||||
const QQuickItemPrivate * const rootItemPrivate = QQuickItemPrivate::get(rootItem);
|
||||
m_topBorderRectangle.reset(new QQuickRectangle(rootItem));
|
||||
const bool frameBorderVisible = shouldDrawFrameBorder();
|
||||
if (frameBorderVisible) {
|
||||
updateTopBorderHeight();
|
||||
updateTopBorderColor();
|
||||
connect(q, &FramelessQuickWindow::visibilityChanged, this, [this, q](){
|
||||
updateTopBorderHeight();
|
||||
Q_EMIT q->zoomedChanged();
|
||||
});
|
||||
connect(q, &FramelessQuickWindow::activeChanged, this, &FramelessQuickWindowPrivate::updateTopBorderColor);
|
||||
connect(manager, &FramelessWindowsManager::systemThemeChanged, this, [this, q](){
|
||||
updateTopBorderColor();
|
||||
Q_EMIT q->frameBorderColorChanged();
|
||||
});
|
||||
const auto topBorderAnchors = new QQuickAnchors(m_topBorderRectangle.data(), m_topBorderRectangle.data());
|
||||
topBorderAnchors->setTop(rootItemPrivate->top());
|
||||
topBorderAnchors->setLeft(rootItemPrivate->left());
|
||||
topBorderAnchors->setRight(rootItemPrivate->right());
|
||||
}
|
||||
#endif
|
||||
if (m_params.options & Option::DisableResizing) {
|
||||
connect(q, &FramelessQuickWindow::visibilityChanged, this, [this, q, frameBorderVisible](){
|
||||
if (frameBorderVisible) {
|
||||
updateTopBorderHeight();
|
||||
}
|
||||
Q_EMIT q->hiddenChanged();
|
||||
Q_EMIT q->normalChanged();
|
||||
Q_EMIT q->minimizedChanged();
|
||||
Q_EMIT q->zoomedChanged();
|
||||
Q_EMIT q->fullScreenChanged();
|
||||
});
|
||||
connect(q, &FramelessQuickWindow::activeChanged, this, &FramelessQuickWindowPrivate::updateTopBorderColor);
|
||||
connect(manager, &FramelessWindowsManager::systemThemeChanged, this, [this, q, frameBorderVisible](){
|
||||
if (frameBorderVisible) {
|
||||
updateTopBorderColor();
|
||||
}
|
||||
Q_EMIT q->frameBorderColorChanged();
|
||||
});
|
||||
m_topBorderAnchors.reset(new QQuickAnchors(m_topBorderRectangle.data(), m_topBorderRectangle.data()));
|
||||
m_topBorderAnchors->setTop(rootItemPrivate->top());
|
||||
m_topBorderAnchors->setLeft(rootItemPrivate->left());
|
||||
m_topBorderAnchors->setRight(rootItemPrivate->right());
|
||||
if (m_settings.options & Option::DisableResizing) {
|
||||
setFixedSize(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
bool FramelessQuickWindowPrivate::isFrameBorderVisible() const
|
||||
QRect FramelessQuickWindowPrivate::mapItemGeometryToScene(const QQuickItem * const item) const
|
||||
{
|
||||
Q_ASSERT(item);
|
||||
if (!item) {
|
||||
return {};
|
||||
}
|
||||
const QPointF originPoint = item->mapToScene(QPointF(0.0, 0.0));
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
||||
const QSizeF size = item->size();
|
||||
#else
|
||||
const QSizeF size = {item->width(), item->height()};
|
||||
#endif
|
||||
return QRectF(originPoint, size).toRect();
|
||||
}
|
||||
|
||||
bool FramelessQuickWindowPrivate::isInSystemButtons(const QPoint &pos, Global::SystemButtonType *button) const
|
||||
{
|
||||
Q_ASSERT(button);
|
||||
if (!button) {
|
||||
return false;
|
||||
}
|
||||
*button = SystemButtonType::Unknown;
|
||||
if (!m_settings.minimizeButton || !m_settings.maximizeButton || !m_settings.closeButton) {
|
||||
return false;
|
||||
}
|
||||
if (!m_settings.minimizeButton->inherits(QT_QUICKITEM_CLASS_NAME)
|
||||
|| !m_settings.maximizeButton->inherits(QT_QUICKITEM_CLASS_NAME)
|
||||
|| !m_settings.closeButton->inherits(QT_QUICKITEM_CLASS_NAME)) {
|
||||
return false;
|
||||
}
|
||||
const auto minBtn = qobject_cast<QQuickItem *>(m_settings.minimizeButton);
|
||||
if (mapItemGeometryToScene(minBtn).contains(pos)) {
|
||||
*button = SystemButtonType::Minimize;
|
||||
return true;
|
||||
}
|
||||
const auto maxBtn = qobject_cast<QQuickItem *>(m_settings.maximizeButton);
|
||||
if (mapItemGeometryToScene(maxBtn).contains(pos)) {
|
||||
*button = SystemButtonType::Maximize;
|
||||
return true;
|
||||
}
|
||||
const auto closeBtn = qobject_cast<QQuickItem *>(m_settings.closeButton);
|
||||
if (mapItemGeometryToScene(closeBtn).contains(pos)) {
|
||||
*button = SystemButtonType::Close;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FramelessQuickWindowPrivate::isInTitleBarDraggableArea(const QPoint &pos) const
|
||||
{
|
||||
if (!m_titleBarItem) {
|
||||
return false;
|
||||
}
|
||||
QRegion region = mapItemGeometryToScene(m_titleBarItem);
|
||||
if (!m_hitTestVisibleItems.isEmpty()) {
|
||||
for (auto &&item : qAsConst(m_hitTestVisibleItems)) {
|
||||
Q_ASSERT(item);
|
||||
if (item) {
|
||||
region -= mapItemGeometryToScene(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return region.contains(pos);
|
||||
}
|
||||
|
||||
bool FramelessQuickWindowPrivate::shouldDrawFrameBorder() const
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
return (Utils::isWindowFrameBorderVisible() && !Utils::isWin11OrGreater());
|
||||
return (Utils::isWindowFrameBorderVisible() && !Utils::isWin11OrGreater()
|
||||
&& isNormal() && !(m_settings.options & Option::DontDrawTopWindowFrameBorder));
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessQuickWindowPrivate::updateTopBorderColor()
|
||||
bool FramelessQuickWindowPrivate::shouldIgnoreMouseEvents(const QPoint &pos) const
|
||||
{
|
||||
if (!isFrameBorderVisible()) {
|
||||
Q_Q(const FramelessQuickWindow);
|
||||
return (isNormal() && ((pos.x() < kDefaultResizeBorderThickness)
|
||||
|| (pos.x() >= (q->width() - kDefaultResizeBorderThickness))
|
||||
|| (pos.y() < kDefaultResizeBorderThickness)));
|
||||
}
|
||||
|
||||
void FramelessQuickWindowPrivate::showEventHandler(QShowEvent *event)
|
||||
{
|
||||
Q_ASSERT(event);
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
if (m_windowExposed) {
|
||||
return;
|
||||
}
|
||||
m_windowExposed = true;
|
||||
if (m_settings.options & Option::DontMoveWindowToDesktopCenter) {
|
||||
if (!m_settings.startupPosition.isNull()) {
|
||||
m_params.setWindowPosition(m_settings.startupPosition);
|
||||
}
|
||||
if (!m_settings.startupSize.isEmpty()) {
|
||||
m_params.setWindowSize(m_settings.startupSize);
|
||||
}
|
||||
if (m_settings.startupState != Qt::WindowNoState) {
|
||||
m_params.setWindowState(m_settings.startupState);
|
||||
}
|
||||
} else {
|
||||
moveToDesktopCenter();
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessQuickWindowPrivate::mousePressEventHandler(QMouseEvent *event)
|
||||
{
|
||||
Q_ASSERT(event);
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
if (m_settings.options & Option::DisableDragging) {
|
||||
return;
|
||||
}
|
||||
if (event->button() != Qt::LeftButton) {
|
||||
return;
|
||||
}
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
const QPoint scenePos = event->scenePosition().toPoint();
|
||||
#else
|
||||
const QPoint scenePos = event->windowPos().toPoint();
|
||||
#endif
|
||||
if (shouldIgnoreMouseEvents(scenePos)) {
|
||||
return;
|
||||
}
|
||||
if (!isInTitleBarDraggableArea(scenePos)) {
|
||||
return;
|
||||
}
|
||||
startSystemMove2();
|
||||
}
|
||||
|
||||
void FramelessQuickWindowPrivate::mouseReleaseEventHandler(QMouseEvent *event)
|
||||
{
|
||||
Q_ASSERT(event);
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
if (m_settings.options & Option::DisableSystemMenu) {
|
||||
return;
|
||||
}
|
||||
if (event->button() != Qt::RightButton) {
|
||||
return;
|
||||
}
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
const QPoint scenePos = event->scenePosition().toPoint();
|
||||
#else
|
||||
const QPoint scenePos = event->windowPos().toPoint();
|
||||
#endif
|
||||
if (shouldIgnoreMouseEvents(scenePos)) {
|
||||
return;
|
||||
}
|
||||
if (!isInTitleBarDraggableArea(scenePos)) {
|
||||
return;
|
||||
}
|
||||
showSystemMenu(scenePos);
|
||||
}
|
||||
|
||||
void FramelessQuickWindowPrivate::mouseDoubleClickEventHandler(QMouseEvent *event)
|
||||
{
|
||||
Q_ASSERT(event);
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
if ((m_settings.options & Option::NoDoubleClickMaximizeToggle) || isFixedSize()) {
|
||||
return;
|
||||
}
|
||||
if (event->button() != Qt::LeftButton) {
|
||||
return;
|
||||
}
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
const QPoint scenePos = event->scenePosition().toPoint();
|
||||
#else
|
||||
const QPoint scenePos = event->windowPos().toPoint();
|
||||
#endif
|
||||
if (shouldIgnoreMouseEvents(scenePos)) {
|
||||
return;
|
||||
}
|
||||
if (!isInTitleBarDraggableArea(scenePos)) {
|
||||
return;
|
||||
}
|
||||
toggleMaximize();
|
||||
}
|
||||
|
||||
void FramelessQuickWindowPrivate::updateTopBorderColor()
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
m_topBorderRectangle->setColor(getFrameBorderColor());
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessQuickWindowPrivate::updateTopBorderHeight()
|
||||
{
|
||||
if (!isFrameBorderVisible()) {
|
||||
return;
|
||||
}
|
||||
Q_Q(FramelessQuickWindow);
|
||||
const qreal newHeight = ((q->visibility() == FramelessQuickWindow::Windowed) ? 1.0 : 0.0);
|
||||
#ifdef Q_OS_WINDOWS
|
||||
const qreal newHeight = (isNormal() ? 1.0 : 0.0);
|
||||
m_topBorderRectangle->setHeight(newHeight);
|
||||
#endif
|
||||
}
|
||||
|
||||
FramelessQuickWindow::FramelessQuickWindow(QWindow *parent, const Options options) : QQuickWindow(parent)
|
||||
FramelessQuickWindow::FramelessQuickWindow(QWindow *parent, const UserSettings &settings) : QQuickWindow(parent)
|
||||
{
|
||||
d_ptr.reset(new FramelessQuickWindowPrivate(this, options));
|
||||
d_ptr.reset(new FramelessQuickWindowPrivate(this, settings));
|
||||
}
|
||||
|
||||
FramelessQuickWindow::~FramelessQuickWindow() = default;
|
||||
|
||||
bool FramelessQuickWindow::zoomed() const
|
||||
bool FramelessQuickWindow::isHidden() const
|
||||
{
|
||||
Q_D(const FramelessQuickWindow);
|
||||
return d->isHidden();
|
||||
}
|
||||
|
||||
bool FramelessQuickWindow::isNormal() const
|
||||
{
|
||||
Q_D(const FramelessQuickWindow);
|
||||
return d->isNormal();
|
||||
}
|
||||
|
||||
bool FramelessQuickWindow::isMinimized() const
|
||||
{
|
||||
Q_D(const FramelessQuickWindow);
|
||||
return d->isMinimized();
|
||||
}
|
||||
|
||||
bool FramelessQuickWindow::isZoomed() const
|
||||
{
|
||||
Q_D(const FramelessQuickWindow);
|
||||
return d->isZoomed();
|
||||
}
|
||||
|
||||
bool FramelessQuickWindow::isFullScreen() const
|
||||
{
|
||||
Q_D(const FramelessQuickWindow);
|
||||
return d->isFullScreen();
|
||||
}
|
||||
|
||||
bool FramelessQuickWindow::fixedSize() const
|
||||
{
|
||||
Q_D(const FramelessQuickWindow);
|
||||
|
@ -354,6 +604,40 @@ void FramelessQuickWindow::moveToDesktopCenter()
|
|||
d->moveToDesktopCenter();
|
||||
}
|
||||
|
||||
void FramelessQuickWindow::bringToFront()
|
||||
{
|
||||
Q_D(FramelessQuickWindow);
|
||||
d->bringToFront();
|
||||
}
|
||||
|
||||
void FramelessQuickWindow::showEvent(QShowEvent *event)
|
||||
{
|
||||
QQuickWindow::showEvent(event);
|
||||
Q_D(FramelessQuickWindow);
|
||||
d->showEventHandler(event);
|
||||
}
|
||||
|
||||
void FramelessQuickWindow::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
QQuickWindow::mousePressEvent(event);
|
||||
Q_D(FramelessQuickWindow);
|
||||
d->mousePressEventHandler(event);
|
||||
}
|
||||
|
||||
void FramelessQuickWindow::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
QQuickWindow::mouseReleaseEvent(event);
|
||||
Q_D(FramelessQuickWindow);
|
||||
d->mouseReleaseEventHandler(event);
|
||||
}
|
||||
|
||||
void FramelessQuickWindow::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
{
|
||||
QQuickWindow::mouseDoubleClickEvent(event);
|
||||
Q_D(FramelessQuickWindow);
|
||||
d->mouseDoubleClickEventHandler(event);
|
||||
}
|
||||
|
||||
void FramelessQuickWindow::showMinimized2()
|
||||
{
|
||||
Q_D(FramelessQuickWindow);
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
QT_BEGIN_NAMESPACE
|
||||
class QQuickItem;
|
||||
class QQuickRectangle;
|
||||
class QQuickAnchors;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
@ -44,13 +45,22 @@ class FRAMELESSHELPER_QUICK_API FramelessQuickWindowPrivate : public QObject
|
|||
Q_DISABLE_COPY_MOVE(FramelessQuickWindowPrivate)
|
||||
|
||||
public:
|
||||
explicit FramelessQuickWindowPrivate(FramelessQuickWindow *q, const Global::Options options);
|
||||
explicit FramelessQuickWindowPrivate(FramelessQuickWindow *q, const Global::UserSettings &settings = {});
|
||||
~FramelessQuickWindowPrivate() override;
|
||||
|
||||
Q_INVOKABLE Q_NODISCARD bool isHidden() const;
|
||||
Q_INVOKABLE Q_NODISCARD bool isNormal() const;
|
||||
Q_INVOKABLE Q_NODISCARD bool isMinimized() const;
|
||||
Q_INVOKABLE Q_NODISCARD bool isZoomed() const;
|
||||
Q_INVOKABLE Q_NODISCARD bool isFullScreen() const;
|
||||
Q_INVOKABLE Q_NODISCARD bool isFixedSize() const;
|
||||
|
||||
Q_INVOKABLE Q_NODISCARD QColor getFrameBorderColor() const;
|
||||
Q_INVOKABLE Q_NODISCARD bool isFrameBorderVisible() const;
|
||||
|
||||
Q_INVOKABLE void showEventHandler(QShowEvent *event);
|
||||
Q_INVOKABLE void mousePressEventHandler(QMouseEvent *event);
|
||||
Q_INVOKABLE void mouseReleaseEventHandler(QMouseEvent *event);
|
||||
Q_INVOKABLE void mouseDoubleClickEventHandler(QMouseEvent *event);
|
||||
|
||||
public Q_SLOTS:
|
||||
void showMinimized2();
|
||||
|
@ -63,9 +73,15 @@ public Q_SLOTS:
|
|||
void setHitTestVisible(QQuickItem *item);
|
||||
void moveToDesktopCenter();
|
||||
void setFixedSize(const bool value, const bool force = false);
|
||||
void bringToFront();
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
Q_NODISCARD QRect mapItemGeometryToScene(const QQuickItem * const item) const;
|
||||
Q_NODISCARD bool isInSystemButtons(const QPoint &pos, Global::SystemButtonType *button) const;
|
||||
Q_NODISCARD bool isInTitleBarDraggableArea(const QPoint &pos) const;
|
||||
Q_NODISCARD bool shouldDrawFrameBorder() const;
|
||||
Q_NODISCARD bool shouldIgnoreMouseEvents(const QPoint &pos) const;
|
||||
|
||||
private Q_SLOTS:
|
||||
void updateTopBorderColor();
|
||||
|
@ -75,8 +91,13 @@ private:
|
|||
FramelessQuickWindow *q_ptr = nullptr;
|
||||
bool m_initialized = false;
|
||||
QScopedPointer<QQuickRectangle> m_topBorderRectangle;
|
||||
QScopedPointer<QQuickAnchors> m_topBorderAnchors;
|
||||
QWindow::Visibility m_savedVisibility = QWindow::Windowed;
|
||||
Global::FramelessHelperParams m_params = {};
|
||||
Global::UserSettings m_settings = {};
|
||||
Global::SystemParameters m_params = {};
|
||||
bool m_windowExposed = false;
|
||||
QQuickItem *m_titleBarItem = nullptr;
|
||||
QList<QQuickItem *> m_hitTestVisibleItems = {};
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -29,9 +29,9 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
|
||||
using namespace Global;
|
||||
|
||||
FramelessMainWindow::FramelessMainWindow(QWidget *parent, const Qt::WindowFlags flags, const Options options) : QMainWindow(parent, flags)
|
||||
FramelessMainWindow::FramelessMainWindow(QWidget *parent, const Qt::WindowFlags flags, const UserSettings &settings) : QMainWindow(parent, flags)
|
||||
{
|
||||
m_helper.reset(new FramelessWidgetsHelper(this, options));
|
||||
m_helper.reset(new FramelessWidgetsHelper(this, settings));
|
||||
}
|
||||
|
||||
FramelessMainWindow::~FramelessMainWindow() = default;
|
||||
|
@ -86,6 +86,32 @@ void FramelessMainWindow::moveToDesktopCenter()
|
|||
m_helper->moveToDesktopCenter();
|
||||
}
|
||||
|
||||
void FramelessMainWindow::bringToFront()
|
||||
{
|
||||
m_helper->bringToFront();
|
||||
}
|
||||
|
||||
void FramelessMainWindow::showSystemMenu(const QPoint &pos)
|
||||
{
|
||||
m_helper->showSystemMenu(pos);
|
||||
}
|
||||
|
||||
void FramelessMainWindow::startSystemMove2()
|
||||
{
|
||||
m_helper->startSystemMove2();
|
||||
}
|
||||
|
||||
void FramelessMainWindow::startSystemResize2(const Qt::Edges edges)
|
||||
{
|
||||
m_helper->startSystemResize2(edges);
|
||||
}
|
||||
|
||||
void FramelessMainWindow::showEvent(QShowEvent *event)
|
||||
{
|
||||
QMainWindow::showEvent(event);
|
||||
m_helper->showEventHandler(event);
|
||||
}
|
||||
|
||||
void FramelessMainWindow::changeEvent(QEvent *event)
|
||||
{
|
||||
QMainWindow::changeEvent(event);
|
||||
|
|
|
@ -29,9 +29,9 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
|
||||
using namespace Global;
|
||||
|
||||
FramelessWidget::FramelessWidget(QWidget *parent, const Options options) : QWidget(parent)
|
||||
FramelessWidget::FramelessWidget(QWidget *parent, const UserSettings &settings) : QWidget(parent)
|
||||
{
|
||||
m_helper.reset(new FramelessWidgetsHelper(this, options));
|
||||
m_helper.reset(new FramelessWidgetsHelper(this, settings));
|
||||
}
|
||||
|
||||
FramelessWidget::~FramelessWidget() = default;
|
||||
|
@ -96,6 +96,32 @@ void FramelessWidget::moveToDesktopCenter()
|
|||
m_helper->moveToDesktopCenter();
|
||||
}
|
||||
|
||||
void FramelessWidget::bringToFront()
|
||||
{
|
||||
m_helper->bringToFront();
|
||||
}
|
||||
|
||||
void FramelessWidget::showSystemMenu(const QPoint &pos)
|
||||
{
|
||||
m_helper->showSystemMenu(pos);
|
||||
}
|
||||
|
||||
void FramelessWidget::startSystemMove2()
|
||||
{
|
||||
m_helper->startSystemMove2();
|
||||
}
|
||||
|
||||
void FramelessWidget::startSystemResize2(const Qt::Edges edges)
|
||||
{
|
||||
m_helper->startSystemResize2(edges);
|
||||
}
|
||||
|
||||
void FramelessWidget::showEvent(QShowEvent *event)
|
||||
{
|
||||
QWidget::showEvent(event);
|
||||
m_helper->showEventHandler(event);
|
||||
}
|
||||
|
||||
void FramelessWidget::changeEvent(QEvent *event)
|
||||
{
|
||||
QWidget::changeEvent(event);
|
||||
|
|
|
@ -54,14 +54,14 @@ QPushButton:pressed {
|
|||
}
|
||||
)");
|
||||
|
||||
FramelessWidgetsHelper::FramelessWidgetsHelper(QWidget *q, const Options options) : QObject(q)
|
||||
FramelessWidgetsHelper::FramelessWidgetsHelper(QWidget *q, const UserSettings &settings) : QObject(q)
|
||||
{
|
||||
Q_ASSERT(q);
|
||||
if (!q) {
|
||||
return;
|
||||
}
|
||||
this->q = q;
|
||||
m_params.options = options;
|
||||
m_settings = settings;
|
||||
initialize();
|
||||
}
|
||||
|
||||
|
@ -74,12 +74,12 @@ bool FramelessWidgetsHelper::isNormal() const
|
|||
|
||||
bool FramelessWidgetsHelper::isZoomed() const
|
||||
{
|
||||
return (q->isMaximized() || ((m_params.options & Option::DontTreatFullScreenAsZoomed) ? false : q->isFullScreen()));
|
||||
return (q->isMaximized() || ((m_settings.options & Option::DontTreatFullScreenAsZoomed) ? false : q->isFullScreen()));
|
||||
}
|
||||
|
||||
bool FramelessWidgetsHelper::isFixedSize() const
|
||||
{
|
||||
if (m_params.options & Option::DisableResizing) {
|
||||
if (m_settings.options & Option::DisableResizing) {
|
||||
return true;
|
||||
}
|
||||
if (q->windowFlags() & Qt::MSWindowsFixedSizeDialogHint) {
|
||||
|
@ -124,7 +124,7 @@ void FramelessWidgetsHelper::setTitleBarWidget(QWidget *widget)
|
|||
if (m_userTitleBarWidget == widget) {
|
||||
return;
|
||||
}
|
||||
if (m_params.options & Option::UseStandardWindowLayout) {
|
||||
if (m_settings.options & Option::UseStandardWindowLayout) {
|
||||
if (m_systemTitleBarWidget && m_systemTitleBarWidget->isVisible()) {
|
||||
m_mainLayout->removeWidget(m_systemTitleBarWidget);
|
||||
m_systemTitleBarWidget->hide();
|
||||
|
@ -152,7 +152,7 @@ void FramelessWidgetsHelper::setContentWidget(QWidget *widget)
|
|||
if (!widget) {
|
||||
return;
|
||||
}
|
||||
if (!(m_params.options & Option::UseStandardWindowLayout)) {
|
||||
if (!(m_settings.options & Option::UseStandardWindowLayout)) {
|
||||
return;
|
||||
}
|
||||
if (m_userContentWidget == widget) {
|
||||
|
@ -188,6 +188,31 @@ void FramelessWidgetsHelper::setHitTestVisible(QWidget *widget)
|
|||
}
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::showEventHandler(QShowEvent *event)
|
||||
{
|
||||
Q_ASSERT(event);
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
if (m_windowExposed) {
|
||||
return;
|
||||
}
|
||||
m_windowExposed = true;
|
||||
if (m_settings.options & Option::DontMoveWindowToDesktopCenter) {
|
||||
if (!m_settings.startupPosition.isNull()) {
|
||||
m_params.setWindowPosition(m_settings.startupPosition);
|
||||
}
|
||||
if (!m_settings.startupSize.isEmpty()) {
|
||||
m_params.setWindowSize(m_settings.startupSize);
|
||||
}
|
||||
if (m_settings.startupState != Qt::WindowNoState) {
|
||||
m_params.setWindowState(m_settings.startupState);
|
||||
}
|
||||
} else {
|
||||
moveToDesktopCenter();
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::changeEventHandler(QEvent *event)
|
||||
{
|
||||
Q_ASSERT(event);
|
||||
|
@ -198,7 +223,7 @@ void FramelessWidgetsHelper::changeEventHandler(QEvent *event)
|
|||
if ((type != QEvent::WindowStateChange) && (type != QEvent::ActivationChange)) {
|
||||
return;
|
||||
}
|
||||
const bool standardLayout = (m_params.options & Option::UseStandardWindowLayout);
|
||||
const bool standardLayout = (m_settings.options & Option::UseStandardWindowLayout);
|
||||
if (type == QEvent::WindowStateChange) {
|
||||
if (standardLayout) {
|
||||
if (isZoomed()) {
|
||||
|
@ -241,7 +266,7 @@ void FramelessWidgetsHelper::mousePressEventHandler(QMouseEvent *event)
|
|||
if (!event) {
|
||||
return;
|
||||
}
|
||||
if (m_params.options & Option::DisableDragging) {
|
||||
if (m_settings.options & Option::DisableDragging) {
|
||||
return;
|
||||
}
|
||||
if (event->button() != Qt::LeftButton) {
|
||||
|
@ -258,7 +283,7 @@ void FramelessWidgetsHelper::mousePressEventHandler(QMouseEvent *event)
|
|||
if (!isInTitleBarDraggableArea(scenePos)) {
|
||||
return;
|
||||
}
|
||||
Utils::startSystemMove(m_window);
|
||||
startSystemMove2();
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::mouseReleaseEventHandler(QMouseEvent *event)
|
||||
|
@ -267,7 +292,7 @@ void FramelessWidgetsHelper::mouseReleaseEventHandler(QMouseEvent *event)
|
|||
if (!event) {
|
||||
return;
|
||||
}
|
||||
if (m_params.options & Option::DisableSystemMenu) {
|
||||
if (m_settings.options & Option::DisableSystemMenu) {
|
||||
return;
|
||||
}
|
||||
if (event->button() != Qt::RightButton) {
|
||||
|
@ -284,16 +309,7 @@ void FramelessWidgetsHelper::mouseReleaseEventHandler(QMouseEvent *event)
|
|||
if (!isInTitleBarDraggableArea(scenePos)) {
|
||||
return;
|
||||
}
|
||||
#ifdef Q_OS_WINDOWS
|
||||
# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
const QPoint globalPos = event->globalPosition().toPoint();
|
||||
# else
|
||||
const QPoint globalPos = event->globalPos();
|
||||
# endif
|
||||
const QPoint nativePos = QPointF(QPointF(globalPos) * q->devicePixelRatioF()).toPoint();
|
||||
Utils::showSystemMenu(m_params.windowId, nativePos, m_params.options,
|
||||
m_params.systemMenuOffset, m_params.isWindowFixedSize);
|
||||
#endif
|
||||
showSystemMenu(scenePos);
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::mouseDoubleClickEventHandler(QMouseEvent *event)
|
||||
|
@ -302,7 +318,7 @@ void FramelessWidgetsHelper::mouseDoubleClickEventHandler(QMouseEvent *event)
|
|||
if (!event) {
|
||||
return;
|
||||
}
|
||||
if ((m_params.options & Option::NoDoubleClickMaximizeToggle) || isFixedSize()) {
|
||||
if ((m_settings.options & Option::NoDoubleClickMaximizeToggle) || isFixedSize()) {
|
||||
return;
|
||||
}
|
||||
if (event->button() != Qt::LeftButton) {
|
||||
|
@ -365,39 +381,54 @@ void FramelessWidgetsHelper::initialize()
|
|||
m_params.getWindowState = [this]() -> Qt::WindowState { return Utils::windowStatesToWindowState(q->windowState()); };
|
||||
m_params.setWindowState = [this](const Qt::WindowState state) -> void { q->setWindowState(state); };
|
||||
m_params.getWindowHandle = [this]() -> QWindow * { return m_window; };
|
||||
if (m_params.options & Option::UseStandardWindowLayout) {
|
||||
m_params.windowToScreen = [this](const QPoint &pos) -> QPoint { return q->mapToGlobal(pos); };
|
||||
m_params.screenToWindow = [this](const QPoint &pos) -> QPoint { return q->mapFromGlobal(pos); };
|
||||
m_params.isInsideSystemButtons = [this](const QPoint &pos, SystemButtonType *button) -> bool { return isInSystemButtons(pos, button); };
|
||||
m_params.isInsideTitleBarDraggableArea = [this](const QPoint &pos) -> bool { return isInTitleBarDraggableArea(pos); };
|
||||
m_params.getWindowDevicePixelRatio = [this]() -> qreal { return q->devicePixelRatioF(); };
|
||||
if (m_settings.options & Option::UseStandardWindowLayout) {
|
||||
if (q->inherits(QT_MAINWINDOW_CLASS_NAME)) {
|
||||
m_params.options &= ~Options(Option::UseStandardWindowLayout);
|
||||
m_settings.options &= ~Options(Option::UseStandardWindowLayout);
|
||||
qWarning() << "\"Option::UseStandardWindowLayout\" is not compatible with QMainWindow and it's subclasses."
|
||||
" Enabling this option will mess up with your main window's layout.";
|
||||
}
|
||||
}
|
||||
if (m_params.options & Option::BeCompatibleWithQtFramelessWindowHint) {
|
||||
if (m_settings.options & Option::BeCompatibleWithQtFramelessWindowHint) {
|
||||
Utils::tryToBeCompatibleWithQtFramelessWindowHint(windowId, m_params.getWindowFlags,
|
||||
m_params.setWindowFlags, true);
|
||||
}
|
||||
FramelessWindowsManager * const manager = FramelessWindowsManager::instance();
|
||||
manager->addWindow(m_params);
|
||||
manager->addWindow(m_settings, m_params);
|
||||
connect(manager, &FramelessWindowsManager::systemThemeChanged, this, [this](){
|
||||
if (m_params.options & Option::UseStandardWindowLayout) {
|
||||
if (m_settings.options & Option::UseStandardWindowLayout) {
|
||||
updateSystemTitleBarStyleSheet();
|
||||
updateSystemButtonsIcon();
|
||||
q->update();
|
||||
}
|
||||
QMetaObject::invokeMethod(q, "systemThemeChanged");
|
||||
});
|
||||
connect(m_window, &QWindow::windowStateChanged, this, [this](){
|
||||
connect(m_window, &QWindow::visibilityChanged, this, [this](){
|
||||
QMetaObject::invokeMethod(q, "hiddenChanged");
|
||||
QMetaObject::invokeMethod(q, "normalChanged");
|
||||
QMetaObject::invokeMethod(q, "zoomedChanged");
|
||||
});
|
||||
setupInitialUi();
|
||||
if (m_params.options & Option::DisableResizing) {
|
||||
if (m_settings.options & Option::UseStandardWindowLayout) {
|
||||
Q_ASSERT(m_systemMinimizeButton);
|
||||
Q_ASSERT(m_systemMaximizeButton);
|
||||
Q_ASSERT(m_systemCloseButton);
|
||||
m_settings.minimizeButton = m_systemMinimizeButton;
|
||||
m_settings.maximizeButton = m_systemMaximizeButton;
|
||||
m_settings.closeButton = m_systemCloseButton;
|
||||
}
|
||||
if (m_settings.options & Option::DisableResizing) {
|
||||
setFixedSize(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::createSystemTitleBar()
|
||||
{
|
||||
if (!(m_params.options & Option::UseStandardWindowLayout)) {
|
||||
if (!(m_settings.options & Option::UseStandardWindowLayout)) {
|
||||
return;
|
||||
}
|
||||
m_systemTitleBarWidget = new QWidget(q);
|
||||
|
@ -440,7 +471,7 @@ void FramelessWidgetsHelper::createSystemTitleBar()
|
|||
|
||||
void FramelessWidgetsHelper::createUserContentContainer()
|
||||
{
|
||||
if (!(m_params.options & Option::UseStandardWindowLayout)) {
|
||||
if (!(m_settings.options & Option::UseStandardWindowLayout)) {
|
||||
return;
|
||||
}
|
||||
m_userContentContainerWidget = new QWidget(q);
|
||||
|
@ -453,7 +484,7 @@ void FramelessWidgetsHelper::createUserContentContainer()
|
|||
|
||||
void FramelessWidgetsHelper::setupInitialUi()
|
||||
{
|
||||
if (m_params.options & Option::UseStandardWindowLayout) {
|
||||
if (m_settings.options & Option::UseStandardWindowLayout) {
|
||||
createSystemTitleBar();
|
||||
createUserContentContainer();
|
||||
m_mainLayout = new QVBoxLayout(q);
|
||||
|
@ -468,33 +499,69 @@ void FramelessWidgetsHelper::setupInitialUi()
|
|||
updateContentsMargins();
|
||||
}
|
||||
|
||||
QRect FramelessWidgetsHelper::mapWidgetGeometryToScene(const QWidget * const widget) const
|
||||
{
|
||||
Q_ASSERT(widget);
|
||||
if (!widget) {
|
||||
return {};
|
||||
}
|
||||
const QPoint originPoint = widget->mapTo(q, QPoint(0, 0));
|
||||
const QSize size = widget->size();
|
||||
return QRect(originPoint, size);
|
||||
}
|
||||
|
||||
bool FramelessWidgetsHelper::isInSystemButtons(const QPoint &pos, Global::SystemButtonType *button) const
|
||||
{
|
||||
Q_ASSERT(button);
|
||||
if (!button) {
|
||||
return false;
|
||||
}
|
||||
*button = SystemButtonType::Unknown;
|
||||
if (!m_settings.minimizeButton || !m_settings.maximizeButton || !m_settings.closeButton) {
|
||||
return false;
|
||||
}
|
||||
if (!m_settings.minimizeButton->isWidgetType() || !m_settings.maximizeButton->isWidgetType()
|
||||
|| !m_settings.closeButton->isWidgetType()) {
|
||||
return false;
|
||||
}
|
||||
const auto minBtn = qobject_cast<QWidget *>(m_settings.minimizeButton);
|
||||
if (minBtn->geometry().contains(pos)) {
|
||||
*button = SystemButtonType::Minimize;
|
||||
return true;
|
||||
}
|
||||
const auto maxBtn = qobject_cast<QWidget *>(m_settings.maximizeButton);
|
||||
if (maxBtn->geometry().contains(pos)) {
|
||||
*button = SystemButtonType::Maximize;
|
||||
return true;
|
||||
}
|
||||
const auto closeBtn = qobject_cast<QWidget *>(m_settings.closeButton);
|
||||
if (closeBtn->geometry().contains(pos)) {
|
||||
*button = SystemButtonType::Close;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FramelessWidgetsHelper::isInTitleBarDraggableArea(const QPoint &pos) const
|
||||
{
|
||||
const QRegion draggableRegion = [this]() -> QRegion {
|
||||
const auto mapGeometryToScene = [this](const QWidget * const widget) -> QRect {
|
||||
Q_ASSERT(widget);
|
||||
if (!widget) {
|
||||
return {};
|
||||
}
|
||||
return QRect(widget->mapTo(q, QPoint(0, 0)), widget->size());
|
||||
};
|
||||
if (m_userTitleBarWidget) {
|
||||
QRegion region = mapGeometryToScene(m_userTitleBarWidget);
|
||||
QRegion region = mapWidgetGeometryToScene(m_userTitleBarWidget);
|
||||
if (!m_hitTestVisibleWidgets.isEmpty()) {
|
||||
for (auto &&widget : qAsConst(m_hitTestVisibleWidgets)) {
|
||||
Q_ASSERT(widget);
|
||||
if (widget) {
|
||||
region -= mapGeometryToScene(widget);
|
||||
region -= mapWidgetGeometryToScene(widget);
|
||||
}
|
||||
}
|
||||
}
|
||||
return region;
|
||||
}
|
||||
if (m_params.options & Option::UseStandardWindowLayout) {
|
||||
QRegion region = mapGeometryToScene(m_systemTitleBarWidget);
|
||||
region -= mapGeometryToScene(m_systemMinimizeButton);
|
||||
region -= mapGeometryToScene(m_systemMaximizeButton);
|
||||
region -= mapGeometryToScene(m_systemCloseButton);
|
||||
if (m_settings.options & Option::UseStandardWindowLayout) {
|
||||
QRegion region = mapWidgetGeometryToScene(m_systemTitleBarWidget);
|
||||
region -= mapWidgetGeometryToScene(m_systemMinimizeButton);
|
||||
region -= mapWidgetGeometryToScene(m_systemMaximizeButton);
|
||||
region -= mapWidgetGeometryToScene(m_systemCloseButton);
|
||||
return region;
|
||||
}
|
||||
return {};
|
||||
|
@ -506,7 +573,7 @@ bool FramelessWidgetsHelper::shouldDrawFrameBorder() const
|
|||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
return (Utils::isWindowFrameBorderVisible() && !Utils::isWin11OrGreater()
|
||||
&& isNormal() && !(m_params.options & Option::DontDrawTopWindowFrameBorder));
|
||||
&& isNormal() && !(m_settings.options & Option::DontDrawTopWindowFrameBorder));
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
@ -528,7 +595,7 @@ void FramelessWidgetsHelper::updateContentsMargins()
|
|||
|
||||
void FramelessWidgetsHelper::updateSystemTitleBarStyleSheet()
|
||||
{
|
||||
if (!(m_params.options & Option::UseStandardWindowLayout)) {
|
||||
if (!(m_settings.options & Option::UseStandardWindowLayout)) {
|
||||
return;
|
||||
}
|
||||
const bool active = q->isActiveWindow();
|
||||
|
@ -563,7 +630,7 @@ void FramelessWidgetsHelper::updateSystemTitleBarStyleSheet()
|
|||
|
||||
void FramelessWidgetsHelper::updateSystemButtonsIcon()
|
||||
{
|
||||
if (!(m_params.options & Option::UseStandardWindowLayout)) {
|
||||
if (!(m_settings.options & Option::UseStandardWindowLayout)) {
|
||||
return;
|
||||
}
|
||||
const SystemTheme theme = ((Utils::shouldAppsUseDarkMode() || Utils::isTitleBarColorized()) ? SystemTheme::Dark : SystemTheme::Light);
|
||||
|
@ -609,4 +676,44 @@ void FramelessWidgetsHelper::moveToDesktopCenter()
|
|||
m_params.getWindowSize, m_params.setWindowPosition, true);
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::bringToFront()
|
||||
{
|
||||
if (q->isHidden()) {
|
||||
q->show();
|
||||
}
|
||||
if (q->isMinimized()) {
|
||||
q->setWindowState(q->windowState() & ~Qt::WindowMinimized);
|
||||
}
|
||||
q->raise();
|
||||
q->activateWindow();
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::showSystemMenu(const QPoint &pos)
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
const QPoint globalPos = q->mapToGlobal(pos);
|
||||
const QPoint nativePos = QPointF(QPointF(globalPos) * q->devicePixelRatioF()).toPoint();
|
||||
Utils::showSystemMenu(m_params.windowId, nativePos, m_settings.options,
|
||||
m_settings.systemMenuOffset, m_params.isWindowFixedSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::startSystemMove2()
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
m_window->startSystemMove();
|
||||
#else
|
||||
Utils::startSystemMove(m_window);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::startSystemResize2(const Qt::Edges edges)
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
m_window->startSystemResize(edges);
|
||||
#else
|
||||
Utils::startSystemResize(m_window, edges);
|
||||
#endif
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
Loading…
Reference in New Issue