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)
34 #include <glib/gi18n.h>
37 #include "api/fma-core-utils.h"
39 #include "core/fma-about.h"
41 #include "fma-application.h"
42 #include "fma-main-window.h"
45 /* private instance data
47 struct _FMAApplicationPrivate
{
48 gboolean dispose_has_run
;
50 const gchar
*application_name
; /* new: st_application_name localized version */
51 const gchar
*description
; /* new: st_description localized version */
52 const gchar
*icon_name
; /* new: icon name */
58 FMAMainWindow
*main_window
;
61 static const gchar
*st_application_name
= N_( "FileManager-Actions Configuration Tool" );
62 static const gchar
*st_description
= N_( "A user interface to edit your own contextual actions" );
63 static const gchar
*st_application_id
= "org.gnome.filemanager-actions.ConfigurationTool";
65 static gboolean st_non_unique_opt
= FALSE
;
66 static gboolean st_version_opt
= FALSE
;
68 static GOptionEntry st_option_entries
[] = {
69 { "non-unique", 'n', 0, G_OPTION_ARG_NONE
, &st_non_unique_opt
,
70 N_( "Set it to run multiple instances of the program [unique]" ), NULL
},
71 { "version" , 'v', 0, G_OPTION_ARG_NONE
, &st_version_opt
,
72 N_( "Output the version number, and exit gracefully [no]" ), NULL
},
76 static GtkApplicationClass
*st_parent_class
= NULL
;
78 static GType
register_type( void );
79 static void class_init( FMAApplicationClass
*klass
);
80 static void instance_init( GTypeInstance
*instance
, gpointer klass
);
81 static void instance_dispose( GObject
*application
);
82 static void instance_finalize( GObject
*application
);
83 static void init_i18n( FMAApplication
*application
);
84 static gboolean
init_gtk_args( FMAApplication
*application
);
85 static gboolean
manage_options( FMAApplication
*application
);
86 static void application_startup( GApplication
*application
);
87 static void application_activate( GApplication
*application
);
88 static void application_open( GApplication
*application
, GFile
**files
, gint n_files
, const gchar
*hint
);
91 fma_application_get_type( void )
93 static GType application_type
= 0;
95 if( !application_type
){
96 application_type
= register_type();
99 return( application_type
);
103 register_type( void )
105 static const gchar
*thisfn
= "fma_application_register_type";
108 static GTypeInfo info
= {
109 sizeof( FMAApplicationClass
),
110 ( GBaseInitFunc
) NULL
,
111 ( GBaseFinalizeFunc
) NULL
,
112 ( GClassInitFunc
) class_init
,
115 sizeof( FMAApplication
),
117 ( GInstanceInitFunc
) instance_init
120 g_debug( "%s", thisfn
);
122 type
= g_type_register_static( GTK_TYPE_APPLICATION
, "FMAApplication", &info
, 0 );
128 class_init( FMAApplicationClass
*klass
)
130 static const gchar
*thisfn
= "fma_application_class_init";
132 g_debug( "%s: klass=%p", thisfn
, ( void * ) klass
);
134 st_parent_class
= GTK_APPLICATION_CLASS( g_type_class_peek_parent( klass
));
136 G_OBJECT_CLASS( klass
)->dispose
= instance_dispose
;
137 G_OBJECT_CLASS( klass
)->finalize
= instance_finalize
;
139 G_APPLICATION_CLASS( klass
)->startup
= application_startup
;
140 G_APPLICATION_CLASS( klass
)->activate
= application_activate
;
141 G_APPLICATION_CLASS( klass
)->open
= application_open
;
145 instance_init( GTypeInstance
*application
, gpointer klass
)
147 static const gchar
*thisfn
= "fma_application_instance_init";
148 FMAApplication
*self
;
150 g_return_if_fail( FMA_IS_APPLICATION( application
));
152 g_debug( "%s: application=%p (%s), klass=%p",
153 thisfn
, ( void * ) application
, G_OBJECT_TYPE_NAME( application
), ( void * ) klass
);
155 self
= FMA_APPLICATION( application
);
157 self
->private = g_new0( FMAApplicationPrivate
, 1 );
159 self
->private->dispose_has_run
= FALSE
;
163 instance_dispose( GObject
*application
)
165 static const gchar
*thisfn
= "fma_application_instance_dispose";
166 FMAApplicationPrivate
*priv
;
168 g_return_if_fail( application
&& FMA_IS_APPLICATION( application
));
170 priv
= FMA_APPLICATION( application
)->private;
172 if( !priv
->dispose_has_run
){
174 g_debug( "%s: application=%p (%s)", thisfn
, ( void * ) application
, G_OBJECT_TYPE_NAME( application
));
176 priv
->dispose_has_run
= TRUE
;
179 g_clear_object( &priv
->updater
);
183 /* chain up to the parent class */
184 G_OBJECT_CLASS( st_parent_class
)->dispose( application
);
188 instance_finalize( GObject
*application
)
190 static const gchar
*thisfn
= "fma_application_instance_finalize";
191 FMAApplication
*self
;
193 g_return_if_fail( FMA_IS_APPLICATION( application
));
195 g_debug( "%s: application=%p (%s)", thisfn
, ( void * ) application
, G_OBJECT_TYPE_NAME( application
));
197 self
= FMA_APPLICATION( application
);
199 g_free( self
->private );
201 /* chain call to the parent class */
202 G_OBJECT_CLASS( st_parent_class
)->finalize( application
);
206 * fma_application_new:
208 * Returns: a newly allocated FMAApplication object.
211 fma_application_new( void )
213 FMAApplication
*application
;
214 FMAApplicationPrivate
*priv
;
216 application
= g_object_new( FMA_TYPE_APPLICATION
,
217 "application-id", st_application_id
,
220 priv
= application
->private;
221 priv
->application_name
= gettext( st_application_name
);
222 priv
->description
= gettext( st_description
);
223 priv
->icon_name
= fma_about_get_icon_name();
225 return( application
);
229 * fma_application_run_with_args:
230 * @application: this #GtkApplication -derived instance.
234 * Starts and runs the application.
235 * Takes care of creating, initializing, and running the main window.
237 * All steps are implemented as virtual functions which provide some
238 * suitable defaults, and may be overriden by a derived class.
240 * Returns: an %int code suitable as an exit code for the program.
242 * Though it is defined as a virtual function itself, it should be very
243 * seldomly needed to override this in a derived class.
246 fma_application_run_with_args( FMAApplication
*application
, int argc
, GStrv argv
)
248 static const gchar
*thisfn
= "fma_application_run_with_args";
249 FMAApplicationPrivate
*priv
;
251 g_debug( "%s: application=%p (%s), argc=%d",
253 ( void * ) application
, G_OBJECT_TYPE_NAME( application
),
256 g_return_val_if_fail( application
&& FMA_IS_APPLICATION( application
), FMA_EXIT_CODE_PROGRAM
);
258 priv
= application
->private;
260 if( !priv
->dispose_has_run
){
263 priv
->argv
= g_strdupv( argv
);
264 priv
->code
= FMA_EXIT_CODE_OK
;
266 init_i18n( application
);
267 g_set_application_name( priv
->application_name
);
268 gtk_window_set_default_icon_name( priv
->icon_name
);
270 if( init_gtk_args( application
) &&
271 manage_options( application
)){
273 g_debug( "%s: entering g_application_run", thisfn
);
274 priv
->code
= g_application_run( G_APPLICATION( application
), 0, NULL
);
278 return( priv
->code
);
282 * i18n initialization
284 * Returns: %TRUE to continue the execution, %FALSE to terminate the program.
285 * The program exit code will be taken from @code.
288 init_i18n( FMAApplication
*application
)
290 static const gchar
*thisfn
= "fma_application_init_i18n";
292 g_debug( "%s: application=%p", thisfn
, ( void * ) application
);
295 bindtextdomain( GETTEXT_PACKAGE
, GNOMELOCALEDIR
);
296 # ifdef HAVE_BIND_TEXTDOMAIN_CODESET
297 bind_textdomain_codeset( GETTEXT_PACKAGE
, "UTF-8" );
299 textdomain( GETTEXT_PACKAGE
);
304 * Pre-Gtk+ initialization
306 * Though GApplication has its own infrastructure to handle command-line
307 * arguments, it appears that it does not deal with Gtk+-specific arguments.
308 * We so have to explicitely call gtk_init_with_args() in order to let Gtk+
309 * "eat" its own arguments, and only have to handle our owns...
312 init_gtk_args( FMAApplication
*application
)
314 static const gchar
*thisfn
= "fma_application_init_gtk_args";
315 FMAApplicationPrivate
*priv
;
317 char *parameter_string
;
320 g_debug( "%s: application=%p", thisfn
, ( void * ) application
);
322 priv
= application
->private;
324 parameter_string
= g_strdup( g_get_application_name());
326 ret
= gtk_init_with_args(
328 ( char *** ) &priv
->argv
,
334 g_warning( "%s: %s", thisfn
, error
->message
);
335 g_error_free( error
);
337 priv
->code
= FMA_EXIT_CODE_ARGS
;
339 g_free( parameter_string
);
345 manage_options( FMAApplication
*application
)
347 static const gchar
*thisfn
= "fma_application_manage_options";
350 g_debug( "%s: application=%p", thisfn
, ( void * ) application
);
354 /* display the program version ?
355 * if yes, then stops here, exiting with code ok
357 if( st_version_opt
){
358 fma_core_utils_print_version();
362 /* run the application as non-unique ?
364 if( ret
&& st_non_unique_opt
){
365 g_application_set_flags( G_APPLICATION( application
), G_APPLICATION_NON_UNIQUE
);
372 * https://wiki.gnome.org/HowDoI/GtkApplication
374 * Invoked on the primary instance immediately after registration.
376 * When your application starts, the startup signal will be fired. This
377 * gives you a chance to perform initialisation tasks that are not
378 * directly related to showing a new window. After this, depending on
379 * how the application is started, either activate or open will be called
382 * GtkApplication defaults to applications being single-instance. If the
383 * user attempts to start a second instance of a single-instance
384 * application then GtkApplication will signal the first instance and
385 * you will receive additional activate or open signals. In this case,
386 * the second instance will exit immediately, without calling startup
389 * For this reason, you should do essentially no work at all from main().
390 * All startup initialisation should be done in startup. This avoids
391 * wasting work in the second-instance case where the program just exits
395 application_startup( GApplication
*application
)
397 static const gchar
*thisfn
= "fma_application_startup";
398 FMAApplicationPrivate
*priv
;
400 g_debug( "%s: application=%p", thisfn
, ( void * ) application
);
402 g_return_if_fail( application
&& FMA_IS_APPLICATION( application
));
403 priv
= FMA_APPLICATION( application
)->private;
405 /* chain up to the parent class */
406 if( G_APPLICATION_CLASS( st_parent_class
)->startup
){
407 G_APPLICATION_CLASS( st_parent_class
)->startup( application
);
410 /* create the FMAPivot object (loading the plugins and so on)
411 * after having dealt with command-line arguments
413 priv
->updater
= fma_updater_new();
414 fma_pivot_set_loadable( FMA_PIVOT( priv
->updater
), PIVOT_LOAD_ALL
);
416 /* define the application menu */
417 fma_menu_app( FMA_APPLICATION( application
));
421 * https://wiki.gnome.org/Projects/GLib/GApplication/Introduction
422 * https://wiki.gnome.org/HowDoI/GtkApplication
424 * activate is executed by GApplication when the application is "activated".
425 * This corresponds to the program being run from the command line, or when
426 * its icon is clicked on in an application launcher.
427 * From a semantic standpoint, activate should usually do one of two things,
428 * depending on the type of application.
430 * If your application is the type of application that deals with several
431 * documents at a time, in separate windows (and/or tabs) then activate
432 * should involve showing a window or creating a tab for a new document.
434 * If your application is more like the type of application with one primary
435 * main window then activate should usually involve raising this window with
436 * gtk_window_present(). It is the choice of the application in this case if
437 * the window itself is constructed in startup or on the first execution of
440 * activate is potentially called many times in a process or maybe never.
441 * If the process is started without files to open then activate will be run
442 * after startup. It may also be run again if a second instance of the
443 * process is started.
446 application_activate( GApplication
*application
)
448 static const gchar
*thisfn
= "fma_application_activate";
449 FMAApplicationPrivate
*priv
;
451 FMAMainWindow
*main_window
;
453 g_debug( "%s: application=%p", thisfn
, ( void * ) application
);
455 g_return_if_fail( application
&& FMA_IS_APPLICATION( application
));
457 priv
= FMA_APPLICATION( application
)->private;
458 windows_list
= gtk_application_get_windows( GTK_APPLICATION( application
));
460 /* if the application is unique, have only one main window */
461 if( !st_non_unique_opt
){
462 if( !g_list_length( windows_list
)){
463 main_window
= fma_main_window_new( FMA_APPLICATION( application
));
464 g_debug( "%s: main window instanciated at %p", thisfn
, main_window
);
466 main_window
= ( FMAMainWindow
* ) windows_list
->data
;
469 /* have as many main windows we want */
471 main_window
= fma_main_window_new( FMA_APPLICATION( application
));
474 g_return_if_fail( main_window
&& FMA_IS_MAIN_WINDOW( main_window
));
476 priv
->main_window
= main_window
;
478 gtk_window_present( GTK_WINDOW( main_window
));
482 * https://wiki.gnome.org/Projects/GLib/GApplication/Introduction
484 * open is similar to activate, but it is used when some files have been
485 * passed to the application to open.
486 * In fact, you could think of activate as a special case of open: the
487 * one with zero files.
488 * Similar to activate, open should create a window or tab. It should
489 * open the file in this window. If multiple files are given, possibly
490 * several windows should be opened.
491 * open will only be invoked in the case that your application declares
492 * that it supports opening files with the G_APPLICATION_HANDLES_OPEN
495 * Openbook: as the G_APPLICATION_HANDLES_OPEN flag is not set, then
496 * this function should never be called.
499 application_open( GApplication
*application
, GFile
**files
, gint n_files
, const gchar
*hint
)
501 static const gchar
*thisfn
= "fma_application_open";
503 g_warning( "%s: application=%p, n_files=%d, hint=%s: unexpected run here",
504 thisfn
, ( void * ) application
, n_files
, hint
);
508 * fma_application_get_application_name:
509 * @application: this #FMAApplication instance.
511 * Returns: the application name as a newly allocated string which should
512 * be be g_free() by the caller.
515 fma_application_get_application_name( const FMAApplication
*application
)
517 FMAApplicationPrivate
*priv
;
520 g_return_val_if_fail( application
&& FMA_IS_APPLICATION( application
), NULL
);
522 priv
= application
->private;
524 if( !priv
->dispose_has_run
){
526 name
= g_strdup( priv
->application_name
);
533 * fma_application_get_updater:
534 * @application: this FMAApplication object.
536 * Returns a pointer on the #FMAUpdater object.
538 * The returned pointer is owned by the #FMAApplication object.
539 * It should not be g_free() not g_object_unref() by the caller.
542 fma_application_get_updater( const FMAApplication
*application
)
544 FMAApplicationPrivate
*priv
;
545 FMAUpdater
*updater
= NULL
;
547 g_return_val_if_fail( application
&& FMA_IS_APPLICATION( application
), NULL
);
549 priv
= application
->private;
551 if( !priv
->dispose_has_run
){
553 updater
= priv
->updater
;
560 * fma_application_get_main_window:
561 * @application: this FMAApplication object.
563 * Returns: the main window.
566 fma_application_get_main_window( FMAApplication
*application
)
568 FMAApplicationPrivate
*priv
;
570 g_return_val_if_fail( application
&& FMA_IS_APPLICATION( application
), NULL
);
572 priv
= application
->private;
574 if( !priv
->dispose_has_run
){
576 return( GTK_WINDOW( priv
->main_window
));