Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
bluez5_helper.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtCore/QGlobalStatic>
5#include <QtCore/QLoggingCategory>
6#include <QtCore/QMap>
7#include <QtCore/QVersionNumber>
8#include <QtNetwork/private/qnet_unix_p.h>
9#include "bluez5_helper_p.h"
10#include "bluez_data_p.h"
11#include "objectmanager_p.h"
12#include "properties_p.h"
13#include "adapter1_bluez5_p.h"
14
16
21
22
24
31
34
35/*
36 Ensures that the DBus types are registered
37 */
38
40{
41 if (*bluezVersion() == BluezVersionUnknown) {
43 QStringLiteral("/"),
45 qDBusRegisterMetaType<InterfaceList>();
46 qDBusRegisterMetaType<ManagedObjectList>();
47 qDBusRegisterMetaType<ManufacturerDataList>();
48 qDBusRegisterMetaType<ServiceDataList>();
49
50 QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects();
51 reply.waitForFinished();
52 if (reply.isError()) {
53 *bluezVersion() = BluezNotAvailable;
54 qWarning() << "Cannot find a compatible running Bluez. "
55 "Please check the Bluez installation. "
56 "QtBluetooth requires at least BlueZ version 5.";
57 } else {
58 *bluezVersion() = BluezVersion5;
59 qCDebug(QT_BT_BLUEZ) << "Bluez 5 detected.";
60 }
61 }
62}
63
64/*
65 Checks that the mandatory Bluetooth HCI ioctls are offered
66 by Linux kernel. Returns \c true if the ictls are available; otherwise \c false.
67
68 Mandatory ioctls:
69 - HCIGETCONNLIST
70 - HCIGETDEVINFO
71 - HCIGETDEVLIST
72 */
74{
75 // open hci socket
76 int hciSocket = ::qt_safe_socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
77 if (hciSocket < 0) {
78 qCWarning(QT_BT_BLUEZ) << "Cannot open HCI socket:" << qt_error_string(errno);
79 return false;
80 }
81
82 // check HCIGETDEVLIST & HCIGETDEVLIST
83 struct hci_dev_req *devRequest = nullptr;
84 struct hci_dev_list_req *devRequestList = nullptr;
85 struct hci_dev_info devInfo;
86 const int devListSize = sizeof(struct hci_dev_list_req)
87 + HCI_MAX_DEV * sizeof(struct hci_dev_req);
88
89 devRequestList = (hci_dev_list_req *) malloc(devListSize);
90 if (!devRequestList) {
91 qt_safe_close(hciSocket);
92 return false; // if we cannot malloc nothing will help anyway
93 }
94
95 QScopedPointer<hci_dev_list_req, QScopedPointerPodDeleter> pDevList(devRequestList);
96 memset(pDevList.data(), 0, devListSize);
97 pDevList->dev_num = HCI_MAX_DEV;
98 devRequest = pDevList->dev_req;
99
100 if (qt_safe_ioctl(hciSocket, HCIGETDEVLIST, devRequestList) < 0) {
101 qt_safe_close(hciSocket);
102 qCWarning(QT_BT_BLUEZ) << "HCI icotl HCIGETDEVLIST:" << qt_error_string(errno);
103 return false;
104 }
105
106 if (devRequestList->dev_num > 0) {
107 devInfo.dev_id = devRequest->dev_id;
108 if (qt_safe_ioctl(hciSocket, HCIGETDEVINFO, &devInfo) < 0) {
109 qt_safe_close(hciSocket);
110 qCWarning(QT_BT_BLUEZ) << "HCI icotl HCIGETDEVINFO:" << qt_error_string(errno);
111 return false;
112 }
113 }
114
115 // check HCIGETCONNLIST
116 const int maxNoOfConnections = 20;
117 hci_conn_list_req *infoList = nullptr;
118 infoList = (hci_conn_list_req *)
119 malloc(sizeof(hci_conn_list_req) + maxNoOfConnections * sizeof(hci_conn_info));
120
121 if (!infoList) {
122 qt_safe_close(hciSocket);
123 return false;
124 }
125
126 QScopedPointer<hci_conn_list_req, QScopedPointerPodDeleter> pInfoList(infoList);
127 pInfoList->conn_num = maxNoOfConnections;
128 pInfoList->dev_id = devInfo.dev_id;
129
130 if (qt_safe_ioctl(hciSocket, HCIGETCONNLIST, (void *) infoList) < 0) {
131 qCWarning(QT_BT_BLUEZ) << "HCI icotl HCIGETCONNLIST:" << qt_error_string(errno);
132 qt_safe_close(hciSocket);
133 return false;
134 }
135
136 qt_safe_close(hciSocket);
137 return true;
138}
139
140/*
141 * This function returns the version of bluetoothd in use on the system.
142 * This is required to determine which QLEControllerPrivate implementation
143 * is required. The following version tags are of significance:
144 *
145 * Version < 4.0 -> QLEControllerPrivateCommon
146 * Version < 5.42 -> QLEControllerPrivateBluez
147 * Version >= 5.42 -> QLEControllerPrivateBluezDBus
148 *
149 * This function utilizes a singleton pattern. It always returns a cached
150 * version tag which is determined on first call. This is necessary to
151 * avoid continuesly running the somewhat expensive tests.
152 *
153 * The function must never return a null QVersionNumber.
154 */
156{
157 if (bluezDaemonVersion()->isNull()) {
158 // Register DBus specific meta types (copied from isBluez5())
159 // Not all code paths run through isBluez5() but still need the
160 // registration.
161 qDBusRegisterMetaType<InterfaceList>();
162 qDBusRegisterMetaType<ManagedObjectList>();
163 qDBusRegisterMetaType<ManufacturerDataList>();
164 qDBusRegisterMetaType<ServiceDataList>();
165
166 qCDebug(QT_BT_BLUEZ) << "Detecting bluetoothd version";
167 //Order of matching
168 // 1. Pick whatever the user decides via BLUETOOTH_FORCE_DBUS_LE_VERSION
169 // Set version to below version 5.42 to use custom/old GATT stack implementation
170 const QString version = qEnvironmentVariable("BLUETOOTH_FORCE_DBUS_LE_VERSION");
171 if (!version.isNull()) {
172 const QVersionNumber vn = QVersionNumber::fromString(version);
173 if (!vn.isNull()) {
174 *bluezDaemonVersion() = vn;
175 qCDebug(QT_BT_BLUEZ) << "Forcing Bluez LE API selection:"
176 << bluezDaemonVersion()->toString();
177 }
178 }
179
180 // 2. Find bluetoothd binary and check "bluetoothd --version"
181 if (bluezDaemonVersion()->isNull() && qt_haveLinuxProcfs()) {
183 qint64 pid = session.interface()->servicePid(QStringLiteral("org.bluez")).value();
185
186 auto determineBinaryVersion = [](const QString &binary) -> QVersionNumber {
187 QProcess process;
188 process.start(binary, {QStringLiteral("--version")});
189 process.waitForFinished();
190
191 const QString version = QString::fromLocal8Bit(process.readAll());
192 const QVersionNumber vn = QVersionNumber::fromString(version);
193 if (!vn.isNull())
194 qCDebug(QT_BT_BLUEZ) << "Detected bluetoothd version" << vn;
195 return vn;
196 };
197
198 //try reading /proc/<pid>/exe first -> requires process owner
199 qCDebug(QT_BT_BLUEZ) << "Using /proc/<pid>/exe";
200 const QString procExe = QStringLiteral("/proc/%1/exe").arg(pid);
201 const QVersionNumber vn = determineBinaryVersion(procExe);
202 if (!vn.isNull())
203 *bluezDaemonVersion() = vn;
204
205 if (bluezDaemonVersion()->isNull()) {
206 qCDebug(QT_BT_BLUEZ) << "Using /proc/<pid>/cmdline";
207 //try to reading /proc/<pid>/cmdline (does not require additional process rights)
208 QFile procFile(QStringLiteral("/proc/%1/cmdline").arg(pid));
209 if (procFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
210 buffer = procFile.readAll();
211 procFile.close();
212
213 // cmdline params separated by character \0 -> first is bluetoothd binary
214 const QString binary = QString::fromLocal8Bit(buffer.split('\0').at(0));
216 if (info.isExecutable())
217 *bluezDaemonVersion() = determineBinaryVersion(binary);
218 else
219 qCDebug(QT_BT_BLUEZ) << "Cannot determine bluetoothd version via cmdline:"
220 << binary;
221 }
222 }
223 }
224
225 // 3. Fall back to custom ATT backend, if possible?
226 if (bluezDaemonVersion()->isNull()) {
227 // Check mandatory HCI ioctls are available
229 // default 4.0 for now -> implies custom (G)ATT implementation
230 *bluezDaemonVersion() = QVersionNumber(4, 0);
231 }
232 }
233
234 // 4. Ultimate fallback -> enable dummy backend
235 if (bluezDaemonVersion()->isNull()) {
236 // version 3 represents disabled BTLE
237 // bluezDaemonVersion should not be null to avoid repeated version tests
238 *bluezDaemonVersion() = QVersionNumber(3, 0);
239 qCWarning(QT_BT_BLUEZ) << "Cannot determine bluetoothd version and required Bluetooth HCI ioctols";
240 qCWarning(QT_BT_BLUEZ) << "Disabling Qt Bluetooth LE feature";
241 }
242
243 qCDebug(QT_BT_BLUEZ) << "Bluetoothd:" << bluezDaemonVersion()->toString();
244 }
245
246 Q_ASSERT(!bluezDaemonVersion()->isNull());
247 return *bluezDaemonVersion();
248}
249
259
261{
262public:
263 QMap<QString, AdapterData *> references;
265};
266
268
269
286 QObject(parent)
287{
288 qCDebug(QT_BT_BLUEZ) << "Creating QtBluezDiscoveryManager";
290
292 QStringLiteral("org.bluez"), QStringLiteral("/"),
294 connect(d->manager, SIGNAL(InterfacesRemoved(QDBusObjectPath,QStringList)),
295 SLOT(InterfacesRemoved(QDBusObjectPath,QStringList)));
296}
297
299{
300 qCDebug(QT_BT_BLUEZ) << "Destroying QtBluezDiscoveryManager";
301
302 const QList<QString> adapterPaths = d->references.keys();
303 for (const QString &adapterPath : adapterPaths) {
304 AdapterData *data = d->references.take(adapterPath);
305 delete data->propteryListener;
306
307 // turn discovery off if it wasn't on already
308 if (!data->wasListeningAlready) {
309 OrgBluezAdapter1Interface iface(QStringLiteral("org.bluez"), adapterPath,
311 iface.StopDiscovery();
312 }
313
314 delete data;
315 }
316
317 delete d;
318}
319
321{
322 return discoveryManager();
323}
324
326{
327 if (adapterPath.isEmpty())
328 return false;
329
330 // already monitored adapter? -> increase ref count -> done
331 if (d->references.contains(adapterPath)) {
332 d->references[adapterPath]->reference++;
333 return true;
334 }
335
337
339 QStringLiteral("org.bluez"), adapterPath, QDBusConnection::systemBus());
341 this, &QtBluezDiscoveryManager::PropertiesChanged);
342 data->propteryListener = propIface;
343
344 OrgBluezAdapter1Interface iface(QStringLiteral("org.bluez"), adapterPath,
346 data->wasListeningAlready = iface.discovering();
347
348 d->references[adapterPath] = data;
349
350 if (!data->wasListeningAlready)
351 iface.StartDiscovery();
352
353 return true;
354}
355
357{
358 if (!d->references.contains(adapterPath))
359 return;
360
361 AdapterData *data = d->references[adapterPath];
362 data->reference--;
363
364 if (data->reference > 0) // more than one client requested discovery mode
365 return;
366
367 d->references.remove(adapterPath);
368 if (!data->wasListeningAlready) { // Qt turned discovery mode on, Qt has to turn it off again
369 OrgBluezAdapter1Interface iface(QStringLiteral("org.bluez"), adapterPath,
371 iface.StopDiscovery();
372 }
373
374 delete data->propteryListener;
375 delete data;
376}
377
378//void QtBluezDiscoveryManager::dumpState() const
379//{
380// qCDebug(QT_BT_BLUEZ) << "-------------------------";
381// if (d->references.isEmpty()) {
382// qCDebug(QT_BT_BLUEZ) << "No running registration";
383// } else {
384// const QList<QString> paths = d->references.keys();
385// for (const QString &path : paths) {
386// qCDebug(QT_BT_BLUEZ) << path << "->" << d->references[path]->reference;
387// }
388// }
389// qCDebug(QT_BT_BLUEZ) << "-------------------------";
390//}
391
392void QtBluezDiscoveryManager::InterfacesRemoved(const QDBusObjectPath &object_path,
393 const QStringList &interfaces)
394{
395 if (!d->references.contains(object_path.path())
396 || !interfaces.contains(QStringLiteral("org.bluez.Adapter1")))
397 return;
398
399 removeAdapterFromMonitoring(object_path.path());
400}
401
402void QtBluezDiscoveryManager::PropertiesChanged(const QString &interface,
403 const QVariantMap &changed_properties,
404 const QStringList &invalidated_properties,
405 const QDBusMessage &)
406{
407 Q_UNUSED(invalidated_properties);
408
410 qobject_cast<OrgFreedesktopDBusPropertiesInterface *>(sender());
411
412 if (!propIface)
413 return;
414
415 if (interface == QStringLiteral("org.bluez.Adapter1")
416 && d->references.contains(propIface->path())
417 && changed_properties.contains(QStringLiteral("Discovering"))) {
418 bool isDiscovering = changed_properties.value(QStringLiteral("Discovering")).toBool();
419 if (!isDiscovering) {
420
421 /*
422 Once we stop the Discovering flag will switch a few ms later. This comes through this code
423 path. If a new device discovery is started while we are still
424 waiting for the flag change signal, then the new device discovery will be aborted prematurely.
425 To compensate we check whether there was renewed interest.
426 */
427
428 AdapterData *data = d->references[propIface->path()];
429 if (!data) {
430 removeAdapterFromMonitoring(propIface->path());
431 } else {
432 OrgBluezAdapter1Interface iface(QStringLiteral("org.bluez"), propIface->path(),
434 iface.StartDiscovery();
435 }
436 }
437 }
438}
439
440void QtBluezDiscoveryManager::removeAdapterFromMonitoring(const QString &dbusPath)
441{
442 // remove adapter from monitoring
443 AdapterData *data = d->references.take(dbusPath);
444 delete data->propteryListener;
445 delete data;
446
447 emit discoveryInterrupted(dbusPath);
448}
449
450/*
451 Finds the path for the local adapter with \a wantedAddress or an empty string
452 if no local adapter with the given address can be found.
453 If \a wantedAddress is \c null it returns the first/default adapter or an empty
454 string if none is available.
455
456 If \a ok is false the lookup was aborted due to a dbus error and this function
457 returns an empty string.
458 */
459QString findAdapterForAddress(const QBluetoothAddress &wantedAddress, bool *ok = nullptr)
460{
462 QStringLiteral("/"),
464
465 QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects();
466 reply.waitForFinished();
467 if (reply.isError()) {
468 if (ok)
469 *ok = false;
470
471 return QString();
472 }
473
474 typedef QPair<QString, QBluetoothAddress> AddressForPathType;
475 QList<AddressForPathType> localAdapters;
476
477 ManagedObjectList managedObjectList = reply.value();
478 for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
479 const QDBusObjectPath &path = it.key();
480 const InterfaceList &ifaceList = it.value();
481
482 for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
483 const QString &iface = jt.key();
484
485 if (iface == QStringLiteral("org.bluez.Adapter1")) {
486 AddressForPathType pair;
487 pair.first = path.path();
488 pair.second = QBluetoothAddress(ifaceList.value(iface).value(
489 QStringLiteral("Address")).toString());
490 if (!pair.second.isNull())
491 localAdapters.append(pair);
492 break;
493 }
494 }
495 }
496
497 if (ok)
498 *ok = true;
499
500 if (localAdapters.isEmpty())
501 return QString(); // -> no local adapter found
502
503 if (wantedAddress.isNull())
504 return localAdapters.front().first; // -> return first found adapter
505
506 for (const AddressForPathType &pair : std::as_const(localAdapters)) {
507 if (pair.second == wantedAddress)
508 return pair.first; // -> found local adapter with wanted address
509 }
510
511 return QString(); // nothing matching found
512}
513
514/*
515
516 Checks the presence of peripheral interface and returns path to the adapter
517
518*/
519
521{
523
524 // First find the object path to the desired adapter
525 bool ok = false;
526 const QString hostAdapterPath = findAdapterForAddress(localAddress, &ok);
527 if (!ok || hostAdapterPath.isEmpty())
528 return {};
529
530 // Then check if that adapter provides peripheral dbus interface
532 QStringLiteral("/"),
534 QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects();
535 reply.waitForFinished();
536 if (reply.isError())
537 return {};
538
539 using namespace Qt::StringLiterals;
540 // For example /org/bluez/hci0 contains org.bluezLEAdvertisingManager1
541 const bool peripheralSupported = reply.value()
542 .value(QDBusObjectPath(hostAdapterPath))
543 .contains("org.bluez.LEAdvertisingManager1"_L1);
544
545 qCDebug(QT_BT_BLUEZ) << "Peripheral role"
546 << (peripheralSupported ? "" : "not")
547 << "supported on" << hostAdapterPath;
548 return peripheralSupported ? hostAdapterPath : QString{};
549}
550
551/*
552 Removes every character that cannot be used in QDbusObjectPath
553
554 See QDbusUtil::isValidObjectPath(QString) for more details.
555 */
557{
558 QString appName = text;
559 for (qsizetype i = 0; i < appName.size(); ++i) {
560 ushort us = appName[i].unicode();
561 bool valid = (us >= 'a' && us <= 'z')
562 || (us >= 'A' && us <= 'Z')
563 || (us >= '0' && us <= '9')
564 || (us == '_');
565
566 if (!valid)
567 appName[i] = QLatin1Char('_');
568 }
569
570 return appName;
571}
572
574
575#include "moc_bluez5_helper_p.cpp"
QT_BEGIN_NAMESPACE enum Bluez5TestResultType Bluez5TestResult
QString adapterWithDBusPeripheralInterface(const QBluetoothAddress &localAddress)
QString sanitizeNameForDBus(const QString &text)
QString findAdapterForAddress(const QBluetoothAddress &wantedAddress, bool *ok=nullptr)
bool mandatoryHciIoctlsAvailable()
QVersionNumber bluetoothdVersion()
Bluez5TestResultType
@ BluezNotAvailable
@ BluezVersion5
@ BluezVersionUnknown
QMap< QDBusObjectPath, InterfaceList > ManagedObjectList
QMap< QString, QDBusVariant > ServiceDataList
QT_BEGIN_NAMESPACE void initializeBluez5()
#define HCIGETDEVLIST
#define HCIGETCONNLIST
#define HCI_MAX_DEV
#define BTPROTO_HCI
#define HCIGETDEVINFO
void PropertiesChanged(const QString &interface, const QVariantMap &changed_properties, const QStringList &invalidated_properties, const QDBusMessage &msg)
\inmodule QtBluetooth
\inmodule QtCore
Definition qbytearray.h:57
QDBusReply< uint > servicePid(const QString &serviceName) const
Returns the Unix Process ID (PID) for the process currently holding the bus service serviceName.
\inmodule QtDBus
static QDBusConnection systemBus()
Returns a QDBusConnection object opened with the system bus.
QDBusConnectionInterface * interface() const
Returns a QDBusConnectionInterface object that represents the D-Bus server interface on this connecti...
\inmodule QtDBus
\inmodule QtDBus
\inmodule QtCore
Definition qfile.h:93
Definition qmap.h:187
bool contains(const Key &key) const
Definition qmap.h:341
size_type remove(const Key &key)
Definition qmap.h:300
QList< Key > keys() const
Definition qmap.h:383
T take(const Key &key)
Definition qmap.h:322
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
QObject * sender() const
Returns a pointer to the object that sent the signal, if called in a slot activated by a signal; othe...
Definition qobject.cpp:2658
const_iterator constBegin() const noexcept
Definition qset.h:139
const_iterator constEnd() const noexcept
Definition qset.h:143
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5949
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition qstring.h:994
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
const QChar * unicode() const
Returns a Unicode representation of the string.
Definition qstring.h:1230
\inmodule QtCore
static Q_CORE_EXPORT QVersionNumber fromString(QAnyStringView string, qsizetype *suffixIndex=nullptr)
QMap< QString, AdapterData * > references
OrgFreedesktopDBusObjectManagerInterface * manager
void discoveryInterrupted(const QString &adapterPath)
static QtBluezDiscoveryManager * instance()
bool registerDiscoveryInterest(const QString &adapterPath)
void unregisterDiscoveryInterest(const QString &adapterPath)
QString text
QSet< QString >::iterator it
Combined button and popup list for selecting options.
constexpr QBindableInterface iface
Definition qproperty.h:666
bool qt_haveLinuxProcfs()
static int qt_safe_close(int fd)
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 int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char * interface
#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS)
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
Q_DECL_COLD_FUNCTION Q_CORE_EXPORT QString qt_error_string(int errorCode=-1)
#define qWarning
Definition qlogging.h:166
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
#define QT_IMPL_METATYPE_EXTERN(TYPE)
Definition qmetatype.h:1390
static int qt_safe_ioctl(int sockfd, unsigned long request, T arg)
static int qt_safe_socket(int domain, int type, int protocol, int flags=0)
Definition qnet_unix_p.h:45
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLsizei GLsizei GLenum void * binary
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint buffer
GLint reference
GLsizei const GLchar *const * path
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
#define QStringLiteral(str)
QString qEnvironmentVariable(const char *varName, const QString &defaultValue)
#define emit
#define Q_UNUSED(x)
ptrdiff_t qsizetype
Definition qtypes.h:165
long long qint64
Definition qtypes.h:60
unsigned short ushort
Definition qtypes.h:33
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QNetworkAccessManager manager
QNetworkReply * reply
QHostInfo info
[0]
char * toString(const MyType &t)
[31]
OrgFreedesktopDBusPropertiesInterface * propteryListener
\inmodule QtCore \reentrant
Definition qchar.h:18