Use Qt signal for macOS Dock icon click event

This moves the Dock icon click reaction code to the common place and
allows some cleanup in obj_c code.

According to the Apple's docs `class_replaceMethod` behaves as
`class_addMethod`, if the method identified by name does not yet exist;
or as `method_setImplementation`, if it does exist.

Github-Pull: #14597
Rebased-From: 2464925e7b
This commit is contained in:
Hennadii Stepanov 2018-10-31 21:15:31 +02:00 committed by João Barbosa
parent 4d4bc37df9
commit 90347141bd
4 changed files with 25 additions and 44 deletions

View file

@ -585,7 +585,7 @@ void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle)
void BitcoinGUI::createTrayIconMenu() void BitcoinGUI::createTrayIconMenu()
{ {
#ifndef Q_OS_MAC #ifndef Q_OS_MAC
// return if trayIcon is unset (only on non-Mac OSes) // return if trayIcon is unset (only on non-macOSes)
if (!trayIcon) if (!trayIcon)
return; return;
@ -595,15 +595,15 @@ void BitcoinGUI::createTrayIconMenu()
connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason))); this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
#else #else
// Note: On Mac, the dock icon is used to provide the tray's functionality. // Note: On macOS, the Dock icon is used to provide the tray's functionality.
MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance(); MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance();
dockIconHandler->setMainWindow(static_cast<QMainWindow*>(this)); connect(dockIconHandler, &MacDockIconHandler::dockIconClicked, this, &BitcoinGUI::macosDockIconActivated);
trayIconMenu = dockIconHandler->dockMenu(); trayIconMenu = dockIconHandler->dockMenu();
#endif #endif
// Configuration of the tray icon (or dock icon) icon menu // Configuration of the tray icon (or Dock icon) menu
#ifndef Q_OS_MAC #ifndef Q_OS_MAC
// Note: On Mac, the dock icon's menu already has show / hide action. // Note: On macOS, the Dock icon's menu already has Show / Hide action.
trayIconMenu->addAction(toggleHideAction); trayIconMenu->addAction(toggleHideAction);
trayIconMenu->addSeparator(); trayIconMenu->addSeparator();
#endif #endif
@ -617,7 +617,7 @@ void BitcoinGUI::createTrayIconMenu()
trayIconMenu->addAction(openRPCConsoleAction); trayIconMenu->addAction(openRPCConsoleAction);
} }
trayIconMenu->addAction(optionsAction); trayIconMenu->addAction(optionsAction);
#ifndef Q_OS_MAC // This is built-in on Mac #ifndef Q_OS_MAC // This is built-in on macOS
trayIconMenu->addSeparator(); trayIconMenu->addSeparator();
trayIconMenu->addAction(quitAction); trayIconMenu->addAction(quitAction);
#endif #endif
@ -632,6 +632,12 @@ void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
toggleHidden(); toggleHidden();
} }
} }
#else
void BitcoinGUI::macosDockIconActivated()
{
show();
activateWindow();
}
#endif #endif
void BitcoinGUI::optionsClicked() void BitcoinGUI::optionsClicked()

View file

@ -250,6 +250,9 @@ private Q_SLOTS:
#ifndef Q_OS_MAC #ifndef Q_OS_MAC
/** Handle tray icon clicked */ /** Handle tray icon clicked */
void trayIconActivated(QSystemTrayIcon::ActivationReason reason); void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
#else
/** Handle macOS Dock icon clicked */
void macosDockIconActivated();
#endif #endif
/** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */ /** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */

View file

