summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Kiagiadakis <george.kiagiadakis@collabora.co.uk>2011-01-06 22:05:23 +0200
committerGeorge Kiagiadakis <george.kiagiadakis@collabora.co.uk>2011-01-06 22:05:23 +0200
commit86725fc8d6475279d50ac0a86cd0271dc971ce83 (patch)
tree7de6bb74dfe0f2acd66df6704af58aa09971a39a
parente43f0c3f28086fd070db60ea24cedb68b80a0f69 (diff)
Implement a new way of wraping objects, similar to the one glibmm uses.
Features: * C++ wrappers are reused among several RefPointer instances. * C++ wrappers are even saved in qdata where applicable, to make sure they are only created once for each object. (This does not apply to MiniObjects and Caps though) * dynamicCast should be faster in certain cases, since it no longer queries the GType of the instance if it is not necessary.
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/QGlib/global.h5
-rw-r--r--src/QGlib/init.cpp32
-rw-r--r--src/QGlib/object.h1
-rw-r--r--src/QGlib/paramspec.h1
-rw-r--r--src/QGlib/refpointer.h151
-rw-r--r--src/QGlib/wrap.cpp97
-rw-r--r--src/QGlib/wrap.h74
-rw-r--r--src/QGst/caps.cpp43
-rw-r--r--src/QGst/caps.h11
-rw-r--r--src/QGst/childproxy.h1
-rw-r--r--src/QGst/colorbalance.h1
-rw-r--r--src/QGst/global.cpp3
-rw-r--r--src/QGst/global.h2
-rw-r--r--src/QGst/miniobject.cpp43
-rw-r--r--src/QGst/miniobject.h9
-rw-r--r--src/QGst/propertyprobe.h1
-rw-r--r--src/QGst/streamvolume.h1
-rw-r--r--src/QGst/urihandler.h1
-rw-r--r--src/QGst/videoorientation.h1
-rw-r--r--src/QGst/xoverlay.h1
-rw-r--r--tests/auto/capstest.cpp2
-rw-r--r--tests/auto/refpointertest.cpp112
-rw-r--r--tests/auto/urihandlertest.cpp12
24 files changed, 530 insertions, 78 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 066d8e7..ff32b14 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -7,6 +7,8 @@ set(QtGstreamer_SRCS
QGlib/signal.cpp
QGlib/error.cpp
QGlib/connect.cpp
+ QGlib/wrap.cpp
+ QGlib/init.cpp
QGst/global.cpp
QGst/objectstore.cpp
@@ -48,6 +50,7 @@ set(INSTALLED_HEADERS
QGlib/quark.h QGlib/Quark
QGlib/type.h QGlib/Type
QGlib/refpointer.h QGlib/RefPointer
+ QGlib/wrap.h
QGlib/paramspec.h QGlib/ParamSpec
QGlib/object.h QGlib/Object
QGlib/value.h QGlib/Value
diff --git a/src/QGlib/global.h b/src/QGlib/global.h
index 7fa5c72..793735c 100644
--- a/src/QGlib/global.h
+++ b/src/QGlib/global.h
@@ -40,6 +40,10 @@ typedef RefPointer<ParamSpec> ParamSpecPtr;
class Object;
typedef RefPointer<Object> ObjectPtr;
+/*! Initializes the type system. You must call
+ * this function before using any QtGLib API. */
+void init();
+
} //namespace QGlib
@@ -51,7 +55,6 @@ typedef RefPointer<Object> ObjectPtr;
CppClass(const CppClass &); \
CppClass & operator=(const CppClass &); \
~CppClass() {} \
- template <class T> friend class QGlib::RefPointer; \
friend QGlib::RefCountedObject* FakeSuperClass##_new(void*); \
private:
diff --git a/src/QGlib/init.cpp b/src/QGlib/init.cpp
new file mode 100644
index 0000000..5dfc1fa
--- /dev/null
+++ b/src/QGlib/init.cpp
@@ -0,0 +1,32 @@
+/*
+ Copyright (C) 2010 Collabora Ltd. <info@collabora.co.uk>
+ @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <glib-object.h>
+
+namespace QGlib {
+
+namespace Private {
+ void registerWrapperConstructors(); //generated by codegen
+}
+
+void init()
+{
+ g_type_init();
+ Private::registerWrapperConstructors();
+}
+
+} //namespace QGlib
diff --git a/src/QGlib/object.h b/src/QGlib/object.h
index 94578e3..9d1d14d 100644
--- a/src/QGlib/object.h
+++ b/src/QGlib/object.h
@@ -99,5 +99,6 @@ void ObjectBase::setProperty(const char *name, const T & value)
QGLIB_REGISTER_TYPE(QGlib::Object)
QGLIB_REGISTER_TYPE(QGlib::Interface)
+QGLIB_REGISTER_WRAPIMPL_FOR_SUBCLASSES_OF(QGlib::Object, QGlib::Private::wrapObject)
#endif
diff --git a/src/QGlib/paramspec.h b/src/QGlib/paramspec.h
index 4cadb2e..11bb567 100644
--- a/src/QGlib/paramspec.h
+++ b/src/QGlib/paramspec.h
@@ -70,5 +70,6 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(ParamSpec::ParamFlags)
QGLIB_REGISTER_TYPE(QGlib::ParamSpec) //codegen: GType=G_TYPE_PARAM
QGLIB_REGISTER_TYPE(QGlib::ParamSpec::ParamFlags)
+QGLIB_REGISTER_WRAPIMPL_FOR_SUBCLASSES_OF(QGlib::ParamSpec, QGlib::Private::wrapParamSpec)
#endif
diff --git a/src/QGlib/refpointer.h b/src/QGlib/refpointer.h
index b42bc4d..25bf606 100644
--- a/src/QGlib/refpointer.h
+++ b/src/QGlib/refpointer.h
@@ -21,10 +21,18 @@
#include "global.h"
#include "type.h"
+#include "wrap.h"
#include <cstddef>
#include <boost/type_traits.hpp>
+#include <boost/utility/enable_if.hpp>
namespace QGlib {
+
+//forward declarations
+class Object;
+class Interface;
+
+
namespace Private {
template <class T, class X>
@@ -82,6 +90,9 @@ public:
inline RefPointer();
inline ~RefPointer();
+ /*! \internal */
+ explicit inline RefPointer(T *cppClass);
+
inline RefPointer(const RefPointer<T> & other);
template <class X>
inline RefPointer(const RefPointer<X> & other);
@@ -149,12 +160,13 @@ private:
*/
class RefCountedObject
{
+public:
+ virtual ~RefCountedObject() {}
+
protected:
template <class T> friend class RefPointer;
template <class T, class X> friend struct Private::RefPointerEqualityCheck;
- virtual ~RefCountedObject() {}
-
virtual void ref(bool increaseRef) = 0;
virtual void unref() = 0;
@@ -184,6 +196,12 @@ inline RefPointer<T>::~RefPointer()
}
template <class T>
+inline RefPointer<T>::RefPointer(T *cppClass)
+ : m_class(cppClass)
+{
+}
+
+template <class T>
template <class X>
inline RefPointer<T>::RefPointer(const RefPointer<X> & other)
: m_class(NULL)
@@ -221,11 +239,10 @@ void RefPointer<T>::assign(const RefPointer<X> & other)
{
//T should be a base class of X
QGLIB_STATIC_ASSERT((boost::is_base_of<T, X>::value),
- "Cannot upcast a RefPointer without using dynamicCast()");
+ "Cannot implicitly cast a RefPointer down the hierarchy");
if (!other.isNull()) {
- m_class = new T();
- m_class->m_object = other.m_class->m_object;
+ m_class = static_cast<T*>(other.m_class);
static_cast<RefCountedObject*>(m_class)->ref(true);
}
}
@@ -262,8 +279,7 @@ template <class T>
void RefPointer<T>::clear()
{
if (!isNull()) {
- static_cast<RefCountedObject*>(m_class)->unref();
- delete m_class;
+ static_cast<RefCountedObject*>(m_class)->unref(); //this may delete m_class at this point
m_class = NULL;
}
}
@@ -274,9 +290,10 @@ RefPointer<T> RefPointer<T>::wrap(typename T::CType *nativePtr, bool increaseRef
{
RefPointer<T> ptr;
if (nativePtr != NULL) {
- ptr.m_class = new T();
- ptr.m_class->m_object = nativePtr;
- static_cast<RefCountedObject*>(ptr.m_class)->ref(increaseRef);
+ RefCountedObject *cppObj = WrapImpl<T>::wrap(nativePtr);
+ cppObj->ref(increaseRef);
+ ptr.m_class = dynamic_cast<T*>(cppObj);
+ Q_ASSERT(ptr.m_class);
}
return ptr;
}
@@ -304,26 +321,126 @@ inline T *RefPointer<T>::operator->() const
template <class T>
inline RefPointer<T>::operator typename T::CType*() const
{
- return m_class ? static_cast<typename T::CType*>(m_class->m_object) : NULL;
+ return m_class ? static_cast<RefCountedObject*>(m_class)->object<typename T::CType>() : NULL;
}
template <class T>
template <class X>
RefPointer<X> RefPointer<T>::staticCast() const
{
- return isNull() ? RefPointer<X>()
- : RefPointer<X>::wrap(static_cast<typename X::CType*>(static_cast<X*>(m_class)->m_object));
+ RefPointer<X> result;
+ if (m_class) {
+ static_cast<RefCountedObject*>(m_class)->ref(true);
+ result.m_class = static_cast<X*>(m_class);
+ }
+ return result;
}
+
+namespace Private {
+
+template <typename T, typename X, typename Enable = void>
+struct IfaceDynamicCastImpl
+{
+ static inline X *doCast(typename X::CType *obj)
+ {
+ Q_UNUSED(obj);
+ return NULL;
+ }
+};
+
+//this version is compiled if X is an interface and T is an object,
+//i.e. we are dynamically casting from an object to an interface.
+template <typename T, typename X>
+struct IfaceDynamicCastImpl<T, X,
+ typename boost::enable_if_c<
+ //to check if something is an interface, we need to also verify that it does
+ //not inherit Object, since derived object classes may also derive from interfaces.
+ (boost::is_base_of<Interface, X>::value &&
+ !boost::is_base_of<Object, X>::value &&
+ boost::is_base_of<Object, T>::value)
+ >::type
+ >
+{
+ static inline X *doCast(typename X::CType *obj)
+ {
+ X *targetClass = NULL;
+
+ //Check that instanceType implements (isA) the interface
+ //and if it does, return a wrapper for that interface.
+ if (Type::fromInstance(obj).isA(GetType<X>()))
+ {
+ targetClass = dynamic_cast<X*>(Private::wrapInterface(GetType<X>(), obj));
+ Q_ASSERT(targetClass);
+ }
+
+ return targetClass;
+ }
+};
+
+//this version is compiled if T is an interface,
+//i.e. we are dynamically casting from an interface to either an object or another interface.
+template <typename T, typename X>
+struct IfaceDynamicCastImpl<T, X,
+ typename boost::enable_if_c<
+ //to check if something is an interface, we need to also verify that it does
+ //not inherit Object, since derived object classes may also derive from interfaces.
+ (boost::is_base_of<Interface, T>::value &&
+ !boost::is_base_of<Object, T>::value)
+ >::type
+ >
+{
+ static inline X *doCast(typename X::CType *obj)
+ {
+ //get the instance type and try to create (or rather fetch from the GObject qdata)
+ //the C++ wrapper class for this type of object.
+ RefCountedObject *cppClass = Private::wrapObject(obj);
+
+ //attempt to cast it to X
+ X *targetClass = dynamic_cast<X*>(cppClass);
+
+ if (!targetClass) {
+ //Cast failed. This either means that X is something that our instance is not
+ //or that X is another interface that is not inherited by the wrapper class
+ //for this instance type, but it is possible that our instance actually
+ //implements it, so let's check it.
+ if (boost::is_base_of<Interface, X>::value &&
+ !boost::is_base_of<Object, X>::value &&
+ Type::fromInstance(obj).isA(GetType<X>()))
+ {
+ targetClass = dynamic_cast<X*>(Private::wrapInterface(GetType<X>(), obj));
+ Q_ASSERT(targetClass);
+ }
+ }
+
+ return targetClass;
+ }
+};
+
+} //namespace Private
+
+
template <class T>
template <class X>
RefPointer<X> RefPointer<T>::dynamicCast() const
{
- if (!isNull() && QGlib::Private::CanConvertTo<X>::from(m_class->m_object)) {
- return RefPointer<X>::wrap(static_cast<typename X::CType*>(m_class->m_object));
- } else {
- return RefPointer<X>();
+ RefPointer<X> result;
+ if (m_class) {
+ X *targetClass = dynamic_cast<X*>(m_class);
+ if (!targetClass) {
+ //in case either X or T is an interface, we need to do some extra checks.
+ //this is a template to optimize the compiled code depending on what X and T are.
+ typename X::CType *obj = static_cast<RefCountedObject*>(m_class)->object<typename X::CType>();
+ targetClass = Private::IfaceDynamicCastImpl<T, X>::doCast(obj);
+ }
+
+ if (targetClass) {
+ static_cast<RefCountedObject*>(targetClass)->ref(true);
+ result.m_class = targetClass;
+ }
}
+
+ return result;
}
// trick GetType to return the same type for GetType<T>() and GetType< RefPointer<T> >()
diff --git a/src/QGlib/wrap.cpp b/src/QGlib/wrap.cpp
new file mode 100644
index 0000000..857e9cb
--- /dev/null
+++ b/src/QGlib/wrap.cpp
@@ -0,0 +1,97 @@
+/*
+ Copyright (C) 2010 Collabora Ltd. <info@collabora.co.uk>
+ @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "refpointer.h"
+#include "quark.h"
+#include <glib-object.h>
+
+namespace QGlib {
+
+RefCountedObject *constructWrapper(Type instanceType, void *instance)
+{
+ Quark q = g_quark_from_static_string("QGlib__wrapper_constructor");
+ RefCountedObject *cppClass = NULL;
+
+ for(Type t = instanceType; t.isValid(); t = t.parent()) {
+ void *funcPtr = t.quarkData(q);
+ if (funcPtr) {
+ cppClass = (reinterpret_cast<RefCountedObject *(*)(void*)>(funcPtr))(instance);
+ Q_ASSERT_X(cppClass, "QGlib::constructWrapper",
+ "Failed to wrap instance. This is a bug in the bindings library.");
+ return cppClass;
+ }
+ }
+
+ Q_ASSERT_X(false, "QGlib::constructWrapper",
+ "No wrapper constructor found for this type. This is a bug in the bindings library.");
+ return cppClass;
+}
+
+namespace Private {
+
+static void qdataDestroyNotify(void *cppInstance)
+{
+ delete static_cast<RefCountedObject*>(cppInstance);
+}
+
+RefCountedObject *wrapObject(void *gobject)
+{
+ Q_ASSERT(gobject);
+
+ Quark q = g_quark_from_static_string("QGlib__object_wrapper");
+ RefCountedObject *obj = static_cast<RefCountedObject*>(g_object_get_qdata(G_OBJECT(gobject), q));
+
+ if (!obj) {
+ obj = constructWrapper(Type::fromInstance(gobject), gobject);
+ g_object_set_qdata_full(G_OBJECT(gobject), q, obj, &qdataDestroyNotify);
+ }
+
+ return obj;
+}
+
+RefCountedObject *wrapParamSpec(void *param)
+{
+ Q_ASSERT(param);
+
+ Quark q = g_quark_from_static_string("QGlib__paramspec_wrapper");
+ RefCountedObject *obj = static_cast<RefCountedObject*>(g_param_spec_get_qdata(G_PARAM_SPEC(param), q));
+
+ if (!obj) {
+ obj = constructWrapper(Type::fromInstance(param), param);
+ g_param_spec_set_qdata_full(G_PARAM_SPEC(param), q, obj, &qdataDestroyNotify);
+ }
+
+ return obj;
+}
+
+RefCountedObject *wrapInterface(Type interfaceType, void *gobject)
+{
+ Q_ASSERT(gobject);
+
+ Quark q = Quark::fromString(QLatin1String("QGlib__interface_wrapper__") + interfaceType.name());
+ RefCountedObject *obj = static_cast<RefCountedObject*>(g_object_get_qdata(G_OBJECT(gobject), q));
+
+ if (!obj) {
+ obj = constructWrapper(interfaceType, gobject);
+ g_object_set_qdata_full(G_OBJECT(gobject), q, obj, &qdataDestroyNotify);
+ }
+
+ return obj;
+}
+
+} //namespace Private
+} //namespace QGlib
diff --git a/src/QGlib/wrap.h b/src/QGlib/wrap.h
new file mode 100644
index 0000000..8f2ce4b
--- /dev/null
+++ b/src/QGlib/wrap.h
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) 2010 Collabora Ltd. <info@collabora.co.uk>
+ @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef QGLIB_WRAP_H
+#define QGLIB_WRAP_H
+
+namespace QGlib {
+
+class RefCountedObject;
+class Type;
+
+/*! This function constructs a RefCountedObject that wraps the given \a instance,
+ * which is of type \a instanceType. It returns a C++ wrapper class that inherits
+ * RefCountedObject and wraps \a instanceType objects in the best possible way.
+ *
+ * This function is provided for implementing bindings that use QtGLib. It is only
+ * needed if those bindings have some reference counted instance type that is not
+ * an Object or Interface or ParamSpec (like QGst::MiniObject and QGst::Caps).
+ * You should \em not otherwise call this function directly.
+ */
+RefCountedObject *constructWrapper(Type instanceType, void *instance);
+
+template <typename T, typename Enable = void>
+struct WrapImpl {};
+
+#define QGLIB_REGISTER_WRAPIMPL_FOR_SUBCLASSES_OF(BaseClass, WrapFunc) \
+ namespace QGlib { \
+ template <typename T> \
+ struct WrapImpl<T, typename boost::enable_if< boost::is_base_of<BaseClass, T> >::type > \
+ { \
+ static inline RefCountedObject *wrap(typename T::CType *object) \
+ { \
+ return WrapFunc(object); \
+ } \
+ }; \
+ } //namespace QGlib
+
+#define QGLIB_REGISTER_INTERFACE(IfaceClass) \
+ namespace QGlib { \
+ template <> \
+ struct WrapImpl<IfaceClass, void> \
+ { \
+ static inline RefCountedObject *wrap(IfaceClass::CType *object) \
+ { \
+ return Private::wrapInterface(GetType<IfaceClass>(), object); \
+ } \
+ }; \
+ } //namespace QGlib
+
+namespace Private {
+
+RefCountedObject *wrapObject(void *gobject);
+RefCountedObject *wrapParamSpec(void *param);
+RefCountedObject *wrapInterface(Type interfaceType, void *gobject);
+
+} //namespace Private
+} //namespace QGlib
+
+
+#endif // QGLIB_WRAP_H
diff --git a/src/QGst/caps.cpp b/src/QGst/caps.cpp
index 08d0e34..d3971c3 100644
--- a/src/QGst/caps.cpp
+++ b/src/QGst/caps.cpp
@@ -185,7 +185,7 @@ CapsPtr Caps::copyNth(uint index) const
void Caps::ref(bool increaseRef)
{
- if (Private::ObjectStore::put(m_object)) {
+ if (Private::ObjectStore::put(this)) {
if (increaseRef) {
gst_caps_ref(GST_CAPS(m_object));
}
@@ -194,32 +194,24 @@ void Caps::ref(bool increaseRef)
void Caps::unref()
{
- if (Private::ObjectStore::take(m_object)) {
+ if (Private::ObjectStore::take(this)) {
gst_caps_unref(GST_CAPS(m_object));
+ delete this;
}
}
-void Caps::makeWritable()
+CapsPtr Caps::makeWritable() const
{
+ /*
+ * Calling gst_*_make_writable() below is tempting but wrong.
+ * Since MiniObjects and Caps do not share the same C++ instance in various wrappings, calling
+ * gst_*_make_writable() on an already writable object and wrapping the result is wrong,
+ * since it would just return the same pointer and we would wrap it in a new C++ instance.
+ */
if (!isWritable()) {
- //m_object will change, need to deal with the reference count properly
- unref();
-
- /*
- * Calling gst_*_make_writable() below is tempting but wrong, as the above unref() might have
- * dropped the gst refcount from 2 to 1 temporarily. When this happens gst_*_make_writable()
- * will do nothing, return the same object, and the refcount will go back to 2 when we ref()
- * it again below.
- * So the right thing to do is to copy() here to make sure we get a new object in this case.
- *
- * Note that if the external refCount is 1 then the gst_*_make_writable() semantics is
- * preserved (nothing is copied, same object is used) as we tested for this condition
- * before entering this code path.
- */
- m_object = gst_caps_copy(GST_CAPS(m_object));
-
- //Manage our reference count for the new m_object
- ref(false);
+ return copy();
+ } else {
+ return CapsPtr(const_cast<Caps*>(this));
}
}
@@ -229,4 +221,13 @@ QDebug operator<<(QDebug debug, const CapsPtr & caps)
return debug.space();
}
+
+namespace Private {
+
+QGlib::RefCountedObject *wrapCaps(void *caps)
+{
+ return QGlib::constructWrapper(GST_CAPS(caps)->type, caps);
+}
+
+} //namespace Private
} //namespace QGst
diff --git a/src/QGst/caps.h b/src/QGst/caps.h
index a83b6e1..4a11f38 100644
--- a/src/QGst/caps.h
+++ b/src/QGst/caps.h
@@ -69,7 +69,7 @@ public:
CapsPtr copyNth(uint index) const;
bool isWritable() const;
- void makeWritable();
+ CapsPtr makeWritable() const;
protected:
virtual void ref(bool increaseRef);
@@ -79,8 +79,15 @@ protected:
/*! \relates QGst::Caps */
QDebug operator<<(QDebug debug, const CapsPtr & caps);
-}
+
+namespace Private {
+
+QGlib::RefCountedObject *wrapCaps(void *caps);
+
+} //namespace Private
+} //namespace QGst
QGLIB_REGISTER_TYPE(QGst::Caps)
+QGLIB_REGISTER_WRAPIMPL_FOR_SUBCLASSES_OF(QGst::Caps, QGst::Private::wrapCaps)
#endif
diff --git a/src/QGst/childproxy.h b/src/QGst/childproxy.h
index 107f3f0..91d43b3 100644
--- a/src/QGst/childproxy.h
+++ b/src/QGst/childproxy.h
@@ -53,5 +53,6 @@ void ChildProxy::setChildProperty(const char *name, const T & value)
}
QGLIB_REGISTER_TYPE(QGst::ChildProxy)
+QGLIB_REGISTER_INTERFACE(QGst::ChildProxy)
#endif // QGST_CHILDPROXY_H
diff --git a/src/QGst/colorbalance.h b/src/QGst/colorbalance.h
index c8bf262..7e54099 100644
--- a/src/QGst/colorbalance.h
+++ b/src/QGst/colorbalance.h
@@ -51,5 +51,6 @@ public:
QGLIB_REGISTER_TYPE(QGst::ColorBalanceChannel)
QGLIB_REGISTER_TYPE(QGst::ColorBalance)
+QGLIB_REGISTER_INTERFACE(QGst::ColorBalance)
#endif // QGST_COLORBALANCE_H
diff --git a/src/QGst/global.cpp b/src/QGst/global.cpp
index 0f5fcf2..9299db0 100644
--- a/src/QGst/global.cpp
+++ b/src/QGst/global.cpp
@@ -22,6 +22,7 @@ namespace QGst {
namespace Private {
void registerValueVTables();
+ void registerWrapperConstructors(); //generated by codegen
}
void init()
@@ -31,11 +32,13 @@ void init()
void init(int *argc, char **argv[])
{
+ QGlib::init();
GError *error;
if (!gst_init_check(argc, argv, &error)) {
throw QGlib::Error(error);
}
Private::registerValueVTables();
+ Private::registerWrapperConstructors();
}
void cleanup()
diff --git a/src/QGst/global.h b/src/QGst/global.h
index b5a8865..5c74c35 100644
--- a/src/QGst/global.h
+++ b/src/QGst/global.h
@@ -164,6 +164,8 @@ namespace QGst {
/*! Initializes the GStreamer library, setting up internal path lists,
* registering built-in elements, and loading standard plugins.
+ * \note This function also calls QGlib::init(),
+ * so there is no need to call it explicitly.
* \param argc pointer to the application's argc
* \param argv pointer to the application's argv
* \throws QGlib::Error when initialization fails
diff --git a/src/QGst/miniobject.cpp b/src/QGst/miniobject.cpp
index 4a063d9..9f5c461 100644
--- a/src/QGst/miniobject.cpp
+++ b/src/QGst/miniobject.cpp
@@ -52,7 +52,7 @@ void MiniObject::unsetFlag(MiniObjectFlag flag)
void MiniObject::ref(bool increaseRef)
{
- if (Private::ObjectStore::put(m_object)) {
+ if (Private::ObjectStore::put(this)) {
if (increaseRef) {
gst_mini_object_ref(GST_MINI_OBJECT(m_object));
}
@@ -61,33 +61,34 @@ void MiniObject::ref(bool increaseRef)
void MiniObject::unref()
{
- if (Private::ObjectStore::take(m_object)) {
+ if (Private::ObjectStore::take(this)) {
gst_mini_object_unref(GST_MINI_OBJECT(m_object));
+ delete this;
}
}
-void MiniObject::makeWritable()
+MiniObjectPtr MiniObject::makeWritable() const
{
+ /*
+ * Calling gst_*_make_writable() below is tempting but wrong.
+ * Since MiniObjects and Caps do not share the same C++ instance in various wrappings, calling
+ * gst_*_make_writable() on an already writable object and wrapping the result is wrong,
+ * since it would just return the same pointer and we would wrap it in a new C++ instance.
+ */
if (!isWritable()) {
- //m_object will change, need to deal with the reference count properly
- unref();
-
- /*
- * Calling gst_*_make_writable() below is tempting but wrong, as the above unref() might have
- * dropped the gst refcount from 2 to 1 temporarily. When this happens gst_*_make_writable()
- * will do nothing, return the same object, and the refcount will go back to 2 when we ref()
- * it again below.
- * So the right thing to do is to copy() here to make sure we get a new object in this case.
- *
- * Note that if the external refCount is 1 then the gst_*_make_writable() semantics is
- * preserved (nothing is copied, same object is used) as we tested for this condition
- * before entering this code path.
- */
- m_object = gst_mini_object_copy(GST_MINI_OBJECT(m_object));
-
- //Manage our reference count for the new m_object
- ref(false);
+ return copy();
+ } else {
+ return MiniObjectPtr(const_cast<MiniObject*>(this));
}
}
+
+namespace Private {
+
+QGlib::RefCountedObject *wrapMiniObject(void *miniObject)
+{
+ return QGlib::constructWrapper(QGlib::Type::fromInstance(miniObject), miniObject);
+}
+
+} //namespace Private
} //namespace QGst
diff --git a/src/QGst/miniobject.h b/src/QGst/miniobject.h
index feb8ae6..61690c7 100644
--- a/src/QGst/miniobject.h
+++ b/src/QGst/miniobject.h
@@ -32,7 +32,7 @@ class MiniObject : public QGlib::RefCountedObject
public:
MiniObjectPtr copy() const;
bool isWritable() const;
- void makeWritable();
+ MiniObjectPtr makeWritable() const;
MiniObjectFlags flags() const;
bool flagIsSet(MiniObjectFlag flag) const;
@@ -44,8 +44,15 @@ protected:
virtual void unref();
};
+
+namespace Private {
+
+QGlib::RefCountedObject *wrapMiniObject(void *miniObject);
+
+} //namespace Private
} //namespace QGst
QGLIB_REGISTER_TYPE(QGst::MiniObject)
+QGLIB_REGISTER_WRAPIMPL_FOR_SUBCLASSES_OF(QGst::MiniObject, QGst::Private::wrapMiniObject)
#endif
diff --git a/src/QGst/propertyprobe.h b/src/QGst/propertyprobe.h
index 75714e6..1385add 100644
--- a/src/QGst/propertyprobe.h
+++ b/src/QGst/propertyprobe.h
@@ -50,5 +50,6 @@ public:
}
QGLIB_REGISTER_TYPE(QGst::PropertyProbe)
+QGLIB_REGISTER_INTERFACE(QGst::PropertyProbe)
#endif // QGST_PROPERTYPROBE_H
diff --git a/src/QGst/streamvolume.h b/src/QGst/streamvolume.h
index b908f66..e646eca 100644
--- a/src/QGst/streamvolume.h
+++ b/src/QGst/streamvolume.h
@@ -41,5 +41,6 @@ public:
} //namespace QGst
QGLIB_REGISTER_TYPE(QGst::StreamVolume)
+QGLIB_REGISTER_INTERFACE(QGst::StreamVolume)
#endif // QGST_STREAMVOLUME_H
diff --git a/src/QGst/urihandler.h b/src/QGst/urihandler.h
index eeb2538..eafd3a5 100644
--- a/src/QGst/urihandler.h
+++ b/src/QGst/urihandler.h
@@ -42,5 +42,6 @@ public:
} //namespace QGst
QGLIB_REGISTER_TYPE(QGst::UriHandler)
+QGLIB_REGISTER_INTERFACE(QGst::UriHandler)
#endif // QGST_URIHANDLER_H
diff --git a/src/QGst/videoorientation.h b/src/QGst/videoorientation.h
index 4764ee1..60c5ff1 100644
--- a/src/QGst/videoorientation.h
+++ b/src/QGst/videoorientation.h
@@ -44,5 +44,6 @@ public:
} //namespace QGst
QGLIB_REGISTER_TYPE(QGst::VideoOrientation)
+QGLIB_REGISTER_INTERFACE(QGst::VideoOrientation)
#endif // QGST_VIDEOORIENTATION_H
diff --git a/src/QGst/xoverlay.h b/src/QGst/xoverlay.h
index f8d665b..2db89f9 100644
--- a/src/QGst/xoverlay.h
+++ b/src/QGst/xoverlay.h
@@ -42,5 +42,6 @@ public:
} //namespace QGst
QGLIB_REGISTER_TYPE(QGst::XOverlay)
+QGLIB_REGISTER_INTERFACE(QGst::XOverlay)
#endif // QGST_XOVERLAY_H
diff --git a/tests/auto/capstest.cpp b/tests/auto/capstest.cpp
index 9bf8163..558803c 100644
--- a/tests/auto/capstest.cpp
+++ b/tests/auto/capstest.cpp
@@ -107,7 +107,7 @@ void CapsTest::writabilityTest()
QVERIFY(GST_CAPS_REFCOUNT_VALUE(caps) == 2);
QVERIFY(!caps->isWritable());
- caps->makeWritable(); //creates a copy
+ caps = caps->makeWritable(); //creates a copy
QVERIFY(caps->isWritable());
QVERIFY(oldPtr != static_cast<GstCaps*>(caps)); //no longer same gstcaps object
}
diff --git a/tests/auto/refpointertest.cpp b/tests/auto/refpointertest.cpp
index 206922c..bbb28ff 100644
--- a/tests/auto/refpointertest.cpp
+++ b/tests/auto/refpointertest.cpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com>
+ Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com>
Copyright (C) 2010 Collabora Ltd.
@author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
@@ -18,9 +18,11 @@
*/
#include "qgsttest.h"
#include <QGst/Object>
-#include <QGst/Bin>
#include <QGst/Message>
#include <QGst/Pipeline>
+#include <QGst/ElementFactory>
+#include <QGst/UriHandler>
+#include <QGst/StreamVolume>
class RefPointerTest : public QGstTest
{
@@ -29,6 +31,11 @@ private Q_SLOTS:
void refTest1();
void refTest2();
void dynamicCastTest();
+ void dynamicCastDownObjectTest();
+ void dynamicCastUpObjectTest();
+ void dynamicCastObjectToIfaceTest();
+ void dynamicCastIfaceToObjectTest();
+ void cppWrappersTest();
void messageDynamicCastTest();
void equalityTest();
};
@@ -75,6 +82,107 @@ void RefPointerTest::dynamicCastTest()
gst_object_unref(bin);
}
+void RefPointerTest::dynamicCastDownObjectTest()
+{
+ GstObject *bin = GST_OBJECT(gst_object_ref(gst_bin_new(NULL)));
+ gst_object_sink(bin);
+
+ {
+ QGlib::ObjectPtr object = QGlib::ObjectPtr::wrap(G_OBJECT(bin));
+ QVERIFY(!object.dynamicCast<QGst::Object>().isNull());
+ QVERIFY(!object.dynamicCast<QGst::Bin>().isNull());
+ QVERIFY(object.dynamicCast<QGst::Pipeline>().isNull());
+ }
+
+ gst_object_unref(bin);
+}
+
+void RefPointerTest::dynamicCastUpObjectTest()
+{
+ GstBin *bin = GST_BIN(gst_object_ref(gst_bin_new(NULL)));
+ gst_object_sink(bin);
+
+ {
+ QGst::BinPtr object = QGst::BinPtr::wrap(bin);
+ QVERIFY(!object.dynamicCast<QGst::Element>().isNull());
+ QVERIFY(!object.dynamicCast<QGlib::Object>().isNull());
+ QVERIFY(!object.dynamicCast<QGst::ChildProxy>().isNull());
+ }
+
+ gst_object_unref(bin);
+}
+
+void RefPointerTest::dynamicCastObjectToIfaceTest()
+{
+ QGst::ElementPtr e = QGst::ElementFactory::make("fakesrc");
+ QGst::UriHandlerPtr u = e.dynamicCast<QGst::UriHandler>();
+ QVERIFY(u.isNull());
+
+ e = QGst::ElementFactory::make("filesrc");
+ u = e.dynamicCast<QGst::UriHandler>();
+ QVERIFY(!u.isNull());
+}
+
+void RefPointerTest::dynamicCastIfaceToObjectTest()
+{
+ GstElement *e = gst_element_factory_make("filesrc", NULL);
+ gst_object_ref_sink(e);
+
+ QGst::UriHandlerPtr u = QGst::UriHandlerPtr::wrap(GST_URI_HANDLER(e), false);
+ QVERIFY(!u.isNull());
+ QVERIFY(!u.dynamicCast<QGst::Element>().isNull());
+}
+
+void RefPointerTest::cppWrappersTest()
+{
+ QGst::ElementPtr e = QGst::ElementFactory::make("playbin2");
+ QVERIFY(!e.isNull());
+
+ {
+ QGst::PipelinePtr pipeline = e.dynamicCast<QGst::Pipeline>();
+ QVERIFY(!pipeline.isNull());
+ //the C++ wrappers must be the same
+ QCOMPARE(static_cast<QGlib::RefCountedObject*>(pipeline.operator->()),
+ static_cast<QGlib::RefCountedObject*>(e.operator->()));
+ }
+
+ {
+ QGst::ChildProxyPtr proxy = e.dynamicCast<QGst::ChildProxy>();
+ QVERIFY(!proxy.isNull());
+ //the C++ wrappers must be the same
+ QCOMPARE(static_cast<QGlib::RefCountedObject*>(proxy.operator->()),
+ static_cast<QGlib::RefCountedObject*>(e.operator->()));
+ }
+
+ { //new wrap() should give the same C++ instance
+ GstElement *gobj = e;
+ QGst::ElementPtr e2 = QGst::ElementPtr::wrap(gobj);
+ QCOMPARE(static_cast<QGlib::RefCountedObject*>(e2.operator->()),
+ static_cast<QGlib::RefCountedObject*>(e.operator->()));
+ }
+
+ {
+ QGst::StreamVolumePtr sv = e.dynamicCast<QGst::StreamVolume>();
+ QVERIFY(!sv.isNull());
+ //now the C++ wrapper must not be the same, since Pipeline does not inherit StreamVolume
+ QVERIFY(static_cast<QGlib::RefCountedObject*>(sv.operator->())
+ != static_cast<QGlib::RefCountedObject*>(e.operator->()));
+ }
+
+ {
+ QGst::MessagePtr msg = QGst::ApplicationMessage::create(e);
+ QGst::MessagePtr msg2 = msg;
+ QCOMPARE(static_cast<QGlib::RefCountedObject*>(msg.operator->()),
+ static_cast<QGlib::RefCountedObject*>(msg2.operator->()));
+ QVERIFY(msg2 == msg);
+
+ QGst::MessagePtr msg3 = QGst::MessagePtr::wrap(msg2);
+ QVERIFY(static_cast<QGlib::RefCountedObject*>(msg3.operator->())
+ != static_cast<QGlib::RefCountedObject*>(msg2.operator->()));
+ QVERIFY(msg3 == msg2);
+ }
+}
+
void RefPointerTest::messageDynamicCastTest()
{
QGst::BinPtr bin = QGst::Bin::create();
diff --git a/tests/auto/urihandlertest.cpp b/tests/auto/urihandlertest.cpp
index c722e87..1ec9792 100644
--- a/tests/auto/urihandlertest.cpp
+++ b/tests/auto/urihandlertest.cpp
@@ -23,22 +23,10 @@ class UriHandlerTest : public QGstTest
{
Q_OBJECT
private Q_SLOTS:
- void castTest();
void interfaceTest();
void makeTest();
};
-void UriHandlerTest::castTest()
-{
- QGst::ElementPtr e = QGst::ElementFactory::make("audioconvert");
- QGst::UriHandlerPtr u = e.dynamicCast<QGst::UriHandler>();
- QVERIFY(u.isNull());
-
- e = QGst::ElementFactory::make("filesrc");
- u = e.dynamicCast<QGst::UriHandler>();
- QVERIFY(!u.isNull());
-}
-
void UriHandlerTest::interfaceTest()
{
QGst::ElementPtr e = QGst::ElementFactory::make("filesrc");