diff --git a/docs/random/interfaces b/docs/random/interfaces index 8c6a3dfdf1..a0542a2939 100644 --- a/docs/random/interfaces +++ b/docs/random/interfaces @@ -144,13 +144,76 @@ gst_element_implements_interface (GstElement *element, return FALSE; } -We could use this in the GST_IS_... () macros. For example, the -macro GST_IS_MIXER () would then look like this: +Let's now add some functions so we can abuse this in case/check +functions. +GstInterface * +gst_interface_cast (gpointer from, + GType type) +{ + GstInterface *iface; + + /* check cast, give warning+fail if it's invalid */ + if (!(iface = G_TYPE_CHECK_INSTANCE_CAST (G_OBJECT (element), + type, GstInterface))) { + return NULL; + } + + /* if we're an element, take care that this interface + * is actually implemented */ + if (GST_IS_ELEMENT (from)) { + gboolean interface_is_implemented = + gst_element_implements_interface (GST_ELEMENT (from), + type); + g_return_val_if_fail (interface_is_implemented == TRUE, NULL); + } + + return iface; +} + +gboolean +gst_interface_check (gpointer from, + GType type) +{ + GstInterface *iface; + + /* check cast, return FALSE if it fails, don't give a warning... */ + if (!G_TYPE_CHECK_INSTANCE_CAST (from, type, + GstInterface)) { + return FALSE; + } + + iface = G_TYPE_CHECK_INSTANCE_CAST (G_OBJECT (element), + type, GstInterface); + + /* now, if we're an element (or derivative), is this thing + * actually implemented for real? */ + if (GST_IS_ELEMENT (from)) { + if (!gst_element_implements_interface (GST_ELEMENT (from), + type)) { + return FALSE; + } + } + + return TRUE; +} + +#define GST_INTERFACE_CHECK_INSTANCE_CAST(obj, type, cast_t) \ + ((cast_t *) gst_interface_cast ((obj), (type)) +#define GST_INTERFACE_CHECK_INSTANCE_TYPE(obj, type) \ + (gst_interface_check ((obj), (type)) + +We could use this in the GST_IS_... () macros. For example, the +macros GST_IS_MIXER () and GST_MIXER () would then look like this: + +/* Note that this is a non-standard macro, and with a reason! */ +#define GST_MIXER(obj) \ + (GST_INTERFACE_CHECK_INSTANCE_CAST ((obj), \ + GST_TYPE_MIXER, + GstMixer)) #define GST_IS_MIXER(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MIXER) && \ - gst_element_implements_interface (GST_ELEMENT (obj), \ - GST_TYPE_MIXER)) + (GST_INTERFACE_CHECK_INSTANCE_TYPE ((obj), \ + GST_TYPE_MIXER)) So the application would just tread it with the known macro, and everything would look extremely simple to the end user. @@ -184,7 +247,8 @@ And alsa* would surely implement the same interface. /* This is confusing naming... (i.e. FIXME) * A channel is referred to both as the number of simultaneous - * sounds the input can handle as well as the in-/output itself + * sound streams the input can handle as well as the in-/output + * itself */ #define GST_MIXER_CHANNEL_INPUT (1<<0) diff --git a/gst/Makefile.am b/gst/Makefile.am index c6afbb1f69..5024fb92a7 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -107,6 +107,7 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \ gstformat.c \ $(GST_INDEX_SRC) \ gstinfo.c \ + gstinterface.c \ gstmemchunk.c \ gstpad.c \ gstpipeline.c \ @@ -167,6 +168,7 @@ gst_headers = \ gstformat.h \ gstindex.h \ gstinfo.h \ + gstinterface.h \ gstlog.h \ gstmacros.h \ gstmemchunk.h \ diff --git a/gst/gst.h b/gst/gst.h index 4d61b98344..476b693b2f 100644 --- a/gst/gst.h +++ b/gst/gst.h @@ -55,6 +55,7 @@ #include #include #include +#include #include #include diff --git a/gst/gstinterface.c b/gst/gstinterface.c new file mode 100644 index 0000000000..4c1245275d --- /dev/null +++ b/gst/gstinterface.c @@ -0,0 +1,170 @@ +/* GStreamer + * + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gstinterface.c: Interface functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstinterface.h" +#include "gstlog.h" + +static void gst_interface_class_init (GstInterfaceClass *ifklass); +static gboolean gst_interface_supported_default (GstInterface *iface); + +GType +gst_interface_get_type (void) +{ + static GType gst_interface_type = 0; + + if (!gst_interface_type) { + static const GTypeInfo gst_interface_info = { + sizeof (GstInterfaceClass), + (GBaseInitFunc) gst_interface_class_init, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + NULL, + NULL + }; + + gst_interface_type = g_type_register_static (G_TYPE_INTERFACE, + "GstInterface", + &gst_interface_info, 0); + } + + return gst_interface_type; +} + +static void +gst_interface_class_init (GstInterfaceClass *klass) +{ + klass->supported = gst_interface_supported_default; +} + +static gboolean +gst_interface_supported_default (GstInterface *interface) +{ + /* Well, if someone didn't set the virtual function, + * then something is clearly wrong. So big no-no here */ + + return FALSE; +} + +/** + * gst_element_implements_interface: + * @element: #GstElement to check for the implementation of the interface + * @iface_type: (final) type of the interface which we want to be implemented + * + * Test whether the given element implements a certain interface of type + * iface_type, and test whether it is supported for this specific instance. + */ + +gboolean +gst_element_implements_interface (GstElement *element, + GType iface_type) +{ + if (G_TYPE_CHECK_INSTANCE_TYPE (G_OBJECT (element), + iface_type)) { + GstInterface *iface; + GstInterfaceClass *ifclass; + + iface = G_TYPE_CHECK_INSTANCE_CAST (G_OBJECT (element), + iface_type, GstInterface); + ifclass = GST_INTERFACE_GET_CLASS (iface); + + if (ifclass->supported != NULL && + ifclass->supported (iface) == TRUE) { + return TRUE; + } + } + + return FALSE; +} + +/** + * gst_interface_cast: + * @from: the object (any sort) from which to cast to the interface + * @type: the interface type to cast to + * + * cast a given object to an interface type, and check whether this + * interface is supported for this specific instance. + */ + +GstInterface * +gst_interface_cast (gpointer from, + GType iface_type) +{ + GstInterface *iface; + + /* check cast, give warning+fail if it's invalid */ + if (!(iface = G_TYPE_CHECK_INSTANCE_CAST (from, iface_type, + GstInterface))) { + return NULL; + } + + /* if we're an element, take care that this interface + * is actually implemented */ + if (GST_IS_ELEMENT (from)) { + gboolean interface_is_implemented = + gst_element_implements_interface (GST_ELEMENT (from), iface_type); + g_return_val_if_fail (interface_is_implemented == TRUE, NULL); + } + + return iface; +} + +/** + * gst_interface_cast: + * @from: the object (any sort) from which to check from for the interface + * @type: the interface type to check for + * + * check a given object for an interface implementation, and check + * whether this interface is supported for this specific instance. + */ + +gboolean +gst_interface_check (gpointer from, + GType type) +{ + GstInterface *iface; + + /* check cast, return FALSE if it fails, don't give a warning... */ + if (!G_TYPE_CHECK_INSTANCE_CAST (from, type, GstInterface)) { + return FALSE; + } + + iface = G_TYPE_CHECK_INSTANCE_CAST (from, type, GstInterface); + + /* now, if we're an element (or derivative), is this thing + * actually implemented for real? */ + if (GST_IS_ELEMENT (from)) { + if (!gst_element_implements_interface (GST_ELEMENT (from), type)) { + return FALSE; + } + } + + return TRUE; +} diff --git a/gst/gstinterface.h b/gst/gstinterface.h new file mode 100644 index 0000000000..4024fd283a --- /dev/null +++ b/gst/gstinterface.h @@ -0,0 +1,73 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gstinterface.h: Declarations of interface stuff + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_INTERFACE_H__ +#define __GST_INTERFACE_H__ + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_INTERFACE \ + (gst_interface_get_type ()) +#define GST_INTERFACE(obj) \ + (GST_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_INTERFACE, GstInterface)) +#define GST_INTERFACE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_INTERFACE, GstInterfaceClass)) +#define GST_IS_INTERFACE(obj) \ + (GST_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_INTERFACE)) +#define GST_IS_INTERFACE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_INTERFACE)) +#define GST_INTERFACE_GET_CLASS(inst) \ + (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_INTERFACE, GstInterfaceClass)) + +typedef struct _GstInterface GstInterface; + +/* This small extra virtual function is here to provide an + * interface functionality on a per-instance basis rather + * than a per-class basis, which is the case for glib. + */ +typedef struct _GstInterfaceClass { + GTypeInterface parent; + + /* virtual functions */ + gboolean (* supported) (GstInterface *iface); +} GstInterfaceClass; + +#define GST_INTERFACE_CHECK_INSTANCE_CAST(obj, type, cast_t) \ + ((cast_t *) gst_interface_cast ((obj), (type))) +#define GST_INTERFACE_CHECK_INSTANCE_TYPE(obj, type) \ + (gst_interface_check ((obj), (type))) + +GType gst_interface_get_type (void); + +/* wrapper functions to check for functionality implementation */ +gboolean gst_element_implements_interface(GstElement *element, + GType iface_type); +GstInterface * gst_interface_cast (gpointer from, + GType type); +gboolean gst_interface_check (gpointer from, + GType type); + +G_END_DECLS + +#endif /* __GST_INTERFACE_H__ */