Control GtkOpenWithDialog lifetime from outside

This commit is contained in:
Ilya Fedin 2021-07-03 05:48:35 +04:00 committed by John Preston
parent aece7c1096
commit 75ff7a6637
3 changed files with 73 additions and 44 deletions

View file

@ -154,11 +154,28 @@ void GtkIntegration::Private::handleMethodCall(
const auto filepath = base::Platform::GlibVariantCast< const auto filepath = base::Platform::GlibVariantCast<
Glib::ustring>(parametersCopy.get_child(1)); Glib::ustring>(parametersCopy.get_child(1));
const auto result = File::internal::ShowGtkOpenWithDialog( const auto dialog = File::internal::CreateGtkOpenWithDialog(
QString::fromStdString(parent), QString::fromStdString(parent),
QString::fromStdString(filepath)); QString::fromStdString(filepath)).release();
if (dialog) {
dialog->response(
) | rpl::start_with_next([=](bool response) {
try {
connection->emit_signal(
std::string(kObjectPath),
std::string(kInterface),
"OpenWithDialogResponse",
parentDBusName,
base::Platform::MakeGlibVariant(std::tuple{
response,
}));
} catch (...) {
}
delete dialog;
}, dialog->lifetime());
if (result) {
invocation->return_value({}); invocation->return_value({});
return; return;
} }
@ -340,23 +357,6 @@ int GtkIntegration::exec(const QString &parentDBusName, int ppid) {
_private->introspectionData->lookup_interface(), _private->introspectionData->lookup_interface(),
_private->interfaceVTable); _private->interfaceVTable);
rpl::lifetime lifetime;
File::internal::GtkOpenWithDialogResponse(
) | rpl::start_with_next([=](bool response) {
try {
_private->dbusConnection->emit_signal(
std::string(kObjectPath),
std::string(kInterface),
"OpenWithDialogResponse",
_private->parentDBusName,
base::Platform::MakeGlibVariant(std::tuple{
response,
}));
} catch (...) {
}
}, lifetime);
const auto app = Gio::Application::create(_private->serviceName); const auto app = Gio::Application::create(_private->serviceName);
app->hold(); app->hold();
_private->parentServiceWatcherId = base::Platform::DBus::RegisterServiceWatcher( _private->parentServiceWatcherId = base::Platform::DBus::RegisterServiceWatcher(
@ -459,21 +459,24 @@ bool GtkIntegration::showOpenWithDialog(const QString &filepath) const {
return false; return false;
} }
if (!File::internal::ShowGtkOpenWithDialog(parent, filepath)) { const auto dialog = File::internal::CreateGtkOpenWithDialog(
parent,
filepath);
if (!dialog) {
return false; return false;
} }
const auto context = Glib::MainContext::create(); const auto context = Glib::MainContext::create();
const auto loop = Glib::MainLoop::create(context); const auto loop = Glib::MainLoop::create(context);
g_main_context_push_thread_default(context->gobj()); g_main_context_push_thread_default(context->gobj());
rpl::lifetime lifetime;
bool result = false; bool result = false;
File::internal::GtkOpenWithDialogResponse( dialog->response(
) | rpl::start_with_next([&](bool response) { ) | rpl::start_with_next([&](bool response) {
result = response; result = response;
loop->quit(); loop->quit();
}, lifetime); }, dialog->lifetime());
QWindow window; QWindow window;
QGuiApplicationPrivate::showModalWindow(&window); QGuiApplicationPrivate::showModalWindow(&window);

View file

@ -19,8 +19,6 @@ namespace {
using namespace Platform::Gtk; using namespace Platform::Gtk;
rpl::event_stream<bool> GtkOpenWithDialogResponseStream;
struct GtkWidgetDeleter { struct GtkWidgetDeleter {
void operator()(GtkWidget *widget) { void operator()(GtkWidget *widget) {
gtk_widget_destroy(widget); gtk_widget_destroy(widget);
@ -37,20 +35,25 @@ bool Supported() {
&& (gtk_widget_destroy != nullptr); && (gtk_widget_destroy != nullptr);
} }
class GtkOpenWithDialog { } // namespace
class GtkOpenWithDialog::Private {
public: public:
GtkOpenWithDialog( Private(
const QString &parent, const QString &parent,
const QString &filepath); const QString &filepath);
private: private:
static void handleResponse(GtkOpenWithDialog *dialog, int responseId); friend class GtkOpenWithDialog;
static void handleResponse(Private *dialog, int responseId);
const Glib::RefPtr<Gio::File> _file; const Glib::RefPtr<Gio::File> _file;
const std::unique_ptr<GtkWidget, GtkWidgetDeleter> _gtkWidget; const std::unique_ptr<GtkWidget, GtkWidgetDeleter> _gtkWidget;
rpl::event_stream<bool> _responseStream;
}; };
GtkOpenWithDialog::GtkOpenWithDialog( GtkOpenWithDialog::Private::Private(
const QString &parent, const QString &parent,
const QString &filepath) const QString &filepath)
: _file(Gio::File::create_for_path(filepath.toStdString())) : _file(Gio::File::create_for_path(filepath.toStdString()))
@ -73,7 +76,7 @@ GtkOpenWithDialog::GtkOpenWithDialog(
gtk_widget_show(_gtkWidget.get()); gtk_widget_show(_gtkWidget.get());
} }
void GtkOpenWithDialog::handleResponse(GtkOpenWithDialog *dialog, int responseId) { void GtkOpenWithDialog::Private::handleResponse(Private *dialog, int responseId) {
Glib::RefPtr<Gio::AppInfo> chosenAppInfo; Glib::RefPtr<Gio::AppInfo> chosenAppInfo;
bool result = true; bool result = true;
@ -101,24 +104,29 @@ void GtkOpenWithDialog::handleResponse(GtkOpenWithDialog *dialog, int responseId
break; break;
} }
GtkOpenWithDialogResponseStream.fire_copy(result); dialog->_responseStream.fire_copy(result);
delete dialog;
} }
} // namespace GtkOpenWithDialog::GtkOpenWithDialog(
const QString &parent,
const QString &filepath)
: _private(std::make_unique<Private>(parent, filepath)) {
}
bool ShowGtkOpenWithDialog( GtkOpenWithDialog::~GtkOpenWithDialog() = default;
rpl::producer<bool> GtkOpenWithDialog::response() {
return _private->_responseStream.events();
}
std::unique_ptr<GtkOpenWithDialog> CreateGtkOpenWithDialog(
const QString &parent, const QString &parent,
const QString &filepath) { const QString &filepath) {
if (!Supported()) { if (!Supported()) {
return false; return nullptr;
} }
return new GtkOpenWithDialog(parent, filepath); return std::make_unique<GtkOpenWithDialog>(parent, filepath);
}
rpl::producer<bool> GtkOpenWithDialogResponse() {
return GtkOpenWithDialogResponseStream.events();
} }
} // namespace internal } // namespace internal

View file

@ -11,12 +11,30 @@ namespace Platform {
namespace File { namespace File {
namespace internal { namespace internal {
bool ShowGtkOpenWithDialog( class GtkOpenWithDialog {
public:
GtkOpenWithDialog(
const QString &parent,
const QString &filepath);
~GtkOpenWithDialog();
[[nodiscard]] rpl::producer<bool> response();
[[nodiscard]] rpl::lifetime &lifetime() {
return _lifetime;
}
private:
class Private;
const std::unique_ptr<Private> _private;
rpl::lifetime _lifetime;
};
[[nodiscard]] std::unique_ptr<GtkOpenWithDialog> CreateGtkOpenWithDialog(
const QString &parent, const QString &parent,
const QString &filepath); const QString &filepath);
[[nodiscard]] rpl::producer<bool> GtkOpenWithDialogResponse();
} // namespace internal } // namespace internal
} // namespace File } // namespace File
} // namespace Platform } // namespace Platform