qtmobility/src/systeminfo/qsysteminfo_mac.mm
changeset 14 6fbed849b4f4
parent 11 06b8e2af4411
--- a/qtmobility/src/systeminfo/qsysteminfo_mac.mm	Fri Jun 11 14:26:25 2010 +0300
+++ b/qtmobility/src/systeminfo/qsysteminfo_mac.mm	Wed Jun 23 19:08:38 2010 +0300
@@ -123,6 +123,7 @@
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 
+
 static QString stringFromCFString(CFStringRef value) {
     QString retVal;
     if(CFStringGetLength(value) > 1) {
@@ -306,6 +307,8 @@
 
 QTM_BEGIN_NAMESPACE
 
+Q_GLOBAL_STATIC(QSystemDeviceInfoPrivate, qsystemDeviceInfoPrivate)
+
 QSystemInfoPrivate *QSystemInfoPrivate::self = 0;
 
 QSystemInfoPrivate::QSystemInfoPrivate(QObject *parent)
@@ -319,7 +322,6 @@
 {
     if(langloopThread->isRunning()) {
         langloopThread->quit();
-        langloopThread->wait();
     }
 }
 
@@ -523,7 +525,10 @@
 }
 
 #ifdef MAC_SDK_10_6
+QtMLangListener *langListener;
 #endif
+
+
 QLangLoopThread::QLangLoopThread(QObject *parent)
     :QThread(parent)
 {
@@ -537,7 +542,12 @@
 {
     mutex.lock();
     keepRunning = false;
+    CFRunLoopStop(CFRunLoopGetCurrent());
+#ifdef MAC_SDK_10_6
+    [langListener release];
+#endif
     mutex.unlock();
+    wait();
 }
 
 void QLangLoopThread::run()
@@ -548,8 +558,7 @@
     mutex.unlock();
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
-    QtMLangListener *listener;
-    listener = [[QtMLangListener alloc] init];
+    langListener = [[QtMLangListener alloc] init];
 
     NSDate *loopUntil = [NSDate dateWithTimeIntervalSinceNow:1.0];
     while (keepRunning &&
@@ -571,18 +580,24 @@
 
 QRunLoopThread::~QRunLoopThread()
 {
-#ifdef MAC_SDK_10_6
-    [listener dealloc];
-#endif
 }
 
-void QRunLoopThread::quit()
+void QRunLoopThread::stop()
 {
-    CFRelease(runloopSource);
     mutex.lock();
     keepRunning = false;
     mutex.unlock();
-    CFRelease(storeSession);
+#ifdef MAC_SDK_10_6
+    [listener release];
+    [delegate release];
+#endif
+    if(currentThread() != this) {
+        QMetaObject::invokeMethod(this, "quit",
+                                  Qt::QueuedConnection);
+    } else {
+        quit();
+    }
+    wait();
 }
 
 
@@ -600,11 +615,11 @@
 
     listener = [[QtMNSListener alloc] init];
 
-    NSDate *loopUntil = [NSDate dateWithTimeIntervalSinceNow:1.0];
+    SInt32 result;
     while (keepRunning &&
-        [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate: loopUntil]) {
-        loopUntil = [NSDate dateWithTimeIntervalSinceNow:1.0];
+           (result = CFRunLoopRunInMode(kCFRunLoopDefaultMode ,5, YES))) {
     }
+    CFRunLoopStop(CFRunLoopGetCurrent());
     [pool release];
 #endif
 }
@@ -687,16 +702,161 @@
     }
 
     CFRunLoopAddSource(CFRunLoopGetCurrent(), runloopSource, kCFRunLoopDefaultMode);
+    CFRelease(runloopSource);
+    CFRelease(storeSession);
     return;
 }
 
 
