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<
Glib::ustring>(parametersCopy.get_child(1));
const auto result = File::internal::ShowGtkOpenWithDialog(
const auto dialog = File::internal::CreateGtkOpenWithDialog(
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({});
return;
}
@ -340,23 +357,6 @@ int GtkIntegration::exec(const QString &parentDBusName, int ppid) {
_private->introspectionData->lookup_interface(),
_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);
app->hold();
_private->parentServiceWatcherId = base::Platform::DBus::RegisterServiceWatcher(
@ -459,21 +459,24 @@ bool GtkIntegration::showOpenWithDialog(const QString &filepath) const {
return false;
}
if (!File::internal::ShowGtkOpenWithDialog(parent, filepath)) {
const auto dialog = File::internal::CreateGtkOpenWithDialog(
parent,
filepath);
if (!dialog) {
return false;
}
const auto context = Glib::MainContext::create();
const auto loop = Glib::MainLoop::create(context);
g_main_context_push_thread_default(context->gobj());
rpl::lifetime lifetime;
bool result = false;
File::internal::GtkOpenWithDialogResponse(
dialog->response(
) | rpl::start_with_next([&](bool response) {
result = response;
loop->quit();
}, lifetime);
}, dialog->lifetime());
QWindow window;
QGuiApplicationPrivate::showModalWindow(&window);

View File

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

View File

@ -11,12 +11,30 @@ namespace Platform {
namespace File {
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 &filepath);
[[nodiscard]] rpl::producer<bool> GtkOpenWithDialogResponse();
} // namespace internal
} // namespace File
} // namespace Platform