Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-03-24 15:57:53 +08:00
parent 6ffc894213
commit fd3b815924
31 changed files with 400 additions and 378 deletions

View File

@ -45,6 +45,7 @@ int main(int argc, char *argv[])
QApplication application(argc, argv);
MainWindow mainWindow;
mainWindow.moveToDesktopCenter();
mainWindow.show();
return QCoreApplication::exec();

View File

@ -29,11 +29,14 @@ 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

View File

@ -45,6 +45,7 @@ int main(int argc, char *argv[])
QApplication application(argc, argv);
Widget widget;
widget.moveToDesktopCenter();
widget.show();
return QCoreApplication::exec();

View File

@ -42,7 +42,7 @@ public:
explicit FramelessHelperQt(QObject *parent = nullptr);
~FramelessHelperQt() override;
static void addWindow(QWindow *window);
static void addWindow(QWindow *window, const IsWindowFixedSizeCallback &isWindowFixedSize);
static void removeWindow(QWindow *window);
protected:

View File

@ -41,7 +41,7 @@ public:
explicit FramelessHelperWin();
~FramelessHelperWin() override;
static void addWindow(QWindow *window);
static void addWindow(QWindow *window, const IsWindowFixedSizeCallback &isWindowFixedSize);
static void removeWindow(QWindow *window);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))

View File

@ -29,6 +29,10 @@
#include <QtCore/qsize.h>
#include <QtGui/qcolor.h>
QT_BEGIN_NAMESPACE
class QScreen;
QT_END_NAMESPACE
#ifndef FRAMELESSHELPER_CORE_API
# ifdef FRAMELESSHELPER_CORE_STATIC
# define FRAMELESSHELPER_CORE_API
@ -155,4 +159,51 @@ Q_DECLARE_FLAGS(Options, Option)
Q_FLAG_NS(Options)
Q_DECLARE_OPERATORS_FOR_FLAGS(Options)
enum class SystemTheme : int
{
Unknown = -1,
Light = 0,
Dark = 1,
HighContrast = 2
};
Q_ENUM_NS(SystemTheme)
enum class SystemButtonType : int
{
Unknown = -1,
WindowIcon = 0,
Minimize = 1,
Maximize = 2,
Restore = 3,
Close = 4
};
Q_ENUM_NS(SystemButtonType)
enum class ResourceType : int
{
Image = 0,
Pixmap = 1,
Icon = 2
};
Q_ENUM_NS(ResourceType)
enum class DwmColorizationArea : int
{
None = 0,
StartMenu_TaskBar_ActionCenter = 1,
TitleBar_WindowBorder = 2,
All = 3
};
Q_ENUM_NS(DwmColorizationArea)
using GetWindowFlagsCallback = std::function<Qt::WindowFlags()>;
using SetWindowFlagsCallback = std::function<void(const Qt::WindowFlags)>;
using GetWindowSizeCallback = std::function<QSize()>;
using MoveWindowCallback = std::function<void(const int, const int)>;
using GetWindowScreenCallback = std::function<QScreen *()>;
using IsWindowFixedSizeCallback = std::function<bool()>;
FRAMELESSHELPER_END_NAMESPACE

View File

@ -47,7 +47,7 @@ public:
Q_NODISCARD static FramelessWindowsManager *instance();
void addWindow(QWindow *window);
void addWindow(QWindow *window, const IsWindowFixedSizeCallback &isWindowFixedSize);
void removeWindow(QWindow *window);
Q_SIGNALS:

View File

