Win32: Remove the dependency of the widgets and quick module

This commit totally removed the dependency of the widgets
and quick modules for the Windows platform. Now the library
itself only depends on the core and gui modules. Currently
no bug can be found. But there are some side effects: one is
we can't set a palette for a widget due to we can't access
QWidget specific functions so if you want to enable blur
effect, you will have to do this by yourself. Another one is
you now have to pass the window handle to WinNativeEventFilter
instead of the pointer of a QObject. Before this patch, I'm
using QWidget::winId() to get the window handle, now we have
get rid of the widgets dependency so I can't get the window
handle now, you have to pass it explicitly. And it leads to
huge refactoring of the whole repository. But I think it's
worth doing. If anyone knows how to get the window handle
without introducing new dependencies, please tell me. It will
help me a lot.

To remove the quick dependency, the FramelessQuickHelper class
is moved out of the library now. If your project needs it,
please copy the files to your project and include them directly.

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2020-11-16 17:05:39 +08:00
parent 9cb3392ce4
commit b672851f51
15 changed files with 260 additions and 471 deletions

View File

@ -53,7 +53,12 @@ If you are using part of or all the code from this repository in your own projec
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
QWidget widget; QWidget widget;
// Do this before the widget is shown. // Do this before the widget is shown.
FramelessWindowsManager::addWindow(&widget); #ifdef Q_OS_WIN
const auto id = reinterpret_cast<FramelessWindowsManager::WindowId>(widget.winId());
#else
const auto id = static_cast<FramelessWindowsManager::WindowId>(&widget);
#endif
FramelessWindowsManager::addWindow(id);
widget.show(); widget.show();
} }
``` ```
@ -65,29 +70,34 @@ Please refer to [the QWidget example](/examples/QWidget/main.cpp) for more detai
```cpp ```cpp
// Only **TOP LEVEL** QWidgets and QWindows are supported. // Only **TOP LEVEL** QWidgets and QWindows are supported.
QMainWindow *mainWindow = new QMainWindow; QMainWindow *mainWindow = new QMainWindow;
#ifdef Q_OS_WIN
const auto id = reinterpret_cast<FramelessWindowsManager::WindowId>(mainWindow->winId());
#else
const auto id = static_cast<FramelessWindowsManager::WindowId>(mainWindow);
#endif
// Disable resizing of the given window. Resizing is enabled by default. // Disable resizing of the given window. Resizing is enabled by default.
FramelessWindowsManager::setResizable(mainWindow, false); FramelessWindowsManager::setResizable(id, false);
// All the following values should not be DPI-aware, just use the // All the following values should not be DPI-aware, just use the
// original numbers, assuming the scale factor is 1.0, don't scale // original numbers, assuming the scale factor is 1.0, don't scale
// them yourself, this code will do the scaling according to DPI // them yourself, this code will do the scaling according to DPI
// internally and automatically. // internally and automatically.
// Maximum window size // Maximum window size
FramelessWindowsManager::setMaximumSize(mainWindow, {1280, 720}); FramelessWindowsManager::setMaximumSize(id, {1280, 720});
// Minimum window size // Minimum window size
FramelessWindowsManager::setMinimumSize(mainWindow, {800, 540}); FramelessWindowsManager::setMinimumSize(id, {800, 540});
// How to set ignore areas: // How to set ignore areas:
// The geometry of something you already know, in window coordinates // The geometry of something you already know, in window coordinates
FramelessWindowsManager::addIgnoreArea(mainWindow, {100, 0, 30, 30}); FramelessWindowsManager::addIgnoreArea(id, {100, 0, 30, 30});
// The geometry of a widget, in window coordinates. // The geometry of a widget, in window coordinates.
// It won't update automatically when the geometry of that widget has // It won't update automatically when the geometry of that widget has
// changed, so if you want to add a widget, which is in a layout and // changed, so if you want to add a widget, which is in a layout and
// it's geometry will possibly change, to the ignore list, try the // it's geometry will possibly change, to the ignore list, try the
// next method (addIgnoreObject) instead. // next method (addIgnoreObject) instead.
FramelessWindowsManager::addIgnoreArea(mainWindow, pushButton_close.geometry()); FramelessWindowsManager::addIgnoreArea(id, pushButton_close.geometry());
// The **POINTER** of a QWidget or QQuickItem // The **POINTER** of a QWidget or QQuickItem
FramelessWindowsManager::addIgnoreObject(mainWindow, ui->pushButton_minimize); FramelessWindowsManager::addIgnoreObject(id, ui->pushButton_minimize);
// Move a QWidget or QWindow to the center of its current desktop. // Move a QWidget or QWindow to the center of its current desktop.
FramelessWindowsManager::moveWindowToDesktopCenter(mainWindow); FramelessWindowsManager::moveWindowToDesktopCenter(id);
``` ```
## Supported Platforms ## Supported Platforms
@ -108,7 +118,7 @@ A not too old version of Linux and macOS, 32 bit & 64 bit.
| Component | Requirement | Additional Information | | Component | Requirement | Additional Information |
| --- | --- | --- | | --- | --- | --- |
| Qt | >= 5.6 | Only the `gui` module is required explicitly, but to make full use of this repository, you'd better install the `widgets` and `quick` modules as well | | Qt | >= 5.6 | Only the `core` and `gui` modules are required |
| Compiler | >= C++11 | MSVC, MinGW, Clang-CL, Intel-CL or cross compile from Linux/macOS are all supported | | Compiler | >= C++11 | MSVC, MinGW, Clang-CL, Intel-CL or cross compile from Linux/macOS are all supported |
### UNIX ### UNIX

View File

@ -32,7 +32,7 @@
```cpp ```cpp
QWidget widget; QWidget widget;
// Do this before the widget is shown. // Do this before the widget is shown.
WinNativeEventFilter::addFramelessWindow(&widget); WinNativeEventFilter::addFramelessWindow(reinterpret_cast<void *>(widget.winId()));
widget.show(); widget.show();
``` ```
@ -41,6 +41,8 @@ Please refer to [the QWidget example](/examples/QWidget/main.cpp) for more detai
### Ignore areas and etc ### Ignore areas and etc
```cpp ```cpp
// Get the window handle (HWND) first.
const auto handle = reinterpret_cast<void *>(widget.winId());
WinNativeEventFilter::WINDOWDATA data = {}; WinNativeEventFilter::WINDOWDATA data = {};
// All the following values should not be DPI-aware, just use the // All the following values should not be DPI-aware, just use the
// original numbers, assuming the scale factor is 1.0, don't scale // original numbers, assuming the scale factor is 1.0, don't scale
@ -62,18 +64,18 @@ data.ignoreAreas.append(pushButton_close.geometry());
// The **POINTER** of a QWidget or QQuickItem // The **POINTER** of a QWidget or QQuickItem
data.ignoreObjects.append(ui->pushButton_minimize); data.ignoreObjects.append(ui->pushButton_minimize);
// Pass data as the second parameter // Pass data as the second parameter
WinNativeEventFilter::addFramelessWindow(&widget, &data); WinNativeEventFilter::addFramelessWindow(handle, &data);
// Or // Or
WinNativeEventFilter::setWindowData(&widget, &data); WinNativeEventFilter::setWindowData(handle, &data);
// Or modify the window data of a specific window directly: // Or modify the window data of a specific window directly:
const auto data = WinNativeEventFilter::getWindowData(&widget); const auto data = WinNativeEventFilter::getWindowData(handle);
if (data) { if (data) {
data->borderWidth = 5; data->borderWidth = 5;
data->borderHeight = 5; data->borderHeight = 5;
data->titleBarHeight = 30; data->titleBarHeight = 30;
} }
// The frameless window is resizable by default. // The frameless window is resizable by default.
WinNativeEventFilter::setWindowResizable(reinterpret_cast<void *>(mainWindow->winId()), false); WinNativeEventFilter::setWindowResizable(handle, false);
``` ```
## Supported Platforms ## Supported Platforms
@ -86,7 +88,7 @@ The code itself should be able to work on Windows Vista in theory, but Qt5 has d
| Component | Requirement | Additional Information | | Component | Requirement | Additional Information |
| --- | --- | --- | | --- | --- | --- |
| Qt | >= 5.6 | Only the `gui` module is required explicitly, but to make full use of this repository, you'd better install the `widgets` and `quick` modules as well | | Qt | >= 5.6 | Only the `core` and `gui` modules are required |
| Compiler | >= C++11 | MSVC, MinGW, Clang-CL, Intel-CL or cross compile from Linux are all supported | | Compiler | >= C++11 | MSVC, MinGW, Clang-CL, Intel-CL or cross compile from Linux are all supported |
## Known Bugs ## Known Bugs

