transmission/gtk/notify.c

239 lines
6.5 KiB
C

/*
* This file Copyright (C) 2008-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include <gio/gio.h>
#include <glib/gi18n.h>
#include "conf.h"
#include "notify.h"
#include "tr-prefs.h"
#include "util.h"
#define NOTIFICATIONS_DBUS_NAME "org.freedesktop.Notifications"
#define NOTIFICATIONS_DBUS_CORE_OBJECT "/org/freedesktop/Notifications"
#define NOTIFICATIONS_DBUS_CORE_INTERFACE "org.freedesktop.Notifications"
static GDBusProxy* proxy = NULL;
static GHashTable* active_notifications = NULL;
static gboolean server_supports_actions = FALSE;
typedef struct TrNotification
{
guint id;
TrCore* core;
int torrent_id;
}
TrNotification;
static void tr_notification_free(gpointer data)
{
TrNotification* n = data;
if (n->core != NULL)
{
g_object_unref(G_OBJECT(n->core));
}
g_free(n);
}
static void get_capabilities_callback(GObject* source, GAsyncResult* res, gpointer user_data UNUSED)
{
char** caps;
GVariant* result;
result = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, NULL);
if (result == NULL || !g_variant_is_of_type(result, G_VARIANT_TYPE("(as)")))
{
if (result != NULL)
{
g_variant_unref(result);
}
return;
}
g_variant_get(result, "(^a&s)", &caps);
for (int i = 0; caps[i] != NULL; i++)
{
if (g_strcmp0(caps[i], "actions") == 0)
{
server_supports_actions = TRUE;
break;
}
}
g_free(caps);
g_variant_unref(result);
}
static void g_signal_callback(GDBusProxy* dbus_proxy UNUSED, char* sender_name UNUSED, char* signal_name, GVariant* params,
gpointer user_data UNUSED)
{
guint id;
TrNotification* n;
g_return_if_fail(g_variant_is_of_type(params, G_VARIANT_TYPE("(u*)")));
g_variant_get(params, "(u*)", &id, NULL);
n = g_hash_table_lookup(active_notifications, GINT_TO_POINTER((int*)&id));
if (n == NULL)
{
return;
}
if (g_strcmp0(signal_name, "NotificationClosed") == 0)
{
g_hash_table_remove(active_notifications, GINT_TO_POINTER((int*)&n->id));
}
else if (g_strcmp0(signal_name, "ActionInvoked") == 0 && g_variant_is_of_type(params, G_VARIANT_TYPE("(us)")))
{
char* action;
tr_torrent* tor;
tor = gtr_core_find_torrent(n->core, n->torrent_id);
if (tor == NULL)
{
return;
}
g_variant_get(params, "(u&s)", NULL, &action);
if (g_strcmp0(action, "folder") == 0)
{
gtr_core_open_folder(n->core, n->torrent_id);
}
else if (g_strcmp0(action, "file") == 0)
{
tr_info const* inf = tr_torrentInfo(tor);
char const* dir = tr_torrentGetDownloadDir(tor);
char* path = g_build_filename(dir, inf->files[0].name, NULL);
gtr_open_file(path);
g_free(path);
}
}
}
static void dbus_proxy_ready_callback(GObject* source UNUSED, GAsyncResult* res, gpointer user_data UNUSED)
{
proxy = g_dbus_proxy_new_for_bus_finish(res, NULL);
if (proxy == NULL)
{
g_warning("Failed to create proxy for %s", NOTIFICATIONS_DBUS_NAME);
return;
}
g_signal_connect(proxy, "g-signal", G_CALLBACK(g_signal_callback), NULL);
g_dbus_proxy_call(proxy, "GetCapabilities", g_variant_new("()"), G_DBUS_CALL_FLAGS_NONE, -1, NULL,
get_capabilities_callback, NULL);
}
void gtr_notify_init(void)
{
active_notifications = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, tr_notification_free);
g_dbus_proxy_new_for_bus(G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, NOTIFICATIONS_DBUS_NAME,
NOTIFICATIONS_DBUS_CORE_OBJECT, NOTIFICATIONS_DBUS_CORE_INTERFACE, NULL, dbus_proxy_ready_callback, NULL);
}
static void notify_callback(GObject* source, GAsyncResult* res, gpointer user_data)
{
GVariant* result;
TrNotification* n = user_data;
result = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, NULL);
if (result == NULL || !g_variant_is_of_type(result, G_VARIANT_TYPE("(u)")))
{
if (result != NULL)
{
g_variant_unref(result);
}
tr_notification_free(n);
return;
}
g_variant_get(result, "(u)", &n->id);
g_hash_table_insert(active_notifications, GINT_TO_POINTER((int*)&n->id), n);
g_variant_unref(result);
}
void gtr_notify_torrent_completed(TrCore* core, int torrent_id)
{
TrNotification* n;
tr_torrent* tor;
char const* cmd = gtr_pref_string_get(TR_KEY_torrent_complete_sound_command);
if (gtr_pref_flag_get(TR_KEY_torrent_complete_sound_enabled))
{
g_spawn_command_line_async(cmd, NULL);
}
if (!gtr_pref_flag_get(TR_KEY_torrent_complete_notification_enabled))
{
return;
}
g_return_if_fail(G_IS_DBUS_PROXY(proxy));
tor = gtr_core_find_torrent(core, torrent_id);
n = g_new0(TrNotification, 1);
g_object_ref(G_OBJECT(core));
n->core = core;
n->torrent_id = torrent_id;
GVariantBuilder actions_builder;
g_variant_builder_init(&actions_builder, G_VARIANT_TYPE("as"));
if (server_supports_actions)
{
tr_info const* inf = tr_torrentInfo(tor);
if (inf->fileCount == 1)
{
g_variant_builder_add(&actions_builder, "s", "file");
g_variant_builder_add(&actions_builder, "s", _("Open File"));
}
else
{
g_variant_builder_add(&actions_builder, "s", "folder");
g_variant_builder_add(&actions_builder, "s", _("Open Folder"));
}
}
GVariantBuilder hints_builder;
g_variant_builder_init(&hints_builder, G_VARIANT_TYPE("a{sv}"));
g_variant_builder_add(&hints_builder, "{sv}", "category", g_variant_new_string("transfer.complete"));
g_dbus_proxy_call(proxy, "Notify", g_variant_new("(susssasa{sv}i)", "Transmission", n->id, "transmission",
_("Torrent Complete"), tr_torrentName(tor), &actions_builder, &hints_builder, -1), G_DBUS_CALL_FLAGS_NONE, -1, NULL,
notify_callback, n);
}
void gtr_notify_torrent_added(char const* name)
{
TrNotification* n;
g_return_if_fail(G_IS_DBUS_PROXY(proxy));
if (!gtr_pref_flag_get(TR_KEY_torrent_added_notification_enabled))
{
return;
}
n = g_new0(TrNotification, 1);
g_dbus_proxy_call(proxy, "Notify", g_variant_new("(susssasa{sv}i)", "Transmission", 0, "transmission", _("Torrent Added"),
name, NULL, NULL, -1), G_DBUS_CALL_FLAGS_NONE, -1, NULL, notify_callback, n);
}