[tracker-miner-chatlog] Add Telepathy logger data migration
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker-miner-chatlog] Add Telepathy logger data migration
- Date: Thu, 24 Dec 2015 00:33:19 +0000 (UTC)
commit 7d1117e21fece3d7d59032570b01e026b4399183
Author: Carlos Garnacho <carlosg gnome org>
Date: Thu Dec 24 01:27:45 2015 +0100
Add Telepathy logger data migration
This is meant to happen only once (which may take looooong).
configure.ac | 28 ++++
src/Makefile.am | 9 +
src/logger-dumper.c | 410 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/logger-dumper.h | 36 +++++
src/miner.c | 71 +++++++++-
src/observer.c | 28 ++++
6 files changed, 579 insertions(+), 3 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 5813a2b..0f4ec8d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -32,6 +32,30 @@ IT_PROG_INTLTOOL([0.40.0])
# dependencies
PKG_CHECK_MODULES(DEPS, [tracker-miner-1.0 telepathy-glib])
+# optional dependencies
+AC_ARG_ENABLE(migration,
+ AS_HELP_STRING([--enable-migration],
+ [enable migration from telepathy-logger]),
+ [enable_migration=$enableval],
+ [enable_migration=yes])
+
+if test "x$enable_migration" != "xno" ; then
+ PKG_CHECK_MODULES(LOGGER,
+ [telepathy-logger-0.2],
+ [have_logger=yes],
+ [have_logger=no])
+
+ AC_SUBST(LOGGER_CFLAGS)
+ AC_SUBST(LOGGER_LIBS)
+ AM_CONDITIONAL(HAVE_MIGRATION, test "$have_logger" = "yes")
+
+ if test "$have_logger" != "no" ; then
+ AC_DEFINE(HAVE_MIGRATION, [], [Define if we have telepathy-logger migration])
+ fi
+else
+ have_logger=no
+fi
+
AC_CONFIG_FILES([
Makefile
data/Makefile
@@ -39,3 +63,7 @@ src/Makefile
po/Makefile.in
])
AC_OUTPUT
+
+echo "
+ Telepathy-logger migration: $have_logger
+"
diff --git a/src/Makefile.am b/src/Makefile.am
index d5d6e2d..ac80f1e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,13 @@
libexec_PROGRAMS = tracker-miner-chatlog
+if HAVE_MIGRATION
+migration_sources = \
+ logger-dumper.c \
+ logger-dumper.h
+endif
+
tracker_miner_chatlog_SOURCES = \
+ $(migration_sources) \
client-factory.c \
client-factory.h \
contact.c \
@@ -28,7 +35,9 @@ tracker_miner_chatlog_SOURCES = \
tracker_miner_chatlog_CPPFLAGS = \
-DG_LOG_DOMAIN=\"Tmc\" \
-I$(top_srcdir)/src \
+ $(LOGGER_CFLAGS) \
$(DEPS_CFLAGS)
tracker_miner_chatlog_LDADD = \
+ $(LOGGER_LIBS) \
$(DEPS_LIBS)
diff --git a/src/logger-dumper.c b/src/logger-dumper.c
new file mode 100644
index 0000000..f58ce34
--- /dev/null
+++ b/src/logger-dumper.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2015 Carlos Garnacho
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg gnome org>
+ */
+
+#include <telepathy-logger/telepathy-logger.h>
+
+#include "logger-dumper.h"
+#include "text-event.h"
+#include "contact.h"
+#include "room.h"
+#include "conversation.h"
+#include "entity-pool.h"
+
+typedef struct _TmcLoggerDumperPrivate TmcLoggerDumperPrivate;
+typedef struct _QueryOperation QueryOperation;
+
+struct _TmcLoggerDumper {
+ GObject parent_instance;
+};
+
+struct _QueryOperation {
+ TmcLoggerDumper *dumper;
+ TpAccount *account;
+ TplEntity *entity;
+ GList *dates;
+};
+
+struct _TmcLoggerDumperPrivate {
+ TplLogManager *log_manager;
+ GList *operations;
+ GList *accounts;
+
+ guint querying : 1;
+};
+
+enum {
+ TEXT_EVENT,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = { 0 };
+
+static gboolean tmc_logger_dumper_next_operation (TmcLoggerDumper *dumper);
+
+G_DEFINE_TYPE_WITH_PRIVATE (TmcLoggerDumper, tmc_logger_dumper, G_TYPE_OBJECT)
+
+static void
+tmc_logger_dumper_finalize (GObject *object)
+{
+ TmcLoggerDumper *dumper;
+ TmcLoggerDumperPrivate *priv;
+
+ dumper = TMC_LOGGER_DUMPER (object);
+ priv = tmc_logger_dumper_get_instance_private (dumper);
+
+ g_object_unref (priv->log_manager);
+
+ g_list_foreach (priv->accounts, (GFunc) g_object_unref, NULL);
+ g_list_free (priv->accounts);
+
+ G_OBJECT_CLASS (tmc_logger_dumper_parent_class)->finalize (object);
+}
+
+static void
+tmc_logger_dumper_class_init (TmcLoggerDumperClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = tmc_logger_dumper_finalize;
+
+ signals[TEXT_EVENT] =
+ g_signal_new ("text-event",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, TMC_TYPE_TEXT_EVENT);
+}
+
+static void
+tmc_logger_dumper_init (TmcLoggerDumper *dumper)
+{
+ TmcLoggerDumperPrivate *priv;
+
+ priv = tmc_logger_dumper_get_instance_private (dumper);
+ priv->log_manager = tpl_log_manager_dup_singleton ();
+}
+
+TmcLoggerDumper *
+tmc_logger_dumper_new (void)
+{
+ return g_object_new (TMC_TYPE_LOGGER_DUMPER, NULL);
+}
+
+static QueryOperation *
+query_operation_new (TmcLoggerDumper *dumper,
+ TpAccount *account,
+ TplEntity *entity)
+{
+ QueryOperation *op;
+
+ op = g_new0 (QueryOperation, 1);
+ op->dumper = dumper;
+ op->account = g_object_ref (account);
+ op->entity = g_object_ref (entity);
+
+ return op;
+}
+
+static void
+query_operation_free (QueryOperation *op)
+{
+ g_object_unref (op->account);
+ g_object_unref (op->entity);
+ g_list_foreach (op->dates, (GFunc) g_date_free, NULL);
+ g_list_free (op->dates);
+
+ g_free (op);
+}
+
+static TmcEntity *
+translate_contact (TplEntity *entity)
+{
+ TmcEntityPool *pool = tmc_entity_pool_contacts_get ();
+ TmcEntity *contact;
+
+ switch (tpl_entity_get_entity_type (entity)) {
+ case TPL_ENTITY_UNKNOWN:
+ case TPL_ENTITY_ROOM:
+ return NULL;
+ case TPL_ENTITY_SELF:
+ return tmc_contact_self_get ();
+ case TPL_ENTITY_CONTACT:
+ contact = tmc_entity_pool_lookup (pool, tpl_entity_get_alias (entity));
+
+ if (!contact) {
+ contact = tmc_contact_new (tpl_entity_get_alias (entity),
+ "irc");
+ tmc_entity_pool_add (pool, contact);
+ }
+
+ return contact;
+ }
+}
+
+static TmcEntity *
+translate_channel (QueryOperation *op)
+{
+ TmcEntityPool *pool = tmc_entity_pool_channels_get ();
+ TmcEntity *channel;
+
+ channel = tmc_entity_pool_lookup (pool, tpl_entity_get_alias (op->entity));
+
+ if (!channel) {
+ switch (tpl_entity_get_entity_type (op->entity)) {
+ case TPL_ENTITY_UNKNOWN:
+ case TPL_ENTITY_SELF:
+ return NULL;
+ case TPL_ENTITY_CONTACT:
+ channel = tmc_conversation_new (TMC_CONTACT (translate_contact (op->entity)));
+ break;
+ case TPL_ENTITY_ROOM:
+ channel = tmc_room_new (tpl_entity_get_alias (op->entity),
+ "irc");
+ break;
+ }
+
+ tmc_entity_pool_add (pool, channel);
+ }
+
+ return channel;
+}
+
+static void
+tmc_logger_dumper_emit_event (TmcLoggerDumper *dumper,
+ TpAccount *account,
+ TplEntity *entity,
+ TplTextEvent *event)
+{
+ TmcLoggerDumperPrivate *priv;
+ QueryOperation *op;
+ TmcTextEvent *text_event;
+ TmcEntity *from, *to, *channel;
+ GList *to_list = NULL;
+
+ priv = tmc_logger_dumper_get_instance_private (dumper);
+ op = priv->operations->data;
+
+ channel = translate_channel (op);
+ from = translate_contact (tpl_event_get_sender (TPL_EVENT (event)));
+ to = translate_contact (tpl_event_get_receiver (TPL_EVENT (event)));
+
+ if (to) {
+ to_list = g_list_prepend (to_list, to);
+ }
+
+ text_event = tmc_text_event_new (channel, from, to_list,
+ tpl_text_event_get_message (event),
+ tpl_event_get_timestamp (TPL_EVENT (event)));
+ g_signal_emit (dumper, signals[TEXT_EVENT], 0, text_event);
+ g_object_unref (text_event);
+}
+
+static void
+get_date_events_async_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ TmcLoggerDumper *dumper = user_data;
+ TmcLoggerDumperPrivate *priv = tmc_logger_dumper_get_instance_private (dumper);
+ QueryOperation *op = priv->operations->data;
+ GError *error = NULL;
+ GList *events, *l;
+
+ if (!tpl_log_manager_get_events_for_date_finish (TPL_LOG_MANAGER (object),
+ res, &events, &error)) {
+ g_warning ("Could not get events for date: %s",
+ error->message);
+ } else {
+ for (l = events; l; l = l->next) {
+ tmc_logger_dumper_emit_event (dumper, op->account,
+ op->entity, l->data);
+ g_object_unref (l->data);
+ }
+
+ g_list_free (events);
+ }
+
+ tmc_logger_dumper_next_operation (dumper);
+}
+
+static void
+get_entity_dates_async_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ TmcLoggerDumper *dumper = user_data;
+ TmcLoggerDumperPrivate *priv = tmc_logger_dumper_get_instance_private (dumper);
+ GError *error = NULL;
+ QueryOperation *op;
+
+ op = priv->operations->data;
+
+ if (!tpl_log_manager_get_dates_finish (TPL_LOG_MANAGER (object),
+ res, &op->dates, &error)) {
+ g_warning ("Could not get dates for entity: %s",
+ error->message);
+ }
+
+ tmc_logger_dumper_next_operation (dumper);
+}
+
+static void
+get_account_entities_async_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ TmcLoggerDumper *dumper = user_data;
+ TmcLoggerDumperPrivate *priv;
+ GList *l, *entities = NULL;
+ GError *error = NULL;
+ TpAccount *account;
+
+ priv = tmc_logger_dumper_get_instance_private (dumper);
+ account = priv->accounts->data;
+ priv->accounts = g_list_remove (priv->accounts, account);
+
+ if (!tpl_log_manager_get_entities_finish (TPL_LOG_MANAGER (object),
+ res, &entities, &error)) {
+ g_warning ("Could not get entities for account: %s",
+ error->message);
+ } else {
+ for (l = entities; l; l = l->next) {
+ TplEntity *entity = l->data;
+ QueryOperation *op;
+
+ op = query_operation_new (dumper, account, entity);
+ priv->operations = g_list_prepend (priv->operations, op);
+ g_object_unref (entity);
+ }
+
+ g_list_free (entities);
+ }
+
+ tmc_logger_dumper_next_operation (dumper);
+ g_object_unref (account);
+}
+
+static gboolean
+tmc_logger_dumper_query_date_events (TmcLoggerDumper *dumper)
+{
+ TmcLoggerDumperPrivate *priv = tmc_logger_dumper_get_instance_private (dumper);
+ QueryOperation *op;
+ GDate *date;
+ GList *elem;
+
+ if (!priv->operations)
+ return FALSE;
+
+ op = priv->operations->data;
+
+ if (!op->dates)
+ return FALSE;
+
+ elem = op->dates;
+ date = elem->data;
+ op->dates = op->dates->next;
+ g_list_free1 (elem);
+
+ tpl_log_manager_get_events_for_date_async (priv->log_manager,
+ op->account, op->entity,
+ TPL_EVENT_MASK_TEXT, date,
+ get_date_events_async_cb,
+ dumper);
+ g_date_free (date);
+
+ return TRUE;
+}
+
+static gboolean
+tmc_logger_dumper_query_next_entity (TmcLoggerDumper *dumper)
+{
+ TmcLoggerDumperPrivate *priv = tmc_logger_dumper_get_instance_private (dumper);
+ QueryOperation *op;
+
+ if (!priv->operations)
+ return FALSE;
+
+ op = priv->operations->data;
+ tpl_log_manager_get_dates_async (priv->log_manager,
+ op->account, op->entity,
+ TPL_EVENT_MASK_TEXT,
+ get_entity_dates_async_cb,
+ dumper);
+ return TRUE;
+}
+
+static gboolean
+tmc_logger_dumper_query_next_account (TmcLoggerDumper *dumper)
+{
+ TmcLoggerDumperPrivate *priv;
+
+ priv = tmc_logger_dumper_get_instance_private (dumper);
+ priv->querying = priv->accounts != NULL;
+
+ if (priv->accounts) {
+ tpl_log_manager_get_entities_async (priv->log_manager,
+ priv->accounts->data,
+ get_account_entities_async_cb,
+ dumper);
+ }
+
+ return priv->querying;
+}
+
+static gboolean
+tmc_logger_dumper_next_operation (TmcLoggerDumper *dumper)
+{
+ TmcLoggerDumperPrivate *priv = tmc_logger_dumper_get_instance_private (dumper);
+ QueryOperation *op;
+
+ if (!priv->operations)
+ return tmc_logger_dumper_query_next_account (dumper);
+
+ op = priv->operations->data;
+
+ if (op->dates) {
+ return tmc_logger_dumper_query_date_events (dumper);
+ } else {
+ priv->operations = g_list_remove (priv->operations, op);
+ query_operation_free (op);
+
+ return tmc_logger_dumper_query_next_entity (dumper);
+ }
+}
+
+void
+tmc_logger_dumper_add_account (TmcLoggerDumper *dumper,
+ TpAccount *account)
+{
+ TmcLoggerDumperPrivate *priv;
+
+ priv = tmc_logger_dumper_get_instance_private (dumper);
+
+ if (g_list_find (priv->accounts, account))
+ return;
+
+ priv->accounts = g_list_prepend (priv->accounts,
+ g_object_ref (account));
+
+ if (!priv->querying)
+ tmc_logger_dumper_next_operation (dumper);
+}
diff --git a/src/logger-dumper.h b/src/logger-dumper.h
new file mode 100644
index 0000000..ff0a124
--- /dev/null
+++ b/src/logger-dumper.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 Carlos Garnacho
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg gnome org>
+ */
+
+#ifndef __TMC_LOGGER_DUMPER_H__
+#define __TMC_LOGGER_DUMPER_H__
+
+#include <glib-object.h>
+#include <telepathy-glib/telepathy-glib.h>
+
+#define TMC_TYPE_LOGGER_DUMPER (tmc_logger_dumper_get_type ())
+
+G_DECLARE_FINAL_TYPE (TmcLoggerDumper, tmc_logger_dumper, TMC, LOGGER_DUMPER, GObject)
+
+TmcLoggerDumper * tmc_logger_dumper_new (void);
+void tmc_logger_dumper_add_account (TmcLoggerDumper *dumper,
+ TpAccount *account);
+
+#endif /* __TMC_LOGGER_DUMPER_H__ */
diff --git a/src/miner.c b/src/miner.c
index 33d6cfc..bd6ca96 100644
--- a/src/miner.c
+++ b/src/miner.c
@@ -19,6 +19,8 @@
* Author: Carlos Garnacho <carlosg gnome org>
*/
+#include "config.h"
+
#include "client-factory.h"
#include "observer.h"
#include "text-event.h"
@@ -27,7 +29,13 @@
#include "conversation.h"
#include "miner.h"
+#ifdef HAVE_MIGRATION
+#include "logger-dumper.h"
+#endif
+
#define GRAPH_URN "urn:uuid:5f15c02c-bede-06c7-413f-7bae48712d3a"
+#define TRANSACTION_LIMIT 10000
+#define TP_MIGRATION_FILENAME "tracker-miner-chatlog.tp-migrated"
typedef struct _TmcMinerPrivate TmcMinerPrivate;
typedef struct _Transaction Transaction;
@@ -63,6 +71,10 @@ struct _TmcMinerPrivate {
TmcClientFactory *client_factory;
TmcObserver *observer;
+#ifdef HAVE_MIGRATION
+ TmcLoggerDumper *dumper;
+#endif
+
GHashTable *room_urn_cache;
GHashTable *contact_urn_cache;
@@ -105,6 +117,10 @@ tmc_miner_finalize (GObject *object)
g_object_unref (priv->client_factory);
g_object_unref (priv->dbus);
+#ifdef HAVE_MIGRATION
+ g_object_unref (priv->dumper);
+#endif
+
G_OBJECT_CLASS (tmc_miner_parent_class)->finalize (object);
}
@@ -596,10 +612,27 @@ idle_flush_cb (Transaction *transaction)
{
TmcMiner *miner = transaction->miner;
TmcMinerPrivate *priv = tmc_miner_get_instance_private (miner);
+ gint i;
+
+ g_debug ("Starting transaction, %ld elements remaining", priv->events->len);
+
+ if (priv->events->len < TRANSACTION_LIMIT) {
+ /* Transfer events to the transaction */
+ transaction->events = priv->events;
+ priv->events = NULL;
+ } else {
+ /* Make a partial copy */
+ transaction->events =
+ g_ptr_array_new_with_free_func (g_object_unref);
+
+ for (i = 0; i < TRANSACTION_LIMIT; i++) {
+ g_ptr_array_add (transaction->events,
+ g_object_ref (g_ptr_array_index (priv->events, i)));
+ }
+
+ g_ptr_array_remove_range (priv->events, 0, TRANSACTION_LIMIT);
+ }
- /* Transfer events to the transaction */
- transaction->events = priv->events;
- priv->events = NULL;
priv->flushing = TRUE;
priv->flush_idle_id = 0;
@@ -724,6 +757,18 @@ populate_contact_urn_cache (TmcMiner *miner,
return (*error) == NULL;
}
+#ifdef HAVE_MIGRATION
+static void
+observer_account_added (TmcMiner *miner,
+ TpAccount *account,
+ TmcObserver *observer)
+{
+ TmcMinerPrivate *priv = tmc_miner_get_instance_private (miner);
+
+ tmc_logger_dumper_add_account (priv->dumper, account);
+}
+#endif
+
static gboolean
tmc_miner_initable_init (GInitable *initable,
GCancellable *cancellable,
@@ -732,6 +777,9 @@ tmc_miner_initable_init (GInitable *initable,
TmcMiner *miner = TMC_MINER (initable);
TmcMinerPrivate *priv = tmc_miner_get_instance_private (miner);
GInitableIface *parent_iface;
+#ifdef HAVE_MIGRATION
+ gchar *filename;
+#endif
parent_iface = g_type_interface_peek_parent (G_INITABLE_GET_IFACE (initable));
@@ -748,6 +796,23 @@ tmc_miner_initable_init (GInitable *initable,
g_signal_connect_swapped (priv->observer, "text-event",
G_CALLBACK (handle_text_event), miner);
+#ifdef HAVE_MIGRATION
+ filename = g_build_filename (g_get_user_cache_dir (), "tracker",
+ "tracker-miner-chatlog.tp-migration", NULL);
+
+ if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
+ priv->dumper = tmc_logger_dumper_new ();
+ g_signal_connect_swapped (priv->dumper, "text-event",
+ G_CALLBACK (handle_text_event), miner);
+ g_signal_connect_swapped (priv->observer, "account",
+ G_CALLBACK (observer_account_added), miner);
+
+ g_file_set_contents (filename, "", -1, NULL);
+ }
+
+ g_free (filename);
+#endif
+
if (!tp_base_client_register (TP_BASE_CLIENT (priv->observer), error))
return FALSE;
diff --git a/src/observer.c b/src/observer.c
index b1690d4..e8542f0 100644
--- a/src/observer.c
+++ b/src/observer.c
@@ -34,9 +34,11 @@ typedef struct _TmcObserverPrivate TmcObserverPrivate;
struct _TmcObserverPrivate {
GList *channels;
GRegex *recipients_regex;
+ GList *accounts;
};
enum {
+ ACCOUNT,
TEXT_EVENT,
N_SIGNALS
};
@@ -55,6 +57,9 @@ tmc_observer_finalize (GObject *object)
g_list_free (priv->channels);
g_regex_unref (priv->recipients_regex);
+ g_list_foreach (priv->accounts, (GFunc) g_object_unref, NULL);
+ g_list_free (priv->accounts);
+
G_OBJECT_CLASS (tmc_observer_parent_class)->finalize (object);
}
@@ -221,6 +226,20 @@ register_channel (TmcObserver *observer,
}
static void
+tmc_observer_manage_account (TmcObserver *observer,
+ TpAccount *account)
+{
+ TmcObserverPrivate *priv = tmc_observer_get_instance_private (observer);
+
+ if (g_list_find (priv->accounts, account))
+ return;
+
+ priv->accounts = g_list_prepend (priv->accounts,
+ g_object_ref (account));
+ g_signal_emit (observer, signals[ACCOUNT], 0, account);
+}
+
+static void
tmc_observer_observe_channels (TpBaseClient *client,
TpAccount *account,
TpConnection *connection,
@@ -232,6 +251,8 @@ tmc_observer_observe_channels (TpBaseClient *client,
TmcObserver *self = TMC_OBSERVER (client);
GList *l;
+ tmc_observer_manage_account (self, account);
+
for (l = channels; l != NULL; l = l->next)
register_channel (self, l->data);
@@ -257,6 +278,13 @@ tmc_observer_class_init (TmcObserverClass *klass)
0, NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, TMC_TYPE_TEXT_EVENT);
+ signals[ACCOUNT] =
+ g_signal_new ("account",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, TP_TYPE_ACCOUNT);
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]