fix(@desktop/general): Changing System Appearance on the fly is not working

This is corresponding dotherside part of the issue 1725.

So far we had kind of a memory leak, cause objects added to the filter were not
deleted ever. When the app is closing, it just removes filters, but doesn't
delete them.

I faced a logical issue, that we were sending qmlengine pointer to the
installEventFilter method, instead object which may or may not rely on the
qqmlengine instance, that is fixed also.

Fixes: #1725
This commit is contained in:
Sale Djenic 2021-08-12 13:31:02 +02:00 committed by Michał
parent cba2e276b2
commit f0e3f04994
10 changed files with 166 additions and 67 deletions

View File

@ -20,7 +20,8 @@ macro(add_target name type)
include/DOtherSide/DosIQAbstractItemModelImpl.h
include/DOtherSide/DosQAbstractItemModel.h
include/DOtherSide/Utils.h
include/DOtherSide/DosDockClicker.h
include/DOtherSide/StatusEvents/StatusDockShowAppEvent.h
include/DOtherSide/StatusEvents/StatusOSThemeEvent.h
include/DOtherSide/DOtherSideStatusWindow.h
include/DOtherSide/DOtherSideSingleInstance.h
src/DOtherSide.cpp
@ -31,7 +32,8 @@ macro(add_target name type)
src/DosQObjectImpl.cpp
src/DosQAbstractItemModel.cpp
src/DosQQuickImageProvider.cpp
src/DosDockClicker.cpp
src/StatusEvents/StatusDockShowAppEvent.cpp
src/StatusEvents/StatusOSThemeEvent.cpp
src/DOtherSideStatusWindow.cpp
src/DOtherSideSingleInstance.cpp
)

View File

@ -82,11 +82,11 @@ DOS_API void DOS_CALL dos_qguiapplication_delete(void);
DOS_API void DOS_CALL dos_qguiapplication_icon(const char *filename);
DOS_API void dos_qguiapplication_installEventFilter(DosQQmlApplicationEngine *vptr);
DOS_API void dos_qguiapplication_installEventFilter(DosStatusEventObject *vptr);
DOS_API void dos_qapplication_clipboard_setText(const char* text);
DOS_API void dos_qapplication_installEventFilter(DosQQmlApplicationEngine *vptr);
DOS_API void dos_qapplication_installEventFilter(DosStatusEventObject *vptr);
/// @}
@ -993,6 +993,11 @@ DOS_API void DOS_CALL dos_singleinstance_delete(DosSingleInstance *vptr);
/// @}
/// Status event object
DOS_API DosStatusEventObject* dos_statusevent_create_showAppEvent(DosQQmlApplicationEngine* vptr);
DOS_API DosStatusEventObject* dos_statusevent_create_osThemeEvent(DosQQmlApplicationEngine* vptr);
DOS_API void dos_statusevent_delete(DosStatusEventObject* vptr);
#ifdef __cplusplus
}
#endif

View File

@ -98,6 +98,9 @@ typedef void DosPixmap;
/// A pointer to SingleInstance
typedef void DosSingleInstance;
/// A pointer to a status event object which is actualy a QObject
typedef void DosStatusEventObject;
/// A pixmap callback to be supplied to an image provider
/// \param id Image source id
/// \param width pointer to the width of the image

View File

@ -1,27 +0,0 @@
#ifndef DOCKCLICKER_H
#define DOCKCLICKER_H
#include <QObject>
#include <QQmlApplicationEngine>
#include "DOtherSideTypes.h"
class DockClicker : public QObject
{
Q_OBJECT
private:
Qt::ApplicationState _prevAppState;
QQmlApplicationEngine* _engine;
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
public:
DockClicker(DosQQmlApplicationEngine *vptr) {
auto engine = static_cast<QQmlApplicationEngine *>(vptr);
_engine = engine;
}
};
#endif // DOCKCLICKER_H

View File

@ -0,0 +1,24 @@
#ifndef STATUS_DOCK_SHOW_APP_EVENT_H
#define STATUS_DOCK_SHOW_APP_EVENT_H
#include "../DOtherSideTypes.h"
#include <QObject>
#include <QQmlApplicationEngine>
class StatusDockShowAppEvent : public QObject
{
Q_OBJECT
public:
StatusDockShowAppEvent(DosQQmlApplicationEngine* vptr, QObject* parent = nullptr);
protected:
bool eventFilter(QObject* obj, QEvent* event) override;
private:
Qt::ApplicationState m_prevAppState;
QQmlApplicationEngine* m_engine;
};
#endif

View File

@ -0,0 +1,23 @@
#ifndef STATUS_OS_THEME_EVENT_H
#define STATUS_OS_THEME_EVENT_H
#include "../DOtherSideTypes.h"
#include <QObject>
#include <QQmlApplicationEngine>
class StatusOSThemeEvent : public QObject
{
Q_OBJECT
public:
StatusOSThemeEvent(DosQQmlApplicationEngine* vptr, QObject* parent = nullptr);
protected:
bool eventFilter(QObject* obj, QEvent* event) override;
private:
QQmlApplicationEngine* m_engine;
};
#endif

View File

