Add option (enabled by default) to omit the sender from a slot's arguments. In most...
[qtgstreamer:qtgstreamer.git] / src / QGlib / signal.h
1 /*
2     Copyright (C) 2010  George Kiagiadakis <kiagiadakis.george@gmail.com>
3
4     This library is free software; you can redistribute it and/or modify
5     it under the terms of the GNU Lesser General Public License as published
6     by the Free Software Foundation; either version 2.1 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU Lesser General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 #ifndef QGLIB_SIGNAL_H
18 #define QGLIB_SIGNAL_H
19
20 #include "global.h"
21 #include "closure.h"
22 #include <QtCore/QString>
23 #include <QtCore/QFlags>
24 #include <QtCore/QSharedData>
25
26 #if !QGLIB_HAVE_CXX0X
27 //boost::bind restricts us to 9 arguments. if you need more,
28 //consider using a modern compiler with variadic template support ;)
29 # define QGLIB_SIGNAL_MAX_ARGS 9
30 # include <boost/preprocessor.hpp>
31 #endif
32
33 //Qt's emit will clash
34 #if defined(emit)
35 # if defined(Q_CC_GNU)
36 #  warning "The emit keyword is defined and will be undefined here to compile QGlib::Signal::emit."
37 #  warning "It is recommended to compile your project with QT_NO_KEYWORDS defined."
38 # elif defined(Q_CC_MSVC)
39 #  pragma message("Warning: The emit keyword is defined and will be undefined here to compile QGlib::Signal::emit.")
40 #  pragma message("Warning: It is recommended to compile your project with QT_NO_KEYWORDS defined.")
41 # endif
42 # undef emit
43 # define QT_NO_EMIT //undocumented Qt macro that skips "#define emit" in qglobal.h
44 #endif
45
46 namespace QGlib {
47
48 class SignalHandler
49 {
50 public:
51     inline bool isValid() const { return m_instance != NULL; }
52
53     bool isConnected() const;
54     void disconnect();
55
56     void block();
57     void unblock();
58
59 private:
60     friend class Signal;
61     inline SignalHandler()
62         : m_instance(NULL), m_id(0) {}
63     inline SignalHandler(void *instance, ulong id)
64         : m_instance(instance), m_id(id) {}
65
66     void *m_instance;
67     ulong m_id;
68 };
69
70 /*! \headerfile signal.h <QGlib/Signal>
71  * \brief Helper class providing integration with the GObject signal system
72  *
73  * Signals are a generic notification mechanism. Each signal is bound to a
74  * certain instantiatable Type and can be emitted on any instance of this type.
75  *
76  * This class allows you to inspect, emit and connect to these signals. To inspect
77  * the signals of a certain Type, you can use the lookup() and listSignals() methods.
78  * To emit or connect a signal, use the emit() and connect() methods respectively.
79  *
80  * For more information, please read the relevant Glib documentation.
81  */
82 class Signal
83 {
84 public:
85     enum SignalFlag {
86         RunFirst = 1<<0,
87         RunLast = 1<<1,
88         RunCleanup = 1<<2,
89         NoRecurse = 1<<3,
90         Detailed = 1<<4,
91         Action = 1<<5,
92         NoHooks = 1<<6
93     };
94     Q_DECLARE_FLAGS(SignalFlags, SignalFlag);
95
96     /*! These flags define options that can be passed to connect() to modify its behaviour. */
97     enum ConnectFlag { //codegen: skip=true
98         /*! If ConnectAfter is specified, the slot passed to connect() will be invoked after the
99          * default signal handler of this signal has been called. See the Glib signals
100          * documentation for more details on this parameter.
101          */
102         ConnectAfter = 1,
103         /*! If PassSender is specified, the slot passed to connect() will receive as the first
104          * argument a pointer to the sender of the signal. Thus, your slot should be defined
105          * like this:
106          * \code
107          * void mySlot(const QGlib::ObjectPtr & sender, const Foo & firstArgument, ...);
108          * \endcode
109          */
110         PassSender = 2
111     };
112     Q_DECLARE_FLAGS(ConnectFlags, ConnectFlag);
113
114     Signal(const Signal & other);
115     Signal & operator=(const Signal & other);
116     virtual ~Signal();
117
118     bool isValid() const;
119
120     uint id() const;
121     QString name() const;
122     SignalFlags flags() const;
123
124     Type instanceType() const;
125     Type returnType() const;
126     QList<Type> paramTypes() const;
127
128     static Signal lookup(const char *name, Type type);
129     static QList<Signal> listSignals(Type type);
130
131
132 #if QGLIB_HAVE_CXX0X
133
134     /*! Emits a signal on a specified \a instance with the specified arguments.
135      *
136      * This method will convert all the specified arguments to GValues using ValueBase::set()
137      * and will then call the non-templated emit() method, which is a wrapper for g_signal_emitv().
138      * The returned value from the signal (if the signal returns a value) will be converted
139      * from GValue to the type R using ValueBase::get() and will be returned. If some argument
140      * is not of the type that the signal expects, a warning will be printed to stderr at runtime
141      * and the signal will not be emitted. If the return value is not of the type that the signal
142      * returns, the signal will be emitted, but a default-constructed value for the type R will
143      * be returned and a warning will be printed to stderr.
144      *
145      * Note that since the implementation uses ValueBase::set() to convert the GValues into the
146      * specified types, the same rules that apply to ValueBase::set() apply here (i.e. you should
147      * only use the types of the bindings and not the C types, which means QGst::ObjectPtr instead
148      * of GstObject*, etc...).
149      *
150      * Emitting a signal is useful for the so-called Action signals. These are meant to be emitted
151      * from the application and not connected to. They are more like dynamic methods that can be
152      * identified with a string.
153      *
154      * \note This method makes use of C++0x features (namely, variadic templates and rvalue
155      * references). If your compiler does not support them, a hacky implementation using boost's
156      * preprocessor, function and bind libraries will be compiled instead. That version has a
157      * limit of 9 arguments.
158      *
159      * \param instance The instance of the object on which the signal will be emitted. You can pass
160      * a RefPointer as an instance without any problems; it will automatically cast to void*.
161      * \param detailedSignal The name of the signal that you want to emit, with an optional
162      * detail if the signal is detailed. The detail may be specified with the following syntax:
163      * "signal::detail".
164      * \param args The arguments that will be passed to the signal.
165      * \returns The return value of the signal.
166      */
167     template <typename R, typename... Args>
168     static R emit(void *instance, const char *detailedSignal, Args&&... args);
169
170     /*! Connects a signal to a specified \a slot.
171      *
172      * This method will generate a set of template functions and classes that bind on a GClosure.
173      * When the signal is emitted, this GClosure will be invoked and its templated marshaller
174      * function will take care of converting the parameters of the signal (which are given as
175      * GValues) to the types that the \a slot expects. In case the types do not match, a warning
176      * will be printed to stderr at runtime and the \a slot will not be invoked. You are
177      * responsible for defining the \a slot with the correct arguments!
178      *
179      * Note that since the implementation uses ValueBase::get() to convert the GValues into the
180      * specified types, the same rules that apply to ValueBase::get() apply here (i.e. you should
181      * only use the types of the bindings and not the C types, which means QGst::ObjectPtr instead
182      * of GstObject*, etc...).
183      *
184      * \note
185      * \li You can use const references for the arguments of the slot to avoid unnecessary
186      * copying of objects. The marshaller will always hold one copy of them during the execution
187      * of your \a slot.
188      * \li This method makes use of C++0x features (namely, variadic templates and rvalue
189      * references). If your compiler does not support them, a hacky implementation using boost's
190      * preprocessor, function and bind libraries will be compiled instead. That version has a
191      * limit of 9 slot arguments.
192      *
193      * \param instance The instance of the object that emits this signal. You can pass
194      * a RefPointer as an instance without any problems; it will automatically cast to void*.
195      * \param detailedSignal The name of the signal that you want to connect to, with an optional
196      * detail if the signal is detailed. The detail may be specified with the following syntax:
197      * "signal::detail".
198      * \param receiver The instance of the class on which \a slot will be invoked.
199      * \param slot A pointer to a member function that will be invoked when the signal is emitted.
200      * \param flags See ConnectFlag.
201      * \returns A SignalHandler instance, which can be used to disconnect or block this handler.
202      * Note that the return type of this function is subject to change before a stable release is made.
203      */
204     template <typename T, typename R, typename... Args>
205     static SignalHandler connect(void *instance, const char *detailedSignal,
206                                  T *receiver, R (T::*slot)(Args...), ConnectFlags flags = 0);
207
208 #else //QGLIB_HAVE_CXX0X
209
210     //versions that take no arguments
211     template <typename R>
212     static R emit(void *instance, const char *detailedSignal);
213
214     template <typename T, typename R>
215     static SignalHandler connect(void *instance, const char *detailedSignal,
216                                  T *receiver, R (T::*slot)(), ConnectFlags flags = 0);
217
218 # define QGLIB_SIGNAL_TMPL_PARAMS(n) \
219         BOOST_PP_ENUM_PARAMS(n, typename A)
220
221 # define QGLIB_SIGNAL_TMPL_ARGS(n) \
222         BOOST_PP_ENUM_PARAMS(n, A)
223
224 # define QGLIB_SIGNAL_EMIT_DECLARATION(z, n, data) \
225     template <typename R, QGLIB_SIGNAL_TMPL_PARAMS(n) > \
226     static R emit(void *instance, const char *detailedSignal, QGLIB_SIGNAL_TMPL_ARGS(n));
227
228 # define QGLIB_SIGNAL_CONNECT_DECLARATION(z, n, data) \
229     template <typename T, typename R, QGLIB_SIGNAL_TMPL_PARAMS(n) > \
230     static SignalHandler connect(void *instance, const char *detailedSignal, \
231                                  T *receiver, R (T::*slot)(QGLIB_SIGNAL_TMPL_ARGS(n)), \
232                                  ConnectFlags flags = 0);
233
234     //versions that take from 1 to QGLIB_SIGNAL_MAX_ARGS arguments
235     BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_INC(QGLIB_SIGNAL_MAX_ARGS), QGLIB_SIGNAL_EMIT_DECLARATION, dummy)
236     BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_INC(QGLIB_SIGNAL_MAX_ARGS), QGLIB_SIGNAL_CONNECT_DECLARATION, dummy)
237
238 # undef QGLIB_SIGNAL_CONNECT_DECLARATION
239 # undef QGLIB_SIGNAL_EMIT_DECLARATION
240 # undef QGLIB_SIGNAL_TMPL_ARGS
241 # undef QGLIB_SIGNAL_TMPL_PARAMS
242
243 #endif //QGLIB_HAVE_CXX0X
244
245     /*! \internal This method is used internally from the templated emit() method. */
246     static Value emit(void *instance, const char *detailedSignal, const QList<Value> & args);
247
248     /*! \internal This method is used internally from the templated connect() method. */
249     static SignalHandler connect(void *instance, const char *detailedSignal,
250                                  const ClosurePtr & closure, ConnectFlags flags = 0);
251
252 private:
253     Signal(uint id);
254
255     struct Private;
256     QSharedDataPointer<Private> d;
257 };
258
259 } //namespace QGlib
260
261 Q_DECLARE_OPERATORS_FOR_FLAGS(QGlib::Signal::SignalFlags)
262
263 #define IN_QGLIB_SIGNAL_H
264 # include "signalimpl_p.h"
265 #undef IN_QGLIB_SIGNAL_H
266
267 #if defined(QGLIB_SIGNAL_MAX_ARGS)
268 # undef QGLIB_SIGNAL_MAX_ARGS
269 #endif
270
271 #endif