[GnomeMeeting-devel-list] DBUS component
- From: PUYDT Julien <jpuydt free fr>
- To: GnomeMeeting Devel Liste <gnomemeeting-devel-list gnome org>
- Subject: [GnomeMeeting-devel-list] DBUS component
- Date: Thu, 21 Oct 2004 13:57:22 +0200
Hi,
there should be three things attached to this mail:
* a patch to re-enable events in gnomemeeting ;
* a patch to add a dbus component to gnomemeeting ;
* the sources of a little remote using dbus.
The re-enabling patch isn't 100% clean for two reasons:
1) there's a mutex that wasn't there last time, and that I'm not sure
won't be an issue
2) the disabling wasn't 100% clean either ;-)
The dbus component patch, as far as I remember, should be quite clean
and not give any problem.
The remote should mostly work, but will most certainly crash if any
problem arises (ie: no error detection and handling in there -- don't do
that for anything serious).
Now, how to use those:
* patch gnomemeeting (both) ;
* compile gnomemeeting ;
* install gnomemeeting (this will make sure gnomemeeting can be launched
through dbus -- you can skip that step if you don't want that) ;
* launch a dbus daemon (dbus-daemon-1 --session --print-address) and get
its address ;
* launch the remote with DBUS_SESSION_BUS_ADDRESS set to what the daemon
said ;
* launch gnomemeeting (either from the remote if you installed it, or by
hand, setting the DBUS_SESSION_BUS_ADDRESS).
* now you should be able to use gnomemeeting as usual, and the remote
will show if you're calling, in a call, etc...
* or make/stop a call using the remote.
If anything goes wrong, please notify me,
Snark
diff -urN gnomemeeting/configure.in gnomemeeting.patched/configure.in
--- gnomemeeting/configure.in 2004-10-01 18:12:04 +0200
+++ gnomemeeting.patched/configure.in 2004-10-03 11:30:17 +0200
@@ -406,6 +406,27 @@
AC_CHECK_TYPES(xmlSAXHandlerV1,,, [#include <libxml/SAX.h>])
CPPFLAGS="$CPPFLAGS_save"
+dnl #########################################################################
+dnl Check for DBUS
+dnl #########################################################################
+AC_ARG_ENABLE(dbus,
+ [ --enable-dbus Enable the DBUS component.],
+ enable_dbus=yes, enable_dbus=no)
+
+AC_MSG_CHECKING(whether the DBUS component should be compiled in)
+if test x"${enable_dbus}" = xyes ; then
+ AC_MSG_RESULT([yes])
+else
+ AC_MSG_RESULT([no])
+fi
+
+if test x"${enable_dbus}" = xyes ; then
+ PKG_CHECK_MODULES(DBUS, dbus-1 = 0.22 dbus-glib-1 = 0.22)
+ GNOMEMEETING_CFLAGS="$GNOMEMEETING_CFLAGS $DBUS_CFLAGS -DHAS_DBUS"
+ GNOMEMEETING_LIBS="$GNOMEMEETING_LIBS $DBUS_LIBS"
+fi
+AM_CONDITIONAL(HAS_DBUS, test x"${enable_dbus}" = xyes)
+AM_CONDITIONAL(DBUS_SERVICES_INSTALL, test x"${enable_dbus}" = xyes)
dnl ###########################################################################
dnl The various CFLAGS are merged into GNOMEMEETING_CFLAGS and
@@ -463,6 +484,7 @@
Makefile
src/gnomemeeting-config-tool
gnomemeeting.schemas.in
+gnomemeeting.service
lib/Makefile
lib/about/Makefile
lib/druid/Makefile
diff -urN gnomemeeting/gnomemeeting.service.in gnomemeeting.patched/gnomemeeting.service.in
--- gnomemeeting/gnomemeeting.service.in 1970-01-01 01:00:00 +0100
+++ gnomemeeting.patched/gnomemeeting.service.in 2004-10-03 11:30:17 +0200
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name=org.gnomemeeting.CallService
+Exec= prefix@/bin/gnomemeeting
+
diff -urN gnomemeeting/Makefile.am gnomemeeting.patched/Makefile.am
--- gnomemeeting/Makefile.am 2004-08-14 16:00:31 +0200
+++ gnomemeeting.patched/Makefile.am 2004-10-03 11:30:17 +0200
@@ -36,8 +36,15 @@
GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) gconftool-2 --makefile-install-rule $(SCHEMAS_FILE) 2>&1 > /dev/null
gconftool-2 --shutdown
+install-services: gnomemeeting.service
+ cp gnomemeeting.service $(libdir)/dbus-1.0/services/
+
if GCONF_SCHEMAS_INSTALL
install-data-local: install-schemas
else
install-data-local:
endif
+
+if DBUS_SERVICES_INSTALL
+install-data-local: install-services
+endif
diff -urN gnomemeeting/src/dbus_component.cpp gnomemeeting.patched/src/dbus_component.cpp
--- gnomemeeting/src/dbus_component.cpp 1970-01-01 01:00:00 +0100
+++ gnomemeeting.patched/src/dbus_component.cpp 2004-10-03 11:30:17 +0200
@@ -0,0 +1,634 @@
+#include "dbus_component.h"
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "gm_conf.h"
+
+#include "common.h"
+#include "gnomemeeting.h"
+#include "endpoint.h"
+
+/* declaration of the GObject */
+
+
+#define DBUS_COMPONENT_TYPE dbus_component_get_type ()
+
+
+#define DBUS_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ DBUS_COMPONENT_TYPE, DBusComponent))
+
+
+#define DBUS_COMPONENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
+ DBUS_COMPONENT_TYPE, DBusComponentClass))
+
+
+#define IS_DBUS_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
+ DBUS_COMPONENT_TYPE))
+
+
+#define DBUS_COMPONENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ DBUS_COMPONENT_TYPE, \
+ DBusComponentClass))
+
+
+typedef struct _DBusComponent DBusComponent;
+
+
+typedef struct _DBusComponentClass DBusComponentClass;
+
+
+struct _DBusComponent
+{
+ GObject parent;
+
+ GMH323EndPoint *endpoint;
+ DBusConnection *connection;
+ gboolean is_registered;
+ gboolean owns_the_service;
+};
+
+
+struct _DBusComponentClass
+{
+ GObjectClass parent;
+};
+
+
+static GType dbus_component_get_type();
+
+
+static void dbus_component_finalize (GObject *self);
+
+
+static void dbus_component_init (DBusComponent *self);
+
+
+static void dbus_component_class_init (DBusComponentClass *klass);
+
+
+/* declaration of various helpers */
+
+
+static const gchar *state_to_string (GMH323EndPoint::CallingState);
+
+
+static gboolean connect_component (gpointer user_data);
+
+
+/* declaration of the signal callbacks */
+
+
+static void call_begin_cb (GObject *self,
+ gchar *call_token,
+ gpointer user_data);
+
+
+static void call_end_cb (GObject *self,
+ gchar *call_token,
+ gpointer user_data);
+
+
+static void endpoint_state_changed_cb (GObject *self,
+ GMH323EndPoint::CallingState new_state,
+ gpointer user_data);
+
+
+/* declaration of the DBUS helper functions */
+
+
+/* this is a sort of callback, called by DBUS when a watched type of message
+ * arrives.
+ */
+static DBusHandlerResult filter_func (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data);
+
+
+
+/* this function is called by DBUS when a message directed at the
+ * GM_DBUS_OBJECT_PATH arrives (provided we're the registered instance!)
+ */
+static DBusHandlerResult path_message_func (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data);
+
+/* the rest of those DBUS helpers, with name "handle_<method call>_message",
+ * are used to handle the various method calls. They get their arguments
+ * directly from path_message_func.
+ */
+static void handle_connect_to_message (DBusConnection *connection,
+ DBusMessage *message);
+
+
+static void handle_get_state_message (DBusConnection *connection,
+ DBusMessage *message);
+
+
+static void handle_disconnect_message (DBusConnection *connection,
+ DBusMessage *message);
+
+
+static void handle_get_calls_list_message (DBusConnection *connection,
+ DBusMessage *message);
+
+
+static void handle_get_call_info_message (DBusConnection *connection,
+ DBusMessage *message);
+
+
+/* definition of some helper DBUS-related data */
+
+
+static DBusObjectPathVTable call_vtable = {
+ NULL,
+ path_message_func,
+ NULL,
+};
+
+
+/* Implementation of the GObject */
+
+
+static GType
+dbus_component_get_type()
+{
+ static GType my_type = 0;
+
+ if (!my_type) {
+ static const GTypeInfo my_info = {
+ sizeof (DBusComponentClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) dbus_component_class_init,
+ NULL,
+ NULL,
+ sizeof(DBusComponent),
+ 0,
+ (GInstanceInitFunc) dbus_component_init
+ };
+ my_type = g_type_register_static (G_TYPE_OBJECT ,
+ "DBusComponent", &my_info,
+ (GTypeFlags)0);
+ }
+
+ return my_type;
+}
+
+
+static void
+dbus_component_finalize (GObject *object)
+{
+ DBusComponent *self = NULL;
+ GObjectClass *parent_class = NULL;
+
+ g_return_if_fail (IS_DBUS_COMPONENT (object));
+
+ self = DBUS_COMPONENT (object);
+
+ if (self->connection != NULL) {
+ dbus_connection_disconnect (self->connection);
+ dbus_connection_unref (self->connection);
+ }
+
+ parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (DBUS_COMPONENT_GET_CLASS (self)));
+
+ parent_class->finalize (G_OBJECT(self));
+}
+
+
+static void
+dbus_component_init (DBusComponent *self)
+{
+ self->endpoint = NULL;
+ self->connection = NULL;
+ self->is_registered = FALSE;
+ self->owns_the_service = FALSE;
+
+ g_signal_connect (G_OBJECT (self),
+ "call-begin",
+ G_CALLBACK (call_begin_cb),
+ NULL);
+ g_signal_connect (G_OBJECT (self),
+ "call-end",
+ G_CALLBACK (call_end_cb),
+ NULL);
+ g_signal_connect (G_OBJECT (self),
+ "endpoint-state-changed",
+ G_CALLBACK (endpoint_state_changed_cb),
+ NULL);
+}
+
+
+static void dbus_component_class_init (DBusComponentClass *klass)
+{
+ GObjectClass *object_klass = G_OBJECT_CLASS (klass);
+
+ object_klass->finalize = dbus_component_finalize;
+}
+
+
+/* implementation of various helpers */
+
+
+static const gchar*
+state_to_string (GMH323EndPoint::CallingState state)
+{
+ const gchar *result;
+
+ switch (state) {
+ case GMH323EndPoint::Standby:
+ result = "Standby";
+ break;
+ case GMH323EndPoint::Calling:
+ result = "Calling";
+ break;
+ case GMH323EndPoint::Connected:
+ result = "Connected";
+ break;
+ case GMH323EndPoint::Called:
+ result = "Called";
+ break;
+ default:
+ result = "Bogus";
+ }
+
+ return result;
+}
+
+
+static gboolean
+connect_component (gpointer user_data)
+{
+ DBusComponent *self = NULL;
+
+ g_return_val_if_fail (IS_DBUS_COMPONENT (user_data), TRUE);
+
+ self = DBUS_COMPONENT (user_data);
+
+ if (self->connection == NULL) { /* we lost contact with the server */
+ self->connection = dbus_bus_get (DBUS_BUS_SESSION, NULL);
+ if (self->connection != NULL) {
+ if (dbus_connection_add_filter (self->connection,
+ filter_func,
+ self, NULL))
+ dbus_connection_setup_with_g_main (self->connection, NULL);
+ else {
+ dbus_connection_disconnect (self->connection);
+ self->connection = NULL;
+ }
+ }
+ }
+
+ if (self->connection != NULL) {
+ /* we have a contact with the server, check the rest */
+ if (self->is_registered == FALSE)
+ self->is_registered
+ = dbus_connection_register_object_path (self->connection,
+ GM_DBUS_OBJECT_PATH,
+ &call_vtable, self);
+
+ if (self->owns_the_service == FALSE)
+ self->owns_the_service
+ = (dbus_bus_acquire_service (self->connection,
+ GM_DBUS_SERVICE, 0, NULL) >= 0);
+
+
+ }
+
+ return self->connection != NULL && self->is_registered && self->owns_the_service;
+}
+
+
+/* implementation of the signal callbacks */
+
+
+static void
+call_begin_cb (GObject *object,
+ gchar *call_token,
+ gpointer user_data)
+{
+ DBusComponent *self = NULL;
+ DBusMessage *message = NULL;
+
+ g_return_if_fail (IS_DBUS_COMPONENT (object));
+
+ self = DBUS_COMPONENT (object);
+
+ if (self->connection == NULL)
+ return;
+
+ message = dbus_message_new_signal (GM_DBUS_OBJECT_PATH,
+ GM_DBUS_INTERFACE, "AddCall");
+
+ if (dbus_message_append_args (message,
+ DBUS_TYPE_STRING, call_token,
+ DBUS_TYPE_INVALID)) {
+ (void)dbus_connection_send (self->connection, message, NULL);
+ dbus_connection_flush (self->connection);
+ }
+ dbus_message_unref (message);
+}
+
+
+static void
+call_end_cb (GObject *object,
+ gchar *call_token,
+ gpointer user_data)
+{
+ DBusComponent *self = NULL;
+ DBusMessage *message = NULL;
+
+ g_return_if_fail (IS_DBUS_COMPONENT (object));
+
+ self = DBUS_COMPONENT (object);
+
+ if (self->connection == NULL)
+ return;
+
+ message = dbus_message_new_signal (GM_DBUS_OBJECT_PATH,
+ GM_DBUS_INTERFACE, "DeleteCall");
+
+ if (dbus_message_append_args (message,
+ DBUS_TYPE_STRING, call_token,
+ DBUS_TYPE_INVALID)) {
+ (void)dbus_connection_send (self->connection, message, NULL);
+ dbus_connection_flush (self->connection);
+ }
+ dbus_message_unref (message);
+}
+
+
+static void
+endpoint_state_changed_cb (GObject *object,
+ GMH323EndPoint::CallingState new_state,
+ gpointer user_data)
+{
+ DBusComponent *self = NULL;
+ DBusMessage *message = NULL;
+
+ g_return_if_fail (IS_DBUS_COMPONENT (object));
+
+ self = DBUS_COMPONENT (object);
+
+ if (self->connection == NULL)
+ return;
+
+ message = dbus_message_new_signal (GM_DBUS_OBJECT_PATH,
+ GM_DBUS_INTERFACE, "StateChanged");
+
+ if (dbus_message_append_args (message,
+ DBUS_TYPE_STRING, state_to_string (new_state),
+ DBUS_TYPE_INVALID)) {
+ (void)dbus_connection_send (self->connection, message, NULL);
+ dbus_connection_flush (self->connection);
+ }
+ dbus_message_unref (message);
+}
+
+
+/* implementation of the DBUS helpers */
+
+
+static DBusHandlerResult
+filter_func (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ DBusComponent *self = NULL;
+
+ g_return_val_if_fail (user_data != NULL,
+ DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+
+ self = DBUS_COMPONENT (user_data);
+
+ g_return_val_if_fail (self->connection == connection,
+ DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+
+ if (dbus_message_is_signal (message,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
+ "Disconnected"))
+ {
+ dbus_connection_unref (self->connection);
+ self->connection = NULL;
+ self->is_registered = FALSE;
+ self->owns_the_service = FALSE;
+ g_timeout_add (3000, connect_component, (gpointer)self);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
+static DBusHandlerResult
+path_message_func (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ DBusComponent *self = NULL;
+ DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ self = DBUS_COMPONENT (user_data);
+ if (dbus_message_is_method_call (message,
+ GM_DBUS_SERVICE,
+ "ConnectTo")) {
+ handle_connect_to_message (connection, message);
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ }
+ else if (dbus_message_is_method_call (message,
+ GM_DBUS_SERVICE,
+ "GetState")) {
+ handle_get_state_message (connection, message);
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ }
+ else if (dbus_message_is_method_call (message,
+ GM_DBUS_SERVICE,
+ "Disconnect")) {
+ handle_disconnect_message (connection, message);
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ }
+ else if (dbus_message_is_method_call (message,
+ GM_DBUS_SERVICE,
+ "GetCallsList")) {
+ handle_get_calls_list_message (connection, message);
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ }
+ else if (dbus_message_is_method_call (message,
+ GM_DBUS_SERVICE,
+ "GetCallInfo")) {
+ handle_get_call_info_message (connection, message);
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ return result;
+}
+
+
+static void
+handle_connect_to_message (DBusConnection *connection,
+ DBusMessage *message)
+{
+ gchar *address = NULL;
+
+ if (dbus_message_get_args (message, NULL,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID)) {
+ GnomeMeeting::Process ()->Connect (address);
+ }
+}
+
+
+static void
+handle_get_state_message (DBusConnection *connection,
+ DBusMessage *message)
+{
+ DBusMessage *reply = NULL;
+ const gchar *state = NULL;
+ GMH323EndPoint *ep = NULL;
+
+ ep = GnomeMeeting::Process ()->Endpoint ();
+
+ reply = dbus_message_new_method_return (message);
+ state = state_to_string (ep->GetCallingState ());
+ if (dbus_message_append_args (reply,
+ DBUS_TYPE_STRING, state,
+ DBUS_TYPE_INVALID)) {
+ (void)dbus_connection_send (connection, reply, NULL);
+ dbus_connection_flush (connection);
+ }
+ dbus_message_unref (reply);
+}
+
+
+static void
+handle_disconnect_message (DBusConnection *connection,
+ DBusMessage *message)
+{
+ gchar *call_token = NULL;
+ if (dbus_message_get_args (message, NULL,
+ DBUS_TYPE_STRING, &call_token,
+ DBUS_TYPE_INVALID)) {
+ /* FIXME: should use call_token, when gnomemeeting will support it! */
+ GnomeMeeting::Process ()->Disconnect ();
+ }
+}
+
+
+static void
+handle_get_calls_list_message (DBusConnection *connection,
+ DBusMessage *message)
+{
+ DBusMessage *reply = NULL;
+ const char *call_token = NULL;
+ GMH323EndPoint *ep = NULL;
+
+ ep = GnomeMeeting::Process ()->Endpoint ();
+
+ reply = dbus_message_new_method_return (message);
+ call_token = (const char *)ep->GetCurrentCallToken ();
+ if (dbus_message_append_args (reply,
+ DBUS_TYPE_STRING, call_token,
+ DBUS_TYPE_INVALID)) {
+ (void)dbus_connection_send (connection, reply, NULL);
+ dbus_connection_flush (connection);
+ }
+ dbus_message_unref (reply);
+}
+
+
+static void
+handle_get_call_info_message (DBusConnection *connection,
+ DBusMessage *message)
+{
+ DBusMessage *reply = NULL;
+ const char *call_token = NULL;
+ GMH323EndPoint *ep = NULL;
+ H323Connection *h323connection = NULL;
+ gchar *name = NULL;
+ gchar *url = NULL;
+ gchar *app = NULL;
+
+ ep = GnomeMeeting::Process ()->Endpoint ();
+
+ if (dbus_message_get_args (message, NULL,
+ DBUS_TYPE_STRING, &call_token,
+ DBUS_TYPE_INVALID)) {
+ h323connection = ep->FindConnectionWithLock((PString)call_token);
+ if (h323connection) {
+ ep->GetRemoteConnectionInfo (*h323connection, name, app, url);
+ h323connection->Unlock ();
+ }
+ reply = dbus_message_new_method_return (message);
+ if (dbus_message_append_args (reply,
+ DBUS_TYPE_STRING, name,
+ DBUS_TYPE_STRING, url,
+ DBUS_TYPE_STRING, app,
+ DBUS_TYPE_INVALID)) {
+ (void)dbus_connection_send (connection, reply, NULL);
+ dbus_connection_flush (connection);
+ }
+ dbus_message_unref (reply);
+ }
+}
+
+
+/* implementation of the externally-visible api */
+
+
+GObject*
+dbus_component_new(GMH323EndPoint *endpoint)
+{
+ DBusComponent *result = NULL;
+
+ result = DBUS_COMPONENT (g_object_new (DBUS_COMPONENT_TYPE, NULL));
+
+ result->endpoint = endpoint;
+ result->endpoint->AddObserver (G_OBJECT (result));
+
+ (void)connect_component ((gpointer)result);
+
+ return G_OBJECT (result);
+}
+
+
+gboolean
+dbus_component_is_first_instance (GObject *object)
+{
+ g_return_val_if_fail (IS_DBUS_COMPONENT (object), FALSE);
+
+ return DBUS_COMPONENT (object)->is_registered;
+}
+
+
+void
+dbus_component_call_address (GObject *object,
+ gchar *address)
+{
+ DBusMessage *message = NULL;
+ DBusComponent *self = NULL;
+
+ g_return_if_fail (IS_DBUS_COMPONENT (object));
+
+ self = DBUS_COMPONENT (object);
+
+ if (self->connection == NULL)
+ return;
+
+ message = dbus_message_new_method_call (GM_DBUS_SERVICE,
+ GM_DBUS_OBJECT_PATH,
+ GM_DBUS_INTERFACE, "Call");
+
+ dbus_message_set_no_reply (message, TRUE);
+
+ if (dbus_message_append_args (message,
+ DBUS_TYPE_STRING, address,
+ DBUS_TYPE_INVALID)) {
+
+ (void)dbus_connection_send (self->connection,
+ message, NULL);
+ dbus_connection_flush (self->connection);
+ }
+ dbus_message_unref (message);
+}
diff -urN gnomemeeting/src/dbus_component.h gnomemeeting.patched/src/dbus_component.h
--- gnomemeeting/src/dbus_component.h 1970-01-01 01:00:00 +0100
+++ gnomemeeting.patched/src/dbus_component.h 2004-10-03 11:30:17 +0200
@@ -0,0 +1,95 @@
+#ifndef _DBUS_COMPONENT_H_
+#define _DBUS_COMPONENT_H_
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "endpoint.h"
+
+
+/* Here is the description of DBUS messages understood by this component:
+ *
+ * Method calls:
+ * =============
+ *
+ * "ConnectTo"
+ * in : string (url)
+ * out : nil
+ * action: makes gnomemeeting call the given url
+ *
+ * "GetState"
+ * in : nil
+ * out : string (describes gnomemeeting's state: Standby, Calling, etc)
+ * action: none
+ *
+ * "Disconnect"
+ * in : string (call token)
+ * out : nil
+ * action: gnomemeeting disconnects the given call
+ *
+ * "GetCallsList"
+ * in : nil
+ * out : list of strings (call tokens, iterate to get them)
+ * action: none
+ *
+ * "GetCallInfo"
+ * in : string (call token)
+ * out : string (name), string (url) and string (application)
+ * action: none
+ *
+ * Signals:
+ * ========
+ *
+ * "StateChanged"
+ * data: string (state)
+ * goal: gnomemeeting's state changed
+ *
+ * "AddCall"
+ * data: string (call token)
+ * goal: gnomemeeting manages a new call
+ *
+ * "DeleteCall"
+ * data: string (call token)
+ * goal: gnomemeeting closed a call (ie: the call token isn't valid anymore!)
+ *
+ */
+
+#define GM_DBUS_OBJECT_PATH "/org/gnomemeeting/Endpoint"
+#define GM_DBUS_INTERFACE "org.gnomemeeting.CallService"
+#define GM_DBUS_SERVICE "org.gnomemeeting.CallService"
+
+
+G_BEGIN_DECLS
+
+
+/* DESCRIPTION : /
+ * BEHAVIOR : Returns a valid DBUS component casted as a GObject
+ * PRE : a valid endpoint
+ */
+GObject *dbus_component_new(GMH323EndPoint *endpoint);
+
+
+/* the two following functions, currently unused, could be used by Damien
+ * to make so that if gnomemeeting is called with "-c url", then if there's
+ * already another instance, pass it the call and exit.
+ */
+
+/* DESCRIPTION : /
+ * BEHAVIOR : Returns TRUE if there's no other gnomemeeting registered
+ * on DBUS.
+ * PRE : A non-NULL DBUS component casted as a GObject
+ */
+gboolean dbus_component_is_first_instance (GObject *object);
+
+
+/* DESCRIPTION : /
+ * BEHAVIOR : Makes the gnomemeeting registered on DBUS call the given
+ * url.
+ * PRE : A non-NULL DBUS component casted as a GObject, and an URL
+ */
+void dbus_component_call_address (GObject *object, gchar *url);
+
+
+G_END_DECLS
+
+#endif
diff -urN gnomemeeting/src/gnomemeeting.cpp gnomemeeting.patched/src/gnomemeeting.cpp
--- gnomemeeting/src/gnomemeeting.cpp 2004-09-24 08:47:19 +0200
+++ gnomemeeting.patched/src/gnomemeeting.cpp 2004-10-03 11:30:17 +0200
@@ -52,6 +52,9 @@
#include "log_window.h"
#include "main_window.h"
#include "misc.h"
+#ifdef HAS_DBUS
+#include "dbus_component.h"
+#endif
#include "dialog.h"
#include "e-splash.h"
@@ -137,6 +140,8 @@
gtk_widget_destroy (main_window);
if (druid_window)
gtk_widget_destroy (druid_window);
+ if (dbus_component)
+ g_object_unref (dbus_component);
}
@@ -417,6 +422,11 @@
#ifndef WIN32
tray = gm_tray_new ();
#endif
+#ifdef HAS_DBUS
+ dbus_component = dbus_component_new (endpoint);
+#else
+ dbus_component = NULL;
+#endif
main_window = gm_main_window_new ();
diff -urN gnomemeeting/src/gnomemeeting.h gnomemeeting.patched/src/gnomemeeting.h
--- gnomemeeting/src/gnomemeeting.h 2004-09-10 21:20:22 +0200
+++ gnomemeeting.patched/src/gnomemeeting.h 2004-10-03 11:30:17 +0200
@@ -274,6 +274,9 @@
GtkWidget *pc2phone_window;
GtkWidget *tray;
+ /* other things */
+ GObject *dbus_component;
+
static GnomeMeeting *GM;
};
diff -urN gnomemeeting/src/Makefile.am gnomemeeting.patched/src/Makefile.am
--- gnomemeeting/src/Makefile.am 2004-10-01 18:12:04 +0200
+++ gnomemeeting.patched/src/Makefile.am 2004-10-03 11:30:18 +0200
@@ -61,6 +61,10 @@
gnomemeeting_SOURCES += bonobo_component.cpp bonobo_component.h
endif
+if HAS_DBUS
+gnomemeeting_SOURCES += dbus_component.cpp dbus_component.h
+endif
+
gnomemeeting_LDADD = \
@GNOMEMEETING_LIBS@ \
$(top_builddir)/lib/libgnomemeeting.la
diff -urN gnomemeeting/lib/Makefile.am gnomemeeting.events/lib/Makefile.am
--- gnomemeeting/lib/Makefile.am 2004-10-16 20:04:37 +0200
+++ gnomemeeting.events/lib/Makefile.am 2004-10-21 09:50:58 +0200
@@ -29,7 +29,9 @@
eggtrayicon.h \
eggtrayicon.c \
stats_drawing_area.h \
- stats_drawing_area.c
+ stats_drawing_area.c \
+ gm_events.h \
+ gm_events.c
if DISABLE_GNOME
libgnomemeeting_la_SOURCES += gm_conf-glib.c
diff -urN gnomemeeting/src/endpoint.cpp gnomemeeting.events/src/endpoint.cpp
--- gnomemeeting/src/endpoint.cpp 2004-10-21 07:30:19 +0200
+++ gnomemeeting.events/src/endpoint.cpp 2004-10-21 09:51:56 +0200
@@ -57,6 +57,7 @@
#include "dialog.h"
#include "gm_conf.h"
+#include "gm_events.h"
#include <h261codec.h>
@@ -108,6 +109,8 @@
missed_calls = 0;
+ dispatcher = gm_events_dispatcher_new ();
+
last_audio_octets_received = 0;
last_video_octets_received = 0;
last_audio_octets_transmitted = 0;
@@ -140,6 +143,9 @@
if (ils_client)
delete (ils_client);
+ if (dispatcher)
+ g_object_unref (dispatcher);
+
/* Create a new one to unregister */
if (ils_registered) {
@@ -322,6 +328,9 @@
PWaitAndSignal m(cs_access_mutex);
calling_state = i;
+ /* FIXME: holding a mutex!? */
+ if (dispatcher)
+ g_signal_emit_by_name (dispatcher, "endpoint-state-changed", i);
}
@@ -1087,6 +1096,8 @@
gm_tray_update_calling_state (tray, GMH323EndPoint::Connected);
gm_tray_update (tray, GMH323EndPoint::Connected, icm, forward_on_busy);
gnomemeeting_threads_leave ();
+ if (dispatcher)
+ g_signal_emit_by_name (dispatcher, "call-begin", (const gchar *)token);
/* Update ILS if needed */
@@ -1351,6 +1362,9 @@
gnomemeeting_text_chat_call_stop_notification (chat_window);
gm_main_window_flash_message (main_window, msg_reason);
gnomemeeting_threads_leave ();
+ if (dispatcher)
+ g_signal_emit_by_name (dispatcher, "call-end",
+ (const gchar *)clearedCallToken);
g_free (utf8_app);
g_free (utf8_name);
@@ -2720,6 +2734,13 @@
return missed_calls;
}
+void
+GMH323EndPoint::AddObserver (GObject *observer)
+{
+ g_return_if_fail (observer != NULL);
+
+ gm_events_dispatcher_add_observer (dispatcher, observer);
+}
PString
GMH323EndPoint::GetLastCallAddress ()
diff -urN gnomemeeting/src/endpoint.h gnomemeeting.events/src/endpoint.h
--- gnomemeeting/src/endpoint.h 2004-10-21 07:30:19 +0200
+++ gnomemeeting.events/src/endpoint.h 2004-10-21 09:50:58 +0200
@@ -738,6 +738,7 @@
H323ListenerTCP *listener;
CallingState calling_state;
+ GObject *dispatcher;
PTimer GatekeeperTimer;
PTimer ILSTimer;
diff -urN gnomemeeting/src/main_window.cpp gnomemeeting.events/src/main_window.cpp
--- gnomemeeting/src/main_window.cpp 2004-10-21 07:30:19 +0200
+++ gnomemeeting.events/src/main_window.cpp 2004-10-21 09:50:58 +0200
@@ -49,6 +49,7 @@
#include "lid.h"
#include "sound_handling.h"
#include "urlhandler.h"
+#include "gm_events.h"
#include <dialog.h>
#include <gmentrydialog.h>
@@ -4139,7 +4140,7 @@
xmlInitParser ();
gm_conf_init (argc, argv);
-
+ gm_events_init ();
/* Upgrade the preferences */
gnomemeeting_conf_upgrade ();
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
#define DBUS_API_SUBJECT_TO_CHANGE
#include <dbus/dbus.h>
#include <dbus/dbus-glib-lowlevel.h>
#define OBJECT "/org/gnomemeeting/Endpoint"
#define INTERFACE "org.gnomemeeting.CallService"
#define SERVICE "org.gnomemeeting.CallService"
struct needed_data {
DBusConnection *connection;
GtkWidget *window;
GtkListStore *call_store;
GtkTreeView *call_view;
};
enum {
CALL_TOKEN_COLUMN,
NAME_COLUMN,
URL_COLUMN,
APP_COLUMN,
NUMBER_OF_COLUMNS
};
/* various helpers (declaration) */
static GtkWidget *call_popup_new (const struct needed_data *my_data);
static gboolean set_iter_on_right_call_token (GtkTreeModel *model,
GtkTreeIter *iter,
gchar *call_token);
static void add_call (struct needed_data *my_data,
gchar *call_token);
static void delete_call (struct needed_data *my_data,
gchar *call_token);
/* gtk callbacks (declaration) */
static gint call_clicked_cb (GtkWidget *widget,
GdkEventButton *button,
gpointer user_data);
static void connect_cb (GtkWidget *,
gpointer);
static void disconnect_cb (GtkWidget *,
gpointer);
static void launch_cb (GtkWidget *,
gpointer);
/* DBUS helpers (declaration) */
static DBusHandlerResult filter_func (DBusConnection *connection,
DBusMessage *message,
void *user_data);
/* various helpers (implementation) */
static GtkWidget *
call_popup_new (const struct needed_data *my_data)
{
GtkWidget *popup = NULL;
GtkWidget *item = NULL;
popup = gtk_menu_new ();
item = gtk_menu_item_new_with_label ("Disconnect");
g_signal_connect (G_OBJECT (item), "activate",
GTK_SIGNAL_FUNC (disconnect_cb), (gpointer)my_data);
gtk_menu_append (popup, item);
return popup;
}
static gboolean
set_iter_on_right_call_token (GtkTreeModel *model,
GtkTreeIter *iter,
gchar *call_token)
{
gchar *iter_call_token = NULL;
g_return_val_if_fail (model != NULL
&& iter != NULL
&& call_token != NULL, FALSE);
if (gtk_tree_model_get_iter_first (model, iter)) {
do {
gtk_tree_model_get (model, iter,
CALL_TOKEN_COLUMN, &iter_call_token,
-1);
if (strcmp (call_token, iter_call_token) == 0)
return TRUE;
} while (gtk_tree_model_iter_next (model, iter));
}
return FALSE;
}
static void
add_call (struct needed_data *my_data,
gchar *call_token)
{
gchar *name = NULL;
gchar *url = NULL;
gchar *app = NULL;
GtkTreeIter iter;
DBusMessage *message = NULL;
DBusMessage *reply = NULL;
DBusPendingCall *call = NULL;
DBusError error;
g_return_if_fail (my_data != NULL && call_token != NULL);
g_print ("add call %s\n", call_token);
dbus_error_init (&error);
/* first, get the data */
message = dbus_message_new_method_call (SERVICE, OBJECT,
INTERFACE, "GetCallInfo");
(void)dbus_message_append_args (message,
DBUS_TYPE_STRING, call_token,
DBUS_TYPE_INVALID);
dbus_message_set_no_reply (message, FALSE);
(void)dbus_connection_send_with_reply (my_data->connection, message,
&call, -1);
dbus_connection_flush (my_data->connection);
dbus_pending_call_block (call);
reply = dbus_pending_call_get_reply (call);
if (!dbus_message_get_args (reply, NULL,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &url,
DBUS_TYPE_STRING, &app,
DBUS_TYPE_INVALID)) {
g_print ("Couldn't get name, url & app: %s\n", name);
dbus_error_free (&error);
return;
}
/* then push it in the store */
gtk_list_store_append (my_data->call_store, &iter);
gtk_list_store_set (my_data->call_store, &iter,
CALL_TOKEN_COLUMN, call_token,
NAME_COLUMN, name,
URL_COLUMN, url,
APP_COLUMN, app,
-1);
}
static void
delete_call (struct needed_data *my_data,
gchar *call_token)
{
GtkTreeIter iter;
g_print ("delete_call %s\n", call_token);
g_return_if_fail (my_data != NULL && call_token != NULL);
if (set_iter_on_right_call_token (GTK_TREE_MODEL (my_data->call_store),
&iter, call_token)) {
(void)gtk_list_store_remove (my_data->call_store, &iter);
}
}
static void
update_status (struct needed_data *my_data)
{
DBusMessage *message = NULL;
DBusMessage *reply = NULL;
DBusPendingCall *call = NULL;
gchar *title = NULL;
g_print ("update_status\n");
if (dbus_bus_service_exists (my_data->connection, SERVICE, NULL)) {
message = dbus_message_new_method_call (SERVICE, OBJECT,
INTERFACE, "GetState");
dbus_message_set_no_reply (message, FALSE);
(void)dbus_connection_send_with_reply (my_data->connection, message,
&call, -1);
dbus_connection_flush (my_data->connection);
dbus_pending_call_block (call);
reply = dbus_pending_call_get_reply (call);
if (dbus_message_get_args (reply, NULL,
DBUS_TYPE_STRING, &title,
DBUS_TYPE_INVALID)) {
gtk_window_set_title (GTK_WINDOW (my_data->window), title);
g_free (title);
}
dbus_message_unref (message);
dbus_message_unref (reply);
dbus_pending_call_unref (call);
}
else
gtk_window_set_title (GTK_WINDOW (my_data->window), "Not running");
}
/* gtk callbacks (implementation) */
static gint
call_clicked_cb (GtkWidget *widget,
GdkEventButton *button,
gpointer user_data)
{
struct needed_data *my_data = (struct needed_data *)user_data;
GtkWidget *popup = NULL;
if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
popup = call_popup_new (my_data);
gtk_menu_popup (GTK_MENU (popup), NULL, NULL, NULL, NULL,
button->button, button->time);
g_signal_connect (G_OBJECT (popup), "hide",
GTK_SIGNAL_FUNC (g_object_unref), (gpointer)popup);
g_object_ref (G_OBJECT (popup)); /* gtk memory management */
gtk_object_sink (GTK_OBJECT (popup)); /* is amazing */
gtk_widget_show_all (popup);
}
return TRUE;
}
static void
connect_cb (GtkWidget *widget,
gpointer user_data)
{
struct needed_data *my_data = (struct needed_data *)user_data;
DBusMessage *message = NULL;
message = dbus_message_new_method_call (SERVICE, OBJECT,
INTERFACE, "ConnectTo");
(void)dbus_message_append_args (message,
DBUS_TYPE_STRING,
gtk_entry_get_text (GTK_ENTRY (widget)),
DBUS_TYPE_INVALID);
dbus_message_set_no_reply (message, TRUE);
(void)dbus_connection_send (my_data->connection, message, NULL);
dbus_connection_flush (my_data->connection);
dbus_message_unref (message);
}
static void
disconnect_cb (GtkWidget *widget,
gpointer user_data)
{
struct needed_data *my_data = (struct needed_data *)user_data;
GtkTreeSelection *selection = NULL;
GtkTreeIter iter;
gchar *call_token = NULL;
DBusMessage *message = NULL;
selection = gtk_tree_view_get_selection (my_data->call_view);
if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
gtk_tree_model_get (GTK_TREE_MODEL (my_data->call_store), &iter,
CALL_TOKEN_COLUMN, &call_token,
-1);
message = dbus_message_new_method_call (SERVICE, OBJECT,
INTERFACE, "Disconnect");
(void)dbus_message_append_args (message,
DBUS_TYPE_STRING, call_token,
DBUS_TYPE_INVALID);
dbus_message_set_no_reply (message, TRUE);
(void)dbus_connection_send (my_data->connection, message, NULL);
dbus_connection_flush (my_data->connection);
dbus_message_unref (message);
}
}
static void
launch_cb (GtkWidget *widget,
gpointer user_data)
{
struct needed_data *my_data = (struct needed_data *)user_data;
(void)dbus_bus_activate_service (my_data->connection, SERVICE, 0, NULL, NULL);
}
/* DBUS helpers (implementation) */
static DBusHandlerResult
filter_func(DBusConnection *connection,
DBusMessage *message,
void *user_data)
{
struct needed_data *my_data = (struct needed_data *)user_data;
char *str = NULL;
/* we just lost contact with DBUS */
if (dbus_message_is_signal (message,
DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
"Disconnected"))
{
g_print ("Disconnected\n");
exit (-1); /* just die */
return DBUS_HANDLER_RESULT_HANDLED;
}
/* DBUS says someone got/lost a service */
else if (dbus_message_is_signal (message,
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
"ServiceCreated")
|| dbus_message_is_signal (message,
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
"ServiceDeleted")) {
dbus_message_get_args (message,
NULL,
DBUS_TYPE_STRING, &str,
DBUS_TYPE_INVALID);
if (strcmp (str, SERVICE) == 0) { /* check it's the right service */
update_status (my_data);
return DBUS_HANDLER_RESULT_HANDLED;
}
}
/* the rest of the messages are from gnomemeeting itself */
else if (dbus_message_is_signal (message,
INTERFACE,
"StateChanged")) {
update_status (my_data);
}
else if (dbus_message_is_signal (message,
INTERFACE,
"AddCall")) {
dbus_message_get_args (message,
NULL,
DBUS_TYPE_STRING, &str,
DBUS_TYPE_INVALID);
add_call (my_data, str);
}
else if (dbus_message_is_signal (message,
INTERFACE,
"DeleteCall")) {
dbus_message_get_args (message,
NULL,
DBUS_TYPE_STRING, &str,
DBUS_TYPE_INVALID);
delete_call (my_data, str);
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
/* well... */
int main (int argc,
char *argv [])
{
GtkWidget *window = NULL;
GtkListStore *call_store = NULL;
GtkWidget *call_view = NULL;
GtkCellRenderer *renderer = NULL;
GtkTreeViewColumn *column = NULL;
GtkWidget *vbox = NULL;
GtkWidget *hbox = NULL;
GtkWidget *entry = NULL;
GtkWidget *entry_label = NULL;
GtkWidget *launch_button = NULL;
struct needed_data *my_data = NULL;
gtk_set_locale ();
gtk_init (&argc, &argv);
my_data = g_new0 (struct needed_data, 1);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
my_data->window = window;
g_signal_connect (G_OBJECT (window), "delete-event",
G_CALLBACK (gtk_false), NULL);
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (gtk_main_quit), NULL);
vbox = gtk_vbox_new (FALSE, 2);
gtk_container_add (GTK_CONTAINER (window), vbox);
call_store = gtk_list_store_new (NUMBER_OF_COLUMNS,
G_TYPE_STRING, /* call token */
G_TYPE_STRING, /* name */
G_TYPE_STRING, /* url */
G_TYPE_STRING); /* app */
my_data->call_store = call_store;
call_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (call_store));
my_data->call_view = GTK_TREE_VIEW (call_view);
gtk_box_pack_start (GTK_BOX (vbox), call_view, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (call_view), "event-after",
G_CALLBACK (call_clicked_cb), my_data);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes ("Name",
renderer,
"text", NAME_COLUMN,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (call_view), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes ("URL",
renderer,
"text", URL_COLUMN,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (call_view), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes ("Application",
renderer,
"text", APP_COLUMN,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (call_view), column);
/* test line */
GtkTreeIter iter;
gtk_list_store_append (call_store, &iter);
gtk_list_store_set (call_store, &iter,
CALL_TOKEN_COLUMN, "test",
NAME_COLUMN, "Remote user",
URL_COLUMN, "In a galaxy far far away",
APP_COLUMN, "Gnomemeeting II",
-1);
/* end test */
hbox = gtk_hbox_new (FALSE, 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
entry_label = gtk_label_new ("URL: ");
gtk_box_pack_start (GTK_BOX (hbox), entry_label, FALSE, FALSE, 0);
entry = gtk_entry_new ();
gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (entry), "activate",
GTK_SIGNAL_FUNC (connect_cb), (gpointer)my_data);
launch_button = gtk_button_new_with_label ("Launch GM");
g_signal_connect (G_OBJECT (launch_button), "clicked",
GTK_SIGNAL_FUNC (launch_cb), (gpointer)my_data);
gtk_box_pack_start (GTK_BOX (hbox), launch_button, FALSE, FALSE, 0);
gtk_widget_show_all (window);
my_data->connection = dbus_bus_get (DBUS_BUS_SESSION, NULL);
/* tell DBUS where our ears are */
if (!dbus_connection_add_filter (my_data->connection,
filter_func,
my_data, NULL)) {
g_print ("Couldn't add filter\n");
exit (-1);
}
/* DBUS will tell us when gnomemeeting comes and goes */
dbus_bus_add_match (my_data->connection,
"type='signal',"
"sender='" DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS "',"
"interface='" DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS "'",
NULL);
/* we want to know what gnomemeeting signals */
dbus_bus_add_match (my_data->connection,
"type='signal',"
"interface='" INTERFACE "'",
NULL);
update_status (my_data);
dbus_connection_setup_with_g_main (my_data->connection, NULL);
gtk_main ();
return 0;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]