1
/* vi:set et ai sw=2 sts=2 ts=2: */
3
* Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License as
7
* published by the Free Software Foundation; either version 2 of
8
* the License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public
16
* License along with this program; if not, write to the Free
17
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18
* Boston, MA 02110-1301, USA.
26
#include <glib/gi18n.h>
27
#include <glib-object.h>
29
#include <dbus/dbus.h>
30
#include <dbus/dbus-glib.h>
31
#include <dbus/dbus-glib-lowlevel.h>
33
#include <tumbler/tumbler.h>
35
#include <tumblerd/tumbler-cache-service.h>
36
#include <tumblerd/tumbler-cache-service-dbus-bindings.h>
37
#include <tumblerd/tumbler-utils.h>
41
typedef struct _MoveRequest MoveRequest;
42
typedef struct _CopyRequest CopyRequest;
43
typedef struct _DeleteRequest DeleteRequest;
44
typedef struct _CleanupRequest CleanupRequest;
48
/* Property identifiers */
57
static void tumbler_cache_service_constructed (GObject *object);
58
static void tumbler_cache_service_finalize (GObject *object);
59
static void tumbler_cache_service_get_property (GObject *object,
63
static void tumbler_cache_service_set_property (GObject *object,
67
static void tumbler_cache_service_move_thread (gpointer data,
69
static void tumbler_cache_service_copy_thread (gpointer data,
71
static void tumbler_cache_service_delete_thread (gpointer data,
73
static void tumbler_cache_service_cleanup_thread (gpointer data,
78
struct _TumblerCacheServiceClass
80
GObjectClass __parent__;
83
struct _TumblerCacheService
87
DBusGConnection *connection;
91
GThreadPool *move_pool;
92
GThreadPool *copy_pool;
93
GThreadPool *delete_pool;
94
GThreadPool *cleanup_pool;
111
struct _DeleteRequest
116
struct _CleanupRequest
124
G_DEFINE_TYPE (TumblerCacheService, tumbler_cache_service, G_TYPE_OBJECT);
129
tumbler_cache_service_class_init (TumblerCacheServiceClass *klass)
131
GObjectClass *gobject_class;
133
gobject_class = G_OBJECT_CLASS (klass);
134
gobject_class->constructed = tumbler_cache_service_constructed;
135
gobject_class->finalize = tumbler_cache_service_finalize;
136
gobject_class->get_property = tumbler_cache_service_get_property;
137
gobject_class->set_property = tumbler_cache_service_set_property;
139
g_object_class_install_property (gobject_class, PROP_CONNECTION,
140
g_param_spec_pointer ("connection",
144
G_PARAM_CONSTRUCT_ONLY));
150
tumbler_cache_service_init (TumblerCacheService *service)
152
service->mutex = g_mutex_new ();
158
tumbler_cache_service_constructed (GObject *object)
160
TumblerCacheService *service = TUMBLER_CACHE_SERVICE (object);
162
/* chain up to parent classes */
163
if (G_OBJECT_CLASS (tumbler_cache_service_parent_class)->constructed != NULL)
164
(G_OBJECT_CLASS (tumbler_cache_service_parent_class)->constructed) (object);
166
service->cache = tumbler_cache_get_default ();
168
service->move_pool = g_thread_pool_new (tumbler_cache_service_move_thread,
169
service, 1, FALSE, NULL);
170
service->copy_pool = g_thread_pool_new (tumbler_cache_service_copy_thread,
171
service, 1, FALSE, NULL);
172
service->delete_pool = g_thread_pool_new (tumbler_cache_service_delete_thread,
173
service, 1, FALSE, NULL);
174
service->cleanup_pool = g_thread_pool_new (tumbler_cache_service_cleanup_thread,
175
service, 1, FALSE, NULL);
181
tumbler_cache_service_finalize (GObject *object)
183
TumblerCacheService *service = TUMBLER_CACHE_SERVICE (object);
185
g_thread_pool_free (service->move_pool, TRUE, TRUE);
186
g_thread_pool_free (service->copy_pool, TRUE, TRUE);
187
g_thread_pool_free (service->delete_pool, TRUE, TRUE);
188
g_thread_pool_free (service->cleanup_pool, TRUE, TRUE);
190
if (service->cache != NULL)
191
g_object_unref (service->cache);
193
dbus_g_connection_unref (service->connection);
195
g_mutex_free (service->mutex);
197
(*G_OBJECT_CLASS (tumbler_cache_service_parent_class)->finalize) (object);
203
tumbler_cache_service_get_property (GObject *object,
208
TumblerCacheService *service = TUMBLER_CACHE_SERVICE (object);
212
case PROP_CONNECTION:
213
g_value_set_pointer (value, service->connection);
216
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
224
tumbler_cache_service_set_property (GObject *object,
229
TumblerCacheService *service = TUMBLER_CACHE_SERVICE (object);
233
case PROP_CONNECTION:
234
service->connection = dbus_g_connection_ref (g_value_get_pointer (value));
237
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
245
tumbler_cache_service_move_thread (gpointer data,
248
TumblerCacheService *service = TUMBLER_CACHE_SERVICE (user_data);
249
MoveRequest *request = data;
251
g_return_if_fail (TUMBLER_IS_CACHE_SERVICE (service));
252
g_return_if_fail (request != NULL);
254
g_mutex_lock (service->mutex);
256
if (service->cache != NULL)
257
tumbler_cache_move (service->cache, request->from_uris, request->to_uris);
259
g_strfreev (request->from_uris);
260
g_strfreev (request->to_uris);
261
g_slice_free (MoveRequest, request);
263
g_mutex_unlock (service->mutex);
269
tumbler_cache_service_copy_thread (gpointer data,
272
TumblerCacheService *service = TUMBLER_CACHE_SERVICE (user_data);
273
CopyRequest *request = data;
275
g_return_if_fail (TUMBLER_IS_CACHE_SERVICE (service));
276
g_return_if_fail (request != NULL);
278
g_mutex_lock (service->mutex);
280
if (service->cache != NULL)
281
tumbler_cache_copy (service->cache, request->from_uris, request->to_uris);
283
g_strfreev (request->from_uris);
284
g_strfreev (request->to_uris);
285
g_slice_free (CopyRequest, request);
287
g_mutex_unlock (service->mutex);
293
tumbler_cache_service_delete_thread (gpointer data,
296
TumblerCacheService *service = TUMBLER_CACHE_SERVICE (user_data);
297
DeleteRequest *request = data;
299
g_return_if_fail (TUMBLER_IS_CACHE_SERVICE (service));
300
g_return_if_fail (request != NULL);
302
g_mutex_lock (service->mutex);
304
if (service->cache != NULL)
305
tumbler_cache_delete (service->cache, request->uris);
307
g_strfreev (request->uris);
308
g_slice_free (DeleteRequest, request);
310
g_mutex_unlock (service->mutex);
316
tumbler_cache_service_cleanup_thread (gpointer data,
319
TumblerCacheService *service = TUMBLER_CACHE_SERVICE (user_data);
320
CleanupRequest *request = data;
322
g_return_if_fail (TUMBLER_IS_CACHE_SERVICE (service));
323
g_return_if_fail (request != NULL);
325
g_mutex_lock (service->mutex);
327
if (service->cache != NULL)
328
tumbler_cache_cleanup (service->cache, request->uri_prefix, request->since);
330
g_free (request->uri_prefix);
331
g_slice_free (CleanupRequest, request);
333
g_mutex_unlock (service->mutex);
338
TumblerCacheService *
339
tumbler_cache_service_new (DBusGConnection *connection)
341
return g_object_new (TUMBLER_TYPE_CACHE_SERVICE, "connection", connection, NULL);
347
tumbler_cache_service_start (TumblerCacheService *service,
350
DBusConnection *connection;
351
DBusError dbus_error;
354
g_return_val_if_fail (TUMBLER_IS_CACHE_SERVICE (service), FALSE);
355
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
357
g_mutex_lock (service->mutex);
359
/* initialize the D-Bus error */
360
dbus_error_init (&dbus_error);
362
/* get the native D-Bus connection */
363
connection = dbus_g_connection_get_connection (service->connection);
365
/* request ownership for the cache interface */
366
result = dbus_bus_request_name (connection, "org.freedesktop.thumbnails.Cache1",
367
DBUS_NAME_FLAG_DO_NOT_QUEUE, &dbus_error);
369
/* check if that failed */
370
if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
372
/* propagate the D-Bus error */
373
if (dbus_error_is_set (&dbus_error))
376
dbus_set_g_error (error, &dbus_error);
378
dbus_error_free (&dbus_error);
380
else if (error != NULL)
382
g_set_error (error, DBUS_GERROR, DBUS_GERROR_FAILED,
383
_("Another thumbnail cache service is already running"));
386
g_mutex_unlock (service->mutex);
391
/* everything's fine, install the cache type D-Bus info */
392
dbus_g_object_type_install_info (G_OBJECT_TYPE (service),
393
&dbus_glib_tumbler_cache_service_object_info);
395
/* register the cache instance as a handler of the cache interface */
396
dbus_g_connection_register_g_object (service->connection,
397
"/org/freedesktop/thumbnails/Cache1",
400
g_mutex_unlock (service->mutex);
408
tumbler_cache_service_move (TumblerCacheService *service,
409
const GStrv from_uris,
411
DBusGMethodInvocation *context)
413
MoveRequest *request;
415
dbus_async_return_if_fail (TUMBLER_IS_CACHE_SERVICE (service), context);
416
dbus_async_return_if_fail (from_uris != NULL, context);
417
dbus_async_return_if_fail (to_uris != NULL, context);
418
dbus_async_return_if_fail (g_strv_length (from_uris) == g_strv_length (to_uris), context);
420
request = g_slice_new0 (MoveRequest);
421
request->from_uris = g_strdupv (from_uris);
422
request->to_uris = g_strdupv (to_uris);
424
g_thread_pool_push (service->move_pool, request, NULL);
426
dbus_g_method_return (context);
432
tumbler_cache_service_copy (TumblerCacheService *service,
433
const GStrv from_uris,
435
DBusGMethodInvocation *context)
437
CopyRequest *request;
439
dbus_async_return_if_fail (TUMBLER_IS_CACHE_SERVICE (service), context);
440
dbus_async_return_if_fail (from_uris != NULL, context);
441
dbus_async_return_if_fail (to_uris != NULL, context);
442
dbus_async_return_if_fail (g_strv_length (from_uris) == g_strv_length (to_uris), context);
444
request = g_slice_new0 (CopyRequest);
445
request->from_uris = g_strdupv (from_uris);
446
request->to_uris = g_strdupv (to_uris);
448
g_thread_pool_push (service->copy_pool, request, NULL);
450
dbus_g_method_return (context);
456
tumbler_cache_service_delete (TumblerCacheService *service,
458
DBusGMethodInvocation *context)
460
DeleteRequest *request;
462
dbus_async_return_if_fail (TUMBLER_IS_CACHE_SERVICE (service), context);
463
dbus_async_return_if_fail (uris != NULL, context);
465
request = g_slice_new0 (DeleteRequest);
466
request->uris = g_strdupv (uris);
468
g_thread_pool_push (service->delete_pool, request, NULL);
470
dbus_g_method_return (context);
476
tumbler_cache_service_cleanup (TumblerCacheService *service,
477
const gchar *uri_prefix,
479
DBusGMethodInvocation *context)
481
CleanupRequest *request;
483
dbus_async_return_if_fail (TUMBLER_IS_CACHE_SERVICE (service), context);
485
request = g_slice_new0 (CleanupRequest);
486
request->uri_prefix = g_strdup (uri_prefix);
487
request->since = since;
489
g_thread_pool_push (service->cleanup_pool, request, NULL);
491
dbus_g_method_return (context);