diff --git a/mms-transfer-list-dbus/src/mms_transfer_list_dbus.c b/mms-transfer-list-dbus/src/mms_transfer_list_dbus.c index b2f6640..e234e54 100644 --- a/mms-transfer-list-dbus/src/mms_transfer_list_dbus.c +++ b/mms-transfer-list-dbus/src/mms_transfer_list_dbus.c @@ -22,14 +22,20 @@ /* Generated code */ #include "org.nemomobile.MmsEngine.TransferList.h" +/* D-Bus interface */ +#define MMS_TRANSFER_LIST_INTERFACE "org.nemomobile.MmsEngine.TransferList" +#define MMS_TRANSFER_LIST_SIGNAL_TRANSFER_STARTED "TransferStarted" +#define MMS_TRANSFER_LIST_SIGNAL_TRANSFER_FINISHED "TransferFinished" + /* Class definition */ typedef MMSTransferListClass MMSTransferListDbusClass; struct mms_transfer_list_dbus { MMSTransferList super; GDBusConnection* bus; - OrgNemomobileMmsEngineTransferList* proxy; + OrgNemomobileMmsEngineTransferList* skeleton; gulong list_transfers_id; GHashTable* transfers; + GHashTable* clients; }; G_DEFINE_TYPE(MMSTransferListDbus, mms_transfer_list_dbus, \ @@ -41,6 +47,45 @@ G_DEFINE_TYPE(MMSTransferListDbus, mms_transfer_list_dbus, \ #define MMS_TRANSFER_LIST_DBUS_PATH "/" #define MMS_TRANSFER_LIST_DBUS_BUS G_BUS_TYPE_SYSTEM +/* + * Sends signals only to registered clients. That's not much of an overhead + * because there's usually no more than one client (i.e. Messages app). + */ +static +void +mms_transfer_dbus_list_emit_signal( + MMSTransferListDbus* self, + const char* signal, + const char* path) +{ + if (self->clients) { + gpointer key; + GHashTableIter it; + GVariant* arg = g_variant_ref_sink(g_variant_new("(o)", path)); + + g_hash_table_iter_init(&it, self->clients); + while (g_hash_table_iter_next(&it, &key, NULL)) { + const char* dest = key; + GError* error = NULL; + GDBusMessage* message = g_dbus_message_new_signal( + g_dbus_interface_skeleton_get_object_path + (G_DBUS_INTERFACE_SKELETON(self->skeleton)), + MMS_TRANSFER_LIST_INTERFACE, signal); + + g_dbus_message_set_body(message, arg); + g_dbus_message_set_destination(message, dest); + g_dbus_connection_send_message(self->bus, message, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &error); + g_object_unref(message); + if (error) { + GERR("%s => %s failed: %s", signal, dest, error->message); + g_error_free(error); + } + } + g_variant_unref(arg); + } +} + static guint mms_transfer_key_hash_cb( @@ -50,6 +95,7 @@ mms_transfer_key_hash_cb( /* There's shouldn't be more than one transfer per message at * any time, it's enough to just hash the message id */ const MMSTransferKey* key = data; + return g_str_hash(key->id); } else { return 0; @@ -69,6 +115,7 @@ mms_transfer_key_equal_cb( } else { const MMSTransferKey* key1 = a; const MMSTransferKey* key2 = a; + return !g_strcmp0(key1->id, key2->id) && !g_strcmp0(key1->type, key2->type); } @@ -80,11 +127,12 @@ mms_transfer_destroy_cb( gpointer data) { MMSTransferDbus* transfer = MMS_TRANSFER_DBUS(data); - MMSTransferListDbus* list = MMS_TRANSFER_LIST_DBUS(transfer->list); + MMSTransferListDbus* self = MMS_TRANSFER_LIST_DBUS(transfer->list); + GDEBUG("Transfer %s finished", transfer->path); mms_transfer_dbus_finished(transfer); - org_nemomobile_mms_engine_transfer_list_emit_transfer_finished(list->proxy, - transfer->path); + mms_transfer_dbus_list_emit_signal(self, + MMS_TRANSFER_LIST_SIGNAL_TRANSFER_FINISHED, transfer->path); transfer->list = NULL; g_object_unref(transfer); } @@ -97,11 +145,12 @@ mms_transfer_list_dbus_bus_cb( gpointer user_data) { MMSTransferListDbus* self = MMS_TRANSFER_LIST_DBUS(user_data); + self->bus = g_bus_get_finish(res, NULL); if (self->bus) { GError* error = NULL; if (!g_dbus_interface_skeleton_export( - G_DBUS_INTERFACE_SKELETON(self->proxy), self->bus, + G_DBUS_INTERFACE_SKELETON(self->skeleton), self->bus, MMS_TRANSFER_LIST_DBUS_PATH, &error)) { GERR("%s", GERRMSG(error)); g_error_free(error); @@ -114,6 +163,7 @@ MMSTransferList* mms_transfer_list_dbus_new() { MMSTransferListDbus* self = g_object_new(MMS_TYPE_TRANSFER_LIST_DBUS, 0); + g_bus_get(MMS_TRANSFER_LIST_DBUS_BUS, NULL, mms_transfer_list_dbus_bus_cb, g_object_ref(self)); return &self->super; @@ -128,11 +178,12 @@ mms_transfer_list_dbus_transfer_started( { MMSTransferListDbus* self = MMS_TRANSFER_LIST_DBUS(list); MMSTransferDbus* transfer = mms_transfer_dbus_new(self->bus, id, type); + GDEBUG("Transfer %s started", transfer->path); transfer->list = self; g_hash_table_replace(self->transfers, &transfer->key, transfer); - org_nemomobile_mms_engine_transfer_list_emit_transfer_started(self->proxy, - transfer->path); + mms_transfer_dbus_list_emit_signal(self, + MMS_TRANSFER_LIST_SIGNAL_TRANSFER_STARTED, transfer->path); } static @@ -144,6 +195,7 @@ mms_transfer_list_dbus_transfer_finished( { MMSTransferListDbus* self = MMS_TRANSFER_LIST_DBUS(list); MMSTransferKey key; + key.id = id; key.type = type; if (!g_hash_table_remove(self->transfers, &key)) { @@ -160,6 +212,7 @@ mms_transfer_list_dbus_find( { MMSTransferDbus* transfer; MMSTransferKey key; + key.id = id; key.type = type; transfer = g_hash_table_lookup(self->transfers, &key); @@ -182,6 +235,7 @@ mms_transfer_list_dbus_send_progress( { MMSTransferListDbus* self = MMS_TRANSFER_LIST_DBUS(list); MMSTransferDbus* transfer = mms_transfer_list_dbus_find(self, id, type); + if (transfer) { mms_transfer_dbus_send_progress(transfer, sent, total); } @@ -198,27 +252,63 @@ mms_transfer_list_dbus_receive_progress( { MMSTransferListDbus* self = MMS_TRANSFER_LIST_DBUS(list); MMSTransferDbus* transfer = mms_transfer_list_dbus_find(self, id, type); + if (transfer) { mms_transfer_dbus_receive_progress(transfer, received, total); } } +static +void +mms_transfer_list_dbus_client_vanished( + GDBusConnection* bus, + const gchar* name, + gpointer user_data) +{ + MMSTransferListDbus* self = MMS_TRANSFER_LIST_DBUS(user_data); + + GDEBUG("Client '%s' has disappeared", name); + g_hash_table_remove(self->clients, name); + if (!g_hash_table_size(self->clients)) { + g_hash_table_destroy(self->clients); + self->clients = NULL; + } +} + /* org.nemomobile.MmsEngine.TransferList.Get */ static gboolean mms_transfer_list_dbus_handle_get( - OrgNemomobileMmsEngineTransferList* proxy, + OrgNemomobileMmsEngineTransferList* skeleton, GDBusMethodInvocation* call, MMSTransferListDbus* self) { + const char* sender = g_dbus_method_invocation_get_sender(call); const char* null = NULL; - const gchar *const *list = &null; - const gchar **paths = NULL; + const gchar* const* list = &null; + const gchar** paths = NULL; guint n = g_hash_table_size(self->transfers); + + /* Store the sender's name */ + if (!self->clients) { + self->clients = /* sender => watch id */ + g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + } + if (!g_hash_table_contains(self->clients, sender)) { + /* New client */ + gulong watch_id = g_bus_watch_name_on_connection(self->bus, + sender, G_BUS_NAME_WATCHER_FLAGS_NONE, NULL, + mms_transfer_list_dbus_client_vanished, self, NULL); + + g_hash_table_insert(self->clients, g_strdup(sender), + GUINT_TO_POINTER(watch_id)); + } + if (n) { guint i = 0; gpointer value; GHashTableIter it; + g_hash_table_iter_init(&it, self->transfers); paths = g_new(const char*, n+1); GVERBOSE("%u transfer(s)", n); @@ -233,47 +323,31 @@ mms_transfer_list_dbus_handle_get( GVERBOSE("No transfers"); list = &null; } - org_nemomobile_mms_engine_transfer_list_complete_get(proxy, call, list); + org_nemomobile_mms_engine_transfer_list_complete_get(skeleton, call, list); g_free(paths); return TRUE; } /** - * First stage of deinitialization (release all references). - * May be called more than once in the lifetime of the object. + * Final stage of deinitialization */ static void -mms_transfer_list_dbus_dispose( +mms_transfer_list_dbus_finalize( GObject* object) { MMSTransferListDbus* self = MMS_TRANSFER_LIST_DBUS(object); - g_hash_table_remove_all(self->transfers); - if (self->proxy) { - g_dbus_interface_skeleton_unexport( - G_DBUS_INTERFACE_SKELETON(self->proxy)); - g_signal_handler_disconnect(self->proxy, self->list_transfers_id); - g_object_unref(self->proxy); - self->list_transfers_id = 0; - self->proxy = NULL; + + g_dbus_interface_skeleton_unexport(G_DBUS_INTERFACE_SKELETON(self->skeleton)); + g_signal_handler_disconnect(self->skeleton, self->list_transfers_id); + g_object_unref(self->skeleton); + g_hash_table_destroy(self->transfers); + if (self->clients) { + g_hash_table_destroy(self->clients); } if (self->bus) { g_object_unref(self->bus); - self->bus = NULL; } - G_OBJECT_CLASS(mms_transfer_list_dbus_parent_class)->dispose(object); -} - -/** - * Final stage of deinitialization - */ -static -void -mms_transfer_list_dbus_finalize( - GObject* object) -{ - MMSTransferListDbus* self = MMS_TRANSFER_LIST_DBUS(object); - g_hash_table_destroy(self->transfers); G_OBJECT_CLASS(mms_transfer_list_dbus_parent_class)->finalize(object); } @@ -285,8 +359,8 @@ void mms_transfer_list_dbus_init( MMSTransferListDbus* self) { - self->proxy = org_nemomobile_mms_engine_transfer_list_skeleton_new(); - self->list_transfers_id = g_signal_connect(self->proxy, "handle-get", + self->skeleton = org_nemomobile_mms_engine_transfer_list_skeleton_new(); + self->list_transfers_id = g_signal_connect(self->skeleton, "handle-get", G_CALLBACK(mms_transfer_list_dbus_handle_get), self); self->transfers = g_hash_table_new_full(mms_transfer_key_hash_cb, mms_transfer_key_equal_cb, NULL, mms_transfer_destroy_cb); @@ -300,13 +374,11 @@ void mms_transfer_list_dbus_class_init( MMSTransferListDbusClass* klass) { - GObjectClass* object_class = G_OBJECT_CLASS(klass); klass->fn_transfer_started = mms_transfer_list_dbus_transfer_started; klass->fn_transfer_finished = mms_transfer_list_dbus_transfer_finished; klass->fn_send_progress = mms_transfer_list_dbus_send_progress; klass->fn_receive_progress = mms_transfer_list_dbus_receive_progress; - object_class->dispose = mms_transfer_list_dbus_dispose; - object_class->finalize = mms_transfer_list_dbus_finalize; + G_OBJECT_CLASS(klass)->finalize = mms_transfer_list_dbus_finalize; } /*