allow user to remove a window from the frameless window list

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-09-20 15:56:59 +08:00
parent 3d3607af7b
commit 47bf4da5ae
19 changed files with 310 additions and 117 deletions

View File

@ -42,6 +42,7 @@ public:
~FramelessHelperQt() override;
static void addWindow(const Global::SystemParameters &params);
static void removeWindow(const WId windowId);
protected:
Q_NODISCARD bool eventFilter(QObject *object, QEvent *event) override;

View File

@ -41,6 +41,7 @@ public:
~FramelessHelperWin() override;
static void addWindow(const Global::SystemParameters &params);
static void removeWindow(const WId windowId);
Q_NODISCARD bool nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result) override;
};

View File

@ -57,6 +57,7 @@ public:
public Q_SLOTS:
void addWindow(const Global::SystemParameters &params);
void removeWindow(const WId windowId);
Q_SIGNALS:
void systemThemeChanged();

View File

@ -53,10 +53,13 @@ public:
Q_NODISCARD Global::WallpaperAspectStyle wallpaperAspectStyle() const;
static void addWindow(const Global::SystemParameters &params);
static void removeWindow(const WId windowId);
Q_INVOKABLE void notifySystemThemeHasChangedOrNot();
Q_INVOKABLE void notifyWallpaperHasChangedOrNot();
Q_NODISCARD static bool usePureQtImplementation();
private:
void initialize();

View File

