diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index ed6a0b364..3ca04dc2b 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -135,6 +135,7 @@ set(NONCLISOURCEFILES retinex.cc rgbcurves.cc rotate.cc + rtappchooserdialog.cc rtimage.cc rtscalable.cc rtsurface.cc diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 775e6a935..6cb90a444 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -39,6 +39,7 @@ #include "procparamchangers.h" #include "placesbrowser.h" #include "pathutils.h" +#include "rtappchooserdialog.h" #include "thumbnail.h" #include "toolpanelcoord.h" @@ -2014,7 +2015,7 @@ void EditorPanel::sendToExternalPressed() { if (options.externalEditorIndex == -1) { // "Other" external editor. Show app chooser dialog to let user pick. - Gtk::AppChooserDialog *dialog = getAppChooserDialog(); + RTAppChooserDialog *dialog = getAppChooserDialog(); dialog->show(); } else { struct ExternalEditor editor = options.externalEditors.at(options.externalEditorIndex); @@ -2195,10 +2196,10 @@ bool EditorPanel::idle_sentToGimp (ProgressConnector *pc, rtengine::IImagef return false; } -Gtk::AppChooserDialog *EditorPanel::getAppChooserDialog() +RTAppChooserDialog *EditorPanel::getAppChooserDialog() { if (!app_chooser_dialog.get()) { - app_chooser_dialog.reset(new Gtk::AppChooserDialog("image/tiff")); + app_chooser_dialog.reset(new RTAppChooserDialog("image/tiff")); app_chooser_dialog->signal_response().connect( sigc::mem_fun(*this, &EditorPanel::onAppChooserDialogResponse) ); diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 1bbb95a6e..e822f1677 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -46,6 +46,7 @@ class FilePanel; class MyProgressBar; class Navigator; class PopUpButton; +class RTAppChooserDialog; class Thumbnail; class ToolPanelCoordinator; @@ -212,7 +213,7 @@ private: bool idle_sendToGimp ( ProgressConnector *pc, Glib::ustring fname); bool idle_sentToGimp (ProgressConnector *pc, rtengine::IImagefloat* img, Glib::ustring filename); void histogramProfile_toggled (); - Gtk::AppChooserDialog *getAppChooserDialog(); + RTAppChooserDialog *getAppChooserDialog(); void onAppChooserDialogResponse(int resposneId); void updateExternalEditorSelection(); @@ -249,7 +250,7 @@ private: Gtk::Button* navNext; Gtk::Button* navPrev; Glib::RefPtr external_editor_info; - std::unique_ptr app_chooser_dialog; + std::unique_ptr app_chooser_dialog; ExternalEditorChangedSignal *externalEditorChangedSignal; sigc::connection externalEditorChangedSignalConnection; diff --git a/rtgui/externaleditorpreferences.cc b/rtgui/externaleditorpreferences.cc index df6b6efc2..b64cdcf9f 100644 --- a/rtgui/externaleditorpreferences.cc +++ b/rtgui/externaleditorpreferences.cc @@ -164,7 +164,7 @@ Gtk::TreeViewColumn *ExternalEditorPreferences::makeCommandColumn() } void ExternalEditorPreferences::onAppChooserDialogResponse( - int response_id, Gtk::AppChooserDialog *dialog) + int response_id, RTAppChooserDialog *dialog) { switch (response_id) { case Gtk::RESPONSE_OK: @@ -190,7 +190,7 @@ void ExternalEditorPreferences::openAppChooserDialog() return; } - app_chooser_dialog.reset(new Gtk::AppChooserDialog("image/tiff")); + app_chooser_dialog.reset(new RTAppChooserDialog("image/tiff")); app_chooser_dialog->signal_response().connect(sigc::bind( sigc::mem_fun(*this, &ExternalEditorPreferences::onAppChooserDialogResponse), app_chooser_dialog.get() diff --git a/rtgui/externaleditorpreferences.h b/rtgui/externaleditorpreferences.h index be988e901..dbd0f1648 100644 --- a/rtgui/externaleditorpreferences.h +++ b/rtgui/externaleditorpreferences.h @@ -18,7 +18,6 @@ */ #pragma once -#include #include #include #include @@ -26,6 +25,8 @@ #include #include +#include "rtappchooserdialog.h" + /** * Widget for editing the external editors options. @@ -98,7 +99,7 @@ private: Gtk::Button *button_app_chooser; Gtk::Button *button_add; Gtk::Button *button_remove; - std::unique_ptr app_chooser_dialog; + std::unique_ptr app_chooser_dialog; /** * Inserts a new editor entry after the current selection, or at the end if @@ -117,7 +118,7 @@ private: * Called when the user is done interacting with the app chooser dialog. * Closes the dialog and updates the selected entry if an app was chosen. */ - void onAppChooserDialogResponse(int responseId, Gtk::AppChooserDialog *dialog); + void onAppChooserDialogResponse(int responseId, RTAppChooserDialog *dialog); /** * Shows the app chooser dialog. */ diff --git a/rtgui/rtappchooserdialog.cc b/rtgui/rtappchooserdialog.cc new file mode 100644 index 000000000..50a71ee38 --- /dev/null +++ b/rtgui/rtappchooserdialog.cc @@ -0,0 +1,77 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 Lawrence Lee + * + * RawTherapee 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 3 of the License, or + * (at your option) any later version. + * + * RawTherapee 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 + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "rtappchooserdialog.h" + +#if !(defined WIN32 || defined __APPLE__) +#define GTKMM_APPCHOOSERDIALOG +#endif + +RTAppChooserDialog::~RTAppChooserDialog() {} + +#ifdef GTKMM_APPCHOOSERDIALOG // Use Gtk::AppChooserDialog directly. + +RTAppChooserDialog::RTAppChooserDialog(const Glib::ustring &content_type) : + Gtk::AppChooserDialog(content_type) +{ +} + +Glib::RefPtr RTAppChooserDialog::get_app_info() +{ + return Gtk::AppChooserDialog::get_app_info(); +} + +Glib::RefPtr RTAppChooserDialog::get_app_info() const +{ + return Gtk::AppChooserDialog::get_app_info(); +} + +#else // Work around bugs with GLib and glibmm. + +RTAppChooserDialog::RTAppChooserDialog(const Glib::ustring &content_type) : + Gtk::AppChooserDialog(content_type) +{ + // GTK calls a faulty GLib function to update the most recently selected + // application after an application is selected. This removes all signal + // handlers to prevent the function call. + auto signal_id = g_signal_lookup("response", GTK_TYPE_APP_CHOOSER_DIALOG); + while (true) { + auto handler_id = g_signal_handler_find(gobj(), G_SIGNAL_MATCH_ID, signal_id, GQuark(), nullptr, nullptr, nullptr); + if (!handler_id) { + break; + } + g_signal_handler_disconnect(gobj(), handler_id); + } +} + +Glib::RefPtr RTAppChooserDialog::get_app_info() +{ + // glibmm wrapping of GAppInfo does not work on some platforms. Manually + // wrap it here. + GAppInfo *gAppInfo = gtk_app_chooser_get_app_info(GTK_APP_CHOOSER(gobj())); + return Glib::wrap(gAppInfo, true); +} + +Glib::RefPtr RTAppChooserDialog::get_app_info() const +{ + GAppInfo *gAppInfo = gtk_app_chooser_get_app_info(GTK_APP_CHOOSER( + const_cast(gobj()))); + return Glib::wrap(gAppInfo, true); +} + +#endif diff --git a/rtgui/rtappchooserdialog.h b/rtgui/rtappchooserdialog.h new file mode 100644 index 000000000..9d0e3b041 --- /dev/null +++ b/rtgui/rtappchooserdialog.h @@ -0,0 +1,39 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 Lawrence Lee + * + * RawTherapee 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 3 of the License, or + * (at your option) any later version. + * + * RawTherapee 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 + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#pragma once + +#include +#include +#include +#include + +/** + * Custom version of gtkmm's Gtk::AppChooserDialog to work around crashes + * (https://gitlab.gnome.org/GNOME/glib/-/issues/1104 and + * https://gitlab.gnome.org/GNOME/glibmm/-/issues/94). + */ +class RTAppChooserDialog : public Gtk::AppChooserDialog +{ +public: + RTAppChooserDialog(const Glib::ustring &content_type); + ~RTAppChooserDialog(); + + Glib::RefPtr get_app_info(); + Glib::RefPtr get_app_info() const; +};