Convert to strictly non-unique GtkApplication
It's not pretty, but it works.
This commit is contained in:
parent
6a7c86a41b
commit
abf4f1a792
216
fiv.c
216
fiv.c
|
@ -2161,89 +2161,12 @@ output_thumbnail(gchar **uris, gboolean extract, const char *size_arg)
|
||||||
cairo_surface_destroy(surface);
|
cairo_surface_destroy(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static void
|
||||||
main(int argc, char *argv[])
|
on_app_startup(GApplication *app, G_GNUC_UNUSED gpointer user_data)
|
||||||
{
|
{
|
||||||
gboolean show_version = FALSE, show_supported_media_types = FALSE,
|
// We can't prevent GApplication from adding --gapplication-service.
|
||||||
invalidate_cache = FALSE, browse = FALSE, extract_thumbnail = FALSE;
|
if (g_application_get_flags(app) & G_APPLICATION_IS_SERVICE)
|
||||||
gchar **args = NULL, *thumbnail_size = NULL, *thumbnail_size_search = NULL;
|
exit(EXIT_FAILURE);
|
||||||
const GOptionEntry options[] = {
|
|
||||||
{G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args,
|
|
||||||
NULL, "[PATH | URI]..."},
|
|
||||||
{"browse", 0, G_OPTION_FLAG_IN_MAIN,
|
|
||||||
G_OPTION_ARG_NONE, &browse,
|
|
||||||
"Start in filesystem browsing mode", NULL},
|
|
||||||
{"invalidate-cache", 0, G_OPTION_FLAG_IN_MAIN,
|
|
||||||
G_OPTION_ARG_NONE, &invalidate_cache,
|
|
||||||
"Invalidate the wide thumbnail cache", NULL},
|
|
||||||
{"list-supported-media-types", 0, G_OPTION_FLAG_IN_MAIN,
|
|
||||||
G_OPTION_ARG_NONE, &show_supported_media_types,
|
|
||||||
"Output supported media types and exit", NULL},
|
|
||||||
{"version", 'V', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
|
|
||||||
&show_version, "Output version information and exit", NULL},
|
|
||||||
{},
|
|
||||||
};
|
|
||||||
const GOptionEntry options_internal[] = {
|
|
||||||
{"extract-thumbnail", 0, 0,
|
|
||||||
G_OPTION_ARG_NONE, &extract_thumbnail,
|
|
||||||
"Output any embedded thumbnail (superseding --thumbnail)", NULL},
|
|
||||||
{"thumbnail", 0, 0,
|
|
||||||
G_OPTION_ARG_STRING, &thumbnail_size,
|
|
||||||
"Generate thumbnails, up to SIZE, and output that size", "SIZE"},
|
|
||||||
{"thumbnail-for-search", 0, 0,
|
|
||||||
G_OPTION_ARG_STRING, &thumbnail_size_search,
|
|
||||||
"Output an image file suitable for searching by content", "SIZE"},
|
|
||||||
{},
|
|
||||||
};
|
|
||||||
|
|
||||||
GOptionContext *context =
|
|
||||||
g_option_context_new(" - Image browser and viewer");
|
|
||||||
g_option_context_add_group(context, gtk_get_option_group(TRUE));
|
|
||||||
g_option_context_add_main_entries(context, options, NULL);
|
|
||||||
|
|
||||||
GOptionGroup *internals = g_option_group_new(
|
|
||||||
"internal", "Internal Options:", "Show internal options", NULL, NULL);
|
|
||||||
g_option_group_add_entries(internals, options_internal);
|
|
||||||
g_option_context_add_group(context, internals);
|
|
||||||
|
|
||||||
GError *error = NULL;
|
|
||||||
gboolean initialized =
|
|
||||||
g_option_context_parse(context, &argc, &argv, &error);
|
|
||||||
g_option_context_free(context);
|
|
||||||
if (show_version) {
|
|
||||||
const char *version = PROJECT_VERSION;
|
|
||||||
printf("%s %s\n", PROJECT_NAME, &version[*version == 'v']);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (show_supported_media_types) {
|
|
||||||
char **types = fiv_io_all_supported_media_types();
|
|
||||||
for (char **p = types; *p; p++)
|
|
||||||
g_print("%s\n", *p);
|
|
||||||
g_strfreev(types);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (invalidate_cache) {
|
|
||||||
fiv_thumbnail_invalidate();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!initialized)
|
|
||||||
exit_fatal("%s", error->message);
|
|
||||||
|
|
||||||
// Normalize all arguments to URIs.
|
|
||||||
for (gsize i = 0; args && args[i]; i++) {
|
|
||||||
GFile *resolved = g_file_new_for_commandline_arg(args[i]);
|
|
||||||
g_free(args[i]);
|
|
||||||
args[i] = g_file_get_uri(resolved);
|
|
||||||
g_object_unref(resolved);
|
|
||||||
}
|
|
||||||
if (thumbnail_size_search) {
|
|
||||||
output_thumbnail_for_search(args, thumbnail_size_search);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (extract_thumbnail || thumbnail_size) {
|
|
||||||
output_thumbnail(args, extract_thumbnail, thumbnail_size);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// It doesn't make much sense to have command line arguments able to
|
// It doesn't make much sense to have command line arguments able to
|
||||||
// resolve to the VFS they may end up being contained within.
|
// resolve to the VFS they may end up being contained within.
|
||||||
|
@ -2346,9 +2269,9 @@ main(int argc, char *argv[])
|
||||||
gtk_container_add(GTK_CONTAINER(g.stack), g.view_box);
|
gtk_container_add(GTK_CONTAINER(g.stack), g.view_box);
|
||||||
gtk_container_add(GTK_CONTAINER(g.stack), g.browser_paned);
|
gtk_container_add(GTK_CONTAINER(g.stack), g.browser_paned);
|
||||||
|
|
||||||
g.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
g.window = gtk_application_window_new(GTK_APPLICATION(app));
|
||||||
g_signal_connect(g.window, "destroy",
|
g_signal_connect_swapped(g.window, "destroy",
|
||||||
G_CALLBACK(gtk_main_quit), NULL);
|
G_CALLBACK(g_application_quit), app);
|
||||||
g_signal_connect(g.window, "key-press-event",
|
g_signal_connect(g.window, "key-press-event",
|
||||||
G_CALLBACK(on_key_press), NULL);
|
G_CALLBACK(on_key_press), NULL);
|
||||||
g_signal_connect(g.window, "window-state-event",
|
g_signal_connect(g.window, "window-state-event",
|
||||||
|
@ -2399,24 +2322,34 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
// XXX: The widget wants to read the display's profile. The realize is ugly.
|
// XXX: The widget wants to read the display's profile. The realize is ugly.
|
||||||
gtk_widget_realize(g.view);
|
gtk_widget_realize(g.view);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
gboolean browse, extract_thumbnail;
|
||||||
|
gchar **args, *thumbnail_size, *thumbnail_size_search;
|
||||||
|
} o;
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_app_activate(
|
||||||
|
G_GNUC_UNUSED GApplication *app, G_GNUC_UNUSED gpointer user_data)
|
||||||
|
{
|
||||||
// XXX: We follow the behaviour of Firefox and Eye of GNOME, which both
|
// XXX: We follow the behaviour of Firefox and Eye of GNOME, which both
|
||||||
// interpret multiple command line arguments differently, as a collection.
|
// interpret multiple command line arguments differently, as a collection.
|
||||||
// However, single-element collections are unrepresentable this way.
|
// However, single-element collections are unrepresentable this way.
|
||||||
// Should we allow multiple targets only in a special new mode?
|
// Should we allow multiple targets only in a special new mode?
|
||||||
g.files_index = -1;
|
g.files_index = -1;
|
||||||
if (args) {
|
if (o.args) {
|
||||||
const gchar *target = *args;
|
const gchar *target = *o.args;
|
||||||
if (args[1]) {
|
if (o.args[1]) {
|
||||||
fiv_collection_reload(args);
|
fiv_collection_reload(o.args);
|
||||||
target = FIV_COLLECTION_SCHEME ":/";
|
target = FIV_COLLECTION_SCHEME ":/";
|
||||||
}
|
}
|
||||||
|
|
||||||
GFile *file = g_file_new_for_uri(target);
|
GFile *file = g_file_new_for_uri(target);
|
||||||
open_any_file(file, browse);
|
open_any_file(file, o.browse);
|
||||||
g_object_unref(file);
|
g_object_unref(file);
|
||||||
g_strfreev(args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g.directory) {
|
if (!g.directory) {
|
||||||
GFile *file = g_file_new_for_path(".");
|
GFile *file = g_file_new_for_path(".");
|
||||||
open_any_file(file, FALSE);
|
open_any_file(file, FALSE);
|
||||||
|
@ -2424,6 +2357,103 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
gtk_widget_show(g.window);
|
gtk_widget_show(g.window);
|
||||||
gtk_main();
|
}
|
||||||
return 0;
|
|
||||||
|
static gint
|
||||||
|
on_app_handle_local_options(G_GNUC_UNUSED GApplication *app,
|
||||||
|
GVariantDict *options, G_GNUC_UNUSED gpointer user_data)
|
||||||
|
{
|
||||||
|
if (g_variant_dict_contains(options, "version")) {
|
||||||
|
const char *version = PROJECT_VERSION;
|
||||||
|
printf("%s %s\n", PROJECT_NAME, &version[*version == 'v']);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (g_variant_dict_contains(options, "list-supported-media-types")) {
|
||||||
|
char **types = fiv_io_all_supported_media_types();
|
||||||
|
for (char **p = types; *p; p++)
|
||||||
|
g_print("%s\n", *p);
|
||||||
|
g_strfreev(types);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (g_variant_dict_contains(options, "invalidate-cache")) {
|
||||||
|
fiv_thumbnail_invalidate();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize all arguments to URIs, and run thumbnailing modes first.
|
||||||
|
for (gsize i = 0; o.args && o.args[i]; i++) {
|
||||||
|
GFile *resolved = g_file_new_for_commandline_arg(o.args[i]);
|
||||||
|
g_free(o.args[i]);
|
||||||
|
o.args[i] = g_file_get_uri(resolved);
|
||||||
|
g_object_unref(resolved);
|
||||||
|
}
|
||||||
|
|
||||||
|
// These come from an option group that doesn't get copied to "options".
|
||||||
|
if (o.thumbnail_size_search) {
|
||||||
|
output_thumbnail_for_search(o.args, o.thumbnail_size_search);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (o.extract_thumbnail || o.thumbnail_size) {
|
||||||
|
output_thumbnail(o.args, o.extract_thumbnail, o.thumbnail_size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
const GOptionEntry options[] = {
|
||||||
|
{G_OPTION_REMAINING, 0, 0,
|
||||||
|
G_OPTION_ARG_FILENAME_ARRAY, &o.args,
|
||||||
|
NULL, "[PATH | URI]..."},
|
||||||
|
{"browse", 0, G_OPTION_FLAG_IN_MAIN,
|
||||||
|
G_OPTION_ARG_NONE, &o.browse,
|
||||||
|
"Start in filesystem browsing mode", NULL},
|
||||||
|
{"invalidate-cache", 0, G_OPTION_FLAG_IN_MAIN,
|
||||||
|
G_OPTION_ARG_NONE, NULL,
|
||||||
|
"Invalidate the wide thumbnail cache", NULL},
|
||||||
|
{"list-supported-media-types", 0, G_OPTION_FLAG_IN_MAIN,
|
||||||
|
G_OPTION_ARG_NONE, NULL,
|
||||||
|
"Output supported media types and exit", NULL},
|
||||||
|
{"version", 'V', G_OPTION_FLAG_IN_MAIN,
|
||||||
|
G_OPTION_ARG_NONE, NULL,
|
||||||
|
"Output version information and exit", NULL},
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
const GOptionEntry options_internal[] = {
|
||||||
|
{"extract-thumbnail", 0, 0,
|
||||||
|
G_OPTION_ARG_NONE, &o.extract_thumbnail,
|
||||||
|
"Output any embedded thumbnail (superseding --thumbnail)", NULL},
|
||||||
|
{"thumbnail", 0, 0,
|
||||||
|
G_OPTION_ARG_STRING, &o.thumbnail_size,
|
||||||
|
"Generate thumbnails, up to SIZE, and output that size", "SIZE"},
|
||||||
|
{"thumbnail-for-search", 0, 0,
|
||||||
|
G_OPTION_ARG_STRING, &o.thumbnail_size_search,
|
||||||
|
"Output an image file suitable for searching by content", "SIZE"},
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
// We never get the ::open signal, thanks to G_OPTION_ARG_FILENAME_ARRAY.
|
||||||
|
GtkApplication *app = gtk_application_new(NULL, G_APPLICATION_NON_UNIQUE);
|
||||||
|
g_application_set_option_context_parameter_string(
|
||||||
|
G_APPLICATION(app), " - Image browser and viewer");
|
||||||
|
g_application_add_main_option_entries(G_APPLICATION(app), options);
|
||||||
|
|
||||||
|
GOptionGroup *internals = g_option_group_new(
|
||||||
|
"internal", "Internal Options:", "Show internal options", NULL, NULL);
|
||||||
|
g_option_group_add_entries(internals, options_internal);
|
||||||
|
g_application_add_option_group(G_APPLICATION(app), internals);
|
||||||
|
|
||||||
|
g_signal_connect(app, "handle-local-options",
|
||||||
|
G_CALLBACK(on_app_handle_local_options), NULL);
|
||||||
|
g_signal_connect(app, "startup",
|
||||||
|
G_CALLBACK(on_app_startup), NULL);
|
||||||
|
g_signal_connect(app, "activate",
|
||||||
|
G_CALLBACK(on_app_activate), NULL);
|
||||||
|
|
||||||
|
int status = g_application_run(G_APPLICATION(app), argc, argv);
|
||||||
|
g_object_unref(app);
|
||||||
|
g_strfreev(o.args);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue