Skip to content

Commit

Permalink
Use Qt signal for macOS Dock icon click event
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
hebasto committed Nov 4, 2018
1 parent 53bb6be commit 2464925
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 44 deletions.
18 changes: 12 additions & 6 deletions src/qt/bitcoingui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle)
void BitcoinGUI::createTrayIconMenu()
{
#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)
return;

Expand All @@ -604,15 +604,15 @@ void BitcoinGUI::createTrayIconMenu()

connect(trayIcon, &QSystemTrayIcon::activated, this, &BitcoinGUI::trayIconActivated);
#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();
dockIconHandler->setMainWindow(static_cast<QMainWindow*>(this));
connect(dockIconHandler, &MacDockIconHandler::dockIconClicked, this, &BitcoinGUI::macosDockIconActivated);
trayIconMenu = dockIconHandler->dockMenu();
#endif

// Configuration of the tray icon (or dock icon) icon menu
// Configuration of the tray icon (or Dock icon) menu
#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->addSeparator();
#endif
Expand All @@ -626,7 +626,7 @@ void BitcoinGUI::createTrayIconMenu()
trayIconMenu->addAction(openRPCConsoleAction);
}
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->addAction(quitAction);
#endif
Expand All @@ -641,6 +641,12 @@ void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
toggleHidden();
}
}
#else
void BitcoinGUI::macosDockIconActivated()
{
show();
activateWindow();
}
#endif

void BitcoinGUI::optionsClicked()
Expand Down
3 changes: 3 additions & 0 deletions src/qt/bitcoingui.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ public Q_SLOTS:
#ifndef Q_OS_MAC
/** Handle tray icon clicked */
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
#else
/** Handle macOS Dock icon clicked */
void macosDockIconActivated();
#endif

/** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */
Expand Down
8 changes: 2 additions & 6 deletions src/qt/macdockiconhandler.h
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
// 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
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_QT_MACDOCKICONHANDLER_H
#define BITCOIN_QT_MACDOCKICONHANDLER_H

#include <QMainWindow>
#include <QObject>

QT_BEGIN_NAMESPACE
class QMenu;
class QWidget;
QT_END_NAMESPACE

/** Macintosh-specific dock icon handler.
/** macOS-specific Dock icon handler.
*/
class MacDockIconHandler : public QObject
{
Expand All @@ -23,10 +22,8 @@ class MacDockIconHandler : public QObject
~MacDockIconHandler();

QMenu *dockMenu();
void setMainWindow(QMainWindow *window);
static MacDockIconHandler *instance();
static void cleanup();
void handleDockIconClickEvent();

Q_SIGNALS:
void dockIconClicked();
Expand All @@ -36,7 +33,6 @@ class MacDockIconHandler : public QObject

QWidget *m_dummyWidget;
QMenu *m_dockMenu;
QMainWindow *mainWindow;
};

#endif // BITCOIN_QT_MACDOCKICONHANDLER_H
40 changes: 8 additions & 32 deletions src/qt/macdockiconhandler.mm
Original file line number Diff line number Diff line change
@@ -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
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

Expand All @@ -18,25 +18,18 @@ bool dockClickHandler(id self,SEL _cmd,...) {
Q_UNUSED(self)
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;
}

void setupDockClickHandler() {
Class cls = objc_getClass("NSApplication");
id appInst = objc_msgSend((id)cls, sel_registerName("sharedApplication"));

if (appInst != nullptr) {
id delegate = objc_msgSend(appInst, sel_registerName("delegate"));
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@:");
}
id app = objc_msgSend((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
id delegate = objc_msgSend(app, sel_registerName("delegate"));
Class delClass = (Class)objc_msgSend(delegate, sel_registerName("class"));
SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:");
}


Expand All @@ -47,21 +40,15 @@ void setupDockClickHandler() {
setupDockClickHandler();
this->m_dummyWidget = new QWidget();
this->m_dockMenu = new QMenu(this->m_dummyWidget);
this->setMainWindow(nullptr);
#if QT_VERSION >= 0x050200
this->m_dockMenu->setAsDockMenu();
#endif
[pool release];
}

void MacDockIconHandler::setMainWindow(QMainWindow *window) {
this->mainWindow = window;
}

MacDockIconHandler::~MacDockIconHandler()
{
delete this->m_dummyWidget;
this->setMainWindow(nullptr);
}

QMenu *MacDockIconHandler::dockMenu()
Expand All @@ -80,14 +67,3 @@ void setupDockClickHandler() {
{
delete s_instance;
}

void MacDockIconHandler::handleDockIconClickEvent()
{
if (this->mainWindow)
{
this->mainWindow->activateWindow();
this->mainWindow->show();
}

Q_EMIT this->dockIconClicked();
}

0 comments on commit 2464925

Please sign in to comment.