various fixes and improvements

1. Make all demo applications be able to record and restore the previous window geometry.
2. Improve the robustness of the widgets and quick implementation.

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-05-13 14:19:50 +08:00
parent 915e775d94
commit 8042a78b8f
21 changed files with 335 additions and 56 deletions

View File

@ -23,13 +23,10 @@
*/
#include <QtWidgets/qapplication.h>
#include <framelessconfig_p.h>
#include "mainwindow.h"
FRAMELESSHELPER_USE_NAMESPACE
using namespace Global;
int main(int argc, char *argv[])
{
// Not necessary, but better call this function, before the construction
@ -38,8 +35,6 @@ int main(int argc, char *argv[])
QApplication application(argc, argv);
FramelessConfig::instance()->set(Option::CenterWindowBeforeShow);
MainWindow mainWindow;
mainWindow.show();

View File

@ -24,6 +24,10 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtCore/qsettings.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qdir.h>
#include <QtWidgets/qboxlayout.h>
#include <Utils>
#include <StandardTitleBar>
@ -34,6 +38,18 @@ FRAMELESSHELPER_USE_NAMESPACE
using namespace Global;
FRAMELESSHELPER_STRING_CONSTANT2(GeoKeyPath, "Window/Geometry")
FRAMELESSHELPER_STRING_CONSTANT2(StateKeyPath, "Window/State")
[[nodiscard]] static inline QSettings *appConfigFile()
{
const QFileInfo fileInfo(QCoreApplication::applicationFilePath());
const QString iniFileName = fileInfo.completeBaseName() + FRAMELESSHELPER_STRING_LITERAL(".ini");
const QString iniFilePath = fileInfo.canonicalPath() + QDir::separator() + iniFileName;
const auto settings = new QSettings(iniFilePath, QSettings::IniFormat);
return settings;
}
MainWindow::MainWindow(QWidget *parent, const Qt::WindowFlags flags) : FramelessMainWindow(parent, flags)
{
initialize();
@ -41,6 +57,14 @@ MainWindow::MainWindow(QWidget *parent, const Qt::WindowFlags flags) : Frameless
MainWindow::~MainWindow() = default;
void MainWindow::closeEvent(QCloseEvent *event)
{
const QScopedPointer<QSettings> settings(appConfigFile());
settings->setValue(kGeoKeyPath, saveGeometry());
settings->setValue(kStateKeyPath, saveState());
FramelessMainWindow::closeEvent(event);
}
void MainWindow::initialize()
{
m_titleBar.reset(new StandardTitleBar(this));
@ -60,6 +84,19 @@ void MainWindow::initialize()
helper->setSystemButton(m_titleBar->maximizeButton(), SystemButtonType::Maximize);
helper->setSystemButton(m_titleBar->closeButton(), SystemButtonType::Close);
helper->setHitTestVisible(mb); // IMPORTANT!
connect(helper, &FramelessWidgetsHelper::ready, this, [this, helper](){
const QScopedPointer<QSettings> settings(appConfigFile());
const QByteArray geoData = settings->value(kGeoKeyPath).toByteArray();
const QByteArray stateData = settings->value(kStateKeyPath).toByteArray();
if (geoData.isEmpty()) {
helper->moveWindowToDesktopCenter();
} else {
restoreGeometry(geoData);
}
if (!stateData.isEmpty()) {
restoreState(stateData);
}
});
setWindowTitle(tr("FramelessHelper demo application - Qt MainWindow"));
}

View File

@ -44,6 +44,9 @@ public:
explicit MainWindow(QWidget *parent = nullptr, const Qt::WindowFlags flags = {});
~MainWindow() override;
protected:
void closeEvent(QCloseEvent *event) override;
private:
void initialize();

View File

@ -52,8 +52,6 @@
#include <QApplication>
#include <QSurfaceFormat>
#include <QOpenGLContext>
#include <framelesshelpercore_global.h>
#include <framelessconfig_p.h>
#include "mainwindow.h"
// This example demonstrates easy, cross-platform usage of OpenGL ES 3.0 functions via
@ -66,8 +64,6 @@
FRAMELESSHELPER_USE_NAMESPACE
using namespace Global;
int main(int argc, char *argv[])
{
// Not necessary, but better call this function, before the construction
@ -76,8 +72,6 @@ int main(int argc, char *argv[])
QApplication application(argc, argv);
FramelessConfig::instance()->set(Option::CenterWindowBeforeShow);
QSurfaceFormat fmt = {};
fmt.setDepthBufferSize(24);

View File

@ -24,6 +24,10 @@
#include "mainwindow.h"
#include "glwidget.h"
#include <QtCore/qsettings.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qdir.h>
#include <QtWidgets/qboxlayout.h>
#include <FramelessWidgetsHelper>
#include <StandardTitleBar>
@ -33,6 +37,17 @@ FRAMELESSHELPER_USE_NAMESPACE
using namespace Global;
FRAMELESSHELPER_STRING_CONSTANT2(IniKeyPath, "Window/Geometry")
[[nodiscard]] static inline QSettings *appConfigFile()
{
const QFileInfo fileInfo(QCoreApplication::applicationFilePath());
const QString iniFileName = fileInfo.completeBaseName() + FRAMELESSHELPER_STRING_LITERAL(".ini");
const QString iniFilePath = fileInfo.canonicalPath() + QDir::separator() + iniFileName;
const auto settings = new QSettings(iniFilePath, QSettings::IniFormat);
return settings;
}
MainWindow::MainWindow(QWidget *parent) : FramelessWidget(parent)
{
initialize();
@ -40,6 +55,13 @@ MainWindow::MainWindow(QWidget *parent) : FramelessWidget(parent)
MainWindow::~MainWindow() = default;
void MainWindow::closeEvent(QCloseEvent *event)
{
const QScopedPointer<QSettings> settings(appConfigFile());
settings->setValue(kIniKeyPath, saveGeometry());
FramelessWidget::closeEvent(event);
}
void MainWindow::initialize()
{
resize(800, 600);
@ -58,4 +80,13 @@ void MainWindow::initialize()
helper->setSystemButton(m_titleBar->minimizeButton(), SystemButtonType::Minimize);
helper->setSystemButton(m_titleBar->maximizeButton(), SystemButtonType::Maximize);
helper->setSystemButton(m_titleBar->closeButton(), SystemButtonType::Close);
connect(helper, &FramelessWidgetsHelper::ready, this, [this, helper](){
const QScopedPointer<QSettings> settings(appConfigFile());
const QByteArray data = settings->value(kIniKeyPath).toByteArray();
if (data.isEmpty()) {
helper->moveWindowToDesktopCenter();
} else {
restoreGeometry(data);
}
});
}

View File

@ -41,6 +41,9 @@ public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow() override;
protected:
void closeEvent(QCloseEvent *event) override;
private:
void initialize();

View File

@ -28,6 +28,8 @@ find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS QuickControls2)
set(SOURCES
qml.qrc
main.cpp
settings.h
settings.cpp
)
if(WIN32)

View File

@ -26,14 +26,33 @@ import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Controls 2.0
import org.wangwenx190.FramelessHelper 1.0
import Demo 1.0
FramelessWindow {
id: window
visible: false // Hide the window before we sets up it's correct size and position.
width: 800
height: 600
title: qsTr("FramelessHelper demo application - Qt Quick")
color: (FramelessUtils.systemTheme === FramelessHelperConstants.Dark)
? FramelessUtils.defaultSystemDarkColor : FramelessUtils.defaultSystemLightColor
onClosing: Settings.saveGeometry(window)
FramelessHelper.onReady: {
// Let FramelessHelper know what's our homemade title bar, otherwise
// our window won't be draggable.
FramelessHelper.titleBarItem = titleBar;
// Make our own items visible to the hit test and on Windows, enable
// the snap layouts feature (available since Windows 11).
FramelessHelper.setSystemButton(titleBar.minimizeButton, FramelessHelperConstants.Minimize);
FramelessHelper.setSystemButton(titleBar.maximizeButton, FramelessHelperConstants.Maximize);
FramelessHelper.setSystemButton(titleBar.closeButton, FramelessHelperConstants.Close);
if (!Settings.restoreGeometry(window)) {
FramelessHelper.moveWindowToDesktopCenter();
}
// Finally, show the window after everything is setted.
window.visible = true;
}
Timer {
interval: 500
@ -55,19 +74,9 @@ FramelessWindow {
StandardTitleBar {
id: titleBar
anchors {
top: window.topBorderBottom
top: window.topBorderBottom // IMPORTANT!
left: parent.left
right: parent.right
}
Component.onCompleted: {
// Make our homemade title bar draggable, and open the system menu
// when the user right clicks on the title bar area.
FramelessHelper.titleBarItem = titleBar;
// Make our own items visible to the hit test and on Windows, enable
// the snap layout feature (available since Windows 11).
FramelessHelper.setSystemButton(titleBar.minimizeButton, FramelessHelperConstants.Minimize);
FramelessHelper.setSystemButton(titleBar.maximizeButton, FramelessHelperConstants.Maximize);
FramelessHelper.setSystemButton(titleBar.closeButton, FramelessHelperConstants.Close);
}
}
}

View File

@ -27,12 +27,10 @@
#include <QtQuick/qquickwindow.h>
#include <QtQuickControls2/qquickstyle.h>
#include <framelessquickmodule.h>
#include <framelessconfig_p.h>
#include "settings.h"
FRAMELESSHELPER_USE_NAMESPACE
using namespace Global;
int main(int argc, char *argv[])
{
// Not necessary, but better call this function, before the construction
@ -41,8 +39,6 @@ int main(int argc, char *argv[])
QGuiApplication application(argc, argv);
FramelessConfig::instance()->set(Option::CenterWindowBeforeShow);
// Allow testing other RHI backends through environment variable.
if (!qEnvironmentVariableIsSet("QSG_RHI_BACKEND")) {
// This line is not relevant to FramelessHelper, we change
@ -63,6 +59,13 @@ int main(int argc, char *argv[])
// Don't forget to register our own custom QML types!
FramelessHelper::Quick::registerTypes(&engine);
qmlRegisterSingletonType<Settings>("Demo", 1, 0, "Settings",
[](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
Q_UNUSED(engine);
Q_UNUSED(scriptEngine);
return new Settings;
});
// This line is not relevant to FramelessHelper, we change the default
// Qt Quick Controls theme to "Basic" (Qt6) or "Default" (Qt5) just
// because other themes will make our homemade system buttons look
@ -73,11 +76,11 @@ int main(int argc, char *argv[])
QQuickStyle::setStyle(FRAMELESSHELPER_STRING_LITERAL("Default"));
#endif
const QUrl homepageUrl(FRAMELESSHELPER_STRING_LITERAL("qrc:///Demo/qml/MainWindow.qml"));
const QUrl mainUrl(FRAMELESSHELPER_STRING_LITERAL("qrc:///Demo/qml/MainWindow.qml"));
const QMetaObject::Connection connection = QObject::connect(
&engine, &QQmlApplicationEngine::objectCreated, &application,
[&homepageUrl, &connection](QObject *object, const QUrl &url) {
if (url != homepageUrl) {
[&mainUrl, &connection](QObject *object, const QUrl &url) {
if (url != mainUrl) {
return;
}
if (object) {
@ -87,7 +90,7 @@ int main(int argc, char *argv[])
}
}, Qt::QueuedConnection);
engine.load(homepageUrl);
engine.load(mainUrl);
return QCoreApplication::exec();
}

View File

@ -0,0 +1,77 @@
/*
* MIT License
*
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "settings.h"
#include <QtCore/qsettings.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qdir.h>
#include <QtCore/qdatastream.h>
#include <QtGui/qwindow.h>
FRAMELESSHELPER_STRING_CONSTANT2(IniKeyPath, "Window/Geometry")
Settings::Settings(QObject *parent) : QObject(parent)
{
const QFileInfo fileInfo(QCoreApplication::applicationFilePath());
const QString iniFileName = fileInfo.completeBaseName() + FRAMELESSHELPER_STRING_LITERAL(".ini");
const QString iniFilePath = fileInfo.canonicalPath() + QDir::separator() + iniFileName;
m_settings.reset(new QSettings(iniFilePath, QSettings::IniFormat));
}
Settings::~Settings() = default;
void Settings::saveGeometry(QWindow *window)
{
Q_ASSERT(window);
if (!window) {
return;
}
QByteArray data = {};
QDataStream stream(&data, QDataStream::WriteOnly);
stream.setVersion(QDataStream::Qt_5_6);
stream << window->geometry();
m_settings->setValue(kIniKeyPath, data);
}
bool Settings::restoreGeometry(QWindow *window)
{
Q_ASSERT(window);
if (!window) {
return false;
}
const QByteArray data = m_settings->value(kIniKeyPath).toByteArray();
if (data.isEmpty()) {
return false;
}
QRect geometry = {};
QDataStream stream(data);
stream.setVersion(QDataStream::Qt_5_6);
stream >> geometry;
if (!geometry.isValid()) {
return false;
}
window->setGeometry(geometry);
return true;
}

50
examples/quick/settings.h Normal file
View File

@ -0,0 +1,50 @@
/*
* MIT License
*
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include <QtCore/qobject.h>
#include <framelesshelpercore_global.h>
QT_BEGIN_NAMESPACE
class QWindow;
class QSettings;
QT_END_NAMESPACE
class Settings : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(Settings)
public:
explicit Settings(QObject *parent = nullptr);
~Settings() override;
public Q_SLOTS:
void saveGeometry(QWindow *window);
Q_NODISCARD bool restoreGeometry(QWindow *window);
private:
QScopedPointer<QSettings> m_settings;
};

View File

@ -23,13 +23,10 @@
*/
#include <QtWidgets/qapplication.h>
#include <framelessconfig_p.h>
#include "widget.h"
FRAMELESSHELPER_USE_NAMESPACE
using namespace Global;
int main(int argc, char *argv[])
{
// Not necessary, but better call this function, before the construction
@ -38,8 +35,6 @@ int main(int argc, char *argv[])
QApplication application(argc, argv);
FramelessConfig::instance()->set(Option::CenterWindowBeforeShow);
Widget widget;
widget.show();

View File

@ -24,6 +24,10 @@
#include "widget.h"
#include <QtCore/qdatetime.h>
#include <QtCore/qsettings.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qdir.h>
#include <QtWidgets/qlabel.h>
#include <QtWidgets/qboxlayout.h>
#include <FramelessManager>
@ -36,6 +40,17 @@ FRAMELESSHELPER_USE_NAMESPACE
using namespace Global;
FRAMELESSHELPER_STRING_CONSTANT2(IniKeyPath, "Window/Geometry")
[[nodiscard]] static inline QSettings *appConfigFile()
{
const QFileInfo fileInfo(QCoreApplication::applicationFilePath());
const QString iniFileName = fileInfo.completeBaseName() + FRAMELESSHELPER_STRING_LITERAL(".ini");
const QString iniFilePath = fileInfo.canonicalPath() + QDir::separator() + iniFileName;
const auto settings = new QSettings(iniFilePath, QSettings::IniFormat);
return settings;
}
Widget::Widget(QWidget *parent) : FramelessWidget(parent)
{
initialize();
@ -53,6 +68,13 @@ void Widget::timerEvent(QTimerEvent *event)
}
}
void Widget::closeEvent(QCloseEvent *event)
{
const QScopedPointer<QSettings> settings(appConfigFile());
settings->setValue(kIniKeyPath, saveGeometry());
FramelessWidget::closeEvent(event);
}
void Widget::initialize()
{
setWindowTitle(tr("FramelessHelper demo application - Qt Widgets"));
@ -83,6 +105,15 @@ void Widget::initialize()
helper->setSystemButton(m_titleBar->minimizeButton(), SystemButtonType::Minimize);
helper->setSystemButton(m_titleBar->maximizeButton(), SystemButtonType::Maximize);
helper->setSystemButton(m_titleBar->closeButton(), SystemButtonType::Close);
connect(helper, &FramelessWidgetsHelper::ready, this, [this, helper](){
const QScopedPointer<QSettings> settings(appConfigFile());
const QByteArray data = settings->value(kIniKeyPath).toByteArray();
if (data.isEmpty()) {
helper->moveWindowToDesktopCenter();
} else {
restoreGeometry(data);
}
});
}
void Widget::updateStyleSheet()

View File

@ -45,6 +45,7 @@ public:
protected:
void timerEvent(QTimerEvent *event) override;
void closeEvent(QCloseEvent *event) override;
private:
void initialize();

View File

@ -71,6 +71,7 @@ protected:
Q_SIGNALS:
void titleBarItemChanged();
void ready();
private:
QScopedPointer<FramelessQuickHelperPrivate> d_ptr;

View File

@ -65,6 +65,8 @@ public:
Q_NODISCARD bool isWindowFixedSize() const;
void setWindowFixedSize(const bool value);
void emitSignalForAllInstances(const char *signal);
private:
Q_NODISCARD QRect mapItemGeometryToScene(const QQuickItem * const item) const;
Q_NODISCARD bool isInSystemButtons(const QPoint &pos, QuickGlobal::SystemButtonType *button) const;

View File

@ -64,6 +64,7 @@ public Q_SLOTS:
Q_SIGNALS:
void titleBarWidgetChanged();
void ready();
private:
QScopedPointer<FramelessWidgetsHelperPrivate> d_ptr;

View File

@ -61,6 +61,8 @@ public:
Q_NODISCARD bool isWindowFixedSize() const;
void setWindowFixedSize(const bool value);
void emitSignalForAllInstances(const char *signal);
private:
Q_NODISCARD QRect mapWidgetGeometryToScene(const QWidget * const widget) const;
Q_NODISCARD bool isInSystemButtons(const QPoint &pos, Global::SystemButtonType *button) const;

View File

@ -163,7 +163,7 @@ FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
switch (uMsg) {
case WM_NCHITTEST: {
// Try to determine what part of the window is being hovered here. This
// is absolutely critical to making sure the snap layout works!
// is absolutely critical to making sure the snap layouts works!
const POINT nativeGlobalPos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
POINT nativeLocalPos = nativeGlobalPos;
if (ScreenToClient(hWnd, &nativeLocalPos) == FALSE) {
@ -371,7 +371,7 @@ FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
const auto dragBarWindowHandle = reinterpret_cast<HWND>(dragBarWindowId);
const UINT flags = (SWP_NOACTIVATE | (hide ? SWP_HIDEWINDOW : SWP_SHOWWINDOW));
// As you can see from the code, we only use the drag bar window to activate the
// snap layout feature introduced in Windows 11. So you may wonder, why not just
// snap layouts feature introduced in Windows 11. So you may wonder, why not just
// limit it to the rectangle of the three system buttons, instead of covering the
// whole title bar area? Well, I've tried that solution already and unfortunately
// it doesn't work. Since our current solution works well, I have no plan to dig
@ -536,7 +536,6 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const LPARAM lParam = msg->lParam;
switch (uMsg) {
case WM_NCCALCSIZE: {
const bool isFixedSize = data.params.isWindowFixedSize();
// Windows是根据这个消息的返回值来设置窗口的客户区窗口中真正显示的内容
// 和非客户区标题栏、窗口边框、菜单栏和状态栏等Windows系统自行提供的部分
// 不过对于Qt来说除了标题栏和窗口边框非客户区基本也都是自绘的的范
@ -870,8 +869,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
(GetAsyncKeyState(VK_RBUTTON) < 0) : (GetAsyncKeyState(VK_LBUTTON) < 0));
const bool isTitleBar = (data.params.isInsideTitleBarDraggableArea(qtScenePos) && leftButtonPressed);
const bool isFixedSize = data.params.isWindowFixedSize();
if( frameBorderVisible )
{
if (frameBorderVisible) {
// This will handle the left, right and bottom parts of the frame
// because we didn't change them.
const LRESULT originalRet = DefWindowProcW(hWnd, WM_NCHITTEST, 0, lParam);
@ -1066,8 +1064,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
case WM_DISPLAYCHANGE: // Sent to a window when the display resolution has changed.
{
const bool isFixedSize = data.params.isWindowFixedSize();
if( !resizeDragBarWindow(windowId, data.dragBarWindowId, isFixedSize) )
{
if (!resizeDragBarWindow(windowId, data.dragBarWindowId, isFixedSize)) {
qWarning() << "Failed to re-position the drag bar window.";
}
} break;

View File

@ -148,8 +148,7 @@ void FramelessQuickHelperPrivate::setTitleBarItem(QQuickItem *value)
return;
}
data->titleBarItem = value;
Q_Q(FramelessQuickHelper);
Q_EMIT q->titleBarItemChanged();
emitSignalForAllInstances("titleBarItemChanged");
}
void FramelessQuickHelperPrivate::attachToWindow()
@ -218,11 +217,11 @@ void FramelessQuickHelperPrivate::attachToWindow()
// we reach here, and all the modifications from the Qt side will be lost
// due to QPA will reset the position and size of the window during it's
// initialization process.
QTimer::singleShot(0, this, [this, window](){
QTimer::singleShot(0, this, [this](){
if (FramelessConfig::instance()->isSet(Option::CenterWindowBeforeShow)) {
moveWindowToDesktopCenter();
}
window->setVisible(true);
emitSignalForAllInstances("ready");
});
}
@ -391,6 +390,27 @@ void FramelessQuickHelperPrivate::setWindowFixedSize(const bool value)
#endif
}
void FramelessQuickHelperPrivate::emitSignalForAllInstances(const char *signal)
{
Q_ASSERT(signal);
if (!signal) {
return;
}
Q_Q(FramelessQuickHelper);
const QQuickWindow * const window = q->window();
if (!window) {
return;
}
const auto rootObject = (window->contentItem() ? qobject_cast<const QObject *>(window->contentItem()) : qobject_cast<const QObject *>(window));
const auto instances = rootObject->findChildren<FramelessQuickHelper *>();
if (instances.isEmpty()) {
return;
}
for (auto &&instance : qAsConst(instances)) {
QMetaObject::invokeMethod(instance, signal);
}
}
QRect FramelessQuickHelperPrivate::mapItemGeometryToScene(const QQuickItem * const item) const
{
Q_ASSERT(item);
@ -616,7 +636,7 @@ FramelessQuickHelper *FramelessQuickHelper::get(QObject *object)
QObject *parent = nullptr;
if (isItem(object)) {
const auto item = qobject_cast<QQuickItem *>(object);
parent = (item->window() ? item->window()->contentItem() : item);
parent = ((item->window() && item->window()->contentItem()) ? item->window()->contentItem() : item);
} else {
parent = object;
}
@ -625,9 +645,8 @@ FramelessQuickHelper *FramelessQuickHelper::get(QObject *object)
instance = new FramelessQuickHelper;
if (isItem(parent)) {
instance->setParentItem(qobject_cast<QQuickItem *>(parent));
} else {
instance->setParent(parent);
}
instance->setParent(parent);
// No need to do this here, we'll do it once the item has been assigned to a specific window.
//instance->d_func()->attachToWindow();
}
@ -734,8 +753,16 @@ void FramelessQuickHelper::itemChange(const ItemChange change, const ItemChangeD
{
QQuickItem::itemChange(change, value);
if ((change == ItemSceneChange) && value.window) {
if (parentItem() != value.window->contentItem()) {
setParentItem(value.window->contentItem());
QQuickItem * const rootItem = value.window->contentItem();
if (rootItem) {
if ((parentItem() != rootItem) || (parent() != rootItem)) {
setParentItem(rootItem);
setParent(rootItem);
}
} else {
if (parent() != value.window) {
setParent(value.window);
}
}
Q_D(FramelessQuickHelper);
d->attachToWindow();

View File

@ -128,6 +128,25 @@ void FramelessWidgetsHelperPrivate::setWindowFixedSize(const bool value)
#endif
}
void FramelessWidgetsHelperPrivate::emitSignalForAllInstances(const char *signal)
{
Q_ASSERT(signal);
if (!signal) {
return;
}
const QWidget * const window = getWindow();
if (!window) {
return;
}
const auto instances = window->findChildren<FramelessWidgetsHelper *>();
if (instances.isEmpty()) {
return;
}
for (auto &&instance : qAsConst(instances)) {
QMetaObject::invokeMethod(instance, signal);
}
}
void FramelessWidgetsHelperPrivate::setTitleBarWidget(QWidget *widget)
{
Q_ASSERT(widget);
@ -143,8 +162,7 @@ void FramelessWidgetsHelperPrivate::setTitleBarWidget(QWidget *widget)
return;
}
data->titleBarWidget = widget;
Q_Q(FramelessWidgetsHelper);
Q_EMIT q->titleBarWidgetChanged();
emitSignalForAllInstances("titleBarWidgetChanged");
}
QWidget *FramelessWidgetsHelperPrivate::getTitleBarWidget() const
@ -245,11 +263,11 @@ void FramelessWidgetsHelperPrivate::attachToWindow()
// we reach here, and all the modifications from the Qt side will be lost
// due to QPA will reset the position and size of the window during it's
// initialization process.
QTimer::singleShot(0, this, [this, window](){
QTimer::singleShot(0, this, [this](){
if (FramelessConfig::instance()->isSet(Option::CenterWindowBeforeShow)) {
moveWindowToDesktopCenter();
}
window->setVisible(true);
emitSignalForAllInstances("ready");
});
}