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 | void discardMessages(); |
68 | |
69 | private: |
70 | friend class QQmlThreadPrivate; |
71 | |
72 | struct Message { |
73 | Message() : next(nullptr) {} |
74 | virtual ~Message() {} |
75 | Message *next; |
76 | virtual void call(QQmlThread *) = 0; |
77 | }; |
78 | template<typename Method, typename ...Args> |
79 | Message *createMessageFromMethod(Method &&method, Args &&...args); |
80 | void internalCallMethodInThread(Message *); |
81 | void internalCallMethodInMain(Message *); |
82 | void internalPostMethodToThread(Message *); |
83 | void internalPostMethodToMain(Message *); |
84 | QQmlThreadPrivate *d; |
85 | }; |
86 | |
87 | namespace QtPrivate { |
88 | template <typename> struct member_function_traits; |
89 | |
90 | template <typename Return, typename Object, typename... Args> |
91 | struct member_function_traits<Return (Object::*)(Args...)> |
92 | { |
93 | using class_type = Object; |
94 | }; |
95 | } |
96 | |
97 | template<typename Method, typename ...Args> |
98 | QQmlThread::Message *QQmlThread::createMessageFromMethod(Method &&method, Args &&...args) |
99 | { |
100 | struct I : public Message { |
101 | Method m; |
102 | std::tuple<std::decay_t<Args>...> arguments; |
103 | I(Method &&method, Args&& ...args) : m(std::forward<Method>(method)), arguments(std::forward<Args>(args)...) {} |
104 | void call(QQmlThread *thread) override { |
105 | using class_type = typename QtPrivate::member_function_traits<Method>::class_type; |
106 | class_type *me = static_cast<class_type *>(thread); |
107 | std::apply(m, std::tuple_cat(std::make_tuple(me), arguments)); |
108 | } |
109 | }; |
110 | return new I(std::forward<Method>(method), std::forward<Args>(args)...); |
111 | } |
112 | |
113 | template<typename Method, typename ...Args> |
114 | void QQmlThread::callMethodInMain(Method &&method, Args&& ...args) |
115 | { |
116 | Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...); |
117 | internalCallMethodInMain(m); |
118 | } |
119 | |
120 | template<typename Method, typename ...Args> |
121 | void QQmlThread::callMethodInThread(Method &&method, Args&& ...args) |
122 | { |
123 | Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...); |
124 | internalCallMethodInThread(m); |
125 | } |
126 | |
127 | template<typename Method, typename ...Args> |
128 | void QQmlThread::postMethodToThread(Method &&method, Args&& ...args) |
129 | { |
130 | Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...); |
131 | internalPostMethodToThread(m); |
132 | } |
133 | |
134 | template<typename Method, typename ...Args> |
135 | void QQmlThread::postMethodToMain(Method &&method, Args&& ...args) |
136 | { |
137 | Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...); |
138 | internalPostMethodToMain(m); |
139 | } |
140 | |
141 | QT_END_NAMESPACE |
142 | |
143 | #endif // QQMLTHREAD_P_H |
144 | |