Skip to content

Commit 916ae1e

Browse files
author
Gabriel de Dietrich
committed
Implement qScriptConnect(), qScriptDisconnect()
These functions are currently being used by QDeclarative. Needed for tst_qdeclarativeecmascript. The semantics are stricter than what the documentation suggests. When calling qScriptDisconnect(), the connection must have been be made with qScriptConnect(). Reviewed-by: Olivier
1 parent 6e5c8d1 commit 916ae1e

File tree

7 files changed

+219
-145
lines changed

7 files changed

+219
-145
lines changed

src/script/api/qscriptengine.cpp

Lines changed: 76 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2501,28 +2501,90 @@ QScriptEngineAgent *QScriptEngine::agent() const
25012501
return agent ? QScriptEngineAgentPrivate::get(agent) : 0;
25022502
}
25032503

2504+
inline v8::Persistent<v8::Object> QScriptEnginePrivate::v8ObjectForConnectedObject(const QObject *o) const
2505+
{
2506+
return m_connectedObjects.value(o);
2507+
}
2508+
2509+
inline void QScriptEnginePrivate::addV8ObjectForConnectedObject(const QObject *o, v8::Persistent<v8::Object> v8Object)
2510+
{
2511+
m_connectedObjects.insert(o, v8Object);
2512+
}
2513+
2514+
void QScriptEnginePrivate::_q_removeConnectedObject(QObject *o)
2515+
{
2516+
m_connectedObjects.take(o).Dispose();
2517+
}
2518+
25042519
bool qScriptConnect(QObject *sender, const char *signal,
25052520
const QScriptValue &receiver,
25062521
const QScriptValue &function)
25072522
{
2508-
Q_UNUSED(sender);
2509-
Q_UNUSED(signal);
2510-
Q_UNUSED(receiver);
2511-
Q_UNUSED(function);
2512-
Q_UNIMPLEMENTED();
2513-
return false;
2523+
if (!sender || !signal)
2524+
return false;
2525+
if (!function.isFunction()) {
2526+
qWarning("qScriptConnect(): 'function' is not a function");
2527+
return false;
2528+
}
2529+
if (receiver.isObject() && (receiver.engine() != function.engine())) {
2530+
qWarning("qScriptConnect(): 'receiver' and 'function' don't share the same engine");
2531+
return false;
2532+
}
2533+
2534+
QScriptEnginePrivate *engine = QScriptEnginePrivate::get(function.engine());
2535+
v8::Handle<v8::Object> v8Sender = engine->v8ObjectForConnectedObject(sender);
2536+
if (v8Sender.IsEmpty()) {
2537+
v8Sender = v8::Handle<v8::Object>::Cast(engine->newQObject(sender));
2538+
engine->addV8ObjectForConnectedObject(sender, v8::Persistent<v8::Object>::New(v8Sender));
2539+
QObject::connect(sender, SIGNAL(destroyed(QObject*)),
2540+
function.engine(), SLOT(_q_removeConnectedObject(QObject*)));
2541+
}
2542+
2543+
QString signalName(signal);
2544+
signalName.remove(0, 1);
2545+
2546+
v8::Handle<v8::Object> signalData = v8Sender->Get(QScriptConverter::toString(signalName))->ToObject();
2547+
if (signalData.IsEmpty() || signalData->IsError() || signalData->IsUndefined()) {
2548+
qWarning("qScriptConnect(): signal '%s' is undefined", qPrintable(signalName));
2549+
return false;
2550+
}
2551+
v8::Handle<v8::Object> v8Receiver;
2552+
if (receiver.isObject())
2553+
v8Receiver = v8::Handle<v8::Object>(*QScriptValuePrivate::get(receiver));
2554+
return !QScriptSignalData::get(signalData)->connect(v8Receiver, v8::Handle<v8::Object>(*QScriptValuePrivate::get(function)))->IsError();
25142555
}
25152556

25162557
bool qScriptDisconnect(QObject *sender, const char *signal,
25172558
const QScriptValue &receiver,
25182559
const QScriptValue &function)
25192560
{
2520-
Q_UNUSED(sender);
2521-
Q_UNUSED(signal);
2522-
Q_UNUSED(receiver);
2523-
Q_UNUSED(function);
2524-
Q_UNIMPLEMENTED();
2525-
return false;
2561+
if (!sender || !signal)
2562+
return false;
2563+
if (!function.isFunction()) {
2564+
qWarning("qScriptDisconnect(): 'function' is not a function");
2565+
return false;
2566+
}
2567+
if (receiver.isObject() && (receiver.engine() != function.engine())) {
2568+
qWarning("qScriptDisconnect(): 'receiver' and 'function' don't share the same engine");
2569+
return false;
2570+
}
2571+
2572+
QScriptEnginePrivate *engine = QScriptEnginePrivate::get(function.engine());
2573+
v8::Handle<v8::Object> v8Sender = engine->v8ObjectForConnectedObject(sender);
2574+
if (v8Sender.IsEmpty()) {
2575+
qWarning("qScriptDisconnect(): 'sender' and ('receiver','function') were not connected with qScriptConnect()");
2576+
return false;
2577+
}
2578+
2579+
QString signalName(signal);
2580+
signalName.remove(0, 1);
2581+
2582+
v8::Handle<v8::Object> signalData = v8Sender->Get(QScriptConverter::toString(signalName))->ToObject();
2583+
if (signalData.IsEmpty() || signalData->IsError() || signalData->IsUndefined()) {
2584+
qWarning("qScriptDisconnect(): signal '%s' is undefined", qPrintable(signalName));
2585+
return false;
2586+
}
2587+
return !QScriptSignalData::get(signalData)->disconnect(v8::Handle<v8::Function>::Cast(v8::Handle<v8::Value>(*QScriptValuePrivate::get(function))))->IsError();
25262588
}
25272589

