Gtk4 - migrating from Gtk3 - help with GtkDialogs

Dear all,
thank you in advance for reading me, and hopefully helping out with my problem.
As mentioned above I am migrating my program to GTK4, and I am having some troubles
with the GtkDialog, in particular because the ‘gtk_dialog_run’ command has been removed.
I have already browse the discussion threads and I have seen that this has been discussed but
not in the way I need, so I will be more specific for my purpose.
In my program I often use GtkDialog to ask for user input, find here a short piece of code
that is suppose to handle thing for GTK3 or GTK4 depending on the use of -DGTK4 at build:

void add_box_child_start (GtkWidget * widg, GtkWidget * child, gboolean expand, gboolean fill, int padding)
{
#ifdef GTK4
  gtk_box_append (GTK_BOX(widg), child);
#else
  gtk_box_pack_start (GTK_BOX(widg), child, expand, fill, padding);
#endif
}

GtkWidget * create_entry (GCallback handler_a,  GCallback handler_b,  gboolean key_release,  gpointer data)
{
  GtkWidget * entry = gtk_entry_new ();
  gtk_entry_set_alignment (GTK_ENTRY(entry), 1.0);

  if (handler_a != NULL) g_signal_connect (G_OBJECT (entry), "activate", handler_a, data);
#ifdef GTK4
  if (key_release) g_signal_connect (G_OBJECT (entry),  "changed", handler_b, data);
#else
  if (handler_b != NULL) g_signal_connect (G_OBJECT (entry), "focus-out-event", handler_b, data);
  if (key_release) g_signal_connect (G_OBJECT (entry), "key-release-event", handler_b, data);
#endif
  return entry;
}

int user_param;

const gchar * entry_get_text (GtkEntry * entry)
{
#ifdef GTK4
  return gtk_editable_get_text (GTK_EDITABLE(entry));
#else
  return gtk_entry_get_text (entry);
#endif
}

G_MODULE_EXPORT void set_param (GtkEntry * entry, gpointer data)
{
  int c = GPOINTER_TO_INT(data);
  const gchar * m = entry_get_text (entry);
  double v = atof(m);
  user_param = (int) v;
}

#ifdef GTK4
G_MODULE_EXPORT void to_get_param (GtkEditable * widg, gpointer data)
#else
G_MODULE_EXPORT gboolean to_get_param (GtkWidget * widg, GdkEventFocus * event, gpointer data)
#endif
{
  get_param (GTK_ENTRY(widg), data);
#ifndef GTK4
  return FALSE;
#endif
}

G_MODULE_EXPORT void run_get_param (GtkDialog * dial, gint response_id, gpointer data)
{
   destroy_this_widget (GTK_WIDGET(dial));
}

int get_param_from_user ()
{
  GtkWidget * dialog = gtk_dialog_new ();
  GtkWidget * entry;
  GtkWidget * vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
  GtkWidget *  hbox;
  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL,  0);
  add_box_child_start (vbox, hbox, FALSE, FALSE, 5);
  add_box_child_start (hbox, gtk_label_new("Enter value here:"), FALSE, FALSE, 5);
  entry = create_entry (G_CALLBACK (get_param), G_CALLBACK (to_get_param));
  add_box_child_start (hbox, entry, FALSE, FALSE, 5);
  user_param = -1;

  gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
  g_signal_connect (G_OBJECT(dialog), "response", G_CALLBACK(run_get_param), NULL);
  show_the_widgets (dial);

// Here comes the issue: 
/* 
 Previously with GTK3 only I add something that looked like:
  if (gtk_dialog_run (dialog) ==  GTK_RESPONSE_ACCEPT)
  {
    return user_param;
  }
  else
  {
    return -1;
  } 
It was easy to ask to get a reponse before moving forward.
*/ 
 // Now the following does not work, and I am kind of stuck:
  return user_param;
}

int param =  get_param_from_user ();

So how could I write that return function “int get_param_from_user ()” to get that value from a GTK4 dialog using only the “response” signal for the GtkDialog ?

Thanks in advance for your help.

Sébastien

My guess is that your problem is that the dialog callback function does not return a result?

But you can pass an optional parameter to the callback function. In C you may pass a struct, and the callback function may modify the fields of that struct. Here is the shape of the callback user function:

https://developer-old.gnome.org/gtk4/stable/GtkDialog.html#GtkDialog-response

Of course you have somehow to access that struct later where you need it. An option may be to subclass the GtkApplicationWindow and pass that whole instance around.

Another way would be to use some global variables, which you can access always. Some of the GTK C examples use global variables, but I personally try to avoid them.

First of all, if you are blocking on a Dialog to get some user feedback you may want to reconsider your UI. Popping up a whole new modal dialog just to get some data isn’t the greatest user experience, as you’re literally preventing any other interaction with the application. You may want to look at widgets like GtkPopover, instead.

Looking at your code example, I see a fairly convoluted hodgepodge of linear state, like you would do if you write a shell script, or a command line tool; this is not how GUI applications are generally written.

If you want to maintain the same user interaction model, then you have two options: one is to connect to the GtkDialog::response signal, and pass some structured data closure to the signal callback; in the closure you’d store some global state, and then update your UI depending on the state.

The other option is to create your own nested main loop, and essentially open code gtk_dialog_run(). You can use GMainLoop to spin up a main loop after presenting the dialog, and have the response signal set a global variable and stopping the main loop; after g_main_loop_run() returns, you can read the global variable.

Thank you for your answer,
actually the problem comes from the fact that the function does not wait for the dialog to close to return a value, therefore the optional parameter for the callback function does not matter, the function will not wait for it anyway … somehow I need to find a way to wait in that int get_param_from_user () function for the GtkDialog to complete the task …

Hello and thank you for your answer,
well at some point no matter what you want to do, you have no choice but to do what must be done,
even if that includes to ask the user to input a parameter … so I need to do it, and I am doing it, or at lest for the moment I am trying :wink:
I will look in the GtkPopover widget right away thank you !
Also I taught my-self how to write code and GUI app, I studied chemistry and physics, coding came latter, but it went somewhere not too bad I hope: #SUPERTECH : découvrez ATOMES, un programme puissant pour la modélisation atomique en 3D - YouTube

And like I did reply to @StefanSalewski I got the response signal idea but it cannot work if the function int get_param_from_user () cannot wait for the dialog to close before returning a value.

I will also look in the GMainLoop idea !

Thank you for your help.

Thank you ! It works with the GMainLoop idea.
Now I can get my user data again :wink: