From 15a9842b9f7ba6e77356775b6d2695028c3afaa6 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Sat, 2 Jan 2021 07:52:06 +0400 Subject: [PATCH] Make open with dialog modal on Linux --- .../platform/linux/file_utilities_linux.cpp | 97 ++++++++++++------- .../SourceFiles/platform/linux/linux_libs.cpp | 2 - .../SourceFiles/platform/linux/linux_libs.h | 8 -- 3 files changed, 62 insertions(+), 45 deletions(-) diff --git a/Telegram/SourceFiles/platform/linux/file_utilities_linux.cpp b/Telegram/SourceFiles/platform/linux/file_utilities_linux.cpp index 0cc204e634..c5c1d0e72c 100644 --- a/Telegram/SourceFiles/platform/linux/file_utilities_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/file_utilities_linux.cpp @@ -45,45 +45,95 @@ bool ShowOpenWithSupported() { && (Libs::gtk_app_chooser_dialog_new != nullptr) && (Libs::gtk_app_chooser_get_app_info != nullptr) && (Libs::gtk_app_chooser_get_type != nullptr) - && (Libs::gtk_widget_get_type != nullptr) && (Libs::gtk_widget_get_window != nullptr) && (Libs::gtk_widget_realize != nullptr) && (Libs::gtk_widget_show != nullptr) && (Libs::gtk_widget_destroy != nullptr); } -void HandleAppChooserResponse( - GtkDialog *dialog, - int responseId, - GFile *file) { +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 = std::nullopt; +}; + +OpenWithDialog::OpenWithDialog(const QString &filepath) +: _gfileInstance(g_file_new_for_path(filepath.toUtf8())) +, _gtkWidget(Libs::gtk_app_chooser_dialog_new( + nullptr, + GTK_DIALOG_MODAL, + _gfileInstance)) { + g_signal_connect_swapped( + _gtkWidget, + "response", + G_CALLBACK(handleAppChooserResponse), + this); +} + +OpenWithDialog::~OpenWithDialog() { + Libs::gtk_widget_destroy(_gtkWidget); + g_object_unref(_gfileInstance); +} + +bool OpenWithDialog::exec() { + Libs::gtk_widget_realize(_gtkWidget); + + if (const auto activeWindow = Core::App().activeWindow()) { + Platform::internal::XSetTransientForHint( + Libs::gtk_widget_get_window(_gtkWidget), + activeWindow->widget().get()->windowHandle()->winId()); + } + + QGuiApplicationPrivate::showModalWindow(this); + Libs::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 = Libs::gtk_app_chooser_get_app_info( - Libs::gtk_app_chooser_cast(dialog)); + Libs::gtk_app_chooser_cast(dialog->_gtkWidget)); if (chosenAppInfo) { GList *uris = nullptr; - uris = g_list_prepend(uris, g_file_get_uri(file)); + 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); } - g_object_unref(file); - Libs::gtk_widget_destroy(Libs::gtk_widget_cast(dialog)); break; case GTK_RESPONSE_CANCEL: case GTK_RESPONSE_DELETE_EVENT: - g_object_unref(file); - Libs::gtk_widget_destroy(Libs::gtk_widget_cast(dialog)); break; default: + dialog->_result = false; break; } + + dialog->_loop.quit(); } #endif // !TDESKTOP_DISABLE_GTK_INTEGRATION @@ -141,30 +191,7 @@ bool UnsafeShowOpenWith(const QString &filepath) { } const auto absolutePath = QFileInfo(filepath).absoluteFilePath(); - auto gfileInstance = g_file_new_for_path(absolutePath.toUtf8()); - - auto appChooserDialog = Libs::gtk_app_chooser_dialog_new( - nullptr, - GTK_DIALOG_MODAL, - gfileInstance); - - g_signal_connect( - appChooserDialog, - "response", - G_CALLBACK(HandleAppChooserResponse), - gfileInstance); - - Libs::gtk_widget_realize(appChooserDialog); - - if (const auto activeWindow = Core::App().activeWindow()) { - Platform::internal::XSetTransientForHint( - Libs::gtk_widget_get_window(appChooserDialog), - activeWindow->widget().get()->windowHandle()->winId()); - } - - Libs::gtk_widget_show(appChooserDialog); - - return true; + return OpenWithDialog(absolutePath).exec(); #else // !TDESKTOP_DISABLE_GTK_INTEGRATION return false; #endif // TDESKTOP_DISABLE_GTK_INTEGRATION diff --git a/Telegram/SourceFiles/platform/linux/linux_libs.cpp b/Telegram/SourceFiles/platform/linux/linux_libs.cpp index 244c99616c..2dbddebb8c 100644 --- a/Telegram/SourceFiles/platform/linux/linux_libs.cpp +++ b/Telegram/SourceFiles/platform/linux/linux_libs.cpp @@ -74,7 +74,6 @@ bool setupGtkBase(QLibrary &lib_gtk) { if (!LOAD_SYMBOL(lib_gtk, "gtk_widget_realize", gtk_widget_realize)) return false; if (!LOAD_SYMBOL(lib_gtk, "gtk_widget_hide_on_delete", gtk_widget_hide_on_delete)) return false; if (!LOAD_SYMBOL(lib_gtk, "gtk_widget_destroy", gtk_widget_destroy)) return false; - if (!LOAD_SYMBOL(lib_gtk, "gtk_widget_get_type", gtk_widget_get_type)) return false; if (!LOAD_SYMBOL(lib_gtk, "gtk_clipboard_get", gtk_clipboard_get)) return false; if (!LOAD_SYMBOL(lib_gtk, "gtk_clipboard_store", gtk_clipboard_store)) return false; if (!LOAD_SYMBOL(lib_gtk, "gtk_clipboard_wait_for_contents", gtk_clipboard_wait_for_contents)) return false; @@ -236,7 +235,6 @@ f_gtk_widget_get_window gtk_widget_get_window = nullptr; f_gtk_widget_realize gtk_widget_realize = nullptr; f_gtk_widget_hide_on_delete gtk_widget_hide_on_delete = nullptr; f_gtk_widget_destroy gtk_widget_destroy = nullptr; -f_gtk_widget_get_type gtk_widget_get_type = nullptr; f_gtk_clipboard_get gtk_clipboard_get = nullptr; f_gtk_clipboard_store gtk_clipboard_store = nullptr; f_gtk_clipboard_wait_for_contents gtk_clipboard_wait_for_contents = nullptr; diff --git a/Telegram/SourceFiles/platform/linux/linux_libs.h b/Telegram/SourceFiles/platform/linux/linux_libs.h index fa651615de..b9661512b4 100644 --- a/Telegram/SourceFiles/platform/linux/linux_libs.h +++ b/Telegram/SourceFiles/platform/linux/linux_libs.h @@ -235,14 +235,6 @@ inline GtkWindow *gtk_window_cast(Object *obj) { return g_type_cic_helper(obj, gtk_window_get_type()); } -typedef GType (*f_gtk_widget_get_type)(void) G_GNUC_CONST; -extern f_gtk_widget_get_type gtk_widget_get_type; - -template -inline GtkWidget *gtk_widget_cast(Object *obj) { - return g_type_cic_helper(obj, gtk_widget_get_type()); -} - typedef GType (*f_gtk_app_chooser_get_type)(void) G_GNUC_CONST; extern f_gtk_app_chooser_get_type gtk_app_chooser_get_type;