/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "platform/linux/linux_open_with_dialog.h" #include "platform/linux/linux_gtk_integration_p.h" #include "platform/linux/linux_gdk_helper.h" #include "window/window_controller.h" #include "core/application.h" #include namespace Platform { namespace File { namespace internal { namespace { using namespace Platform::Gtk; bool OpenWithDialogSupported() { return Platform::internal::GdkHelperLoaded() && (gtk_app_chooser_dialog_new != nullptr) && (gtk_app_chooser_get_app_info != nullptr) && (gtk_app_chooser_get_type != nullptr) && (gtk_widget_get_window != nullptr) && (gtk_widget_realize != nullptr) && (gtk_widget_show != nullptr) && (gtk_widget_destroy != nullptr); } class OpenWithDialog : public QWindow { public: OpenWithDialog(const QString &filepath); ~OpenWithDialog(); bool exec(); private: static void handleResponse(OpenWithDialog *dialog, int responseId); GFile *_gfileInstance = nullptr; GtkWidget *_gtkWidget = nullptr; QEventLoop _loop; std::optional _result; }; OpenWithDialog::OpenWithDialog(const QString &filepath) : _gfileInstance(g_file_new_for_path(filepath.toUtf8())) , _gtkWidget(gtk_app_chooser_dialog_new( nullptr, GTK_DIALOG_MODAL, _gfileInstance)) { g_signal_connect_swapped( _gtkWidget, "response", G_CALLBACK(handleResponse), this); } OpenWithDialog::~OpenWithDialog() { gtk_widget_destroy(_gtkWidget); g_object_unref(_gfileInstance); } bool OpenWithDialog::exec() { gtk_widget_realize(_gtkWidget); if (const auto activeWindow = Core::App().activeWindow()) { Platform::internal::XSetTransientForHint( gtk_widget_get_window(_gtkWidget), activeWindow->widget().get()->windowHandle()->winId()); } QGuiApplicationPrivate::showModalWindow(this); gtk_widget_show(_gtkWidget); if (!_result.has_value()) { _loop.exec(); } QGuiApplicationPrivate::hideModalWindow(this); return *_result; } void OpenWithDialog::handleResponse(OpenWithDialog *dialog, int responseId) { GAppInfo *chosenAppInfo = nullptr; dialog->_result = true; switch (responseId) { case GTK_RESPONSE_OK: chosenAppInfo = gtk_app_chooser_get_app_info( gtk_app_chooser_cast(dialog->_gtkWidget)); if (chosenAppInfo) { GList *uris = nullptr; uris = g_list_prepend(uris, g_file_get_uri(dialog->_gfileInstance)); g_app_info_launch_uris(chosenAppInfo, uris, nullptr, nullptr); g_list_free(uris); g_object_unref(chosenAppInfo); } break; case GTK_RESPONSE_CANCEL: case GTK_RESPONSE_DELETE_EVENT: break; default: dialog->_result = false; break; } dialog->_loop.quit(); } } // namespace bool ShowOpenWithDialog(const QString &filepath) { if (!OpenWithDialogSupported()) { return false; } return OpenWithDialog(filepath).exec(); } } // namespace internal } // namespace File } // namespace Platform