QtGStreamer  0.10.2
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
signal.cpp
00001 /*
00002     Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com>
00003     Copyright (C) 2010 Collabora Ltd.
00004       @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
00005 
00006     This library is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU Lesser General Public License as published
00008     by the Free Software Foundation; either version 2.1 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU Lesser General Public License for more details.
00015 
00016     You should have received a copy of the GNU Lesser General Public License
00017     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00018 */
00019 #include "signal.h"
00020 #include "quark.h"
00021 #include <glib-object.h>
00022 #include <QtCore/QStringList>
00023 #include <QtCore/QDebug>
00024 
00025 //proper initializer for GValue structs on the stack
00026 #define QGLIB_G_VALUE_INITIALIZER {0, {{0}, {0}}}
00027 
00028 namespace QGlib {
00029 
00030 //BEGIN ******** Signal ********
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 //static
00117 Signal Signal::lookup(const char *name, Type type)
00118 {
00119     return Signal(g_signal_lookup(name, type));
00120 }
00121 
00122 //static
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 //END ******** Signal ********
00136 
00137 namespace Private {
00138 
00139 //BEGIN ******** emit ********
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     //initialize arguments array
00151     GValue *values = new GValue[args.size() + 1];
00152     memset(values, 0, sizeof(GValue) * (args.size() + 1));
00153 
00154     //set instance
00155     g_value_init(&values[0], itype);
00156     g_value_set_instance(&values[0], instance);
00157 
00158     try {
00159         //find the signal and perform sanity checks
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         //set arguments
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         //initialize return value
00184         GValue returnValue = QGLIB_G_VALUE_INITIALIZER;
00185         if (signal.returnType() != Type::None) {
00186             g_value_init(&returnValue, signal.returnType());
00187         }
00188 
00189         //emit the signal
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     //cleanup
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 //END ******** emit ********
00213 
00214 } //namespace Private
00215 } //namespace QGlib