@ -26,60 +26,9 @@
#include "framelesshelpercore_global.h"
#include <QtGui/qwindowdefs.h>
#include <functional>
QT_BEGIN_NAMESPACE
class QScreen;
QT_END_NAMESPACE
FRAMELESSHELPER_BEGIN_NAMESPACE
enum class SystemTheme : int
{
Light = 0,
Dark = 1,
HighContrastLight = 2,
HighContrastDark = 3
};
Q_ENUM_NS(SystemTheme)
enum class SystemButtonType : int
{
WindowIcon = 0,
Minimize = 1,
Maximize = 2,
Restore = 3,
Close = 4
};
Q_ENUM_NS(SystemButtonType)
enum class ResourceType : int
{
Image = 0,
Pixmap = 1,
Icon = 2
};
Q_ENUM_NS(ResourceType)
#ifdef Q_OS_WINDOWS
enum class DwmColorizationArea : int
{
None = 0,
StartMenu_TaskBar_ActionCenter = 1,
TitleBar_WindowBorder = 2,
All = 3
};
Q_ENUM_NS(DwmColorizationArea)
#endif
using GetWindowFlagsCallback = std::function<Qt::WindowFlags()>;
using SetWindowFlagsCallback = std::function<void(const Qt::WindowFlags)>;
using GetWindowSizeCallback = std::function<QSize()>;
using MoveWindowCallback = std::function<void(const int, const int)>;
using GetWindowScreenCallback = std::function<QScreen *()>;
namespace Utils
{
@ -87,13 +36,13 @@ namespace Utils
[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::Edges calculateWindowEdges(const QWindow *window, const QPoint &pos);
FRAMELESSHELPER_CORE_API void startSystemMove(QWindow *window);
FRAMELESSHELPER_CORE_API void startSystemResize(QWindow *window, const Qt::Edges edges);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowFixedSize(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API QVariant getSystemButtonIconResource
(const SystemButtonType button, const SystemTheme theme, const ResourceType type);
FRAMELESSHELPER_CORE_API void sendMouseReleaseEvent();
[[nodiscard]] FRAMELESSHELPER_CORE_API QWindow *findWindow(const WId winId);
FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter(const GetWindowScreenCallback &getWindowScreen,
const GetWindowSizeCallback &getWindowSize, const MoveWindowCallback &moveWindow, const bool considerTaskBar);
[[nodiscard]] FRAMELESSHELPER_CORE_API SystemTheme getSystemTheme();
#ifdef Q_OS_WINDOWS
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWin8OrGreater();
@ -109,7 +58,8 @@ FRAMELESSHELPER_CORE_API void updateInternalWindowFrameMargins(QWindow *window,
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isFullScreen(const WId winId);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowNoState(const WId winId);
FRAMELESSHELPER_CORE_API void syncWmPaintWithDwm();
FRAMELESSHELPER_CORE_API void showSystemMenu(const QWindow *window, const QPoint &pos);
FRAMELESSHELPER_CORE_API void showSystemMenu(const QWindow *window, const QPoint &pos,
const IsWindowFixedSizeCallback &isWindowFixedSize);
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getDwmColorizationColor();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode();
[[nodiscard]] FRAMELESSHELPER_CORE_API DwmColorizationArea getDwmColorizationArea();
@ -126,11 +76,12 @@ FRAMELESSHELPER_CORE_API void fixupQtInternals(const WId winId);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowFrameBorderVisible();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isTitleBarColorized();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isFrameBorderColorized();
FRAMELESSHELPER_CORE_API void installSystemMenuHook(const QWindow *window);
FRAMELESSHELPER_CORE_API void installSystemMenuHook(const QWindow *window,
const IsWindowFixedSizeCallback &isWindowFixedSize);
FRAMELESSHELPER_CORE_API void uninstallSystemMenuHook(const WId winId);
FRAMELESSHELPER_CORE_API void tryToBeCompatibleWithQtFramelessWindowHint(const WId winId,
const GetWindowFlagsCallback &getWindowFlags, const SetWindowFlagsCallback &setWindowFlags, const bool enable);
FRAMELESSHELPER_CORE_API void disableAeroSnapping(const WId winId);
FRAMELESSHELPER_CORE_API void setAeroSnappingEnabled(const WId winId, const bool enable);
FRAMELESSHELPER_CORE_API void tryToEnableHighestDpiAwarenessLevel();
#endif // Q_OS_WINDOWS

View File

@ -1 +0,0 @@
#include <framelessquickhelper.h>

View File

@ -43,10 +43,10 @@ public:
explicit FramelessQuickEventFilter(QObject *parent = nullptr);
~FramelessQuickEventFilter() override;
Q_INVOKABLE static void addWindow(QQuickWindow *window);
Q_INVOKABLE static void removeWindow(QQuickWindow *window);
Q_INVOKABLE static void setTitleBarItem(QQuickWindow *window, QQuickItem *item);
Q_INVOKABLE static void setHitTestVisible(QQuickWindow *window, QQuickItem *item);
static void addWindow(QQuickWindow *window, const IsWindowFixedSizeCallback &isWindowFixedSize);
static void removeWindow(QQuickWindow *window);
static void setTitleBarItem(QQuickWindow *window, QQuickItem *item);
static void setHitTestVisible(QQuickWindow *window, QQuickItem *item);
protected:
Q_NODISCARD bool eventFilter(QObject *object, QEvent *event) override;

View File

@ -1,58 +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 FramelessQuickHelper : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(FramelessQuickHelper)
#ifdef QML_NAMED_ELEMENT
QML_NAMED_ELEMENT(FramelessHelper)
#endif
#ifdef QML_SINGLETON
QML_SINGLETON
#endif
public:
explicit FramelessQuickHelper(QObject *parent = nullptr);
~FramelessQuickHelper() override;
Q_INVOKABLE static void addWindow(QQuickWindow *window);
Q_INVOKABLE static void removeWindow(QQuickWindow *window);
Q_INVOKABLE static void setTitleBarItem(QQuickWindow *window, QQuickItem *item);
Q_INVOKABLE static void setHitTestVisible(QQuickWindow *window, QQuickItem *item);
};
FRAMELESSHELPER_END_NAMESPACE

View File

@ -41,6 +41,7 @@ class FRAMELESSHELPER_QUICK_API FramelessQuickWindow : public QQuickWindow
Q_DECLARE_PRIVATE(FramelessQuickWindow)
Q_DISABLE_COPY_MOVE(FramelessQuickWindow)
Q_PROPERTY(bool zoomed READ zoomed NOTIFY zoomedChanged FINAL)
Q_PROPERTY(bool fixedSize READ fixedSize WRITE setFixedSize NOTIFY fixedSizeChanged FINAL)
Q_PROPERTY(QColor frameBorderColor READ frameBorderColor NOTIFY frameBorderColorChanged FINAL)
public:
@ -48,6 +49,10 @@ public:
~FramelessQuickWindow() override;
Q_NODISCARD bool zoomed() const;
Q_NODISCARD bool fixedSize() const;
void setFixedSize(const bool value);
Q_NODISCARD QColor frameBorderColor() const;
public Q_SLOTS:
@ -59,9 +64,11 @@ public Q_SLOTS:
void startSystemResize2(const Qt::Edges edges);
void setTitleBarItem(QQuickItem *item);
void setHitTestVisible(QQuickItem *item);
void moveToDesktopCenter();
Q_SIGNALS:
void zoomedChanged();
void fixedSizeChanged();
void frameBorderColorChanged();
private:

View File

@ -35,6 +35,8 @@ class FRAMELESSHELPER_WIDGETS_API FramelessMainWindow : public QMainWindow
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(FramelessMainWindow)
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:
@ -42,15 +44,20 @@ public:
~FramelessMainWindow() override;
Q_NODISCARD Q_INVOKABLE bool isNormal() const;
Q_NODISCARD Q_INVOKABLE bool isZoomed() const;
Q_NODISCARD bool isZoomed() const;
Q_NODISCARD bool isFixedSize() const;
void setFixedSize(const bool value);
void setTitleBarWidget(QWidget *widget);
Q_NODISCARD QWidget *titleBarWidget() const;
Q_INVOKABLE void setHitTestVisible(QWidget *widget);
Q_INVOKABLE void toggleMaximized();
Q_INVOKABLE void toggleFullScreen();
public Q_SLOTS:
void setHitTestVisible(QWidget *widget);
void toggleMaximized();
void toggleFullScreen();
void moveToDesktopCenter();
protected:
void changeEvent(QEvent *event) override;
@ -60,6 +67,8 @@ protected:
void mouseDoubleClickEvent(QMouseEvent *event) override;
Q_SIGNALS:
void zoomedChanged();
void fixedSizeChanged();
void titleBarWidgetChanged();
void systemThemeChanged();

View File

@ -35,6 +35,8 @@ class FRAMELESSHELPER_WIDGETS_API FramelessWidget : public QWidget
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(FramelessWidget)
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)
@ -43,7 +45,11 @@ public:
~FramelessWidget() override;
Q_NODISCARD Q_INVOKABLE bool isNormal() const;
Q_NODISCARD Q_INVOKABLE bool isZoomed() const;
Q_NODISCARD bool isZoomed() const;
Q_NODISCARD bool isFixedSize() const;
void setFixedSize(const bool value);
void setTitleBarWidget(QWidget *widget);
Q_NODISCARD QWidget *titleBarWidget() const;
@ -51,10 +57,11 @@ public:
void setContentWidget(QWidget *widget);
Q_NODISCARD QWidget *contentWidget() const;
Q_INVOKABLE void setHitTestVisible(QWidget *widget);
Q_INVOKABLE void toggleMaximized();
Q_INVOKABLE void toggleFullScreen();
public Q_SLOTS:
void setHitTestVisible(QWidget *widget);
void toggleMaximized();
void toggleFullScreen();
void moveToDesktopCenter();
protected:
void changeEvent(QEvent *event) override;
@ -64,6 +71,8 @@ protected:
void mouseDoubleClickEvent(QMouseEvent *event) override;
Q_SIGNALS:
void zoomedChanged();
void fixedSizeChanged();
void titleBarWidgetChanged();
void contentWidgetChanged();
void systemThemeChanged();

View File

@ -50,17 +50,14 @@ public:
Q_NODISCARD Q_INVOKABLE bool isNormal() const;
Q_NODISCARD Q_INVOKABLE bool isZoomed() const;
Q_NODISCARD Q_INVOKABLE bool isFixedSize() const;
Q_INVOKABLE void setFixedSize(const bool value);
Q_INVOKABLE void setTitleBarWidget(QWidget *widget);
Q_NODISCARD Q_INVOKABLE QWidget *titleBarWidget() const;
Q_NODISCARD Q_INVOKABLE QWidget *getTitleBarWidget() const;
Q_INVOKABLE void setContentWidget(QWidget *widget);
Q_NODISCARD Q_INVOKABLE QWidget *contentWidget() const;
Q_INVOKABLE void setHitTestVisible(QWidget *widget);
Q_INVOKABLE void toggleMaximized();
Q_INVOKABLE void toggleFullScreen();
Q_NODISCARD Q_INVOKABLE QWidget *getContentWidget() const;
Q_INVOKABLE void changeEventHandler(QEvent *event);
Q_INVOKABLE void paintEventHandler(QPaintEvent *event);
@ -68,6 +65,12 @@ public:
Q_INVOKABLE void mouseReleaseEventHandler(QMouseEvent *event);
Q_INVOKABLE void mouseDoubleClickEventHandler(QMouseEvent *event);
public Q_SLOTS:
void setHitTestVisible(QWidget *widget);
void toggleMaximized();
void toggleFullScreen();
void moveToDesktopCenter();
private:
void initialize();
void createSystemTitleBar();

View File

@ -35,6 +35,7 @@ struct QtHelperInternalData
QWindow *window = nullptr;
FramelessHelperQt *qtFramelessHelper = nullptr;
Options options = {};
IsWindowFixedSizeCallback isWindowFixedSize = nullptr;
};
struct QtHelper
@ -55,10 +56,11 @@ FramelessHelperQt::FramelessHelperQt(QObject *parent) : QObject(parent) {}
FramelessHelperQt::~FramelessHelperQt() = default;
void FramelessHelperQt::addWindow(QWindow *window)
void FramelessHelperQt::addWindow(QWindow *window, const IsWindowFixedSizeCallback &isWindowFixedSize)
{
Q_ASSERT(window);
if (!window) {
Q_ASSERT(isWindowFixedSize);
if (!window || !isWindowFixedSize) {
return;
}
g_qtHelper()->mutex.lock();
@ -71,6 +73,7 @@ void FramelessHelperQt::addWindow(QWindow *window)
// Give it a parent so that it can be deleted even if we forget to do so.
data.qtFramelessHelper = new FramelessHelperQt(window);
data.options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
data.isWindowFixedSize = isWindowFixedSize;
g_qtHelper()->data.insert(window, data);
g_qtHelper()->mutex.unlock();
window->setFlags(window->flags() | Qt::FramelessWindowHint);
@ -120,7 +123,7 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
}
const QtHelperInternalData data = g_qtHelper()->data.value(window);
g_qtHelper()->mutex.unlock();
if (Utils::isWindowFixedSize(window)) {
if (data.isWindowFixedSize()) {
return false;
}
const auto mouseEvent = static_cast<QMouseEvent *>(event);

View File

@ -35,12 +35,19 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
struct Win32HelperInternalData
{
HWND hwnd = nullptr;
QWindow *window = nullptr;
Options options = {};
IsWindowFixedSizeCallback isWindowFixedSize = nullptr;
};
struct Win32Helper
{
QMutex mutex = {};
QScopedPointer<FramelessHelperWin> nativeEventFilter;
QHash<QWindow *, Options> options = {};
QHash<WId, QWindow *> windowMapping = {};
QHash<WId, Win32HelperInternalData> data = {};
explicit Win32Helper() = default;
~Win32Helper() = default;
@ -58,26 +65,31 @@ FramelessHelperWin::~FramelessHelperWin()
qApp->removeNativeEventFilter(this);
}
void FramelessHelperWin::addWindow(QWindow *window)
void FramelessHelperWin::addWindow(QWindow *window, const IsWindowFixedSizeCallback &isWindowFixedSize)
{
Q_ASSERT(window);
if (!window) {
Q_ASSERT(isWindowFixedSize);
if (!window || !isWindowFixedSize) {
return;
}
const WId winId = window->winId();
g_win32Helper()->mutex.lock();
if (g_win32Helper()->options.contains(window)) {
if (g_win32Helper()->data.contains(winId)) {
g_win32Helper()->mutex.unlock();
return;
}
Win32HelperInternalData data = {};
data.hwnd = reinterpret_cast<HWND>(winId);
data.window = window;
auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
if ((options & Option::ForceHideWindowFrameBorder) && (options & Option::ForceShowWindowFrameBorder)) {
qWarning() << "You can't use both \"Option::ForceHideWindowFrameBorder\" and "
"\"Option::ForceShowWindowFrameBorder\" at the same time.";
options &= ~(Option::ForceHideWindowFrameBorder | Option::ForceShowWindowFrameBorder);
}
g_win32Helper()->options.insert(window, options);
const WId winId = window->winId();
g_win32Helper()->windowMapping.insert(winId, window);
data.options = options;
data.isWindowFixedSize = isWindowFixedSize;
g_win32Helper()->data.insert(winId, data);
if (g_win32Helper()->nativeEventFilter.isNull()) {
g_win32Helper()->nativeEventFilter.reset(new FramelessHelperWin);
qApp->installNativeEventFilter(g_win32Helper()->nativeEventFilter.data());
@ -100,14 +112,13 @@ void FramelessHelperWin::removeWindow(QWindow *window)
if (!window) {
return;
}
const WId winId = window->winId();
g_win32Helper()->mutex.lock();
if (!g_win32Helper()->options.contains(window)) {
if (!g_win32Helper()->data.contains(winId)) {
g_win32Helper()->mutex.unlock();
return;
}
g_win32Helper()->options.remove(window);
const WId winId = window->winId();
g_win32Helper()->windowMapping.remove(winId);
g_win32Helper()->data.remove(winId);
g_win32Helper()->mutex.unlock();
Utils::updateInternalWindowFrameMargins(window, false);
Utils::updateWindowFrameMargins(winId, true);
@ -135,27 +146,22 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
}
const WId winId = reinterpret_cast<WId>(msg->hwnd);
g_win32Helper()->mutex.lock();
if (!g_win32Helper()->windowMapping.contains(winId)) {
if (!g_win32Helper()->data.contains(winId)) {
g_win32Helper()->mutex.unlock();
return false;
}
QWindow * const window = g_win32Helper()->windowMapping.value(winId);
Q_ASSERT(window);
if (!window) {
g_win32Helper()->mutex.unlock();
return false;
}
const Options options = g_win32Helper()->options.value(window);
const Win32HelperInternalData data = g_win32Helper()->data.value(winId);
g_win32Helper()->mutex.unlock();
const bool frameBorderVisible = [options]() -> bool {
if (options & Option::ForceShowWindowFrameBorder) {
const bool frameBorderVisible = [&data]() -> bool {
if (data.options & Option::ForceShowWindowFrameBorder) {
return true;
}
if (options & Option::ForceHideWindowFrameBorder) {
if (data.options & Option::ForceHideWindowFrameBorder) {
return false;
}
return Utils::isWindowFrameBorderVisible();
}();
const bool fixedSize = data.isWindowFixedSize();
switch (msg->message) {
case WM_NCCALCSIZE: {
// Windows是根据这个消息的返回值来设置窗口的客户区窗口中真正显示的内容
@ -473,7 +479,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// another branch, if you are interested in it, you can give it a
// try.
if (Utils::isWindowFixedSize(window)) {
if (fixedSize) {
*result = HTCLIENT;
return true;
}
@ -487,7 +493,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const bool full = Utils::isFullScreen(winId);
const int frameSizeY = Utils::getResizeBorderThickness(winId, false, true);
const bool isTop = (localPos.y < frameSizeY);
const bool isTitleBar = (false && !(options & Option::DisableDragging));
const bool isTitleBar = (false && !(data.options & Option::DisableDragging));
if (frameBorderVisible) {
// This will handle the left, right and bottom parts of the frame
// because we didn't change them.
@ -592,7 +598,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
#endif
case WM_DPICHANGED: {
// Sync the internal window frame margins with the latest DPI.
Utils::updateInternalWindowFrameMargins(window, true);
Utils::updateInternalWindowFrameMargins(data.window, true);
} break;
case WM_DWMCOMPOSITIONCHANGED: {
// Re-apply the custom window frame if recovered from the basic theme.
@ -687,7 +693,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
return false;
}();
if (themeSettingChanged) {
if (!(options & Option::DontTouchWindowFrameBorderColor)) {
if (!(data.options & Option::DontTouchWindowFrameBorderColor)) {
const bool dark = Utils::shouldAppsUseDarkMode();
Utils::updateWindowFrameBorderColor(winId, dark);
}

View File

@ -161,10 +161,11 @@ FramelessWindowsManager *FramelessWindowsManager::instance()
return g_manager();
}
void FramelessWindowsManager::addWindow(QWindow *window)
void FramelessWindowsManager::addWindow(QWindow *window, const IsWindowFixedSizeCallback &isWindowFixedSize)
{
Q_ASSERT(window);
if (!window) {
Q_ASSERT(isWindowFixedSize);
if (!window || !isWindowFixedSize) {
return;
}
Q_D(FramelessWindowsManager);
@ -199,14 +200,14 @@ void FramelessWindowsManager::addWindow(QWindow *window)
d->mutex.unlock();
const auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
if (pureQt) {
FramelessHelperQt::addWindow(window);
FramelessHelperQt::addWindow(window, isWindowFixedSize);
}
#ifdef Q_OS_WINDOWS
if (!pureQt) {
FramelessHelperWin::addWindow(window);
FramelessHelperWin::addWindow(window, isWindowFixedSize);
}
if (!(options & Option::DontInstallSystemMenuHook)) {
Utils::installSystemMenuHook(window);
Utils::installSystemMenuHook(window, isWindowFixedSize);
}
#endif
}

View File

@ -92,32 +92,16 @@ Qt::Edges Utils::calculateWindowEdges(const QWindow *window, const QPoint &pos)
return edges;
}
bool Utils::isWindowFixedSize(const QWindow *window)
{
Q_ASSERT(window);
if (!window) {
return false;
}
const auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
if (options & Option::DisableResizing) {
return true;
}
if (window->flags() & Qt::MSWindowsFixedSizeDialogHint) {
return true;
}
const QSize minSize = window->minimumSize();
const QSize maxSize = window->maximumSize();
return (!minSize.isEmpty() && !maxSize.isEmpty() && (minSize == maxSize));
}
QVariant Utils::getSystemButtonIconResource
(const SystemButtonType button, const SystemTheme theme, const ResourceType type)
{
const QString resourceUri = [button, theme]() -> QString {
const QString szButton = [button]() -> QString {
switch (button) {
case SystemButtonType::Unknown:
return {};
case SystemButtonType::WindowIcon:
break;
return QStringLiteral("windowIcon");
case SystemButtonType::Minimize:
return QStringLiteral("minimize");
case SystemButtonType::Maximize:
@ -131,14 +115,14 @@ QVariant Utils::getSystemButtonIconResource
}();
const QString szTheme = [theme]() -> QString {
switch (theme) {
case SystemTheme::Unknown:
return {};
case SystemTheme::Light:
return QStringLiteral("light");
case SystemTheme::Dark:
return QStringLiteral("dark");
case SystemTheme::HighContrastLight:
return QStringLiteral("hc-light");
case SystemTheme::HighContrastDark:
return QStringLiteral("hc-dark");
case SystemTheme::HighContrast:
return QStringLiteral("highcontrast");
}
return {};
}();

View File

@ -59,6 +59,7 @@ struct Win32UtilsInternalData
QWindow *window = nullptr;
WNDPROC originalWindowProc = nullptr;
Options options = {};
IsWindowFixedSizeCallback isWindowFixedSize = nullptr;
};
struct Win32UtilsHelper
@ -192,7 +193,8 @@ static const QString successErrorText = QStringLiteral("The operation completed
const Win32UtilsInternalData data = g_utilsHelper()->data.value(hWnd);
g_utilsHelper()->mutex.unlock();
Q_ASSERT(data.window);
if (!data.window) {
Q_ASSERT(data.isWindowFixedSize);
if (!data.window || !data.isWindowFixedSize) {
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
const auto winId = reinterpret_cast<WId>(hWnd);
@ -251,7 +253,7 @@ static const QString successErrorText = QStringLiteral("The operation completed
}
}
if (shouldShowSystemMenu) {
Utils::showSystemMenu(data.window, globalPos);
Utils::showSystemMenu(data.window, globalPos, data.isWindowFixedSize);
// QPA's internal code will handle system menu events separately, and its
// behavior is not what we would want to see because it doesn't know our
// window doesn't have any window frame now, so return early here to avoid
@ -498,10 +500,12 @@ DwmColorizationArea Utils::getDwmColorizationArea()
return DwmColorizationArea::None;
}
void Utils::showSystemMenu(const QWindow *window, const QPoint &pos)
void Utils::showSystemMenu(const QWindow *window, const QPoint &pos,
const IsWindowFixedSizeCallback &isWindowFixedSize)
{
Q_ASSERT(window);
if (!window) {
Q_ASSERT(isWindowFixedSize);
if (!window || !isWindowFixedSize) {
return;
}
const auto hWnd = reinterpret_cast<HWND>(window->winId());
@ -526,7 +530,7 @@ void Utils::showSystemMenu(const QWindow *window, const QPoint &pos)
const auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
const bool maxOrFull = (IsMaximized(hWnd) ||
((options & Option::DontTreatFullScreenAsZoomed) ? false : isFullScreen(reinterpret_cast<WId>(hWnd))));
const bool fixedSize = isWindowFixedSize(window);
const bool fixedSize = isWindowFixedSize();
if (!setState(SC_RESTORE, (maxOrFull && !fixedSize), true)) {
return;
}
@ -1024,10 +1028,12 @@ bool Utils::isFrameBorderColorized()
return isTitleBarColorized();
}
void Utils::installSystemMenuHook(const QWindow *window)
void Utils::installSystemMenuHook(const QWindow *window,
const IsWindowFixedSizeCallback &isWindowFixedSize)
{
Q_ASSERT(window);
if (!window) {
Q_ASSERT(isWindowFixedSize);
if (!window || !isWindowFixedSize) {
return;
}
const auto hwnd = reinterpret_cast<HWND>(window->winId());
@ -1053,6 +1059,7 @@ void Utils::installSystemMenuHook(const QWindow *window)
data.window = const_cast<QWindow *>(window);
data.originalWindowProc = originalWindowProc;
data.options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
data.isWindowFixedSize = isWindowFixedSize;
g_utilsHelper()->data.insert(hwnd, data);
}
@ -1118,7 +1125,7 @@ void Utils::tryToBeCompatibleWithQtFramelessWindowHint(const WId winId,
triggerFrameChange(winId);
}
void Utils::disableAeroSnapping(const WId winId)
void Utils::setAeroSnappingEnabled(const WId winId, const bool enable)
{
Q_ASSERT(winId);
if (!winId) {
@ -1131,7 +1138,13 @@ void Utils::disableAeroSnapping(const WId winId)
qWarning() << getSystemErrorMessage(QStringLiteral("GetWindowLongPtrW"));
return;
}
const DWORD newWindowStyle = ((oldWindowStyle & ~WS_THICKFRAME) | WS_POPUP);
const DWORD newWindowStyle = [enable, oldWindowStyle]() -> DWORD {
if (enable) {
return ((oldWindowStyle & ~WS_POPUP) | WS_THICKFRAME);
} else {
return ((oldWindowStyle & ~WS_THICKFRAME) | WS_POPUP);
}
}();
SetLastError(ERROR_SUCCESS);
if (SetWindowLongPtrW(hwnd, GWL_STYLE, static_cast<LONG_PTR>(newWindowStyle)) == 0) {
qWarning() << getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
@ -1186,4 +1199,15 @@ void Utils::tryToEnableHighestDpiAwarenessLevel()
SetProcessDPIAware();
}
SystemTheme Utils::getSystemTheme()
{
if (isHighContrastModeEnabled()) {
return SystemTheme::HighContrast;
}
if (isWin101809OrGreater() && shouldAppsUseDarkMode()) {
return SystemTheme::Dark;
}
return SystemTheme::Light;
}
FRAMELESSHELPER_END_NAMESPACE

View File

@ -4,7 +4,6 @@ set(INCLUDE_PREFIX ../../include/FramelessHelper/Quick)
set(SOURCES
${INCLUDE_PREFIX}/framelesshelperquick_global.h
${INCLUDE_PREFIX}/framelessquickhelper.h
${INCLUDE_PREFIX}/framelessquickutils.h
${INCLUDE_PREFIX}/framelesshelperimageprovider.h
${INCLUDE_PREFIX}/framelessquickeventfilter.h
@ -13,7 +12,6 @@ set(SOURCES
framelessquickwindow_p.h
framelesshelperquick.qrc
framelesshelper_quick.cpp
framelessquickhelper.cpp
framelessquickutils.cpp
framelesshelperimageprovider.cpp
framelessquickeventfilter.cpp

View File

@ -25,7 +25,6 @@
#include "framelesshelper_quick.h"
#include <QtQml/qqmlengine.h>
#include "framelesshelperimageprovider.h"
#include "framelessquickhelper.h"
#include "framelessquickutils.h"
#include "framelessquickwindow.h"
@ -55,11 +54,6 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
return;
}
engine->addImageProvider(QStringLiteral("framelesshelper"), new FramelessHelperImageProvider);
qmlRegisterSingletonType<FramelessQuickHelper>(FRAMELESSHELPER_QUICK_URI, 1, 0, "FramelessHelper", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
Q_UNUSED(engine);
Q_UNUSED(scriptEngine);
return new FramelessQuickHelper;
});
qmlRegisterSingletonType<FramelessQuickUtils>(FRAMELESSHELPER_QUICK_URI, 1, 0, "FramelessUtils", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
Q_UNUSED(engine);
Q_UNUSED(scriptEngine);

View File

@ -31,7 +31,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
{
Q_ASSERT(!str.isEmpty());
if (str.isEmpty()) {
return SystemTheme::Light;
return SystemTheme::Unknown;
}
if (str.compare(QStringLiteral("light"), Qt::CaseInsensitive) == 0) {
return SystemTheme::Light;
@ -39,19 +39,19 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
if (str.compare(QStringLiteral("dark"), Qt::CaseInsensitive) == 0) {
return SystemTheme::Dark;
}
if (str.compare(QStringLiteral("hc-light"), Qt::CaseInsensitive) == 0) {
return SystemTheme::HighContrastLight;
if (str.compare(QStringLiteral("highcontrast"), Qt::CaseInsensitive) == 0) {
return SystemTheme::HighContrast;
}
if (str.compare(QStringLiteral("hc-dark"), Qt::CaseInsensitive) == 0) {
return SystemTheme::HighContrastDark;
}
return SystemTheme::Light;
return SystemTheme::Unknown;
}
[[nodiscard]] static inline SystemButtonType strToButton(const QString &str)
{
Q_ASSERT(!str.isEmpty());
if (str.isEmpty()) {
return SystemButtonType::Unknown;
}
if (str.compare(QStringLiteral("windowicon"), Qt::CaseInsensitive) == 0) {
return SystemButtonType::WindowIcon;
}
if (str.compare(QStringLiteral("minimize"), Qt::CaseInsensitive) == 0) {
@ -66,7 +66,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
if (str.compare(QStringLiteral("close"), Qt::CaseInsensitive) == 0) {
return SystemButtonType::Close;
}
return SystemButtonType::WindowIcon;
return SystemButtonType::Unknown;
}
FramelessHelperImageProvider::FramelessHelperImageProvider() : QQuickImageProvider(QQuickImageProvider::Pixmap) {}

View File

@ -39,6 +39,7 @@ struct EventFilterDataInternal
QQuickItem *titleBarItem = nullptr;
QList<QQuickItem *> hitTestVisibleItems = {};
Options options = {};
IsWindowFixedSizeCallback isWindowFixedSize = nullptr;
};
struct EventFilterData
@ -94,10 +95,11 @@ FramelessQuickEventFilter::FramelessQuickEventFilter(QObject *parent) : QObject(
FramelessQuickEventFilter::~FramelessQuickEventFilter() = default;
void FramelessQuickEventFilter::addWindow(QQuickWindow *window)
void FramelessQuickEventFilter::addWindow(QQuickWindow *window, const IsWindowFixedSizeCallback &isWindowFixedSize)
{
Q_ASSERT(window);
if (!window) {
Q_ASSERT(isWindowFixedSize);
if (!window || !isWindowFixedSize) {
return;
}
g_data()->mutex.lock();
@ -110,6 +112,7 @@ void FramelessQuickEventFilter::addWindow(QQuickWindow *window)
data.options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
// Give it a parent so that it can be deleted even if we forget to do so.
data.eventFilter = new FramelessQuickEventFilter(window);
data.isWindowFixedSize = isWindowFixedSize;
g_data()->data.insert(window, data);
g_data()->mutex.unlock();
window->installEventFilter(data.eventFilter);
@ -188,7 +191,7 @@ bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event)
g_data()->mutex.unlock();
return false;
}
const Options options = g_data()->data.value(window).options;
const EventFilterDataInternal data = g_data()->data.value(window);
g_data()->mutex.unlock();
const QEvent::Type eventType = event->type();
if ((eventType != QEvent::MouseButtonPress)
@ -213,9 +216,10 @@ bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event)
return false;
}
const bool titleBar = isInTitleBarDraggableArea(window, scenePos);
const bool isFixedSize = data.isWindowFixedSize();
switch (eventType) {
case QEvent::MouseButtonPress: {
if (options & Option::DisableDragging) {
if (data.options & Option::DisableDragging) {
return false;
}
if (button != Qt::LeftButton) {
@ -228,7 +232,7 @@ bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event)
return true;
}
case QEvent::MouseButtonRelease: {
if (options & Option::DisableSystemMenu) {
if (data.options & Option::DisableSystemMenu) {
return false;
}
if (button != Qt::RightButton) {
@ -243,11 +247,11 @@ bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event)
const QPoint globalPos = mouseEvent->globalPos();
#endif
const QPoint nativePos = QPointF(QPointF(globalPos) * window->effectiveDevicePixelRatio()).toPoint();
Utils::showSystemMenu(window, nativePos);
Utils::showSystemMenu(window, nativePos, data.isWindowFixedSize);
return true;
}
case QEvent::MouseButtonDblClick: {
if ((options & Option::NoDoubleClickMaximizeToggle) || Utils::isWindowFixedSize(window)) {
if ((data.options & Option::NoDoubleClickMaximizeToggle) || isFixedSize) {
return false;
}
if (button != Qt::LeftButton) {
@ -257,7 +261,7 @@ bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event)
return false;
}
if ((visibility == QQuickWindow::Maximized) ||
((options & Option::DontTreatFullScreenAsZoomed) ? false : (visibility == QQuickWindow::FullScreen))) {
((data.options & Option::DontTreatFullScreenAsZoomed) ? false : (visibility == QQuickWindow::FullScreen))) {
window->showNormal();
} else {
window->showMaximized();

View File

@ -1,76 +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 "framelessquickhelper.h"
#include <QtQuick/qquickwindow.h>
#include <framelesswindowsmanager.h>
#include "framelessquickeventfilter.h"
FRAMELESSHELPER_BEGIN_NAMESPACE
FramelessQuickHelper::FramelessQuickHelper(QObject *parent) : QObject(parent) {}
FramelessQuickHelper::~FramelessQuickHelper() = default;
void FramelessQuickHelper::addWindow(QQuickWindow *window)
{
Q_ASSERT(window);
if (!window) {
return;
}
FramelessWindowsManager::instance()->addWindow(window);
FramelessQuickEventFilter::addWindow(window);
}
void FramelessQuickHelper::removeWindow(QQuickWindow *window)
{
Q_ASSERT(window);
if (!window) {
return;
}
FramelessQuickEventFilter::removeWindow(window);
FramelessWindowsManager::instance()->removeWindow(window);
}
void FramelessQuickHelper::setTitleBarItem(QQuickWindow *window, QQuickItem *item)
{
Q_ASSERT(window);
Q_ASSERT(item);
if (!window || !item) {
return;
}
FramelessQuickEventFilter::setTitleBarItem(window, item);
}
void FramelessQuickHelper::setHitTestVisible(QQuickWindow *window, QQuickItem *item)
{
Q_ASSERT(window);
Q_ASSERT(item);
if (!window || !item) {
return;
}
FramelessQuickEventFilter::setHitTestVisible(window, item);
}
FRAMELESSHELPER_END_NAMESPACE

View File

@ -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/framelessquickhelper.h"

View File

@ -29,7 +29,7 @@
#include <QtQuick/private/qquickanchors_p.h>
#include <framelesswindowsmanager.h>
#include <utils.h>
#include "framelessquickhelper.h"
#include "framelessquickeventfilter.h"
FRAMELESSHELPER_BEGIN_NAMESPACE
@ -54,6 +54,23 @@ bool FramelessQuickWindowPrivate::isZoomed() const
((m_options & Option::DontTreatFullScreenAsZoomed) ? false : (visibility == FramelessQuickWindow::FullScreen)));
}
bool FramelessQuickWindowPrivate::isFixedSize() const
{
if (m_options & Option::DisableResizing) {
return true;
}
Q_Q(const FramelessQuickWindow);
if (q->flags() & Qt::MSWindowsFixedSizeDialogHint) {
return true;
}
const QSize minSize = q->minimumSize();
const QSize maxSize = q->maximumSize();
if (!minSize.isEmpty() && !maxSize.isEmpty() && (minSize == maxSize)) {
return true;
}
return false;
}
QColor FramelessQuickWindowPrivate::getFrameBorderColor() const
{
#ifdef Q_OS_WINDOWS
@ -71,7 +88,7 @@ void FramelessQuickWindowPrivate::setTitleBarItem(QQuickItem *item)
return;
}
Q_Q(FramelessQuickWindow);
FramelessQuickHelper::setTitleBarItem(q, item);
FramelessQuickEventFilter::setTitleBarItem(q, item);
}
void FramelessQuickWindowPrivate::setHitTestVisible(QQuickItem *item)
@ -81,7 +98,37 @@ void FramelessQuickWindowPrivate::setHitTestVisible(QQuickItem *item)
return;
}
Q_Q(FramelessQuickWindow);
FramelessQuickHelper::setHitTestVisible(q, item);
FramelessQuickEventFilter::setHitTestVisible(q, item);
}
void FramelessQuickWindowPrivate::moveToDesktopCenter()
{
Q_Q(FramelessQuickWindow);
Utils::moveWindowToDesktopCenter([q]() -> QScreen * { return q->screen(); },
[q]() -> QSize { return q->size(); },
[q](const int x, const int y) -> void {
q->setX(x);
q->setY(y);
}, true);
}
void FramelessQuickWindowPrivate::setFixedSize(const bool value)
{
if (isFixedSize() == value) {
return;
}
Q_Q(FramelessQuickWindow);
if (value) {
const QSize size = q->size();
q->setMinimumSize(size);
q->setMaximumSize(size);
q->setFlags(q->flags() | Qt::MSWindowsFixedSizeDialogHint);
} else {
q->setFlags(q->flags() & ~Qt::MSWindowsFixedSizeDialogHint);
q->setMinimumSize(kInvalidWindowSize);
q->setMaximumSize(QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX));
}
Q_EMIT q->fixedSizeChanged();
}
void FramelessQuickWindowPrivate::showMinimized2()
@ -100,10 +147,10 @@ void FramelessQuickWindowPrivate::showMinimized2()
void FramelessQuickWindowPrivate::toggleMaximize()
{
Q_Q(FramelessQuickWindow);
if (Utils::isWindowFixedSize(q)) {
if (isFixedSize()) {
return;
}
Q_Q(FramelessQuickWindow);
if (isZoomed()) {
q->showNormal();
} else {
@ -113,10 +160,10 @@ void FramelessQuickWindowPrivate::toggleMaximize()
void FramelessQuickWindowPrivate::toggleFullScreen()
{
Q_Q(FramelessQuickWindow);
if (Utils::isWindowFixedSize(q)) {
if (isFixedSize()) {
return;
}
Q_Q(FramelessQuickWindow);
const QWindow::Visibility visibility = q->visibility();
if (visibility == QWindow::FullScreen) {
q->setVisibility(m_savedVisibility);
@ -136,7 +183,7 @@ void FramelessQuickWindowPrivate::showSystemMenu(const QPoint &pos)
const QPoint globalPos = q->mapToGlobal(pos);
# endif
const QPoint nativePos = QPointF(QPointF(globalPos) * q->effectiveDevicePixelRatio()).toPoint();
Utils::showSystemMenu(q, nativePos);
Utils::showSystemMenu(q, nativePos, [this]() -> bool { return isFixedSize(); });
#endif
}
@ -152,13 +199,13 @@ void FramelessQuickWindowPrivate::startSystemMove2()
void FramelessQuickWindowPrivate::startSystemResize2(const Qt::Edges edges)
{
if (isFixedSize()) {
return;
}
if (edges == Qt::Edges{}) {
return;
}
Q_Q(FramelessQuickWindow);
if (Utils::isWindowFixedSize(q)) {
return;
}
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
q->startSystemResize(edges);
#else
@ -174,7 +221,9 @@ void FramelessQuickWindowPrivate::initialize()
m_initialized = true;
Q_Q(FramelessQuickWindow);
q->setProperty(kInternalOptionsFlag, QVariant::fromValue(m_options));
FramelessQuickHelper::addWindow(q);
FramelessWindowsManager * const manager = FramelessWindowsManager::instance();
manager->addWindow(q, [this]() -> bool { return isFixedSize(); });
FramelessQuickEventFilter::addWindow(q, [this]() -> bool { return isFixedSize(); });
#ifdef Q_OS_WINDOWS
if (isFrameBorderVisible()) {
QQuickItem * const rootItem = q->contentItem();
@ -187,7 +236,7 @@ void FramelessQuickWindowPrivate::initialize()
Q_EMIT q->zoomedChanged();
});
connect(q, &FramelessQuickWindow::activeChanged, this, &FramelessQuickWindowPrivate::updateTopBorderColor);
connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged, this, [this, q](){
connect(manager, &FramelessWindowsManager::systemThemeChanged, this, [this, q](){
updateTopBorderColor();
Q_EMIT q->frameBorderColorChanged();
});
@ -197,12 +246,6 @@ void FramelessQuickWindowPrivate::initialize()
topBorderAnchors->setRight(rootItemPrivate->right());
}
#endif
Utils::moveWindowToDesktopCenter([q]() -> QScreen * { return q->screen(); },
[q]() -> QSize { return q->size(); },
[q](const int x, const int y) -> void {
q->setX(x);
q->setY(y);
}, true);
}
bool FramelessQuickWindowPrivate::isFrameBorderVisible() const
@ -245,6 +288,18 @@ bool FramelessQuickWindow::zoomed() const
return d->isZoomed();
}
bool FramelessQuickWindow::fixedSize() const
{
Q_D(const FramelessQuickWindow);
return d->isFixedSize();
}
void FramelessQuickWindow::setFixedSize(const bool value)
{
Q_D(FramelessQuickWindow);
d->setFixedSize(value);
}
QColor FramelessQuickWindow::frameBorderColor() const
{
Q_D(const FramelessQuickWindow);
@ -271,6 +326,12 @@ void FramelessQuickWindow::setHitTestVisible(QQuickItem *item)
d->setHitTestVisible(item);
}
void FramelessQuickWindow::moveToDesktopCenter()
{
Q_D(FramelessQuickWindow);
d->moveToDesktopCenter();
}
void FramelessQuickWindow::showMinimized2()
{
Q_D(FramelessQuickWindow);

View File

@ -48,6 +48,7 @@ public:
~FramelessQuickWindowPrivate() override;
Q_INVOKABLE Q_NODISCARD bool isZoomed() const;
Q_INVOKABLE Q_NODISCARD bool isFixedSize() const;
Q_INVOKABLE Q_NODISCARD QColor getFrameBorderColor() const;
Q_INVOKABLE Q_NODISCARD bool isFrameBorderVisible() const;
@ -60,6 +61,8 @@ public Q_SLOTS:
void startSystemResize2(const Qt::Edges edges);
void setTitleBarItem(QQuickItem *item);
void setHitTestVisible(QQuickItem *item);
void moveToDesktopCenter();
void setFixedSize(const bool value);
private:
void initialize();

View File

@ -44,6 +44,16 @@ bool FramelessMainWindow::isZoomed() const
return m_helper->isZoomed();
}
bool FramelessMainWindow::isFixedSize() const
{
return m_helper->isFixedSize();
}
void FramelessMainWindow::setFixedSize(const bool value)
{
m_helper->setFixedSize(value);
}
void FramelessMainWindow::setTitleBarWidget(QWidget *widget)
{
m_helper->setTitleBarWidget(widget);
@ -51,7 +61,7 @@ void FramelessMainWindow::setTitleBarWidget(QWidget *widget)
QWidget *FramelessMainWindow::titleBarWidget() const
{
return m_helper->titleBarWidget();
return m_helper->getTitleBarWidget();
}
void FramelessMainWindow::setHitTestVisible(QWidget *widget)
@ -69,6 +79,11 @@ void FramelessMainWindow::toggleFullScreen()
m_helper->toggleFullScreen();
}
void FramelessMainWindow::moveToDesktopCenter()
{
m_helper->moveToDesktopCenter();
}
void FramelessMainWindow::changeEvent(QEvent *event)
{
QMainWindow::changeEvent(event);

View File

@ -44,6 +44,16 @@ bool FramelessWidget::isZoomed() const
return m_helper->isZoomed();
}
bool FramelessWidget::isFixedSize() const
{
return m_helper->isFixedSize();
}
void FramelessWidget::setFixedSize(const bool value)
{
m_helper->setFixedSize(value);
}
void FramelessWidget::setTitleBarWidget(QWidget *widget)
{
m_helper->setTitleBarWidget(widget);
@ -51,7 +61,7 @@ void FramelessWidget::setTitleBarWidget(QWidget *widget)
QWidget *FramelessWidget::titleBarWidget() const
{
return m_helper->titleBarWidget();
return m_helper->getTitleBarWidget();
}
void FramelessWidget::setContentWidget(QWidget *widget)
@ -61,7 +71,7 @@ void FramelessWidget::setContentWidget(QWidget *widget)
QWidget *FramelessWidget::contentWidget() const
{
return m_helper->contentWidget();
return m_helper->getContentWidget();
}
void FramelessWidget::setHitTestVisible(QWidget *widget)
@ -79,6 +89,11 @@ void FramelessWidget::toggleFullScreen()
m_helper->toggleFullScreen();
}
void FramelessWidget::moveToDesktopCenter()
{
m_helper->moveToDesktopCenter();
}
void FramelessWidget::changeEvent(QEvent *event)
{
QWidget::changeEvent(event);

View File

@ -32,7 +32,6 @@
#include <QtWidgets/qpushbutton.h>
#include <framelesswindowsmanager.h>
#include <utils.h>
#include "framelesswidget.h"
FRAMELESSHELPER_BEGIN_NAMESPACE
@ -76,6 +75,41 @@ bool FramelessWidgetsHelper::isZoomed() const
return (q->isMaximized() || ((m_options & Option::DontTreatFullScreenAsZoomed) ? false : q->isFullScreen()));
}
bool FramelessWidgetsHelper::isFixedSize() const
{
if (m_options & Option::DisableResizing) {
return true;
}
if (q->windowFlags() & Qt::MSWindowsFixedSizeDialogHint) {
return true;
}
const QSize minSize = q->minimumSize();
const QSize maxSize = q->maximumSize();
if (!minSize.isEmpty() && !maxSize.isEmpty() && (minSize == maxSize)) {
return true;
}
if (q->sizePolicy() == QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)) {
return true;
}
return false;
}
void FramelessWidgetsHelper::setFixedSize(const bool value)
{
if (isFixedSize() == value) {
return;
}
if (value) {
q->setFixedSize(q->size());
q->setWindowFlags(q->windowFlags() | Qt::MSWindowsFixedSizeDialogHint);
} else {
q->setWindowFlags(q->windowFlags() & ~Qt::MSWindowsFixedSizeDialogHint);
q->setMinimumSize(kInvalidWindowSize);
q->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
}
QMetaObject::invokeMethod(q, "fixedSizeChanged");
}
void FramelessWidgetsHelper::setTitleBarWidget(QWidget *widget)
{
Q_ASSERT(widget);
@ -102,7 +136,7 @@ void FramelessWidgetsHelper::setTitleBarWidget(QWidget *widget)
QMetaObject::invokeMethod(q, "titleBarWidgetChanged");
}
QWidget *FramelessWidgetsHelper::titleBarWidget() const
QWidget *FramelessWidgetsHelper::getTitleBarWidget() const
{
return m_userTitleBarWidget;
}
@ -128,7 +162,7 @@ void FramelessWidgetsHelper::setContentWidget(QWidget *widget)
QMetaObject::invokeMethod(q, "contentWidgetChanged");
}
QWidget *FramelessWidgetsHelper::contentWidget() const
QWidget *FramelessWidgetsHelper::getContentWidget() const
{
return m_userContentWidget;
}
@ -252,7 +286,7 @@ void FramelessWidgetsHelper::mouseReleaseEventHandler(QMouseEvent *event)
const QPoint globalPos = event->globalPos();
# endif
const QPoint nativePos = QPointF(QPointF(globalPos) * q->devicePixelRatioF()).toPoint();
Utils::showSystemMenu(m_window, nativePos);
Utils::showSystemMenu(m_window, nativePos, [this]() -> bool { return isFixedSize(); });
#endif
}
@ -262,7 +296,7 @@ void FramelessWidgetsHelper::mouseDoubleClickEventHandler(QMouseEvent *event)
if (!event) {
return;
}
if ((m_options & Option::NoDoubleClickMaximizeToggle) || Utils::isWindowFixedSize(m_window)) {
if ((m_options & Option::NoDoubleClickMaximizeToggle) || isFixedSize()) {
return;
}
if (event->button() != Qt::LeftButton) {
@ -315,8 +349,8 @@ void FramelessWidgetsHelper::initialize()
[this](const Qt::WindowFlags flags) -> void { q->setWindowFlags(flags); },
true);
}
FramelessWindowsManager *manager = FramelessWindowsManager::instance();
manager->addWindow(m_window);
FramelessWindowsManager * const manager = FramelessWindowsManager::instance();
manager->addWindow(m_window, [this]() -> bool { return isFixedSize(); });
connect(manager, &FramelessWindowsManager::systemThemeChanged, this, [this](){
if (m_options & Option::UseStandardWindowLayout) {
updateSystemTitleBarStyleSheet();
@ -326,19 +360,9 @@ void FramelessWidgetsHelper::initialize()
QMetaObject::invokeMethod(q, "systemThemeChanged");
});
setupInitialUi();
if (!(m_options & Option::DontMoveWindowToDesktopCenter)) {
Utils::moveWindowToDesktopCenter(
[this]() -> QScreen * {
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
return q->screen();
#else
return m_window->screen();
#endif
},
[this]() -> QSize { return q->size(); },
[this](const int x, const int y) -> void { q->move(x, y); },
true);
}
connect(m_window, &QWindow::windowStateChanged, this, [this](){
QMetaObject::invokeMethod(q, "zoomedChanged");
});
}
void FramelessWidgetsHelper::createSystemTitleBar()
@ -355,12 +379,12 @@ void FramelessWidgetsHelper::createSystemTitleBar()
windowTitleFont.setPointSize(11);
m_systemWindowTitleLabel->setFont(windowTitleFont);
m_systemWindowTitleLabel->setText(q->windowTitle());
connect(q, &FramelessWidget::windowTitleChanged, m_systemWindowTitleLabel, &QLabel::setText);
connect(q, &QWidget::windowTitleChanged, m_systemWindowTitleLabel, &QLabel::setText);
m_systemMinimizeButton = new QPushButton(m_systemTitleBarWidget);
m_systemMinimizeButton->setFixedSize(kDefaultSystemButtonSize);
m_systemMinimizeButton->setIconSize(kDefaultSystemButtonIconSize);
m_systemMinimizeButton->setToolTip(tr("Minimize"));
connect(m_systemMinimizeButton, &QPushButton::clicked, q, &FramelessWidget::showMinimized);
connect(m_systemMinimizeButton, &QPushButton::clicked, q, &QWidget::showMinimized);
m_systemMaximizeButton = new QPushButton(m_systemTitleBarWidget);
m_systemMaximizeButton->setFixedSize(kDefaultSystemButtonSize);
m_systemMaximizeButton->setIconSize(kDefaultSystemButtonIconSize);
@ -370,7 +394,7 @@ void FramelessWidgetsHelper::createSystemTitleBar()
m_systemCloseButton->setFixedSize(kDefaultSystemButtonSize);
m_systemCloseButton->setIconSize(kDefaultSystemButtonIconSize);
m_systemCloseButton->setToolTip(tr("Close"));
connect(m_systemCloseButton, &QPushButton::clicked, q, &FramelessWidget::close);
connect(m_systemCloseButton, &QPushButton::clicked, q, &QWidget::close);
updateSystemButtonsIcon();
const auto systemTitleBarLayout = new QHBoxLayout(m_systemTitleBarWidget);
systemTitleBarLayout->setContentsMargins(0, 0, 0, 0);
@ -525,7 +549,7 @@ void FramelessWidgetsHelper::updateSystemButtonsIcon()
void FramelessWidgetsHelper::toggleMaximized()
{
if (Utils::isWindowFixedSize(m_window)) {
if (isFixedSize()) {
return;
}
if (isZoomed()) {
@ -537,7 +561,7 @@ void FramelessWidgetsHelper::toggleMaximized()
void FramelessWidgetsHelper::toggleFullScreen()
{
if (Utils::isWindowFixedSize(m_window)) {
if (isFixedSize()) {
return;
}
const Qt::WindowStates windowState = q->windowState();
@ -549,4 +573,19 @@ void FramelessWidgetsHelper::toggleFullScreen()
}
}
void FramelessWidgetsHelper::moveToDesktopCenter()
{
Utils::moveWindowToDesktopCenter(
[this]() -> QScreen * {
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
return q->screen();
#else
return m_window->screen();
#endif
},
[this]() -> QSize { return q->size(); },
[this](const int x, const int y) -> void { q->move(x, y); },
true);
}
FRAMELESSHELPER_END_NAMESPACE