fix: Restore window after closing on MacOS (#11748)
This commit is contained in:
parent
ea91cd605f
commit
d8c9802d77
|
@ -4,5 +4,9 @@
|
|||
<dict>
|
||||
<key>com.apple.security.device.camera</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.associated-domains</key>
|
||||
<array>
|
||||
<string>applinks:status.app</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.developer.associated-domains</key>
|
||||
<array>
|
||||
<string>applinks:status.app</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
|
@ -131,7 +131,6 @@ proc mainProc() =
|
|||
|
||||
QResource.registerResource(app.applicationDirPath & resourcesPath)
|
||||
# Register events objects
|
||||
let dockShowAppEvent = newStatusDockShowAppEventObject(singletonInstance.engine)
|
||||
let osThemeEvent = newStatusOSThemeEventObject(singletonInstance.engine)
|
||||
|
||||
if not main_constants.IS_MACOS:
|
||||
|
@ -149,7 +148,6 @@ proc mainProc() =
|
|||
singletonInstance.engine.setRootContextProperty("signals", signalsManagerQVariant)
|
||||
singletonInstance.engine.setRootContextProperty("production", isProductionQVariant)
|
||||
|
||||
app.installEventFilter(dockShowAppEvent)
|
||||
app.installEventFilter(osThemeEvent)
|
||||
app.installEventFilter(urlSchemeEvent)
|
||||
|
||||
|
@ -161,7 +159,6 @@ proc mainProc() =
|
|||
isExperimentalQVariant.delete()
|
||||
signalsManagerQVariant.delete()
|
||||
networkAccessFactory.delete()
|
||||
dockShowAppEvent.delete()
|
||||
osThemeEvent.delete()
|
||||
appController.delete()
|
||||
statusFoundation.delete()
|
||||
|
|
30
ui/main.qml
30
ui/main.qml
|
@ -92,6 +92,11 @@ StatusWindow {
|
|||
onWidthChanged: Qt.callLater(storeAppState)
|
||||
onHeightChanged: Qt.callLater(storeAppState)
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
property int previousApplicationState: -1
|
||||
}
|
||||
|
||||
Action {
|
||||
shortcut: StandardKey.FullScreen
|
||||
onTriggered: {
|
||||
|
@ -220,6 +225,20 @@ StatusWindow {
|
|||
}
|
||||
}
|
||||
|
||||
// On MacOS, explicitely restore the window on activating
|
||||
Connections {
|
||||
target: Qt.application
|
||||
enabled: Qt.platform.os === Constants.mac
|
||||
function onStateChanged() {
|
||||
if (Qt.application.state == d.previousApplicationState
|
||||
&& Qt.application.state == Qt.ApplicationActive) {
|
||||
applicationWindow.visible = true
|
||||
applicationWindow.showNormal()
|
||||
}
|
||||
d.previousApplicationState = Qt.application.state
|
||||
}
|
||||
}
|
||||
|
||||
//TODO remove direct backend access
|
||||
Connections {
|
||||
target: singleInstance
|
||||
|
@ -358,16 +377,17 @@ StatusWindow {
|
|||
|
||||
onClose: {
|
||||
if (loader.sourceComponent != app) {
|
||||
Qt.quit();
|
||||
Qt.quit()
|
||||
return
|
||||
}
|
||||
else if (loader.sourceComponent == app) {
|
||||
|
||||
if (localAccountSensitiveSettings.quitOnClose) {
|
||||
Qt.quit();
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
applicationWindow.visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMinimised: {
|
||||
applicationWindow.showMinimized()
|
||||
|
|
|
@ -998,7 +998,6 @@ DOS_API void DOS_CALL dos_singleinstance_delete(DosSingleInstance *vptr);
|
|||
|
||||
#pragma region Events exposed methods
|
||||
|
||||
DOS_API DosEvent* dos_event_create_showAppEvent(DosQQmlApplicationEngine* vptr);
|
||||
DOS_API DosEvent* dos_event_create_osThemeEvent(DosQQmlApplicationEngine* vptr);
|
||||
DOS_API DosEvent* dos_event_create_urlSchemeEvent();
|
||||
DOS_API void dos_event_delete(DosEvent* vptr);
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
#ifndef STATUS_DOCK_SHOW_APP_EVENT_H
|
||||
#define STATUS_DOCK_SHOW_APP_EVENT_H
|
||||
|
||||
#include "../DOtherSideTypes.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QQmlApplicationEngine>
|
||||
|
||||
namespace Status
|
||||
{
|
||||
class DockShowAppEvent : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DockShowAppEvent(DosQQmlApplicationEngine* vptr, QObject* parent = nullptr);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject* obj, QEvent* event) override;
|
||||
|
||||
private:
|
||||
Qt::ApplicationState m_prevAppState;
|
||||
QQmlApplicationEngine* m_engine;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -68,7 +68,6 @@
|
|||
#include "DOtherSide/DosQQuickImageProvider.h"
|
||||
#include "DOtherSide/DOtherSideSingleInstance.h"
|
||||
|
||||
#include "DOtherSide/Status/DockShowAppEvent.h"
|
||||
#include "DOtherSide/Status/OSThemeEvent.h"
|
||||
#include "DOtherSide/Status/UrlSchemeEvent.h"
|
||||
#include "DOtherSide/Status/OSNotification.h"
|
||||
|
@ -1553,11 +1552,6 @@ bool dos_singleinstance_isfirst(DosSingleInstance *vptr)
|
|||
}
|
||||
|
||||
#pragma region Events
|
||||
::DosEvent* dos_event_create_showAppEvent(::DosQQmlApplicationEngine* vptr)
|
||||
{
|
||||
auto engine = static_cast<QQmlApplicationEngine*>(vptr);
|
||||
return new Status::DockShowAppEvent(engine);
|
||||
}
|
||||
|
||||
::DosEvent* dos_event_create_osThemeEvent(::DosQQmlApplicationEngine* vptr)
|
||||
{
|
||||
|
|
|
@ -2,23 +2,25 @@
|
|||
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QDebug>
|
||||
|
||||
#import <AppKit/NSApplication.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
|
||||
@interface AppDelegate: NSObject <NSApplicationDelegate>
|
||||
@interface StatusApplicationDelegate: NSObject <NSApplicationDelegate>
|
||||
- (BOOL)application:(NSApplication *)application
|
||||
continueUserActivity:(NSUserActivity *)userActivity
|
||||
restorationHandler:(void (^)(NSArray<id<NSUserActivityRestoring>> *restorableObjects))restorationHandler;
|
||||
@end
|
||||
|
||||
@implementation AppDelegate
|
||||
- (BOOL)application:(NSApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<NSUserActivityRestoring>> *))restorationHandler {
|
||||
@implementation StatusApplicationDelegate
|
||||
- (BOOL)application:(NSApplication *)application
|
||||
continueUserActivity:(NSUserActivity *)userActivity
|
||||
restorationHandler:(void (^)(NSArray<id<NSUserActivityRestoring>> *))restorationHandler {
|
||||
if (userActivity.activityType == NSUserActivityTypeBrowsingWeb) {
|
||||
NSURL *url = userActivity.webpageURL;
|
||||
if (!url) {
|
||||
if (!url)
|
||||
return FALSE;
|
||||
}
|
||||
QUrl deeplink = QUrl::fromNSURL(url);
|
||||
// set it to nim
|
||||
return TRUE;
|
||||
|
@ -26,14 +28,44 @@ continueUserActivity:(NSUserActivity *)userActivity
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
qDebug() << "StatusApplicationDelegate::applicationDidFinishLaunching";
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
namespace app_delegate {
|
||||
|
||||
void swizzle_appdelegate_method(SEL selector) {
|
||||
Class originalClass = [NSApplication sharedApplication].delegate.class;
|
||||
Class swizzledClass = [StatusApplicationDelegate class];
|
||||
|
||||
Method originalMethod = class_getInstanceMethod(originalClass, selector);
|
||||
Method swizzledMethod = class_getInstanceMethod(swizzledClass, selector);
|
||||
|
||||
method_exchangeImplementations(originalMethod, swizzledMethod);
|
||||
}
|
||||
|
||||
void install()
|
||||
{
|
||||
NSApplication* applicationShared = [NSApplication sharedApplication];
|
||||
[applicationShared setDelegate:([[[AppDelegate alloc] init] autorelease])];
|
||||
/*
|
||||
A simple solution to implement custom ApplicationDelegate would be to call `NSApplication::setDelegate`
|
||||
with an instantse of StatusApplicationDelegate. But this will override Qt's ApplicationDelegate implementation
|
||||
`QCocoaApplicationDelegate` (qtbase/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm).
|
||||
|
||||
Overriding breaks some Qt events like `QApplicationStateChangeEvent`. And I suppose (and pretty sure)
|
||||
that this might also break other things.
|
||||
|
||||
Would be cool to simply inherit `QCocoaApplicationDelegate`, but it's only available in Qt's sources.
|
||||
|
||||
The solution here is to use "method swizzling" technique.
|
||||
We replace the method of a class with own implementation.
|
||||
|
||||
In future we could contribute to Qt to add "continueUserActivity" event.
|
||||
*/
|
||||
swizzle_appdelegate_method(@selector(applicationDidFinishLaunching:)); // for testing purposes (ApplicationDelegate works, method swizzled)
|
||||
swizzle_appdelegate_method(@selector(application:continueUserActivity:restorationHandler:)); // for Univeral Links support
|
||||
}
|
||||
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
#include "DOtherSide/Status/DockShowAppEvent.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.
|
||||
*/
|
||||
|
||||
using namespace Status;
|
||||
|
||||
DockShowAppEvent::DockShowAppEvent(DosQQmlApplicationEngine* vptr,
|
||||
QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
m_engine = static_cast<QQmlApplicationEngine*>(vptr);
|
||||
}
|
||||
|
||||
bool DockShowAppEvent::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);
|
||||
}
|
|
@ -1 +1 @@
|
|||
Subproject commit ab78548aa3838fb51aff791d14203e29849ed200
|
||||
Subproject commit 3f61ec4addbd1e59c6936658258214a58b768c4a
|
Loading…
Reference in New Issue