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 | #ifndef QQMLTHREAD_P_H |
5 | #define QQMLTHREAD_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists purely as an |
12 | // implementation detail. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | |
19 | #include <QtCore/qglobal.h> |
20 | |
21 | #include <private/qintrusivelist_p.h> |
22 | |
23 | QT_BEGIN_NAMESPACE |
24 | |
25 | class QThread; |
26 | class QMutex; |
27 | |
28 | class QQmlThreadPrivate; |
29 | class QQmlThread |
30 | { |
31 | public: |
32 | QQmlThread(); |
33 | virtual ~QQmlThread(); |
34 | |
35 | void startup(); |
36 | void shutdown(); |
37 | bool isShutdown() const; |
38 | |
39 | QMutex &mutex(); |
40 | void lock(); |
41 | void unlock(); |
42 | void wakeOne(); |
43 | void wait(); |
44 | |
45 | QThread *thread() const; |
46 | bool isThisThread() const; |
47 | |
48 | // Synchronously invoke a method in the thread |
49 | template<typename Method, typename ...Args> |
50 | void callMethodInThread(Method &&method, Args &&...args); |
51 | |
52 | // Synchronously invoke a method in the main thread. If the main thread is |
53 | // blocked in a callMethodInThread() call, the call is made from within that |
54 | // call. |
55 | template<typename Method, typename ...Args> |
56 | void callMethodInMain(Method &&method, Args &&...args); |
57 | |
58 | // Asynchronously invoke a method in the thread. |
59 | template<typename Method, typename ...Args> |
60 | void postMethodToThread(Method &&method, Args &&...args); |
61 | |
62 | // Asynchronously invoke a method in the main thread. |
63 | template<typename Method, typename ...Args> |
64 | void postMethodToMain(Method &&method, Args &&...args); |
65 | |
66 | void waitForNextMessage(); |
67 | |
68 | private: |
69 | friend class QQmlThreadPrivate; |
70 | |
71 | struct Message { |
72 | Message() : next(nullptr) {} |
73 | virtual ~Message() {} |
74 | Message *next; |
75 | virtual void call(QQmlThread *) = 0; |
76 | }; |
77 | template<typename Method, typename ...Args> |
78 | Message *createMessageFromMethod(Method &&method, Args &&...args); |
79 | void internalCallMethodInThread(Message *); |
80 | void internalCallMethodInMain(Message *); |
81 | void internalPostMethodToThread(Message *); |
82 | void internalPostMethodToMain(Message *); |
83 | QQmlThreadPrivate *d; |
84 | }; |
85 | |
86 | namespace QtPrivate { |
87 | template <typename> struct member_function_traits; |
88 | |
89 | template <typename Return, typename Object, typename... Args> |
90 | struct member_function_traits<Return (Object::*)(Args...)> |
91 | { |
92 | using class_type = Object; |
93 | }; |
94 | } |
95 | |
96 | template<typename Method, typename ...Args> |
97 | QQmlThread::Message *QQmlThread::createMessageFromMethod(Method &&method, Args &&...args) |
98 | { |
99 | struct I : public Message { |
100 | Method m; |
101 | std::tuple<std::decay_t<Args>...> arguments; |
102 | I(Method &&method, Args&& ...args) : m(std::forward<Method>(method)), arguments(std::forward<Args>(args)...) {} |
103 | void call(QQmlThread *thread) override { |
104 | using class_type = typename QtPrivate::member_function_traits<Method>::class_type; |
105 | class_type *me = static_cast<class_type *>(thread); |
106 | std::apply(m, std::tuple_cat(std::make_tuple(me), arguments)); |
107 | } |
108 | }; |
109 | return new I(std::forward<Method>(method), std::forward<Args>(args)...); |
110 | } |
111 | |
112 | template<typename Method, typename ...Args> |
113 | void QQmlThread::callMethodInMain(Method &&method, Args&& ...args) |
114 | { |
115 | Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...); |
116 | internalCallMethodInMain(m); |
117 | } |
118 | |
119 | template<typename Method, typename ...Args> |
120 | void QQmlThread::callMethodInThread(Method &&method, Args&& ...args) |
121 | { |
122 | Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...); |
123 | internalCallMethodInThread(m); |
124 | } |
125 | |
126 | template<typename Method, typename ...Args> |
127 | void QQmlThread::postMethodToThread(Method &&method, Args&& ...args) |
128 | { |
129 | Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...); |
130 | internalPostMethodToThread(m); |
131 | } |
132 | |
133 | template<typename Method, typename ...Args> |
134 | void QQmlThread::postMethodToMain(Method &&method, Args&& ...args) |
135 | { |
136 | Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...); |
137 | internalPostMethodToMain(m); |
138 | } |
139 | |
140 | QT_END_NAMESPACE |
141 | |
142 | #endif // QQMLTHREAD_P_H |
143 | |