Compare commits

...

7 Commits

Author SHA1 Message Date
Mentalflow 7ab4d66702
Merge branch 'main' of ssh://ourdocs.cn:60022/github_mirror/framelesshelper 2023-06-24 22:24:17 +08:00
Yuhang Zhao 86a9b85d04 cmake: fix cmake error on Apple 2023-06-20 11:07:38 +08:00
Yuhang Zhao b7556d467e cmake: update 2023-06-19 18:04:04 +08:00
Yuhang Zhao 074664afc2 cmake: update submodule 2023-06-19 17:48:40 +08:00
Yuhang Zhao 6229a0db3c README: fix wrong function name 2023-06-19 17:14:31 +08:00
Yuhang Zhao 6c27125d69 win: guard some code with proper version check 2023-06-19 16:07:43 +08:00
Yuhang Zhao fdd6640d5c cmake: fix wrong compilation flags 2023-06-19 15:29:14 +08:00
4 changed files with 14 additions and 4 deletions

View File

@ -111,6 +111,10 @@ if(MSVC)
if(FRAMELESSHELPER_ENABLE_VCLTL)
include(cmake/VC-LTL.cmake)
if("x${SupportLTL}" STREQUAL "xtrue")
# Make sure we will always overwrite the previous settings.
unset(CMAKE_MSVC_RUNTIME_LIBRARY)
unset(CMAKE_MSVC_RUNTIME_LIBRARY CACHE)
#unset(CMAKE_MSVC_RUNTIME_LIBRARY PARENT_SCOPE)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>" CACHE STRING "" FORCE)
endif()
endif()

View File