+static bool isBtPowerOn()
+{
+    //depreciated yes, but what's the replacement?
+    BluetoothHCIPowerState powerState;
+    IOBluetoothLocalDeviceGetPowerState(&powerState);
+    if(powerState == kBluetoothHCIPowerStateON)
+        return true;
+    return false;
+}
+
+void btPowerStateChange(void *ref, io_service_t /*service*/, natural_t messageType, void */*info*/)
+{
+    QBluetoothListenerThread * thread = reinterpret_cast< QBluetoothListenerThread *>(ref);
+    switch (messageType) {
+    case kIOMessageDeviceWillPowerOff:
+        {
+            if(!isBtPowerOn())
+                thread->emitBtPower(false);
+        }
+        break;
+    case kIOMessageDeviceHasPoweredOn:
+        {
+            if(isBtPowerOn())
+                thread->emitBtPower(true);
+        }
+        break;
+    }
+}
+
+QBluetoothListenerThread::QBluetoothListenerThread(QObject *parent)
+    :QThread(parent)
+{
+    setTerminationEnabled(true);
+}
+
+QBluetoothListenerThread::~QBluetoothListenerThread()
+{
+    if(isRunning()) {
+        terminate();
+        wait();
+    }
+}
+
+void QBluetoothListenerThread::stop()
+{
+    mutex.lock();
+    keepRunning = false;
+    mutex.unlock();
+
+    if(CFRunLoopContainsSource(rl,rls,kCFRunLoopDefaultMode)) {
+        CFRunLoopRemoveSource(rl,
+                              rls,
+                              kCFRunLoopDefaultMode);
+        CFRunLoopStop(rl);
+    }
+    if(currentThread() != this) {
+        QMetaObject::invokeMethod(this, "quit",
+                                  Qt::QueuedConnection);
+    } else {
+        quit();
+    }
+    mutex.lock();
+    IONotificationPortDestroy(port);
+    mutex.unlock();
+}
+
+void QBluetoothListenerThread::run()
+{
+#ifdef MAC_SDK_10_6
+    mutex.lock();
+    keepRunning = true;
+    mutex.unlock();
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+    io_object_t notifyObject;
+    io_service_t bluetoothservice;
+
+    io_iterator_t ioIterator;
+    mach_port_t masterPort;
+    CFMutableDictionaryRef serviceMatchDict;
+
+    if (0 != IOMasterPort(MACH_PORT_NULL, &masterPort)) {
+        qDebug() << "IOMasterPort failed";
+    }
+
+    serviceMatchDict = IOServiceMatching("IOBluetoothHCIController");
+    if (NULL == serviceMatchDict) {
+        qDebug() << "IOServiceMatching failed";
+    }
+
+    if (0 != IOServiceGetMatchingServices(masterPort, serviceMatchDict, &ioIterator)) {
+        qDebug() << "IOServiceGetMatchingServices failed";
+    }
+
+    IOReturn ret;
+
+    bluetoothservice = IOIteratorNext(ioIterator);
+    if (0 == bluetoothservice) {
+        IOObjectRelease(ioIterator);
+        qDebug() << "IOIteratorNext failed";
+    }
+    IOObjectRelease(ioIterator);
+
+    port = IONotificationPortCreate(masterPort);
+    if (0 == port) {
+        qDebug() << "IONotificationPortCreate failed";
+    }
+
+    ret = IOServiceAddInterestNotification(port, bluetoothservice,
+                                           kIOGeneralInterest, btPowerStateChange,
+                                           this, &notifyObject);
+    if(ret != kIOReturnSuccess) {
+        qDebug() << "IOServiceAddInterestNotification failed";
+        return;
+    }
+
+    rl = CFRunLoopGetCurrent();
+    rls = IONotificationPortGetRunLoopSource(port);
+
+    CFRunLoopAddSource(rl,
+                       rls,
+                       kCFRunLoopDefaultMode);
+    SInt32 result;
+    while (keepRunning &&
+           (result = CFRunLoopRunInMode(kCFRunLoopDefaultMode ,1, NO))) {
+    }
+
+    CFRunLoopStop(rl);
+
+    IOObjectRelease(bluetoothservice);
+    CFRunLoopRemoveSource(rl,
+                          rls,
+                          kCFRunLoopDefaultMode);
+    [pool release];
+#endif
+}
+
+void QBluetoothListenerThread::emitBtPower(bool b)
+{
+    Q_EMIT bluetoothPower(b);
+}
+
+
 QSystemNetworkInfoPrivate::QSystemNetworkInfoPrivate(QObject *parent)
         : QObject(parent), signalStrengthCache(0)
 {
      defaultInterface = "";
     qRegisterMetaType<QSystemNetworkInfo::NetworkMode>("QSystemNetworkInfo::NetworkMode");
     qRegisterMetaType<QSystemNetworkInfo::NetworkStatus>("QSystemNetworkInfo::NetworkStatus");
+
 #ifdef MAC_SDK_10_6
 if([[CWInterface supportedInterfaces] count] > 0 ) {
         hasWifi = true;
@@ -715,9 +875,7 @@
 {
 #ifdef MAC_SDK_10_6
     if(hasWifi && runloopThread->isRunning()) {
-        runloopThread->quit();
-        runloopThread->wait();
-        [delegate release];
+        runloopThread->stop();
     }
 #endif
 }
@@ -1377,8 +1535,6 @@
     return drivesList;
 }
 
-QSystemDeviceInfoPrivate *QSystemDeviceInfoPrivate::self = 0;
-
 void powerInfoChanged(void* runLoopInfo)
 {
     Q_UNUSED(runLoopInfo)
@@ -1387,24 +1543,52 @@
 }
 
 QSystemDeviceInfoPrivate::QSystemDeviceInfoPrivate(QObject *parent)
-        : QObject(parent)
+        : QObject(parent),btThread(0)
 {
     batteryLevelCache = 0;
     currentPowerStateCache = QSystemDeviceInfo::UnknownPower;
     batteryStatusCache = QSystemDeviceInfo::NoBatteryLevel;
-    CFRunLoopSourceRef runLoopSource = (CFRunLoopSourceRef)IOPSNotificationCreateRunLoopSource(powerInfoChanged, this);
-    if (runLoopSource) {
-        CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
-        CFRelease(runLoopSource);
-    }
-    if(!self)
-        self = this;
 }
 
 QSystemDeviceInfoPrivate::~QSystemDeviceInfoPrivate()
 {
+    btThread->stop();
 }
 
+QSystemDeviceInfoPrivate *QSystemDeviceInfoPrivate::instance()
+{
+    return qsystemDeviceInfoPrivate();
+}
+
+void QSystemDeviceInfoPrivate::connectNotify(const char *signal)
+{
+    if (QLatin1String(signal) == SIGNAL(bluetoothStateChanged(bool))) {
+        if(!btThread) {
+            btThread = new QBluetoothListenerThread(this);
+            btThread->start();
+            connect(btThread,SIGNAL(bluetoothPower(bool)), this, SIGNAL(bluetoothStateChanged(bool)));
+        }
+    }
+
+    if (QLatin1String(signal) == SIGNAL(powerStateChanged(QSystemDeviceInfo::PowerState))) {
+        CFRunLoopSourceRef runLoopSource = (CFRunLoopSourceRef)IOPSNotificationCreateRunLoopSource(powerInfoChanged, this);
+        if (runLoopSource) {
+            CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
+            CFRelease(runLoopSource);
+        }
+    }
+}
+
+void QSystemDeviceInfoPrivate::disconnectNotify(const char *signal)
+{
+    if (QLatin1String(signal) == SIGNAL(bluetoothStateChanged(bool))) {
+        if(btThread->isRunning()) {
+            btThread->stop();
+        }
+    }
+}
+
+
 QSystemDeviceInfo::Profile QSystemDeviceInfoPrivate::currentProfile()
 {
     return QSystemDeviceInfo::UnknownProfile;