View File

@ -103,17 +103,21 @@ int main(int argc, char *argv[])
mainWindow->setWindowIcon(icon); mainWindow->setWindowIcon(icon);
mainWindow->setWindowTitle(QObject::tr("Hello, World!")); mainWindow->setWindowTitle(QObject::tr("Hello, World!"));
FramelessWindowsManager::addWindow(mainWindow); #ifdef Q_OS_WIN
const auto id = reinterpret_cast<FramelessWindowsManager::WindowId>(mainWindow->winId());
#else
const auto id = static_cast<FramelessWindowsManager::WindowId>(mainWindow);
#endif
FramelessWindowsManager::addIgnoreObject(mainWindow, titleBarWidget.minimizeButton); FramelessWindowsManager::addWindow(id);
FramelessWindowsManager::addIgnoreObject(mainWindow, titleBarWidget.maximizeButton);
FramelessWindowsManager::addIgnoreObject(mainWindow, titleBarWidget.closeButton); FramelessWindowsManager::addIgnoreObject(id, titleBarWidget.minimizeButton);
FramelessWindowsManager::addIgnoreObject(mainWindow, appMainWindow.menubar); FramelessWindowsManager::addIgnoreObject(id, titleBarWidget.maximizeButton);
FramelessWindowsManager::addIgnoreObject(id, titleBarWidget.closeButton);
FramelessWindowsManager::addIgnoreObject(id, appMainWindow.menubar);
mainWindow->resize(800, 600); mainWindow->resize(800, 600);
//FramelessWindowsManager::moveWindowToDesktopCenter(mainWindow);
mainWindow->show(); mainWindow->show();
return QApplication::exec(); return QApplication::exec();

View File

@ -94,16 +94,20 @@ int main(int argc, char *argv[])
widget.setLayout(mainLayout); widget.setLayout(mainLayout);
widget.setWindowTitle(QObject::tr("Hello, World!")); widget.setWindowTitle(QObject::tr("Hello, World!"));
FramelessWindowsManager::addWindow(&widget); #ifdef Q_OS_WIN
const auto id = reinterpret_cast<FramelessWindowsManager::WindowId>(widget.winId());
#else
const auto id = static_cast<FramelessWindowsManager::WindowId>(&widget);
#endif
FramelessWindowsManager::addIgnoreObject(&widget, minimizeButton); FramelessWindowsManager::addWindow(id);
FramelessWindowsManager::addIgnoreObject(&widget, maximizeButton);
FramelessWindowsManager::addIgnoreObject(&widget, closeButton); FramelessWindowsManager::addIgnoreObject(id, minimizeButton);
FramelessWindowsManager::addIgnoreObject(id, maximizeButton);
FramelessWindowsManager::addIgnoreObject(id, closeButton);
widget.resize(800, 600); widget.resize(800, 600);
//FramelessWindowsManager::moveWindowToDesktopCenter(&widget);
widget.show(); widget.show();
return QApplication::exec(); return QApplication::exec();

View File

@ -1,6 +1,7 @@
TARGET = Quick TARGET = Quick
TEMPLATE = app TEMPLATE = app
QT += quick QT += quick
SOURCES += main.cpp HEADERS += ../../framelessquickhelper.h
SOURCES += ../../framelessquickhelper.cpp main.cpp
RESOURCES += qml.qrc RESOURCES += qml.qrc
include($$PWD/../common.pri) include($$PWD/../common.pri)

View File

