Skip to content

Commit 124824d

Browse files
xdustinfacehebastopromag
authoredApr 30, 2020
* Remove obj_c for macOS Dock icon setting Qt `setWindowIcon()` does this work. * 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. * Remove obj_c for macOS Dock icon menu Qt `setAsDockMenu()` does this work. * qt: Add GUIUtil::bringToFront * qt: Use GUIUtil::bringToFront where possible * qt: All tray menu actions call showNormalIfMinimized * qt: Replace objc_msgSend with native syntax Co-authored-by: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Co-authored-by: João Barbosa <joao.paulo.barbosa@gmail.com>
1 parent 10baa4a commit 124824d

8 files changed

+72
-153
lines changed
 

‎configure.ac

+1-1
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ case $host in
539539
fi
540540

541541
AX_CHECK_LINK_FLAG([[-Wl,-headerpad_max_install_names]], [LDFLAGS="$LDFLAGS -Wl,-headerpad_max_install_names"])
542-
CPPFLAGS="$CPPFLAGS -DMAC_OSX"
542+
CPPFLAGS="$CPPFLAGS -DMAC_OSX -DOBJC_OLD_DISPATCH_PROTOTYPES=0"
543543
OBJCXXFLAGS="$CXXFLAGS"
544544
;;
545545
*linux*)

‎src/qt/bitcoingui.cpp

+17-27
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,8 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle *
148148
QString userWindowTitle = QString::fromStdString(gArgs.GetArg("-windowtitle", ""));
149149
if(!userWindowTitle.isEmpty()) windowTitle += " - " + userWindowTitle;
150150
windowTitle += " " + networkStyle->getTitleAddText();
151-
#ifndef Q_OS_MAC
152151
QApplication::setWindowIcon(networkStyle->getTrayAndWindowIcon());
153152
setWindowIcon(networkStyle->getTrayAndWindowIcon());
154-
#else
155-
MacDockIconHandler::instance()->setIcon(networkStyle->getAppIcon());
156-
#endif
157153
setWindowTitle(windowTitle);
158154

159155
#if defined(Q_OS_MAC) && QT_VERSION < 0x050000
@@ -500,7 +496,9 @@ void BitcoinGUI::createActions()
500496
connect(changePassphraseAction, SIGNAL(triggered()), walletFrame, SLOT(changePassphrase()));
501497
connect(unlockWalletAction, SIGNAL(triggered()), walletFrame, SLOT(unlockWallet()));
502498
connect(lockWalletAction, SIGNAL(triggered()), walletFrame, SLOT(lockWallet()));
499+
connect(signMessageAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
503500
connect(signMessageAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab()));
501+
connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
504502
connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab()));
505503
connect(usedSendingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedSendingAddresses()));
506504
connect(usedReceivingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedReceivingAddresses()));
@@ -645,8 +643,10 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel)
645643
// Note: On Mac, the dock icon is also used to provide menu functionality
646644
// similar to one for tray icon
647645
MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance();
648-
dockIconHandler->setMainWindow((QMainWindow *)this);
649-
dockIconMenu = dockIconHandler->dockMenu();
646+
connect(dockIconHandler, SIGNAL(dockIconClicked()), this, SLOT(macosDockIconActivated()));
647+
648+
dockIconMenu = new QMenu(this);
649+
dockIconMenu->setAsDockMenu();
650650

651651
createIconMenu(dockIconMenu);
652652
#endif
@@ -808,6 +808,12 @@ void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
808808
toggleHidden();
809809
}
810810
}
811+
#else
812+
void BitcoinGUI::macosDockIconActivated()
813+
{
814+
show();
815+
activateWindow();
816+
}
811817
#endif
812818

813819
void BitcoinGUI::optionsClicked()
@@ -831,10 +837,7 @@ void BitcoinGUI::aboutClicked()
831837

