forked from github_mirror/framelesshelper
add the Options feature to control some details
Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
parent
09acbfaf02
commit
12988f2ddf
|
@ -29,7 +29,7 @@
|
|||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags) : FramelessMainWindow(parent, flags)
|
||||
MainWindow::MainWindow(QWidget *parent, const Qt::WindowFlags flags) : FramelessMainWindow(parent, flags)
|
||||
{
|
||||
setupUi();
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ class MainWindow : public FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessMainWindow)
|
|||
Q_DISABLE_COPY_MOVE(MainWindow)
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = {});
|
||||
explicit MainWindow(QWidget *parent = nullptr, const Qt::WindowFlags flags = {});
|
||||
~MainWindow() override;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
Widget::Widget(QWidget *parent) : FramelessWidget(parent, WindowLayout::Standard)
|
||||
Widget::Widget(QWidget *parent) : FramelessWidget(parent, {Option::UseStandardWindowLayout})
|
||||
{
|
||||
setupUi();
|
||||
startTimer(500);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qvariant.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
#include "framelesswindowsmanager.h"
|
||||
|
@ -76,11 +77,16 @@ void FramelessHelperWin::addWindow(QWindow *window)
|
|||
qApp->installNativeEventFilter(g_win32Helper()->nativeEventFilter.data());
|
||||
}
|
||||
g_win32Helper()->mutex.unlock();
|
||||
Utils::fixupQtInternals(winId);
|
||||
const auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
|
||||
if (!(options & Option::DontModifyQtInternals)) {
|
||||
Utils::fixupQtInternals(winId);
|
||||
}
|
||||
Utils::updateInternalWindowFrameMargins(window, true);
|
||||
Utils::updateWindowFrameMargins(winId, false);
|
||||
const bool dark = Utils::shouldAppsUseDarkMode();
|
||||
Utils::updateWindowFrameBorderColor(winId, dark);
|
||||
if (!(options & Option::DontModifyWindowFrameBorderColor)) {
|
||||
const bool dark = Utils::shouldAppsUseDarkMode();
|
||||
Utils::updateWindowFrameBorderColor(winId, dark);
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessHelperWin::removeWindow(QWindow *window)
|
||||
|
@ -119,7 +125,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
#endif
|
||||
if (!msg->hwnd) {
|
||||
// Why sometimes the window handle is null? Is it designed to be like this?
|
||||
// Anyway, we should skip the entire function in this case.
|
||||
// Anyway, we should skip the entire processing in this case.
|
||||
return false;
|
||||
}
|
||||
const WId winId = reinterpret_cast<WId>(msg->hwnd);
|
||||
|
@ -134,6 +140,22 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
window->setProperty(kInternalOptionsFlag, QVariant::fromValue(options));
|
||||
}
|
||||
const bool frameBorderVisible = [options]() -> bool {
|
||||
if (options & Option::ForceShowWindowFrameBorder) {
|
||||
return true;
|
||||
}
|
||||
if (options & Option::ForceHideWindowFrameBorder) {
|
||||
return false;
|
||||
}
|
||||
return Utils::isWindowFrameBorderVisible();
|
||||
}();
|
||||
switch (msg->message) {
|
||||
case WM_NCCALCSIZE: {
|
||||
// Windows是根据这个消息的返回值来设置窗口的客户区(窗口中真正显示的内容)
|
||||
|
@ -226,7 +248,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
const auto clientRect = ((static_cast<BOOL>(msg->wParam) == FALSE)
|
||||
? reinterpret_cast<LPRECT>(msg->lParam)
|
||||
: &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(msg->lParam))->rgrc[0]);
|
||||
if (Utils::isWindowFrameBorderVisible()) {
|
||||
if (frameBorderVisible) {
|
||||
// Store the original top before the default window proc applies the default frame.
|
||||
const LONG originalTop = clientRect->top;
|
||||
// Apply the default frame.
|
||||
|
@ -252,7 +274,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// a window when it's maximized unless you restore it).
|
||||
const int frameSizeY = Utils::getResizeBorderThickness(winId, false, true);
|
||||
clientRect->top += frameSizeY;
|
||||
if (!Utils::isWindowFrameBorderVisible()) {
|
||||
if (!frameBorderVisible) {
|
||||
clientRect->bottom -= frameSizeY;
|
||||
const int frameSizeX = Utils::getResizeBorderThickness(winId, true, true);
|
||||
clientRect->left += frameSizeX;
|
||||
|
@ -466,7 +488,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
const int frameSizeY = Utils::getResizeBorderThickness(winId, false, true);
|
||||
const bool isTop = (localPos.y < frameSizeY);
|
||||
static constexpr const bool isTitleBar = false;
|
||||
if (Utils::isWindowFrameBorderVisible()) {
|
||||
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);
|
||||
|
@ -579,7 +601,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
default:
|
||||
break;
|
||||
}
|
||||
if (!Utils::isWindowFrameBorderVisible()) {
|
||||
if (!frameBorderVisible) {
|
||||
switch (msg->message) {
|
||||
case WM_NCUAHDRAWCAPTION:
|
||||
case WM_NCUAHDRAWFRAME: {
|
||||
|
@ -665,8 +687,10 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
return false;
|
||||
}();
|
||||
if (themeSettingChanged) {
|
||||
const bool dark = Utils::shouldAppsUseDarkMode();
|
||||
Utils::updateWindowFrameBorderColor(winId, dark);
|
||||
if (!(options & Option::DontModifyWindowFrameBorderColor)) {
|
||||
const bool dark = Utils::shouldAppsUseDarkMode();
|
||||
Utils::updateWindowFrameBorderColor(winId, dark);
|
||||
}
|
||||
}
|
||||
if (themeSettingChanged || (msg->message == WM_THEMECHANGED)
|
||||
|| (msg->message == WM_DWMCOLORIZATIONCOLORCHANGED)) {
|
||||
|
|
|
@ -108,11 +108,29 @@ Q_NAMESPACE_EXPORT(FRAMELESSHELPER_CORE_API)
|
|||
[[maybe_unused]] static constexpr const QSize kDefaultSystemButtonSize = {int(qRound(qreal(kDefaultTitleBarHeight) * 1.5)), kDefaultTitleBarHeight};
|
||||
[[maybe_unused]] static constexpr const QSize kDefaultSystemButtonIconSize = {16, 16};
|
||||
|
||||
enum class WindowLayout : int
|
||||
[[maybe_unused]] static constexpr const char kInternalOptionsFlag[] = "FRAMELESSHELPER_INTERNAL_OPTIONS";
|
||||
|
||||
enum class Option : int
|
||||
{
|
||||
Standard = 0,
|
||||
Custom = 1
|
||||
Default = 0x00000000, // Default placeholder, have no effect.
|
||||
ForceHideWindowFrameBorder = 0x00000001, // Windows only, force hide the window frame border even on Windows 10 and onwards.
|
||||
ForceShowWindowFrameBorder = 0x00000002, // Windows only, force show the window frame border even on Windows 7 (~ 8.1).
|
||||
DontDrawTopWindowFrameBorder = 0x00000004, // Windows only, don't draw the top window frame border even if the window frame border is visible.
|
||||
EnableRoundedWindowCorners = 0x00000008, // Not implemented yet.
|
||||
TransparentWindowBackground = 0x00000010, // Not implemented yet.
|
||||
MaximizeButtonDocking = 0x00000020, // Windows only, enable the window docking feature introduced in Windows 11.
|
||||
UseStandardWindowLayout = 0x00000040, // The standard window layout is a titlebar always on top and fill the window width.
|
||||
BeCompatibleWithQtFramelessWindowHint = 0x00000080, // Windows only, make the code compatible with Qt::FramelessWindowHint. Don't use this option unless you really need that flag.
|
||||
DontModifyQtInternals = 0x00000100, // Windows only, don't touch Qt's internal data.
|
||||
DontModifyWindowFrameBorderColor = 0x00000200, // Windows only, don't touch the window frame border color.
|
||||
DontInstallSystemMenuHook = 0x00000400, // Windows only, don't install the system menu hook.
|
||||
DisableSystemMenu = 0x00000800, // Windows only, don't open the system menu when right clicks the titlebar.
|
||||
NoDoubleClickMaximizeToggle = 0x00001000 // Don't toggle the maximize state when double clicks the titlebar.
|
||||
};
|
||||
Q_ENUM_NS(WindowLayout)
|
||||
Q_FLAG_NS(Option)
|
||||
Q_DECLARE_FLAGS(Options, Option)
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(Options)
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(Options))
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "framelesswindowsmanager.h"
|
||||
#include "framelesswindowsmanager_p.h"
|
||||
#include <QtCore/qvariant.h>
|
||||
#include <QtGui/qscreen.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
#include "framelesshelper_qt.h"
|
||||
|
@ -182,7 +183,10 @@ void FramelessWindowsManager::addWindow(QWindow *window)
|
|||
if (!pureQt) {
|
||||
FramelessHelperWin::addWindow(window);
|
||||
}
|
||||
Utils::installSystemMenuHook(winId);
|
||||
const auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
|
||||
if (!(options & Option::DontInstallSystemMenuHook)) {
|
||||
Utils::installSystemMenuHook(winId);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -208,7 +212,10 @@ void FramelessWindowsManager::removeWindow(QWindow *window)
|
|||
disconnect(d->win32WorkaroundConnections.value(uuid));
|
||||
d->win32WorkaroundConnections.remove(uuid);
|
||||
}
|
||||
Utils::uninstallSystemMenuHook(winId);
|
||||
const auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
|
||||
if (!(options & Option::DontInstallSystemMenuHook)) {
|
||||
Utils::uninstallSystemMenuHook(winId);
|
||||
}
|
||||
#endif
|
||||
static const bool pureQt = d->usePureQtImplementation();
|
||||
if (pureQt) {
|
||||
|
|
|
@ -77,6 +77,7 @@ FRAMELESSHELPER_CORE_API void startSystemResize(QWindow *window, const Qt::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();
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWin8OrGreater();
|
||||
|
@ -111,6 +112,7 @@ FRAMELESSHELPER_CORE_API void fixupQtInternals(const WId winId);
|
|||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isFrameBorderColorized();
|
||||
FRAMELESSHELPER_CORE_API void installSystemMenuHook(const WId winId);
|
||||
FRAMELESSHELPER_CORE_API void uninstallSystemMenuHook(const WId winId);
|
||||
FRAMELESSHELPER_CORE_API void tryToBeCompatibleWithQtFramelessWindowHint(QWindow *window, const bool enable);
|
||||
#endif // Q_OS_WINDOWS
|
||||
|
||||
} // namespace Utils
|
||||
|
|
|
@ -913,7 +913,9 @@ void Utils::fixupQtInternals(const WId winId)
|
|||
SetLastError(ERROR_SUCCESS);
|
||||
if (SetWindowLongPtrW(hwnd, GWL_STYLE, static_cast<LONG_PTR>(newWindowStyle)) == 0) {
|
||||
qWarning() << getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
|
||||
return;
|
||||
}
|
||||
triggerFrameChange(winId);
|
||||
}
|
||||
|
||||
void Utils::startSystemMove(QWindow *window)
|
||||
|
@ -925,10 +927,7 @@ void Utils::startSystemMove(QWindow *window)
|
|||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
window->startSystemMove();
|
||||
#else
|
||||
if (ReleaseCapture() == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(QStringLiteral("ReleaseCapture"));
|
||||
return;
|
||||
}
|
||||
sendMouseReleaseEvent();
|
||||
const auto hwnd = reinterpret_cast<HWND>(window->winId());
|
||||
if (PostMessageW(hwnd, WM_SYSCOMMAND, 0xF012 /*SC_DRAGMOVE*/, 0) == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(QStringLiteral("PostMessageW"));
|
||||
|
@ -948,10 +947,7 @@ void Utils::startSystemResize(QWindow *window, const Qt::Edges edges)
|
|||
if (edges == Qt::Edges{}) {
|
||||
return;
|
||||
}
|
||||
if (ReleaseCapture() == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(QStringLiteral("ReleaseCapture"));
|
||||
return;
|
||||
}
|
||||
sendMouseReleaseEvent();
|
||||
const auto hwnd = reinterpret_cast<HWND>(window->winId());
|
||||
if (PostMessageW(hwnd, WM_SYSCOMMAND, qtEdgesToWin32Orientation(edges), 0) == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(QStringLiteral("PostMessageW"));
|
||||
|
@ -1024,6 +1020,7 @@ void Utils::installSystemMenuHook(const WId winId)
|
|||
return;
|
||||
}
|
||||
g_utilsHelper()->qtWindowProcs.insert(hwnd, originalWindowProc);
|
||||
//triggerFrameChange(winId);
|
||||
}
|
||||
|
||||
void Utils::uninstallSystemMenuHook(const WId winId)
|
||||
|
@ -1048,6 +1045,40 @@ void Utils::uninstallSystemMenuHook(const WId winId)
|
|||
return;
|
||||
}
|
||||
g_utilsHelper()->qtWindowProcs.remove(hwnd);
|
||||
//triggerFrameChange(winId);
|
||||
}
|
||||
|
||||
void Utils::sendMouseReleaseEvent()
|
||||
{
|
||||
if (ReleaseCapture() == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(QStringLiteral("ReleaseCapture"));
|
||||
}
|
||||
}
|
||||
|
||||
void Utils::tryToBeCompatibleWithQtFramelessWindowHint(QWindow *window, const bool enable)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
const WId winId = window->winId();
|
||||
const auto hwnd = reinterpret_cast<HWND>(winId);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
const LONG_PTR originalWindowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE);
|
||||
if (originalWindowStyle == 0) {
|
||||
qWarning() << getSystemErrorMessage(QStringLiteral("GetWindowLongPtrW"));
|
||||
return;
|
||||
}
|
||||
const Qt::WindowFlags originalWindowFlags = window->flags();
|
||||
const Qt::WindowFlags newWindowFlags = (enable ? (originalWindowFlags | Qt::FramelessWindowHint)
|
||||
: (originalWindowFlags & ~Qt::FramelessWindowHint));
|
||||
window->setFlags(newWindowFlags);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
if (SetWindowLongPtrW(hwnd, GWL_STYLE, originalWindowStyle) == 0) {
|
||||
qWarning() << getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
|
||||
return;
|
||||
}
|
||||
triggerFrameChange(winId);
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -208,6 +208,7 @@ bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event)
|
|||
return false;
|
||||
}
|
||||
const bool titleBar = isInTitleBarDraggableArea(window, scenePos);
|
||||
const auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
|
||||
switch (eventType) {
|
||||
case QEvent::MouseButtonPress: {
|
||||
if (button != Qt::LeftButton) {
|
||||
|
@ -220,6 +221,9 @@ bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event)
|
|||
return true;
|
||||
}
|
||||
case QEvent::MouseButtonRelease: {
|
||||
if (options & Option::DisableSystemMenu) {
|
||||
return false;
|
||||
}
|
||||
if (button != Qt::RightButton) {
|
||||
return false;
|
||||
}
|
||||
|
@ -236,6 +240,9 @@ bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event)
|
|||
return true;
|
||||
}
|
||||
case QEvent::MouseButtonDblClick: {
|
||||
if (options & Option::NoDoubleClickMaximizeToggle) {
|
||||
return false;
|
||||
}
|
||||
if (button != Qt::LeftButton) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
FramelessMainWindow::FramelessMainWindow(QWidget *parent, Qt::WindowFlags flags) : QMainWindow(parent, flags)
|
||||
FramelessMainWindow::FramelessMainWindow(QWidget *parent, const Qt::WindowFlags flags, const Options options) : QMainWindow(parent, flags)
|
||||
{
|
||||
m_helper.reset(new FramelessWidgetsHelper(this, WindowLayout::Custom));
|
||||
m_helper.reset(new FramelessWidgetsHelper(this, options));
|
||||
}
|
||||
|
||||
FramelessMainWindow::~FramelessMainWindow() = default;
|
||||
|
@ -64,12 +64,6 @@ void FramelessMainWindow::toggleMaximized()
|
|||
m_helper->toggleMaximized();
|
||||
}
|
||||
|
||||
void FramelessMainWindow::showEvent(QShowEvent *event)
|
||||
{
|
||||
QMainWindow::showEvent(event);
|
||||
m_helper->showEventHandler(event);
|
||||
}
|
||||
|
||||
void FramelessMainWindow::changeEvent(QEvent *event)
|
||||
{
|
||||
QMainWindow::changeEvent(event);
|
||||
|
|
|
@ -38,7 +38,7 @@ class FRAMELESSHELPER_WIDGETS_API FramelessMainWindow : public QMainWindow
|
|||
Q_PROPERTY(QWidget* titleBarWidget READ titleBarWidget WRITE setTitleBarWidget NOTIFY titleBarWidgetChanged FINAL)
|
||||
|
||||
public:
|
||||
explicit FramelessMainWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = {});
|
||||
explicit FramelessMainWindow(QWidget *parent = nullptr, const Qt::WindowFlags flags = {}, const Options options = {});
|
||||
~FramelessMainWindow() override;
|
||||
|
||||
Q_NODISCARD Q_INVOKABLE bool isNormal() const;
|
||||
|
@ -52,7 +52,6 @@ public:
|
|||
Q_INVOKABLE void toggleMaximized();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void changeEvent(QEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
|
|
@ -27,9 +27,9 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
FramelessWidget::FramelessWidget(QWidget *parent, const WindowLayout wl) : QWidget(parent)
|
||||
FramelessWidget::FramelessWidget(QWidget *parent, const Options options) : QWidget(parent)
|
||||
{
|
||||
m_helper.reset(new FramelessWidgetsHelper(this, wl));
|
||||
m_helper.reset(new FramelessWidgetsHelper(this, options));
|
||||
}
|
||||
|
||||
FramelessWidget::~FramelessWidget() = default;
|
||||
|
@ -74,12 +74,6 @@ void FramelessWidget::toggleMaximized()
|
|||
m_helper->toggleMaximized();
|
||||
}
|
||||
|
||||
void FramelessWidget::showEvent(QShowEvent *event)
|
||||
{
|
||||
QWidget::showEvent(event);
|
||||
m_helper->showEventHandler(event);
|
||||
}
|
||||
|
||||
void FramelessWidget::changeEvent(QEvent *event)
|
||||
{
|
||||
QWidget::changeEvent(event);
|
||||
|
|
|
@ -39,7 +39,7 @@ class FRAMELESSHELPER_WIDGETS_API FramelessWidget : public QWidget
|
|||
Q_PROPERTY(QWidget* contentWidget READ contentWidget WRITE setContentWidget NOTIFY contentWidgetChanged FINAL)
|
||||
|
||||
public:
|
||||
explicit FramelessWidget(QWidget *parent = nullptr, const WindowLayout wl = WindowLayout::Standard);
|
||||
explicit FramelessWidget(QWidget *parent = nullptr, const Options options = {});
|
||||
~FramelessWidget() override;
|
||||
|
||||
Q_NODISCARD Q_INVOKABLE bool isNormal() const;
|
||||
|
@ -56,7 +56,6 @@ public:
|
|||
Q_INVOKABLE void toggleMaximized();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void changeEvent(QEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
|
|
@ -23,8 +23,10 @@
|
|||
*/
|
||||
|
||||
#include "framelesswidgetshelper.h"
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtGui/qpainter.h>
|
||||
#include <QtGui/qevent.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
#include <QtWidgets/qboxlayout.h>
|
||||
#include <QtWidgets/qlabel.h>
|
||||
#include <QtWidgets/qpushbutton.h>
|
||||
|
@ -49,12 +51,12 @@ QPushButton:pressed {
|
|||
}
|
||||
)");
|
||||
|
||||
FramelessWidgetsHelper::FramelessWidgetsHelper(QWidget *q, const WindowLayout wl) : QObject(q)
|
||||
FramelessWidgetsHelper::FramelessWidgetsHelper(QWidget *q, const Options options) : QObject(q)
|
||||
{
|
||||
Q_ASSERT(q);
|
||||
if (q) {
|
||||
this->q = q;
|
||||
m_windowLayout = wl;
|
||||
m_options = options;
|
||||
initialize();
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +82,7 @@ void FramelessWidgetsHelper::setTitleBarWidget(QWidget *widget)
|
|||
if (m_userTitleBarWidget == widget) {
|
||||
return;
|
||||
}
|
||||
if (isStandardLayout()) {
|
||||
if (m_options & Option::UseStandardWindowLayout) {
|
||||
if (m_systemTitleBarWidget && m_systemTitleBarWidget->isVisible()) {
|
||||
m_mainLayout->removeWidget(m_systemTitleBarWidget);
|
||||
m_systemTitleBarWidget->hide();
|
||||
|
@ -108,7 +110,7 @@ void FramelessWidgetsHelper::setContentWidget(QWidget *widget)
|
|||
if (!widget) {
|
||||
return;
|
||||
}
|
||||
if (isCustomLayout()) {
|
||||
if (!(m_options & Option::UseStandardWindowLayout)) {
|
||||
return;
|
||||
}
|
||||
if (m_userContentWidget == widget) {
|
||||
|
@ -143,15 +145,6 @@ void FramelessWidgetsHelper::setHitTestVisible(QWidget *widget, const bool visib
|
|||
}
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::showEventHandler(QShowEvent *event)
|
||||
{
|
||||
Q_ASSERT(event);
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
setupFramelessHelperOnce();
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::changeEventHandler(QEvent *event)
|
||||
{
|
||||
Q_ASSERT(event);
|
||||
|
@ -162,8 +155,9 @@ void FramelessWidgetsHelper::changeEventHandler(QEvent *event)
|
|||
if ((type != QEvent::WindowStateChange) && (type != QEvent::ActivationChange)) {
|
||||
return;
|
||||
}
|
||||
const bool standardLayout = (m_options & Option::UseStandardWindowLayout);
|
||||
if (type == QEvent::WindowStateChange) {
|
||||
if (isStandardLayout()) {
|
||||
if (standardLayout) {
|
||||
if (isZoomed()) {
|
||||
m_systemMaximizeButton->setToolTip(tr("Restore"));
|
||||
} else {
|
||||
|
@ -173,7 +167,7 @@ void FramelessWidgetsHelper::changeEventHandler(QEvent *event)
|
|||
}
|
||||
updateContentsMargins();
|
||||
}
|
||||
if (isStandardLayout()) {
|
||||
if (standardLayout) {
|
||||
updateSystemTitleBarStyleSheet();
|
||||
}
|
||||
q->update();
|
||||
|
@ -227,6 +221,9 @@ void FramelessWidgetsHelper::mouseReleaseEventHandler(QMouseEvent *event)
|
|||
if (!event) {
|
||||
return;
|
||||
}
|
||||
if (m_options & Option::DisableSystemMenu) {
|
||||
return;
|
||||
}
|
||||
if (event->button() != Qt::RightButton) {
|
||||
return;
|
||||
}
|
||||
|
@ -258,6 +255,9 @@ void FramelessWidgetsHelper::mouseDoubleClickEventHandler(QMouseEvent *event)
|
|||
if (!event) {
|
||||
return;
|
||||
}
|
||||
if (m_options & Option::NoDoubleClickMaximizeToggle) {
|
||||
return;
|
||||
}
|
||||
if (event->button() != Qt::LeftButton) {
|
||||
return;
|
||||
}
|
||||
|
@ -281,21 +281,35 @@ void FramelessWidgetsHelper::initialize()
|
|||
return;
|
||||
}
|
||||
m_initialized = true;
|
||||
// Without this flag, Qt will always create an invisible native parent window
|
||||
// for any native widgets which will intercept some win32 messages and confuse
|
||||
// our own native event filter, so to prevent some weired bugs from happening,
|
||||
// just disable this feature.
|
||||
q->setAttribute(Qt::WA_DontCreateNativeAncestors);
|
||||
// Force the widget become a native window now so that we can deal with its
|
||||
// win32 events as soon as possible.
|
||||
q->createWinId();
|
||||
setupInitialUi();
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::setupFramelessHelperOnce()
|
||||
{
|
||||
if (m_framelessHelperSetup) {
|
||||
QWindow * const window = q->windowHandle();
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
m_framelessHelperSetup = true;
|
||||
window->setProperty(kInternalOptionsFlag, QVariant::fromValue(m_options));
|
||||
if (m_options & Option::UseStandardWindowLayout) {
|
||||
if (q->inherits("QMainWindow")) {
|
||||
m_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_options & Option::BeCompatibleWithQtFramelessWindowHint) {
|
||||
Utils::tryToBeCompatibleWithQtFramelessWindowHint(window, true);
|
||||
Q_ASSERT(window->flags() & Qt::FramelessWindowHint);
|
||||
}
|
||||
FramelessWindowsManager *manager = FramelessWindowsManager::instance();
|
||||
manager->addWindow(q->windowHandle());
|
||||
connect(manager, &FramelessWindowsManager::systemThemeChanged, this, [this](){
|
||||
if (isStandardLayout()) {
|
||||
if (m_options & Option::UseStandardWindowLayout) {
|
||||
updateSystemTitleBarStyleSheet();
|
||||
updateSystemButtonsIcon();
|
||||
q->update();
|
||||
|
@ -305,11 +319,12 @@ void FramelessWidgetsHelper::setupFramelessHelperOnce()
|
|||
connect(manager, &FramelessWindowsManager::systemMenuRequested, this, [this](const QPointF &pos){
|
||||
QMetaObject::invokeMethod(q, "systemMenuRequested", Q_ARG(QPointF, pos));
|
||||
});
|
||||
setupInitialUi();
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::createSystemTitleBar()
|
||||
{
|
||||
if (isCustomLayout()) {
|
||||
if (!(m_options & Option::UseStandardWindowLayout)) {
|
||||
return;
|
||||
}
|
||||
m_systemTitleBarWidget = new QWidget(q);
|
||||
|
@ -352,7 +367,7 @@ void FramelessWidgetsHelper::createSystemTitleBar()
|
|||
|
||||
void FramelessWidgetsHelper::createUserContentContainer()
|
||||
{
|
||||
if (isCustomLayout()) {
|
||||
if (!(m_options & Option::UseStandardWindowLayout)) {
|
||||
return;
|
||||
}
|
||||
m_userContentContainerWidget = new QWidget(q);
|
||||
|
@ -365,7 +380,7 @@ void FramelessWidgetsHelper::createUserContentContainer()
|
|||
|
||||
void FramelessWidgetsHelper::setupInitialUi()
|
||||
{
|
||||
if (isStandardLayout()) {
|
||||
if (m_options & Option::UseStandardWindowLayout) {
|
||||
createSystemTitleBar();
|
||||
createUserContentContainer();
|
||||
m_mainLayout = new QVBoxLayout(q);
|
||||
|
@ -402,7 +417,7 @@ bool FramelessWidgetsHelper::isInTitleBarDraggableArea(const QPoint &pos) const
|
|||
}
|
||||
return region;
|
||||
}
|
||||
if (isStandardLayout()) {
|
||||
if (m_options & Option::UseStandardWindowLayout) {
|
||||
QRegion region = mapGeometryToScene(m_systemTitleBarWidget);
|
||||
region -= mapGeometryToScene(m_systemMinimizeButton);
|
||||
region -= mapGeometryToScene(m_systemMaximizeButton);
|
||||
|
@ -417,22 +432,13 @@ bool FramelessWidgetsHelper::isInTitleBarDraggableArea(const QPoint &pos) const
|
|||
bool FramelessWidgetsHelper::shouldDrawFrameBorder() const
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
return (Utils::isWindowFrameBorderVisible() && !Utils::isWin11OrGreater() && isNormal());
|
||||
return (Utils::isWindowFrameBorderVisible() && !Utils::isWin11OrGreater()
|
||||
&& isNormal() && !(m_options & Option::DontDrawTopWindowFrameBorder));
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FramelessWidgetsHelper::isStandardLayout() const
|
||||
{
|
||||
return (m_windowLayout == WindowLayout::Standard);
|
||||
}
|
||||
|
||||
bool FramelessWidgetsHelper::isCustomLayout() const
|
||||
{
|
||||
return (m_windowLayout == WindowLayout::Custom);
|
||||
}
|
||||
|
||||
bool FramelessWidgetsHelper::shouldIgnoreMouseEvents(const QPoint &pos) const
|
||||
{
|
||||
return (isNormal() && ((pos.x() < kDefaultResizeBorderThickness)
|
||||
|
@ -449,7 +455,7 @@ void FramelessWidgetsHelper::updateContentsMargins()
|
|||
|
||||
void FramelessWidgetsHelper::updateSystemTitleBarStyleSheet()
|
||||
{
|
||||
if (isCustomLayout()) {
|
||||
if (!(m_options & Option::UseStandardWindowLayout)) {
|
||||
return;
|
||||
}
|
||||
const bool active = q->isActiveWindow();
|
||||
|
@ -484,7 +490,7 @@ void FramelessWidgetsHelper::updateSystemTitleBarStyleSheet()
|
|||
|
||||
void FramelessWidgetsHelper::updateSystemButtonsIcon()
|
||||
{
|
||||
if (isCustomLayout()) {
|
||||
if (!(m_options & Option::UseStandardWindowLayout)) {
|
||||
return;
|
||||
}
|
||||
const SystemTheme theme = ((Utils::shouldAppsUseDarkMode() || Utils::isTitleBarColorized()) ? SystemTheme::Dark : SystemTheme::Light);
|
||||
|
|
|
@ -45,7 +45,7 @@ class FRAMELESSHELPER_WIDGETS_API FramelessWidgetsHelper : public QObject
|
|||
Q_DISABLE_COPY_MOVE(FramelessWidgetsHelper)
|
||||
|
||||
public:
|
||||
explicit FramelessWidgetsHelper(QWidget *q, const WindowLayout wl);
|
||||
explicit FramelessWidgetsHelper(QWidget *q, const Options options = {});
|
||||
~FramelessWidgetsHelper() override;
|
||||
|
||||
Q_NODISCARD Q_INVOKABLE bool isNormal() const;
|
||||
|
@ -61,7 +61,6 @@ public:
|
|||
|
||||
Q_INVOKABLE void toggleMaximized();
|
||||
|
||||
Q_INVOKABLE void showEventHandler(QShowEvent *event);
|
||||
Q_INVOKABLE void changeEventHandler(QEvent *event);
|
||||
Q_INVOKABLE void paintEventHandler(QPaintEvent *event);
|
||||
Q_INVOKABLE void mousePressEventHandler(QMouseEvent *event);
|
||||
|
@ -70,14 +69,11 @@ public:
|
|||
|
||||
private:
|
||||
void initialize();
|
||||
void setupFramelessHelperOnce();
|
||||
void createSystemTitleBar();
|
||||
void createUserContentContainer();
|
||||
void setupInitialUi();
|
||||
Q_NODISCARD bool isInTitleBarDraggableArea(const QPoint &pos) const;
|
||||
Q_NODISCARD bool shouldDrawFrameBorder() const;
|
||||
Q_NODISCARD bool isStandardLayout() const;
|
||||
Q_NODISCARD bool isCustomLayout() const;
|
||||
Q_NODISCARD bool shouldIgnoreMouseEvents(const QPoint &pos) const;
|
||||
|
||||
private Q_SLOTS:
|
||||
|
@ -88,8 +84,7 @@ private Q_SLOTS:
|
|||
private:
|
||||
QWidget *q = nullptr;
|
||||
bool m_initialized = false;
|
||||
bool m_framelessHelperSetup = false;
|
||||
WindowLayout m_windowLayout = WindowLayout::Standard;
|
||||
Options m_options = {};
|
||||
QWidget *m_systemTitleBarWidget = nullptr;
|
||||
QLabel *m_systemWindowTitleLabel = nullptr;
|
||||
QPushButton *m_systemMinimizeButton = nullptr;
|
||||
|
|
Loading…
Reference in New Issue