From: Colin Clark Date: Sun, 3 Dec 2023 13:29:39 +0000 (+0000) Subject: Open With feature X-Git-Tag: v2.2~27 X-Git-Url: http://geeqie.org/cgi-bin/gitweb.cgi?p=geeqie.git;a=commitdiff_plain;h=022e9b12e84460cc56a140ffbbd12e3bd1027ade Open With feature The File menu has an Open With menu item, and there is an Open With plugin. In both cases the standard GTK application chooser dialog is called. --- diff --git a/plugins/meson.build b/plugins/meson.build index 65d55bb7..503c94c4 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -16,6 +16,7 @@ subdir('export-jpeg') subdir('geocode-parameters') subdir('image-crop') subdir('lens') +subdir('open-with') subdir('random-image') subdir('resize-image') subdir('rotate') diff --git a/plugins/open-with/meson.build b/plugins/open-with/meson.build new file mode 100644 index 00000000..4f533f5d --- /dev/null +++ b/plugins/open-with/meson.build @@ -0,0 +1,21 @@ +# This file is a part of Geeqie project (https://www.geeqie.org/). +# Copyright (C) 2008 - 2023 The Geeqie Team +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# + +i18n.merge_file( + input : 'org.geeqie.open-with.desktop.in', + output : 'org.geeqie.open-with.desktop', + type : 'desktop', + po_dir : podir, + install : true, + install_dir : desktopdir) + diff --git a/plugins/open-with/org.geeqie.open-with.desktop.in b/plugins/open-with/org.geeqie.open-with.desktop.in new file mode 100644 index 00000000..5e3677c9 --- /dev/null +++ b/plugins/open-with/org.geeqie.open-with.desktop.in @@ -0,0 +1,16 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Name=Open With +Comment=Call the gtk application chooser dialog + +Exec=geeqie --remote --action:OpenWith %f + +# Desktop files that are usable only in Geeqie should be marked like this: +Categories=X-Geeqie; +OnlyShowIn=X-Geeqie; + +# It can be made verbose +# X-Geeqie-Verbose=true + +Icon=geeqie diff --git a/src/layout-util.cc b/src/layout-util.cc index 8dfac9cc..062c4c4c 100644 --- a/src/layout-util.cc +++ b/src/layout-util.cc @@ -904,6 +904,95 @@ static void layout_menu_view_in_new_window_cb(GtkAction *, gpointer data) view_window_new(layout_image_get_fd(lw)); } +struct OpenWithData +{ + GAppInfo *application; + GList *g_file_list; + GtkWidget *app_chooser_dialog; +}; + +void open_with_response_cb(GtkDialog *, gint response_id, gpointer data) +{ + GError *error = NULL; + auto open_with_data = static_cast(data); + + if (response_id == GTK_RESPONSE_OK) + { + g_app_info_launch(open_with_data->application, open_with_data->g_file_list, nullptr, &error); + + if (error) + { + log_printf("Error launching app: %s\n", error->message); + g_error_free(error); + } + } + + g_object_unref(open_with_data->application); + g_object_unref(g_list_first(open_with_data->g_file_list)->data); + g_list_free(open_with_data->g_file_list); + gtk_widget_destroy(GTK_WIDGET(open_with_data->app_chooser_dialog)); + g_free(open_with_data); +} + +static void open_with_application_selected_cb(GtkAppChooserWidget *, GAppInfo *application, gpointer data) +{ + auto open_with_data = static_cast(data); + + g_object_unref(open_with_data->application); + + open_with_data->application = g_app_info_dup(application); +} + +static void open_with_application_activated_cb(GtkAppChooserWidget *, GAppInfo *application, gpointer data) +{ + GError *error = NULL; + auto open_with_data = static_cast(data); + + g_app_info_launch(application, open_with_data->g_file_list, nullptr, &error); + + if (error) + { + log_printf("Error launching app.: %s\n", error->message); + g_error_free(error); + } + + g_object_unref(open_with_data->application); + g_object_unref(g_list_first(open_with_data->g_file_list)->data); + g_list_free(open_with_data->g_file_list); + gtk_widget_destroy(GTK_WIDGET(open_with_data->app_chooser_dialog)); + g_free(open_with_data); +} + +static void layout_menu_open_with_cb(GtkAction *, gpointer data) +{ + auto lw = static_cast(data); + FileData *fd; + GtkWidget *widget; + OpenWithData *open_with_data; + + if (layout_selection_list(lw)) + { + open_with_data = g_new(OpenWithData, 1); + + fd = static_cast(g_list_first(layout_selection_list(lw))->data); + + open_with_data->g_file_list = g_list_append(nullptr, g_file_new_for_path(fd->path)); + + open_with_data->app_chooser_dialog = gtk_app_chooser_dialog_new(nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, G_FILE(g_list_first(open_with_data->g_file_list)->data)); + + widget = gtk_app_chooser_dialog_get_widget(GTK_APP_CHOOSER_DIALOG(open_with_data->app_chooser_dialog)); + + open_with_data->application = gtk_app_chooser_get_app_info(GTK_APP_CHOOSER(open_with_data->app_chooser_dialog)); + + g_signal_connect(G_OBJECT(widget), "application-selected", G_CALLBACK(open_with_application_selected_cb), open_with_data); + g_signal_connect(G_OBJECT(widget), "application-activated", G_CALLBACK(open_with_application_activated_cb), open_with_data); + g_signal_connect(G_OBJECT(open_with_data->app_chooser_dialog), "response", G_CALLBACK(open_with_response_cb), open_with_data); + g_signal_connect(G_OBJECT(open_with_data->app_chooser_dialog), "close", G_CALLBACK(open_with_response_cb), open_with_data); + + gtk_widget_show(open_with_data->app_chooser_dialog); + } +} + static void layout_menu_open_archive_cb(GtkAction *, gpointer data) { auto lw = static_cast(data); @@ -2608,6 +2697,7 @@ static GtkActionEntry menu_entries[] = { { "OpenArchive", GQ_ICON_OPEN, N_("Open archive"), nullptr, N_("Open archive"), CB(layout_menu_open_archive_cb) }, { "OpenCollection", GQ_ICON_OPEN, N_("_Open collection..."), "O", N_("Open collection..."), nullptr }, { "OpenRecent", nullptr, N_("Open recen_t"), nullptr, N_("Open recent collection"), nullptr }, + { "OpenWith", GQ_ICON_OPEN_WITH, N_("Open With..."), nullptr, N_("Open With..."), CB(layout_menu_open_with_cb) }, { "OrientationMenu", nullptr, N_("_Orientation"), nullptr, nullptr, nullptr }, { "OverlayMenu", nullptr, N_("Image _Overlay"), nullptr, nullptr, nullptr }, { "PanView", PIXBUF_INLINE_ICON_PANORAMA, N_("Pa_n view"), "J", N_("Pan view"), CB(layout_menu_pan_cb) }, diff --git a/src/main.h b/src/main.h index 3ec5c70e..79fa7ccb 100644 --- a/src/main.h +++ b/src/main.h @@ -138,6 +138,7 @@ #define GQ_ICON_UNDO "edit-undo" #define GQ_ICON_REDO "edit-redo" #define GQ_ICON_OPEN "document-open" +#define GQ_ICON_OPEN_WITH "open-menu" #define GQ_ICON_SAVE "document-save" #define GQ_ICON_SAVE_AS "document-save-as" #define GQ_ICON_NEW "document-new" diff --git a/src/ui/menu.ui b/src/ui/menu.ui index 56e8a86d..a0f081ba 100644 --- a/src/ui/menu.ui +++ b/src/ui/menu.ui @@ -17,6 +17,7 @@ +