00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "signal.h"
00020 #include "quark.h"
00021 #include <glib-object.h>
00022 #include <QtCore/QStringList>
00023 #include <QtCore/QDebug>
00024
00025
00026 #define QGLIB_G_VALUE_INITIALIZER {0, {{0}, {0}}}
00027
00028 namespace QGlib {
00029
00030
00031
00032 #ifndef DOXYGEN_RUN
00033
00034 struct QTGLIB_NO_EXPORT Signal::Private : public QSharedData
00035 {
00036 Private(uint i) : id(i), m_queryInitialized(false) {}
00037
00038 uint id;
00039 GSignalQuery *query() const;
00040
00041 private:
00042 mutable GSignalQuery m_query;
00043 mutable bool m_queryInitialized;
00044 };
00045
00046 GSignalQuery *Signal::Private::query() const
00047 {
00048 if (!m_queryInitialized) {
00049 g_signal_query(id, &m_query);
00050 m_queryInitialized = true;
00051 }
00052 return &m_query;
00053 }
00054
00055 #endif //DOXYGEN_RUN
00056
00057 Signal::Signal(uint id)
00058 : d(new Private(id))
00059 {
00060 }
00061
00062 Signal::Signal(const Signal & other)
00063 : d(other.d)
00064 {
00065 }
00066
00067 Signal & Signal::operator=(const Signal & other)
00068 {
00069 d = other.d;
00070 return *this;
00071 }
00072
00073 Signal::~Signal()
00074 {
00075 }
00076
00077 bool Signal::isValid() const
00078 {
00079 return d->id != 0;
00080 }
00081
00082 uint Signal::id() const
00083 {
00084 return d->id;
00085 }
00086
00087 QString Signal::name() const
00088 {
00089 return QString::fromUtf8(d->query()->signal_name);
00090 }
00091
00092 Signal::SignalFlags Signal::flags() const
00093 {
00094 return QFlag(d->query()->signal_flags);
00095 }
00096
00097 Type Signal::instanceType() const
00098 {
00099 return d->query()->itype;
00100 }
00101
00102 Type Signal::returnType() const
00103 {
00104 return d->query()->return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE;
00105 }
00106
00107 QList<Type> Signal::paramTypes() const
00108 {
00109 QList<Type> result;
00110 for(uint i=0; i<d->query()->n_params; ++i) {
00111 result.append(d->query()->param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE);
00112 }
00113 return result;
00114 }
00115
00116
00117 Signal Signal::lookup(const char *name, Type type)
00118 {
00119 return Signal(g_signal_lookup(name, type));
00120 }
00121
00122
00123 QList<Signal> Signal::listSignals(Type type)
00124 {
00125 QList<Signal> result;
00126 uint n_ids;
00127 uint *ids = g_signal_list_ids(type, &n_ids);
00128 for(uint i=0; i<n_ids; ++i) {
00129 result.append(Signal(ids[i]));
00130 }
00131 g_free(ids);
00132 return result;
00133 }
00134
00135
00136
00137 namespace Private {
00138
00139
00140
00141 Value emit(void *instance, const char *detailedSignal, Quark detail, const QList<Value> & args)
00142 {
00143 Value result;
00144 Type itype = Type::fromInstance(instance);
00145 QStringList signalParts = QString::fromUtf8(detailedSignal).split(QLatin1String("::"));
00146 if (!detail && signalParts.size() > 1) {
00147 detail = Quark::fromString(signalParts[1]);
00148 }
00149
00150
00151 GValue *values = new GValue[args.size() + 1];
00152 memset(values, 0, sizeof(GValue) * (args.size() + 1));
00153
00154
00155 g_value_init(&values[0], itype);
00156 g_value_set_instance(&values[0], instance);
00157
00158 try {
00159
00160 Signal signal = Signal::lookup(signalParts[0].toUtf8(), itype);
00161 if (!signal.isValid()) {
00162 throw QString(QLatin1String("Could not find any signal named %1 "
00163 "on this instance type")).arg(signalParts[0]);
00164 }
00165
00166 QList<Type> paramTypes = signal.paramTypes();
00167 if (paramTypes.size() != args.size()) {
00168 throw QString(QLatin1String("The number of arguments that the signal accepts differ "
00169 "from the number of arguments provided to emit"));
00170 }
00171
00172
00173 for(int i=0; i<args.size(); i++) {
00174 if (!args[i].type().isA(paramTypes[i])) {
00175 throw QString(QLatin1String("Argument %1 provided to emit is not of the "
00176 "type that the signal expects")).arg(i);
00177 } else {
00178 g_value_init(&values[i+1], args[i].type());
00179 g_value_copy(args[i], &values[i+1]);
00180 }
00181 }
00182
00183
00184 GValue returnValue = QGLIB_G_VALUE_INITIALIZER;
00185 if (signal.returnType() != Type::None) {
00186 g_value_init(&returnValue, signal.returnType());
00187 }
00188
00189
00190 g_signal_emitv(values, signal.id(), detail, &returnValue);
00191
00192 if (G_IS_VALUE(&returnValue)) {
00193 result = Value(&returnValue);
00194 g_value_unset(&returnValue);
00195 }
00196 } catch (const QString & msg) {
00197 QString instanceName = Value(&values[0]).toString();
00198
00199 qCritical() << "Error during emission of signal" << detailedSignal
00200 << "on object"<< instanceName << ":" << msg;
00201 }
00202
00203
00204 for(int i=0; i<args.size() + 1; i++) {
00205 g_value_unset(&values[i]);
00206 }
00207 delete[] values;
00208
00209 return result;
00210 }
00211
00212
00213
00214 }
00215 }