[GnomeMeeting-devel-list] [PATCH] leaks in the dbus component



Hi,

the following patch fixes leaks in the dbus component.

It also renames the names of the dbus service&object&interface to
something better (at least imnsho). The attached gm_remote.c is updated
to reflect this.

I don't want to apply that patch myself, since I don't want to do
anything that would disturb Damien's work (well, that and the fact that
committing on a 56k is really painful).

Snark
#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 SERVICE "org.gnomemeeting.instance"
#define INTERFACE "org.gnomemeeting.instance"
#define OBJECT "/org/gnomemeeting/instance"


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;
}
diff -ur gnomemeeting/gnomemeeting.service.in gnomemeeting.patched/gnomemeeting.service.in
--- gnomemeeting/gnomemeeting.service.in	2004-10-27 09:52:45 +0200
+++ gnomemeeting.patched/gnomemeeting.service.in	2004-12-20 15:51:18 +0100
@@ -1,4 +1,4 @@
 [D-BUS Service]
-Name=org.gnomemeeting.CallService
+Name=org.gnomemeeting.instance
 Exec= prefix@/bin/gnomemeeting
 
diff -ur gnomemeeting/src/dbus_component.cpp gnomemeeting.patched/src/dbus_component.cpp
--- gnomemeeting/src/dbus_component.cpp	2004-10-27 09:52:45 +0200
+++ gnomemeeting.patched/src/dbus_component.cpp	2004-12-20 15:51:02 +0100
@@ -542,6 +542,7 @@
 			     DBUS_TYPE_INVALID)) {
 
     GnomeMeeting::Process ()->Connect (address);
+    g_free (address);
   }
 }
 
@@ -580,6 +581,7 @@
   
     /* FIXME: should use call_token, when gnomemeeting will support it! */
     GnomeMeeting::Process ()->Disconnect ();
+    g_free (call_token);
   }
 }
 
@@ -642,6 +644,9 @@
       dbus_connection_flush (connection);
     }
     dbus_message_unref (reply);
+    g_free (name);
+    g_free (app);
+    g_free (url);
   }
 }
 
@@ -676,7 +681,7 @@
 
 void
 dbus_component_call_address (GObject *object, 
-			     gchar *address)
+			     const gchar *address)
 {
   DBusMessage *message = NULL;
   DBusComponent *self = NULL;
diff -ur gnomemeeting/src/dbus_component.h gnomemeeting.patched/src/dbus_component.h
--- gnomemeeting/src/dbus_component.h	2004-10-27 09:52:45 +0200
+++ gnomemeeting.patched/src/dbus_component.h	2004-12-20 15:51:02 +0100
@@ -111,9 +111,9 @@
  * "endpoint-state-changed".
  */
 
-#define GM_DBUS_OBJECT_PATH "/org/gnomemeeting/Endpoint"
-#define GM_DBUS_INTERFACE "org.gnomemeeting.CallService"
-#define GM_DBUS_SERVICE "org.gnomemeeting.CallService"
+#define GM_DBUS_SERVICE "org.gnomemeeting.instance"
+#define GM_DBUS_INTERFACE "org.gnomemeeting.instance"
+#define GM_DBUS_OBJECT_PATH "/org/gnomemeeting/instance"
 
 
 G_BEGIN_DECLS
@@ -144,7 +144,7 @@
  *                url.
  * PRE          : A non-NULL DBUS component casted as a GObject, and an URL
  */
-void dbus_component_call_address (GObject *object, gchar *url);
+void dbus_component_call_address (GObject *object, const gchar *url);
 
 
 G_END_DECLS


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]