# HG changeset patch
# User rosfran
# Date 1179857677 -3600
# Node ID 7afeec40ed620b0c9fd0bc70f9a7391d0a73f016
# Parent  4712c96954be705a611d2ded8fa9e83ea3e07c45
[svn r702] Changed the architecture to support GObject signals in the clinkc's UPnP model.

diff -r 4712c96954be -r 7afeec40ed62 gmyth-upnp/src/Makefile.am
--- a/gmyth-upnp/src/Makefile.am	Fri May 18 23:29:00 2007 +0100
+++ b/gmyth-upnp/src/Makefile.am	Tue May 22 19:14:37 2007 +0100
@@ -2,9 +2,25 @@
 
 lib_LTLIBRARIES = libgmythupnp.la
 
+BUILT_SOURCES =                                 \
+        gmyth_upnp_marshal.c                    \
+	gmyth_upnp_marshal.h
+
 libgmythupnp_la_SOURCES = 			\
 	gmyth_upnp.c
-	
+
+EXTRA_libgmythupnp_la_SOURCES = gmyth_upnp_marshal.list
+
+gmyth_upnp_marshal.h: gmyth_upnp_marshal.list
+	glib-genmarshal --header --prefix=gmyth_upnp_marshal gmyth_upnp_marshal.list > gmyth_upnp_marshal.h.tmp
+	mv gmyth_upnp_marshal.h.tmp gmyth_upnp_marshal.h
+
+gmyth_upnp_marshal.c: gmyth_upnp_marshal.list gmyth_upnp_marshal.h
+	echo "#include \"glib-object.h\"" > gmyth_upnp_marshal.c.tmp
+	echo "#include \"gmyth_upnp_marshal.h\"" >> gmyth_upnp_marshal.c.tmp
+	glib-genmarshal --body --prefix=gmyth_upnp_marshal $(srcdir)/gmyth_upnp_marshal.list >> gmyth_upnp_marshal.c.tmp
+	mv gmyth_upnp_marshal.c.tmp gmyth_upnp_marshal.c
+
 libgmythupnp_la_CFLAGS = 			\
 	-DDATADIR=\"$(pkgdatadir)\" 	\
 	$(LIBGMYTH_CFLAGS)			\
diff -r 4712c96954be -r 7afeec40ed62 gmyth-upnp/src/gmyth_upnp.c
--- a/gmyth-upnp/src/gmyth_upnp.c	Fri May 18 23:29:00 2007 +0100
+++ b/gmyth-upnp/src/gmyth_upnp.c	Tue May 22 19:14:37 2007 +0100
@@ -32,6 +32,7 @@
 #endif
 
 #include "gmyth_upnp.h"
+#include "gmyth_upnp_marshal.h"
 
 #include <arpa/inet.h>
 #include <sys/types.h>
@@ -45,48 +46,83 @@
 #include <gmyth/gmyth_uri.h>
 #include <gmyth/gmyth_debug.h>
 
+/* Maximum number of searches in the synchronized search */
 #define GMYTH_UPNP_MAX_SEARCHS		10
 
+#define GMYTH_UPNP_GET_PRIVATE(obj) \
+    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GMYTH_UPNP_TYPE, GMythUPnPPrivate))
+
+struct _GMythUPnPPrivate {
+	GHashTable *mythtv_servers;
+	GMythUPnPDeviceStatus last_status;
+	gboolean upnp_dev_found;
+	gchar *udn;
+	GMutex *mutex;
+};
+
 static void gmyth_upnp_class_init          (GMythUPnPClass *klass);
 static void gmyth_upnp_init                (GMythUPnP *object);
 
 static void gmyth_upnp_dispose  (GObject *object);
 static void gmyth_upnp_finalize (GObject *object);
 
-static gboolean gmyth_upnp_initialize ( GMythUPnP *gmyth_upnp, GMythBackendInfo *gmyth_backend_info );
+static void _mythtv_device_found ( GMythUPnPDeviceStatus status, gchar *dev );
+static void _clinkc_mythtv_device_found ( gchar *udn, GMythUPnPDeviceStatus status );
 
