tdesktop/Telegram/SourceFiles/platform/linux/linux_open_with_dialog.cpp

133 lines
3.0 KiB
C++

/*
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 <private/qguiapplication_p.h>
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<bool> _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