Open With feature
authorColin Clark <colin.clark@cclark.uk>
Sun, 3 Dec 2023 13:29:39 +0000 (13:29 +0000)
committerColin Clark <colin.clark@cclark.uk>
Sun, 3 Dec 2023 13:29:39 +0000 (13:29 +0000)
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.

plugins/meson.build
plugins/open-with/meson.build [new file with mode: 0644]
plugins/open-with/org.geeqie.open-with.desktop.in [new file with mode: 0644]
src/layout-util.cc
src/main.h
src/ui/menu.ui

index 65d55bb..503c94c 100644 (file)
@@ -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 (file)
index 0000000..4f533f5
--- /dev/null
@@ -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 (file)
index 0000000..5e3677c
--- /dev/null
@@ -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
index 8dfac9c..062c4c4 100644 (file)
@@ -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<OpenWithData *>(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<OpenWithData *>(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<OpenWithData *>(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<LayoutWindow *>(data);
+       FileData *fd;
+       GtkWidget *widget;
+       OpenWithData *open_with_data;
+
+       if (layout_selection_list(lw))
+               {
+               open_with_data = g_new(OpenWithData, 1);
+
+               fd = static_cast<FileData *>(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<LayoutWindow *>(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"),                                        "<control>J",          N_("Pan view"),                                        CB(layout_menu_pan_cb) },
index 3ec5c70..79fa7cc 100644 (file)
 #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"
index 56e8a86..a0f081b 100644 (file)
@@ -17,6 +17,7 @@
       <menuitem action="Copy"/>
       <menuitem action="Move"/>
       <menuitem action="Rename"/>
+      <menuitem action="OpenWith"/>
       <separator/>
       <menuitem action="Delete"/>
       <menuitem action="PermanentDelete"/>