diff options
Diffstat (limited to 'src/plugins')
29 files changed, 1189 insertions, 256 deletions
diff --git a/src/plugins/bearer/corewlan/qcorewlanengine.mm b/src/plugins/bearer/corewlan/qcorewlanengine.mm index 7549b4a9f7..b0ed4076da 100644 --- a/src/plugins/bearer/corewlan/qcorewlanengine.mm +++ b/src/plugins/bearer/corewlan/qcorewlanengine.mm @@ -52,23 +52,18 @@ #include <QtCore/qdebug.h> #include <QDir> -#include <CoreWLAN/CoreWLAN.h> -#include <CoreWLAN/CWInterface.h> -#include <CoreWLAN/CWNetwork.h> -#include <CoreWLAN/CWNetwork.h> -#include <CoreWLAN/CW8021XProfile.h> - -#include <Foundation/NSEnumerator.h> -#include <Foundation/NSKeyValueObserving.h> -#include <Foundation/NSAutoreleasePool.h> -#include <Foundation/NSLock.h> - -#include <SystemConfiguration/SCNetworkConfiguration.h> + +extern "C" { // Otherwise it won't find CWKeychain* symbols at link time +#import <CoreWLAN/CoreWLAN.h> +} + #include "private/qcore_mac_p.h" #include <net/if.h> #include <ifaddrs.h> +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_NA) + @interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject { NSNotificationCenter *notificationCenter; @@ -94,7 +89,7 @@ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; notificationCenter = [NSNotificationCenter defaultCenter]; currentInterface = [CWInterface interfaceWithName:nil]; - [notificationCenter addObserver:self selector:@selector(notificationHandler:) name:kCWPowerDidChangeNotification object:nil]; + [notificationCenter addObserver:self selector:@selector(notificationHandler:) name:CWPowerDidChangeNotification object:nil]; [locker unlock]; [autoreleasepool release]; return self; @@ -131,7 +126,7 @@ } @end -QT_MANGLE_NAMESPACE(QNSListener) *listener = 0; +static QT_MANGLE_NAMESPACE(QNSListener) *listener = 0; QT_BEGIN_NAMESPACE @@ -171,33 +166,25 @@ void QScanThread::run() CWInterface *currentInterface = [CWInterface interfaceWithName: QCFString::toNSString(interfaceName)]; mutex.unlock(); - if([currentInterface power]) { + if (currentInterface.powerOn) { NSError *err = nil; - NSDictionary *parametersDict = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithBool:YES], kCWScanKeyMerge, - [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, - [NSNumber numberWithInteger:100], kCWScanKeyRestTime, nil]; - NSArray* apArray = [currentInterface scanForNetworksWithParameters:parametersDict error:&err]; - CWNetwork *apNetwork; + NSSet* apSet = [currentInterface scanForNetworksWithName:nil error:&err]; if (!err) { - - for(uint row=0; row < [apArray count]; row++ ) { - apNetwork = [apArray objectAtIndex:row]; - + for (CWNetwork *apNetwork in apSet) { const QString networkSsid = QCFString::toQString([apNetwork ssid]); const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkSsid)); found.append(id); QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; bool known = isKnownSsid(networkSsid); - if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { + if (currentInterface.serviceActive) { if( networkSsid == QCFString::toQString( [currentInterface ssid])) { state = QNetworkConfiguration::Active; } } - if(state == QNetworkConfiguration::Undefined) { + if (state == QNetworkConfiguration::Undefined) { if(known) { state = QNetworkConfiguration::Discovered; } else { @@ -205,7 +192,7 @@ void QScanThread::run() } } QNetworkConfiguration::Purpose purpose = QNetworkConfiguration::UnknownPurpose; - if([[apNetwork securityMode] intValue] == kCWSecurityModeOpen) { + if ([apNetwork supportsSecurity:kCWSecurityNone]) { purpose = QNetworkConfiguration::PublicPurpose; } else { purpose = QNetworkConfiguration::PrivatePurpose; @@ -235,7 +222,7 @@ void QScanThread::run() interfaceName = ij.value(); } - if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { + if (currentInterface.serviceActive) { if( networkSsid == QCFString::toQString([currentInterface ssid])) { state = QNetworkConfiguration::Active; } @@ -298,14 +285,14 @@ void QScanThread::getUserConfigurations() NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; userProfiles.clear(); - NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; - for(uint row=0; row < [wifiInterfaces count]; row++ ) { + NSSet *wifiInterfaces = [CWInterface interfaceNames]; + for (NSString *ifName in wifiInterfaces) { - CWInterface *wifiInterface = [CWInterface interfaceWithName: [wifiInterfaces objectAtIndex:row]]; - if ( ![wifiInterface power] ) + CWInterface *wifiInterface = [CWInterface interfaceWithName: ifName]; + if (!wifiInterface.powerOn) continue; - NSString *nsInterfaceName = [wifiInterface name]; + NSString *nsInterfaceName = wifiInterface.ssid; // add user configured system networks SCDynamicStoreRef dynRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault, (CFStringRef)@"Qt corewlan", nil, nil); NSDictionary * airportPlist = (NSDictionary *)SCDynamicStoreCopyValue(dynRef, (CFStringRef)[NSString stringWithFormat:@"Setup:/Network/Interface/%@/AirPort", nsInterfaceName]); @@ -314,7 +301,7 @@ void QScanThread::getUserConfigurations() NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"]; NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"]; - for(NSString *ssidkey in thisSsidarray) { + for (NSString *ssidkey in thisSsidarray) { QString thisSsid = QCFString::toQString(ssidkey); if(!userProfiles.contains(thisSsid)) { QMap <QString,QString> map; @@ -442,7 +429,7 @@ void QCoreWlanEngine::initialize() QMutexLocker locker(&mutex); NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; - if([[CWInterface supportedInterfaces] count] > 0 && !listener) { + if ([[CWInterface interfaceNames] count] > 0 && !listener) { listener = [[QT_MANGLE_NAMESPACE(QNSListener) alloc] init]; listener.engine = this; hasWifi = true; @@ -479,135 +466,62 @@ void QCoreWlanEngine::connectToId(const QString &id) CWInterface *wifiInterface = [CWInterface interfaceWithName: QCFString::toNSString(interfaceString)]; - if ([wifiInterface power]) { + if (wifiInterface.powerOn) { NSError *err = nil; - NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0]; - QString wantedSsid; - QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); const QString idHash = QString::number(qHash(QLatin1String("corewlan:") + ptr->name)); const QString idHash2 = QString::number(qHash(QLatin1String("corewlan:") + scanThread->getNetworkNameFromSsid(ptr->name))); - bool using8021X = false; - if (idHash2 != id) { - NSArray *array = [CW8021XProfile allUser8021XProfiles]; - - for (NSUInteger i = 0; i < [array count]; ++i) { - const QString networkNameHashCheck = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString([[array objectAtIndex:i] userDefinedName]))); - - const QString ssidHash = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString([[array objectAtIndex:i] ssid]))); - - if (id == networkNameHashCheck || id == ssidHash) { - const QString thisName = scanThread->getSsidFromNetworkName(id); - if (thisName.isEmpty()) - wantedSsid = id; - else - wantedSsid = thisName; - - [params setValue: [array objectAtIndex:i] forKey:kCWAssocKey8021XProfile]; - using8021X = true; - break; - } + QString wantedNetwork; + QMapIterator<QString, QMap<QString, QString> > i(scanThread->userProfiles); + while (i.hasNext()) { + i.next(); + wantedNetwork = i.key(); + const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork)); + if (id == networkNameHash) { + wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork); + break; } } - if (!using8021X) { - QString wantedNetwork; - QMapIterator<QString, QMap<QString,QString> > i(scanThread->userProfiles); - while (i.hasNext()) { - i.next(); - wantedNetwork = i.key(); - const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork)); - if (id == networkNameHash) { - wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork); - break; - } - } - } - NSDictionary *scanParameters = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithBool:YES], kCWScanKeyMerge, - [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, - [NSNumber numberWithInteger:100], kCWScanKeyRestTime, - QCFString::toNSString(wantedSsid), kCWScanKeySSID, - nil]; - - NSArray *scanArray = [wifiInterface scanForNetworksWithParameters:scanParameters error:&err]; + NSSet *scanSet = [wifiInterface scanForNetworksWithName:QCFString::toNSString(wantedSsid) error:&err]; if(!err) { - for(uint row=0; row < [scanArray count]; row++ ) { - CWNetwork *apNetwork = [scanArray objectAtIndex:row]; - - if(wantedSsid == QCFString::toQString([apNetwork ssid])) { - - if(!using8021X) { - SecKeychainAttribute attributes[3]; - - NSString *account = [apNetwork ssid]; - NSString *keyKind = @"AirPort network password"; - NSString *keyName = account; - - attributes[0].tag = kSecAccountItemAttr; - attributes[0].data = (void *)[account UTF8String]; - attributes[0].length = [account length]; - - attributes[1].tag = kSecDescriptionItemAttr; - attributes[1].data = (void *)[keyKind UTF8String]; - attributes[1].length = [keyKind length]; - - attributes[2].tag = kSecLabelItemAttr; - attributes[2].data = (void *)[keyName UTF8String]; - attributes[2].length = [keyName length]; - - SecKeychainAttributeList attributeList = {3,attributes}; - - SecKeychainSearchRef searchRef; - SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributeList, &searchRef); - - NSString *password = @""; - SecKeychainItemRef searchItem; - - if (SecKeychainSearchCopyNext(searchRef, &searchItem) == noErr) { - UInt32 realPasswordLength; - SecKeychainAttribute attributesW[8]; - attributesW[0].tag = kSecAccountItemAttr; - SecKeychainAttributeList listW = {1,attributesW}; - char *realPassword; - OSStatus status = SecKeychainItemCopyContent(searchItem, NULL, &listW, &realPasswordLength,(void **)&realPassword); - - if (status == noErr) { - if (realPassword != NULL) { - - QByteArray pBuf; - pBuf.resize(realPasswordLength); - pBuf.prepend(realPassword); - pBuf.insert(realPasswordLength,'\0'); - - password = [NSString stringWithUTF8String:pBuf]; - } - SecKeychainItemFreeContent(&listW, realPassword); - } - - CFRelease(searchItem); - } else { - qDebug() << "SecKeychainSearchCopyNext error"; - } - [params setValue: password forKey: kCWAssocKeyPassphrase]; - } // end using8021X - - - bool result = [wifiInterface associateToNetwork: apNetwork parameters:[NSDictionary dictionaryWithDictionary:params] error:&err]; + for (CWNetwork *apNetwork in scanSet) { + CFDataRef ssidData = (CFDataRef)[apNetwork ssidData]; + bool result = false; + + SecIdentityRef identity = 0; + // Check first whether we require IEEE 802.1X authentication for the wanted SSID + if (CWKeychainCopyEAPIdentity(ssidData, &identity) == errSecSuccess) { + CFStringRef username = 0; + CFStringRef password = 0; + if (CWKeychainCopyEAPUsernameAndPassword(ssidData, &username, &password) == errSecSuccess) { + result = [wifiInterface associateToEnterpriseNetwork:apNetwork + identity:identity username:(NSString *)username password:(NSString *)password + error:&err]; + CFRelease(username); + CFRelease(password); + } + CFRelease(identity); + } else { + CFStringRef password = 0; + if (CWKeychainCopyPassword(ssidData, &password) == errSecSuccess) { + result = [wifiInterface associateToNetwork:apNetwork password:(NSString *)password error:&err]; + CFRelease(password); + } + } - if(!err) { - if(!result) { - emit connectionError(id, ConnectError); - } else { - return; - } + if (!err) { + if (!result) { + emit connectionError(id, ConnectError); } else { - qDebug() <<"associate ERROR"<< QCFString::toQString([err localizedDescription ]); + return; } + } else { + qDebug() <<"associate ERROR"<< QCFString::toQString([err localizedDescription ]); } } //end scan network } else { @@ -632,7 +546,7 @@ void QCoreWlanEngine::disconnectFromId(const QString &id) [CWInterface interfaceWithName: QCFString::toNSString(interfaceString)]; [wifiInterface disassociate]; - if ([[wifiInterface interfaceState]intValue] != kCWInterfaceStateInactive) { + if (wifiInterface.serviceActive) { locker.unlock(); emit connectionError(id, DisconnectionError); locker.relock(); @@ -652,9 +566,9 @@ void QCoreWlanEngine::doRequestUpdate() NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; - NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; - for (uint row = 0; row < [wifiInterfaces count]; ++row) { - scanThread->interfaceName = QCFString::toQString([wifiInterfaces objectAtIndex:row]); + NSSet *wifiInterfaces = [CWInterface interfaceNames]; + for (NSString *ifName in wifiInterfaces) { + scanThread->interfaceName = QCFString::toQString(ifName); scanThread->start(); } locker.unlock(); @@ -668,7 +582,7 @@ bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName) if(hasWifi) { NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; CWInterface *defaultInterface = [CWInterface interfaceWithName: QCFString::toNSString(wifiDeviceName)]; - if([defaultInterface power]) { + if (defaultInterface.powerOn) { haswifi = true; } [autoreleasepool release]; @@ -942,3 +856,7 @@ quint64 QCoreWlanEngine::getBytes(const QString &interfaceName, bool b) } QT_END_NAMESPACE + +#else // QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE +#include "qcorewlanengine_10_6.mm" +#endif diff --git a/src/plugins/bearer/corewlan/qcorewlanengine_10_6.mm b/src/plugins/bearer/corewlan/qcorewlanengine_10_6.mm new file mode 100644 index 0000000000..1b95ae29ad --- /dev/null +++ b/src/plugins/bearer/corewlan/qcorewlanengine_10_6.mm @@ -0,0 +1,916 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <SystemConfiguration/SCNetworkConfiguration.h> + +@interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject +{ + NSNotificationCenter *notificationCenter; + CWInterface *currentInterface; + QCoreWlanEngine *engine; + NSLock *locker; +} +- (void)notificationHandler;//:(NSNotification *)notification; +- (void)remove; +- (void)setEngine:(QCoreWlanEngine *)coreEngine; +- (QCoreWlanEngine *)engine; +- (void)dealloc; + +@property (assign) QCoreWlanEngine* engine; + +@end + +@implementation QT_MANGLE_NAMESPACE(QNSListener) + +- (id) init +{ + [locker lock]; + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + notificationCenter = [NSNotificationCenter defaultCenter]; + currentInterface = [CWInterface interfaceWithName:nil]; + [notificationCenter addObserver:self selector:@selector(notificationHandler:) name:kCWPowerDidChangeNotification object:nil]; + [locker unlock]; + [autoreleasepool release]; + return self; +} + +-(void)dealloc +{ + [super dealloc]; +} + +-(void)setEngine:(QCoreWlanEngine *)coreEngine +{ + [locker lock]; + if(!engine) + engine = coreEngine; + [locker unlock]; +} + +-(QCoreWlanEngine *)engine +{ + return engine; +} + +-(void)remove +{ + [locker lock]; + [notificationCenter removeObserver:self]; + [locker unlock]; +} + +- (void)notificationHandler//:(NSNotification *)notification +{ + engine->requestUpdate(); +} +@end + +static QT_MANGLE_NAMESPACE(QNSListener) *listener = 0; + +QT_BEGIN_NAMESPACE + +void networkChangeCallback(SCDynamicStoreRef/* store*/, CFArrayRef changedKeys, void *info) +{ + for ( long i = 0; i < CFArrayGetCount(changedKeys); i++) { + + QString changed = QCFString::toQString((CFStringRef)CFArrayGetValueAtIndex(changedKeys, i)); + if( changed.contains("/Network/Global/IPv4")) { + QCoreWlanEngine* wlanEngine = static_cast<QCoreWlanEngine*>(info); + wlanEngine->requestUpdate(); + } + } + return; +} + + +QScanThread::QScanThread(QObject *parent) + :QThread(parent) +{ +} + +QScanThread::~QScanThread() +{ +} + +void QScanThread::quit() +{ + wait(); +} + +void QScanThread::run() +{ + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + QStringList found; + mutex.lock(); + CWInterface *currentInterface = [CWInterface interfaceWithName: QCFString::toNSString(interfaceName)]; + mutex.unlock(); + + if([currentInterface power]) { + NSError *err = nil; + NSDictionary *parametersDict = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], kCWScanKeyMerge, + [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, + [NSNumber numberWithInteger:100], kCWScanKeyRestTime, nil]; + + NSArray* apArray = [currentInterface scanForNetworksWithParameters:parametersDict error:&err]; + CWNetwork *apNetwork; + + if (!err) { + + for(uint row=0; row < [apArray count]; row++ ) { + apNetwork = [apArray objectAtIndex:row]; + + const QString networkSsid = QCFString::toQString([apNetwork ssid]); + const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkSsid)); + found.append(id); + + QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; + bool known = isKnownSsid(networkSsid); + if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { + if( networkSsid == QCFString::toQString( [currentInterface ssid])) { + state = QNetworkConfiguration::Active; + } + } + if(state == QNetworkConfiguration::Undefined) { + if(known) { + state = QNetworkConfiguration::Discovered; + } else { + state = QNetworkConfiguration::Undefined; + } + } + QNetworkConfiguration::Purpose purpose = QNetworkConfiguration::UnknownPurpose; + if([[apNetwork securityMode] intValue] == kCWSecurityModeOpen) { + purpose = QNetworkConfiguration::PublicPurpose; + } else { + purpose = QNetworkConfiguration::PrivatePurpose; + } + + found.append(foundNetwork(id, networkSsid, state, interfaceName, purpose)); + + } + } + } + // add known configurations that are not around. + QMapIterator<QString, QMap<QString,QString> > i(userProfiles); + while (i.hasNext()) { + i.next(); + + QString networkName = i.key(); + const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkName)); + + if(!found.contains(id)) { + QString networkSsid = getSsidFromNetworkName(networkName); + const QString ssidId = QString::number(qHash(QLatin1String("corewlan:") + networkSsid)); + QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; + QString interfaceName; + QMapIterator<QString, QString> ij(i.value()); + while (ij.hasNext()) { + ij.next(); + interfaceName = ij.value(); + } + + if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { + if( networkSsid == QCFString::toQString([currentInterface ssid])) { + state = QNetworkConfiguration::Active; + } + } + if(state == QNetworkConfiguration::Undefined) { + if( userProfiles.contains(networkName) + && found.contains(ssidId)) { + state = QNetworkConfiguration::Discovered; + } + } + + if(state == QNetworkConfiguration::Undefined) { + state = QNetworkConfiguration::Defined; + } + + found.append(foundNetwork(id, networkName, state, interfaceName, QNetworkConfiguration::UnknownPurpose)); + } + } + emit networksChanged(); + [autoreleasepool release]; +} + +QStringList QScanThread::foundNetwork(const QString &id, const QString &name, const QNetworkConfiguration::StateFlags state, const QString &interfaceName, const QNetworkConfiguration::Purpose purpose) +{ + QStringList found; + QMutexLocker locker(&mutex); + QNetworkConfigurationPrivate *ptr = new QNetworkConfigurationPrivate; + + ptr->name = name; + ptr->isValid = true; + ptr->id = id; + ptr->state = state; + ptr->type = QNetworkConfiguration::InternetAccessPoint; + ptr->bearerType = QNetworkConfiguration::BearerWLAN; + ptr->purpose = purpose; + + fetchedConfigurations.append( ptr); + configurationInterface.insert(ptr->id, interfaceName); + + locker.unlock(); + locker.relock(); + found.append(id); + return found; +} + +QList<QNetworkConfigurationPrivate *> QScanThread::getConfigurations() +{ + QMutexLocker locker(&mutex); + + QList<QNetworkConfigurationPrivate *> foundConfigurations = fetchedConfigurations; + fetchedConfigurations.clear(); + + return foundConfigurations; +} + +void QScanThread::getUserConfigurations() +{ + QMutexLocker locker(&mutex); + + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + userProfiles.clear(); + + NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; + for(uint row=0; row < [wifiInterfaces count]; row++ ) { + + CWInterface *wifiInterface = [CWInterface interfaceWithName: [wifiInterfaces objectAtIndex:row]]; + if ( ![wifiInterface power] ) + continue; + + NSString *nsInterfaceName = [wifiInterface name]; +// add user configured system networks + SCDynamicStoreRef dynRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault, (CFStringRef)@"Qt corewlan", nil, nil); + NSDictionary * airportPlist = (NSDictionary *)SCDynamicStoreCopyValue(dynRef, (CFStringRef)[NSString stringWithFormat:@"Setup:/Network/Interface/%@/AirPort", nsInterfaceName]); + CFRelease(dynRef); + if(airportPlist != nil) { + NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"]; + + NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"]; + for(NSString *ssidkey in thisSsidarray) { + QString thisSsid = QCFString::toQString(ssidkey); + if(!userProfiles.contains(thisSsid)) { + QMap <QString,QString> map; + map.insert(thisSsid, QCFString::toQString(nsInterfaceName)); + userProfiles.insert(thisSsid, map); + } + } + CFRelease(airportPlist); + } + + // 802.1X user profiles + QString userProfilePath = QDir::homePath() + "/Library/Preferences/com.apple.eap.profiles.plist"; + NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile: QCFString::toNSString(userProfilePath)] autorelease]; + if(eapDict != nil) { + NSString *profileStr= @"Profiles"; + NSString *nameStr = @"UserDefinedName"; + NSString *networkSsidStr = @"Wireless Network"; + for (id profileKey in eapDict) { + if ([profileStr isEqualToString:profileKey]) { + NSDictionary *itemDict = [eapDict objectForKey:profileKey]; + for (id itemKey in itemDict) { + + NSInteger dictSize = [itemKey count]; + id objects[dictSize]; + id keys[dictSize]; + + [itemKey getObjects:objects andKeys:keys]; + QString networkName; + QString ssid; + for(int i = 0; i < dictSize; i++) { + if([nameStr isEqualToString:keys[i]]) { + networkName = QCFString::toQString(objects[i]); + } + if([networkSsidStr isEqualToString:keys[i]]) { + ssid = QCFString::toQString(objects[i]); + } + if(!userProfiles.contains(networkName) + && !ssid.isEmpty()) { + QMap<QString,QString> map; + map.insert(ssid, QCFString::toQString(nsInterfaceName)); + userProfiles.insert(networkName, map); + } + } + } + } + } + } + } + [autoreleasepool release]; +} + +QString QScanThread::getSsidFromNetworkName(const QString &name) +{ + QMutexLocker locker(&mutex); + + QMapIterator<QString, QMap<QString,QString> > i(userProfiles); + while (i.hasNext()) { + i.next(); + QMap<QString,QString> map = i.value(); + QMapIterator<QString, QString> ij(i.value()); + while (ij.hasNext()) { + ij.next(); + const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") +i.key())); + if(name == i.key() || name == networkNameHash) { + return ij.key(); + } + } + } + return QString(); +} + +QString QScanThread::getNetworkNameFromSsid(const QString &ssid) +{ + QMutexLocker locker(&mutex); + + QMapIterator<QString, QMap<QString,QString> > i(userProfiles); + while (i.hasNext()) { + i.next(); + QMap<QString,QString> map = i.value(); + QMapIterator<QString, QString> ij(i.value()); + while (ij.hasNext()) { + ij.next(); + if(ij.key() == ssid) { + return i.key(); + } + } + } + return QString(); +} + +bool QScanThread::isKnownSsid(const QString &ssid) +{ + QMutexLocker locker(&mutex); + + QMapIterator<QString, QMap<QString,QString> > i(userProfiles); + while (i.hasNext()) { + i.next(); + QMap<QString,QString> map = i.value(); + if(map.keys().contains(ssid)) { + return true; + } + } + return false; +} + + +QCoreWlanEngine::QCoreWlanEngine(QObject *parent) +: QBearerEngineImpl(parent), scanThread(0) +{ + scanThread = new QScanThread(this); + connect(scanThread, SIGNAL(networksChanged()), + this, SLOT(networksChanged())); +} + +QCoreWlanEngine::~QCoreWlanEngine() +{ + while (!foundConfigurations.isEmpty()) + delete foundConfigurations.takeFirst(); + [listener remove]; + [listener release]; +} + +void QCoreWlanEngine::initialize() +{ + QMutexLocker locker(&mutex); + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + + if([[CWInterface supportedInterfaces] count] > 0 && !listener) { + listener = [[QT_MANGLE_NAMESPACE(QNSListener) alloc] init]; + listener.engine = this; + hasWifi = true; + } else { + hasWifi = false; + } + storeSession = NULL; + + startNetworkChangeLoop(); + [autoreleasepool release]; +} + + +QString QCoreWlanEngine::getInterfaceFromId(const QString &id) +{ + QMutexLocker locker(&mutex); + + return scanThread->configurationInterface.value(id); +} + +bool QCoreWlanEngine::hasIdentifier(const QString &id) +{ + QMutexLocker locker(&mutex); + + return scanThread->configurationInterface.contains(id); +} + +void QCoreWlanEngine::connectToId(const QString &id) +{ + QMutexLocker locker(&mutex); + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + QString interfaceString = getInterfaceFromId(id); + + CWInterface *wifiInterface = + [CWInterface interfaceWithName: QCFString::toNSString(interfaceString)]; + + if ([wifiInterface power]) { + NSError *err = nil; + NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0]; + + QString wantedSsid; + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + + const QString idHash = QString::number(qHash(QLatin1String("corewlan:") + ptr->name)); + const QString idHash2 = QString::number(qHash(QLatin1String("corewlan:") + scanThread->getNetworkNameFromSsid(ptr->name))); + + bool using8021X = false; + if (idHash2 != id) { + NSArray *array = [CW8021XProfile allUser8021XProfiles]; + + for (NSUInteger i = 0; i < [array count]; ++i) { + const QString networkNameHashCheck = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString([[array objectAtIndex:i] userDefinedName]))); + + const QString ssidHash = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString([[array objectAtIndex:i] ssid]))); + + if (id == networkNameHashCheck || id == ssidHash) { + const QString thisName = scanThread->getSsidFromNetworkName(id); + if (thisName.isEmpty()) + wantedSsid = id; + else + wantedSsid = thisName; + + [params setValue: [array objectAtIndex:i] forKey:kCWAssocKey8021XProfile]; + using8021X = true; + break; + } + } + } + + if (!using8021X) { + QString wantedNetwork; + QMapIterator<QString, QMap<QString,QString> > i(scanThread->userProfiles); + while (i.hasNext()) { + i.next(); + wantedNetwork = i.key(); + const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork)); + if (id == networkNameHash) { + wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork); + break; + } + } + } + NSDictionary *scanParameters = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], kCWScanKeyMerge, + [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, + [NSNumber numberWithInteger:100], kCWScanKeyRestTime, + QCFString::toNSString(wantedSsid), kCWScanKeySSID, + nil]; + + NSArray *scanArray = [wifiInterface scanForNetworksWithParameters:scanParameters error:&err]; + + if(!err) { + for(uint row=0; row < [scanArray count]; row++ ) { + CWNetwork *apNetwork = [scanArray objectAtIndex:row]; + + if(wantedSsid == QCFString::toQString([apNetwork ssid])) { + + if(!using8021X) { + SecKeychainAttribute attributes[3]; + + NSString *account = [apNetwork ssid]; + NSString *keyKind = @"AirPort network password"; + NSString *keyName = account; + + attributes[0].tag = kSecAccountItemAttr; + attributes[0].data = (void *)[account UTF8String]; + attributes[0].length = [account length]; + + attributes[1].tag = kSecDescriptionItemAttr; + attributes[1].data = (void *)[keyKind UTF8String]; + attributes[1].length = [keyKind length]; + + attributes[2].tag = kSecLabelItemAttr; + attributes[2].data = (void *)[keyName UTF8String]; + attributes[2].length = [keyName length]; + + SecKeychainAttributeList attributeList = {3,attributes}; + + SecKeychainSearchRef searchRef; + SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributeList, &searchRef); + + NSString *password = @""; + SecKeychainItemRef searchItem; + + if (SecKeychainSearchCopyNext(searchRef, &searchItem) == noErr) { + UInt32 realPasswordLength; + SecKeychainAttribute attributesW[8]; + attributesW[0].tag = kSecAccountItemAttr; + SecKeychainAttributeList listW = {1,attributesW}; + char *realPassword; + OSStatus status = SecKeychainItemCopyContent(searchItem, NULL, &listW, &realPasswordLength,(void **)&realPassword); + + if (status == noErr) { + if (realPassword != NULL) { + + QByteArray pBuf; + pBuf.resize(realPasswordLength); + pBuf.prepend(realPassword); + pBuf.insert(realPasswordLength,'\0'); + + password = [NSString stringWithUTF8String:pBuf]; + } + SecKeychainItemFreeContent(&listW, realPassword); + } + + CFRelease(searchItem); + } else { + qDebug() << "SecKeychainSearchCopyNext error"; + } + [params setValue: password forKey: kCWAssocKeyPassphrase]; + } // end using8021X + + + bool result = [wifiInterface associateToNetwork: apNetwork parameters:[NSDictionary dictionaryWithDictionary:params] error:&err]; + + if(!err) { + if(!result) { + emit connectionError(id, ConnectError); + } else { + return; + } + } else { + qDebug() <<"associate ERROR"<< QCFString::toQString([err localizedDescription ]); + } + } + } //end scan network + } else { + qDebug() <<"scan ERROR"<< QCFString::toQString([err localizedDescription ]); + } + emit connectionError(id, InterfaceLookupError); + } + + locker.unlock(); + emit connectionError(id, InterfaceLookupError); + [autoreleasepool release]; +} + +void QCoreWlanEngine::disconnectFromId(const QString &id) +{ + QMutexLocker locker(&mutex); + + QString interfaceString = getInterfaceFromId(id); + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + + CWInterface *wifiInterface = + [CWInterface interfaceWithName: QCFString::toNSString(interfaceString)]; + + [wifiInterface disassociate]; + if ([[wifiInterface interfaceState]intValue] != kCWInterfaceStateInactive) { + locker.unlock(); + emit connectionError(id, DisconnectionError); + locker.relock(); + } + [autoreleasepool release]; +} + +void QCoreWlanEngine::requestUpdate() +{ + scanThread->getUserConfigurations(); + doRequestUpdate(); +} + +void QCoreWlanEngine::doRequestUpdate() +{ + QMutexLocker locker(&mutex); + + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + + NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; + for (uint row = 0; row < [wifiInterfaces count]; ++row) { + scanThread->interfaceName = QCFString::toQString([wifiInterfaces objectAtIndex:row]); + scanThread->start(); + } + locker.unlock(); + [autoreleasepool release]; +} + +bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName) +{ + QMutexLocker locker(&mutex); + bool haswifi = false; + if(hasWifi) { + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + CWInterface *defaultInterface = [CWInterface interfaceWithName: QCFString::toNSString(wifiDeviceName)]; + if([defaultInterface power]) { + haswifi = true; + } + [autoreleasepool release]; + } + return haswifi; +} + + +QNetworkSession::State QCoreWlanEngine::sessionStateForId(const QString &id) +{ + QMutexLocker locker(&mutex); + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + + if (!ptr) + return QNetworkSession::Invalid; + + if (!ptr->isValid) { + return QNetworkSession::Invalid; + } else if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { + return QNetworkSession::Connected; + } else if ((ptr->state & QNetworkConfiguration::Discovered) == + QNetworkConfiguration::Discovered) { + return QNetworkSession::Disconnected; + } else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) { + return QNetworkSession::NotAvailable; + } else if ((ptr->state & QNetworkConfiguration::Undefined) == + QNetworkConfiguration::Undefined) { + return QNetworkSession::NotAvailable; + } + + return QNetworkSession::Invalid; +} + +QNetworkConfigurationManager::Capabilities QCoreWlanEngine::capabilities() const +{ + return QNetworkConfigurationManager::ForcedRoaming; +} + +void QCoreWlanEngine::startNetworkChangeLoop() +{ + + SCDynamicStoreContext dynStoreContext = { 0, this/*(void *)storeSession*/, NULL, NULL, NULL }; + storeSession = SCDynamicStoreCreate(NULL, + CFSTR("networkChangeCallback"), + networkChangeCallback, + &dynStoreContext); + if (!storeSession ) { + qWarning() << "could not open dynamic store: error:" << SCErrorString(SCError()); + return; + } + + CFMutableArrayRef notificationKeys; + notificationKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + CFMutableArrayRef patternsArray; + patternsArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + + CFStringRef storeKey; + storeKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, + kSCDynamicStoreDomainState, + kSCEntNetIPv4); + CFArrayAppendValue(notificationKeys, storeKey); + CFRelease(storeKey); + + storeKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, + kSCDynamicStoreDomainState, + kSCCompAnyRegex, + kSCEntNetIPv4); + CFArrayAppendValue(patternsArray, storeKey); + CFRelease(storeKey); + + if (!SCDynamicStoreSetNotificationKeys(storeSession , notificationKeys, patternsArray)) { + qWarning() << "register notification error:"<< SCErrorString(SCError()); + CFRelease(storeSession ); + CFRelease(notificationKeys); + CFRelease(patternsArray); + return; + } + CFRelease(notificationKeys); + CFRelease(patternsArray); + + runloopSource = SCDynamicStoreCreateRunLoopSource(NULL, storeSession , 0); + if (!runloopSource) { + qWarning() << "runloop source error:"<< SCErrorString(SCError()); + CFRelease(storeSession ); + return; + } + + CFRunLoopAddSource(CFRunLoopGetCurrent(), runloopSource, kCFRunLoopDefaultMode); + return; +} + +QNetworkSessionPrivate *QCoreWlanEngine::createSessionBackend() +{ + return new QNetworkSessionPrivateImpl; +} + +QNetworkConfigurationPrivatePointer QCoreWlanEngine::defaultConfiguration() +{ + return QNetworkConfigurationPrivatePointer(); +} + +bool QCoreWlanEngine::requiresPolling() const +{ + return true; +} + +void QCoreWlanEngine::networksChanged() +{ + QMutexLocker locker(&mutex); + + QStringList previous = accessPointConfigurations.keys(); + + QList<QNetworkConfigurationPrivate *> foundConfigurations = scanThread->getConfigurations(); + while (!foundConfigurations.isEmpty()) { + QNetworkConfigurationPrivate *cpPriv = foundConfigurations.takeFirst(); + + previous.removeAll(cpPriv->id); + + if (accessPointConfigurations.contains(cpPriv->id)) { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(cpPriv->id); + + bool changed = false; + + ptr->mutex.lock(); + + if (ptr->isValid != cpPriv->isValid) { + ptr->isValid = cpPriv->isValid; + changed = true; + } + + if (ptr->name != cpPriv->name) { + ptr->name = cpPriv->name; + changed = true; + } + + if (ptr->bearerType != cpPriv->bearerType) { + ptr->bearerType = cpPriv->bearerType; + changed = true; + } + + if (ptr->state != cpPriv->state) { + ptr->state = cpPriv->state; + changed = true; + } + + ptr->mutex.unlock(); + + if (changed) { + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } + + delete cpPriv; + } else { + QNetworkConfigurationPrivatePointer ptr(cpPriv); + + accessPointConfigurations.insert(ptr->id, ptr); + + locker.unlock(); + emit configurationAdded(ptr); + locker.relock(); + } + } + + while (!previous.isEmpty()) { + QNetworkConfigurationPrivatePointer ptr = + accessPointConfigurations.take(previous.takeFirst()); + + locker.unlock(); + emit configurationRemoved(ptr); + locker.relock(); + } + + locker.unlock(); + emit updateCompleted(); + +} + +quint64 QCoreWlanEngine::bytesWritten(const QString &id) +{ + QMutexLocker locker(&mutex); + const QString interfaceStr = getInterfaceFromId(id); + return getBytes(interfaceStr,false); +} + +quint64 QCoreWlanEngine::bytesReceived(const QString &id) +{ + QMutexLocker locker(&mutex); + const QString interfaceStr = getInterfaceFromId(id); + return getBytes(interfaceStr,true); +} + +quint64 QCoreWlanEngine::startTime(const QString &identifier) +{ + QMutexLocker locker(&mutex); + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + quint64 timestamp = 0; + + NSString *filePath = @"/Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist"; + NSDictionary* plistDict = [[[NSDictionary alloc] initWithContentsOfFile:filePath] autorelease]; + if(plistDict == nil) + return timestamp; + NSString *input = @"KnownNetworks"; + NSString *timeStampStr = @"_timeStamp"; + + NSString *ssidStr = @"SSID_STR"; + + for (id key in plistDict) { + if ([input isEqualToString:key]) { + + NSDictionary *knownNetworksDict = [plistDict objectForKey:key]; + if(knownNetworksDict == nil) + return timestamp; + for (id networkKey in knownNetworksDict) { + bool isFound = false; + NSDictionary *itemDict = [knownNetworksDict objectForKey:networkKey]; + if(itemDict == nil) + return timestamp; + NSInteger dictSize = [itemDict count]; + id objects[dictSize]; + id keys[dictSize]; + + [itemDict getObjects:objects andKeys:keys]; + bool ok = false; + for(int i = 0; i < dictSize; i++) { + if([ssidStr isEqualToString:keys[i]]) { + const QString ident = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString(objects[i]))); + if(ident == identifier) { + ok = true; + } + } + if(ok && [timeStampStr isEqualToString:keys[i]]) { + timestamp = (quint64)[objects[i] timeIntervalSince1970]; + isFound = true; + break; + } + } + if(isFound) + break; + } + } + } + [autoreleasepool release]; + return timestamp; +} + +quint64 QCoreWlanEngine::getBytes(const QString &interfaceName, bool b) +{ + struct ifaddrs *ifAddressList, *ifAddress; + struct if_data *if_data; + + quint64 bytes = 0; + ifAddressList = nil; + if(getifaddrs(&ifAddressList) == 0) { + for(ifAddress = ifAddressList; ifAddress; ifAddress = ifAddress->ifa_next) { + if(interfaceName == ifAddress->ifa_name) { + if_data = (struct if_data*)ifAddress->ifa_data; + if(b) { + bytes = if_data->ifi_ibytes; + break; + } else { + bytes = if_data->ifi_obytes; + break; + } + } + } + freeifaddrs(ifAddressList); + } + return bytes; +} + +QT_END_NAMESPACE diff --git a/src/plugins/generic/evdevkeyboard/README b/src/plugins/generic/evdevkeyboard/README new file mode 100644 index 0000000000..0d7b52bd24 --- /dev/null +++ b/src/plugins/generic/evdevkeyboard/README @@ -0,0 +1,7 @@ +On development machines it might be useful to add the input devices +to a group that your development user is part of. I.e. add: +KERNEL=="event*", SUBSYSTEM=="input", MODE="0640", GROUP="users" + +to a file such as: +/etc/udev/rules.d/10-local.rules + diff --git a/src/plugins/generic/evdevmouse/README b/src/plugins/generic/evdevmouse/README index 76ee76bc91..c0dd3db8b3 100644 --- a/src/plugins/generic/evdevmouse/README +++ b/src/plugins/generic/evdevmouse/README @@ -12,3 +12,11 @@ initial position. Touchpads reporting absolute events will work too, the positions will be turned into relative. Touchscreens are however not supported. + +On development machines it might be useful to add the input devices +to a group that your development user is part of. I.e. add: +KERNEL=="event*", SUBSYSTEM=="input", MODE="0640", GROUP="users" + +to a file such as: +/etc/udev/rules.d/10-local.rules + diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp b/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp index 4d741807d0..9d6d4003f7 100644 --- a/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp +++ b/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp @@ -46,6 +46,8 @@ #include <QtCore/qdebug.h> #include <qpa/qwindowsysteminterface.h> +#include <QtGui/private/qopenglcontext_p.h> + QT_BEGIN_NAMESPACE QAndroidOpenGLContext::QAndroidOpenGLContext(const QAndroidPlatformIntegration *integration, @@ -75,4 +77,17 @@ void QAndroidOpenGLContext::swapBuffers(QPlatformSurface *surface) } } +bool QAndroidOpenGLContext::makeCurrent(QPlatformSurface *surface) +{ + bool ret = QEglFSContext::makeCurrent(surface); + + const char *rendererString = reinterpret_cast<const char *>(glGetString(GL_RENDERER)); + if (rendererString != 0 && qstrncmp(rendererString, "Android Emulator", 16) == 0) { + QOpenGLContextPrivate *ctx_d = QOpenGLContextPrivate::get(context()); + ctx_d->workaround_missingPrecisionQualifiers = true; + } + + return ret; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.h b/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.h index c4c5a430ad..c419ae8392 100644 --- a/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.h +++ b/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.h @@ -58,6 +58,7 @@ public: EGLenum eglApi = EGL_OPENGL_ES_API); void swapBuffers(QPlatformSurface *surface); + bool makeCurrent(QPlatformSurface *surface); private: const QAndroidPlatformIntegration *m_platformIntegration; diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h index 7224ee2ff8..59fda96dff 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.h +++ b/src/plugins/platforms/cocoa/qcocoamenu.h @@ -84,6 +84,8 @@ public: inline NSMenuItem *nsMenuItem() const { return m_nativeItem; } + inline bool isVisible() const { return m_visible; } + virtual QPlatformMenuItem *menuItemAt(int position) const; virtual QPlatformMenuItem *menuItemForTag(quintptr tag) const; @@ -100,6 +102,7 @@ private: NSMenuItem *m_nativeItem; NSObject *m_delegate; bool m_enabled; + bool m_visible; quintptr m_tag; QCocoaMenuBar *m_menuBar; }; diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 8c4325a775..3ac48df09e 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -218,6 +218,7 @@ QT_BEGIN_NAMESPACE QCocoaMenu::QCocoaMenu() : m_enabled(true), + m_visible(true), m_tag(0), m_menuBar(0) { @@ -423,6 +424,7 @@ void QCocoaMenu::setEnabled(bool enabled) void QCocoaMenu::setVisible(bool visible) { [m_nativeItem setSubmenu:(visible ? m_nativeMenu : nil)]; + m_visible = visible; } void QCocoaMenu::showPopup(const QWindow *parentWindow, QPoint pos, const QPlatformMenuItem *item) diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index da2704f19c..0fea55ac68 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -149,15 +149,17 @@ void QCocoaMenuBar::syncMenu(QPlatformMenu *menu) Q_FOREACH (QCocoaMenuItem *item, cocoaMenu->items()) cocoaMenu->syncMenuItem(item); - // If the NSMenu has no visble items, or only separators, we should hide it - // on the menubar. This can happen after syncing the menu items since they - // can be moved to other menus. BOOL shouldHide = YES; - for (NSMenuItem *item in [cocoaMenu->nsMenu() itemArray]) - if (![item isSeparatorItem] && ![item isHidden]) { - shouldHide = NO; - break; - } + if (cocoaMenu->isVisible()) { + // If the NSMenu has no visble items, or only separators, we should hide it + // on the menubar. This can happen after syncing the menu items since they + // can be moved to other menus. + for (NSMenuItem *item in [cocoaMenu->nsMenu() itemArray]) + if (![item isSeparatorItem] && ![item isHidden]) { + shouldHide = NO; + break; + } + } [cocoaMenu->nsMenuItem() setHidden:shouldHide]; } diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index cc72f050d2..fcebb7e0dc 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -270,7 +270,6 @@ void QCocoaWindow::setGeometry(const QRect &rect) #ifdef QT_COCOA_ENABLE_WINDOW_DEBUG qDebug() << "QCocoaWindow::setGeometry" << this << rect; #endif - QPlatformWindow::setGeometry(rect); setCocoaGeometry(rect); } @@ -278,8 +277,10 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect) { QCocoaAutoReleasePool pool; - if (m_contentViewIsEmbedded) + if (m_contentViewIsEmbedded) { + QPlatformWindow::setGeometry(rect); return; + } if (m_nsWindow) { NSRect bounds = qt_mac_flipRect(rect, window()); @@ -287,6 +288,8 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect) } else { [m_contentView setFrame : NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())]; } + + // will call QPlatformWindow::setGeometry(rect) during resize confirmation (see qnsview.mm) } void QCocoaWindow::setVisible(bool visible) @@ -423,11 +426,13 @@ NSInteger QCocoaWindow::windowLevel(Qt::WindowFlags flags) if (type == Qt::ToolTip) windowLevel = NSScreenSaverWindowLevel; - // A window should be in at least the same level as its parent. - const QWindow * const transientParent = window()->transientParent(); - const QCocoaWindow * const transientParentWindow = transientParent ? static_cast<QCocoaWindow *>(transientParent->handle()) : 0; - if (transientParentWindow) - windowLevel = qMax([transientParentWindow->m_nsWindow level], windowLevel); + // Any "special" window should be in at least the same level as its parent. + if (type != Qt::Window) { + const QWindow * const transientParent = window()->transientParent(); + const QCocoaWindow * const transientParentWindow = transientParent ? static_cast<QCocoaWindow *>(transientParent->handle()) : 0; + if (transientParentWindow) + windowLevel = qMax([transientParentWindow->m_nsWindow level], windowLevel); + } return windowLevel; } diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 3c93fdcf4a..3063ce452e 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -1211,7 +1211,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) timestamp, (lastKnownModifiers & mac_mask) ? QEvent::KeyRelease : QEvent::KeyPress, modifier_key_symbols[i].qt_code, - qmodifiers); + qmodifiers ^ [QNSView convertKeyModifiers:mac_mask]); } } diff --git a/src/plugins/platforms/cocoa/qprintengine_mac.mm b/src/plugins/platforms/cocoa/qprintengine_mac.mm index 2dedf99582..ee8d7ea157 100644 --- a/src/plugins/platforms/cocoa/qprintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qprintengine_mac.mm @@ -187,10 +187,8 @@ void QMacPrintEnginePrivate::setPaperName(const QString &name) if (PMSessionGetCurrentPrinter(session(), &printer) == noErr) { CFArrayRef array; - if (PMPrinterGetPaperList(printer, &array) != noErr) { - PMRelease(printer); + if (PMPrinterGetPaperList(printer, &array) != noErr) return; - } int count = CFArrayGetCount(array); for (int i = 0; i < count; ++i) { PMPaper paper = static_cast<PMPaper>(const_cast<void *>(CFArrayGetValueAtIndex(array, i))); @@ -208,7 +206,6 @@ void QMacPrintEnginePrivate::setPaperName(const QString &name) } } } - PMRelease(printer); } } diff --git a/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp b/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp index 1898cde886..e09154bb59 100644 --- a/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp +++ b/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp @@ -79,6 +79,9 @@ void QEglFSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPo makeCurrent(); + QRectF sr = window->screen()->geometry(); + glViewport(0, 0, sr.width(), sr.height()); + #ifdef QEGL_EXTRA_DEBUG qWarning("QEglBackingStore::flush %p", window); #endif @@ -120,7 +123,6 @@ void QEglFSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPo }; QRectF r = window->geometry(); - QRectF sr = window->screen()->geometry(); GLfloat x1 = (r.left() / sr.width()) * 2 - 1; GLfloat x2 = (r.right() / sr.width()) * 2 - 1; @@ -192,8 +194,6 @@ void QEglFSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPo void QEglFSBackingStore::makeCurrent() { - // needed to prevent QOpenGLContext::makeCurrent() from failing - window()->setSurfaceType(QSurface::OpenGLSurface); (static_cast<QEglFSWindow *>(window()->handle()))->create(); m_context->makeCurrent(window()); } diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp index 1cc252d285..bf6e375ac0 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp @@ -55,12 +55,12 @@ QEglFSWindow::QEglFSWindow(QWindow *w) : QPlatformWindow(w) , m_surface(0) , m_window(0) + , has_window(false) { - static int serialNo = 0; - m_winid = ++serialNo; #ifdef QEGL_EXTRA_DEBUG - qWarning("QEglWindow %p: %p 0x%x\n", this, w, uint(m_winid)); + qWarning("QEglWindow %p: %p 0x%x\n", this, w, uint(m_window)); #endif + w->setSurfaceType(QSurface::OpenGLSurface); } QEglFSWindow::~QEglFSWindow() @@ -75,7 +75,7 @@ static inline bool supportsMultipleWindows() void QEglFSWindow::create() { - if (m_window) + if (has_window) return; setWindowState(Qt::WindowFullScreen); @@ -100,7 +100,7 @@ void QEglFSWindow::create() void QEglFSWindow::invalidateSurface() { // Native surface has been deleted behind our backs - m_window = 0; + has_window = false; if (m_surface != 0) { EGLDisplay display = (static_cast<QEglFSScreen *>(window()->screen()->handle()))->display(); eglDestroySurface(display, m_surface); @@ -113,6 +113,7 @@ void QEglFSWindow::resetSurface() EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display(); m_window = QEglFSHooks::hooks()->createNativeWindow(QEglFSHooks::hooks()->screenSize(), m_format); + has_window = true; m_surface = eglCreateWindowSurface(display, m_config, m_window, NULL); if (m_surface == EGL_NO_SURFACE) { @@ -138,9 +139,9 @@ void QEglFSWindow::destroy() m_surface = 0; } - if (m_window) { + if (has_window) { QEglFSHooks::hooks()->destroyNativeWindow(m_window); - m_window = 0; + has_window = false; } } @@ -160,7 +161,7 @@ void QEglFSWindow::setWindowState(Qt::WindowState) WId QEglFSWindow::winId() const { - return m_winid; + return WId(m_window); } EGLSurface QEglFSWindow::surface() const diff --git a/src/plugins/platforms/eglfs/qeglfswindow.h b/src/plugins/platforms/eglfs/qeglfswindow.h index ff360962ed..936537807a 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.h +++ b/src/plugins/platforms/eglfs/qeglfswindow.h @@ -75,9 +75,9 @@ protected: EGLNativeWindowType m_window; private: - WId m_winid; EGLConfig m_config; QSurfaceFormat m_format; + bool has_window; }; QT_END_NAMESPACE #endif // QEGLFSWINDOW_H diff --git a/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp b/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp index cb245f2e5c..db6e5d94da 100644 --- a/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp +++ b/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp @@ -80,9 +80,6 @@ void QMinimalEglBackingStore::flush(QWindow *window, const QRegion ®ion, cons void QMinimalEglBackingStore::beginPaint(const QRegion &) { - // needed to prevent QOpenGLContext::makeCurrent() from failing - window()->setSurfaceType(QSurface::OpenGLSurface); - m_context->makeCurrent(window()); m_device = new QOpenGLPaintDevice(window()->size()); } diff --git a/src/plugins/platforms/minimalegl/qminimaleglwindow.cpp b/src/plugins/platforms/minimalegl/qminimaleglwindow.cpp index 13640b73d6..956b5470e5 100644 --- a/src/plugins/platforms/minimalegl/qminimaleglwindow.cpp +++ b/src/plugins/platforms/minimalegl/qminimaleglwindow.cpp @@ -58,6 +58,7 @@ QMinimalEglWindow::QMinimalEglWindow(QWindow *w) if (w->geometry() != screenGeometry) { QWindowSystemInterface::handleGeometryChange(w, screenGeometry); } + w->setSurfaceType(QSurface::OpenGLSurface); } void QMinimalEglWindow::setGeometry(const QRect &) diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index 92664826ab..377ca32e64 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -2,7 +2,9 @@ TEMPLATE = subdirs android:!android-no-sdk: SUBDIRS += android -SUBDIRS += minimal offscreen +SUBDIRS += minimal + +!win32|contains(QT_CONFIG, freetype):SUBDIRS += offscreen contains(QT_CONFIG, xcb) { SUBDIRS += xcb diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index a9fd1d9836..de0a583e58 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -593,6 +593,11 @@ QWindow *QWindowsContext::windowUnderMouse() const return d->m_mouseHandler.windowUnderMouse(); } +void QWindowsContext::clearWindowUnderMouse() +{ + d->m_mouseHandler.clearWindowUnderMouse(); +} + /*! \brief Find a child window at a screen point. @@ -868,10 +873,15 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::CloseEvent: QWindowSystemInterface::handleCloseEvent(platformWindow->window()); return true; - case QtWindows::ThemeChanged: // ### fixme: Compress these events? + case QtWindows::ThemeChanged: { + // Switch from Aero to Classic changes margins. + const Qt::WindowFlags flags = platformWindow->window()->flags(); + if ((flags & Qt::WindowType_Mask) != Qt::Desktop && !(flags & Qt::FramelessWindowHint)) + platformWindow->setFlag(QWindowsWindow::FrameDirty); if (QWindowsTheme *theme = QWindowsTheme::instance()) theme->windowsThemeChanged(platformWindow->window()); return true; + } #ifndef Q_OS_WINCE case QtWindows::ActivateWindowEvent: #ifndef QT_NO_TABLETEVENT diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index b5c97cddc9..0d3476e00f 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -168,6 +168,7 @@ public: unsigned cwex_flags) const; QWindow *windowUnderMouse() const; + void clearWindowUnderMouse(); inline bool windowsProc(HWND hwnd, UINT message, QtWindows::WindowsEventType et, diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 17a6cd6579..354f6700b3 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -2098,7 +2098,7 @@ QPlatformDialogHelper *createHelper(QPlatformTheme::DialogType type) || QSysInfo::windowsVersion() <= QSysInfo::WV_2003) { return new QWindowsXpFileDialogHelper(); } - if (QSysInfo::windowsVersion() > QSysInfo::WV_XP) + if (QSysInfo::windowsVersion() > QSysInfo::WV_2003) return new QWindowsFileDialogHelper(); #else return new QWindowsFileDialogHelper(); diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h index caf30e6b1a..7a7b92ca7e 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.h +++ b/src/plugins/platforms/windows/qwindowsmousehandler.h @@ -72,6 +72,7 @@ public: static Qt::MouseButtons queryMouseButtons(); QWindow *windowUnderMouse() const { return m_windowUnderMouse.data(); } + void clearWindowUnderMouse() { m_windowUnderMouse = 0; } private: inline bool translateMouseWheelEvent(QWindow *window, HWND hwnd, diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 83d93b08bd..882967d22c 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -226,7 +226,6 @@ static inline QPalette menuPalette(const QPalette &systemPalette) const QColor menuColor(getSysColor(COLOR_MENU)); const QColor menuTextColor(getSysColor(COLOR_MENUTEXT)); const QColor disabled(getSysColor(COLOR_GRAYTEXT)); - const bool isFlat = booleanSystemParametersInfo(SPI_GETFLATMENU, false); // we might need a special color group for the result. result.setColor(QPalette::Active, QPalette::Button, menuColor); result.setColor(QPalette::Active, QPalette::Text, menuTextColor); @@ -235,6 +234,7 @@ static inline QPalette menuPalette(const QPalette &systemPalette) result.setColor(QPalette::Disabled, QPalette::WindowText, disabled); result.setColor(QPalette::Disabled, QPalette::Text, disabled); #ifndef Q_OS_WINCE + const bool isFlat = booleanSystemParametersInfo(SPI_GETFLATMENU, false); result.setColor(QPalette::Disabled, QPalette::Highlight, getSysColor(isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT)); #else diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index dc51dbfc88..e7e964a128 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -871,6 +871,9 @@ void QWindowsWindow::destroyWindow() qDebug() << __FUNCTION__ << this << window() << m_data.hwnd; if (m_data.hwnd) { // Stop event dispatching before Window is destroyed. setFlag(WithinDestroy); + QWindowsContext *context = QWindowsContext::instance(); + if (context->windowUnderMouse() == window()) + context->clearWindowUnderMouse(); if (hasMouseCapture()) setMouseGrabEnabled(false); unregisterDropSite(); @@ -893,7 +896,7 @@ void QWindowsWindow::destroyWindow() #endif // !Q_OS_WINCE if (m_data.hwnd != GetDesktopWindow()) DestroyWindow(m_data.hwnd); - QWindowsContext::instance()->removeWindow(m_data.hwnd); + context->removeWindow(m_data.hwnd); m_data.hwnd = 0; } } @@ -1795,6 +1798,7 @@ void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const } #endif // !Q_OS_WINCE +#ifndef QT_NO_CURSOR // Return the default cursor (Arrow) from QWindowsCursor's cache. static inline QWindowsWindowCursor defaultCursor(const QWindow *w) { @@ -1805,6 +1809,24 @@ static inline QWindowsWindowCursor defaultCursor(const QWindow *w) return QWindowsWindowCursor(Qt::ArrowCursor); } +// Check whether to apply a new cursor. Either the window in question is +// currently under mouse, or it is the parent of the window under mouse and +// there is no other window with an explicitly set cursor in-between. +static inline bool applyNewCursor(const QWindow *w) +{ + const QWindow *underMouse = QWindowsContext::instance()->windowUnderMouse(); + if (underMouse == w) + return true; + for (const QWindow *p = underMouse; p ; p = p->parent()) { + if (p == w) + return true; + if (!QWindowsWindow::baseWindowOf(p)->cursor().isNull()) + return false; + } + return false; +} +#endif // !QT_NO_CURSOR + /*! \brief Applies to cursor property set on the window to the global cursor. @@ -1826,23 +1848,6 @@ void QWindowsWindow::applyCursor() #endif } -// Check whether to apply a new cursor. Either the window in question is -// currently under mouse, or it is the parent of the window under mouse and -// there is no other window with an explicitly set cursor in-between. -static inline bool applyNewCursor(const QWindow *w) -{ - const QWindow *underMouse = QWindowsContext::instance()->windowUnderMouse(); - if (underMouse == w) - return true; - for (const QWindow *p = underMouse; p ; p = p->parent()) { - if (p == w) - return true; - if (!QWindowsWindow::baseWindowOf(p)->cursor().isNull()) - return false; - } - return false; -} - void QWindowsWindow::setCursor(const QWindowsWindowCursor &c) { #ifndef QT_NO_CURSOR diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 5fbc23c049..2529fb8a83 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -583,7 +583,7 @@ static const Qt::KeyboardModifiers ModsTbl[] = { Qt::AltModifier | Qt::ShiftModifier, // 5 Qt::AltModifier | Qt::ControlModifier, // 6 Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier, // 7 - Qt::NoModifier // Fall-back to raw Key_* + Qt::NoModifier // Fall-back to raw Key_*, for non-latin1 kb layouts }; Qt::KeyboardModifiers QXcbKeyboard::translateModifiers(int s) const @@ -602,8 +602,9 @@ Qt::KeyboardModifiers QXcbKeyboard::translateModifiers(int s) const return ret; } -void QXcbKeyboard::readXKBConfig(struct xkb_rule_names *xkb_names) +void QXcbKeyboard::readXKBConfig() { + clearXKBConfig(); xcb_generic_error_t *error; xcb_get_property_cookie_t cookie; xcb_get_property_reply_t *config_reply; @@ -634,15 +635,30 @@ void QXcbKeyboard::readXKBConfig(struct xkb_rule_names *xkb_names) length -= len + 1; } while (p < end || i < 5); - xkb_names->rules = qstrdup(names[0]); - xkb_names->model = qstrdup(names[1]); - xkb_names->layout = qstrdup(names[2]); - xkb_names->variant = qstrdup(names[3]); - xkb_names->options = qstrdup(names[4]); + xkb_names.rules = qstrdup(names[0]); + xkb_names.model = qstrdup(names[1]); + xkb_names.layout = qstrdup(names[2]); + xkb_names.variant = qstrdup(names[3]); + xkb_names.options = qstrdup(names[4]); free(config_reply); } +void QXcbKeyboard::clearXKBConfig() +{ + if (xkb_names.rules) + delete[] xkb_names.rules; + if (xkb_names.model) + delete[] xkb_names.model; + if (xkb_names.layout) + delete[] xkb_names.layout; + if (xkb_names.variant) + delete[] xkb_names.variant; + if (xkb_names.options) + delete[] xkb_names.options; + memset(&xkb_names, 0, sizeof(xkb_names)); +} + void QXcbKeyboard::updateKeymap() { m_config = true; @@ -654,22 +670,13 @@ void QXcbKeyboard::updateKeymap() return; } } - - struct xkb_rule_names xkb_names = {0, 0, 0, 0, 0}; - - readXKBConfig(&xkb_names); + readXKBConfig(); // Compile a keymap from RMLVO (rules, models, layouts, variants and options) names if (xkb_keymap) xkb_keymap_unref(xkb_keymap); xkb_keymap = xkb_keymap_new_from_names(xkb_context, &xkb_names, (xkb_keymap_compile_flags)0); - delete[] xkb_names.rules; - delete[] xkb_names.model; - delete[] xkb_names.layout; - delete[] xkb_names.variant; - delete[] xkb_names.options; - if (!xkb_keymap) { qWarning("Qt: Failed to compile a keymap"); m_config = false; @@ -724,14 +731,14 @@ void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state) if (connection()->hasXKB()) { - xkb_state_component newState; - newState = xkb_state_update_mask(xkb_state, - state->baseMods, - state->latchedMods, - state->lockedMods, - state->baseGroup, - state->latchedGroup, - state->lockedGroup); + const xkb_state_component newState + = xkb_state_update_mask(xkb_state, + state->baseMods, + state->latchedMods, + state->lockedMods, + state->baseGroup, + state->latchedGroup, + state->lockedGroup); if ((newState & XKB_STATE_LAYOUT_EFFECTIVE) == XKB_STATE_LAYOUT_EFFECTIVE) { //qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)"); @@ -745,17 +752,22 @@ void QXcbKeyboard::updateXKBStateFromCore(quint16 state) if (!m_config) return; - quint32 modsDepressed, modsLatched, modsLocked; - modsDepressed = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_DEPRESSED); - modsLatched = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED); - modsLocked = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED); - - quint32 xkbMask = xkbModMask(state); - xkb_state_component newState; - newState = xkb_state_update_mask(xkb_state, - modsDepressed & xkbMask, - modsLatched & xkbMask, - modsLocked & xkbMask, + const quint32 modsDepressed = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_DEPRESSED); + const quint32 modsLatched = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED); + const quint32 modsLocked = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED); + const quint32 xkbMask = xkbModMask(state); + + const quint32 latched = modsLatched & xkbMask; + const quint32 locked = modsLocked & xkbMask; + quint32 depressed = modsDepressed & xkbMask; + // set modifiers in depressed if they don't appear in any of the final masks + depressed |= ~(depressed | latched | locked) & xkbMask; + + const xkb_state_component newState + = xkb_state_update_mask(xkb_state, + depressed, + latched, + locked, 0, 0, (state >> 13) & 3); // bits 13 and 14 report the state keyboard group @@ -838,7 +850,7 @@ QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const xkb_mod_index_t controlMod = xkb_keymap_mod_get_index(xkb_keymap, "Control"); xkb_mod_mask_t depressed; - + struct xkb_keymap *fallback_keymap = 0; int qtKey = 0; //obtain a list of possible shortcuts for the given key event for (uint i = 1; i < sizeof(ModsTbl) / sizeof(*ModsTbl) ; ++i) { @@ -854,8 +866,23 @@ QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const depressed |= (1 << controlMod); // update a keyboard state from a set of explicit masks - xkb_state_update_mask(kb_state, depressed, latchedMods, lockedMods, - baseLayout, latchedLayout, lockedLayout); + if (i == 8) { + // Add a fall back key for layouts with non Latin-1 characters + if (baseQtKey > 255) { + struct xkb_rule_names names = { xkb_names.rules, xkb_names.model, "us", 0, 0 }; + fallback_keymap = xkb_keymap_new_from_names(xkb_context, &names, (xkb_keymap_compile_flags)0); + if (!fallback_keymap) + continue; + xkb_state_unref(kb_state); + kb_state = xkb_state_new(fallback_keymap); + if (!kb_state) + continue; + } else + continue; + } else { + xkb_state_update_mask(kb_state, depressed, latchedMods, lockedMods, + baseLayout, latchedLayout, lockedLayout); + } sym = xkb_state_key_get_one_sym(kb_state, event->nativeScanCode()); if (sym == XKB_KEY_NoSymbol) @@ -870,8 +897,11 @@ QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const result += (qtKey + mods); } } + if (kb_state) + xkb_state_unref(kb_state); + if (fallback_keymap) + xkb_keymap_unref(fallback_keymap); - xkb_state_unref(kb_state); return result; } @@ -941,6 +971,7 @@ QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection) , core_device_id(0) #endif { + memset(&xkb_names, 0, sizeof(xkb_names)); updateKeymap(); #ifndef QT_NO_XKB if (connection->hasXKB()) { @@ -982,6 +1013,7 @@ QXcbKeyboard::~QXcbKeyboard() #ifdef QT_NO_XKB xcb_key_symbols_free(m_key_symbols); #endif + clearXKBConfig(); } #ifndef QT_NO_XKB diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index 770a7eabea..0256602782 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -91,7 +91,8 @@ protected: int keysymToQtKey(xcb_keysym_t keysym) const; int keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, QString text) const; - void readXKBConfig(struct xkb_rule_names *names); + void readXKBConfig(); + void clearXKBConfig(); #ifdef QT_NO_XKB void updateModifiers(); @@ -107,6 +108,7 @@ private: struct xkb_context *xkb_context; struct xkb_keymap *xkb_keymap; struct xkb_state *xkb_state; + struct xkb_rule_names xkb_names; struct _mod_masks { uint alt; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 911db83836..85b01d74a0 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -1302,6 +1302,9 @@ QRect QXcbWindow::windowToWmGeometry(QRect r) const r.translate(m_frameMargins.left(), m_frameMargins.top()); } else if (!frameInclusive && m_gravity == XCB_GRAVITY_NORTH_WEST) { r.translate(-m_frameMargins.left(), -m_frameMargins.top()); + } else if (!frameInclusive && m_gravity == XCB_GRAVITY_CENTER) { + r.translate(-(m_frameMargins.left() - m_frameMargins.right())/2, + -(m_frameMargins.top() - m_frameMargins.bottom())/2); } return r; } @@ -1646,7 +1649,8 @@ void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event) void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) { - if (window() != QGuiApplication::focusWindow()) { + const bool isWheel = event->detail >= 4 && event->detail <= 7; + if (!isWheel && window() != QGuiApplication::focusWindow()) { QWindow *w = static_cast<QWindowPrivate *>(QObjectPrivate::get(window()))->eventReceiver(); if (!(w->flags() & Qt::WindowDoesNotAcceptFocus)) w->requestActivate(); @@ -1668,7 +1672,7 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); - if (event->detail >= 4 && event->detail <= 7) { + if (isWheel) { // Logic borrowed from qapplication_x11.cpp int delta = 120 * ((event->detail == 4 || event->detail == 6) ? 1 : -1); bool hor = (((event->detail == 4 || event->detail == 5) diff --git a/src/plugins/platforms/xcb/qxcbxsettings.cpp b/src/plugins/platforms/xcb/qxcbxsettings.cpp index c106bd00f8..1423c6262d 100644 --- a/src/plugins/platforms/xcb/qxcbxsettings.cpp +++ b/src/plugins/platforms/xcb/qxcbxsettings.cpp @@ -221,6 +221,7 @@ QXcbXSettings::QXcbXSettings(QXcbScreen *screen) xcb_intern_atom_reply_t *atom_reply = xcb_intern_atom_reply(screen->xcb_connection(),atom_cookie,&error); if (error) { qWarning() << Q_FUNC_INFO << "Failed to find XSETTINGS_S atom"; + free(error); return; } xcb_atom_t selection_owner_atom = atom_reply->atom; @@ -233,14 +234,15 @@ QXcbXSettings::QXcbXSettings(QXcbScreen *screen) xcb_get_selection_owner_reply(screen->xcb_connection(), selection_cookie, &error); if (error) { qWarning() << Q_FUNC_INFO << "Failed to get selection owner for XSETTINGS_S atom"; + free(error); return; } d_ptr->x_settings_window = selection_result->owner; + free(selection_result); if (!d_ptr->x_settings_window) { return; } - free(selection_result); const uint32_t event = XCB_CW_EVENT_MASK; const uint32_t event_mask[] = { XCB_EVENT_MASK_STRUCTURE_NOTIFY|XCB_EVENT_MASK_PROPERTY_CHANGE }; diff --git a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp index 4e9cc446b3..e8758da1c7 100644 --- a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp +++ b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp @@ -587,6 +587,7 @@ QFont QGtk2FontDialogHelper::currentFont() const void QGtk2FontDialogHelper::onAccepted() { + emit currentFontChanged(currentFont()); emit accept(); emit fontSelected(currentFont()); } |