-static gboolean gmyth_upnp_print_cp_device_list( CgUpnpControlPoint* controlPt, gchar **udn, 
-						GList **mythtv_servers_lst );
+static gboolean gmyth_upnp_initialize ( GMythUPnP *gmyth_upnp, GMythBackendInfo *gmyth_backend_info,
+		GMythUPnPDeviceListener listener);
+
+static gboolean gmyth_upnp_got_mythtv_service( CgUpnpControlPoint* controlPt, gchar **udn, 
+						GHashTable **mythtv_servers_lst );
 
 G_DEFINE_TYPE(GMythUPnP, gmyth_upnp, G_TYPE_OBJECT)
 
-static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+static GMythUPnP *gmyth_upnp_static = NULL;
 
 static void
 gmyth_upnp_class_init (GMythUPnPClass *klass)
 {
 	GObjectClass *gobject_class;
+	GMythUPnPClass *gupnp_class;
 
 	gobject_class = (GObjectClass *) klass;
+	gupnp_class = (GMythUPnPClass*) gobject_class;
 
 	gobject_class->dispose  = gmyth_upnp_dispose;
-	gobject_class->finalize = gmyth_upnp_finalize;	
+	gobject_class->finalize = gmyth_upnp_finalize;
+	
+	g_type_class_add_private( gobject_class, sizeof( GMythUPnPPrivate ) );
+
+	gupnp_class->device_found_handler = _mythtv_device_found;
+
+	gupnp_class->device_found_handler_signal_id =
+		g_signal_new ("device-found",
+				G_TYPE_FROM_CLASS (gupnp_class),
+				G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE |
+				G_SIGNAL_NO_HOOKS, 0, NULL, NULL,
+				gmyth_upnp_marshal_VOID__INT_STRING, G_TYPE_NONE, 2,
+				G_TYPE_INT, G_TYPE_STRING);
+
 }
 
 static void
 gmyth_upnp_init ( GMythUPnP *gmyth_upnp )
 {
-	gmyth_upnp->upnp_dev_found = FALSE;
-	
-	gmyth_upnp->uri = NULL;
-	gmyth_upnp->host = NULL;
-	gmyth_upnp->port = 0;
-	gmyth_upnp->protocol = NULL;
-	
-	gmyth_upnp->gmyth_backend_info = NULL;
-	
+
+	gmyth_upnp->backend_info = NULL;
+
 	gmyth_upnp->control_point = NULL;
-	
+
+	gmyth_upnp->priv = GMYTH_UPNP_GET_PRIVATE(gmyth_upnp);
+	gmyth_upnp->priv->mutex = g_mutex_new ();
+	gmyth_upnp->priv->upnp_dev_found = FALSE;
+
+	g_signal_connect (G_OBJECT (gmyth_upnp), "device-found",
+			(GCallback) (GMYTH_UPNP_GET_CLASS (gmyth_upnp)->
+				device_found_handler), NULL);
+
+	gmyth_upnp_static = gmyth_upnp;
+
 }
 
 /** Creates a new instance of GMythUPnP.
@@ -94,14 +130,18 @@
  * @return a new instance of GMythUPnP. 
  */
 GMythUPnP *
-gmyth_upnp_new ( GMythBackendInfo *gmyth_backend_info ) 
+gmyth_upnp_new ( GMythBackendInfo *gmyth_backend_info, GMythUPnPDeviceListener handler ) 
 {
     GMythUPnP *gmyth_upnp = GMYTH_UPNP (g_object_new (GMYTH_UPNP_TYPE, NULL));
     
-    gmyth_upnp->gmyth_backend_info = gmyth_backend_info;
-    
-    if ( !gmyth_upnp_initialize ( gmyth_upnp, gmyth_backend_info ) )
-    	return NULL;
+    g_object_ref( gmyth_backend_info );
+
+    gmyth_upnp->backend_info = gmyth_backend_info;
+
+    if ( !gmyth_upnp_initialize ( gmyth_upnp, gmyth_backend_info, handler ) )
+    {
+    	gmyth_debug( "Error initializing the GMythUPnP!!!" );
+    }
     
     return gmyth_upnp;
 }
@@ -116,27 +156,17 @@
 		cg_upnp_controlpoint_delete( gmyth_upnp->control_point );
 		gmyth_upnp->control_point = NULL;
 	}