@ -189,9 +189,9 @@ set(QML_IMPORT_PATH ${QML_IMPORT_PATH} CACHE STRING "Qt Creator extra QML import
### Qt Widgets
To customize the window frame of a QWidget, you need to instantiate a `FramelessWidgetsHelper` object and then attach it to the widget's top level widget, and then `FramelessWidgetsHelper` will do all the rest work for you: the window frame will be removed automatically once it has been attached to the top level widget successfully. In theory you can instantiate multiple `FramelessWidgetsHelper` objects for a same widget, in this case there will be only one object that keeps functional, all other objects will become a wrapper of that one. But to make sure everything goes smoothly and normally, you should not do that in any case. The simplest way to instantiate a `FramelessWidgetsHelper`
object is to call the static method `FramelessWidgetsHelper *FramelessWidgetsHelper::get(QObject *)`. It will return the handle of the previously instantiated object if any, or it will instantiate a new object if it can't find one. It's safe to call this method multiple times for a same widget, it won't instantiate any new objects if there is one already. It also does not matter when and where you call that function as long as the top level widget is the same. The internally created objects will always be parented to the top level widget. Once you get the handle of the `FramelessWidgetsHelper` object, you can call `void FramelessWidgetsHelper::setContentExtendedIntoTitleBar(true)` to let it hide the default title bar provided by the operating system. In order to make sure `FramelessWidgetsHelper` can find the correct top level widget, you should call the `FramelessWidgetsHelper *FramelessWidgetsHelper::get(QObject *)` function on a widget which has a complete parent-chain whose root parent is the top level widget. To make the frameless window draggable, you should provide a homemade title bar widget yourself, the title bar widget doesn't need to be in rectangular shape, it also doesn't need to be placed on the first row of the window. Call `void FramelessWidgetsHelper::setTitleBarWidget(QWidget *)` to let `FramelessHelper` know what's your title bar widget. By default, all the widgets in the title bar area won't be responsible to any mouse and keyboard events due to they have been intercepted by FramelessHelper. To make them recover the responsible state, you should make them visible to hit test. Call `void FramelessWidgetsHelper::setHitTestVisible(QWidget* )` to do that. You can of course call it on a widget that is not inside the title bar at all, it won't have any effect though. Due to Qt's own limitations, you need to make sure your widget has a complete parent-chain whose root parent is the top level widget. Do not ever try to delete the `FramelessWidgetsHelper` object, it may still be monitoring and controlling your widget, and Qt will delete it for you automatically. No need to worry about memory leaks.
object is to call the static method `FramelessWidgetsHelper *FramelessWidgetsHelper::get(QObject *)`. It will return the handle of the previously instantiated object if any, or it will instantiate a new object if it can't find one. It's safe to call this method multiple times for a same widget, it won't instantiate any new objects if there is one already. It also does not matter when and where you call that function as long as the top level widget is the same. The internally created objects will always be parented to the top level widget. Once you get the handle of the `FramelessWidgetsHelper` object, you can call `void FramelessWidgetsHelper::extendsContentIntoTitleBar()` to let it hide the default title bar provided by the operating system. In order to make sure `FramelessWidgetsHelper` can find the correct top level widget, you should call the `FramelessWidgetsHelper *FramelessWidgetsHelper::get(QObject *)` function on a widget which has a complete parent-chain whose root parent is the top level widget. To make the frameless window draggable, you should provide a homemade title bar widget yourself, the title bar widget doesn't need to be in rectangular shape, it also doesn't need to be placed on the first row of the window. Call `void FramelessWidgetsHelper::setTitleBarWidget(QWidget *)` to let `FramelessHelper` know what's your title bar widget. By default, all the widgets in the title bar area won't be responsible to any mouse and keyboard events due to they have been intercepted by FramelessHelper. To make them recover the responsible state, you should make them visible to hit test. Call `void FramelessWidgetsHelper::setHitTestVisible(QWidget* )` to do that. You can of course call it on a widget that is not inside the title bar at all, it won't have any effect though. Due to Qt's own limitations, you need to make sure your widget has a complete parent-chain whose root parent is the top level widget. Do not ever try to delete the `FramelessWidgetsHelper` object, it may still be monitoring and controlling your widget, and Qt will delete it for you automatically. No need to worry about memory leaks.
There are also two classes called `FramelessWidget` and `FramelessMainWindow`, they are only simple wrappers of `FramelessWidgetsHelper`, which just saves the call of the `void FramelessWidgetsHelper::setContentExtendedIntoTitleBar(true)` function for you. You can absolutely use plain `QWidget` instead.
There are also two classes called `FramelessWidget` and `FramelessMainWindow`, they are only simple wrappers of `FramelessWidgetsHelper`, which just saves the call of the `void FramelessWidgetsHelper::extendsContentIntoTitleBar()` function for you. You can absolutely use plain `QWidget` instead.
#### Code Snippet
@ -211,7 +211,7 @@ Then hide the standard title bar provided by the OS:
MyWidget::MyWidget(QWidget *parent) : QWidget(parent)
{
// You should do this early enough.
FramelessWidgetsHelper::get(this)->setContentExtendedIntoTitleBar(true);
FramelessWidgetsHelper::get(this)->extendsContentIntoTitleBar();
// ...
}
```

2
cmake

@ -1 +1 @@
Subproject commit 2229432bf7f0e7ea81fc19b021aaccea09b6e57d
Subproject commit ea37ad2a4bc0f6738387af8a1f1d980acc385c37

View File

@ -99,7 +99,9 @@ struct Win32HelperData
bool trackingMouse = false;
WId fallbackTitleBarWindowId = 0;
Dpi dpi = {};
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
QRect restoreGeometry = {};
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
};
struct Win32Helper
@ -640,6 +642,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const WPARAM wParam = msg->wParam;
const LPARAM lParam = msg->lParam;
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
const auto updateRestoreGeometry = [windowId, &data](const bool ignoreWindowState) -> void {
if (!ignoreWindowState && !Utils::isWindowNoState(windowId)) {
return;
@ -654,6 +657,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
}
g_win32Helper()->data[windowId].restoreGeometry = rect;
};
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
switch (uMsg) {
#if (QT_VERSION < QT_VERSION_CHECK(5, 9, 0)) // Qt has done this for us since 5.9.0
@ -1175,11 +1179,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
DEBUG.noquote() << "New DPI for window" << hwnd2str(hWnd)
<< "is" << newDpi << "(was" << oldDpi << ").";
g_win32Helper()->data[windowId].dpi = newDpi;
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
if (Utils::isValidGeometry(data.restoreGeometry)) {
// Update the window size only. The position should not be changed.
g_win32Helper()->data[windowId].restoreGeometry.setSize(
Utils::rescaleSize(data.restoreGeometry.size(), oldDpi.x, newDpi.x));
}
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
data.params.forceChildrenRepaint(500);
} break;
case WM_DWMCOMPOSITIONCHANGED: {