]> git.0d.be Git - empathy.git/blobdiff - src/empathy-debug-window.c
debug: make add_client() more generic
[empathy.git] / src / empathy-debug-window.c
index 2fe8f3e2272435c740edb04d10303a1316126a2b..f813becc2f9d877e93d4f033f18ff63e60e439d3 100644 (file)
 */
 
 #include "config.h"
-
-#include <string.h>
+#include "empathy-debug-window.h"
 
 #include <glib/gi18n.h>
-#include <gtk/gtk.h>
-#include <gio/gio.h>
-#include <gdk/gdkkeysyms.h>
 #include <libsoup/soup.h>
+#include <tp-account-widgets/tpaw-utils.h>
+#include <telepathy-glib/telepathy-glib-dbus.h>
 
-#define DEBUG_FLAG EMPATHY_DEBUG_OTHER
-#include <libempathy/empathy-debug.h>
-#include <libempathy/empathy-utils.h>
-
-#include <libempathy-gtk/empathy-account-chooser.h>
-#include <libempathy-gtk/empathy-geometry.h>
-#include <libempathy-gtk/empathy-ui-utils.h>
-
-#include <telepathy-glib/dbus.h>
-#include <telepathy-glib/interfaces.h>
-#include <telepathy-glib/util.h>
-#include <telepathy-glib/proxy-subclass.h>
-#include <telepathy-glib/account-manager.h>
-
-#include "extensions/extensions.h"
+#include "empathy-geometry.h"
+#include "empathy-ui-utils.h"
+#include "empathy-utils.h"
 
-#include "empathy-debug-window.h"
+#define DEBUG_FLAG EMPATHY_DEBUG_OTHER
+#include "empathy-debug.h"
 
 G_DEFINE_TYPE (EmpathyDebugWindow, empathy_debug_window,
     GTK_TYPE_WINDOW)
@@ -58,12 +45,7 @@ typedef enum
 
 enum
 {
-  COL_DEBUG_TIMESTAMP = 0,
-  COL_DEBUG_DOMAIN,
-  COL_DEBUG_CATEGORY,
-  COL_DEBUG_LEVEL_STRING,
-  COL_DEBUG_MESSAGE,
-  COL_DEBUG_LEVEL_VALUE,
+  COL_DEBUG_MESSAGE = 0,
   NUM_DEBUG_COLS
 };
 
@@ -129,26 +111,26 @@ struct _EmpathyDebugWindowPriv
 };
 
 static const gchar *
