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 <gio/gio.h>
35 
36 #include "nadp-monitor.h"
37 
38 /* private class data
39  */
40 struct _NadpMonitorClassPrivate {
41 	void *empty;						/* so that gcc -pedantic is happy */
42 };
43 
44 /* private instance data
45  */
46 struct _NadpMonitorPrivate {
47 	gboolean             dispose_has_run;
48 	NadpDesktopProvider *provider;
49 	gchar               *name;
50 	GFile               *file;
51 	GFileMonitor        *monitor;
52 	gulong               handler;
53 };
54 
55 static GObjectClass *st_parent_class = NULL;
56 
57 static GType  register_type( void );
58 static void   class_init( NadpMonitorClass *klass );
59 static void   instance_init( GTypeInstance *instance, gpointer klass );
60 static void   instance_dispose( GObject *object );
61 static void   instance_finalize( GObject *object );
62 
63 static void   on_monitor_changed( GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, NadpMonitor *my_monitor );
64 
65 GType
nadp_monitor_get_type(void)66 nadp_monitor_get_type( void )
67 {
68 	static GType class_type = 0;
69 
70 	if( !class_type ){
71 		class_type = register_type();
72 	}
73 
74 	return( class_type );
75 }
76 
77 static GType
register_type(void)78 register_type( void )
79 {
80 	static const gchar *thisfn = "nadp_monitor_register_type";
81 	GType type;
82 
83 	static GTypeInfo info = {
84 		sizeof( NadpMonitorClass ),
85 		NULL,
86 		NULL,
87 		( GClassInitFunc ) class_init,
88 		NULL,
89 		NULL,
90 		sizeof( NadpMonitor ),
91 		0,
92 		( GInstanceInitFunc ) instance_init
93 	};
94 
95 	g_debug( "%s", thisfn );
96 
97 	type = g_type_register_static( G_TYPE_OBJECT, "NadpMonitor", &info, 0 );
98 
99 	return( type );
100 }
101 
102 static void
class_init(NadpMonitorClass * klass)103 class_init( NadpMonitorClass *klass )
104 {
105 	static const gchar *thisfn = "nadp_monitor_class_init";
106 	GObjectClass *object_class;
107 
108 	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
109 
110 	st_parent_class = g_type_class_peek_parent( klass );
111 
112 	object_class = G_OBJECT_CLASS( klass );
113 	object_class->dispose = instance_dispose;
114 	object_class->finalize = instance_finalize;
115 
116 	klass->private = g_new0( NadpMonitorClassPrivate, 1 );
117 }
118 
119 static void
instance_init(GTypeInstance * instance,gpointer klass)120 instance_init( GTypeInstance *instance, gpointer klass )
121 {
122 	static const gchar *thisfn = "nadp_monitor_instance_init";
123 	NadpMonitor *self;
124 
125 	g_return_if_fail( NADP_IS_MONITOR( instance ));
126 
127 	g_debug( "%s: instance=%p (%s), klass=%p",
128 			thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
129 
130 	self = NADP_MONITOR( instance );
131 
132 	self->private = g_new0( NadpMonitorPrivate, 1 );
133 
134 	self->private->dispose_has_run = FALSE;
135 }
136 
137 static void
instance_dispose(GObject * object)138 instance_dispose( GObject *object )
139 {
140 	static const gchar *thisfn = "nadp_monitor_instance_dispose";
141 	NadpMonitor *self;
142 
143 	g_return_if_fail( NADP_IS_MONITOR( object ));
144 
145 	self = NADP_MONITOR( object );
146 
147 	if( !self->private->dispose_has_run ){
148 
149 		g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
150 
151 		if( self->private->handler ){
152 			g_signal_handler_disconnect( self->private->monitor, self->private->handler );
153 		}
154 
155 		if( self->private->monitor ){
156 			g_object_unref( self->private->monitor );
157 		}
158 
159 		if( self->private->file ){
160 			g_object_unref( self->private->file );
161 		}
162 
163 		self->private->dispose_has_run = TRUE;
164 
165 		/* chain up to the parent class */
166 		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
167 			G_OBJECT_CLASS( st_parent_class )->dispose( object );
168 		}
169 	}
170 }
171 
172 static void
instance_finalize(GObject * object)173 instance_finalize( GObject *object )
174 {
175 	static const gchar *thisfn = "nadp_monitor_instance_finalize";
176 	NadpMonitor *self;
177 
178 	g_return_if_fail( NADP_IS_MONITOR( object ));
179 
180 	g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
181 
182 	self = NADP_MONITOR( object );
183 
184 	g_free( self->private->name );
185 
186 	g_free( self->private );
187 
188 	/* chain call to parent class */
189 	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
190 		G_OBJECT_CLASS( st_parent_class )->finalize( object );
191 	}
192 }
193 
194 /**
195  * nadp_monitor_new:
196  * @provider: the #NadpDesktopProvider instance.
197  * @path: the path of a directory to be monitored.
198  *
199  * Installs a new monitor on the given directory.
200  *
201  * Returns: a new #NadpMonitor instance.
202  */
203 NadpMonitor *
nadp_monitor_new(const NadpDesktopProvider * provider,const gchar * path)204 nadp_monitor_new( const NadpDesktopProvider *provider, const gchar *path )
205 {
206 	static const gchar *thisfn = "nadp_monitor_new";
207 	NadpMonitor *monitor;
208 	GFileMonitorFlags flags;
209 	GError *error;
210 
211 	monitor = g_object_new( NADP_TYPE_MONITOR, NULL );
212 
213 	monitor->private->provider = NADP_DESKTOP_PROVIDER( provider );
214 	monitor->private->name = g_strdup( path );
215 	monitor->private->file = g_file_new_for_path( path );
216 
217 	error = NULL;
218 	flags = G_FILE_MONITOR_NONE;
219 
220 	monitor->private->monitor = g_file_monitor_directory( monitor->private->file, flags, NULL, &error );
221 	if( error ){
222 		g_warning( "%s: g_file_monitor: %s", thisfn, error->message );
223 		g_error_free( error );
224 		error = NULL;
225 		g_object_unref( monitor );
226 		return( NULL );
227 	}
228 
229 	g_return_val_if_fail( monitor->private->monitor, NULL );
230 
231 	monitor->private->handler = g_signal_connect(
232 				monitor->private->monitor, "changed", G_CALLBACK( on_monitor_changed ), monitor );
233 
234 	return( monitor );
235 }
236 
237 /*
238  * - an existing file is modified: n events on dir + m events on file
239  * - an existing file is deleted: 1 event on file + 1 event on dir
240  * - a new file is created: n events on the dir
241  * - a new directory is created: 1 event of this new dir
242  * - a directory is removed: 1 event of this new dir
243  * - an existing file is renamed: 1 event on file + n events on dir
244  * - the renamed file is modified: n events on dir
245  */
246 static void
on_monitor_changed(GFileMonitor * monitor,GFile * file,GFile * other_file,GFileMonitorEvent event_type,NadpMonitor * my_monitor)247 on_monitor_changed( GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, NadpMonitor *my_monitor )
248 {
249 	nadp_desktop_provider_on_monitor_event( my_monitor->private->provider );
250 }
251