gtk4 removed the blocking behavior of GtkDialogs
:
int res = gtk_dialog_run(GTK_DIALOG(dialog));
The proposed alternative is, to make the Dialog modal and connect the "response"
signal.
But this has a big draw back: Some old code bases have a linear and deterministic CFG. Changing only the way all dialogs are called and handled leads to the fact, that code can be wrong after leaving the scope, if the processing of the dialog was expected in the outer scopes.
To circumvent this, I used std::promise
and std::future
but this will block the gtk-event loop :/.
My proposed solution would be, to "join" the gtk-event-loop until the result is ready. This will have the advantages of both aproaches: "Do not stop the world" / handle event-loop and keep the linear CFG. But it has the disadvantage, that it can lead to a stack overflow or starvation when calling the join recursively.
Pseudocode of proposed/searched solution:
auto future_result = generate_future_for_dialog_result(dialog);
while(!future_result.isDone()){
g_join();
}
My first not working approach:
auto wait_for_gtk_dialog_result =
[](GtkDialog* dialog) {
std::promise<int> promise;
auto future = promise.get_future();
g_signal_connect(dialog, "result",
GCallback(+[](GtkDialog* /*self*/, int result, std::promise<int>* promise) {
promise->set_value(result);
}),
&promise);
return future.get();
};
Is there a function to join the event loop?
If not; is there a good alternative to achieve similar?
Edit:
Found a promising approach in the documentation:
Look at the g_main_context_iteration
.
auto wait_for_gtk_dialog_result =
[](GtkDialog* dialog) {
std::promise<int> promise;
auto future = promise.get_future();
g_signal_connect(dialog, "result",
GCallback(+[](GtkDialog* /*self*/, int result, std::promise<int>* promise) {
promise->set_value(result);
}),
&promise);
do {
g_main_context_iteration(g_main_context_default(), false);
} while (future.wait_for(std::chrono::milliseconds(1)) != std::future_status::ready);
return future.get();
};