832838
void BitcoinGUI::showDebugWindow()
833839
{
834-
rpcConsole->showNormal();
835-
rpcConsole->show();
836-
rpcConsole->raise();
837-
rpcConsole->activateWindow();
840+
GUIUtil::bringToFront(rpcConsole);
838841
}
839842

840843
void BitcoinGUI::showInfo()
@@ -1468,24 +1471,11 @@ void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden)
14681471
if(!clientModel)
14691472
return;
14701473

1471-
// activateWindow() (sometimes) helps with keyboard focus on Windows
1472-
if (isHidden())
1473-
{
1474-
show();
1475-
activateWindow();
1476-
}
1477-
else if (isMinimized())
1478-
{
1479-
showNormal();
1480-
activateWindow();
1481-
}
1482-
else if (GUIUtil::isObscured(this))
1483-
{
1484-
raise();
1485-
activateWindow();
1486-
}
1487-
else if(fToggleHidden)
1474+
if (!isHidden() && !isMinimized() && !GUIUtil::isObscured(this) && fToggleHidden) {
14881475
hide();
1476+
} else {
1477+
GUIUtil::bringToFront(this);
1478+
}
14891479
}
14901480

14911481
void BitcoinGUI::toggleHidden()

‎src/qt/bitcoingui.h

+3
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,9 @@ private Q_SLOTS:
274274
#ifndef Q_OS_MAC
275275
/** Handle tray icon clicked */
276276
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
277+
#else
278+
/** Handle macOS Dock icon clicked */
279+
void macosDockIconActivated();
277280
#endif
278281

279282
/** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */

‎src/qt/guiutil.cpp

+26-5
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ extern double NSAppKitVersionNumber;
7373
#if !defined(NSAppKitVersionNumber10_9)
7474
#define NSAppKitVersionNumber10_9 1265
7575
#endif
76+
77+
#pragma GCC diagnostic push
78+
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
79+
80+
#include <CoreServices/CoreServices.h>
81+
#include <QProcess>
82+
83+
void ForceActivation();
7684
#endif
7785

7886
namespace GUIUtil {
@@ -471,6 +479,24 @@ bool isObscured(QWidget *w)
471479
&& checkPoint(QPoint(w->width() / 2, w->height() / 2), w));
472480
}
473481