@ -138,6 +138,7 @@ const QLatin1String g_sCloseButtonImageLight(":/images/button_close_white.svg");
Widget::Widget(QWidget *parent) : QWidget(parent) Widget::Widget(QWidget *parent) : QWidget(parent)
{ {
createWinId(); // Internal function
initializeWindow(); initializeWindow();
} }
@ -373,7 +374,7 @@ bool Widget::eventFilter(QObject *object, QEvent *event)
break; break;
} }
case QEvent::WinIdChange: case QEvent::WinIdChange:
WinNativeEventFilter::addFramelessWindow(this); WinNativeEventFilter::addFramelessWindow(rawHandle());
break; break;
case QEvent::WindowActivate: case QEvent::WindowActivate:
case QEvent::WindowDeactivate: case QEvent::WindowDeactivate:
@ -400,9 +401,7 @@ bool Widget::nativeEvent(const QByteArray &eventType, void *message, long *resul
switch (msg->message) { switch (msg->message) {
case WM_NCRBUTTONUP: { case WM_NCRBUTTONUP: {
if (msg->wParam == HTCAPTION) { if (msg->wParam == HTCAPTION) {
const int x = GET_X_LPARAM(msg->lParam); if (WinNativeEventFilter::displaySystemMenu(msg->hwnd)) {
const int y = GET_Y_LPARAM(msg->lParam);
if (WinNativeEventFilter::displaySystemMenu(msg->hwnd, false, x, y)) {
*result = 0; *result = 0;
return true; return true;
} }
@ -581,6 +580,15 @@ void Widget::setupConnections()
QColorDialog::ShowAlphaChannel); QColorDialog::ShowAlphaChannel);
} }
} }
// Qt will paint a solid white background to the window,
// it will cover the blurred effect, so we need to
// make the background become totally transparent. Achieve
// this by setting a palette to the window.
QPalette palette = {};
if (enable) {
palette.setColor(QPalette::Window, Qt::transparent);
}
setPalette(palette);
WinNativeEventFilter::setBlurEffectEnabled(rawHandle(), enable, color); WinNativeEventFilter::setBlurEffectEnabled(rawHandle(), enable, color);
updateWindow(); updateWindow();
if (useAcrylicEffect && enable && WinNativeEventFilter::isTransparencyEffectEnabled()) { if (useAcrylicEffect && enable && WinNativeEventFilter::isTransparencyEffectEnabled()) {
@ -621,7 +629,7 @@ void Widget::initializeFramelessFunctions()
{ {
WinNativeEventFilter::WINDOWDATA data = {}; WinNativeEventFilter::WINDOWDATA data = {};
data.ignoreObjects << iconButton << minimizeButton << maximizeButton << closeButton; data.ignoreObjects << iconButton << minimizeButton << maximizeButton << closeButton;
WinNativeEventFilter::addFramelessWindow(this, &data); WinNativeEventFilter::addFramelessWindow(rawHandle(), &data);
installEventFilter(this); installEventFilter(this);
} }

View File

@ -14,10 +14,9 @@ win32 {
RC_FILE = $$PWD/windows.rc RC_FILE = $$PWD/windows.rc
OTHER_FILES += $$PWD/windows.manifest OTHER_FILES += $$PWD/windows.manifest
} }
CONFIG(debug, debug|release) { win32 {
LIBS += -L$$OUT_PWD/../../debug CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../debug -lFramelessHelperd
win32: LIBS += -lFramelessHelperd else: CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../release -lFramelessHelper
else: unix: LIBS += -lFramelessHelper_debug } else: unix {
} else: CONFIG(release, debug|release) { LIBS += -L$$OUT_PWD/../../bin -lFramelessHelper
LIBS += -L$$OUT_PWD/../../release -lFramelessHelper
} }

View File

@ -407,29 +407,31 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
if (!obj) { if (!obj) {
continue; continue;
} }
#ifdef QT_WIDGETS_LIB const bool isWidget = obj->inherits("QWidget");
const auto widget = qobject_cast<QWidget *>(obj); const bool isQuickItem = obj->inherits("QQuickItem");
if (widget) { if (!isWidget && !isQuickItem) {
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) qWarning() << obj << "is not a QWidget or QQuickItem!";
const QPointF pos = widget->mapToGlobal(QPointF{0, 0}); continue;
#else
const QPoint pos = widget->mapToGlobal(QPoint{0, 0});
#endif
if (QRectF(pos.x(), pos.y(), widget->width(), widget->height()).contains(mousePos)) {
return true;
}
} }
#endif const auto mapOriginPointToWindow = [](const QObject *obj) -> QPointF {
#ifdef QT_QUICK_LIB Q_ASSERT(obj);
const auto quickItem = qobject_cast<QQuickItem *>(obj); QPointF point = {obj->property("x").toReal(), obj->property("y").toReal()};
if (quickItem) { for (QObject *parent = obj->parent(); parent; parent = parent->parent()) {
const QPointF pos = quickItem->mapToGlobal({0, 0}); point += {parent->property("x").toReal(),
if (QRectF(pos.x(), pos.y(), quickItem->width(), quickItem->height()) parent->property("y").toReal()};
.contains(mousePos)) {
return true;
} }
return point;
};
const QPointF originPoint = mapOriginPointToWindow(obj);
const qreal width = obj->property("width").toReal();
const qreal height = obj->property("height").toReal();
if (QRectF(originPoint.x(),
originPoint.y(),
width,
height)
.contains(mousePos)) {
return true;
} }
#endif
} }
return false; return false;
}; };
@ -441,13 +443,7 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
const auto isInIgnoreObjects = [this, &isInSpecificObjects](const QPointF &point, const auto isInIgnoreObjects = [this, &isInSpecificObjects](const QPointF &point,
QObject *window) -> bool { QObject *window) -> bool {
Q_ASSERT(window); Q_ASSERT(window);
#if defined(QT_WIDGETS_LIB) || defined(QT_QUICK_LIB)
return isInSpecificObjects(point, getIgnoreObjects(window)); return isInSpecificObjects(point, getIgnoreObjects(window));
#else
Q_UNUSED(point)
Q_UNUSED(window)
return false;
#endif
}; };
const auto isInDraggableAreas = [this, &isInSpecificAreas](const QPointF &point, const auto isInDraggableAreas = [this, &isInSpecificAreas](const QPointF &point,
QObject *window) -> bool { QObject *window) -> bool {
@ -458,14 +454,8 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
const auto isInDraggableObjects = [this, &isInSpecificObjects](const QPointF &point, const auto isInDraggableObjects = [this, &isInSpecificObjects](const QPointF &point,
QObject *window) -> bool { QObject *window) -> bool {
Q_ASSERT(window); Q_ASSERT(window);
#if defined(QT_WIDGETS_LIB) || defined(QT_QUICK_LIB)
const auto objs = getDraggableObjects(window); const auto objs = getDraggableObjects(window);
return (objs.isEmpty() ? true : isInSpecificObjects(point, objs)); return (objs.isEmpty() ? true : isInSpecificObjects(point, objs));
#else
Q_UNUSED(point)
Q_UNUSED(window)
return true;
#endif
}; };
const auto isResizePermitted = [&isInIgnoreAreas, &isInIgnoreObjects](const QPointF &globalPoint, const auto isResizePermitted = [&isInIgnoreAreas, &isInIgnoreObjects](const QPointF &globalPoint,
const QPointF &point, const QPointF &point,

View File

@ -31,15 +31,34 @@
#include <QOperatingSystemVersion> #include <QOperatingSystemVersion>
#endif #endif
#ifdef Q_OS_WINDOWS
namespace { namespace {
#ifdef Q_OS_WINDOWS
const char g_sPreserveWindowFrame[] = "WNEF_FORCE_PRESERVE_WINDOW_FRAME"; const char g_sPreserveWindowFrame[] = "WNEF_FORCE_PRESERVE_WINDOW_FRAME";
const char g_sDontExtendFrame[] = "WNEF_DO_NOT_EXTEND_FRAME"; const char g_sDontExtendFrame[] = "WNEF_DO_NOT_EXTEND_FRAME";
const char g_sForceUseAcrylicEffect[] = "WNEF_FORCE_ACRYLIC_ON_WIN10"; const char g_sForceUseAcrylicEffect[] = "WNEF_FORCE_ACRYLIC_ON_WIN10";
#endif
FramelessWindowsManager::WindowId getWindowId(QObject *object)
{
Q_ASSERT(object);
if (!object->isWindowType()) {
qWarning() << object << "is not a window!";
return nullptr;
}
const auto window = qobject_cast<QWindow *>(object);
if (!window) {
qWarning() << "Failed to convert" << object << "to QWindow!";
return nullptr;
}
#ifdef Q_OS_WINDOWS
return reinterpret_cast<FramelessWindowsManager::WindowId>(window->winId());
#else
return static_cast<FramelessWindowsManager::WindowId>(window);
#endif
}
} // namespace } // namespace
#endif
FramelessQuickHelper::FramelessQuickHelper(QQuickItem *parent) : QQuickItem(parent) FramelessQuickHelper::FramelessQuickHelper(QQuickItem *parent) : QQuickItem(parent)
{ {
@ -50,56 +69,56 @@ FramelessQuickHelper::FramelessQuickHelper(QQuickItem *parent) : QQuickItem(pare
int FramelessQuickHelper::borderWidth() const int FramelessQuickHelper::borderWidth() const
{ {
return FramelessWindowsManager::getBorderWidth(window()); return FramelessWindowsManager::getBorderWidth(getWindowId(window()));
} }
void FramelessQuickHelper::setBorderWidth(const int val) void FramelessQuickHelper::setBorderWidth(const int val)
{ {
FramelessWindowsManager::setBorderWidth(window(), val); FramelessWindowsManager::setBorderWidth(getWindowId(window()), val);
Q_EMIT borderWidthChanged(val); Q_EMIT borderWidthChanged(val);
} }
int FramelessQuickHelper::borderHeight() const int FramelessQuickHelper::borderHeight() const
{ {
return FramelessWindowsManager::getBorderHeight(window()); return FramelessWindowsManager::getBorderHeight(getWindowId(window()));
} }
void FramelessQuickHelper::setBorderHeight(const int val) void FramelessQuickHelper::setBorderHeight(const int val)
{ {
FramelessWindowsManager::setBorderHeight(window(), val); FramelessWindowsManager::setBorderHeight(getWindowId(window()), val);
Q_EMIT borderHeightChanged(val); Q_EMIT borderHeightChanged(val);
} }
int FramelessQuickHelper::titleBarHeight() const int FramelessQuickHelper::titleBarHeight() const
{ {
return FramelessWindowsManager::getTitleBarHeight(window()); return FramelessWindowsManager::getTitleBarHeight(getWindowId(window()));
} }
void FramelessQuickHelper::setTitleBarHeight(const int val) void FramelessQuickHelper::setTitleBarHeight(const int val)
{ {
FramelessWindowsManager::setTitleBarHeight(window(), val); FramelessWindowsManager::setTitleBarHeight(getWindowId(window()), val);
Q_EMIT titleBarHeightChanged(val); Q_EMIT titleBarHeightChanged(val);
} }
bool FramelessQuickHelper::resizable() const bool FramelessQuickHelper::resizable() const
{ {
return FramelessWindowsManager::getResizable(window()); return FramelessWindowsManager::getResizable(getWindowId(window()));
} }
void FramelessQuickHelper::setResizable(const bool val) void FramelessQuickHelper::setResizable(const bool val)
{ {
FramelessWindowsManager::setResizable(window(), val); FramelessWindowsManager::setResizable(getWindowId(window()), val);
Q_EMIT resizableChanged(val); Q_EMIT resizableChanged(val);
} }
bool FramelessQuickHelper::titleBarEnabled() const bool FramelessQuickHelper::titleBarEnabled() const
{ {
return FramelessWindowsManager::getTitleBarEnabled(window()); return FramelessWindowsManager::getTitleBarEnabled(getWindowId(window()));
} }
void FramelessQuickHelper::setTitleBarEnabled(const bool val) void FramelessQuickHelper::setTitleBarEnabled(const bool val)
{ {
FramelessWindowsManager::setTitleBarEnabled(window(), val); FramelessWindowsManager::setTitleBarEnabled(getWindowId(window()), val);
Q_EMIT titleBarEnabledChanged(val); Q_EMIT titleBarEnabledChanged(val);
} }
@ -136,7 +155,7 @@ bool FramelessQuickHelper::highContrastModeEnabled() const
bool FramelessQuickHelper::darkFrameEnabled() const bool FramelessQuickHelper::darkFrameEnabled() const
{ {
return WinNativeEventFilter::isDarkFrameEnabled(rawHandle()); return WinNativeEventFilter::isDarkFrameEnabled(rawWindowHandle());
} }
bool FramelessQuickHelper::transparencyEffectEnabled() const bool FramelessQuickHelper::transparencyEffectEnabled() const
@ -147,71 +166,56 @@ bool FramelessQuickHelper::transparencyEffectEnabled() const
QSize FramelessQuickHelper::minimumSize() const QSize FramelessQuickHelper::minimumSize() const
{ {
return FramelessWindowsManager::getMinimumSize(window()); return FramelessWindowsManager::getMinimumSize(getWindowId(window()));
} }
void FramelessQuickHelper::setMinimumSize(const QSize &val) void FramelessQuickHelper::setMinimumSize(const QSize &val)
{ {
FramelessWindowsManager::setMinimumSize(window(), val); FramelessWindowsManager::setMinimumSize(getWindowId(window()), val);
Q_EMIT minimumSizeChanged(val); Q_EMIT minimumSizeChanged(val);
} }
QSize FramelessQuickHelper::maximumSize() const QSize FramelessQuickHelper::maximumSize() const
{ {
return FramelessWindowsManager::getMaximumSize(window()); return FramelessWindowsManager::getMaximumSize(getWindowId(window()));
} }
void FramelessQuickHelper::setMaximumSize(const QSize &val) void FramelessQuickHelper::setMaximumSize(const QSize &val)
{ {
FramelessWindowsManager::setMaximumSize(window(), val); FramelessWindowsManager::setMaximumSize(getWindowId(window()), val);
Q_EMIT maximumSizeChanged(val); Q_EMIT maximumSizeChanged(val);
} }
void FramelessQuickHelper::removeWindowFrame(const bool center) void FramelessQuickHelper::removeWindowFrame(const bool center)
{ {
FramelessWindowsManager::addWindow(window(), center); FramelessWindowsManager::addWindow(getWindowId(window()), center);
} }
QSize FramelessQuickHelper::desktopSize() const void FramelessQuickHelper::moveWindowToDesktopCenter()
{ {
return FramelessWindowsManager::getDesktopSize(window()); FramelessWindowsManager::moveWindowToDesktopCenter(getWindowId(window()));
}
QRect FramelessQuickHelper::desktopAvailableGeometry() const
{
return FramelessWindowsManager::getDesktopAvailableGeometry(window());
}
QSize FramelessQuickHelper::desktopAvailableSize() const
{
return FramelessWindowsManager::getDesktopAvailableSize(window());
}
void FramelessQuickHelper::moveWindowToDesktopCenter(const bool realCenter)
{
FramelessWindowsManager::moveWindowToDesktopCenter(window(), realCenter);
} }
void FramelessQuickHelper::addIgnoreArea(const QRect &val) void FramelessQuickHelper::addIgnoreArea(const QRect &val)
{ {
FramelessWindowsManager::addIgnoreArea(window(), val); FramelessWindowsManager::addIgnoreArea(getWindowId(window()), val);
} }
void FramelessQuickHelper::addDraggableArea(const QRect &val) void FramelessQuickHelper::addDraggableArea(const QRect &val)
{ {
FramelessWindowsManager::addDraggableArea(window(), val); FramelessWindowsManager::addDraggableArea(getWindowId(window()), val);
} }
void FramelessQuickHelper::addIgnoreObject(QQuickItem *val) void FramelessQuickHelper::addIgnoreObject(QQuickItem *val)
{ {
Q_ASSERT(val); Q_ASSERT(val);
FramelessWindowsManager::addIgnoreObject(window(), val); FramelessWindowsManager::addIgnoreObject(getWindowId(window()), val);
} }
void FramelessQuickHelper::addDraggableObject(QQuickItem *val) void FramelessQuickHelper::addDraggableObject(QQuickItem *val)
{ {
Q_ASSERT(val); Q_ASSERT(val);
FramelessWindowsManager::addDraggableObject(window(), val); FramelessWindowsManager::addDraggableObject(getWindowId(window()), val);
} }
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
@ -227,9 +231,9 @@ void FramelessQuickHelper::timerEvent(QTimerEvent *event)
Q_EMIT transparencyEffectEnabledChanged(transparencyEffectEnabled()); Q_EMIT transparencyEffectEnabledChanged(transparencyEffectEnabled());
} }
void *FramelessQuickHelper::rawHandle() const void *FramelessQuickHelper::rawWindowHandle() const
{ {
QWindow *win = window(); const QWindow *win = window();
if (win) { if (win) {
return reinterpret_cast<void *>(win->winId()); return reinterpret_cast<void *>(win->winId());
} }
@ -247,9 +251,9 @@ void FramelessQuickHelper::setWindowFrameVisible(const bool value)
} }
} }
void FramelessQuickHelper::displaySystemMenu(const int x, const int y, const bool isRtl) void FramelessQuickHelper::displaySystemMenu(const QPointF &pos)
{ {
WinNativeEventFilter::displaySystemMenu(rawHandle(), isRtl, x, y); WinNativeEventFilter::displaySystemMenu(rawWindowHandle(), pos);
} }
void FramelessQuickHelper::setBlurEffectEnabled(const bool enabled, void FramelessQuickHelper::setBlurEffectEnabled(const bool enabled,
@ -261,6 +265,6 @@ void FramelessQuickHelper::setBlurEffectEnabled(const bool enabled,
} else { } else {
qunsetenv(g_sForceUseAcrylicEffect); qunsetenv(g_sForceUseAcrylicEffect);
} }
WinNativeEventFilter::setBlurEffectEnabled(rawHandle(), enabled, gradientColor); WinNativeEventFilter::setBlurEffectEnabled(rawWindowHandle(), enabled, gradientColor);
} }
#endif #endif

View File

@ -24,7 +24,6 @@
#pragma once #pragma once
#include "framelesshelper_global.h"
#include <QQuickItem> #include <QQuickItem>
#if (defined(Q_OS_WIN) || defined(Q_OS_WIN32) || defined(Q_OS_WIN64) || defined(Q_OS_WINRT)) \ #if (defined(Q_OS_WIN) || defined(Q_OS_WIN32) || defined(Q_OS_WIN64) || defined(Q_OS_WINRT)) \
@ -42,7 +41,7 @@
Q_DISABLE_MOVE(Class) Q_DISABLE_MOVE(Class)
#endif #endif
class FRAMELESSHELPER_EXPORT FramelessQuickHelper : public QQuickItem class FramelessQuickHelper : public QQuickItem
{ {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY_MOVE(FramelessQuickHelper) Q_DISABLE_COPY_MOVE(FramelessQuickHelper)
@ -110,11 +109,7 @@ public:
public Q_SLOTS: public Q_SLOTS:
void removeWindowFrame(const bool center = false); void removeWindowFrame(const bool center = false);
void moveWindowToDesktopCenter(const bool realCenter = true); void moveWindowToDesktopCenter();
QSize desktopSize() const;
QRect desktopAvailableGeometry() const;
QSize desktopAvailableSize() const;
void addIgnoreArea(const QRect &val); void addIgnoreArea(const QRect &val);
void addDraggableArea(const QRect &val); void addDraggableArea(const QRect &val);
@ -124,7 +119,7 @@ public Q_SLOTS:
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
void setWindowFrameVisible(const bool value = true); void setWindowFrameVisible(const bool value = true);
void displaySystemMenu(const int x, const int y, const bool isRtl = false); void displaySystemMenu(const QPointF &pos = {});
void setBlurEffectEnabled(const bool enabled = true, void setBlurEffectEnabled(const bool enabled = true,
const bool forceAcrylic = false, const bool forceAcrylic = false,
const QColor &gradientColor = Qt::white); const QColor &gradientColor = Qt::white);
@ -135,7 +130,7 @@ protected:
void timerEvent(QTimerEvent *event) override; void timerEvent(QTimerEvent *event) override;
private: private:
void *rawHandle() const; void *rawWindowHandle() const;
#endif #endif
Q_SIGNALS: Q_SIGNALS:

View File

@ -24,16 +24,9 @@
#include "framelesswindowsmanager.h" #include "framelesswindowsmanager.h"
#ifndef Q_OS_WINDOWS
#include <QGuiApplication> #include <QGuiApplication>
#include <QScreen>
#include <QWindow> #include <QWindow>
#ifdef QT_WIDGETS_LIB
#include <QWidget>
#endif
#if (defined(Q_OS_WIN) || defined(Q_OS_WIN32) || defined(Q_OS_WIN64) || defined(Q_OS_WINRT)) \
&& !defined(Q_OS_WINDOWS)
#define Q_OS_WINDOWS
#endif #endif
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
@ -42,70 +35,30 @@
#include "framelesshelper.h" #include "framelesshelper.h"
#endif #endif
#ifndef Q_OS_WINDOWS
namespace { namespace {
void reportError() QWindow *toWindow(QObject *object)
{ {
qFatal("Only top level QWidgets and QWindows are accepted."); Q_ASSERT(object);
return object->isWindowType() ? qobject_cast<QWindow *>(object) : nullptr;
} }
QScreen *getCurrentScreenFromWindow(QObject *window)
{
Q_ASSERT(window);
if (window->isWindowType()) {
return qobject_cast<QWindow *>(window)->screen();
}
#ifdef QT_WIDGETS_LIB
else if (window->isWidgetType()) {
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
return qobject_cast<QWidget *>(window)->screen();
#else
QWindow *win = qobject_cast<QWidget *>(window)->windowHandle();
return win ? win->screen() : nullptr;
#endif
}
#endif
else {
reportError();
}
return nullptr;
}
#ifdef Q_OS_WINDOWS
void *getRawHandleFromWindow(QObject *window)
{
Q_ASSERT(window);
if (window->isWindowType()) {
return reinterpret_cast<void *>(qobject_cast<QWindow *>(window)->winId());
}
#ifdef QT_WIDGETS_LIB
else if (window->isWidgetType()) {
return reinterpret_cast<void *>(qobject_cast<QWidget *>(window)->winId());
}
#endif
else {
reportError();
}
return nullptr;
}
#endif
#ifndef Q_OS_WINDOWS
using FLWM_CORE_DATA = struct _FLWM_CORE_DATA using FLWM_CORE_DATA = struct _FLWM_CORE_DATA
{ {
FramelessHelper framelessHelper; FramelessHelper framelessHelper;
}; };
#endif
} // namespace } // namespace
#endif
#ifndef Q_OS_WINDOWS #ifndef Q_OS_WINDOWS
Q_GLOBAL_STATIC(FLWM_CORE_DATA, coreData) Q_GLOBAL_STATIC(FLWM_CORE_DATA, coreData)
#endif #endif
FramelessWindowsManager::FramelessWindowsManager() {} FramelessWindowsManager::FramelessWindowsManager() = default;
void FramelessWindowsManager::addWindow(QObject *window, const bool center) void FramelessWindowsManager::addWindow(WindowId window, const bool center)
{ {
Q_ASSERT(window); Q_ASSERT(window);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
@ -118,86 +71,17 @@ void FramelessWindowsManager::addWindow(QObject *window, const bool center)
} }
} }
void FramelessWindowsManager::moveWindowToDesktopCenter(QObject *window, const bool realCenter) void FramelessWindowsManager::moveWindowToDesktopCenter(WindowId window)
{ {
Q_ASSERT(window); Q_ASSERT(window);
if (realCenter) {
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
WinNativeEventFilter::moveWindowToDesktopCenter(getRawHandleFromWindow(window)); WinNativeEventFilter::moveWindowToDesktopCenter(window);
#else #else
FramelessHelper::moveWindowToDesktopCenter(window); FramelessHelper::moveWindowToDesktopCenter(window);
#endif #endif
} else {
QSize windowSize = {}, screenSize = {};
QRect screenGeometry = {};
if (window->isWindowType()) {
const auto win = qobject_cast<QWindow *>(window);
if (win) {
windowSize = win->size();
screenSize = getDesktopAvailableSize(win);
screenGeometry = getDesktopAvailableGeometry(win);
}
}
#ifdef QT_WIDGETS_LIB
else if (window->isWidgetType()) {
const auto widget = qobject_cast<QWidget *>(window);
if (widget && widget->isTopLevel()) {
windowSize = widget->size();
screenSize = getDesktopAvailableSize(widget);
screenGeometry = getDesktopAvailableGeometry(widget);
}
}
#endif
else {
reportError();
}
const int newX = qRound(static_cast<qreal>(screenSize.width() - windowSize.width()) / 2.0);
const int newY = qRound(static_cast<qreal>(screenSize.height() - windowSize.height()) / 2.0);
const int x = newX + screenGeometry.x();
const int y = newY + screenGeometry.y();
if (window->isWindowType()) {
const auto win = qobject_cast<QWindow *>(window);
if (win) {
win->setX(x);
win->setY(y);
}
}
#ifdef QT_WIDGETS_LIB
else if (window->isWidgetType()) {
const auto widget = qobject_cast<QWidget *>(window);
if (widget && widget->isTopLevel()) {
widget->move(x, y);
}
}
#endif
else {
reportError();
}
}
} }
QSize FramelessWindowsManager::getDesktopSize(QObject *window) void FramelessWindowsManager::addIgnoreArea(WindowId window, const QRect &area)
{
const QScreen *screen = window ? getCurrentScreenFromWindow(window)
: QGuiApplication::primaryScreen();
return screen ? screen->size() : QSize();
}
QRect FramelessWindowsManager::getDesktopAvailableGeometry(QObject *window)
{
const QScreen *screen = window ? getCurrentScreenFromWindow(window)
: QGuiApplication::primaryScreen();
return screen ? screen->availableGeometry() : QRect();
}
QSize FramelessWindowsManager::getDesktopAvailableSize(QObject *window)
{
const QScreen *screen = window ? getCurrentScreenFromWindow(window)
: QGuiApplication::primaryScreen();
return screen ? screen->availableSize() : QSize();
}
void FramelessWindowsManager::addIgnoreArea(QObject *window, const QRect &area)
{ {
Q_ASSERT(window); Q_ASSERT(window);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
@ -210,7 +94,7 @@ void FramelessWindowsManager::addIgnoreArea(QObject *window, const QRect &area)
#endif #endif
} }
void FramelessWindowsManager::addDraggableArea(QObject *window, const QRect &area) void FramelessWindowsManager::addDraggableArea(WindowId window, const QRect &area)
{ {
Q_ASSERT(window); Q_ASSERT(window);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
@ -223,7 +107,7 @@ void FramelessWindowsManager::addDraggableArea(QObject *window, const QRect &are
#endif #endif
} }
void FramelessWindowsManager::addIgnoreObject(QObject *window, QObject *object) void FramelessWindowsManager::addIgnoreObject(WindowId window, QObject *object)
{ {
Q_ASSERT(window); Q_ASSERT(window);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
@ -236,7 +120,7 @@ void FramelessWindowsManager::addIgnoreObject(QObject *window, QObject *object)
#endif #endif
} }
void FramelessWindowsManager::addDraggableObject(QObject *window, QObject *object) void FramelessWindowsManager::addDraggableObject(WindowId window, QObject *object)
{ {
Q_ASSERT(window); Q_ASSERT(window);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
@ -249,11 +133,11 @@ void FramelessWindowsManager::addDraggableObject(QObject *window, QObject *objec
#endif #endif
} }
int FramelessWindowsManager::getBorderWidth(QObject *window) int FramelessWindowsManager::getBorderWidth(WindowId window)
{ {
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
Q_ASSERT(window); Q_ASSERT(window);
return WinNativeEventFilter::getSystemMetric(getRawHandleFromWindow(window), return WinNativeEventFilter::getSystemMetric(window,
WinNativeEventFilter::SystemMetric::BorderWidth); WinNativeEventFilter::SystemMetric::BorderWidth);
#else #else
Q_UNUSED(window) Q_UNUSED(window)
@ -261,7 +145,7 @@ int FramelessWindowsManager::getBorderWidth(QObject *window)
#endif #endif
} }
void FramelessWindowsManager::setBorderWidth(QObject *window, const int value) void FramelessWindowsManager::setBorderWidth(WindowId window, const int value)
{ {
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
Q_ASSERT(window); Q_ASSERT(window);
@ -275,11 +159,11 @@ void FramelessWindowsManager::setBorderWidth(QObject *window, const int value)
#endif #endif
} }
int FramelessWindowsManager::getBorderHeight(QObject *window) int FramelessWindowsManager::getBorderHeight(WindowId window)
{ {
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
Q_ASSERT(window); Q_ASSERT(window);
return WinNativeEventFilter::getSystemMetric(getRawHandleFromWindow(window), return WinNativeEventFilter::getSystemMetric(window,
WinNativeEventFilter::SystemMetric::BorderHeight); WinNativeEventFilter::SystemMetric::BorderHeight);
#else #else
Q_UNUSED(window) Q_UNUSED(window)
@ -287,7 +171,7 @@ int FramelessWindowsManager::getBorderHeight(QObject *window)
#endif #endif
} }
void FramelessWindowsManager::setBorderHeight(QObject *window, const int value) void FramelessWindowsManager::setBorderHeight(WindowId window, const int value)
{ {
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
Q_ASSERT(window); Q_ASSERT(window);
@ -301,11 +185,11 @@ void FramelessWindowsManager::setBorderHeight(QObject *window, const int value)
#endif #endif
} }
int FramelessWindowsManager::getTitleBarHeight(QObject *window) int FramelessWindowsManager::getTitleBarHeight(WindowId window)
{ {
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
Q_ASSERT(window); Q_ASSERT(window);
return WinNativeEventFilter::getSystemMetric(getRawHandleFromWindow(window), return WinNativeEventFilter::getSystemMetric(window,
WinNativeEventFilter::SystemMetric::TitleBarHeight); WinNativeEventFilter::SystemMetric::TitleBarHeight);
#else #else
Q_UNUSED(window) Q_UNUSED(window)
@ -313,7 +197,7 @@ int FramelessWindowsManager::getTitleBarHeight(QObject *window)
#endif #endif
} }
void FramelessWindowsManager::setTitleBarHeight(QObject *window, const int value) void FramelessWindowsManager::setTitleBarHeight(WindowId window, const int value)
{ {
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
Q_ASSERT(window); Q_ASSERT(window);
@ -327,7 +211,7 @@ void FramelessWindowsManager::setTitleBarHeight(QObject *window, const int value
#endif #endif
} }
bool FramelessWindowsManager::getResizable(QObject *window) bool FramelessWindowsManager::getResizable(WindowId window)
{ {
Q_ASSERT(window); Q_ASSERT(window);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
@ -338,39 +222,29 @@ bool FramelessWindowsManager::getResizable(QObject *window)
#endif #endif
} }
void FramelessWindowsManager::setResizable(QObject *window, const bool value) void FramelessWindowsManager::setResizable(WindowId window, const bool value)
{ {
Q_ASSERT(window); Q_ASSERT(window);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
WinNativeEventFilter::setWindowResizable(getRawHandleFromWindow(window), value); WinNativeEventFilter::setWindowResizable(window, value);
#else #else
coreData()->framelessHelper.setResizable(window, value); coreData()->framelessHelper.setResizable(window, value);
#endif #endif
} }
QSize FramelessWindowsManager::getMinimumSize(QObject *window) QSize FramelessWindowsManager::getMinimumSize(WindowId window)
{ {
Q_ASSERT(window); Q_ASSERT(window);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
const auto data = WinNativeEventFilter::getWindowData(window); const auto data = WinNativeEventFilter::getWindowData(window);
return data ? data->minimumSize : QSize(); return data ? data->minimumSize : QSize();
#else #else
if (window->isWindowType()) { const auto win = toWindow(window);
return qobject_cast<QWindow *>(window)->minimumSize(); return win ? win->minimumSize() : QSize();
}
#ifdef QT_WIDGETS_LIB
else if (window->isWidgetType()) {
return qobject_cast<QWidget *>(window)->minimumSize();
}
#endif
else {
reportError();
}
return {};
#endif #endif
} }
void FramelessWindowsManager::setMinimumSize(QObject *window, const QSize &value) void FramelessWindowsManager::setMinimumSize(WindowId window, const QSize &value)
{ {
Q_ASSERT(window); Q_ASSERT(window);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
@ -379,43 +253,26 @@ void FramelessWindowsManager::setMinimumSize(QObject *window, const QSize &value
data->minimumSize = value; data->minimumSize = value;
} }
#else #else
if (window->isWindowType()) { const auto win = toWindow(window);
qobject_cast<QWindow *>(window)->setMinimumSize(value); if (win) {
} win->setMinimumSize(value);
#ifdef QT_WIDGETS_LIB
else if (window->isWidgetType()) {
qobject_cast<QWidget *>(window)->setMinimumSize(value);
}
#endif
else {
reportError();
} }
#endif #endif
} }
QSize FramelessWindowsManager::getMaximumSize(QObject *window) QSize FramelessWindowsManager::getMaximumSize(WindowId window)
{ {
Q_ASSERT(window); Q_ASSERT(window);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
const auto data = WinNativeEventFilter::getWindowData(window); const auto data = WinNativeEventFilter::getWindowData(window);
return data ? data->maximumSize : QSize(); return data ? data->maximumSize : QSize();
#else #else
if (window->isWindowType()) { const auto win = toWindow(window);
return qobject_cast<QWindow *>(window)->maximumSize(); return win ? win->maximumSize() : QSize();
}
#ifdef QT_WIDGETS_LIB
else if (window->isWidgetType()) {
return qobject_cast<QWidget *>(window)->maximumSize();
}
#endif
else {
reportError();
}
return {};
#endif #endif
} }
void FramelessWindowsManager::setMaximumSize(QObject *window, const QSize &value) void FramelessWindowsManager::setMaximumSize(WindowId window, const QSize &value)
{ {
Q_ASSERT(window); Q_ASSERT(window);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
@ -424,21 +281,14 @@ void FramelessWindowsManager::setMaximumSize(QObject *window, const QSize &value
data->maximumSize = value; data->maximumSize = value;
} }
#else #else
if (window->isWindowType()) { const auto win = toWindow(window);
qobject_cast<QWindow *>(window)->setMaximumSize(value); if (win) {
} win->setMaximumSize(value);
#ifdef QT_WIDGETS_LIB
else if (window->isWidgetType()) {
qobject_cast<QWidget *>(window)->setMaximumSize(value);
}
#endif
else {
reportError();
} }
#endif #endif
} }
bool FramelessWindowsManager::getTitleBarEnabled(QObject *window) bool FramelessWindowsManager::getTitleBarEnabled(WindowId window)
{ {
Q_ASSERT(window); Q_ASSERT(window);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
@ -449,7 +299,7 @@ bool FramelessWindowsManager::getTitleBarEnabled(QObject *window)
#endif #endif
} }
void FramelessWindowsManager::setTitleBarEnabled(QObject *window, const bool value) void FramelessWindowsManager::setTitleBarEnabled(WindowId window, const bool value)
{ {
Q_ASSERT(window); Q_ASSERT(window);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS

View File

@ -27,6 +27,11 @@
#include "framelesshelper_global.h" #include "framelesshelper_global.h"
#include <QRect> #include <QRect>
#if (defined(Q_OS_WIN) || defined(Q_OS_WIN32) || defined(Q_OS_WIN64) || defined(Q_OS_WINRT)) \
&& !defined(Q_OS_WINDOWS)
#define Q_OS_WINDOWS
#endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
QT_FORWARD_DECLARE_CLASS(QObject) QT_FORWARD_DECLARE_CLASS(QObject)
QT_END_NAMESPACE QT_END_NAMESPACE
@ -46,41 +51,45 @@ class FRAMELESSHELPER_EXPORT FramelessWindowsManager
Q_DISABLE_COPY_MOVE(FramelessWindowsManager) Q_DISABLE_COPY_MOVE(FramelessWindowsManager)
public: public:
using WindowId =
#ifdef Q_OS_WINDOWS
void *
#else
QObject *
#endif
;
explicit FramelessWindowsManager(); explicit FramelessWindowsManager();
~FramelessWindowsManager() = default; ~FramelessWindowsManager() = default;
static void addWindow(QObject *window, const bool center = false); static void addWindow(WindowId window, const bool center = false);
static void moveWindowToDesktopCenter(QObject *window, const bool realCenter = true); static void moveWindowToDesktopCenter(WindowId window);
static QSize getDesktopSize(QObject *window = nullptr); static void addIgnoreArea(WindowId window, const QRect &area);
static QRect getDesktopAvailableGeometry(QObject *window = nullptr); static void addDraggableArea(WindowId window, const QRect &area);
static QSize getDesktopAvailableSize(QObject *window = nullptr);
static void addIgnoreArea(QObject *window, const QRect &area); static void addIgnoreObject(WindowId window, QObject *object);
static void addDraggableArea(QObject *window, const QRect &area); static void addDraggableObject(WindowId window, QObject *object);
static void addIgnoreObject(QObject *window, QObject *object); static int getBorderWidth(WindowId window);
static void addDraggableObject(QObject *window, QObject *object); static void setBorderWidth(WindowId window, const int value);
static int getBorderWidth(QObject *window); static int getBorderHeight(WindowId window);
static void setBorderWidth(QObject *window, const int value); static void setBorderHeight(WindowId window, const int value);
static int getBorderHeight(QObject *window); static int getTitleBarHeight(WindowId window);
static void setBorderHeight(QObject *window, const int value); static void setTitleBarHeight(WindowId window, const int value);
static int getTitleBarHeight(QObject *window); static bool getResizable(WindowId window);
static void setTitleBarHeight(QObject *window, const int value); static void setResizable(WindowId window, const bool value = true);
static bool getResizable(QObject *window); static QSize getMinimumSize(WindowId window);
static void setResizable(QObject *window, const bool value = true); static void setMinimumSize(WindowId window, const QSize &value);
static QSize getMinimumSize(QObject *window); static QSize getMaximumSize(WindowId window);
static void setMinimumSize(QObject *window, const QSize &value); static void setMaximumSize(WindowId window, const QSize &value);
static QSize getMaximumSize(QObject *window); static bool getTitleBarEnabled(WindowId window);
static void setMaximumSize(QObject *window, const QSize &value); static void setTitleBarEnabled(WindowId window, const bool value = true);
static bool getTitleBarEnabled(QObject *window);
static void setTitleBarEnabled(QObject *window, const bool value = true);
}; };

10
lib.pro
View File

@ -3,8 +3,10 @@ TEMPLATE = lib
win32: DLLDESTDIR = $$OUT_PWD/bin win32: DLLDESTDIR = $$OUT_PWD/bin
else: unix: DESTDIR = $$OUT_PWD/bin else: unix: DESTDIR = $$OUT_PWD/bin
QT += gui-private QT += gui-private
qtHaveModule(widgets): QT += widgets unix {
qtHaveModule(quick): QT += quick qtHaveModule(widgets): QT += widgets
qtHaveModule(quick): QT += quick
}
CONFIG += c++17 strict_c++ utf8_source warn_on CONFIG += c++17 strict_c++ utf8_source warn_on
DEFINES += \ DEFINES += \
QT_NO_CAST_FROM_ASCII \ QT_NO_CAST_FROM_ASCII \
@ -14,10 +16,6 @@ HEADERS += \
framelesshelper_global.h \ framelesshelper_global.h \
framelesswindowsmanager.h framelesswindowsmanager.h
SOURCES += framelesswindowsmanager.cpp SOURCES += framelesswindowsmanager.cpp
qtHaveModule(quick) {
HEADERS += framelessquickhelper.h
SOURCES += framelessquickhelper.cpp
}
win32 { win32 {
DEFINES += WIN32_LEAN_AND_MEAN _CRT_SECURE_NO_WARNINGS DEFINES += WIN32_LEAN_AND_MEAN _CRT_SECURE_NO_WARNINGS
CONFIG += LINK_TO_SYSTEM_DLL CONFIG += LINK_TO_SYSTEM_DLL

View File

@ -46,12 +46,6 @@
#else #else
#include <QSysInfo> #include <QSysInfo>
#endif #endif
#ifdef QT_QUICK_LIB
#include <QQuickItem>
#endif
#ifdef QT_WIDGETS_LIB
#include <QWidget>
#endif
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
#include <qpa/qplatformnativeinterface.h> #include <qpa/qplatformnativeinterface.h>
#else #else
@ -1115,25 +1109,6 @@ void qCoreAppFixup()
} }
} }
HWND getHWNDFromQObject(QObject *object)
{
Q_ASSERT(object);
WId wid = 0;
if (object->isWindowType()) {
wid = qobject_cast<QWindow *>(object)->winId();
}
#ifdef QT_WIDGETS_LIB
else if (object->isWidgetType()) {
wid = qobject_cast<QWidget *>(object)->winId();
}
#endif
else {
qFatal(
"Can't acquire the window handle: only top level QWidgets and QWindows are accepted.");
}
return reinterpret_cast<HWND>(wid);
}
void updateQtFrame_internal(const HWND handle, const bool resetToDefault = false) void updateQtFrame_internal(const HWND handle, const bool resetToDefault = false)
{ {
Q_ASSERT(handle); Q_ASSERT(handle);
@ -1149,21 +1124,17 @@ void updateQtFrame_internal(const HWND handle, const bool resetToDefault = false
} }
} }
bool displaySystemMenu_internal(const HWND handle, const bool isRtl, const LPARAM lParam) bool displaySystemMenu_internal(const HWND handle, const LPARAM lParam)
{ {
Q_ASSERT(handle); Q_ASSERT(handle);
if (WNEF_EXECUTE_WINAPI_RETURN(IsWindow, FALSE, handle)) { if (WNEF_EXECUTE_WINAPI_RETURN(IsWindow, FALSE, handle)) {
const POINT globalMouse{GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; POINT localMouse = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
POINT localMouse = globalMouse;
WNEF_EXECUTE_WINAPI(ScreenToClient, handle, &localMouse) WNEF_EXECUTE_WINAPI(ScreenToClient, handle, &localMouse)
const int tbh = WinNativeEventFilter::getSystemMetric( const int tbh = WinNativeEventFilter::getSystemMetric(
handle, WinNativeEventFilter::SystemMetric::TitleBarHeight, true); handle, WinNativeEventFilter::SystemMetric::TitleBarHeight, true);
const bool isTitleBar = localMouse.y <= tbh; const bool isTitleBar = localMouse.y <= tbh;
if (isTitleBar && !IsFullScreen(handle)) { if (isTitleBar && !IsFullScreen(handle)) {
return WinNativeEventFilter::displaySystemMenu(handle, return WinNativeEventFilter::displaySystemMenu(handle);
isRtl,
globalMouse.x,
globalMouse.y);
} }
} }
return false; return false;
@ -1256,18 +1227,6 @@ void WinNativeEventFilter::addFramelessWindow(void *window,
} }
} }
void WinNativeEventFilter::addFramelessWindow(QObject *window,
const WINDOWDATA *data,
const bool center,
const int x,
const int y,
const int width,
const int height)
{
Q_ASSERT(window);
addFramelessWindow(getHWNDFromQObject(window), data, center, x, y, width, height);
}
void WinNativeEventFilter::removeFramelessWindow(void *window) void WinNativeEventFilter::removeFramelessWindow(void *window)
{ {
Q_ASSERT(window); Q_ASSERT(window);
@ -1282,12 +1241,6 @@ void WinNativeEventFilter::removeFramelessWindow(void *window)
updateWindow(window, true, false); updateWindow(window, true, false);
} }
void WinNativeEventFilter::removeFramelessWindow(QObject *window)
{
Q_ASSERT(window);
removeFramelessWindow(getHWNDFromQObject(window));
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
void *message, void *message,
@ -1775,6 +1728,7 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
*result = HTTRANSPARENT; *result = HTTRANSPARENT;
return true; return true;
} }
const auto isInSpecificAreas = const auto isInSpecificAreas =
[](const QPointF &mousePos, const QList<QRect> &areas, const qreal dpr) -> bool { [](const QPointF &mousePos, const QList<QRect> &areas, const qreal dpr) -> bool {
if (areas.isEmpty()) { if (areas.isEmpty()) {
@ -1794,7 +1748,6 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
} }
return false; return false;
}; };
#if defined(QT_WIDGETS_LIB) || defined(QT_QUICK_LIB)
const auto isInSpecificObjects = [](const QPointF &mousePos, const auto isInSpecificObjects = [](const QPointF &mousePos,
const QList<QObject *> &objects, const QList<QObject *> &objects,
const qreal dpr) -> bool { const qreal dpr) -> bool {
@ -1805,40 +1758,34 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
if (!object) { if (!object) {
continue; continue;
} }
#ifdef QT_WIDGETS_LIB const bool isWidget = object->inherits("QWidget");
const auto widget = qobject_cast<QWidget *>(object); const bool isQuickItem = object->inherits("QQuickItem");
if (widget) { if (!isWidget && !isQuickItem) {
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) qWarning() << object << "is not a QWidget or QQuickItem!";
const QPointF pos = widget->mapToGlobal(QPointF{0, 0}); continue;
#else
const QPoint pos = widget->mapToGlobal(QPoint{0, 0});
#endif
if (QRectF(pos.x() * dpr,
pos.y() * dpr,
widget->width() * dpr,
widget->height() * dpr)
.contains(mousePos)) {
return true;
}
} }
#endif const auto mapOriginPointToWindow = [](const QObject *obj) -> QPointF {
#ifdef QT_QUICK_LIB Q_ASSERT(obj);
const auto quickItem = qobject_cast<QQuickItem *>(object); QPointF point = {obj->property("x").toReal(), obj->property("y").toReal()};
if (quickItem) { for (QObject *parent = obj->parent(); parent; parent = parent->parent()) {
const QPointF pos = quickItem->mapToGlobal(QPointF{0, 0}); point += {parent->property("x").toReal(),
if (QRectF(pos.x() * dpr, parent->property("y").toReal()};
pos.y() * dpr,
quickItem->width() * dpr,
quickItem->height() * dpr)
.contains(mousePos)) {
return true;
} }
return point;
};
const QPointF originPoint = mapOriginPointToWindow(object);
const qreal width = object->property("width").toReal();
const qreal height = object->property("height").toReal();
if (QRectF(originPoint.x() * dpr,
originPoint.y() * dpr,
width * dpr,
height * dpr)
.contains(mousePos)) {
return true;
} }
#endif
} }
return false; return false;
}; };
#endif
const qreal dpr = GetDevicePixelRatioForWindow(msg->hwnd); const qreal dpr = GetDevicePixelRatioForWindow(msg->hwnd);
const QPointF globalMouse = QCursor::pos() * dpr; const QPointF globalMouse = QCursor::pos() * dpr;
POINT winLocalMouse = {qRound(globalMouse.x()), qRound(globalMouse.y())}; POINT winLocalMouse = {qRound(globalMouse.x()), qRound(globalMouse.y())};
@ -1852,7 +1799,6 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
data->draggableAreas, data->draggableAreas,
dpr) dpr)
: true; : true;
#if defined(QT_WIDGETS_LIB) || defined(QT_QUICK_LIB)
const bool isInIgnoreObjects = isInSpecificObjects(globalMouse, const bool isInIgnoreObjects = isInSpecificObjects(globalMouse,
data->ignoreObjects, data->ignoreObjects,
dpr); dpr);
@ -1862,14 +1808,6 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
data->draggableObjects, data->draggableObjects,
dpr) dpr)
: true; : true;
#else
// Don't block resizing if both of the Qt Widgets module and Qt
// Quick module are not compiled in, although there's not much
// significance of using this code in this case.
const bool isInIgnoreObjects = false;
const bool isInDraggableObjects = true;
const bool customDragObjects = false;
#endif
const bool customDrag = customDragAreas || customDragObjects; const bool customDrag = customDragAreas || customDragObjects;
const bool isResizePermitted = !isInIgnoreAreas && !isInIgnoreObjects; const bool isResizePermitted = !isInIgnoreAreas && !isInIgnoreObjects;
const int bh = getSystemMetric(msg->hwnd, SystemMetric::BorderHeight, true); const int bh = getSystemMetric(msg->hwnd, SystemMetric::BorderHeight, true);
@ -2074,7 +2012,7 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
// (SHIFT + F10 or the context menu key), lParam will be -1. // (SHIFT + F10 or the context menu key), lParam will be -1.
const LPARAM lParam = (msg->lParam == -1) ? WNEF_EXECUTE_WINAPI_RETURN(GetMessagePos, 0) const LPARAM lParam = (msg->lParam == -1) ? WNEF_EXECUTE_WINAPI_RETURN(GetMessagePos, 0)
: msg->lParam; : msg->lParam;
if (displaySystemMenu_internal(msg->hwnd, false, lParam)) { if (displaySystemMenu_internal(msg->hwnd, lParam)) {
// The WM_CONTEXTMENU message has no return value so there's // The WM_CONTEXTMENU message has no return value so there's
// no need to modify *result. // no need to modify *result.
return true; return true;
@ -2110,12 +2048,6 @@ void WinNativeEventFilter::setWindowData(void *window, const WINDOWDATA *data)
} }
} }
void WinNativeEventFilter::setWindowData(QObject *window, const WINDOWDATA *data)
{
Q_ASSERT(window);
setWindowData(getHWNDFromQObject(window), data);
}
WinNativeEventFilter::WINDOWDATA *WinNativeEventFilter::getWindowData(void *window) WinNativeEventFilter::WINDOWDATA *WinNativeEventFilter::getWindowData(void *window)
{ {
Q_ASSERT(window); Q_ASSERT(window);
@ -2128,12 +2060,6 @@ WinNativeEventFilter::WINDOWDATA *WinNativeEventFilter::getWindowData(void *wind
return nullptr; return nullptr;
} }
WinNativeEventFilter::WINDOWDATA *WinNativeEventFilter::getWindowData(QObject *window)
{
Q_ASSERT(window);
return getWindowData(getHWNDFromQObject(window));
}
void WinNativeEventFilter::setBorderWidth(const int bw) void WinNativeEventFilter::setBorderWidth(const int bw)
{ {
coreData()->m_borderWidth = bw; coreData()->m_borderWidth = bw;
@ -2338,10 +2264,7 @@ void WinNativeEventFilter::updateQtFrame(QWindow *window, const int titleBarHeig
} }
} }
bool WinNativeEventFilter::displaySystemMenu(void *handle, bool WinNativeEventFilter::displaySystemMenu(void *handle, const QPointF &pos)
const bool isRtl,
const int x,
const int y)
{ {
Q_ASSERT(handle); Q_ASSERT(handle);
const auto hwnd = reinterpret_cast<HWND>(handle); const auto hwnd = reinterpret_cast<HWND>(handle);
@ -2377,15 +2300,20 @@ bool WinNativeEventFilter::displaySystemMenu(void *handle,
WNEF_EXECUTE_WINAPI(SetMenuItemInfoW, hMenu, SC_RESTORE, FALSE, &mii) WNEF_EXECUTE_WINAPI(SetMenuItemInfoW, hMenu, SC_RESTORE, FALSE, &mii)
} }
} }
const QPointF mousePos = pos.isNull()
? QCursor::pos() * GetDevicePixelRatioForWindow(hwnd)
: pos;
const LPARAM cmd = WNEF_EXECUTE_WINAPI_RETURN(TrackPopupMenu, const LPARAM cmd = WNEF_EXECUTE_WINAPI_RETURN(TrackPopupMenu,
0, 0,
hMenu, hMenu,
(TPM_LEFTBUTTON | TPM_RIGHTBUTTON (TPM_LEFTBUTTON | TPM_RIGHTBUTTON
| TPM_RETURNCMD | TPM_TOPALIGN | TPM_RETURNCMD | TPM_TOPALIGN
| (isRtl ? TPM_RIGHTALIGN | (QGuiApplication::layoutDirection()
: TPM_LEFTALIGN)), == Qt::RightToLeft
x, ? TPM_RIGHTALIGN
y, : TPM_LEFTALIGN)),
qRound(mousePos.x()),
qRound(mousePos.y()),
0, 0,
hwnd, hwnd,
nullptr); nullptr);