@ -1,11 +1,10 @@
// Copyright (c) 2011-2015 The Bitcoin Core developers // Copyright (c) 2011-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_QT_MACDOCKICONHANDLER_H #ifndef BITCOIN_QT_MACDOCKICONHANDLER_H
#define BITCOIN_QT_MACDOCKICONHANDLER_H #define BITCOIN_QT_MACDOCKICONHANDLER_H
#include <QMainWindow>
#include <QObject> #include <QObject>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -13,7 +12,7 @@ class QMenu;
class QWidget; class QWidget;
QT_END_NAMESPACE QT_END_NAMESPACE
/** Macintosh-specific dock icon handler. /** macOS-specific Dock icon handler.
*/ */
class MacDockIconHandler : public QObject class MacDockIconHandler : public QObject
{ {
@ -23,10 +22,8 @@ public:
~MacDockIconHandler(); ~MacDockIconHandler();
QMenu *dockMenu(); QMenu *dockMenu();
void setMainWindow(QMainWindow *window);
static MacDockIconHandler *instance(); static MacDockIconHandler *instance();
static void cleanup(); static void cleanup();
void handleDockIconClickEvent();
Q_SIGNALS: Q_SIGNALS:
void dockIconClicked(); void dockIconClicked();
@ -36,7 +33,6 @@ private:
QWidget *m_dummyWidget; QWidget *m_dummyWidget;
QMenu *m_dockMenu; QMenu *m_dockMenu;
QMainWindow *mainWindow;
}; };
#endif // BITCOIN_QT_MACDOCKICONHANDLER_H #endif // BITCOIN_QT_MACDOCKICONHANDLER_H

View file

@ -1,4 +1,4 @@
// Copyright (c) 2011-2013 The Bitcoin Core developers // Copyright (c) 2011-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -18,25 +18,18 @@ bool dockClickHandler(id self,SEL _cmd,...) {
Q_UNUSED(self) Q_UNUSED(self)
Q_UNUSED(_cmd) Q_UNUSED(_cmd)
s_instance->handleDockIconClickEvent(); Q_EMIT s_instance->dockIconClicked();
// Return NO (false) to suppress the default OS X actions // Return NO (false) to suppress the default macOS actions
return false; return false;
} }
void setupDockClickHandler() { void setupDockClickHandler() {
Class cls = objc_getClass("NSApplication"); id app = objc_msgSend((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
id appInst = objc_msgSend((id)cls, sel_registerName("sharedApplication")); id delegate = objc_msgSend(app, sel_registerName("delegate"));
Class delClass = (Class)objc_msgSend(delegate, sel_registerName("class"));
if (appInst != nullptr) { SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
id delegate = objc_msgSend(appInst, sel_registerName("delegate")); class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:");
Class delClass = (Class)objc_msgSend(delegate, sel_registerName("class"));
SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
if (class_getInstanceMethod(delClass, shouldHandle))
class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:");
else
class_addMethod(delClass, shouldHandle, (IMP)dockClickHandler,"B@:");
}
} }
@ -47,21 +40,15 @@ MacDockIconHandler::MacDockIconHandler() : QObject()
setupDockClickHandler(); setupDockClickHandler();
this->m_dummyWidget = new QWidget(); this->m_dummyWidget = new QWidget();
this->m_dockMenu = new QMenu(this->m_dummyWidget); this->m_dockMenu = new QMenu(this->m_dummyWidget);
this->setMainWindow(nullptr);
#if QT_VERSION >= 0x050200 #if QT_VERSION >= 0x050200
this->m_dockMenu->setAsDockMenu(); this->m_dockMenu->setAsDockMenu();
#endif #endif
[pool release]; [pool release];
} }
void MacDockIconHandler::setMainWindow(QMainWindow *window) {
this->mainWindow = window;
}
MacDockIconHandler::~MacDockIconHandler() MacDockIconHandler::~MacDockIconHandler()
{ {
delete this->m_dummyWidget; delete this->m_dummyWidget;
this->setMainWindow(nullptr);
} }
QMenu *MacDockIconHandler::dockMenu() QMenu *MacDockIconHandler::dockMenu()
@ -80,14 +67,3 @@ void MacDockIconHandler::cleanup()
{ {
delete s_instance; delete s_instance;
} }
void MacDockIconHandler::handleDockIconClickEvent()
{
if (this->mainWindow)
{
this->mainWindow->activateWindow();
this->mainWindow->show();
}
Q_EMIT this->dockIconClicked();
}