9#include <QtBluetooth/private/qbluetoothdevicewatcher_winrt_p.h>
10#include <QtBluetooth/private/qbluetoothutils_winrt_p.h>
11#include <QtBluetooth/private/qtbluetoothglobal_p.h>
13#include <QtCore/QLoggingCategory>
14#include <QtCore/QMutex>
15#include <QtCore/qendian.h>
17#include <winrt/Windows.Devices.Bluetooth.h>
18#include <winrt/Windows.Devices.Bluetooth.Advertisement.h>
19#include <winrt/Windows.Devices.Bluetooth.Rfcomm.h>
20#include <winrt/Windows.Devices.Bluetooth.GenericAttributeProfile.h>
21#include <winrt/Windows.Devices.Enumeration.h>
22#include <winrt/Windows.Foundation.h>
23#include <winrt/Windows.Foundation.Collections.h>
24#include <winrt/Windows.Storage.Streams.h>
26using namespace winrt::Windows::Devices::Bluetooth;
27using namespace winrt::Windows::Devices::Bluetooth::Advertisement;
28using namespace winrt::Windows::Devices::Bluetooth::GenericAttributeProfile;
29using namespace winrt::Windows::Devices::Bluetooth::Rfcomm;
30using namespace winrt::Windows::Devices::Enumeration;
31using namespace winrt::Windows::Foundation;
32using namespace winrt::Windows::Storage::Streams;
51 const auto data = ad.ManufacturerData();
53 const uint16_t
id =
item.CompanyId();
56 qCWarning(QT_BT_WINDOWS) <<
"Company ID already present in manufacturer data.";
57 ret.insert(
id, bufferData);
64 static constexpr int serviceDataTypes[3] = { 0x16, 0x20, 0x21 };
68 for (
const auto &serviceDataType : serviceDataTypes) {
69 const auto dataSections = ad.GetSectionsByType(serviceDataType);
70 for (
const auto §ion : dataSections) {
71 const unsigned char dataType = section.DataType();
73 if (dataType == 0x16) {
77 }
else if (dataType == 0x20) {
81 }
else if (dataType == 0x21) {
84 qFromLittleEndian<QUuid::Id128Bytes>(bufferData.
constData()))),
100 { guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
101 guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7] }
107 public std::enable_shared_from_this<AdvertisementWatcherWrapper>
118 m_watcher.ScanningMode(BluetoothLEScanningMode::Active);
127 unsubscribeFromEvents();
136 const ManufacturerData &manufacturerData,
137 const ServiceData &serviceData,
138 const QList<QBluetoothUuid> &uuids);
140 void subscribeToEvents()
144 auto thisPtr = shared_from_this();
145 m_receivedToken = m_watcher.Received(
146 [thisPtr](BluetoothLEAdvertisementWatcher,
147 BluetoothLEAdvertisementReceivedEventArgs
args) {
149 const short rssi =
args.RawSignalStrengthInDBm();
150 const BluetoothLEAdvertisement ad =
args.Advertisement();
155 QList<QBluetoothUuid> serviceUuids;
156 const auto guids = ad.ServiceUuids();
157 for (
const auto &guid : guids) {
162 emit thisPtr->advertisementDataReceived(
address,
rssi, manufacturerData,
163 serviceData, serviceUuids);
166 void unsubscribeFromEvents()
168 m_watcher.Received(m_receivedToken);
172 const auto status = m_watcher.Status();
173 return status == BluetoothLEAdvertisementWatcherStatus::Started
174 || status == BluetoothLEAdvertisementWatcherStatus::Aborted;
177 BluetoothLEAdvertisementWatcher m_watcher;
178 winrt::event_token m_receivedToken;
185 L
"System.Devices.Aep.ProtocolId:=\"{e0cbf06c-cd8b-4647-bb8a-263b43f0f974}\"";
191 public std::enable_shared_from_this<QWinRTBluetoothDeviceDiscoveryWorker>
204 std::shared_ptr<QBluetoothDeviceWatcherWinRT> createDeviceWatcher(winrt::hstring
selector,
208 void finishDiscovery();
209 bool isFinished()
const;
212 void getClassicDeviceFromId(
const winrt::hstring &
id);
213 void handleClassicDevice(
const BluetoothDevice &
device);
214 void handleRfcommServices(
const RfcommDeviceServicesResult &servicesResult,
218 void getLowEnergyDeviceFromId(
const winrt::hstring &
id);
219 void handleLowEnergyDevice(
const BluetoothLEDevice &
device);
220 void handleGattServices(
const GattDeviceServicesResult &servicesResult,
224 std::shared_ptr<AdvertisementWatcherWrapper> createAdvertisementWatcher();
227 Q_INVOKABLE void decrementPendingDevicesCountAndCheckFinished(
228 std::shared_ptr<QWinRTBluetoothDeviceDiscoveryWorker> worker);
233 qint16 rssi, ManufacturerData manufacturerData, ServiceData serviceData);
238 void onBluetoothDeviceFound(winrt::hstring deviceId,
int watcherId);
239 void onDeviceEnumerationCompleted(
int watcherId);
242 const ManufacturerData &manufacturerData,
243 const ServiceData &serviceData,
244 const QList<QBluetoothUuid> &uuids);
246 void stopAdvertisementWatcher();
249 struct LEAdvertisingInfo {
250 QList<QBluetoothUuid> services;
251 ManufacturerData manufacturerData;
252 ServiceData serviceData;
256 quint8 requestedModes = 0;
258 QMap<quint64, LEAdvertisingInfo> m_foundLEDevicesMap;
259 int m_pendingDevices = 0;
261 static constexpr int ClassicWatcherId = 1;
262 static constexpr int LowEnergyWatcherId = 2;
264 std::shared_ptr<QBluetoothDeviceWatcherWinRT> m_classicWatcher;
265 std::shared_ptr<QBluetoothDeviceWatcherWinRT> m_lowEnergyWatcher;
266 std::shared_ptr<AdvertisementWatcherWrapper> m_advertisementWatcher;
267 bool m_classicScanStarted =
false;
268 bool m_lowEnergyScanStarted =
false;
269 QTimer *m_leScanTimer =
nullptr;
273 std::shared_ptr<QWinRTBluetoothDeviceDiscoveryWorker> worker)
277 Q_ARG(std::shared_ptr<QWinRTBluetoothDeviceDiscoveryWorker>,
282 QBluetoothDeviceDiscoveryAgent::DiscoveryMethods
methods,
int interval)
285 qRegisterMetaType<QBluetoothDeviceInfo>();
286 qRegisterMetaType<QBluetoothDeviceInfo::Fields>();
287 qRegisterMetaType<ManufacturerData>();
288 qRegisterMetaType<std::shared_ptr<QWinRTBluetoothDeviceDiscoveryWorker>>();
293 const auto leSelector = BluetoothLEDevice::GetDeviceSelectorFromPairingState(
true);
294 m_lowEnergyWatcher = createDeviceWatcher(leSelector, LowEnergyWatcherId);
295 m_advertisementWatcher = createAdvertisementWatcher();
302 m_leScanTimer =
new QTimer(
this);
306 &QWinRTBluetoothDeviceDiscoveryWorker::stopAdvertisementWatcher);
318 if (m_classicWatcher && m_classicWatcher->init()) {
319 m_classicWatcher->start();
320 m_classicScanStarted =
true;
323 "Could not start classic device watcher");
327 if (m_lowEnergyWatcher && m_lowEnergyWatcher->init()) {
328 m_lowEnergyWatcher->start();
329 m_lowEnergyScanStarted =
true;
332 "Could not start low energy device watcher");
334 if (m_advertisementWatcher) {
335 m_advertisementWatcher->init();
336 m_advertisementWatcher->start();
338 m_leScanTimer->
start();
341 "Could not start low energy advertisement watcher");
345 qCDebug(QT_BT_WINDOWS) <<
"Worker started";
350 if (m_leScanTimer && m_leScanTimer->
isActive())
351 m_leScanTimer->
stop();
352 m_classicWatcher->stop();
353 m_lowEnergyWatcher->stop();
354 m_advertisementWatcher->stop();
357void QWinRTBluetoothDeviceDiscoveryWorker::finishDiscovery()
363bool QWinRTBluetoothDeviceDiscoveryWorker::isFinished()
const
367 return (m_pendingDevices == 0) && !m_lowEnergyScanStarted && !m_classicScanStarted
368 && (m_leScanTimer && !m_leScanTimer->
isActive());
371void QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothDeviceFound(winrt::hstring deviceId,
int watcherId)
373 if (watcherId == ClassicWatcherId)
374 getClassicDeviceFromId(deviceId);
375 else if (watcherId == LowEnergyWatcherId)
376 getLowEnergyDeviceFromId(deviceId);
379void QWinRTBluetoothDeviceDiscoveryWorker::onDeviceEnumerationCompleted(
int watcherId)
381 qCDebug(QT_BT_WINDOWS) << (watcherId == ClassicWatcherId ?
"BT" :
"BTLE")
382 <<
"enumeration completed";
383 if (watcherId == ClassicWatcherId) {
384 m_classicWatcher->stop();
385 m_classicScanStarted =
false;
386 }
else if (watcherId == LowEnergyWatcherId) {
387 m_lowEnergyWatcher->stop();
388 m_lowEnergyScanStarted =
false;
395void QWinRTBluetoothDeviceDiscoveryWorker::onAdvertisementDataReceived(
397 const ServiceData &serviceData,
const QList<QBluetoothUuid> &uuids)
400 bool needDiscoverServices =
false;
405 const LEAdvertisingInfo adInfo = m_foundLEDevicesMap.
value(
address);
406 QList<QBluetoothUuid> foundServices = adInfo.services;
407 if (adInfo.rssi !=
rssi) {
411 if (adInfo.manufacturerData != manufacturerData) {
412 m_foundLEDevicesMap[
address].manufacturerData.
insert(manufacturerData);
413 if (adInfo.manufacturerData != m_foundLEDevicesMap[
address].manufacturerData)
416 if (adInfo.serviceData != serviceData) {
417 m_foundLEDevicesMap[
address].serviceData.
insert(serviceData);
418 if (adInfo.serviceData != m_foundLEDevicesMap[
address].serviceData)
422 if (!foundServices.contains(uuid)) {
423 foundServices.append(uuid);
424 needDiscoverServices =
true;
427 if (!needDiscoverServices) {
431 Q_ARG(QBluetoothDeviceInfo::Fields, changedFields),
433 Q_ARG(ManufacturerData, manufacturerData),
434 Q_ARG(ServiceData, serviceData));
437 m_foundLEDevicesMap[
address].services = foundServices;
439 needDiscoverServices =
true;
440 LEAdvertisingInfo
info;
441 info.services = std::move(uuids);
442 info.manufacturerData = std::move(manufacturerData);
443 info.serviceData = std::move(serviceData);
448 if (needDiscoverServices) {
450 auto thisPtr = shared_from_this();
451 auto asyncOp = BluetoothLEDevice::FromBluetoothAddressAsync(
address);
452 asyncOp.Completed([thisPtr,
address](
auto &&op, AsyncStatus status) {
454 if (status == AsyncStatus::Completed) {
455 BluetoothLEDevice
device = op.GetResults();
457 thisPtr->handleLowEnergyDevice(
device);
462 qCDebug(QT_BT_WINDOWS) <<
"Failed to get LE device from address"
470void QWinRTBluetoothDeviceDiscoveryWorker::stopAdvertisementWatcher()
472 m_advertisementWatcher->stop();
477std::shared_ptr<QBluetoothDeviceWatcherWinRT>
478QWinRTBluetoothDeviceDiscoveryWorker::createDeviceWatcher(winrt::hstring
selector,
int watcherId)
480 auto watcher = std::make_shared<QBluetoothDeviceWatcherWinRT>(
481 watcherId,
selector, DeviceInformationKind::AssociationEndpoint);
484 this, &QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothDeviceFound,
487 this, &QWinRTBluetoothDeviceDiscoveryWorker::onDeviceEnumerationCompleted,
493void QWinRTBluetoothDeviceDiscoveryWorker::generateError(
502 qCDebug(QT_BT_WINDOWS) <<
"Discovered BTLE device: " <<
info.address() <<
info.name()
503 <<
"Num UUIDs" <<
info.serviceUuids().size() <<
"RSSI:" <<
info.rssi()
504 <<
"Num manufacturer data" <<
info.manufacturerData().size()
505 <<
"Num service data" <<
info.serviceData().size();
512void QWinRTBluetoothDeviceDiscoveryWorker::getClassicDeviceFromId(
const winrt::hstring &
id)
515 auto thisPtr = shared_from_this();
516 auto asyncOp = BluetoothDevice::FromIdAsync(
id);
517 asyncOp.Completed([thisPtr](
auto &&op, AsyncStatus status) {
519 if (status == AsyncStatus::Completed) {
520 BluetoothDevice
device = op.GetResults();
522 thisPtr->handleClassicDevice(
device);
527 qCDebug(QT_BT_WINDOWS) <<
"Failed to get Classic device from id";
534void QWinRTBluetoothDeviceDiscoveryWorker::handleClassicDevice(
const BluetoothDevice &
device)
539 const uint32_t deviceClass =
device.ClassOfDevice().RawValue();
540 auto thisPtr = shared_from_this();
541 auto asyncOp =
device.GetRfcommServicesAsync();
542 asyncOp.Completed([thisPtr,
address, btName, deviceClass](
auto &&op, AsyncStatus status) {
544 if (status == AsyncStatus::Completed) {
545 auto servicesResult = op.GetResults();
546 if (servicesResult) {
547 thisPtr->handleRfcommServices(servicesResult,
address, btName, deviceClass);
552 qCDebug(QT_BT_WINDOWS) <<
"Failed to get RFCOMM services for device" << btName;
559void QWinRTBluetoothDeviceDiscoveryWorker::handleRfcommServices(
560 const RfcommDeviceServicesResult &servicesResult, uint64_t
address,
564 auto shared = shared_from_this();
570 const auto error = servicesResult.Error();
571 if (
error != BluetoothError::Success) {
572 qCWarning(QT_BT_WINDOWS) <<
"Obtain device services completed with BluetoothError"
573 <<
static_cast<int>(
error);
577 const auto services = servicesResult.Services();
578 QList<QBluetoothUuid> uuids;
579 for (
const auto &service :
services) {
580 const auto serviceId =
service.ServiceId();
587 qCDebug(QT_BT_WINDOWS) <<
"Discovered BT device: " << btAddress <<
name
588 <<
"Num UUIDs" << uuids.size();
592 info.setServiceUuids(uuids);
593 info.setCached(
true);
599void QWinRTBluetoothDeviceDiscoveryWorker::decrementPendingDevicesCountAndCheckFinished(
600 std::shared_ptr<QWinRTBluetoothDeviceDiscoveryWorker> worker)
611void QWinRTBluetoothDeviceDiscoveryWorker::getLowEnergyDeviceFromId(
const winrt::hstring &
id)
614 auto asyncOp = BluetoothLEDevice::FromIdAsync(
id);
615 auto thisPtr = shared_from_this();
616 asyncOp.Completed([thisPtr](
auto &&op, AsyncStatus status) {
618 if (status == AsyncStatus::Completed) {
619 BluetoothLEDevice
device = op.GetResults();
621 thisPtr->handleLowEnergyDevice(
device);
626 qCDebug(QT_BT_WINDOWS) <<
"Failed to get LE device from id";
633void QWinRTBluetoothDeviceDiscoveryWorker::handleLowEnergyDevice(
const BluetoothLEDevice &
device)
638 const bool isPaired =
device.DeviceInformation().Pairing().IsPaired();
640 m_leDevicesMutex.
lock();
641 const LEAdvertisingInfo adInfo = m_foundLEDevicesMap.
value(
address);
642 m_leDevicesMutex.
unlock();
643 const ManufacturerData manufacturerData = adInfo.manufacturerData;
644 const ServiceData serviceData = adInfo.serviceData;
654 info.setCached(
true);
658 info.setServiceUuids(adInfo.services);
660 invokeDeviceFoundWithDebug(
info);
662 auto asyncOp =
device.GetGattServicesAsync();
663 auto thisPtr = shared_from_this();
664 asyncOp.Completed([thisPtr,
info](
auto &&op, AsyncStatus status)
mutable {
665 if (status == AsyncStatus::Completed) {
666 auto servicesResult = op.GetResults();
667 if (servicesResult) {
668 thisPtr->handleGattServices(servicesResult,
info);
673 qCDebug(QT_BT_WINDOWS) <<
"Failed to get GATT services for device" <<
info.name();
680void QWinRTBluetoothDeviceDiscoveryWorker::handleGattServices(
684 auto shared = shared_from_this();
690 const auto status = servicesResult.Status();
691 if (status == GattCommunicationStatus::Success) {
692 const auto services = servicesResult.Services();
693 QList<QBluetoothUuid> uuids;
694 for (
const auto &service :
services) {
698 info.setServiceUuids(uuids);
700 qCWarning(QT_BT_WINDOWS) <<
"Obtaining LE services finished with status"
701 <<
static_cast<int>(status);
703 invokeDeviceFoundWithDebug(
info);
706std::shared_ptr<AdvertisementWatcherWrapper>
707QWinRTBluetoothDeviceDiscoveryWorker::createAdvertisementWatcher()
709 auto watcher = std::make_shared<AdvertisementWatcherWrapper>();
712 this, &QWinRTBluetoothDeviceDiscoveryWorker::onAdvertisementDataReceived,
720 : q_ptr(parent), adapterAddress(deviceAdapter)
727 disconnectAndClearWorker();
733 return worker !=
nullptr;
744 if (!adapter.isValid()) {
745 qCWarning(QT_BT_WINDOWS) <<
"Cannot find Bluetooth adapter for device search";
747 errorString = QBluetoothDeviceDiscoveryAgent::tr(
"Cannot find valid Bluetooth adapter.");
751 qCWarning(QT_BT_WINDOWS) <<
"Bluetooth adapter powered off";
753 errorString = QBluetoothDeviceDiscoveryAgent::tr(
"Bluetooth adapter powered off.");
761 worker = std::make_shared<QWinRTBluetoothDeviceDiscoveryWorker>(
methods,
762 lowEnergySearchTimeout);
765 discoveredDevices.
clear();
767 this, &QBluetoothDeviceDiscoveryAgentPrivate::registerDevice);
769 this, &QBluetoothDeviceDiscoveryAgentPrivate::updateDeviceData);
771 this, &QBluetoothDeviceDiscoveryAgentPrivate::onErrorOccured);
773 this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished);
782 disconnectAndClearWorker();
793 if (
iter->address() ==
info.address()) {
794 qCDebug(QT_BT_WINDOWS) <<
"Updating device" <<
iter->name() <<
iter->address();
796 QList<QBluetoothUuid> uuids =
iter->serviceUuids();
797 uuids.append(
info.serviceUuids());
798 const QSet<QBluetoothUuid> uuidSet(uuids.begin(), uuids.end());
799 if (
iter->serviceUuids().size() != uuidSet.size())
800 iter->setServiceUuids(uuidSet.values().toVector());
801 if (
iter->coreConfigurations() !=
info.coreConfigurations())
807 discoveredDevices <<
info;
812 QBluetoothDeviceInfo::Fields fields,
814 ManufacturerData manufacturerData,
815 ServiceData serviceData)
824 qCDebug(QT_BT_WINDOWS) <<
"Updating data for device" <<
iter->name() <<
iter->address();
843 emit q->errorOccurred(e);
846void QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished()
849 disconnectAndClearWorker();
853void QBluetoothDeviceDiscoveryAgentPrivate::disconnectAndClearWorker()
859 this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished);
861 this, &QBluetoothDeviceDiscoveryAgentPrivate::registerDevice);
863 this, &QBluetoothDeviceDiscoveryAgentPrivate::updateDeviceData);
865 this, &QBluetoothDeviceDiscoveryAgentPrivate::onErrorOccured);
872#include <qbluetoothdevicediscoveryagent_winrt.moc>
static JNINativeMethod methods[]
IOBluetoothDevice * device
std::vector< ObjCStrongReference< CBMutableService > > services
~AdvertisementWatcherWrapper()
void advertisementDataReceived(quint64 address, qint16 rssi, const ManufacturerData &manufacturerData, const ServiceData &serviceData, const QList< QBluetoothUuid > &uuids)
AdvertisementWatcherWrapper()
~QBluetoothDeviceDiscoveryAgentPrivate()
void start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods)
QBluetoothDeviceDiscoveryAgentPrivate(const QBluetoothAddress &deviceAdapter, QBluetoothDeviceDiscoveryAgent *parent)
static DiscoveryMethods supportedDiscoveryMethods()
This function returns the discovery methods supported by the current platform.
void errorOccurred(QBluetoothDeviceDiscoveryAgent::Error error)
This signal is emitted when an error occurs during Bluetooth device discovery.
DiscoveryMethod
This enum descibes the type of discovery method employed by the QBluetoothDeviceDiscoveryAgent.
Error
Indicates all possible error conditions found during Bluetooth device discovery.
@ InvalidBluetoothAdapterError
@ BaseRateAndLowEnergyCoreConfiguration
@ LowEnergyCoreConfiguration
@ BaseRateCoreConfiguration
void enumerationCompleted(int id)
void deviceAdded(winrt::hstring deviceId, int id)
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
iterator insert(const Key &key, const T &value)
T value(const Key &key, const T &defaultValue=T()) const
bool contains(const Key &key) const
void unlock() noexcept
Unlocks the mutex.
void lock() noexcept
Locks the mutex.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
\macro QT_RESTRICTED_CAST_FROM_ASCII
void clear()
Clears the contents of the string and makes it null.
static QString fromStdWString(const std::wstring &s)
Returns a copy of the str string.
void setSingleShot(bool singleShot)
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
void setInterval(int msec)
bool isActive() const
Returns true if the timer is running (pending); otherwise returns false.
void stop()
Stops the timer.
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
void deviceDataChanged(const QBluetoothAddress &address, QBluetoothDeviceInfo::Fields, qint16 rssi, ManufacturerData manufacturerData, ServiceData serviceData)
void deviceFound(const QBluetoothDeviceInfo &info)
void errorOccured(QBluetoothDeviceDiscoveryAgent::Error error)
QWinRTBluetoothDeviceDiscoveryWorker(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods, int interval)
~QWinRTBluetoothDeviceDiscoveryWorker()
Combined button and popup list for selecting options.
Q_CORE_EXPORT QtJniTypes::Service service()
static ManufacturerData extractManufacturerData(const BluetoothLEAdvertisement &ad)
static void invokeDecrementPendingDevicesCountAndCheckFinished(std::shared_ptr< QWinRTBluetoothDeviceDiscoveryWorker > worker)
static const winrt::hstring ClassicDeviceSelector
static GUID fromWinRtGuid(const winrt::guid &guid)
static QT_BEGIN_NAMESPACE QByteArray byteArrayFromBuffer(const IBuffer &buffer)
static ServiceData extractServiceData(const BluetoothLEAdvertisement &ad)
void mainThreadCoInit(void *caller)
void mainThreadCoUninit(void *caller)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
DBusConnection const char DBusError * error
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
#define Q_ARG(Type, data)
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint GLuint64EXT address
GLdouble GLdouble GLdouble GLdouble q
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
unsigned long long quint64
QFutureWatcher< int > watcher
QFileSelector selector
[1]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
myObject disconnect()
[26]