25282590
#ifdef QT_BUILD_INTERNAL
@@ -2576,3 +2638,5 @@ QScriptValue::PropertyFlags QScriptEnginePrivate::getPropertyFlagsFromScriptClas
25762638
}
25772639

25782640
QT_END_NAMESPACE
2641+
2642+
#include "moc_qscriptengine.cpp"

src/script/api/qscriptengine.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ class Q_SCRIPT_EXPORT QScriptEngine
218218
private:
219219
Q_DECLARE_PRIVATE(QScriptEngine)
220220
Q_DISABLE_COPY(QScriptEngine)
221+
Q_PRIVATE_SLOT(d_func(), void _q_removeConnectedObject(QObject*))
221222
};
222223

223224
#define Q_SCRIPT_DECLARE_QMETAOBJECT(T, _Arg1) \

src/script/api/qscriptengine_p.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,11 @@ class QScriptEnginePrivate
191191

192192
QScriptValue scriptValueFromInternal(v8::Handle<v8::Value>) const;
193193

194+
v8::Persistent<v8::Object> v8ObjectForConnectedObject(const QObject *o) const;
195+
void addV8ObjectForConnectedObject(const QObject *o, v8::Persistent<v8::Object> v8Object);
196+
// private slot
197+
void _q_removeConnectedObject(QObject*);
198+
194199
inline operator v8::Handle<v8::Context>();
195200
inline void clearExceptions();
196201
inline void setException(v8::Handle<v8::Value> value, v8::Handle<v8::Message> message = v8::Handle<v8::Message>());
@@ -324,6 +329,7 @@ class QScriptEnginePrivate
324329
QScriptBagContainer<QScriptablePrivate> m_scriptable;
325330
QScriptBagContainer<QScriptEngineAgentPrivate> m_agents;
326331
QScriptBagContainer<QScriptEngineAgentPrivate::UnloadData> m_scripts;
332+
QHash<const QObject *, v8::Persistent<v8::Object> > m_connectedObjects;
327333

328334
QScriptEngineAgentPrivate *m_currentAgent;
329335
class ProcessEventTimeoutThread;

src/script/api/qscriptqobject.cpp

Lines changed: 4 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -386,13 +386,11 @@ class QtObjectNotifyCaller : public QObject
386386
}
387387
};
388388

389-
390389
// A C++ signal-to-JS handler connection.
391390
//
392391
// Acts as a middle-man; intercepts a C++ signal,
393392
// and invokes a JS callback function.
394393
//
395-
class QScriptSignalData;
396394
class QScriptConnection : public QObject
397395
{
398396
public:
@@ -425,138 +423,12 @@ class QScriptConnection : public QObject
425423
v8::Persistent<v8::Object> m_receiver;
426424
};
427425

