1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtSystems module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL21$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 or version 3 as published by the Free
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22** following information to ensure the GNU Lesser General Public License
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** As a special exception, The Qt Company gives you certain additional
27** rights. These rights are described in The Qt Company LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** $QT_END_LICENSE$
31**
32****************************************************************************/
33#include "qslotinvoker_p.h"
34#include "qsignalintercepter_p.h"
35#include "qservicedebuglog_p.h"
36#include <qmetaobject.h>
37#include <qmetatype.h>
38#include <qvarlengtharray.h>
39
40#include <stdlib.h>
41
42/*!
43 \class QSlotInvoker
44 \inpublicgroup QtBaseModule
45 \internal
46
47 \brief The QSlotInvoker class provides an interface for invoking slots with explicit arguments
48
49 IPC mechanisms need to intercept protocol messages and convert them into
50 slot invocations, but it is generally impractical to create explicit code
51 for every slot that needs to be dispatched. The QSlotInvoker class allows
52 an IPC dispatching mechanism to invoke slots in a generic fashion using
53 the invoke() method.
54
55 Methods that are marked with Q_INVOKABLE or Q_SCRIPTABLE can also
56 be invoked with this class.
57
58 \sa QSignalIntercepter
59
60 \ingroup objectmodel
61*/
62
63QT_BEGIN_NAMESPACE
64
65class QSlotInvokerPrivate
66{
67public:
68 QObject *receiver;
69 QByteArray member;
70 int memberIndex;
71 bool destroyed;
72 int returnType;
73 int *types;
74 int numArgs;
75
76 ~QSlotInvokerPrivate()
77 {
78 if ( types )
79 free(ptr: types);
80 }
81};
82
83/*!
84 Create a slot invoker that can invoke \a member on \a receiver.
85 The object will be attached to \a parent, if present.
86*/
87QSlotInvoker::QSlotInvoker( QObject *receiver, const QByteArray &member,
88 QObject *parent )
89 : QObject( parent )
90{
91 d = new QSlotInvokerPrivate();
92 d->receiver = receiver;
93 QByteArray name;
94 if ( member.size() > 0 && member[0] >= '0' && member[0] <= '9' ) {
95 // Strip off the member type code.
96 name = member.mid(index: 1);
97 } else {
98 name = member;
99 }
100 name = QMetaObject::normalizedSignature( method: name.constData() );
101 d->member = name;
102 d->destroyed = false;
103 d->returnType = 0;
104 d->types = 0;
105 d->numArgs = 0;
106 if ( receiver && name.size() > 0 ) {
107 d->memberIndex
108 = receiver->metaObject()->indexOfMethod( method: name.constData() );
109 } else {
110 d->memberIndex = -1;
111 }
112 if ( d->memberIndex != -1 ) {
113 QMetaMethod method = receiver->metaObject()->method
114 ( index: d->memberIndex );
115 {
116 connect( sender: receiver, SIGNAL(destroyed()),
117 receiver: this, SLOT(receiverDestroyed()) );
118 d->returnType =
119 QSignalIntercepter::typeFromName( name: method.typeName() );
120 d->types = QSignalIntercepter::connectionTypes
121 ( member: name, nargs&: d->numArgs );
122 if ( !( d->types ) )
123 d->destroyed = true;
124 }
125 } else {
126 d->destroyed = true;
127 }
128}
129
130/*!
131 Destroy a slot invoker.
132*/
133QSlotInvoker::~QSlotInvoker()
134{
135 delete d;
136}
137
138/*!
139 Returns true if the member is present on the object.
140*/
141bool QSlotInvoker::memberPresent() const
142{
143 return ! d->destroyed;
144}
145
146/*!
147 Returns true if the member can be invoked with \a numArgs arguments.
148 That is, the receiver has not been destroyed, the member is present,
149 and it requires \a numArgs or less arguments.
150*/
151bool QSlotInvoker::canInvoke( int numArgs ) const
152{
153 if ( d->destroyed )
154 return false;
155 return ( numArgs >= d->numArgs );
156}
157
158/*!
159 Returns the object that will receive slot invocations.
160*/
161QObject *QSlotInvoker::receiver() const
162{
163 return d->receiver;
164}
165
166/*!
167 Returns the member that will receiver slot invocations.
168*/
169QByteArray QSlotInvoker::member() const
170{
171 return d->member;
172}
173
174/*!
175 Returns the parameter types associated with this member.
176*/
177int *QSlotInvoker::parameterTypes() const
178{
179 return d->types;
180}
181
182/*!
183 Returns the number of parameter types associated with this member.
184*/
185int QSlotInvoker::parameterTypesCount() const
186{
187 return d->numArgs;
188}
189
190/*!
191 Invokes the slot represented by this object with the argument
192 list \a args. The slot's return value is returned from
193 this method. If the slot's return type is "void", then a
194 QVariant instance of type QVariant::Invalid will be returned.
195
196 If it is possible that the slot may throw an exception,
197 it is the responsibility of the caller to catch and
198 handle the exception.
199*/
200QVariant QSlotInvoker::invoke( const QList<QVariant>& args )
201{
202 int arg;
203 QVariant returnValue;
204
205 // Create a default instance of the return type for the result buffer.
206 if ( d->returnType != (int)QVariant::Invalid ) {
207 returnValue = QVariant( d->returnType, (const void *)0 );
208 }
209
210 // Bail out if the receiver object has already disappeared.
211 if ( d->destroyed )
212 return returnValue;
213
214 // Check that the number of arguments is compatible with the slot.
215 int numArgs = args.size();
216 if ( numArgs < d->numArgs ) {
217 qWarning( msg: "QSlotInvoker::invoke: insufficient arguments for slot" );
218 return returnValue;
219 } else if ( numArgs > d->numArgs ) {
220 // Drop extraneous arguments.
221 numArgs = d->numArgs;
222 }
223
224 // Construct the raw argument list.
225 QVarLengthArray<void *, 32> a( numArgs + 1 );
226 if ( d->returnType == (int)QVariant::Invalid )
227 a[0] = 0;
228 else
229 a[0] = returnValue.data();
230 for ( arg = 0; arg < numArgs; ++arg ) {
231 if ( d->types[arg] == QSignalIntercepter::QVariantId ) {
232 a[arg + 1] = (void *)&( args[arg] );
233 } else if ( args[arg].userType() != d->types[arg] ) {
234 qWarning( msg: "QSlotInvoker::invoke: argument %d has incorrect type",
235 arg );
236 return QVariant();
237 } else {
238 a[arg + 1] = (void *)( args[arg].data() );
239 }
240 }
241
242 qServiceLog() << "event" << "slot invoked"
243 << "class" << "QSlotInvoker"
244 << "receiver" << d->receiver->objectName()
245 << "member" << QString::fromLatin1(str: d->member)
246 << "args" << numArgs;
247
248 // Invoke the specified slot.
249 d->receiver->qt_metacall( QMetaObject::InvokeMetaMethod,
250 d->memberIndex, a.data() );
251 return returnValue;
252}
253
254void QSlotInvoker::receiverDestroyed()
255{
256 d->destroyed = true;
257}
258
259#include "moc_qslotinvoker_p.cpp"
260
261QT_END_NAMESPACE
262

source code of qtsystems/src/serviceframework/ipc/qslotinvoker.cpp