Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ file(GLOB SOURCE_FILES
"plugins/*.h"
)

if(APPLE)
list(APPEND SOURCE_FILES
"utils/os/macos_sleep.mm")
endif()

get_cmake_property(_vars VARIABLES)
set(PLUGIN_PREFIX "WITH_PLUGIN_")

Expand Down
45 changes: 44 additions & 1 deletion src/WindowManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
#include <QMessageBox>
#include <QWindow>

#if defined(Q_OS_MACOS)
#include "utils/os/macos_sleep.h"
#include <QTimer>
#endif

#include "Application.h"
#include "constants.h"
#include "MainWindow.h"
Expand Down Expand Up @@ -41,6 +46,12 @@ WindowManager::WindowManager(QObject *parent)

connect(qApp, SIGNAL(anotherInstanceStarted()), this, SLOT(raise()));
connect(qApp, &QGuiApplication::lastWindowClosed, this, &WindowManager::quitAfterLastWindow);
#if defined(Q_OS_MACOS)
m_macSleepObserver = new MacSleepObserver(this);
connect(m_macSleepObserver, &MacSleepObserver::didWake, this, [this] {
QTimer::singleShot(0, this, &WindowManager::recoverFromSleep);
});
#endif

m_tray = new QSystemTrayIcon(icons()->icon("appicons/64x64.png"));
m_tray->setToolTip("Feather Wallet");
Expand Down Expand Up @@ -621,6 +632,38 @@ void WindowManager::onWalletPassphraseNeeded(bool on_device) {
m_walletManager->onPassphraseEntered(passphrase, false, false);
}

void WindowManager::recoverFromSleep() {
#if defined(Q_OS_MACOS)
// Recreate tray icon to work around macOS Qt status item issues after sleep.
const bool trayVisible = conf()->get(Config::showTrayIcon).toBool();
if (m_tray) {
m_tray->setVisible(false);
delete m_tray;
m_tray = nullptr;
}

m_tray = new QSystemTrayIcon(icons()->icon("appicons/64x64.png"));
m_tray->setToolTip("Feather Wallet");
this->buildTrayMenu();
m_tray->setVisible(trayVisible);

for (const auto &window : m_windows) {
if (!window) {
continue;
}
if (!window->isHidden()) {
window->bringToFront();
} else {
window->update();
}
}
if (m_wizard && !m_wizard->isHidden()) {
m_wizard->raise();
m_wizard->activateWindow();
}
#endif
}

// ######################## TRAY ########################

void WindowManager::buildTrayMenu() {
Expand Down Expand Up @@ -818,4 +861,4 @@ WindowManager* WindowManager::instance()
}

return m_instance;
}
}
4 changes: 4 additions & 0 deletions src/WindowManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ private slots:
void onDeviceError(const QString &errorMessage, quint64 errorCode);
void onWalletPassphraseNeeded(bool on_device);
void onChangeTheme(const QString &themeName);
void recoverFromSleep();

private:
void tryCreateWallet(Seed seed, const QString &path, const QString &password, const QString &seedLanguage, const QString &seedOffset, const QString &subaddressLookahead, bool newWallet);
Expand Down Expand Up @@ -115,6 +116,9 @@ private slots:
bool m_initialNetworkConfigured = false;

QThread *m_cleanupThread;
#if defined(Q_OS_MACOS)
class MacSleepObserver *m_macSleepObserver = nullptr;
#endif
};

inline WindowManager* windowManager()
Expand Down
27 changes: 27 additions & 0 deletions src/utils/os/macos_sleep.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: BSD-3-Clause
// SPDX-FileCopyrightText: The Monero Project

#ifndef FEATHER_MACOS_SLEEP_H
#define FEATHER_MACOS_SLEEP_H

#include <QObject>

class MacSleepObserver : public QObject {
Q_OBJECT

public:
explicit MacSleepObserver(QObject *parent = nullptr);
~MacSleepObserver() override;

void notifyWillSleep();
void notifyDidWake();

signals:
void willSleep();
void didWake();

private:
void *m_observer = nullptr;
};

#endif // FEATHER_MACOS_SLEEP_H
90 changes: 90 additions & 0 deletions src/utils/os/macos_sleep.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// SPDX-License-Identifier: BSD-3-Clause
// SPDX-FileCopyrightText: The Monero Project

#include "macos_sleep.h"

#if defined(Q_OS_MACOS)

#import <Cocoa/Cocoa.h>

@interface FeatherSleepObserver : NSObject
@property (nonatomic, assign) MacSleepObserver *owner;
@end

@implementation FeatherSleepObserver
- (instancetype)initWithOwner:(MacSleepObserver *)owner {
self = [super init];
if (self) {
_owner = owner;
NSNotificationCenter *center = [[NSWorkspace sharedWorkspace] notificationCenter];
[center addObserver:self selector:@selector(onWillSleep:) name:NSWorkspaceWillSleepNotification object:nil];
[center addObserver:self selector:@selector(onDidWake:) name:NSWorkspaceDidWakeNotification object:nil];
}
return self;
}

- (void)dealloc {
NSNotificationCenter *center = [[NSWorkspace sharedWorkspace] notificationCenter];
[center removeObserver:self];
#if !__has_feature(objc_arc)
[super dealloc];
#endif
}

- (void)onWillSleep:(NSNotification *)__unused notification {
if (_owner) {
_owner->notifyWillSleep();
}
}

- (void)onDidWake:(NSNotification *)__unused notification {
if (_owner) {
_owner->notifyDidWake();
}
}
@end

MacSleepObserver::MacSleepObserver(QObject *parent)
: QObject(parent)
{
FeatherSleepObserver *observer = [[FeatherSleepObserver alloc] initWithOwner:this];
#if __has_feature(objc_arc)
m_observer = (__bridge_retained void *)observer;
#else
m_observer = observer;
#endif
}

MacSleepObserver::~MacSleepObserver() {
if (m_observer) {
#if !__has_feature(objc_arc)
FeatherSleepObserver *observer = static_cast<FeatherSleepObserver *>(m_observer);
[observer release];
#else
CFBridgingRelease(m_observer);
#endif
m_observer = nullptr;
}
}

void MacSleepObserver::notifyWillSleep() {
emit willSleep();
}

void MacSleepObserver::notifyDidWake() {
emit didWake();
}

#else

MacSleepObserver::MacSleepObserver(QObject *parent)
: QObject(parent)
{}

MacSleepObserver::~MacSleepObserver() = default;

void MacSleepObserver::notifyWillSleep() {}

void MacSleepObserver::notifyDidWake() {}

#endif