View File

@ -79,26 +79,16 @@ public:
const int y = -1, const int y = -1,
const int width = -1, const int width = -1,
const int height = -1); const int height = -1);
static void addFramelessWindow(QObject *window,
const WINDOWDATA *data = nullptr,
const bool center = false,
const int x = -1,
const int y = -1,
const int width = -1,
const int height = -1);
static void removeFramelessWindow(void *window /* HWND */); static void removeFramelessWindow(void *window /* HWND */);
static void removeFramelessWindow(QObject *window);
// Set borderWidth, borderHeight or titleBarHeight to a negative value to // Set borderWidth, borderHeight or titleBarHeight to a negative value to
// restore default behavior. // restore default behavior.
// Note that it can only affect one specific window. // Note that it can only affect one specific window.
// If you want to change these values globally, use setBorderWidth instead. // If you want to change these values globally, use setBorderWidth instead.
static void setWindowData(void *window /* HWND */, const WINDOWDATA *data); static void setWindowData(void *window /* HWND */, const WINDOWDATA *data);
static void setWindowData(QObject *window, const WINDOWDATA *data);
// You can modify the given window's data directly, it's the same with using // You can modify the given window's data directly, it's the same with using
// setWindowData. // setWindowData.
static WINDOWDATA *getWindowData(void *window /* HWND */); static WINDOWDATA *getWindowData(void *window /* HWND */);
static WINDOWDATA *getWindowData(QObject *window);
// Change settings globally, not a specific window. // Change settings globally, not a specific window.
// These values will be scaled automatically according to DPI, don't scale // These values will be scaled automatically according to DPI, don't scale
@ -135,10 +125,7 @@ public:
static void updateQtFrame(QWindow *window, const int titleBarHeight); static void updateQtFrame(QWindow *window, const int titleBarHeight);
// Display the system context menu. // Display the system context menu.
static bool displaySystemMenu(void *handle /* HWND */, static bool displaySystemMenu(void *handle /* HWND */, const QPointF &pos = {});
const bool isRtl,
const int x,
const int y);
// Enable or disable the blur effect for a specific window. // Enable or disable the blur effect for a specific window.
// On Win10 it's the Acrylic effect. // On Win10 it's the Acrylic effect.