+	
+	if ( gmyth_upnp->priv->mythtv_servers != NULL )	{
+		g_hash_table_destroy( gmyth_upnp->priv->mythtv_servers );
+		gmyth_upnp->priv->mythtv_servers = NULL;
+	}
 
-	if ( gmyth_upnp->uri != NULL ) {
-		g_free ( gmyth_upnp->uri );
-		gmyth_upnp->uri = NULL;
+	if ( gmyth_upnp->backend_info != NULL )	{
+		g_object_unref( gmyth_upnp->backend_info );
+		gmyth_upnp->backend_info = NULL;
 	}
-	
-	if ( gmyth_upnp->host != NULL ) {
-		g_free ( gmyth_upnp->host );
-		gmyth_upnp->host = NULL;
-	}
-	
-	if ( gmyth_upnp->protocol != NULL ) {
-		g_free ( gmyth_upnp->protocol );
-		gmyth_upnp->protocol = NULL;
-	}
-	
-	if ( gmyth_upnp->mythtv_servers != NULL )	{
-		g_list_free( gmyth_upnp->mythtv_servers );
-		gmyth_upnp->mythtv_servers = NULL;
-	}
-	
+
 	G_OBJECT_CLASS (gmyth_upnp_parent_class)->dispose (object);
 }
 
@@ -149,103 +179,139 @@
 }
 
 /**
+ * GObject's signal handler
+ */ 
+static void
+_mythtv_device_found( GMythUPnPDeviceStatus status, gchar* udn )
+{
+	g_debug( "status = %d, UDN = %s\n", status, udn );
+}
+
+/**
+ * GObject's signal handler
+ */
+static void 
+_clinkc_mythtv_device_found ( gchar *udn, GMythUPnPDeviceStatus status )
+{
+	if ( gmyth_upnp_static != NULL )
+		g_signal_emit ( gmyth_upnp_static, 
+			GMYTH_UPNP_GET_CLASS (gmyth_upnp_static)->device_found_handler_signal_id, 0, /* details */
+			status, udn );
+}
+
+/**
  * Create a control point and start it.
  */
 static gboolean
-gmyth_upnp_initialize ( GMythUPnP *gmyth_upnp, GMythBackendInfo *gmyth_backend_info )
+gmyth_upnp_initialize ( GMythUPnP *gmyth_upnp, GMythBackendInfo *gmyth_backend_info, 
+	GMythUPnPDeviceListener device_found_handler )
 {
-	
-	gboolean ret = FALSE;
-	
-	GMythURI* uri = NULL;
-	
-	guint iter_count = GMYTH_UPNP_MAX_SEARCHS;
-	
+	gboolean ret = TRUE;
+
 	g_return_val_if_fail( gmyth_backend_info != NULL, FALSE );
-	
+
 	/* Create the cybergarage control point */
 	gmyth_upnp->control_point = cg_upnp_controlpoint_new();
-	/* cg_upnp_controlpoint_setdevicelistener( gmyth_upnp->control_point, device_listener ); */
-	
+
+	if ( device_found_handler != NULL )
+	{
+		GMYTH_UPNP_GET_CLASS(gmyth_upnp)->device_found_handler = device_found_handler; 
+
+		cg_upnp_controlpoint_setdevicelistener( gmyth_upnp->control_point, _clinkc_mythtv_device_found );
+	}
+
 	/* Start the control point */
-  if ( cg_upnp_controlpoint_start( gmyth_upnp->control_point ) == FALSE)
+	if ( cg_upnp_controlpoint_start( gmyth_upnp->control_point ) == FALSE)
 	{
-	  gmyth_debug( "Unable to start UPnP control point!!!" );
-	  goto done;
-  }
+		gmyth_debug( "Unable to start UPnP control point!!!" );
+		ret = FALSE;
+		goto done;
+	}
 	else
 	{
-    gmyth_debug( "Control point started." );
+		gmyth_debug( "Control point started." );
 	}
