Fixed mac specific compiler errors and cleaned up Objective C code

Created new file src/gui/macutilities.mm, moved code from mainwindow.cpp and torrentcontentmodel.cpp that used the Objective C runtime into it and converted it to actual Objective C. Rewrote pixmapForExtension() so that it doesn't call into private Qt functions.
This commit is contained in:
Brian Kendall 2017-08-11 01:37:06 -04:00
parent 6f0d16bca5
commit 62b956946f
8 changed files with 144 additions and 56 deletions

View file

@ -9,7 +9,7 @@ exists($$OUT_PWD/../conf.pri) {
include(conf.pri)
}
LIBS += -framework Carbon -framework IOKit
LIBS += -framework Carbon -framework IOKit -framework AppKit
QT_LANG_PATH = ../dist/qt-translations
DIST_PATH = ../dist/mac

View file

@ -141,5 +141,6 @@ endif ()
if (APPLE)
find_library(IOKit_LIBRARY IOKit)
find_library(Carbon_LIBRARY Carbon)
target_link_libraries(qbt_base PRIVATE ${Carbon_LIBRARY} ${IOKit_LIBRARY})
find_library(AppKit_LIBRARY AppKit)
target_link_libraries(qbt_base PRIVATE ${Carbon_LIBRARY} ${IOKit_LIBRARY} ${AppKit_LIBRARY})
endif (APPLE)

View file

@ -118,6 +118,11 @@ transferlistwidget.cpp
updownratiodlg.cpp
)
if (APPLE)
list(APPEND QBT_GUI_HEADERS macutilities.h)
list(APPEND QBT_GUI_SOURCES macutilities.mm)
endif (APPLE)
if (WIN32 OR APPLE)
list(APPEND QBT_GUI_HEADERS programupdater.h)
list(APPEND QBT_GUI_SOURCES programupdater.cpp)

View file

@ -121,6 +121,11 @@ win32|macx {
SOURCES += $$PWD/programupdater.cpp
}
macx {
HEADERS += $$PWD/macutilities.h
OBJECTIVE_SOURCES += $$PWD/macutilities.mm
}
FORMS += \
$$PWD/mainwindow.ui \
$$PWD/about.ui \

39
src/gui/macutilities.h Normal file
View file

@ -0,0 +1,39 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2017 Brian Kendall <brian@briankendall.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#ifndef MACUTILITIES_H
#define MACUTILITIES_H
#include <QPixmap>
#include <QSize>
#include <objc/objc.h>
QPixmap pixmapForExtension(const QString &ext, const QSize &size);
void overrideDockClickHandler(bool (*dockClickHandler)(id, SEL, ...));
#endif // MACUTILITIES_H

71
src/gui/macutilities.mm Normal file
View file