482+
void bringToFront(QWidget* w)
483+
{
484+
#ifdef Q_OS_MAC
485+
ForceActivation();
486+
#endif
487+
488+
if (w) {
489+
// activateWindow() (sometimes) helps with keyboard focus on Windows
490+
if (w->isMinimized()) {
491+
w->showNormal();
492+
} else {
493+
w->show();
494+
}
495+
w->activateWindow();
496+
w->raise();
497+
}
498+
}
499+
474500
void openDebugLogfile()
475501
{
476502
fs::path pathDebug = GetDataDir() / "debug.log";
@@ -841,13 +867,8 @@ bool SetStartOnSystemStartup(bool fAutoStart)
841867

842868

843869
#elif defined(Q_OS_MAC)
844-
#pragma GCC diagnostic push
845-
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
846870
// based on: https://github.com/Mozketo/LaunchAtLoginController/blob/master/LaunchAtLoginController.m
847871

848-
#include <CoreFoundation/CoreFoundation.h>
849-
#include <CoreServices/CoreServices.h>
850-
851872
LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl);
852873
LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl)
853874
{

‎src/qt/guiutil.h

+3
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ namespace GUIUtil
151151
// Determine whether a widget is hidden behind other windows
152152
bool isObscured(QWidget *w);
153153

154+
// Activate, show and raise the widget
155+
void bringToFront(QWidget* w);
156+
154157
// Open debug.log
155158
void openDebugLogfile();
156159

‎src/qt/macdockiconhandler.h

+2-19
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,27 @@
1-
// Copyright (c) 2011-2015 The Bitcoin Core developers
1+
// Copyright (c) 2011-2018 The Bitcoin Core developers
22
// Distributed under the MIT software license, see the accompanying
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

55
#ifndef BITCOIN_QT_MACDOCKICONHANDLER_H
66
#define BITCOIN_QT_MACDOCKICONHANDLER_H
77

8-
#include <QMainWindow>
98
#include <QObject>
109

11-
QT_BEGIN_NAMESPACE
12-
class QIcon;
13-
class QMenu;
14-
class QWidget;
15-
QT_END_NAMESPACE
16-
17-
/** Macintosh-specific dock icon handler.
10+
/** macOS-specific Dock icon handler.
1811
*/
1912
class MacDockIconHandler : public QObject
2013
{
2114
Q_OBJECT
2215

2316
public:
24-
~MacDockIconHandler();
25-
26-
QMenu *dockMenu();
27-
void setIcon(const QIcon &icon);
28-
void setMainWindow(QMainWindow *window);
2917
static MacDockIconHandler *instance();
3018
static void cleanup();
31-
void handleDockIconClickEvent();
3219

3320
Q_SIGNALS:
3421
void dockIconClicked();
3522

3623
private:
3724
MacDockIconHandler();
38-
39-
QWidget *m_dummyWidget;
40-
QMenu *m_dockMenu;
41-
QMainWindow *mainWindow;
4225
};
4326

4427
#endif // BITCOIN_QT_MACDOCKICONHANDLER_H

‎src/qt/macdockiconhandler.mm

+18-95
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,37 @@
1-
// Copyright (c) 2011-2013 The Bitcoin Core developers
1+
// Copyright (c) 2011-2019 The Bitcoin Core developers
22
// Distributed under the MIT software license, see the accompanying
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

55
#include "macdockiconhandler.h"
66

7-
#include <QImageWriter>
8-
#include <QMenu>
9-
#include <QBuffer>
10-
#include <QWidget>
11-
12-
#undef slots
13-
#include <Cocoa/Cocoa.h>
14-
#include <objc/objc.h>
15-
#include <objc/message.h>
7+
#include <AppKit/AppKit.h>
8+
#include <objc/runtime.h>
169

1710
#if QT_VERSION < 0x050000
1811
extern void qt_mac_set_dock_menu(QMenu *);
1912
#endif
2013

2114
static MacDockIconHandler *s_instance = nullptr;
2215

23-
bool dockClickHandler(id self,SEL _cmd,...) {
16+
bool dockClickHandler(id self, SEL _cmd, ...) {
2417
Q_UNUSED(self)
2518
Q_UNUSED(_cmd)
26-
27-
s_instance->handleDockIconClickEvent();
28-
29-
// Return NO (false) to suppress the default OS X actions
19+
20+
Q_EMIT s_instance->dockIconClicked();
21+
22+
// Return NO (false) to suppress the default macOS actions
3023
return false;
3124
}
3225

3326
void setupDockClickHandler() {
34-
Class cls = objc_getClass("NSApplication");
35-
id appInst = objc_msgSend((id)cls, sel_registerName("sharedApplication"));
36-
37-
if (appInst != nullptr) {
38-
id delegate = objc_msgSend(appInst, sel_registerName("delegate"));
39-
Class delClass = (Class)objc_msgSend(delegate, sel_registerName("class"));
40-
SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
41-
if (class_getInstanceMethod(delClass, shouldHandle))
42-
class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:");
43-
else
44-
class_addMethod(delClass, shouldHandle, (IMP)dockClickHandler,"B@:");
45-
}
27+
Class delClass = (Class)[[[NSApplication sharedApplication] delegate] class];
28+
SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
29+
class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:");
4630
}
4731

48-
4932
MacDockIconHandler::MacDockIconHandler() : QObject()
5033
{
51-
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
52-
5334
setupDockClickHandler();
54-
this->m_dummyWidget = new QWidget();
55-
this->m_dockMenu = new QMenu(this->m_dummyWidget);
56-
this->setMainWindow(nullptr);
57-
#if QT_VERSION < 0x050000
58-
qt_mac_set_dock_menu(this->m_dockMenu);
59-
#elif QT_VERSION >= 0x050200
60-
this->m_dockMenu->setAsDockMenu();
61-
#endif
62-
[pool release];
63-
}
64-
65-
void MacDockIconHandler::setMainWindow(QMainWindow *window) {
66-
this->mainWindow = window;
67-
}
68-
69-
MacDockIconHandler::~MacDockIconHandler()
70-
{
71-
delete this->m_dummyWidget;
72-
this->setMainWindow(nullptr);
73-
}
74-
75-
QMenu *MacDockIconHandler::dockMenu()
76-
{
77-
return this->m_dockMenu;
78-
}
79-
80-
void MacDockIconHandler::setIcon(const QIcon &icon)
81-
{
82-
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
83-
NSImage *image = nil;
84-
if (icon.isNull())
85-
image = [[NSImage imageNamed:@"NSApplicationIcon"] retain];
86-
else {
87-
// generate NSImage from QIcon and use this as dock icon.
88-
QSize size = icon.actualSize(QSize(128, 128));
89-
QPixmap pixmap = icon.pixmap(size);
90-
91-
// Write image into a R/W buffer from raw pixmap, then save the image.
92-
QBuffer notificationBuffer;
93-
if (!pixmap.isNull() && notificationBuffer.open(QIODevice::ReadWrite)) {
94-
QImageWriter writer(&notificationBuffer, "PNG");
95-
if (writer.write(pixmap.toImage())) {
96-
NSData* macImgData = [NSData dataWithBytes:notificationBuffer.buffer().data()
97-
length:notificationBuffer.buffer().size()];
98-
image = [[NSImage alloc] initWithData:macImgData];
99-
}
100-
}
101-
102-
if(!image) {
103-
// if testnet image could not be created, load std. app icon
104-
image = [[NSImage imageNamed:@"NSApplicationIcon"] retain];
105-
}
106-
}
107-
108-
[NSApp setApplicationIconImage:image];
109-
[image release];
110-
[pool release];
11135
}
11236

11337
MacDockIconHandler *MacDockIconHandler::instance()
@@ -122,13 +46,12 @@ void setupDockClickHandler() {
12246
delete s_instance;
12347
}
12448

125-
void MacDockIconHandler::handleDockIconClickEvent()
49+
/**
50+
* Force application activation on macOS. With Qt 5.5.1 this is required when
51+
* an action in the Dock menu is triggered.
52+
* TODO: Define a Qt version where it's no-longer necessary.
53+
*/
54+
void ForceActivation()
12655
{
127-
if (this->mainWindow)
128-
{
129-
this->mainWindow->activateWindow();
130-
this->mainWindow->show();
131-
}
132-
133-
Q_EMIT this->dockIconClicked();
56+
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
13457
}

‎src/qt/walletview.cpp

+2-6
Original file line numberDiff line numberDiff line change
@@ -346,19 +346,15 @@ void WalletView::usedSendingAddresses()
346346
if(!walletModel)
347347
return;
348348

349-
usedSendingAddressesPage->show();
350-
usedSendingAddressesPage->raise();
351-
usedSendingAddressesPage->activateWindow();
349+
GUIUtil::bringToFront(usedSendingAddressesPage);
352350
}
353351

354352
void WalletView::usedReceivingAddresses()
355353
{
356354
if(!walletModel)
357355
return;
358356

359-
usedReceivingAddressesPage->show();
360-
usedReceivingAddressesPage->raise();
361-
usedReceivingAddressesPage->activateWindow();
357+
GUIUtil::bringToFront(usedReceivingAddressesPage);
362358
}
363359

364360
void WalletView::showProgress(const QString &title, int nProgress)

0 commit comments

Comments
 (0)
Please sign in to comment.