12 #ifndef hifi_Shared_QtHelpers_h
13 #define hifi_Shared_QtHelpers_h
15 #include <QtCore/QObject>
16 #include <QtCore/QLoggingCategory>
17 #include <QtCore/QThread>
19 #include "../Profile.h"
23 #define DEBUG_EVENT_QUEUE
26 class QLoggingCategory;
27 const QLoggingCategory& thread_safety();
29 namespace hifi {
namespace qt {
30 void addBlockingForbiddenThread(
const QString& name, QThread* thread =
nullptr);
31 QString isBlockingForbiddenThread(QThread* currentThread);
33 bool blockingInvokeMethod(
35 QObject *obj,
const char *member,
36 QGenericReturnArgument ret,
37 QGenericArgument val0 = QGenericArgument(Q_NULLPTR),
38 QGenericArgument val1 = QGenericArgument(),
39 QGenericArgument val2 = QGenericArgument(),
40 QGenericArgument val3 = QGenericArgument(),
41 QGenericArgument val4 = QGenericArgument(),
42 QGenericArgument val5 = QGenericArgument(),
43 QGenericArgument val6 = QGenericArgument(),
44 QGenericArgument val7 = QGenericArgument(),
45 QGenericArgument val8 = QGenericArgument(),
46 QGenericArgument val9 = QGenericArgument());
48 bool blockingInvokeMethod(
50 QObject *obj,
const char *member,
51 QGenericArgument val0 = QGenericArgument(Q_NULLPTR),
52 QGenericArgument val1 = QGenericArgument(),
53 QGenericArgument val2 = QGenericArgument(),
54 QGenericArgument val3 = QGenericArgument(),
55 QGenericArgument val4 = QGenericArgument(),
56 QGenericArgument val5 = QGenericArgument(),
57 QGenericArgument val6 = QGenericArgument(),
58 QGenericArgument val7 = QGenericArgument(),
59 QGenericArgument val8 = QGenericArgument(),
60 QGenericArgument val9 = QGenericArgument());
63 template <
typename Func,
typename ReturnType>
64 typename std::enable_if<!std::is_convertible<Func, const char*>::value,
bool>::type
65 blockingInvokeMethod(
const char* callingFunction, QObject* context, Func
function, ReturnType* retVal) {
66 auto currentThread = QThread::currentThread();
67 if (currentThread == qApp->thread()) {
68 qCWarning(thread_safety) <<
"BlockingQueuedConnection invoked on main thread from " << callingFunction;
69 return QMetaObject::invokeMethod(context,
function, Qt::BlockingQueuedConnection, retVal);
72 QString forbiddenThread = isBlockingForbiddenThread(currentThread);
73 if (!forbiddenThread.isEmpty()) {
74 qCWarning(thread_safety) <<
"BlockingQueuedConnection invoked on forbidden thread " << forbiddenThread;
77 PROFILE_RANGE(app, callingFunction);
78 return QMetaObject::invokeMethod(context,
function, Qt::BlockingQueuedConnection, retVal);
81 template <
typename Func>
82 typename std::enable_if<!std::is_convertible<Func, const char*>::value,
bool>::type
83 blockingInvokeMethod(
const char* callingFunction, QObject* context, Func
function) {
84 auto currentThread = QThread::currentThread();
85 if (currentThread == qApp->thread()) {
86 qCWarning(thread_safety) <<
"BlockingQueuedConnection invoked on main thread from " << callingFunction;
87 return QMetaObject::invokeMethod(context,
function, Qt::BlockingQueuedConnection);
90 QString forbiddenThread = isBlockingForbiddenThread(currentThread);
91 if (!forbiddenThread.isEmpty()) {
92 qCWarning(thread_safety) <<
"BlockingQueuedConnection invoked on forbidden thread " << forbiddenThread;
95 PROFILE_RANGE(app, callingFunction);
96 return QMetaObject::invokeMethod(context,
function, Qt::BlockingQueuedConnection);
106 #ifdef DEBUG_EVENT_QUEUE
107 int getEventQueueSize(QThread* thread);
108 void dumpEventQueue(QThread* thread);
113 #define BLOCKING_INVOKE_METHOD(obj, member, ...) \
114 ::hifi::qt::blockingInvokeMethod(__FUNCTION__, obj, member, ##__VA_ARGS__)