diff --git a/src/plugins/qt4projectmanager/qt-s60/s60deployconfigurationwidget.cpp b/src/plugins/qt4projectmanager/qt-s60/s60deployconfigurationwidget.cpp index a7f8d813e45..ffea34bb732 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60deployconfigurationwidget.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60deployconfigurationwidget.cpp @@ -269,8 +269,8 @@ QWidget *S60DeployConfigurationWidget::createCommunicationChannel() serialPortHBoxLayout->addWidget(m_serialPortsCombo); serialPortHBoxLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored)); -#ifndef Q_OS_WIN - // Update device list: on Linux only. +#if !defined(Q_OS_WIN) && !defined(Q_OS_MACX) + // Update device list: only needed on linux. QToolButton *updateSerialDevicesButton(new QToolButton); updateSerialDevicesButton->setIcon(qApp->style()->standardIcon(QStyle::SP_BrowserReload)); connect(updateSerialDevicesButton, SIGNAL(clicked()), diff --git a/src/shared/symbianutils/symbiandevicemanager.cpp b/src/shared/symbianutils/symbiandevicemanager.cpp index a92d60dfafd..8ef371d24c9 100644 --- a/src/shared/symbianutils/symbiandevicemanager.cpp +++ b/src/shared/symbianutils/symbiandevicemanager.cpp @@ -49,6 +49,17 @@ #include #include +#ifdef Q_OS_MACX +#include +#include +#include +#include +#if defined(MAC_OS_X_VERSION_10_3) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3) +#include +#endif +#include +#endif + namespace SymbianUtils { enum { debug = 0 }; @@ -266,7 +277,14 @@ SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDevice &cd) // ------------- SymbianDeviceManagerPrivate struct SymbianDeviceManagerPrivate { - SymbianDeviceManagerPrivate() : m_initialized(false), m_devicesLock(QMutex::Recursive) {} + SymbianDeviceManagerPrivate() : + m_initialized(false), + m_devicesLock(QMutex::Recursive) + { +#ifdef Q_OS_MACX + m_deviceListChangedNotification = 0; +#endif + } bool m_initialized; SymbianDeviceManager::SymbianDeviceList m_devices; @@ -274,6 +292,9 @@ struct SymbianDeviceManagerPrivate { // The following 2 variables are needed to manage requests for a CODA port not coming from the main thread int m_constructCodaPortEventType; QMutex m_codaPortWaitMutex; +#ifdef Q_OS_MACX + IONotificationPortRef m_deviceListChangedNotification; +#endif }; class QConstructCodaPortEvent : public QEvent @@ -298,6 +319,10 @@ SymbianDeviceManager::SymbianDeviceManager(QObject *parent) : SymbianDeviceManager::~SymbianDeviceManager() { +#ifdef Q_OS_MACX + if (d && d->m_deviceListChangedNotification) + IONotificationPortDestroy(d->m_deviceListChangedNotification); +#endif delete d; } @@ -551,10 +576,30 @@ void SymbianDeviceManager::update(bool emitSignals) qDebug("(result.data())); + return result; +} + +void deviceListChanged(void *refCon, io_iterator_t iter) +{ + // The way we're structured, it's easier to rescan rather than take advantage of the finer-grained device addition and removal info that OS X gives us + io_object_t obj; + while ((obj = IOIteratorNext(iter))) IOObjectRelease(obj); + static_cast(refCon)->update(); +} + +#endif + SymbianDeviceManager::SymbianDeviceList SymbianDeviceManager::serialPorts() const { SymbianDeviceList rc; -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) const QSettings registry(REGKEY_CURRENT_CONTROL_SET, QSettings::NativeFormat); const QString usbSerialRootKey = QLatin1String(USBSER) + QLatin1Char('/'); const int count = registry.value(usbSerialRootKey + QLatin1String("Count")).toInt(); @@ -575,6 +620,100 @@ SymbianDeviceManager::SymbianDeviceList SymbianDeviceManager::serialPorts() cons rc.append(SymbianDevice(device.take())); } } +#elif defined(Q_OS_MACX) + CFMutableDictionaryRef classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue); + if (!classesToMatch) return rc; + + CFDictionarySetValue(classesToMatch, + CFSTR(kIOSerialBSDTypeKey), + CFSTR(kIOSerialBSDAllTypes)); + + // Setup notifier if necessary + if (d->m_deviceListChangedNotification == 0) { + d->m_deviceListChangedNotification = IONotificationPortCreate(kIOMasterPortDefault); + if (d->m_deviceListChangedNotification) { + CFRunLoopSourceRef runloopSource = IONotificationPortGetRunLoopSource(d->m_deviceListChangedNotification); + CFRunLoopAddSource(CFRunLoopGetCurrent(), runloopSource, kCFRunLoopDefaultMode); + // IOServiceAddMatchingNotification eats a reference each time we call it, so make sure it's still valid for the IOServiceGetMatchingServices later + CFRetain(classesToMatch); + CFRetain(classesToMatch); + io_iterator_t devicesAddedIterator; + io_iterator_t devicesRemovedIterator; + IOServiceAddMatchingNotification(d->m_deviceListChangedNotification, kIOMatchedNotification, classesToMatch, &deviceListChanged, (void*)this, &devicesAddedIterator); + IOServiceAddMatchingNotification(d->m_deviceListChangedNotification, kIOTerminatedNotification, classesToMatch, &deviceListChanged, (void*)this, &devicesRemovedIterator); + // Arm the iterators - we're not interested in the lists at this point, and the API rather expects that we will be + io_object_t obj; + while ((obj = IOIteratorNext(devicesAddedIterator))) IOObjectRelease(obj); + while ((obj = IOIteratorNext(devicesRemovedIterator))) IOObjectRelease(obj); + } + } + io_iterator_t matchingServices; + kern_return_t kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatch, &matchingServices); + if (kernResult != KERN_SUCCESS) { + if (debug) + qDebug("IOServiceGetMatchingServices returned %d", kernResult); + return rc; + } + + io_object_t serialPort; + kernResult = KERN_FAILURE; + while ((serialPort = IOIteratorNext(matchingServices))) { + // Check if it's Bluetooth or USB, and if so we can apply additional filters to weed out things that definitely aren't valid ports + io_object_t parent, grandparent; + kernResult = IORegistryEntryGetParentEntry(serialPort, kIOServicePlane, &parent); + bool match = true; + DeviceCommunicationType deviceType = SerialPortCommunication; + CFStringRef name = NULL; + if (kernResult == KERN_SUCCESS) { + kernResult = IORegistryEntryGetParentEntry(parent, kIOServicePlane, &grandparent); + if (kernResult == KERN_SUCCESS) { + CFStringRef className = IOObjectCopyClass(grandparent); + if (CFStringCompare(className, CFSTR("IOBluetoothSerialClient"), 0) == 0) { + // CODA doesn't support bluetooth and TRK makes connections back to the PC so we're not going to support it - use CODA :) + match = false; + } + else if (CFStringCompare(className, CFSTR("AppleUSBCDCACMData"), 0) == 0) { + match = false; + CFNumberRef interfaceNumber = (CFNumberRef)IORegistryEntrySearchCFProperty(grandparent, kIOServicePlane, CFSTR(kUSBInterfaceNumber), kCFAllocatorDefault, kIORegistryIterateParents | kIORegistryIterateRecursively); + if (interfaceNumber) { + int val; + if (CFNumberGetValue(interfaceNumber, kCFNumberIntType, &val) && val == 4) match = true; + CFRelease(interfaceNumber); + } + if (match) { + CFStringRef deviceName = (CFStringRef)IORegistryEntrySearchCFProperty(grandparent, kIOServicePlane, CFSTR(kUSBProductString), kCFAllocatorDefault, kIORegistryIterateParents | kIORegistryIterateRecursively); + CFStringRef vendorName = (CFStringRef)IORegistryEntrySearchCFProperty(grandparent, kIOServicePlane, CFSTR(kUSBVendorString), kCFAllocatorDefault, kIORegistryIterateParents | kIORegistryIterateRecursively); + if (deviceName && vendorName) name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ %@"), vendorName, deviceName); + if (deviceName) CFRelease(deviceName); + if (vendorName) CFRelease(vendorName); + } + } + else { + // We don't expect TRK/CODA on any other type of serial port + match = false; + } + CFRelease(className); + IOObjectRelease(grandparent); + } + IOObjectRelease(parent); + } + + if (match) { + CFStringRef devPath = (CFStringRef)IORegistryEntryCreateCFProperty(serialPort, CFSTR(kIODialinDeviceKey), kCFAllocatorDefault, 0); + if (name == NULL) + name = (CFStringRef)IORegistryEntryCreateCFProperty(serialPort, CFSTR(kIOTTYBaseNameKey), kCFAllocatorDefault, 0); + QScopedPointer device(new SymbianDeviceData); + device->type = deviceType; + device->friendlyName = CFStringToQString(name); + device->portName = CFStringToQString(devPath); + + CFRelease(devPath); + CFRelease(name); + rc.append(SymbianDevice(device.take())); + } + IOObjectRelease(serialPort); + } + IOObjectRelease(matchingServices); #endif return rc; } diff --git a/src/shared/symbianutils/symbianutils.pri b/src/shared/symbianutils/symbianutils.pri index 2d32680defa..e71dd6052da 100644 --- a/src/shared/symbianutils/symbianutils.pri +++ b/src/shared/symbianutils/symbianutils.pri @@ -39,3 +39,5 @@ contains(QT, gui) { } else { message(Trk: Console ...) } + +macx:LIBS += -framework IOKit -framework CoreFoundation