@ -0,0 +1,71 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2017 Brian Kendall <brian@briankendall.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#include "macutilities.h"
#include <QtMac>
#include <objc/message.h>
#import <Cocoa/Cocoa.h>
QPixmap pixmapForExtension(const QString &ext, const QSize &size)
{
@autoreleasepool {
NSImage *image = [[NSWorkspace sharedWorkspace] iconForFileType:ext.toNSString()];
if (image) {
NSRect rect = NSMakeRect(0, 0, size.width(), size.height());
CGImageRef cgImage = [image CGImageForProposedRect:&rect context:nil hints:nil];
return QtMac::fromCGImageRef(cgImage);
}
return QPixmap();
}
}
void overrideDockClickHandler(bool (*dockClickHandler)(id, SEL, ...))
{
NSApplication *appInst = [NSApplication sharedApplication];
if (!appInst)
return;
Class delClass = [[appInst delegate] class];
SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
if (class_getInstanceMethod(delClass, shouldHandle)) {
if (class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:"))
qDebug("Registered dock click handler (replaced original method)");
else
qWarning("Failed to replace method for dock click handler");
}
else {
if (class_addMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:"))
qDebug("Registered dock click handler");
else
qWarning("Failed to register dock click handler");
}
}

View file

@ -31,8 +31,6 @@
#include "mainwindow.h"
#ifdef Q_OS_MAC
#include <objc/objc.h>
#include <objc/message.h>
#include <QtMacExtras>
#include <QtMac>
#endif
@ -107,7 +105,11 @@
#include "hidabletabwidget.h"
#include "ui_mainwindow.h"
#ifdef Q_OS_MAC
#if defined (Q_OS_MAC)
#include "macutilities.h"
#endif
#if defined (Q_OS_MAC)
void qt_mac_set_dock_menu(QMenu *menu);
#endif
@ -1294,29 +1296,9 @@ static bool dockClickHandler(id self, SEL cmd, ...)
}
void MainWindow::setupDockClickHandler()
{
Class cls = objc_getClass("NSApplication");
objc_object *appInst = objc_msgSend(reinterpret_cast<objc_object *>(cls), sel_registerName("sharedApplication"));
if (!appInst)
return;
{
dockMainWindowHandle = this;
objc_object* delegate = objc_msgSend(appInst, sel_registerName("delegate"));
Class delClass = reinterpret_cast<Class>(objc_msgSend(delegate, sel_registerName("class")));
SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
if (class_getInstanceMethod(delClass, shouldHandle)) {
if (class_replaceMethod(delClass, shouldHandle, reinterpret_cast<IMP>(dockClickHandler), "B@:"))
qDebug("Registered dock click handler (replaced original method)");
else
qWarning("Failed to replace method for dock click handler");
}
else {
if (class_addMethod(delClass, shouldHandle, reinterpret_cast<IMP>(dockClickHandler), "B@:"))
qDebug("Registered dock click handler");
else
qWarning("Failed to register dock click handler");
}
overrideDockClickHandler(dockClickHandler);
}
#endif

View file

@ -32,14 +32,12 @@
#include <QFileIconProvider>
#include <QFileInfo>
#include <QIcon>
#include <QMap>
#if defined(Q_OS_WIN)
#include <Windows.h>
#include <Shellapi.h>
#include <QtWin>
#elif defined(Q_OS_MAC)
#include <objc/objc.h>
#include <objc/message.h>
#else
#include <QMimeDatabase>
#include <QMimeType>
@ -52,13 +50,8 @@
#include "torrentcontentmodelitem.h"
#include "torrentcontentmodelfolder.h"
#include "torrentcontentmodelfile.h"
#ifdef Q_OS_MAC
struct NSImage;
// This function is a private QtGui library export on macOS
// See src/gui/painting/qcoregraphics_p.h for more details
// QtMac::fromCGImageRef takes a CGImageRef and thus requires a double conversion
QPixmap qt_mac_toQPixmap(const NSImage *image, const QSizeF &size);
#if defined(Q_OS_MAC)
#include "macutilities.h"
#endif
namespace
@ -113,31 +106,23 @@ namespace
{
const QString ext = info.suffix();
if (!ext.isEmpty()) {
const QPixmap pixmap = pixmapForExtension(ext, QSize(32, 32));
if (!pixmap.isNull())
return QIcon(pixmap);
auto cacheIter = m_iconCache.find(ext);
if (cacheIter != m_iconCache.end())
return *cacheIter;
QIcon icon = QIcon(pixmapForExtension(ext, QSize(32, 32)));
if (!icon.isNull()) {
m_iconCache.insert(ext, icon);
return icon;
}
}
return UnifiedFileIconProvider::icon(info);
}
private:
QPixmap pixmapForExtension(const QString &ext, const QSize &size) const
{
QMacAutoReleasePool pool;
objc_object *woskspaceCls = reinterpret_cast<objc_object *>(objc_getClass("NSWorkspace"));
SEL sharedWorkspaceSel = sel_registerName("sharedWorkspace");
SEL iconForFileTypeSel = sel_registerName("iconForFileType:");
objc_object *sharedWorkspace = objc_msgSend(woskspaceCls, sharedWorkspaceSel);
if (sharedWorkspace) {
objc_object *image = objc_msgSend(sharedWorkspace, iconForFileTypeSel, ext.toNSString());
if (image)
return qt_mac_toQPixmap(reinterpret_cast<NSImage *>(image), size);
}
return QPixmap();
}
mutable QMap<QString, QIcon> m_iconCache;
};
#else
/**