@ -42,10 +42,10 @@ Q_DECLARE_LOGGING_CATEGORY(lcUtilsCommon)
namespace Utils
{
[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::CursorShape calculateCursorShape(const QWindow *window,
const QPoint &pos);
[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::Edges calculateWindowEdges(const QWindow *window,
const QPoint &pos);
[[nodiscard]] FRAMELESSHELPER_CORE_API
Qt::CursorShape calculateCursorShape(const QWindow *window, const QPoint &pos);
[[nodiscard]] FRAMELESSHELPER_CORE_API
Qt::Edges calculateWindowEdges(const QWindow *window, const QPoint &pos);
FRAMELESSHELPER_CORE_API void startSystemMove(QWindow *window, const QPoint &globalPos);
FRAMELESSHELPER_CORE_API void startSystemResize(QWindow *window, const Qt::Edges edges, const QPoint &globalPos);
[[nodiscard]] FRAMELESSHELPER_CORE_API QString getSystemButtonIconCode(const Global::SystemButtonType button);

View File

@ -50,7 +50,7 @@ class FRAMELESSHELPER_QUICK_API FramelessQuickHelper : public QQuickItem
Q_PROPERTY(bool windowFixedSize READ isWindowFixedSize WRITE setWindowFixedSize NOTIFY windowFixedSizeChanged FINAL)
Q_PROPERTY(bool blurBehindWindowEnabled READ isBlurBehindWindowEnabled WRITE setBlurBehindWindowEnabled NOTIFY blurBehindWindowEnabledChanged FINAL)
Q_PROPERTY(QQuickWindow* window READ window NOTIFY windowChanged2 FINAL)
Q_PROPERTY(bool attached READ isAttached NOTIFY attachedChanged FINAL)
Q_PROPERTY(bool extendsContentIntoTitleBar READ isContentExtendedIntoTitleBar WRITE setContentExtendedIntoTitleBar NOTIFY extendsContentIntoTitleBarChanged FINAL)
public:
explicit FramelessQuickHelper(QQuickItem *parent = nullptr);
@ -62,10 +62,11 @@ public:
Q_NODISCARD QQuickItem *titleBarItem() const;
Q_NODISCARD bool isWindowFixedSize() const;
Q_NODISCARD bool isBlurBehindWindowEnabled() const;
Q_NODISCARD bool isAttached() const;
Q_NODISCARD bool isContentExtendedIntoTitleBar() const;
public Q_SLOTS:
void extendsContentIntoTitleBar();
[[deprecated("Use the extendsContentIntoTitleBar property instead.")]] void extendsContentIntoTitleBar();
void setContentExtendedIntoTitleBar(const bool value);
void setTitleBarItem(QQuickItem *value);
void setSystemButton(QQuickItem *item, const QuickGlobal::SystemButtonType buttonType);
@ -85,11 +86,11 @@ protected:
void itemChange(const ItemChange change, const ItemChangeData &value) override;
Q_SIGNALS:
void extendsContentIntoTitleBarChanged();
void titleBarItemChanged();
void windowFixedSizeChanged();
void blurBehindWindowEnabledChanged();
void windowChanged2();
void attachedChanged();
void ready();
private:

View File

@ -50,10 +50,14 @@ public:
Q_NODISCARD static FramelessQuickHelperPrivate *get(FramelessQuickHelper *pub);
Q_NODISCARD static const FramelessQuickHelperPrivate *get(const FramelessQuickHelper *pub);
Q_NODISCARD bool isContentExtendedIntoTitleBar() const;
void setContentExtendedIntoTitleBar(const bool value);
Q_NODISCARD QQuickItem *getTitleBarItem() const;
void setTitleBarItem(QQuickItem *value);
void attachToWindow();
void attach();
void detach();
void setSystemButton(QQuickItem *item, const QuickGlobal::SystemButtonType buttonType);
void setHitTestVisible(QQuickItem *item, const bool visible = true);
void setHitTestVisible(const QRect &rect, const bool visible = true);
@ -75,8 +79,6 @@ public:
void setProperty(const QByteArray &name, const QVariant &value);
Q_NODISCARD QVariant getProperty(const QByteArray &name, const QVariant &defaultValue = {});
Q_NODISCARD bool isAttached() const;
protected:
Q_NODISCARD bool eventFilter(QObject *object, QEvent *event) override;

View File

@ -44,7 +44,7 @@ class FRAMELESSHELPER_WIDGETS_API FramelessWidgetsHelper : public QObject
Q_PROPERTY(bool windowFixedSize READ isWindowFixedSize WRITE setWindowFixedSize NOTIFY windowFixedSizeChanged FINAL)
Q_PROPERTY(bool blurBehindWindowEnabled READ isBlurBehindWindowEnabled WRITE setBlurBehindWindowEnabled NOTIFY blurBehindWindowEnabledChanged FINAL)
Q_PROPERTY(QWidget* window READ window NOTIFY windowChanged FINAL)
Q_PROPERTY(bool attached READ isAttached NOTIFY attachedChanged FINAL)
Q_PROPERTY(bool extendsContentIntoTitleBar READ isContentExtendedIntoTitleBar WRITE setContentExtendedIntoTitleBar NOTIFY extendsContentIntoTitleBarChanged FINAL)
public:
explicit FramelessWidgetsHelper(QObject *parent = nullptr);
@ -56,10 +56,11 @@ public:
Q_NODISCARD bool isWindowFixedSize() const;
Q_NODISCARD bool isBlurBehindWindowEnabled() const;
Q_NODISCARD QWidget *window() const;
Q_NODISCARD bool isAttached() const;
Q_NODISCARD bool isContentExtendedIntoTitleBar() const;
public Q_SLOTS:
void extendsContentIntoTitleBar();
[[deprecated("Use the extendsContentIntoTitleBar property instead.")]] void extendsContentIntoTitleBar();
void setContentExtendedIntoTitleBar(const bool value);
void setTitleBarWidget(QWidget *widget);
void setSystemButton(QWidget *widget, const Global::SystemButtonType buttonType);
@ -76,11 +77,11 @@ public Q_SLOTS:
void setBlurBehindWindowEnabled(const bool value);
Q_SIGNALS:
void extendsContentIntoTitleBarChanged();
void titleBarWidgetChanged();
void windowFixedSizeChanged();
void blurBehindWindowEnabledChanged();
void windowChanged();
void attachedChanged();
void ready();
private:

View File

@ -46,10 +46,14 @@ public:
Q_NODISCARD static FramelessWidgetsHelperPrivate *get(FramelessWidgetsHelper *pub);
Q_NODISCARD static const FramelessWidgetsHelperPrivate *get(const FramelessWidgetsHelper *pub);
Q_NODISCARD bool isContentExtendedIntoTitleBar() const;
void setContentExtendedIntoTitleBar(const bool value);
Q_NODISCARD QWidget *getTitleBarWidget() const;
void setTitleBarWidget(QWidget *widget);
void attachToWindow();
void attach();
void detach();
void setSystemButton(QWidget *widget, const Global::SystemButtonType buttonType);
void setHitTestVisible(QWidget *widget, const bool visible = true);
void setHitTestVisible(const QRect &rect, const bool visible = true);
@ -72,7 +76,6 @@ public:
Q_NODISCARD QVariant getProperty(const QByteArray &name, const QVariant &defaultValue = {});
Q_NODISCARD QWidget *window() const;
Q_NODISCARD bool isAttached() const;
private:
Q_NODISCARD QRect mapWidgetGeometryToScene(const QWidget * const widget) const;

View File

@ -106,6 +106,24 @@ void FramelessHelperQt::addWindow(const SystemParameters &params)
FramelessHelper::Core::setApplicationOSThemeAware();
}
void FramelessHelperQt::removeWindow(const WId windowId)
{
Q_ASSERT(windowId);
if (!windowId) {
return;
}
const QMutexLocker locker(&g_qtHelper()->mutex);
if (!g_qtHelper()->data.contains(windowId)) {
return;
}
const QtHelperData data = g_qtHelper()->data.value(windowId);
g_qtHelper()->data.remove(windowId);
if (QWindow * const window = Utils::findWindow(windowId)) {
window->removeEventFilter(data.eventFilter);
}
delete data.eventFilter;
}
bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
{
Q_ASSERT(object);

View File

@ -552,6 +552,41 @@ void FramelessHelperWin::addWindow(const SystemParameters &params)
}
}
void FramelessHelperWin::removeWindow(const WId windowId)
{
Q_ASSERT(windowId);
if (!windowId) {
return;
}
g_win32Helper()->mutex.lock();
if (!g_win32Helper()->data.contains(windowId)) {
g_win32Helper()->mutex.unlock();
return;
}
g_win32Helper()->data.remove(windowId);
if (g_win32Helper()->data.isEmpty()) {
if (!g_win32Helper()->nativeEventFilter.isNull()) {
qApp->removeNativeEventFilter(g_win32Helper()->nativeEventFilter.data());
g_win32Helper()->nativeEventFilter.reset();
}
}
HWND hwnd = nullptr;
auto it = g_win32Helper()->fallbackTitleBarToParentWindowMapping.constBegin();
while (it != g_win32Helper()->fallbackTitleBarToParentWindowMapping.constEnd()) {
if (it.value() == windowId) {
const WId key = it.key();
hwnd = reinterpret_cast<HWND>(key);
g_win32Helper()->fallbackTitleBarToParentWindowMapping.remove(key);
break;
}
++it;
}
g_win32Helper()->mutex.unlock();
if (DestroyWindow(reinterpret_cast<HWND>(hwnd)) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kDestroyWindow);
}
}
bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result)
{
if ((eventType != kWin32MessageTypeName) || !message || !result) {

View File

@ -54,10 +54,15 @@ Q_LOGGING_CATEGORY(lcFramelessManager, "wangwenx190.framelesshelper.core.framele
using namespace Global;
struct FramelessManagerHelperData
{
QMetaObject::Connection screenChangeConnection = {};
};
struct FramelessManagerHelper
{
QMutex mutex;
QList<WId> windowIds = {};
QHash<WId, FramelessManagerHelperData> data = {};
};
Q_GLOBAL_STATIC(FramelessManagerHelper, g_helper)
@ -182,24 +187,22 @@ void FramelessManagerPrivate::addWindow(const SystemParameters &params)
}
const WId windowId = params.getWindowId();
g_helper()->mutex.lock();
if (g_helper()->windowIds.contains(windowId)) {
if (g_helper()->data.contains(windowId)) {
g_helper()->mutex.unlock();
return;
}
g_helper()->windowIds.append(windowId);
g_helper()->data.insert(windowId, {});
g_helper()->mutex.unlock();
static const bool pureQt = []() -> bool {
#ifdef Q_OS_WINDOWS
return FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation);
#else
return true;
#endif
}();
QMetaObject::Connection screenChangeConnection = {};
static const bool pureQt = usePureQtImplementation();
#ifdef Q_OS_WINDOWS
if (!pureQt) {
// Work-around Win32 multi-monitor artifacts.
QWindow * const window = params.getWindowHandle();
Q_ASSERT(window);
if (window) {
g_helper()->mutex.lock();
g_helper()->data[windowId].screenChangeConnection =
connect(window, &QWindow::screenChanged, window, [windowId, window](QScreen *screen){
Q_UNUSED(screen);
// Force a WM_NCCALCSIZE event to inform Windows about our custom window frame,
@ -211,6 +214,8 @@ void FramelessManagerPrivate::addWindow(const SystemParameters &params)
// observed disappeared indeed, amazingly.
window->resize(window->size());
});
g_helper()->mutex.unlock();
}
}
#endif
if (pureQt) {
@ -225,6 +230,37 @@ void FramelessManagerPrivate::addWindow(const SystemParameters &params)
#endif
}
void FramelessManagerPrivate::removeWindow(const WId windowId)
{
Q_ASSERT(windowId);
if (!windowId) {
return;
}
g_helper()->mutex.lock();
if (!g_helper()->data.contains(windowId)) {
g_helper()->mutex.unlock();
return;
}
const FramelessManagerHelperData data = g_helper()->data.value(windowId);
g_helper()->data.remove(windowId);
g_helper()->mutex.unlock();
static const bool pureQt = usePureQtImplementation();
#ifdef Q_OS_WINDOWS
if (!pureQt && data.screenChangeConnection) {
disconnect(data.screenChangeConnection);
}
#endif
if (pureQt) {
FramelessHelperQt::removeWindow(windowId);
}
#ifdef Q_OS_WINDOWS
if (!pureQt) {
FramelessHelperWin::removeWindow(windowId);
}
Utils::uninstallSystemMenuHook(windowId);
#endif
}
void FramelessManagerPrivate::notifySystemThemeHasChangedOrNot()
{
const QMutexLocker locker(&g_helper()->mutex);
@ -282,6 +318,18 @@ void FramelessManagerPrivate::notifyWallpaperHasChangedOrNot()
}
}
bool FramelessManagerPrivate::usePureQtImplementation()
{
static const bool result = []() -> bool {
#ifdef Q_OS_WINDOWS
return FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation);
#else
return true;
#endif
}();
return result;
}
void FramelessManagerPrivate::initialize()
{
const QMutexLocker locker(&g_helper()->mutex);
@ -342,4 +390,10 @@ void FramelessManager::addWindow(const SystemParameters &params)
d->addWindow(params);
}
void FramelessManager::removeWindow(const WId windowId)
{
Q_D(FramelessManager);
d->removeWindow(windowId);
}
FRAMELESSHELPER_END_NAMESPACE