-	
-	while ( gmyth_upnp->upnp_dev_found == FALSE && ( --iter_count > 0 ) ) {
-		
+
+done:
+
+	return ret;
+}
+
+static void
+_gmyth_foreach_key_value( gchar *udn, gchar *dev, GList *upnp_servers_list )
+{
+	GMythUPnPDevice *gmyth_upnp = g_malloc0( sizeof( GMythUPnPDevice ) );
+
+	GMythURI* uri = NULL;
+	gmyth_upnp->uri = (gchar*) (dev);
+	uri = gmyth_uri_new_with_value( gmyth_upnp->uri );
+
+	gmyth_upnp->host = gmyth_uri_get_host( uri );
+	gmyth_upnp->port = gmyth_uri_get_port( uri );
+	gmyth_upnp->protocol = gmyth_uri_get_protocol( uri );
+
+	upnp_servers_list = g_list_append( upnp_servers_list, gmyth_upnp );
+
+	if ( uri != NULL )
+	{
+		g_object_unref( uri );
+		uri = NULL;
+	}
+
+}
+
+GList *
+gmyth_upnp_do_search_sync( GMythUPnP* gmyth_upnp )
+{
+	GList *upnp_servers_list = NULL;
+	guint iter_count = GMYTH_UPNP_MAX_SEARCHS;
+	/* gmyth_upnp->priv = GMYTH_UPNP_GET_PRIVATE( gmyth_upnp ); */
+
+	while ( gmyth_upnp->priv->upnp_dev_found == FALSE && ( --iter_count > 0 ) ) {
+
 		gmyth_debug( "UPnP MythTV Client control point is searching MythTV AV Device server...\n" );
-       
+
 		if ( gmyth_upnp->control_point != NULL )
 			cg_upnp_controlpoint_search ( gmyth_upnp->control_point, 
-		        		"urn:schemas-upnp-org:service:ContentDirectory:1" );
+					"urn:schemas-upnp-org:service:ContentDirectory:1" );
 
 		/* just to avoid clinkc pthread concurrency faults */
 		cg_wait( 1000 );
-		
+
 		/* discover if it was found */
-		gmyth_upnp->upnp_dev_found = gmyth_upnp_print_cp_device_list( gmyth_upnp->control_point, &gmyth_upnp->udn,
-									&gmyth_upnp->mythtv_servers );
-		
-	}
-	
-	if ( gmyth_upnp->upnp_dev_found ) {
-		
+		gmyth_upnp->priv->upnp_dev_found = gmyth_upnp_got_mythtv_service( gmyth_upnp->control_point, &gmyth_upnp->priv->udn,
+				&gmyth_upnp->priv->mythtv_servers );
+
+	} /* while */
+
+	if ( gmyth_upnp->priv->upnp_dev_found ) {
+
 		gmyth_debug( "Found UPnP MythTV AV Device...\n" );
-		
-		if ( g_list_first( gmyth_upnp->mythtv_servers ) != NULL && (g_list_first( gmyth_upnp->mythtv_servers ))->data != NULL )
-		{
-			gmyth_upnp->uri = (gchar*) (g_list_first( gmyth_upnp->mythtv_servers ))->data;
-			uri = gmyth_uri_new_with_value( gmyth_upnp->uri );
-			
-			gmyth_upnp->host = gmyth_uri_get_host( uri );
-			gmyth_upnp->port = gmyth_uri_get_port( uri );
-			gmyth_upnp->protocol = gmyth_uri_get_protocol( uri );
-			
-			/* sets all the discovered data from the UPnP remote device, like host name, IP address, port,... */
-			if ( NULL != gmyth_upnp->host )
-				gmyth_backend_info_set_hostname ( gmyth_upnp->gmyth_backend_info, gmyth_upnp->host );
-			
-			if ( gmyth_upnp->port > 0 )
-				 gmyth_backend_info_set_port ( gmyth_upnp->gmyth_backend_info, gmyth_upnp->port );
-				 
-			ret = TRUE;
-		}
-	}	
 
-done:
+		g_hash_table_foreach( gmyth_upnp->priv->mythtv_servers, (GHFunc)_gmyth_foreach_key_value, upnp_servers_list );
 
-  if ( uri != NULL )
-  {
-  	g_object_unref( uri );
-  	uri = NULL;
-  }  	
+	} /* if - found UPnP device  */
 
