GTK4: yet another progess bar not updating

Dear all I cannot update the progress bar of my GTK4 program,
and I am not able to understand why, I obviously noticed this thread:

But no source code is provided to understand the solution and I do not have to knowledge to understand it like this.

In GTK3 I was using:

gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(encoding_pb), fraction);
while (gtk_events_pending()) gtk_main_iteration();

And everything was fine.

With GTK4 after reading the migration guide (Gtk – 4.0: Migrating from GTK 3.x to GTK 4) I tried:

gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(encoding_pb), fraction);
while (g_main_context_pending (g_main_context_default())) g_main_context_iteration (NULL, TRUE);

Which has a bad effect, it blurs the GTK window and render the main app task (movie encoding) impossible (the encoded movie end up entirely black).

With getting rid on the while () instruction line I have a clean move, but not progress bar update.

Would anyone be able to explain to me how to update my progress bar ?

Thanks in advance for your help !

Hard to say without looking at your code. But it’s highly recommended to use g_application_run instead of iterating the main loop manually like that.

Hello,
and thank you for taking the time to help, for the entire source code you can have a look here:

However, and to make it clear how this part of the GTK engineering is unknown to me, I have no idea what you are trying to tell me, sorry really, however I can tell you that I use the g_application_run instruction in my code here (at the end of that file) to initialize the program, how I think it must be done:

I think that progress bar are widgets likely used in cases extremely similar to mine. However such example cases can not be found in any of the example codes shipped with the GTK sources, gtk-demo, widget-factory or else for that matter, I just used grep over the entire gtk directory tree searching for gtk_progress_bar lines and the corresponding instructions … none that match what I am looking for, basically all the examples are updating the progress bar by clicking on a button to do so or something alike … this will not help :frowning:

However without any advanced knowledge on what seems to be both the GLib application management, and the GTK application engineering, this remains elusive, look at my program (https://atomes.ipcms.unistra.fr), I am no beginner coding in GTK, still no way to find that information, that is why I am asking here to be educated.

Please teach me :slight_smile:

The short answer is: “never iterate the main context yourself, ever”.

An example is here:

Don’t do that, just let GTK iterate the context, as you told it to when you called g_application_run(). You are almost certainly interfering with GTK’s attempts to coordinate drawing and other events.

If the progress bar is not updating, I would be looking to print out the fractional values you are trying to set it to, and ensure you are comparing floating point numbers with an appropriate epsilon.

You can browse https://grep.app/search?q=gtk_progress_bar_set_fraction for some examples in the wild.

1 Like

Just as another note, if you’re expecting GTK to update the UI, you must at some point return control to the main loop, which is iterating the main context.

If you are simply calling some long-running event in a closed loop, in the main thread, you are probably not allowing GTK to redraw the UI.

1 Like

Dear @andyholmes first of all thank you for taking the time to dig into my code :wink:

So here some short answers / informations for you:

  • I certainly asserted before starting this thread that the values I used to update the progress bar are appropriate, so no error at this stage.

  • You identified the part of my code doing the progress bar update, or I whish it would, something else here that might help you help me, is that just before starting to encode the movie I ask the user the enter a file name to save it, after the file name is given I kill the file chooser dialog here:

See in the file src/gui/gtk-misc.c for the implementation of this function (line 2053, associated with the function run_this_gtk_native_dialog to run the dialog line 445 to run the in the same file).

For GTK4 no way to kill/hide the file chooser dialog window, to display the encoding window and the progress bar, If I do not uncoment line 1122 that you pointed out in the src/opengl/draw/movie.c file, however and as I said in the first message of this thread, that same line makes the movie rendering impossible (that is why I commented it in the first place).
So basically I am stuck with a progress bar not updating, and a file chooser dialog window blocking the screen … but the movie encoding working fine :wink:

Again, I do not understand what it is the “iteration of the main context” you and @jfrancis are talking about.
I just followed the migration guide from GTK3 to GTK4, that somehow says to replace line 1120 by line 1122 (in your selection above).

I am in vacation and away from my computer to keep working on this for the time being, but I wanted to answer to your message properly, I will be back at work by August 15th.

Regards.

Okay, GLib employs a type of cooperative scheduling, and the units of the scheduling are called sources. It works like this:

  • Every thread that plans on cooperating in this scheduling has a GMainContext. The main thread has one of these by default, and this is what g_application_run() is operating on. This is also where GTK schedules its events.

  • There are a number of ways to schedule events in a GMainContext, notable g_idle_add(), g_timeout_add() and GTask operations. Each of these, one way or the other will create a GSource and add it to the GMainContext which will dispatch it (i.e. execute the callback function) in the appropriate thread.

  • When a GSource is dispatched, it takes control of the program’s execution until it completes, then control is returned to the GMainContext. The next time the GMainContext is iterated it determines the next GSource to dispatch and the process repeats.

  • For the GMainContext to dispatch event, it must therefore be iterated. There are two proper ways to do this:

    • With g_application_run(), which will iterate the default GMainContext until g_application_quit() is called.

    • With g_main_loop_run(), which will iterate the GMainContext set at construction (or the default if NULL is passed), until g_main_loop_quit() is called.

If g_application_run() has been called, you are operating in a GMainContext whether you like it or not. This means that no other sources can be dispatched by the context while you are running code. This is why asynchronous and non-blocking code is so important in a GLib application.

In your case, I’m going to assume you have some function like encode_movie() which is synchronous and blocking. Because you are not returning control to the GMainContext, it is unable to dispatch the source responsible for redrawing the progress bar.

You should therefore do your encoding in another thread, possibly by creating your own GTask function. While in that thread, you can dispatch progress updates to the default GMainContext by using g_idle_add().

2 Likes

Thank you very much for this very detailed and clear explanation, not that I can understand everything yet :stuck_out_tongue:
But it helps a lot, and I really appreciate that you took the time to teach me all this :wink:
I will work on the thread idea, I tried to do that already years ago, but since I am not a specialist
I gave up after facing too many issues that I could not understand.
I guess now is as good time as ever to give it another try :slight_smile:

I am not a dev by training, but a chemist/physicist and sometime it is hard to grasp everything that
matters when you are self taught, so really thank you for your efforts in educating me, really appreciate it !

Thanks you very much !

PS: Please keep it up for the next person asking for help … even if that’s me again :wink:

2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.