@ -57,10 +57,12 @@
#include "DOtherSide/DosQAbstractItemModel.h"
#include "DOtherSide/DosQDeclarative.h"
#include "DOtherSide/DosQQuickImageProvider.h"
#include "DOtherSide/DosDockClicker.h"
#include "DOtherSide/DOtherSideStatusWindow.h"
#include "DOtherSide/DOtherSideSingleInstance.h"
#include "DOtherSide/StatusEvents/StatusDockShowAppEvent.h"
#include "DOtherSide/StatusEvents/StatusOSThemeEvent.h"
namespace {
void register_meta_types()
@ -155,7 +157,8 @@ void dos_qguiapplication_exec()
void dos_qguiapplication_quit()
{
qGuiApp->quit();
// This way we will be safe for quitting the app (avoid potential crashes).
QMetaObject::invokeMethod(qGuiApp, "quit", Qt::QueuedConnection);
}
void dos_qguiapplication_icon(const char *filename)
@ -163,10 +166,10 @@ void dos_qguiapplication_icon(const char *filename)
qGuiApp->setWindowIcon(QIcon(filename));
}
void dos_qguiapplication_installEventFilter(::DosQQmlApplicationEngine *vptr)
void dos_qguiapplication_installEventFilter(::DosStatusEventObject* vptr)
{
DockClicker *dockClicker = new DockClicker(vptr);
qGuiApp->installEventFilter(dockClicker);
auto qobject = static_cast<QObject*>(vptr);
qGuiApp->installEventFilter(qobject);
}
void dos_qapplication_create()
@ -196,13 +199,14 @@ void dos_qapplication_icon(const char *filename)
void dos_qapplication_quit()
{
qApp->quit();
// This way we will be safe for quitting the app (avoid potential crashes).
QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection);
}
void dos_qapplication_installEventFilter(::DosQQmlApplicationEngine *vptr)
void dos_qapplication_installEventFilter(::DosStatusEventObject* vptr)
{
DockClicker *dockClicker = new DockClicker(vptr);
qApp->installEventFilter(dockClicker);
auto qobject = static_cast<QObject*>(vptr);
qApp->installEventFilter(qobject);
}
::DosQQmlApplicationEngine *dos_qqmlapplicationengine_create()
@ -1313,3 +1317,21 @@ bool dos_singleinstance_isfirst(DosSingleInstance *vptr)
}
return false;
}
::DosStatusEventObject* dos_statusevent_create_showAppEvent(::DosQQmlApplicationEngine* vptr)
{
auto engine = static_cast<QQmlApplicationEngine*>(vptr);
return new StatusDockShowAppEvent(engine);
}
::DosStatusEventObject* dos_statusevent_create_osThemeEvent(::DosQQmlApplicationEngine* vptr)
{
auto engine = static_cast<QQmlApplicationEngine*>(vptr);
return new StatusOSThemeEvent(engine);
}
void dos_statusevent_delete(DosStatusEventObject* vptr)
{
auto qobject = static_cast<QObject*>(vptr);
qobject->deleteLater();
}

View File

@ -1,27 +0,0 @@
#include "DOtherSide/DosDockClicker.h"
#include <QQuickWindow>
#include <QCoreApplication>
bool DockClicker::eventFilter(QObject *obj, QEvent *event)
{
#ifdef Q_OS_MACOS
if (obj == qApp) {
if (event->type() == QEvent::ApplicationStateChange) {
auto ev = static_cast<QApplicationStateChangeEvent*>(event);
if (_prevAppState == Qt::ApplicationActive && ev->applicationState() == Qt::ApplicationActive) {
QObject *topLevel = _engine->rootObjects().value(0);
QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
window->setVisible(true);
window->showNormal();
}
_prevAppState = ev->applicationState();
return true;
} else {
return false;
}
}
#endif // Q_OS_MACOS
return QObject::eventFilter(obj, event);
}

View File

@ -0,0 +1,45 @@
#include "DOtherSide/StatusEvents/StatusDockShowAppEvent.h"
#include <QQuickWindow>
/*
Code here is exactly the same as it was before, logic is not changed. I only
put it in another form, nothing else. To match an improved flow for
installing filters.
*/
StatusDockShowAppEvent::StatusDockShowAppEvent(DosQQmlApplicationEngine* vptr,
QObject* parent)
: QObject(parent)
{
m_engine = static_cast<QQmlApplicationEngine*>(vptr);
}
bool StatusDockShowAppEvent::eventFilter(QObject* obj, QEvent* event)
{
#ifdef Q_OS_MACOS
if (event->type() == QEvent::ApplicationStateChange)
{
auto ev = static_cast<QApplicationStateChangeEvent*>(event);
if (m_prevAppState == Qt::ApplicationActive
&& ev->applicationState() == Qt::ApplicationActive)
{
QObject* topLevelObj = m_engine->rootObjects().value(0);
if(topLevelObj && topLevelObj->objectName() == "mainWindow")
{
QQuickWindow* window = qobject_cast<QQuickWindow *>(topLevelObj);
if(window)
{
window->setVisible(true);
window->showNormal();
return true;
}
}
}
m_prevAppState = ev->applicationState();
}
#endif
return QObject::eventFilter(obj, event);
}

View File

@ -0,0 +1,29 @@
#include "DOtherSide/StatusEvents/StatusOSThemeEvent.h"
#include <QQuickWindow>
StatusOSThemeEvent::StatusOSThemeEvent(DosQQmlApplicationEngine* vptr, QObject* parent)
: QObject(parent)
{
m_engine = static_cast<QQmlApplicationEngine*>(vptr);
}
bool StatusOSThemeEvent::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::PaletteChange ||
event->type() == QEvent::ApplicationPaletteChange)
{
QObject* topLevelObj = m_engine->rootObjects().value(0);
if(topLevelObj && topLevelObj->objectName() == "mainWindow")
{
QQuickWindow* window = qobject_cast<QQuickWindow *>(topLevelObj);
if(window)
{
QMetaObject::invokeMethod(window, "changeThemeFromOutside");
return true;
}
}
}
return QObject::eventFilter(obj, event);
}