-	return ret;
-	
+	return upnp_servers_list;
 }
 
 /** 
- * Prints the Control Point's device list
+ * Checks if got the MythTV service in the Control Point's device list.
  */
 static gboolean
-gmyth_upnp_print_cp_device_list( CgUpnpControlPoint* controlPt, gchar **udn, GList **mythtv_servers_lst )
+gmyth_upnp_got_mythtv_service( CgUpnpControlPoint* controlPt, gchar **udn, 
+	GHashTable **mythtv_servers_lst )
 {
 	
 	g_return_val_if_fail( mythtv_servers_lst != NULL, FALSE );	
 	g_return_val_if_fail( controlPt != NULL, FALSE );
+
+	*mythtv_servers_lst = g_hash_table_new( g_str_hash, g_str_equal );
 	
 	gchar* mythtvFriendlyName = "Myth";
 	/* begin assertion about the size of discovered devices */
 	gint numDevices = cg_upnp_controlpoint_getndevices(controlPt);
 	gint cntDevs = 0;	
-	//CgUpnpDeviceList *devList = NULL;
 	CgUpnpDevice *childDev;
 	gchar *devName = NULL, *dev_url = NULL;
 	gboolean upnp_dev_found = FALSE;
@@ -259,8 +325,10 @@
 		gmyth_debug( "Device's friendly name = %s, and  device's URL = %s\n", devName, dev_url );
 		if ( ( upnp_dev_found = ( g_strstr_len( devName, strlen( devName ), mythtvFriendlyName ) != NULL ) ) == TRUE ) 
 		{
+			/* stores the last UDN number ID */
 			*udn = cg_upnp_device_getudn( childDev );
-			*mythtv_servers_lst = g_list_append( *mythtv_servers_lst, dev_url ); 
+			/* *mythtv_servers_lst = g_list_append( *mythtv_servers_lst, dev_url );  */
+			g_hash_table_insert( *mythtv_servers_lst, (gpointer)*udn, (gpointer)dev_url );
 		}
 		++cntDevs;
 	}
@@ -277,57 +345,22 @@
 
 }
 
-/** Gets the GMythBackendInfo host object associated to this upnp.
- * 
- * @return The string host object currently valid or NULL if the settings
- * were not opened.
- */
-gchar*
-gmyth_upnp_get_host ( GMythUPnP *gmyth_upnp )
-{
-	
-	if ( NULL == gmyth_upnp || NULL == gmyth_upnp->host ) 
-	{
-		gmyth_debug ("[%s] GMythUPnP host field not initialized\n", __FUNCTION__);
-		return NULL;
-	}
-
-	return gmyth_upnp->host;
-}
-
-/** Gets the GMythBackendInfo port object associated to this upnp.
- * 
- * @return The string object currently valid or NULL if the port number.
- */
-gint
-gmyth_upnp_get_port( GMythUPnP *gmyth_upnp )
-{
-
-	if ( NULL == gmyth_upnp || gmyth_upnp->port <= 0 ) 
-	{
-		gmyth_debug ("[%s] GMythUPnP host field not initialized\n", __FUNCTION__);
-		return 0;
-	}
-
-	return gmyth_upnp->port;
-}
-
 /** Gets the UPnP AV devices server's list associated to this upnp.
  * 
- * @return The GList* containing all the URI values for each recognized UPnP device,
+ * @return The GHashTable* containing all the URI values for each recognized UPnP device,
  * 			or NULL if it couldn't recognize any MythTV AV device.
  */