428-
union QScriptMetaMethodInfo {
429-
QScriptMetaMethodInfo(): intData(0)
430-
{ }
431-
432-
uint32_t intData;
433-
struct {
434-
uint index: 28;
435-
uint resolveMode: 1;
436-
uint overloaded: 1;
437-
uint voidvoid: 1;
438-
uint padding: 1; // Make sure the struct fits in an SMI
439-
};
440-
};
441-
442-
template <typename T, v8::Persistent<v8::FunctionTemplate> QScriptEnginePrivate::*functionTemplate>
443-
class QScriptGenericMetaMethodData : public QScriptV8ObjectWrapper<T, functionTemplate> {
444-
public:
445-
enum ResolveMode {
446-
ResolvedByName = 0,
447-
ResolvedBySignature = 1
448-
};
449-
450-
QScriptGenericMetaMethodData(QScriptEnginePrivate *eng, v8::Handle<v8::Object> object, QScriptMetaMethodInfo info)
451-
: m_object(v8::Persistent<v8::Object>::New(object)), m_info(info)
452-
{
453-
this->engine = eng;
454-
// We cannot keep a persistant reference to the object, else it would never be garbage collected.
455-
// (the object also reference us, and persistent object are automatically marked.
456-
// A reference is kept in the second internal field of the v8 method object.
457-
m_object.MakeWeak(this, objectDestroyed);
458-
}
459-
~QScriptGenericMetaMethodData()
460-
{
461-
m_object.Dispose();
462-
}
463-
464-
// The QObject wrapper object that this signal is bound to.
465-
v8::Handle<v8::Object> object() const
466-
{ return m_object; }
467-
468-
int index() const
469-
{ return m_info.index; }
470-
471-
ResolveMode resolveMode() const
472-
{ return ResolveMode(m_info.resolveMode); }
473-
474-
v8::Handle<v8::Value> call();
475-
476-
v8::Persistent<v8::Object> m_object;
477-
QScriptMetaMethodInfo m_info;
478-
private:
479-
static void objectDestroyed(v8::Persistent<v8::Value> object, void *data) {
480-
QScriptGenericMetaMethodData *that = static_cast<QScriptGenericMetaMethodData *>(data);
481-
Q_ASSERT(that->m_object == object);
482-
that->m_object.Clear();
483-
object.Dispose();
484-
// Note that since the method keep a reference to the object in its internal field,
485-
// this is only called when the QScriptGenericMetaMethodData is about to be garbage collected as well.
486-
}
487-
};
488-
489-
class QScriptMetaMethodData : public QScriptGenericMetaMethodData<QScriptMetaMethodData, &QScriptEnginePrivate::metaMethodTemplate>
426+
QScriptSignalData::~QScriptSignalData()
490427
{
491-
typedef QScriptGenericMetaMethodData<QScriptMetaMethodData, &QScriptEnginePrivate::metaMethodTemplate> Base;
492-
public:
493-
QScriptMetaMethodData(QScriptEnginePrivate *engine, v8::Handle<v8::Object> object, QScriptMetaMethodInfo info)
494-
: Base(engine, object, info)
495-
{ }
496-
497-
static v8::Handle<v8::FunctionTemplate> createFunctionTemplate(QScriptEnginePrivate *engine);
498-
};
499-
500-
// Data associated with a signal JS wrapper object.
501-
//
502-
// A signal wrapper is bound to the particular Qt wrapper object
503-
// where it was looked up as a member, i.e. signal wrappers are
504-
// _per instance_, not per class (prototype). This is in order
505-
// to support the connect() and disconnect() syntax:
506-
//
507-
// button1.clicked.connect(...);
508-
// button2.clicked.connect(...);
509-
//
510-
// When connect() is called, the this-object will be the signal
511-
// wrapper, not the QObject. Hence, in order to know which object's
512-
// clicked() signal to connect to, the signal must be bound to
513-
// that object.
514-
//
515-
// - object: The Qt wrapper object that this signal is bound to.
516-
//
517-
// - index: The index of the C++ signal.
518-
//
519-
// - resolve mode: How the signal was resolved; by name or signature.
520-
// If it was resolved by name, there's a chance the signal might have overloads.
521-
//
522-
class QScriptSignalData : public QScriptGenericMetaMethodData<QScriptSignalData, &QScriptEnginePrivate::signalTemplate>
523-
{
524-
typedef QScriptGenericMetaMethodData<QScriptSignalData, &QScriptEnginePrivate::signalTemplate> Base;
525-
public:
526-
527-
QScriptSignalData(QScriptEnginePrivate *engine, v8::Handle<v8::Object> object, QScriptMetaMethodInfo info)
528-
: Base(engine, object, info)
529-
{ }
530-
531-
~QScriptSignalData()
532-
{
533-
foreach (QScriptConnection *connection, m_connections) {
534-
delete connection;
535-
}
428+
foreach (QScriptConnection *connection, m_connections) {
429+
delete connection;
536430
}
537-
538-
static v8::Handle<v8::FunctionTemplate> createFunctionTemplate(QScriptEnginePrivate *engine);
539-
540-
v8::Handle<v8::Value> connect(v8::Handle<v8::Object> receiver,
541-
v8::Handle<v8::Object> slot,
542-
Qt::ConnectionType type = Qt::AutoConnection);
543-
v8::Handle<v8::Value> disconnect(v8::Handle<v8::Function> callback);
544-
545-
static QScriptSignalData *get(v8::Handle<v8::Object> object)
546-
{
547-
void *ptr = object->GetPointerFromInternalField(0);
548-
Q_ASSERT(ptr != 0);
549-
return static_cast<QScriptSignalData*>(ptr);
550-
}
551-
552-
void unregisterQScriptConnection(QScriptConnection *connection) { m_connections.removeAll(connection); }
553-
private:
554-
static v8::Handle<v8::Value> QtConnectCallback(const v8::Arguments& args);
555-
static v8::Handle<v8::Value> QtDisconnectCallback(const v8::Arguments& args);
556-
QList<QScriptConnection*> m_connections;
557-
};
558-
559-
431+
}
560432

561433
v8::Handle<v8::FunctionTemplate> QScriptSignalData::createFunctionTemplate(QScriptEnginePrivate* engine)
562434
{

0 commit comments

Comments
 (0)