source: trunk/gtk/notify.c @ 13107

Last change on this file since 13107 was 13107, checked in by jordan, 10 years ago

(trunk libT) #4372 "make notification and system sounds configurable" -- instead of using notify-send, use GDBus on the org.freedesktop.Notifications API. Patch by fmuellner.

  • Property svn:keywords set to Date Rev Author Id
File size: 7.6 KB
Line 
1/*
2 * This file Copyright (C) Mnemosyne LLC
3 *
4 * This file is licensed by the GPL version 2. Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: notify.c 13107 2011-12-10 19:00:50Z jordan $
11 */
12
13#include <string.h> /* strcmp() */
14
15#include <gio/gio.h>
16
17#include <glib/gi18n.h>
18#include "conf.h"
19#include "notify.h"
20#include "tr-prefs.h"
21#include "util.h"
22
23#define NOTIFICATIONS_DBUS_NAME           "org.freedesktop.Notifications"
24#define NOTIFICATIONS_DBUS_CORE_OBJECT    "/org/freedesktop/Notifications"
25#define NOTIFICATIONS_DBUS_CORE_INTERFACE "org.freedesktop.Notifications"
26
27static GDBusProxy *proxy = NULL;
28static GHashTable *active_notifications = NULL;
29static gboolean server_supports_actions = FALSE;
30
31typedef struct _TrNotification
32{
33    guint    id;
34    TrCore * core;
35    int      torrent_id;
36} TrNotification;
37
38static void
39tr_notification_free( gpointer data )
40{
41    TrNotification * n = data;
42    if( n->core )
43        g_object_unref( G_OBJECT( n->core ) );
44    g_free( n );
45}
46
47static void
48get_capabilities_callback( GObject      * source,
49                           GAsyncResult * res,
50                           gpointer       user_data UNUSED )
51{
52    GVariant  *result;
53    char     **caps;
54    int        i;
55
56    result = g_dbus_proxy_call_finish( G_DBUS_PROXY( source ), res, NULL );
57    if( !result || !g_variant_is_of_type( result, G_VARIANT_TYPE( "(as)" ) ) )
58    {
59        if( result )
60            g_variant_unref( result );
61        return;
62    }
63
64    g_variant_get( result, "(^a&s)", &caps );
65    for( i = 0; caps[i]; i++ )
66    {
67        if( strcmp( caps[i], "actions" ) == 0 )
68        {
69            server_supports_actions = TRUE;
70            break;
71        }
72    }
73    g_free( caps );
74    g_variant_unref( result );
75}
76
77static void
78g_signal_callback( GDBusProxy * proxy UNUSED,
79                   char       * sender_name UNUSED,
80                   char       * signal_name,
81                   GVariant   * params,
82                   gpointer     user_data UNUSED )
83{
84    TrNotification * n;
85    guint id;
86
87    g_return_if_fail( g_variant_is_of_type( params, G_VARIANT_TYPE( "(u*)" ) ) );
88
89    g_variant_get( params, "(u*)", &id, NULL );
90    n = g_hash_table_lookup( active_notifications,
91                             GINT_TO_POINTER( (int *) &id ) );
92    if( n == NULL )
93        return;
94
95    if( strcmp( signal_name, "NotificationClosed" ) == 0 )
96    {
97        g_hash_table_remove( active_notifications,
98                             GINT_TO_POINTER( (int *) &n->id ) );
99    }
100    else if( strcmp( signal_name, "ActionInvoked" ) == 0 &&
101             g_variant_is_of_type( params, G_VARIANT_TYPE( "(us)" ) ) )
102    {
103        char * action;
104        tr_torrent * tor;
105
106        tor = gtr_core_find_torrent( n->core, n->torrent_id );
107        if( tor == NULL )
108            return;
109
110        g_variant_get( params, "(u&s)", NULL, &action );
111        if( strcmp( action, "folder" ) == 0 )
112        {
113            gtr_core_open_folder( n->core, n->torrent_id );
114        }
115        else if( strcmp( action, "file" ) == 0)
116        {
117            const tr_info * inf = tr_torrentInfo( tor );
118            const char * dir = tr_torrentGetDownloadDir( tor );
119            char * path = g_build_filename( dir, inf->files[0].name, NULL );
120            gtr_open_file( path );
121            g_free( path );
122        }
123    }
124}
125
126static void
127dbus_proxy_ready_callback( GObject      * source UNUSED,
128                           GAsyncResult * res,
129                           gpointer       user_data UNUSED )
130{
131    proxy = g_dbus_proxy_new_for_bus_finish( res, NULL );
132    if( proxy == NULL )
133    {
134        g_warning( "Failed to create proxy for %s", NOTIFICATIONS_DBUS_NAME );
135        return;
136    }
137
138    g_signal_connect( proxy, "g-signal",
139                      G_CALLBACK( g_signal_callback ), NULL );
140    g_dbus_proxy_call( proxy,
141                       "GetCapabilities",
142                       g_variant_new( "()" ),
143                       G_DBUS_CALL_FLAGS_NONE, -1, NULL,
144                       get_capabilities_callback, NULL );
145}
146
147void
148gtr_notify_init( void )
149{
150    active_notifications = g_hash_table_new_full( g_int_hash, g_int_equal,
151                                                  NULL, tr_notification_free );
152    g_dbus_proxy_new_for_bus( G_BUS_TYPE_SESSION,
153                              G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
154                              NULL,
155                              NOTIFICATIONS_DBUS_NAME,
156                              NOTIFICATIONS_DBUS_CORE_OBJECT,
157                              NOTIFICATIONS_DBUS_CORE_INTERFACE,
158                              NULL, dbus_proxy_ready_callback, NULL );
159}
160
161static void
162notify_callback( GObject      * source,
163                 GAsyncResult * res,
164                 gpointer       user_data )
165{
166    TrNotification * n = user_data;
167    GVariant * result;
168
169    result = g_dbus_proxy_call_finish( G_DBUS_PROXY( source ), res, NULL );
170    if( !result || !g_variant_is_of_type( result, G_VARIANT_TYPE( "(u)" ) ) )
171    {
172        if( result )
173            g_variant_unref( result );
174        tr_notification_free( n );
175        return;
176    }
177
178    g_variant_get( result, "(u)", &n->id );
179    g_hash_table_insert( active_notifications,
180                         GINT_TO_POINTER( ( int * )&n->id ), n );
181
182    g_variant_unref( result );
183}
184
185void
186gtr_notify_torrent_completed( TrCore * core, int torrent_id )
187{
188    GVariantBuilder actions_builder;
189    TrNotification * n;
190    tr_torrent * tor;
191    const char * cmd = gtr_pref_string_get( PREF_KEY_TORRENT_COMPLETE_SOUND_COMMAND );
192    g_spawn_command_line_async( cmd, NULL );
193
194    if( ! gtr_pref_flag_get( PREF_KEY_TORRENT_COMPLETE_NOTIFICATION_ENABLED ) )
195        return;
196
197    g_return_if_fail( G_IS_DBUS_PROXY( proxy ) );
198
199    tor = gtr_core_find_torrent( core, torrent_id );
200
201    n = g_new0( TrNotification, 1 );
202    n->core = g_object_ref( G_OBJECT( core ) );
203    n->torrent_id = torrent_id;
204
205    g_variant_builder_init( &actions_builder, G_VARIANT_TYPE( "as" ) );
206
207    if( server_supports_actions )
208    {
209        const tr_info * inf = tr_torrentInfo( tor );
210        if( inf->fileCount == 1 )
211        {
212            g_variant_builder_add( &actions_builder, "s", "file" );
213            g_variant_builder_add( &actions_builder, "s", _( "Open File" ) );
214        }
215        else
216        {
217            g_variant_builder_add( &actions_builder, "s", "folder" );
218            g_variant_builder_add( &actions_builder, "s", _( "Open Folder" ) );
219        }
220    }
221
222    g_dbus_proxy_call( proxy,
223                       "Notify",
224                       g_variant_new( "(susssasa{sv}i)",
225                                      "Transmission", n->id, "transmission",
226                                      _( "Torrent Complete" ),
227                                      tr_torrentName( tor ),
228                                      &actions_builder, NULL, -1 ),
229                       G_DBUS_CALL_FLAGS_NONE, -1, NULL,
230                       notify_callback, n );
231}
232
233void
234gtr_notify_torrent_added( const char * name )
235{
236    TrNotification * n;
237
238    g_return_if_fail( G_IS_DBUS_PROXY( proxy ) );
239
240    if( !gtr_pref_flag_get( PREF_KEY_TORRENT_ADDED_NOTIFICATION_ENABLED ) )
241        return;
242
243    n = g_new0( TrNotification, 1 );
244    g_dbus_proxy_call( proxy,
245                       "Notify",
246                       g_variant_new( "(susssasa{sv}i)",
247                                      "Transmission", 0, "transmission",
248                                      _( "Torrent Added" ), name,
249                                      NULL, NULL, -1 ),
250                       G_DBUS_CALL_FLAGS_NONE, -1, NULL,
251                       notify_callback, n );
252}
Note: See TracBrowser for help on using the repository browser.