3 * A file-manager extension which offers configurable context menu actions.
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006-2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009-2015 Pierre Wieser and others (see AUTHORS)
9 * FileManager-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.
14 * FileManager-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.
19 * You should have received a copy of the GNU General Public License
20 * along with FileManager-Actions; see the file COPYING. If not, see
21 * <http://www.gnu.org/licenses/>.
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)
36 #include "api/fma-dbus.h"
37 #include "api/fma-fm-defines.h"
39 #include "plugin-tracker/fma-tracker-plugin.h"
40 #include "plugin-tracker/fma-tracker-gdbus.h"
44 struct _FMATrackerPluginClassPrivate
{
45 void *empty
; /* so that gcc -pedantic is happy */
48 /* private instance data
50 struct _FMATrackerPluginPrivate
{
51 gboolean dispose_has_run
;
52 guint owner_id
; /* the identifier returns by g_bus_own_name */
53 GDBusObjectManagerServer
*manager
;
57 static GObjectClass
*st_parent_class
= NULL
;
58 static GType st_module_type
= 0;
60 static void class_init( FMATrackerPluginClass
*klass
);
61 static void instance_init( GTypeInstance
*instance
, gpointer klass
);
62 static void initialize_dbus_connection( FMATrackerPlugin
*tracker
);
63 static void on_bus_acquired( GDBusConnection
*connection
, const gchar
*name
, FMATrackerPlugin
*tracker
);
64 static void on_name_acquired( GDBusConnection
*connection
, const gchar
*name
, FMATrackerPlugin
*tracker
);
65 static void on_name_lost( GDBusConnection
*connection
, const gchar
*name
, FMATrackerPlugin
*tracker
);
66 static gboolean
on_properties1_get_selected_paths( FMATrackerGDBusProperties1
*properties
, GDBusMethodInvocation
*invocation
, FMATrackerPlugin
*tracker
);
67 static void instance_dispose( GObject
*object
);
68 static void instance_finalize( GObject
*object
);
70 static void menu_provider_iface_init( FileManagerMenuProviderIface
*iface
);
71 static GList
*menu_provider_get_background_items( FileManagerMenuProvider
*provider
, GtkWidget
*window
, FileManagerFileInfo
*folder
);
72 static GList
*menu_provider_get_file_items( FileManagerMenuProvider
*provider
, GtkWidget
*window
, GList
*files
);
74 static void set_uris( FMATrackerPlugin
*tracker
, GList
*files
);
75 static gchar
**get_selected_paths( FMATrackerPlugin
*tracker
);
76 static GList
*free_selected( GList
*selected
);
79 fma_tracker_plugin_get_type( void )
81 g_assert( st_module_type
);
82 return( st_module_type
);
86 fma_tracker_plugin_register_type( GTypeModule
*module
)
88 static const gchar
*thisfn
= "fma_tracker_plugin_register_type";
90 static const GTypeInfo info
= {
91 sizeof( FMATrackerPluginClass
),
92 ( GBaseInitFunc
) NULL
,
93 ( GBaseFinalizeFunc
) NULL
,
94 ( GClassInitFunc
) class_init
,
97 sizeof( FMATrackerPlugin
),
99 ( GInstanceInitFunc
) instance_init
,
102 static const GInterfaceInfo menu_provider_iface_info
= {
103 ( GInterfaceInitFunc
) menu_provider_iface_init
,
108 g_debug( "%s: module=%p", thisfn
, ( void * ) module
);
109 g_assert( st_module_type
== 0 );
111 st_module_type
= g_type_module_register_type( module
, G_TYPE_OBJECT
, "FMATrackerPlugin", &info
, 0 );
113 g_type_module_add_interface( module
, st_module_type
, FILE_MANAGER_TYPE_MENU_PROVIDER
, &menu_provider_iface_info
);
117 class_init( FMATrackerPluginClass
*klass
)
119 static const gchar
*thisfn
= "fma_tracker_plugin_class_init";
120 GObjectClass
*gobject_class
;
122 g_debug( "%s: klass=%p", thisfn
, ( void * ) klass
);
124 st_parent_class
= g_type_class_peek_parent( klass
);
126 gobject_class
= G_OBJECT_CLASS( klass
);
127 gobject_class
->dispose
= instance_dispose
;
128 gobject_class
->finalize
= instance_finalize
;
130 klass
->private = g_new0( FMATrackerPluginClassPrivate
, 1 );
134 instance_init( GTypeInstance
*instance
, gpointer klass
)
136 static const gchar
*thisfn
= "fma_tracker_plugin_instance_init";
137 FMATrackerPlugin
*self
;
139 g_debug( "%s: instance=%p, klass=%p", thisfn
, ( void * ) instance
, ( void * ) klass
);
140 g_return_if_fail( FMA_IS_TRACKER_PLUGIN( instance
));
142 self
= FMA_TRACKER_PLUGIN( instance
);
144 self
->private = g_new0( FMATrackerPluginPrivate
, 1 );
145 self
->private->dispose_has_run
= FALSE
;
147 initialize_dbus_connection( self
);
151 * initialize the DBus connection at instanciation time
152 * & instantiate the object which will do effective tracking
155 initialize_dbus_connection( FMATrackerPlugin
*tracker
)
157 FMATrackerPluginPrivate
*priv
= tracker
->private;
159 priv
->owner_id
= g_bus_own_name(
161 FILEMANAGER_ACTIONS_DBUS_SERVICE
,
162 G_BUS_NAME_OWNER_FLAGS_REPLACE
,
163 ( GBusAcquiredCallback
) on_bus_acquired
,
164 ( GBusNameAcquiredCallback
) on_name_acquired
,
165 ( GBusNameLostCallback
) on_name_lost
,
171 on_bus_acquired( GDBusConnection
*connection
, const gchar
*name
, FMATrackerPlugin
*tracker
)
173 static const gchar
*thisfn
= "fma_tracker_plugin_on_bus_acquired";
174 FMATrackerGDBusObjectSkeleton
*tracker_object
;
175 FMATrackerGDBusProperties1
*tracker_properties1
;
177 /*FMATrackerGDBusDBus *tracker_object;*/
179 g_debug( "%s: connection=%p, name=%s, tracker=%p",
181 ( void * ) connection
,
183 ( void * ) tracker
);
185 /* create a new org.freedesktop.DBus.ObjectManager rooted at
186 * /org/filemanager_actions/DBus/Tracker
188 tracker
->private->manager
= g_dbus_object_manager_server_new( FILEMANAGER_ACTIONS_DBUS_TRACKER_PATH
);
190 /* create a new D-Bus object at the path
191 * /org/filemanager_actions/DBus/Tracker
192 * (which must be same or below than that of object manager server)
194 tracker_object
= fma_tracker_gdbus_object_skeleton_new( FILEMANAGER_ACTIONS_DBUS_TRACKER_PATH
"/0" );
196 /* make a newly created object export the interface
197 * org.filemanager_actions.DBus.Tracker.Properties1
198 * and attach it to the D-Bus object, which takes its own reference on it
200 tracker_properties1
= fma_tracker_gdbus_properties1_skeleton_new();
201 fma_tracker_gdbus_object_skeleton_set_properties1( tracker_object
, tracker_properties1
);
202 g_object_unref( tracker_properties1
);
204 /* handle GetSelectedPaths method invocation on the .Properties1 interface
208 "handle-get-selected-paths",
209 G_CALLBACK( on_properties1_get_selected_paths
),
212 /* and export the DBus object on the object manager server
213 * (which takes its own reference on it)
215 g_dbus_object_manager_server_export( tracker
->private->manager
, G_DBUS_OBJECT_SKELETON( tracker_object
));
216 g_object_unref( tracker_object
);
218 /* and connect the object manager server to the D-Bus session
219 * exporting all attached objects
221 g_dbus_object_manager_server_set_connection( tracker
->private->manager
, connection
);
225 on_name_acquired( GDBusConnection
*connection
, const gchar
*name
, FMATrackerPlugin
*tracker
)
227 static const gchar
*thisfn
= "fma_tracker_plugin_on_name_acquired";
229 g_debug( "%s: connection=%p, name=%s, tracker=%p",
231 ( void * ) connection
,
233 ( void * ) tracker
);
237 on_name_lost( GDBusConnection
*connection
, const gchar
*name
, FMATrackerPlugin
*tracker
)
239 static const gchar
*thisfn
= "fma_tracker_plugin_on_name_lost";
241 g_debug( "%s: connection=%p, name=%s, tracker=%p",
243 ( void * ) connection
,
245 ( void * ) tracker
);
249 instance_dispose( GObject
*object
)
251 static const gchar
*thisfn
= "fma_tracker_plugin_instance_dispose";
252 FMATrackerPluginPrivate
*priv
;
254 g_debug( "%s: object=%p", thisfn
, ( void * ) object
);
255 g_return_if_fail( FMA_IS_TRACKER_PLUGIN( object
));
257 priv
= FMA_TRACKER_PLUGIN( object
)->private;
259 if( !priv
->dispose_has_run
){
261 priv
->dispose_has_run
= TRUE
;
263 if( priv
->owner_id
){
264 g_bus_unown_name( priv
->owner_id
);
267 g_object_unref( priv
->manager
);
270 priv
->selected
= free_selected( priv
->selected
);
272 /* chain up to the parent class */
273 if( G_OBJECT_CLASS( st_parent_class
)->dispose
){
274 G_OBJECT_CLASS( st_parent_class
)->dispose( object
);
280 instance_finalize( GObject
*object
)
282 static const gchar
*thisfn
= "fma_tracker_plugin_instance_finalize";
283 FMATrackerPlugin
*self
;
285 g_debug( "%s: object=%p", thisfn
, ( void * ) object
);
286 g_return_if_fail( FMA_IS_TRACKER_PLUGIN( object
));
287 self
= FMA_TRACKER_PLUGIN( object
);
289 g_free( self
->private );
291 /* chain up to the parent class */
292 if( G_OBJECT_CLASS( st_parent_class
)->finalize
){
293 G_OBJECT_CLASS( st_parent_class
)->finalize( object
);
298 menu_provider_iface_init( FileManagerMenuProviderIface
*iface
)
300 static const gchar
*thisfn
= "fma_tracker_plugin_menu_provider_iface_init";
302 g_debug( "%s: iface=%p", thisfn
, ( void * ) iface
);
304 iface
->get_background_items
= menu_provider_get_background_items
;
305 iface
->get_file_items
= menu_provider_get_file_items
;
309 menu_provider_get_background_items( FileManagerMenuProvider
*provider
, GtkWidget
*window
, FileManagerFileInfo
*folder
)
311 static const gchar
*thisfn
= "fma_tracker_plugin_menu_provider_get_background_items";
312 FMATrackerPlugin
*tracker
;
316 g_return_val_if_fail( FMA_IS_TRACKER_PLUGIN( provider
), NULL
);
318 tracker
= FMA_TRACKER_PLUGIN( provider
);
320 if( !tracker
->private->dispose_has_run
){
322 uri
= file_manager_file_info_get_uri( folder
);
323 g_debug( "%s: provider=%p, window=%p, folder=%s",
330 selected
= g_list_prepend( NULL
, folder
);
331 set_uris( tracker
, selected
);
332 g_list_free( selected
);
339 * this function is called each time the selection changed
340 * menus items are available :
341 * a) in Edit menu while the selection stays unchanged
342 * b) in contextual menu while the selection stays unchanged
345 menu_provider_get_file_items( FileManagerMenuProvider
*provider
, GtkWidget
*window
, GList
*files
)
347 static const gchar
*thisfn
= "fma_tracker_plugin_menu_provider_get_file_items";
348 FMATrackerPlugin
*tracker
;
350 g_return_val_if_fail( FMA_IS_TRACKER_PLUGIN( provider
), NULL
);
352 tracker
= FMA_TRACKER_PLUGIN( provider
);
354 if( !tracker
->private->dispose_has_run
){
356 g_debug( "%s: provider=%p, window=%p, files=%p, count=%d",
360 ( void * ) files
, g_list_length( files
));
362 set_uris( tracker
, files
);
370 * @tracker: this #FMATrackerPlugin instance.
371 * @files: the list of currently selected items.
373 * Maintains our own list of uris.
376 set_uris( FMATrackerPlugin
*tracker
, GList
*files
)
378 FMATrackerPluginPrivate
*priv
;
380 priv
= tracker
->private;
382 priv
->selected
= free_selected( tracker
->private->selected
);
383 priv
->selected
= file_manager_file_info_list_copy( files
);
387 * Returns: %TRUE if the method has been handled.
390 on_properties1_get_selected_paths( FMATrackerGDBusProperties1
*properties
, GDBusMethodInvocation
*invocation
, FMATrackerPlugin
*tracker
)
394 g_return_val_if_fail( FMA_IS_TRACKER_PLUGIN( tracker
), FALSE
);
396 paths
= get_selected_paths( tracker
);
398 fma_tracker_gdbus_properties1_complete_get_selected_paths(
401 ( const gchar
* const * ) paths
);
407 * get_selected_paths:
408 * @tracker: this #FMATrackerPlugin object.
410 * Sends on session D-Bus the list of currently selected items, as two
411 * strings for each item :
413 * - the mimetype as returned by NautilusFileInfo.
415 * This is required as some particular items are only known by Nautilus
416 * (e.g. computer), and standard GLib functions are not able to retrieve
419 * Exported as GetSelectedPaths method on Tracker.Properties1 interface.
422 get_selected_paths( FMATrackerPlugin
*tracker
)
424 static const gchar
*thisfn
= "fma_tracker_plugin_get_selected_paths";
425 FMATrackerPluginPrivate
*priv
;
432 priv
= tracker
->private;
434 g_debug( "%s: tracker=%p", thisfn
, ( void * ) tracker
);
436 count
= 2 * g_list_length( priv
->selected
);
437 paths
= ( char ** ) g_new0( gchar
*, 1+count
);
440 for( it
= priv
->selected
; it
; it
= it
->next
){
441 *iter
= file_manager_file_info_get_uri(( FileManagerFileInfo
* ) it
->data
);
443 *iter
= file_manager_file_info_get_mime_type(( FileManagerFileInfo
* ) it
->data
);
451 free_selected( GList
*selected
)
453 file_manager_file_info_list_free( selected
);