View File

@ -1154,30 +1154,32 @@ void Utils::fixupQtInternals(const WId windowId)
if (qEnvironmentVariableIntValue(kNoFixQtInternalEnvVar)) {
return;
}
bool shouldUpdateFrame = false;
const auto hwnd = reinterpret_cast<HWND>(windowId);
SetLastError(ERROR_SUCCESS);
const auto oldClassStyle = static_cast<DWORD>(GetClassLongPtrW(hwnd, GCL_STYLE));
if (oldClassStyle == 0) {
WARNING << getSystemErrorMessage(kGetClassLongPtrW);
return;
}
const auto classStyle = static_cast<DWORD>(GetClassLongPtrW(hwnd, GCL_STYLE));
if (classStyle != 0) {
// CS_HREDRAW/CS_VREDRAW will trigger a repaint event when the window size changes
// horizontally/vertically, which will cause flicker and jitter during window
// resizing, mostly for the applications which do all the painting by themselves.
// So we remove these flags from the window class here, Qt by default won't add them
// but let's make it extra safe.
const DWORD newClassStyle = (oldClassStyle & ~(CS_HREDRAW | CS_VREDRAW));
// horizontally/vertically, which will cause flicker and jitter during window resizing,
// mostly for the applications which do all the painting by themselves (eg: Qt).
// So we remove these flags from the window class here. Qt by default won't add them
// but let's make it extra safe in case the user may add them by accident.
static constexpr const DWORD badClassStyle = (CS_HREDRAW | CS_VREDRAW);
if (classStyle & badClassStyle) {
SetLastError(ERROR_SUCCESS);
if (SetClassLongPtrW(hwnd, GCL_STYLE, static_cast<LONG_PTR>(newClassStyle)) == 0) {
if (SetClassLongPtrW(hwnd, GCL_STYLE,
static_cast<LONG_PTR>(classStyle & ~badClassStyle)) == 0) {
WARNING << getSystemErrorMessage(kSetClassLongPtrW);
return;
} else {
shouldUpdateFrame = true;
}
}
} else {
WARNING << getSystemErrorMessage(kGetClassLongPtrW);
}
SetLastError(ERROR_SUCCESS);
const auto oldWindowStyle = static_cast<DWORD>(GetWindowLongPtrW(hwnd, GWL_STYLE));
if (oldWindowStyle == 0) {
WARNING << getSystemErrorMessage(kGetWindowLongPtrW);
return;
}
const auto windowStyle = static_cast<DWORD>(GetWindowLongPtrW(hwnd, GWL_STYLE));
if (windowStyle != 0) {
// Qt by default adds the "WS_POPUP" flag to all Win32 windows it created and maintained,
// which is not a good thing (although it won't cause any obvious issues in most cases
// either), because popup windows have some different behavior with normal overlapped
@ -1185,16 +1187,24 @@ void Utils::fixupQtInternals(const WId windowId)
// necessary window styles in some cases (caused by misconfigured setWindowFlag(s) calls)
// and this will also break the normal functionalities for our windows, so we do the
// correction here unconditionally.
static constexpr const DWORD normalWindowStyle =
static constexpr const DWORD goodWindowStyle =
(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME);
const DWORD newWindowStyle = ((oldWindowStyle & ~WS_POPUP) | normalWindowStyle);
if (!(windowStyle & goodWindowStyle)) {
SetLastError(ERROR_SUCCESS);
if (SetWindowLongPtrW(hwnd, GWL_STYLE, static_cast<LONG_PTR>(newWindowStyle)) == 0) {
if (SetWindowLongPtrW(hwnd, GWL_STYLE,
static_cast<LONG_PTR>((windowStyle & ~WS_POPUP) | goodWindowStyle)) == 0) {
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
return;
} else {
shouldUpdateFrame = true;
}
}
} else {
WARNING << getSystemErrorMessage(kGetWindowLongPtrW);
}
if (shouldUpdateFrame) {
triggerFrameChange(windowId);
}
}
void Utils::startSystemMove(QWindow *window, const QPoint &globalPos)
{

View File

@ -52,7 +52,7 @@ using namespace Global;
struct QuickHelperData
{
bool attached = false;
bool ready = false;
SystemParameters params = {};
QPointer<QQuickItem> titleBarItem = nullptr;
QList<QPointer<QQuickItem>> hitTestVisibleItems = {};
@ -97,11 +97,14 @@ FramelessQuickHelperPrivate::FramelessQuickHelperPrivate(FramelessQuickHelper *q
return;
}
q_ptr = q;
// Workaround a moc limitation.
// Workaround a MOC limitation: we can't emit a signal from the parent class.
connect(q_ptr, &FramelessQuickHelper::windowChanged, q_ptr, &FramelessQuickHelper::windowChanged2);
}
FramelessQuickHelperPrivate::~FramelessQuickHelperPrivate() = default;
FramelessQuickHelperPrivate::~FramelessQuickHelperPrivate()
{
detach();
}
FramelessQuickHelperPrivate *FramelessQuickHelperPrivate::get(FramelessQuickHelper *pub)
{
@ -121,6 +124,24 @@ const FramelessQuickHelperPrivate *FramelessQuickHelperPrivate::get(const Framel
return pub->d_func();
}
bool FramelessQuickHelperPrivate::isContentExtendedIntoTitleBar() const
{
return getWindowData().ready;
}
void FramelessQuickHelperPrivate::setContentExtendedIntoTitleBar(const bool value)
{
if (isContentExtendedIntoTitleBar() == value) {
return;
}
if (value) {
attach();
} else {
detach();
}
emitSignalForAllInstances(FRAMELESSHELPER_BYTEARRAY_LITERAL("extendsContentIntoTitleBarChanged"));
}
QQuickItem *FramelessQuickHelperPrivate::getTitleBarItem() const
{
return getWindowData().titleBarItem;
@ -144,7 +165,7 @@ void FramelessQuickHelperPrivate::setTitleBarItem(QQuickItem *value)
emitSignalForAllInstances(FRAMELESSHELPER_BYTEARRAY_LITERAL("titleBarItemChanged"));
}
void FramelessQuickHelperPrivate::attachToWindow()
void FramelessQuickHelperPrivate::attach()
{
Q_Q(FramelessQuickHelper);
QQuickWindow * const window = q->window();
@ -154,18 +175,13 @@ void FramelessQuickHelperPrivate::attachToWindow()
}
g_quickHelper()->mutex.lock();
QuickHelperData *data = getWindowDataMutable();
if (!data) {
QuickHelperData * const data = getWindowDataMutable();
if (!data || data->ready) {
g_quickHelper()->mutex.unlock();
return;
}
const bool attached = data->attached;
g_quickHelper()->mutex.unlock();
if (attached) {
return;
}
window->installEventFilter(this);
SystemParameters params = {};
@ -208,7 +224,7 @@ void FramelessQuickHelperPrivate::attachToWindow()
g_quickHelper()->mutex.lock();
data->params = params;
data->attached = true;
data->ready = true;
g_quickHelper()->mutex.unlock();
// We have to wait for a little time before moving the top level window
@ -223,11 +239,27 @@ void FramelessQuickHelperPrivate::attachToWindow()
if (FramelessConfig::instance()->isSet(Option::EnableBlurBehindWindow)) {
setBlurBehindWindowEnabled(true, {});
}
emitSignalForAllInstances(FRAMELESSHELPER_BYTEARRAY_LITERAL("attachedChanged"));
emitSignalForAllInstances(FRAMELESSHELPER_BYTEARRAY_LITERAL("ready"));
});
}
void FramelessQuickHelperPrivate::detach()
{
Q_Q(FramelessQuickHelper);
QQuickWindow * const w = q->window();
if (!w) {
return;
}
const WId windowId = w->winId();
const QMutexLocker locker(&g_quickHelper()->mutex);
if (!g_quickHelper()->data.contains(windowId)) {
return;
}
g_quickHelper()->data.remove(windowId);
w->removeEventFilter(this);
FramelessManager::instance()->removeWindow(windowId);
}
void FramelessQuickHelperPrivate::setSystemButton(QQuickItem *item, const QuickGlobal::SystemButtonType buttonType)
{
Q_ASSERT(item);
@ -512,12 +544,6 @@ QVariant FramelessQuickHelperPrivate::getProperty(const QByteArray &name, const
return (value.isValid() ? value : defaultValue);
}
bool FramelessQuickHelperPrivate::isAttached() const
{
const QMutexLocker locker(&g_quickHelper()->mutex);
return getWindowData().attached;
}
bool FramelessQuickHelperPrivate::eventFilter(QObject *object, QEvent *event)
{
Q_ASSERT(object);
@ -838,7 +864,7 @@ FramelessQuickHelper *FramelessQuickHelper::get(QObject *object)
instance->setParentItem(parentItem);
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();
//instance->d_func()->attach();
}
return instance;
}
@ -870,15 +896,21 @@ bool FramelessQuickHelper::isBlurBehindWindowEnabled() const
return d->isBlurBehindWindowEnabled();
}
bool FramelessQuickHelper::isAttached() const
bool FramelessQuickHelper::isContentExtendedIntoTitleBar() const
{
Q_D(const FramelessQuickHelper);
return d->isAttached();
return d->isContentExtendedIntoTitleBar();
}
void FramelessQuickHelper::extendsContentIntoTitleBar()
{
// Intentionally not doing anything here.
setContentExtendedIntoTitleBar(true);
}
void FramelessQuickHelper::setContentExtendedIntoTitleBar(const bool value)
{
Q_D(FramelessQuickHelper);
d->setContentExtendedIntoTitleBar(value);
}
void FramelessQuickHelper::setTitleBarItem(QQuickItem *value)
@ -988,7 +1020,7 @@ void FramelessQuickHelper::itemChange(const ItemChange change, const ItemChangeD
}
}
Q_D(FramelessQuickHelper);
d->attachToWindow();
d->attach();
}
}

