Skip to content

Commit

Permalink
Fixed mac specific compiler errors and cleaned up Objective C code
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
briankendall committed Aug 12, 2017
1 parent 6f0d16b commit 62b9569
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 56 deletions.
2 changes: 1 addition & 1 deletion macxconf.pri
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/base/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
5 changes: 5 additions & 0 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions src/gui/gui.pri
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
39 changes: 39 additions & 0 deletions src/gui/macutilities.h
Original file line number Diff line number Diff line change
@@ -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 changes: 71 additions & 0 deletions src/gui/macutilities.mm
Original file line number Diff line number Diff line change
@@ -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");
}
}
32 changes: 7 additions & 25 deletions src/gui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@
#include "mainwindow.h"

#ifdef Q_OS_MAC
#include <objc/objc.h>
#include <objc/message.h>
#include <QtMacExtras>
#include <QtMac>
#endif
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
43 changes: 14 additions & 29 deletions src/gui/torrentcontentmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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
Expand Down Expand Up @@ -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
/**
Expand Down

0 comments on commit 62b9569

Please sign in to comment.