-GList*
+GHashTable*
 gmyth_upnp_get_servers ( GMythUPnP *gmyth_upnp )
 {
 	
-	if ( NULL == gmyth_upnp || NULL == gmyth_upnp->mythtv_servers ) 
+	if ( NULL == gmyth_upnp || NULL == gmyth_upnp->priv->mythtv_servers ) 
 	{
 		gmyth_debug ("[%s] GMythUPnP has no MythTV servers recognized.\n", __FUNCTION__);
 		return NULL;
 	}
 
-	return gmyth_upnp->mythtv_servers;
+	return gmyth_upnp->priv->mythtv_servers;
 }
 
 /** Gets the GMythBackendInfo object associated to this upnp.
@@ -339,12 +372,12 @@
 gmyth_upnp_get_backend_info ( GMythUPnP *gmyth_upnp )
 {
 	
-	if ( NULL == gmyth_upnp || NULL == gmyth_upnp->gmyth_backend_info ) 
+	if ( NULL == gmyth_upnp || NULL == gmyth_upnp->backend_info ) 
 	{
 		gmyth_debug ("[%s] GMythUPnP not initialized\n", __FUNCTION__);
 		return NULL;
 	}
 
-	return gmyth_upnp->gmyth_backend_info;
+	return gmyth_upnp->backend_info;
 }
 
diff -r 4712c96954be -r 7afeec40ed62 gmyth-upnp/src/gmyth_upnp.h
--- a/gmyth-upnp/src/gmyth_upnp.h	Fri May 18 23:29:00 2007 +0100
+++ b/gmyth-upnp/src/gmyth_upnp.h	Tue May 22 19:14:37 2007 +0100
@@ -51,45 +51,62 @@
 
 typedef struct _GMythUPnP         GMythUPnP;
 typedef struct _GMythUPnPClass    GMythUPnPClass;
+typedef struct _GMythUPnPPrivate  GMythUPnPPrivate;
 
 /****************************************
 * Data Type
 ****************************************/
 
+typedef enum upnp_device_list_status {
+	GMYTH_UPNP_DEVICE_ADDED = 0,
+	GMYTH_UPNP_DEVICE_REMOVED,
+	GMYTH_UPNP_DEVICE_UPDATED
+} GMythUPnPDeviceStatus;
+
+typedef void (*GMythUPnPDeviceListener) ( GMythUPnPDeviceStatus status, gchar *dev );
+
 struct _GMythUPnPClass
 {
-  GObjectClass parent_class;
+	GObjectClass parent_class;
 
-  /* callbacks */
-  /* no one for now */
+	/* callbacks */
+	guint device_found_handler_signal_id;
+
+	GMythUPnPDeviceListener device_found_handler;
+
+	/* no one for now */
 };
 
+struct _GMythUPnPDevice {
+	gchar *uri;
+	gchar *host;
+	gint port;
+	gchar *protocol;
+};
+
+typedef struct _GMythUPnPDevice GMythUPnPDevice;
+
 struct _GMythUPnP {
 	
 	GObject parent;
+	GMythUPnPPrivate *priv;
 	
-	gchar *uri;
-	gchar *host;
-	gint port;
-	gchar *protocol;
-	
+
 	CgUpnpControlPoint* control_point;
 	
 	gchar *udn;
 	
-	GMythBackendInfo *gmyth_backend_info;
-	
-	GList* mythtv_servers;
-	
+	GMythBackendInfo *backend_info;
+
 	gboolean upnp_dev_found;
-	
 };
 
 GType       			gmyth_upnp_get_type (void);
-GMythUPnP *				gmyth_upnp_new ( GMythBackendInfo *gmyth_backend_info );
-gchar*						gmyth_upnp_get_host ( GMythUPnP *gmyth_upnp );
-gint							gmyth_upnp_get_port ( GMythUPnP *gmyth_upnp );
-GMythBackendInfo*	gmyth_upnp_get_backend_info ( GMythUPnP *gmyth_upnp );
+GMythUPnP *			gmyth_upnp_new ( GMythBackendInfo *gmyth_backend_info, 
+						GMythUPnPDeviceListener handler );
+gchar*				gmyth_upnp_get_host ( GMythUPnP *gmyth_upnp );
+gint				gmyth_upnp_get_port ( GMythUPnP *gmyth_upnp );
+GMythBackendInfo*		gmyth_upnp_get_backend_info ( GMythUPnP *gmyth_upnp );
 
 G_END_DECLS
 
diff -r 4712c96954be -r 7afeec40ed62 gmyth-upnp/src/gmyth_upnp_marshal.list
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gmyth-upnp/src/gmyth_upnp_marshal.list	Tue May 22 19:14:37 2007 +0100
@@ -0,0 +1,2 @@
+VOID:INT,STRING
+VOID:INT,POINTER