-log_level_to_string (guint level)
+log_level_to_string (GLogLevelFlags level)
 {
   switch (level)
     {
-    case TP_DEBUG_LEVEL_ERROR:
+    case G_LOG_LEVEL_ERROR:
       return "Error";
       break;
-    case TP_DEBUG_LEVEL_CRITICAL:
+    case G_LOG_LEVEL_CRITICAL:
       return "Critical";
       break;
-    case TP_DEBUG_LEVEL_WARNING:
+    case G_LOG_LEVEL_WARNING:
       return "Warning";
       break;
-    case TP_DEBUG_LEVEL_MESSAGE:
+    case G_LOG_LEVEL_MESSAGE:
       return "Message";
       break;
-    case TP_DEBUG_LEVEL_INFO:
+    case G_LOG_LEVEL_INFO:
       return "Info";
       break;
-    case TP_DEBUG_LEVEL_DEBUG:
+    case G_LOG_LEVEL_DEBUG:
       return "Debug";
       break;
     default:
@@ -181,140 +163,89 @@ copy_buffered_messages (GtkTreeModel *buffer,
 {
   GtkListStore *active_buffer = data;
   GtkTreeIter active_buffer_iter;
-  gdouble timestamp;
-  gchar *domain, *category, *message, *level_string;
-  guint level;
+  TpDebugMessage *msg;
 
   gtk_tree_model_get (buffer, iter,
-      COL_DEBUG_TIMESTAMP, &timestamp,
-      COL_DEBUG_DOMAIN, &domain,
-      COL_DEBUG_CATEGORY, &category,
-      COL_DEBUG_LEVEL_STRING, &level_string,
-      COL_DEBUG_MESSAGE, &message,
-      COL_DEBUG_LEVEL_VALUE, &level,
+      COL_DEBUG_MESSAGE, &msg,
       -1);
   gtk_list_store_insert_with_values (active_buffer, &active_buffer_iter, -1,
-      COL_DEBUG_TIMESTAMP, timestamp,
-      COL_DEBUG_DOMAIN, domain,
-      COL_DEBUG_CATEGORY, category,
-      COL_DEBUG_LEVEL_STRING, level_string,
-      COL_DEBUG_MESSAGE, message,
-      COL_DEBUG_LEVEL_VALUE, level,
+      COL_DEBUG_MESSAGE, msg,
       -1);
 
-  g_free (domain);
-  g_free (category);
-  g_free (level_string);
-  g_free (message);
+  g_object_unref (msg);
 
   return FALSE;
 }
 
 static void
 insert_values_in_buffer (GtkListStore *store,
-        gdouble timestamp,
-        const gchar *domain,
-        const gchar *category,
-        guint level,
-        const gchar *string)
+    TpDebugMessage *msg)
 {
   GtkTreeIter iter;
 
   gtk_list_store_insert_with_values (store, &iter, -1,
-      COL_DEBUG_TIMESTAMP, timestamp,
-      COL_DEBUG_DOMAIN, domain,
-      COL_DEBUG_CATEGORY, category,
-      COL_DEBUG_LEVEL_STRING, log_level_to_string (level),
-      COL_DEBUG_MESSAGE, string,
-      COL_DEBUG_LEVEL_VALUE, level,
+      COL_DEBUG_MESSAGE, msg,
       -1);
 }
 
 static void
 debug_window_add_message (EmpathyDebugWindow *self,
-    TpProxy *proxy,
-    gdouble timestamp,
-    const gchar *domain_category,
-    guint level,
-    const gchar *message)
-{
-  gchar *domain, *category;
-  gchar *string;
+    TpDebugClient *debug,
+    TpDebugMessage *msg)
+{
   GtkListStore *active_buffer, *pause_buffer;
 
-  if (g_strrstr (domain_category, "/"))
-    {
-      gchar **parts = g_strsplit (domain_category, "/", 2);
-      domain = g_strdup (parts[0]);
-      category = g_strdup (parts[1]);
-      g_strfreev (parts);
-    }
-  else
-    {
-      domain = g_strdup (domain_category);
-      category = g_strdup ("");
-    }
-
-  if (g_str_has_suffix (message, "\n"))
-    string = g_strchomp (g_strdup (message));
-  else
-    string = g_strdup (message);
-
-  pause_buffer = g_object_get_data (G_OBJECT (proxy), "pause-buffer");
-  active_buffer = g_object_get_data (G_OBJECT (proxy), "active-buffer");
+  pause_buffer = g_object_get_data (G_OBJECT (debug), "pause-buffer");
+  active_buffer = g_object_get_data (G_OBJECT (debug), "active-buffer");
 
   if (self->priv->paused)
     {
-      insert_values_in_buffer (pause_buffer, timestamp,
-          domain, category, level,
-          string);
+      insert_values_in_buffer (pause_buffer, msg);
     }
   else
     {
       /* Append 'this' message to this service's and All's active-buffers */
-      insert_values_in_buffer (active_buffer, timestamp,
-          domain, category, level,
-          string);
+      insert_values_in_buffer (active_buffer, msg);
 
-      insert_values_in_buffer (self->priv->all_active_buffer, timestamp,
-          domain, category, level,
-          string);
+      insert_values_in_buffer (self->priv->all_active_buffer, msg);
     }
-
-  g_free (string);
-  g_free (domain);
-  g_free (category);
 }
 
 static void
-debug_window_new_debug_message_cb (TpProxy *proxy,
-    gdouble timestamp,
-    const gchar *domain,
-    guint level,
-    const gchar *message,
-    gpointer user_data,
-    GObject *weak_object)
+debug_window_new_debug_message_cb (TpDebugClient *debug,
+    TpDebugMessage *msg,
+    gpointer user_data)
 {
   EmpathyDebugWindow *self = user_data;
 
-  debug_window_add_message (self, proxy, timestamp, domain, level,
-      message);
+  debug_window_add_message (self, debug, msg);
 }
 
 static void
-debug_window_set_enabled (TpProxy *proxy,
-    gboolean enabled)
+set_enabled_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
 {
-  GValue *val;
-
-  g_return_if_fail (proxy != NULL);
+  TpDebugClient *debug = TP_DEBUG_CLIENT (source);
+  gboolean enabled = GPOINTER_TO_UINT (user_data);
+  GError *error = NULL;
 
-  val = tp_g_value_slice_new_boolean (enabled);
+  if (!tp_debug_client_set_enabled_finish (debug, result, &error))
+    {
+      DEBUG ("Failed to %s debugging on %s", enabled ? "enable" : "disable",
+          tp_proxy_get_bus_name (debug));
+      g_error_free (error);
+    }
+}
 
-  tp_cli_dbus_properties_call_set (proxy, -1, TP_IFACE_DEBUG,
-      "Enabled", val, NULL, NULL, NULL, NULL);
+static void
+debug_window_set_enabled (TpDebugClient *debug,
+    gboolean enabled)
+{
+  g_return_if_fail (debug != NULL);
 
-  tp_g_value_slice_free (val);
+  tp_debug_client_set_enabled_async (debug, enabled,
+      set_enabled_cb, GUINT_TO_POINTER (enabled));
 }
 
 static void
@@ -419,12 +350,11 @@ proxy_invalidated_cb (TpProxy *proxy,
 }
 
 static void
-debug_window_get_messages_cb (TpProxy *proxy,
-    const GPtrArray *messages,
-    const GError *error,
-    gpointer user_data,
-    GObject *weak_object)
+debug_window_get_messages_cb (GObject *object,
+    GAsyncResult *result,
+    gpointer user_data)
 {
+  TpDebugClient *debug = TP_DEBUG_CLIENT (object);
   EmpathyDebugWindow *self = user_data;
   gchar *active_service_name;
   guint i;
@@ -432,8 +362,10 @@ debug_window_get_messages_cb (TpProxy *proxy,
   gboolean valid_iter;
   GtkTreeIter iter;
   gchar *proxy_service_name;
+  GPtrArray *messages;
+  GError *error = NULL;
 
-  active_buffer = g_object_get_data (G_OBJECT (proxy), "active-buffer");
+  active_buffer = g_object_get_data (object, "active-buffer");
   valid_iter = debug_window_get_iter_for_active_buffer (active_buffer, &iter,
       self);
   gtk_tree_model_get (GTK_TREE_MODEL (self->priv->service_store), &iter,
@@ -441,9 +373,12 @@ debug_window_get_messages_cb (TpProxy *proxy,
       -1);
 
   active_service_name = get_active_service_name (self);
-  if (error != NULL)
+
+  messages = tp_debug_client_get_messages_finish (debug, result, &error);
+  if (messages == NULL)
     {
-      DEBUG ("GetMessages failed: %s", error->message);
+      DEBUG ("Failed to get debug messages: %s", error->message);
+      g_error_free (error);
 
       /* We want to set the window sensitivity to false only when proxy for the
        * selected service is unable to fetch debug messages */
@@ -451,7 +386,7 @@ debug_window_get_messages_cb (TpProxy *proxy,
         debug_window_set_toolbar_sensitivity (self, FALSE);
 
       /* We created the proxy for GetMessages call. Now destroy it. */
-      tp_clear_object (&proxy);
+      tp_clear_object (&debug);
       return;
     }
 
@@ -459,16 +394,11 @@ debug_window_get_messages_cb (TpProxy *proxy,
   g_free (active_service_name);
   debug_window_set_toolbar_sensitivity (self, TRUE);
 
-
   for (i = 0; i < messages->len; i++)
     {
-      GValueArray *values = g_ptr_array_index (messages, i);
+      TpDebugMessage *msg = g_ptr_array_index (messages, i);
 
-      debug_window_add_message (self, proxy,
-          g_value_get_double (g_value_array_get_nth (values, 0)),
-          g_value_get_string (g_value_array_get_nth (values, 1)),
-          g_value_get_uint (g_value_array_get_nth (values, 2)),
-          g_value_get_string (g_value_array_get_nth (values, 3)));
+      debug_window_add_message (self, debug, msg);
     }
 
   /* Now we save this precious proxy in the service_store along its service */
@@ -478,20 +408,20 @@ debug_window_get_messages_cb (TpProxy *proxy,
           " messages. Saving it.", proxy_service_name);
 
       gtk_list_store_set (self->priv->service_store, &iter,
-          COL_PROXY, proxy,
+          COL_PROXY, debug,
           -1);
     }
+  g_ptr_array_unref (messages);
 
   g_free (proxy_service_name);
 
   /* Connect to "invalidated" signal */
-  g_signal_connect (proxy, "invalidated",
+  g_signal_connect (debug, "invalidated",
       G_CALLBACK (proxy_invalidated_cb), self);
 
  /* Connect to NewDebugMessage */
-  emp_cli_debug_connect_to_new_debug_message (
-      proxy, debug_window_new_debug_message_cb, self,
-      NULL, NULL, NULL);
+  tp_g_signal_connect_object (debug, "new-debug-message",
+      G_CALLBACK (debug_window_new_debug_message_cb), self, 0);
 
   /* Now that active-buffer is up to date, we can see which messages are
    * to be visible */
@@ -499,7 +429,7 @@ debug_window_get_messages_cb (TpProxy *proxy,
         self->priv->store_filter));
 
   /* Set the proxy to signal for new debug messages */
-  debug_window_set_enabled (proxy, TRUE);
+  debug_window_set_enabled (debug, TRUE);
 }
 
 static void
@@ -508,9 +438,10 @@ create_proxy_to_get_messages (EmpathyDebugWindow *self,
     TpDBusDaemon *dbus)
 {
   gchar *bus_name, *name = NULL;
-  TpProxy *new_proxy, *stored_proxy = NULL;
+  TpDebugClient *new_proxy, *stored_proxy = NULL;
   GtkTreeModel *pause_buffer, *active_buffer;
   gboolean gone;
+  GError *error = NULL;
 
   gtk_tree_model_get (GTK_TREE_MODEL (self->priv->service_store), iter,
       COL_NAME, &name,
@@ -535,11 +466,17 @@ create_proxy_to_get_messages (EmpathyDebugWindow *self,
 
   gtk_tree_model_get (GTK_TREE_MODEL (self->priv->service_store), iter,
       COL_UNIQUE_NAME, &bus_name, -1);
-  new_proxy = g_object_new (TP_TYPE_PROXY,
-      "bus-name", bus_name,
-      "dbus-daemon", dbus,
-      "object-path", DEBUG_OBJECT_PATH,
-      NULL);
+
+  new_proxy = tp_debug_client_new (dbus, bus_name, &error);
+
+  if (new_proxy == NULL)
+    {
+      DEBUG ("Failed to create TpDebugClient on bus %s: %s", bus_name,
+          error->message);
+      g_free (bus_name);
+      goto finally;
+    }
+
   g_free (bus_name);
 
   g_object_set_data (G_OBJECT (new_proxy), "active-buffer", active_buffer);
@@ -550,10 +487,9 @@ create_proxy_to_get_messages (EmpathyDebugWindow *self,
    * * Wasn't saved as last GetMessages call failed
    * * The service has newly arrived and no proxy has been prepared yet for it
    * * A service with the same name has reappeared but the owner maybe new */
-  tp_proxy_add_interface_by_id (new_proxy, emp_iface_quark_debug ());
 
-  emp_cli_debug_call_get_messages (new_proxy, -1,
-      debug_window_get_messages_cb, self, NULL, NULL);
+  tp_debug_client_get_messages_async (TP_DEBUG_CLIENT (new_proxy),
+      debug_window_get_messages_cb, self);
 
 finally:
   g_free (name);
@@ -566,12 +502,7 @@ static GtkListStore *
 new_list_store_for_service (void)
 {
   return gtk_list_store_new (NUM_DEBUG_COLS,
-             G_TYPE_DOUBLE, /* COL_DEBUG_TIMESTAMP */
-             G_TYPE_STRING, /* COL_DEBUG_DOMAIN */
-             G_TYPE_STRING, /* COL_DEBUG_CATEGORY */
-             G_TYPE_STRING, /* COL_DEBUG_LEVEL_STRING */
-             G_TYPE_STRING, /* COL_DEBUG_MESSAGE */
-             G_TYPE_UINT);  /* COL_DEBUG_LEVEL_VALUE */
+             TP_TYPE_DEBUG_MESSAGE); /* COL_DEBUG_MESSAGE */
 }
 
 static gboolean
@@ -580,23 +511,25 @@ debug_window_visible_func (GtkTreeModel *model,
     gpointer user_data)
 {
   EmpathyDebugWindow *self = user_data;
-  guint filter_value, level;
+  GLogLevelFlags filter_value;
   GtkTreeModel *filter_model;
   GtkTreeIter filter_iter;
+  TpDebugMessage *msg;
+  gboolean result;
 
   filter_model = gtk_combo_box_get_model (
       GTK_COMBO_BOX (self->priv->level_filter));
   gtk_combo_box_get_active_iter (GTK_COMBO_BOX (self->priv->level_filter),
       &filter_iter);
 
-  gtk_tree_model_get (model, iter, COL_DEBUG_LEVEL_VALUE, &level, -1);
+  gtk_tree_model_get (model, iter, COL_DEBUG_MESSAGE, &msg, -1);
   gtk_tree_model_get (filter_model, &filter_iter,
       COL_LEVEL_VALUE, &filter_value, -1);
 
-  if (level <= filter_value)
-    return TRUE;
+  result = (tp_debug_message_get_level (msg) <= filter_value);
+  g_object_unref (msg);
 
-  return FALSE;
+  return result;
 }
 
 static gboolean
@@ -850,21 +783,21 @@ get_cm_display_name (EmpathyDebugWindow *self,
   GList *accounts, *ptr;
   char *retval;
 
-  accounts = tp_account_manager_get_valid_accounts (self->priv->am);
+  accounts = tp_account_manager_dup_valid_accounts (self->priv->am);
 
   for (ptr = accounts; ptr != NULL; ptr = ptr->next)
     {
       TpAccount *account = TP_ACCOUNT (ptr->data);
 
-      if (!tp_strdiff (tp_account_get_connection_manager (account), cm_name))
+      if (!tp_strdiff (tp_account_get_cm_name (account), cm_name))
         {
           g_hash_table_insert (protocols,
-              (char *) tp_account_get_protocol (account),
+              (char *) tp_account_get_protocol_name (account),
               GUINT_TO_POINTER (TRUE));
         }
     }
 
-  g_list_free (accounts);
+  g_list_free_full (accounts, g_object_unref);
 
   if (g_hash_table_size (protocols) > 0)
     {
@@ -1074,7 +1007,7 @@ debug_window_name_owner_changed_cb (TpDBusDaemon *proxy,
       return;
     }
 
-  if (EMP_STR_EMPTY (arg1) && !EMP_STR_EMPTY (arg2))
+  if (TPAW_STR_EMPTY (arg1) && !TPAW_STR_EMPTY (arg2))
     {
       GtkTreeIter *found_at_iter = NULL;
       gchar *display_name;
@@ -1154,7 +1087,7 @@ debug_window_name_owner_changed_cb (TpDBusDaemon *proxy,
 
       g_free (display_name);
     }
-  else if (!EMP_STR_EMPTY (arg1) && EMP_STR_EMPTY (arg2))
+  else if (!TPAW_STR_EMPTY (arg1) && TPAW_STR_EMPTY (arg2))
     {
       /* A service died */
       GtkTreeIter *iter = NULL;
@@ -1175,18 +1108,17 @@ debug_window_name_owner_changed_cb (TpDBusDaemon *proxy,
 }
 
 static void
-add_client (EmpathyDebugWindow *self,
-    const gchar *name)
+add_service (EmpathyDebugWindow *self,
+    const gchar *bus_name,
+    const gchar *display_name,
+    ServiceType type)
 {
-  const gchar *suffix;
   FillServiceChooserData *data;
 
-  suffix = name + strlen (TP_CLIENT_BUS_NAME_BASE);
-
-  data = fill_service_chooser_data_new (self, suffix, SERVICE_TYPE_CLIENT);
+  data = fill_service_chooser_data_new (self, display_name, type);
 
   tp_cli_dbus_daemon_call_get_name_owner (self->priv->dbus, -1,
-      name, debug_window_get_name_owner_cb, data, NULL, NULL);
+      bus_name, debug_window_get_name_owner_cb, data, NULL, NULL);
 
   self->priv->services_detected ++;
 }
@@ -1211,7 +1143,8 @@ list_names_cb (TpDBusDaemon *bus_daemon,
     {
       if (g_str_has_prefix (names[i], TP_CLIENT_BUS_NAME_BASE))
         {
-          add_client (self, names[i]);
+          add_service (self, names[i],
+              names[i] + strlen (TP_CLIENT_BUS_NAME_BASE), SERVICE_TYPE_CLIENT);
         }
     }
 }
@@ -1345,7 +1278,8 @@ debug_window_menu_copy_activate_cb (GtkMenuItem *menu_item,
   GtkTreePath *path;
   GtkTreeViewColumn *focus_column;
   GtkTreeIter iter;
-  gchar *message;
+  TpDebugMessage *msg;
+  const gchar *message;
   GtkClipboard *clipboard;
 
   gtk_tree_view_get_cursor (GTK_TREE_VIEW (self->priv->view),
@@ -1360,10 +1294,12 @@ debug_window_menu_copy_activate_cb (GtkMenuItem *menu_item,
   gtk_tree_model_get_iter (self->priv->store_filter, &iter, path);
 
   gtk_tree_model_get (self->priv->store_filter, &iter,
-      COL_DEBUG_MESSAGE, &message,
+      COL_DEBUG_MESSAGE, &msg,
       -1);
 
-  if (EMP_STR_EMPTY (message))
+  message = tp_debug_message_get_message (msg);
+
+  if (TPAW_STR_EMPTY (message))
     {
       DEBUG ("Log message is empty");
       return;
@@ -1375,7 +1311,7 @@ debug_window_menu_copy_activate_cb (GtkMenuItem *menu_item,
 
   gtk_clipboard_set_text (clipboard, message, -1);
 
-  g_free (message);
+  g_object_unref (msg);
 }
 
 typedef struct
@@ -1433,25 +1369,20 @@ debug_window_button_press_event_cb (GtkTreeView *view,
 }
 
 static gchar *
-debug_window_format_timestamp (gdouble timestamp)
+debug_window_format_timestamp (TpDebugMessage *msg)
 {
-  struct tm *tstruct;
-  char time_str[32];
+  GDateTime *t;
+  gchar *time_str, *text;
   gint ms;
-  time_t sec;
-  gchar *text;
 
-  ms = (int) ((timestamp - (int) timestamp)*1e6);
-  sec = (long) timestamp;
-  tstruct = localtime ((time_t *) &sec);
-  if (!strftime (time_str, sizeof (time_str), "%x %T", tstruct))
-    {
-      DEBUG ("Failed to format timestamp: %e", timestamp);
-      time_str[0] = '\0';
-    }
+  t = tp_debug_message_get_time (msg);
+
+  time_str = g_date_time_format (t, "%x %T");
 
+  ms = g_date_time_get_microsecond (t);
   text = g_strdup_printf ("%s.%d", time_str, ms);
 
+  g_free (time_str);
   return text;
 }
 
@@ -1462,62 +1393,131 @@ debug_window_time_formatter (GtkTreeViewColumn *tree_column,
     GtkTreeIter *iter,
     gpointer data)
 {
-  gdouble timestamp;
+  TpDebugMessage *msg;
   gchar *time_str;
 
-  gtk_tree_model_get (tree_model, iter, COL_DEBUG_TIMESTAMP, &timestamp, -1);
+  gtk_tree_model_get (tree_model, iter, COL_DEBUG_MESSAGE, &msg, -1);
 
-  time_str = debug_window_format_timestamp (timestamp);
+  time_str = debug_window_format_timestamp (msg);
 
   g_object_set (G_OBJECT (cell), "text", time_str, NULL);
 
-  g_free (time_str);
+  g_object_unref (msg);
+}
+
+static void
+debug_window_domain_formatter (GtkTreeViewColumn *tree_column,
+    GtkCellRenderer *cell,
+    GtkTreeModel *tree_model,
+    GtkTreeIter *iter,
+    gpointer data)
+{
+  TpDebugMessage *msg;
+
+  gtk_tree_model_get (tree_model, iter, COL_DEBUG_MESSAGE, &msg, -1);
+
+  g_object_set (G_OBJECT (cell), "text", tp_debug_message_get_domain (msg),
+      NULL);
+
+  g_object_unref (msg);
+}
+
+static void
+debug_window_category_formatter (GtkTreeViewColumn *tree_column,
+    GtkCellRenderer *cell,
+    GtkTreeModel *tree_model,
+    GtkTreeIter *iter,
+    gpointer data)
+{
+  TpDebugMessage *msg;
+  const gchar *category;
+
+  gtk_tree_model_get (tree_model, iter, COL_DEBUG_MESSAGE, &msg, -1);
+
+  category = tp_debug_message_get_category (msg);
+
+  g_object_set (G_OBJECT (cell), "text", category ? category : "", NULL);
+
+  g_object_unref (msg);
+}
+
+static void
+debug_window_message_formatter (GtkTreeViewColumn *tree_column,
+    GtkCellRenderer *cell,
+    GtkTreeModel *tree_model,
+    GtkTreeIter *iter,
+    gpointer data)
+{
+  TpDebugMessage *msg;
+
+  gtk_tree_model_get (tree_model, iter, COL_DEBUG_MESSAGE, &msg, -1);
+
+  g_object_set (G_OBJECT (cell), "text",
+      tp_debug_message_get_message (msg), NULL);
+
+  g_object_unref (msg);
+}
+
+static void
+debug_window_level_formatter (GtkTreeViewColumn *tree_column,
+    GtkCellRenderer *cell,
+    GtkTreeModel *tree_model,
+    GtkTreeIter *iter,
+    gpointer data)
+{
+  TpDebugMessage *msg;
+  const gchar *level;
+
+  gtk_tree_model_get (tree_model, iter, COL_DEBUG_MESSAGE, &msg, -1);
+
+  level = log_level_to_string (tp_debug_message_get_level (msg));
+
+  g_object_set (G_OBJECT (cell), "text", level, NULL);
+
+  g_object_unref (msg);
 }
 
 static gboolean
-debug_window_store_filter_foreach (GtkTreeModel *model,
+debug_window_copy_model_foreach (GtkTreeModel *model,
     GtkTreePath *path,
     GtkTreeIter *iter,
     gpointer user_data)
 {
-  gchar **debug_data = (gchar **)user_data;
-  gchar *domain, *category, *message, *level_str, *level_upper;
-  gdouble timestamp;
-  gchar *line, *time_str, *tmp;
+  gchar **text = (gchar **) user_data;
+  gchar *tmp;
+  gchar *level_upper;
+  const gchar *level_str, *category;
+  gchar *line, *time_str;
+  TpDebugMessage *msg;
+
+  if (*text == NULL)
+    *text = g_strdup ("");
 
   gtk_tree_model_get (model, iter,
-      COL_DEBUG_TIMESTAMP, &timestamp,
-      COL_DEBUG_DOMAIN, &domain,
-      COL_DEBUG_CATEGORY, &category,
-      COL_DEBUG_LEVEL_STRING, &level_str,
-      COL_DEBUG_MESSAGE, &message,
+      COL_DEBUG_MESSAGE, &msg,
       -1);
 
+  level_str = log_level_to_string (tp_debug_message_get_level (msg));
   level_upper = g_ascii_strup (level_str, -1);
 
-  time_str = debug_window_format_timestamp (timestamp);
+  time_str = debug_window_format_timestamp (msg);
+  category = tp_debug_message_get_category (msg);
 
   line = g_strdup_printf ("%s%s%s-%s: %s: %s\n",
-      domain, EMP_STR_EMPTY (category) ? "" : "/",
-      category, level_upper, time_str, message);
+      tp_debug_message_get_domain (msg),
+      category ? "" : "/", category ? category : "",
+      level_upper, time_str, tp_debug_message_get_message (msg));
 
   g_free (time_str);
 
-  /* Compact all message lines in the out parameter debug_data */
-  if (!tp_str_empty (*debug_data))
-    tmp = g_strconcat (*debug_data, line, NULL);
-  else
-    tmp = g_strdup (line);
-
-  g_free (*debug_data);
-  *debug_data = tmp;
+  tmp = g_strconcat (*text, line, NULL);
 
+  g_free (*text);
   g_free (line);
   g_free (level_upper);
-  g_free (level_str);
-  g_free (domain);
-  g_free (category);
-  g_free (message);
+  g_object_unref (msg);
+
+  *text = tmp;
 
   return FALSE;
 }
@@ -1553,7 +1553,7 @@ debug_window_save_file_chooser_response_cb (GtkDialog *dialog,
     }
 
   gtk_tree_model_foreach (self->priv->store_filter,
-      debug_window_store_filter_foreach, &debug_data);
+      debug_window_copy_model_foreach, &debug_data);
 
   g_output_stream_write (G_OUTPUT_STREAM (output_stream), debug_data,
       strlen (debug_data), NULL, &file_write_error);
@@ -1747,65 +1747,18 @@ debug_window_send_to_pastebin_cb (GtkToolButton *tool_button,
   DEBUG ("Preparing debug data for sending to pastebin.");
 
   gtk_tree_model_foreach (self->priv->store_filter,
-      debug_window_store_filter_foreach, &debug_data);
+      debug_window_copy_model_foreach, &debug_data);
 
   debug_window_send_to_pastebin (self, debug_data);
   g_free (debug_data);
 }
 
-static gboolean
-debug_window_copy_model_foreach (GtkTreeModel *model,
-    GtkTreePath *path,
-    GtkTreeIter *iter,
-    gpointer user_data)
-{
-  gchar **text = (gchar **) user_data;
-  gchar *tmp;
-  gchar *domain, *category, *message, *level_str, *level_upper;
-  gdouble timestamp;
-  gchar *line, *time_str;
-
-  gtk_tree_model_get (model, iter,
-      COL_DEBUG_TIMESTAMP, &timestamp,
-      COL_DEBUG_DOMAIN, &domain,
-      COL_DEBUG_CATEGORY, &category,
-      COL_DEBUG_LEVEL_STRING, &level_str,
-      COL_DEBUG_MESSAGE, &message,
-      -1);
-
-  level_upper = g_ascii_strup (level_str, -1);
-
-  time_str = debug_window_format_timestamp (timestamp);
-
-  line = g_strdup_printf ("%s%s%s-%s: %s: %s\n",
-      domain, EMP_STR_EMPTY (category) ? "" : "/",
-      category, level_upper, time_str, message);
-
-  g_free (time_str);
-
-  tmp = g_strconcat (*text, line, NULL);
-
-  g_free (*text);
-  g_free (line);
-  g_free (level_upper);
-  g_free (level_str);
-  g_free (domain);
-  g_free (category);
-  g_free (message);
-
-  *text = tmp;
-
-  return FALSE;
-}
-
 static void
 debug_window_copy_clicked_cb (GtkToolButton *tool_button,
     EmpathyDebugWindow *self)
 {
   GtkClipboard *clipboard;
-  gchar *text;
-
-  text = g_strdup ("");
+  gchar *text = NULL;
 
   gtk_tree_model_foreach (self->priv->store_filter,
       debug_window_copy_model_foreach, &text);
@@ -1883,6 +1836,7 @@ am_prepared_cb (GObject *am,
   GtkListStore *level_store;
   GtkTreeIter iter;
   GError *error = NULL;
+  GtkWidget *infobar, *content;
 
   if (!tp_proxy_prepare_finish (am, res, &error))
     {
@@ -1890,8 +1844,10 @@ am_prepared_cb (GObject *am,
       g_clear_error (&error);
     }
 
+  empathy_set_css_provider (GTK_WIDGET (object));
+
   gtk_window_set_title (GTK_WINDOW (object), _("Debug Window"));
-  gtk_window_set_default_size (GTK_WINDOW (object), 800, 400);
+  gtk_widget_set_size_request (GTK_WIDGET (object), 600, 300);
   empathy_geometry_bind (GTK_WINDOW (object), "debug-window");
 
   g_signal_connect (object, "key-press-event",
@@ -2026,38 +1982,64 @@ am_prepared_cb (GObject *am,
 
   gtk_list_store_insert_with_values (level_store, &iter, -1,
       COL_LEVEL_NAME, _("Debug"),
-      COL_LEVEL_VALUE, TP_DEBUG_LEVEL_DEBUG,
+      COL_LEVEL_VALUE, G_LOG_LEVEL_DEBUG,
       -1);
 
   gtk_list_store_insert_with_values (level_store, &iter, -1,
       COL_LEVEL_NAME, _("Info"),
-      COL_LEVEL_VALUE, TP_DEBUG_LEVEL_INFO,
+      COL_LEVEL_VALUE, G_LOG_LEVEL_INFO,
       -1);
 
   gtk_list_store_insert_with_values (level_store, &iter, -1,
       COL_LEVEL_NAME, _("Message"),
-      COL_LEVEL_VALUE, TP_DEBUG_LEVEL_MESSAGE,
+      COL_LEVEL_VALUE, G_LOG_LEVEL_MESSAGE,
       -1);
 
   gtk_list_store_insert_with_values (level_store, &iter, -1,
       COL_LEVEL_NAME, _("Warning"),
-      COL_LEVEL_VALUE, TP_DEBUG_LEVEL_WARNING,
+      COL_LEVEL_VALUE, G_LOG_LEVEL_WARNING,
       -1);
 
   gtk_list_store_insert_with_values (level_store, &iter, -1,
       COL_LEVEL_NAME, _("Critical"),
-      COL_LEVEL_VALUE, TP_DEBUG_LEVEL_CRITICAL,
+      COL_LEVEL_VALUE, G_LOG_LEVEL_CRITICAL,
       -1);
 
   gtk_list_store_insert_with_values (level_store, &iter, -1,
       COL_LEVEL_NAME, _("Error"),
-      COL_LEVEL_VALUE, TP_DEBUG_LEVEL_ERROR,
+      COL_LEVEL_VALUE, G_LOG_LEVEL_ERROR,
       -1);
 
   gtk_combo_box_set_active (GTK_COMBO_BOX (self->priv->level_filter), 0);
   g_signal_connect (self->priv->level_filter, "changed",
       G_CALLBACK (debug_window_filter_changed_cb), object);
 
+  /* Info bar */
+  infobar = gtk_info_bar_new ();
+  gtk_info_bar_set_message_type (GTK_INFO_BAR (infobar), GTK_MESSAGE_INFO);
+
+  label = gtk_label_new (
+        _("Even if they don't display passwords, logs can contain sensitive "
+          "information such as your list of contacts or the messages you "
+          "recently sent or received.\nIf you don't want to see such "
+          "information available in a public bug report, you "
+          "can choose to limit the visibility of your bug to "
+          "Empathy developers when reporting it by displaying "
+          "the advanced fields in the "
+          "<a href=\"https://bugzilla.gnome.org/enter_bug.cgi?product=empathy\">"
+          "bug report</a>."));
+  gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+  gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+  gtk_style_context_add_class (gtk_widget_get_style_context (label),
+      GTK_STYLE_CLASS_DIM_LABEL);
+
+  content = gtk_info_bar_get_content_area (GTK_INFO_BAR (infobar));
+  gtk_box_pack_start (GTK_BOX (content), label, FALSE, FALSE, 0);
+
+  gtk_widget_show (infobar);
+  gtk_widget_show (label);
+  gtk_box_pack_start (GTK_BOX (vbox), infobar, FALSE, FALSE, 0);
+
   /* Debug treeview */
   self->priv->view = gtk_tree_view_new ();
   gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (self->priv->view), TRUE);
@@ -2066,22 +2048,31 @@ am_prepared_cb (GObject *am,
       G_CALLBACK (debug_window_button_press_event_cb), object);
 
   renderer = gtk_cell_renderer_text_new ();
-  g_object_set (renderer, "yalign", 0, NULL);
+  g_object_set (renderer, "yalign", (gfloat) 0, NULL);
 
   gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (self->priv->view),
       -1, _("Time"), renderer,
       (GtkTreeCellDataFunc) debug_window_time_formatter, NULL, NULL);
-  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (self->priv->view),
-      -1, _("Domain"), renderer, "text", COL_DEBUG_DOMAIN, NULL);
-  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (self->priv->view),
-      -1, _("Category"), renderer, "text", COL_DEBUG_CATEGORY, NULL);
-  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (self->priv->view),
-      -1, _("Level"), renderer, "text", COL_DEBUG_LEVEL_STRING, NULL);
+  gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (self->priv->view),
+      -1, _("Domain"), renderer,
+      (GtkTreeCellDataFunc) debug_window_domain_formatter, NULL, NULL);
+  gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (self->priv->view),
+      -1, _("Category"), renderer,
+      (GtkTreeCellDataFunc) debug_window_category_formatter, NULL, NULL);
+  gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (self->priv->view),
+      -1, _("Level"), renderer,
+      (GtkTreeCellDataFunc) debug_window_level_formatter, NULL, NULL);
 
   renderer = gtk_cell_renderer_text_new ();
-  g_object_set (renderer, "family", "Monospace", NULL);
-  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (self->priv->view),
-      -1, _("Message"), renderer, "text", COL_DEBUG_MESSAGE, NULL);
+
+  g_object_set (renderer,
+      "family", "Monospace",
+      "ellipsize", PANGO_ELLIPSIZE_END,
+      NULL);
+
+  gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (self->priv->view),
+      -1, _("Message"), renderer,
+      (GtkTreeCellDataFunc) debug_window_message_formatter, NULL, NULL);
 
   self->priv->store_filter = NULL;