View File

@ -162,7 +162,7 @@ void FramelessQuickWindowPrivate::initialize()
{
Q_Q(FramelessQuickWindow);
QQuickItem * const rootItem = q->contentItem();
FramelessQuickHelper::get(rootItem)->extendsContentIntoTitleBar();
FramelessQuickHelper::get(rootItem)->setContentExtendedIntoTitleBar(true);
m_topBorderRectangle.reset(new QQuickRectangle(rootItem));
m_topBorderRectangle->setZ(999); // Make sure the frame border stays on top of eveything.
m_topBorderRectangle->setColor(kDefaultTransparentColor);

View File

@ -71,7 +71,7 @@ const FramelessDialogPrivate *FramelessDialogPrivate::get(const FramelessDialog
void FramelessDialogPrivate::initialize()
{
Q_Q(FramelessDialog);
FramelessWidgetsHelper::get(q)->extendsContentIntoTitleBar();
FramelessWidgetsHelper::get(q)->setContentExtendedIntoTitleBar(true);
m_helper.reset(new WidgetsSharedHelper(this));
m_helper->setup(q);
}

View File

@ -71,7 +71,7 @@ const FramelessMainWindowPrivate *FramelessMainWindowPrivate::get(const Frameles
void FramelessMainWindowPrivate::initialize()
{
Q_Q(FramelessMainWindow);
FramelessWidgetsHelper::get(q)->extendsContentIntoTitleBar();
FramelessWidgetsHelper::get(q)->setContentExtendedIntoTitleBar(true);
m_helper.reset(new WidgetsSharedHelper(this));
m_helper->setup(q);
}

View File

@ -71,7 +71,7 @@ const FramelessWidgetPrivate *FramelessWidgetPrivate::get(const FramelessWidget
void FramelessWidgetPrivate::initialize()
{
Q_Q(FramelessWidget);
FramelessWidgetsHelper::get(q)->extendsContentIntoTitleBar();
FramelessWidgetsHelper::get(q)->setContentExtendedIntoTitleBar(true);
m_helper.reset(new WidgetsSharedHelper(this));
m_helper->setup(q);
}

View File

@ -54,7 +54,7 @@ using namespace Global;
struct WidgetsHelperData
{
bool attached = false;
bool ready = false;
SystemParameters params = {};
QPointer<QWidget> titleBarWidget = nullptr;
QList<QPointer<QWidget>> hitTestVisibleWidgets = {};
@ -107,7 +107,10 @@ FramelessWidgetsHelperPrivate::FramelessWidgetsHelperPrivate(FramelessWidgetsHel
q_ptr = q;
}
FramelessWidgetsHelperPrivate::~FramelessWidgetsHelperPrivate() = default;
FramelessWidgetsHelperPrivate::~FramelessWidgetsHelperPrivate()
{
detach();
}
FramelessWidgetsHelperPrivate *FramelessWidgetsHelperPrivate::get(FramelessWidgetsHelper *pub)
{
@ -264,10 +267,9 @@ QWidget *FramelessWidgetsHelperPrivate::window() const
return m_window;
}
bool FramelessWidgetsHelperPrivate::isAttached() const
bool FramelessWidgetsHelperPrivate::isContentExtendedIntoTitleBar() const
{
const QMutexLocker locker(&g_widgetsHelper()->mutex);
return getWindowData().attached;
return getWindowData().ready;
}
void FramelessWidgetsHelperPrivate::setTitleBarWidget(QWidget *widget)
@ -333,7 +335,7 @@ void FramelessWidgetsHelperPrivate::setHitTestVisible(const QRect &rect, const b
}
}
void FramelessWidgetsHelperPrivate::attachToWindow()
void FramelessWidgetsHelperPrivate::attach()
{
QWidget * const window = findTopLevelWindow();
Q_ASSERT(window);
@ -346,18 +348,13 @@ void FramelessWidgetsHelperPrivate::attachToWindow()
m_window = window;
g_widgetsHelper()->mutex.lock();
WidgetsHelperData *data = getWindowDataMutable();
if (!data) {
WidgetsHelperData * const data = getWindowDataMutable();
if (!data || data->ready) {
g_widgetsHelper()->mutex.unlock();
return;
}
const bool attached = data->attached;
g_widgetsHelper()->mutex.unlock();
if (attached) {
return;
}
// Without this flag, Qt will always create an invisible native parent window
// for any native widgets which will intercept some win32 messages and confuse
// our own native event filter, so to prevent some weired bugs from happening,
@ -405,7 +402,7 @@ void FramelessWidgetsHelperPrivate::attachToWindow()
g_widgetsHelper()->mutex.lock();
data->params = params;
data->attached = true;
data->ready = true;
g_widgetsHelper()->mutex.unlock();
// We have to wait for a little time before moving the top level window
@ -421,11 +418,39 @@ void FramelessWidgetsHelperPrivate::attachToWindow()
setBlurBehindWindowEnabled(true, {});
}
emitSignalForAllInstances(FRAMELESSHELPER_BYTEARRAY_LITERAL("windowChanged"));
emitSignalForAllInstances(FRAMELESSHELPER_BYTEARRAY_LITERAL("attachedChanged"));
emitSignalForAllInstances(FRAMELESSHELPER_BYTEARRAY_LITERAL("ready"));
});
}
void FramelessWidgetsHelperPrivate::detach()
{
if (!m_window) {
return;
}
const WId windowId = m_window->winId();
const QMutexLocker locker(&g_widgetsHelper()->mutex);
if (!g_widgetsHelper()->data.contains(windowId)) {
return;
}
g_widgetsHelper()->data.remove(windowId);
FramelessManager::instance()->removeWindow(windowId);
m_window = nullptr;
emitSignalForAllInstances(FRAMELESSHELPER_BYTEARRAY_LITERAL("windowChanged"));
}
void FramelessWidgetsHelperPrivate::setContentExtendedIntoTitleBar(const bool value)
{
if (isContentExtendedIntoTitleBar() == value) {
return;
}
if (value) {
attach();
} else {
detach();
}
emitSignalForAllInstances(FRAMELESSHELPER_BYTEARRAY_LITERAL("extendsContentIntoTitleBarChanged"));
}
QWidget *FramelessWidgetsHelperPrivate::findTopLevelWindow() const
{
Q_Q(const FramelessWidgetsHelper);
@ -796,7 +821,7 @@ FramelessWidgetsHelper *FramelessWidgetsHelper::get(QObject *object)
FramelessWidgetsHelper *instance = parent->findChild<FramelessWidgetsHelper *>();
if (!instance) {
instance = new FramelessWidgetsHelper(parent);
instance->d_func()->attachToWindow();
instance->d_func()->attach();
}
return instance;
}
@ -825,15 +850,21 @@ QWidget *FramelessWidgetsHelper::window() const
return d->window();
}
bool FramelessWidgetsHelper::isAttached() const
bool FramelessWidgetsHelper::isContentExtendedIntoTitleBar() const
{
Q_D(const FramelessWidgetsHelper);
return d->isAttached();
return d->isContentExtendedIntoTitleBar();
}
void FramelessWidgetsHelper::extendsContentIntoTitleBar()
{
// Intentionally not doing anything here.
setContentExtendedIntoTitleBar(true);
}
void FramelessWidgetsHelper::setContentExtendedIntoTitleBar(const bool value)
{
Q_D(FramelessWidgetsHelper);
d->setContentExtendedIntoTitleBar(value);
}
void FramelessWidgetsHelper::setTitleBarWidget(QWidget *widget)