From dd3182ad7089053c726e79e15d21e9ce09e0a5ab Mon Sep 17 00:00:00 2001 From: John Maguire Date: Fri, 23 Jul 2010 13:46:30 +0000 Subject: [PATCH] Messy mac device listing code using three different APIs. At least the IOKit one will probably go away. --- src/CMakeLists.txt | 8 +- src/devices/devicelister.h | 2 +- src/devices/devicemanager.cpp | 7 + src/devices/macdevicelister.h | 55 ++++++++ src/devices/macdevicelister.mm | 227 +++++++++++++++++++++++++++++++++ 5 files changed, 296 insertions(+), 3 deletions(-) create mode 100644 src/devices/macdevicelister.h create mode 100644 src/devices/macdevicelister.mm diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b6bd43001..08b5025b9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -409,6 +409,8 @@ endif(HAVE_GSTREAMER) if(APPLE) list(APPEND SOURCES widgets/osd_mac.mm) list(APPEND SOURCES core/macglobalshortcutbackend.mm) + list(APPEND SOURCES devices/macdevicelister.mm) + list(APPEND HEADERS devices/macdevicelister.h) list(APPEND SOURCES ui/macsystemtrayicon.mm) list(APPEND HEADERS core/macglobalshortcutbackend.h) list(APPEND HEADERS ui/macsystemtrayicon.h) @@ -562,9 +564,11 @@ if (APPLE) ${GROWL} ${SPARKLE} z - /System/Library/Frameworks/Carbon.framework - /System/Library/Frameworks/Foundation.framework /System/Library/Frameworks/AppKit.framework + /System/Library/Frameworks/Carbon.framework + /System/Library/Frameworks/DiskArbitration.framework + /System/Library/Frameworks/Foundation.framework + /System/Library/Frameworks/IOKit.framework ) include_directories(${SPARKLE}/Headers) else (APPLE) diff --git a/src/devices/devicelister.h b/src/devices/devicelister.h index 07bc63b0f..78d0c11ca 100644 --- a/src/devices/devicelister.h +++ b/src/devices/devicelister.h @@ -30,7 +30,7 @@ class DeviceLister : public QObject { public: DeviceLister(); - ~DeviceLister(); + virtual ~DeviceLister(); // Tries to start the thread and initialise the engine. This object will be // moved to the new thread. diff --git a/src/devices/devicemanager.cpp b/src/devices/devicemanager.cpp index 84cf2e609..13814108c 100644 --- a/src/devices/devicemanager.cpp +++ b/src/devices/devicemanager.cpp @@ -26,6 +26,10 @@ #include "core/utilities.h" #include "ui/iconloader.h" +#ifdef Q_OS_DARWIN +#include "macdevicelister.h" +#endif + #include #include #include @@ -158,6 +162,9 @@ DeviceManager::DeviceManager(BackgroundThread* database, #ifdef HAVE_GIO AddLister(new GioLister); #endif +#ifdef Q_OS_DARWIN + AddLister(new MacDeviceLister); +#endif AddDeviceClass(); diff --git a/src/devices/macdevicelister.h b/src/devices/macdevicelister.h new file mode 100644 index 000000000..7e5f7a029 --- /dev/null +++ b/src/devices/macdevicelister.h @@ -0,0 +1,55 @@ +#ifndef MACDEVICELISTER_H +#define MACDEVICELISTER_H + +#include "devicelister.h" + +#include + +#include +#include +#include + +#include + +class MacDeviceListerPrivate; + +class MacDeviceLister : public DeviceLister { + Q_OBJECT + public: + MacDeviceLister(); + ~MacDeviceLister(); + + virtual QStringList DeviceUniqueIDs(); + virtual QStringList DeviceIcons(const QString& id); + virtual QString DeviceManufacturer(const QString& id); + virtual QString DeviceModel(const QString& id); + virtual quint64 DeviceCapacity(const QString& id); + virtual quint64 DeviceFreeSpace(const QString& id); + virtual QVariantMap DeviceHardwareInfo(const QString& id); + virtual QString MakeFriendlyName(const QString& id); + virtual QUrl MakeDeviceUrl(const QString& id); + + private: + virtual void Init(); + + bool AddNotification( + const io_name_t type, + const char* class_name, + IOServiceMatchingCallback callback); + + static void DeviceAddedCallback(void* refcon, io_iterator_t it); + static void DeviceRemovedCallback(void* refcon, io_iterator_t it); + + static void StorageAddedCallback(void* refcon, io_iterator_t it); + + static void DiskAddedCallback(DADiskRef disk, void* context); + static void DiskRemovedCallback(DADiskRef disk, void* context); + + static DADissenterRef DiskMountCallback(DADiskRef disk, void* context); + + IONotificationPortRef notification_port_; + + boost::scoped_ptr p_; +}; + +#endif diff --git a/src/devices/macdevicelister.mm b/src/devices/macdevicelister.mm new file mode 100644 index 000000000..05fd968cd --- /dev/null +++ b/src/devices/macdevicelister.mm @@ -0,0 +1,227 @@ +#include "macdevicelister.h" + +#include +#include +#include +#include +#include + +#import +#import +#import + +#include + +#include +#include + +@interface NotificationTarget :NSObject { + +} + +- (void) mediaMounted: (NSNotification*) notification; +- (void) mediaUnmounted: (NSNotification*) notification; + +@end + +@implementation NotificationTarget + +- (id) init { + qDebug() << Q_FUNC_INFO; + if ((self = [super init])) { + [[[NSWorkspace sharedWorkspace] notificationCenter] + addObserver:self + selector:@selector(mediaMounted:) + name:NSWorkspaceDidMountNotification + object:[NSWorkspace sharedWorkspace]]; + + [[[NSWorkspace sharedWorkspace] notificationCenter] + addObserver:self + selector:@selector(mediaUnmounted:) + name:NSWorkspaceDidUnmountNotification + object:[NSWorkspace sharedWorkspace]]; + } + return self; +} + +- (void) mediaMounted: (NSNotification*) notification { + NSString* path = [[notification userInfo] objectForKey:@"NSDevicePath"]; + qDebug() << Q_FUNC_INFO << QString::fromUtf8([path UTF8String]); +} + +- (void) mediaUnmounted: (NSNotification*) notification { + NSString* path = [[notification userInfo] objectForKey:@"NSDevicePath"]; + qDebug() << Q_FUNC_INFO << QString::fromUtf8([path UTF8String]); +} + +@end + + +class MacDeviceListerPrivate { + public: + MacDeviceListerPrivate() { + target_ = [[NotificationTarget alloc] init]; + } + + private: + NotificationTarget* target_; +}; + + +MacDeviceLister::MacDeviceLister() : p_(new MacDeviceListerPrivate) { +} + +MacDeviceLister::~MacDeviceLister() { + qDebug() << Q_FUNC_INFO; +} + +void MacDeviceLister::Init() { + qDebug() << Q_FUNC_INFO; + + notification_port_ = IONotificationPortCreate(kIOMasterPortDefault); + CFRunLoopSourceRef loop_source = + IONotificationPortGetRunLoopSource(notification_port_); + + CFRunLoopRef run_loop = CFRunLoopGetCurrent(); + CFRunLoopAddSource(run_loop, loop_source, kCFRunLoopDefaultMode); + + AddNotification( + kIOFirstMatchNotification, + kIOUSBDeviceClassName, + &DeviceAddedCallback); + AddNotification( + kIOTerminatedNotification, + kIOUSBDeviceClassName, + &DeviceRemovedCallback); + + AddNotification( + kIOFirstMatchNotification, + kIOBlockStorageDeviceClass, + &StorageAddedCallback); + + + DASessionRef da_session = DASessionCreate(kCFAllocatorDefault); + DARegisterDiskAppearedCallback( + da_session, NULL, &DiskAddedCallback, reinterpret_cast(this)); + DARegisterDiskDisappearedCallback( + da_session, NULL, &DiskRemovedCallback, reinterpret_cast(this)); + DAApprovalSessionRef approval_session = DAApprovalSessionCreate(kCFAllocatorDefault); + DARegisterDiskMountApprovalCallback( + approval_session, NULL, &DiskMountCallback, reinterpret_cast(this)); + DASessionScheduleWithRunLoop(da_session, run_loop, kCFRunLoopDefaultMode); + DAApprovalSessionScheduleWithRunLoop(approval_session, run_loop, kCFRunLoopDefaultMode); + CFRelease(da_session); + CFRelease(approval_session); + + + qDebug() << "STARTING LOOP"; + CFRunLoopRun(); + qDebug() << "ENDING LOOP"; +} + +bool MacDeviceLister::AddNotification( + const io_name_t type, + const char* class_name, + IOServiceMatchingCallback callback) { + CFMutableDictionaryRef matching_dict = IOServiceMatching(class_name); + io_iterator_t it; + kern_return_t ret = IOServiceAddMatchingNotification( + notification_port_, + type, + matching_dict, + callback, + reinterpret_cast(this), + &it); + if (ret != KERN_SUCCESS) { + return false; + } + + while (IOIteratorNext(it)); + return true; +} + +void MacDeviceLister::DeviceAddedCallback(void* refcon, io_iterator_t it) { + qDebug() << Q_FUNC_INFO; + + io_object_t object; + while ((object = IOIteratorNext(it))) { + io_name_t class_name; + IOObjectGetClass(object, class_name); + qDebug() << class_name; + + IOObjectRelease(object); + } +} + +void MacDeviceLister::DeviceRemovedCallback(void* refcon, io_iterator_t it) { + qDebug() << Q_FUNC_INFO; + while (IOIteratorNext(it)); +} + +void MacDeviceLister::StorageAddedCallback(void* refcon, io_iterator_t it) { + qDebug() << Q_FUNC_INFO; + + io_object_t object; + while ((object = IOIteratorNext(it))) { + io_name_t class_name; + IOObjectGetClass(object, class_name); + qDebug() << class_name; + + io_iterator_t registry_it; + kern_return_t ret = IORegistryEntryGetParentEntry( + object, kIOServicePlane, ®istry_it); + + io_object_t registry_entry; + while ((registry_entry = IOIteratorNext(registry_it))) { + io_name_t name; + IORegistryEntryGetName(registry_entry, name); + qDebug() << name; + + IOObjectRelease(registry_entry); + } + + + IOObjectRelease(object); + } +} + +void MacDeviceLister::DiskAddedCallback(DADiskRef disk, void* context) { + qDebug() << Q_FUNC_INFO; + + io_service_t service = DADiskCopyIOMedia(disk); + io_iterator_t registry_it; + IORegistryEntryGetParentEntry( + service, kIOServicePlane, ®istry_it); + + io_object_t registry_entry; + while ((registry_entry = IOIteratorNext(registry_it))) { + io_name_t name; + IORegistryEntryGetName(registry_entry, name); + qDebug() << name; + + IOObjectRelease(registry_entry); + } + + qDebug() << DADiskGetBSDName(disk); + + IOObjectRelease(service); +} + +void MacDeviceLister::DiskRemovedCallback(DADiskRef, void* context) { + qDebug() << Q_FUNC_INFO; +} + +DADissenterRef MacDeviceLister::DiskMountCallback(DADiskRef disk, void* context) { + qDebug() << Q_FUNC_INFO << DADiskGetBSDName(disk); + return NULL; +} + +QStringList MacDeviceLister::DeviceUniqueIDs(){return QStringList();} +QStringList MacDeviceLister::DeviceIcons(const QString& id){return QStringList();} +QString MacDeviceLister::DeviceManufacturer(const QString& id){return QString();} +QString MacDeviceLister::DeviceModel(const QString& id){return QString();} +quint64 MacDeviceLister::DeviceCapacity(const QString& id){return 0;} +quint64 MacDeviceLister::DeviceFreeSpace(const QString& id){return 0;} +QVariantMap MacDeviceLister::DeviceHardwareInfo(const QString& id){return QVariantMap();} +QString MacDeviceLister::MakeFriendlyName(const QString& id){return QString();} +QUrl MacDeviceLister::MakeDeviceUrl(const QString& id){return QUrl();}