1 /*
2  * Nautilus-Actions
3  * A Nautilus extension which offers configurable context menu actions.
4  *
5  * Copyright (C) 2005 The GNOME Foundation
6  * Copyright (C) 2006-2008 Frederic Ruaudel and others (see AUTHORS)
7  * Copyright (C) 2009-2014 Pierre Wieser and others (see AUTHORS)
8  *
9  * Nautilus-Actions is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * Nautilus-Actions is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Nautilus-Actions; see the file COPYING. If not, see
21  * <http://www.gnu.org/licenses/>.
22  *
23  * Authors:
24  *   Frederic Ruaudel <grumz@grumz.net>
25  *   Rodrigo Moya <rodrigo@gnome-db.org>
26  *   Pierre Wieser <pwieser@trychlos.org>
27  *   ... and many others (see AUTHORS)
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 #include <glib/gi18n.h>
35 #include <string.h>
36 
37 #include <api/na-core-utils.h>
38 #include <api/na-ifactory-provider.h>
39 
40 #include "nadp-desktop-provider.h"
41 #include "nadp-formats.h"
42 #include "nadp-keys.h"
43 #include "nadp-monitor.h"
44 #include "nadp-reader.h"
45 #include "nadp-writer.h"
46 
47 /* private class data
48  */
49 struct _NadpDesktopProviderClassPrivate {
50 	void *empty;						/* so that gcc -pedantic is happy */
51 };
52 
53 static GType         st_module_type = 0;
54 static GObjectClass *st_parent_class = NULL;
55 static guint         st_burst_timeout = 100;		/* burst timeout in msec */
56 
57 static void   class_init( NadpDesktopProviderClass *klass );
58 static void   instance_init( GTypeInstance *instance, gpointer klass );
59 static void   instance_dispose( GObject *object );
60 static void   instance_finalize( GObject *object );
61 
62 static void   iio_provider_iface_init( NAIIOProviderInterface *iface );
63 static gchar *iio_provider_get_id( const NAIIOProvider *provider );
64 static gchar *iio_provider_get_name( const NAIIOProvider *provider );
65 static guint  iio_provider_get_version( const NAIIOProvider *provider );
66 
67 static void   ifactory_provider_iface_init( NAIFactoryProviderInterface *iface );
68 static guint  ifactory_provider_get_version( const NAIFactoryProvider *reader );
69 
70 static void   iimporter_iface_init( NAIImporterInterface *iface );
71 static guint  iimporter_get_version( const NAIImporter *importer );
72 
73 static void   iexporter_iface_init( NAIExporterInterface *iface );
74 static guint  iexporter_get_version( const NAIExporter *exporter );
75 static gchar *iexporter_get_name( const NAIExporter *exporter );
76 static void  *iexporter_get_formats( const NAIExporter *exporter );
77 static void   iexporter_free_formats( const NAIExporter *exporter, GList *format_list );
78 
79 static void   on_monitor_timeout( NadpDesktopProvider *provider );
80 
81 GType
nadp_desktop_provider_get_type(void)82 nadp_desktop_provider_get_type( void )
83 {
84 	return( st_module_type );
85 }
86 
87 void
nadp_desktop_provider_register_type(GTypeModule * module)88 nadp_desktop_provider_register_type( GTypeModule *module )
89 {
90 	static const gchar *thisfn = "nadp_desktop_provider_register_type";
91 
92 	static GTypeInfo info = {
93 		sizeof( NadpDesktopProviderClass ),
94 		NULL,
95 		NULL,
96 		( GClassInitFunc ) class_init,
97 		NULL,
98 		NULL,
99 		sizeof( NadpDesktopProvider ),
100 		0,
101 		( GInstanceInitFunc ) instance_init
102 	};
103 
104 	static const GInterfaceInfo iio_provider_iface_info = {
105 		( GInterfaceInitFunc ) iio_provider_iface_init,
106 		NULL,
107 		NULL
108 	};
109 
110 	static const GInterfaceInfo ifactory_provider_iface_info = {
111 		( GInterfaceInitFunc ) ifactory_provider_iface_init,
112 		NULL,
113 		NULL
114 	};
115 
116 	static const GInterfaceInfo iimporter_iface_info = {
117 		( GInterfaceInitFunc ) iimporter_iface_init,
118 		NULL,
119 		NULL
120 	};
121 
122 	static const GInterfaceInfo iexporter_iface_info = {
123 		( GInterfaceInitFunc ) iexporter_iface_init,
124 		NULL,
125 		NULL
126 	};
127 
128 	g_debug( "%s", thisfn );
129 
130 	st_module_type = g_type_module_register_type( module, G_TYPE_OBJECT, "NadpDesktopProvider", &info, 0 );
131 
132 	g_type_module_add_interface( module, st_module_type, NA_TYPE_IIO_PROVIDER, &iio_provider_iface_info );
133 
134 	g_type_module_add_interface( module, st_module_type, NA_TYPE_IFACTORY_PROVIDER, &ifactory_provider_iface_info );
135 
136 	g_type_module_add_interface( module, st_module_type, NA_TYPE_IIMPORTER, &iimporter_iface_info );
137 
138 	g_type_module_add_interface( module, st_module_type, NA_TYPE_IEXPORTER, &iexporter_iface_info );
139 }
140 
141 static void
class_init(NadpDesktopProviderClass * klass)142 class_init( NadpDesktopProviderClass *klass )
143 {
144 	static const gchar *thisfn = "nadp_desktop_provider_class_init";
145 	GObjectClass *object_class;
146 
147 	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
148 
149 	st_parent_class = g_type_class_peek_parent( klass );
150 
151 	object_class = G_OBJECT_CLASS( klass );
152 	object_class->dispose = instance_dispose;
153 	object_class->finalize = instance_finalize;
154 
155 	klass->private = g_new0( NadpDesktopProviderClassPrivate, 1 );
156 }
157 
158 static void
instance_init(GTypeInstance * instance,gpointer klass)159 instance_init( GTypeInstance *instance, gpointer klass )
160 {
161 	static const gchar *thisfn = "nadp_desktop_provider_instance_init";
162 	NadpDesktopProvider *self;
163 
164 	g_return_if_fail( NADP_IS_DESKTOP_PROVIDER( instance ));
165 
166 	g_debug( "%s: instance=%p (%s), klass=%p",
167 			thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
168 
169 	self = NADP_DESKTOP_PROVIDER( instance );
170 
171 	self->private = g_new0( NadpDesktopProviderPrivate, 1 );
172 
173 	self->private->dispose_has_run = FALSE;
174 	self->private->monitors = NULL;
175 	self->private->timeout.timeout = st_burst_timeout;
176 	self->private->timeout.handler = ( NATimeoutFunc ) on_monitor_timeout;
177 	self->private->timeout.user_data = self;
178 	self->private->timeout.source_id = 0;
179 }
180 
181 static void
instance_dispose(GObject * object)182 instance_dispose( GObject *object )
183 {
184 	static const gchar *thisfn = "nadp_desktop_provider_instance_dispose";
185 	NadpDesktopProvider *self;
186 
187 	g_return_if_fail( NADP_IS_DESKTOP_PROVIDER( object ));
188 
189 	self = NADP_DESKTOP_PROVIDER( object );
190 
191 	if( !self->private->dispose_has_run ){
192 
193 		g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
194 
195 		self->private->dispose_has_run = TRUE;
196 
197 		nadp_desktop_provider_release_monitors( self );
198 
199 		/* chain up to the parent class */
200 		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
201 			G_OBJECT_CLASS( st_parent_class )->dispose( object );
202 		}
203 	}
204 }
205 
206 static void
instance_finalize(GObject * object)207 instance_finalize( GObject *object )
208 {
209 	static const gchar *thisfn = "nadp_desktop_provider_instance_finalize";
210 	NadpDesktopProvider *self;
211 
212 	g_return_if_fail( NADP_IS_DESKTOP_PROVIDER( object ));
213 
214 	g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
215 
216 	self = NADP_DESKTOP_PROVIDER( object );
217 
218 	g_free( self->private );
219 
220 	/* chain call to parent class */
221 	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
222 		G_OBJECT_CLASS( st_parent_class )->finalize( object );
223 	}
224 }
225 
226 static void
iio_provider_iface_init(NAIIOProviderInterface * iface)227 iio_provider_iface_init( NAIIOProviderInterface *iface )
228 {
229 	static const gchar *thisfn = "nadp_desktop_provider_iio_provider_iface_init";
230 
231 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
232 
233 	iface->get_version = iio_provider_get_version;
234 	iface->get_id = iio_provider_get_id;
235 	iface->get_name = iio_provider_get_name;
236 	iface->read_items = nadp_iio_provider_read_items;
237 	iface->is_willing_to_write = nadp_iio_provider_is_willing_to_write;
238 	iface->is_able_to_write = nadp_iio_provider_is_able_to_write;
239 	iface->write_item = nadp_iio_provider_write_item;
240 	iface->delete_item = nadp_iio_provider_delete_item;
241 	iface->duplicate_data = nadp_iio_provider_duplicate_data;
242 }
243 
244 static guint
iio_provider_get_version(const NAIIOProvider * provider)245 iio_provider_get_version( const NAIIOProvider *provider )
246 {
247 	return( 1 );
248 }
249 
250 static gchar *
iio_provider_get_id(const NAIIOProvider * provider)251 iio_provider_get_id( const NAIIOProvider *provider )
252 {
253 	return( g_strdup( PROVIDER_ID ));
254 }
255 
256 static gchar *
iio_provider_get_name(const NAIIOProvider * provider)257 iio_provider_get_name( const NAIIOProvider *provider )
258 {
259 	return( g_strdup( _( "Nautilus-Actions Desktop I/O Provider" )));
260 }
261 
262 static void
ifactory_provider_iface_init(NAIFactoryProviderInterface * iface)263 ifactory_provider_iface_init( NAIFactoryProviderInterface *iface )
264 {
265 	static const gchar *thisfn = "nadp_desktop_provider_ifactory_provider_iface_init";
266 
267 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
268 
269 	iface->get_version = ifactory_provider_get_version;
270 	iface->read_start = nadp_reader_ifactory_provider_read_start;
271 	iface->read_data = nadp_reader_ifactory_provider_read_data;
272 	iface->read_done = nadp_reader_ifactory_provider_read_done;
273 	iface->write_start = nadp_writer_ifactory_provider_write_start;
274 	iface->write_data = nadp_writer_ifactory_provider_write_data;
275 	iface->write_done = nadp_writer_ifactory_provider_write_done;
276 }
277 
278 static guint
ifactory_provider_get_version(const NAIFactoryProvider * reader)279 ifactory_provider_get_version( const NAIFactoryProvider *reader )
280 {
281 	return( 1 );
282 }
283 
284 static void
iimporter_iface_init(NAIImporterInterface * iface)285 iimporter_iface_init( NAIImporterInterface *iface )
286 {
287 	static const gchar *thisfn = "nadp_desktop_provider_iimporter_iface_init";
288 
289 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
290 
291 	iface->get_version = iimporter_get_version;
292 	iface->import_from_uri = nadp_reader_iimporter_import_from_uri;
293 }
294 
295 static guint
iimporter_get_version(const NAIImporter * importer)296 iimporter_get_version( const NAIImporter *importer )
297 {
298 	return( 2 );
299 }
300 
301 static void
iexporter_iface_init(NAIExporterInterface * iface)302 iexporter_iface_init( NAIExporterInterface *iface )
303 {
304 	static const gchar *thisfn = "nadp_desktop_iexporter_iface_init";
305 
306 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
307 
308 	iface->get_version = iexporter_get_version;
309 	iface->get_name = iexporter_get_name;
310 	iface->get_formats = iexporter_get_formats;
311 	iface->free_formats = iexporter_free_formats;
312 	iface->to_file = nadp_writer_iexporter_export_to_file;
313 	iface->to_buffer = nadp_writer_iexporter_export_to_buffer;
314 }
315 
316 static guint
iexporter_get_version(const NAIExporter * exporter)317 iexporter_get_version( const NAIExporter *exporter )
318 {
319 	return( 2 );
320 }
321 
322 static gchar *
iexporter_get_name(const NAIExporter * exporter)323 iexporter_get_name( const NAIExporter *exporter )
324 {
325 	return( g_strdup( "NA Desktop Exporter" ));
326 }
327 
328 static void *
iexporter_get_formats(const NAIExporter * exporter)329 iexporter_get_formats( const NAIExporter *exporter )
330 {
331 	return(( void * ) nadp_formats_get_formats( exporter ));
332 }
333 
334 static void
iexporter_free_formats(const NAIExporter * exporter,GList * format_list)335 iexporter_free_formats( const NAIExporter *exporter, GList *format_list )
336 {
337 	nadp_formats_free_formats( format_list );
338 }
339 
340 /**
341  * nadp_desktop_provider_add_monitor:
342  * @provider: this #NadpDesktopProvider object.
343  * @dir: the path to the directory to be monitored. May not exist.
344  *
345  * Installs a GIO monitor on the given directory.
346  */
347 void
nadp_desktop_provider_add_monitor(NadpDesktopProvider * provider,const gchar * dir)348 nadp_desktop_provider_add_monitor( NadpDesktopProvider *provider, const gchar *dir )
349 {
350 	NadpMonitor *monitor;
351 
352 	g_return_if_fail( NADP_IS_DESKTOP_PROVIDER( provider ));
353 
354 	if( !provider->private->dispose_has_run ){
355 
356 		monitor = nadp_monitor_new( provider, dir );
357 		provider->private->monitors = g_list_prepend( provider->private->monitors, monitor );
358 	}
359 }
360 
361 /**
362  * nadp_desktop_provider_on_monitor_event:
363  * @provider: this #NadpDesktopProvider object.
364  *
365  * Factorize events received from GIO when monitoring desktop directories.
366  */
367 void
nadp_desktop_provider_on_monitor_event(NadpDesktopProvider * provider)368 nadp_desktop_provider_on_monitor_event( NadpDesktopProvider *provider )
369 {
370 	g_return_if_fail( NADP_IS_DESKTOP_PROVIDER( provider ));
371 
372 	if( !provider->private->dispose_has_run ){
373 
374 		na_timeout_event( &provider->private->timeout );
375 	}
376 }
377 
378 /**
379  * nadp_desktop_provider_release_monitors:
380  * @provider: this #NadpDesktopProvider object.
381  *
382  * Release previously set desktop monitors.
383  */
384 void
nadp_desktop_provider_release_monitors(NadpDesktopProvider * provider)385 nadp_desktop_provider_release_monitors( NadpDesktopProvider *provider )
386 {
387 	g_return_if_fail( NADP_IS_DESKTOP_PROVIDER( provider ));
388 
389 	if( provider->private->monitors ){
390 
391 		g_list_foreach( provider->private->monitors, ( GFunc ) g_object_unref, NULL );
392 		g_list_free( provider->private->monitors );
393 		provider->private->monitors = NULL;
394 	}
395 }
396 
397 static void
on_monitor_timeout(NadpDesktopProvider * provider)398 on_monitor_timeout( NadpDesktopProvider *provider )
399 {
400 	static const gchar *thisfn = "nadp_desktop_provider_on_monitor_timeout";
401 
402 	/* last individual notification is older that the st_burst_timeout
403 	 * so triggers the NAIIOProvider interface and destroys this timeout
404 	 */
405 	g_debug( "%s: triggering NAIIOProvider interface for provider=%p (%s)",
406 			thisfn, ( void * ) provider, G_OBJECT_TYPE_NAME( provider ));
407 
408 	na_iio_provider_item_changed( NA_IIO_PROVIDER( provider ));
409 }
410