GTK4 progress bar is not updating

have problem with GTK4 app written in C - progress bar value is not updated.

In apps window for first I show some data loaded from xml. After confirmation this screen I hide vBox with data and create new one with progress bar which I want actualize according progres. But progressBar is shown with value 0. Zero is shown for whole time of another counting and than app goes to its third screen (without progressbar reached 100% value).

When I want update progress bar I emmit my custom signal “custom-signal-update-progress”. I can see that app is in callback function (from comandline output). I can also see that percentage value sended to progressbar is also increased.

This behaviour is in win10 but also in xubuntu 21.10.

Please could anybody give me any advice how to solve it?

static void
update_progress (gpointer data) {
    printf("update_progress value %f  index %d \n",progressValue, checkedTestPlace);
    gpointer bar = g_object_get_data(G_OBJECT(data), "bar");
    gpointer window = g_object_get_data(G_OBJECT(data), "window");

    gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(bar),progressValue);

    if (progressValue >= 1.0) {
        g_signal_emit_by_name(window, "custom-signal-hide-progress");
    };
}

static gboolean
start_test_pcace_checking (gpointer data) {
    gpointer window = g_object_get_data(G_OBJECT(data), "window");

    unsigned int vectSize = testPlaceVector.size();
    for (unsigned int i = 0; i < vectSize; ++i) {
        progressValue = (gfloat) (i+1) / (gfloat) vectSize;
        printf("we are sending signal for update \n");
        g_signal_emit_by_name(window, "custom-signal-update-progress");
        if (testPlaceVector.at(i).defaultValue.compare("YES")==0) {
            //check_test_place (testPlaceVector.at(i).address, testPlaceVector.at(i).name);
        }
        sleep( 1 );
    }
    return false;
}

static void
close_chooser_window (gpointer data) {
    cout << "test places changes:"<<endl;
    vypis_vektor(testPlaceVector);

    gpointer window = g_object_get_data(G_OBJECT(data), "window");
    gpointer box = g_object_get_data(G_OBJECT(data), "box");
    gtk_widget_hide(GTK_WIDGET(box));

   GtkWidget *vBox;
   GtkWidget *bar;
   GtkWidget *lab;

    vBox =  gtk_box_new (GTK_ORIENTATION_VERTICAL,3);
    gtk_box_set_homogeneous (GTK_BOX (vBox), TRUE);
    gtk_window_set_child (GTK_WINDOW (window), vBox);

    lab =  gtk_label_new ("checking proggress");
    gtk_box_append (GTK_BOX (vBox), lab);

    bar = gtk_progress_bar_new ();
    gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(bar),0.0);
    gtk_progress_bar_set_show_text (GTK_PROGRESS_BAR(bar), TRUE);
    gtk_box_append (GTK_BOX (vBox), bar);

    lab =  gtk_label_new ("");
    gtk_box_append (GTK_BOX (vBox), lab);

    g_object_set_data(G_OBJECT(window), "window",window);
    g_object_set_data(G_OBJECT(window), "box",vBox);
    g_object_set_data(G_OBJECT(window), "bar",bar);

   g_timeout_add(200,start_test_pcace_checking,window);
}

static void
app_activate (GApplication *app, gpointer user_data) {
    GtkWidget *win;
    GtkWidget *vBox;
    GtkWidget *btn;
    GtkWidget *chBtn;

    win = gtk_application_window_new (GTK_APPLICATION (app));
    gtk_window_set_title (GTK_WINDOW (win), "Git Status - choose what check");
    gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);

    testPlaceVector = load_config_xml();

    vBox =  gtk_box_new (GTK_ORIENTATION_VERTICAL,3);
    gtk_box_set_homogeneous (GTK_BOX (vBox), TRUE);
    gtk_window_set_child (GTK_WINDOW (win), vBox);

    for (unsigned int i = 0; i < testPlaceVector.size(); ++i)
    {
        chBtn = gtk_check_button_new_with_label (testPlaceVector.at(i).name.c_str());
        if ( testPlaceVector.at(i).defaultValue.compare("YES") ==0) {
            gtk_check_button_set_active(GTK_CHECK_BUTTON(chBtn),true);
        }
        gtk_box_append (GTK_BOX (vBox), chBtn);
        g_signal_connect(G_OBJECT(chBtn),"toggled",G_CALLBACK(check_button_clicked),chBtn);
    }

    btn = gtk_button_new_from_icon_name("emblem-default");
    //gtk_button_set_label(GTK_BUTTON(btn),"OK");
    gtk_box_append (GTK_BOX (vBox), btn);

    //tu si nadefinujeme nas signal - kterej poslem, kdyz dozkoumame jeden testovaci stav a budem potrebovat aktualizovat progress bar
    g_signal_new("custom-signal-update-progress", G_TYPE_OBJECT, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
    //tu priradime obsluznou proceduru k nasemu signalu
    g_signal_connect(win, "custom-signal-update-progress", G_CALLBACK(update_progress), NULL);

    g_signal_new("custom-signal-hide-progress", G_TYPE_OBJECT, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
    g_signal_connect(win, "custom-signal-hide-progress", G_CALLBACK(hide_progress), win);

    g_object_set_data(G_OBJECT(btn), "window",win);
    g_object_set_data(G_OBJECT(btn), "box",vBox);
    g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(close_chooser_window), btn);

    gtk_widget_show (win);
}

int
main (int argc, char **argv) {
  GtkApplication *app;
  int stat;

  //app = gtk_application_new ("git.status.checker.gui", G_APPLICATION_FLAGS_NONE);
  app = gtk_application_new ("Git.status.icon", G_APPLICATION_FLAGS_NONE);
  g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
  stat =g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);
  return stat;
}

comandline output:

we are sending signal for update
update_progress value 0,111111  index 0
we are sending signal for update
update_progress value 0,222222  index 0
we are sending signal for update
update_progress value 0,333333  index 0
we are sending signal for update
update_progress value 0,444444  index 0
we are sending signal for update
update_progress value 0,555556  index 0
we are sending signal for update
update_progress value 0,666667  index 0
we are sending signal for update
update_progress value 0,777778  index 0
we are sending signal for update
update_progress value 0,888889  index 0
we are sending signal for update
update_progress value 1,000000  index 0

Process returned 0 (0x0)   execution time : 18.095 s
Press any key to continue.

You cannot expect the event-driven toolkit GTK is to play nice when the UI thread (normally the main one in GTK apps) is busy/locked (in your example, the sleep(1) call.

The way GTK works is that it has an event loop (started with gtk_main()/g_application_run()) which dispatches tasks based on time, priority and other details; if the loop cannot run because the code is stuck in another function (here, your sleep(1)), it doesn’t have a chance to dispatch the UI update events. Additionally, methods to change state on widgets like the percentage of the scrollbar do not directly update the UI, they merely change the internal state of the widget and post an update event for when there is time to repaint or when the next frame clock hits.

Basically, using sleep(1), or any other blocking calls, in the UI thread is not gonna work nicely. If you have busy work to do, you basically have 2 options:

  1. do the work in a separate thread, and notify the main thread to update the UI accordingly (g_idle_add() is your friend, as you cannot call GTK methods from different threads)
  2. split work in smaller chunks and leave time for the main thread to “breathe”. It means you won’t be able to be as busy, but depending on what you’re actually doing it might be an option.

A “third” case is when the call you makes are not actually busy, but have latency (basically, I/O). There, you often can integrate waiting for the reply on the GTK loop itself (it’s fairly easy to integrate FD polling or similar for example).

HTH

BTW, is there any GTK analogon for WaitForSingleObject?

poll is the rough Unix equivalent (or epoll if on Linux) for both WaitForSingleObject and WaitForMultipleObjects. GLib has a wrapper function g_poll that GTK calls internally in its event loop, so you should not have to call it yourself unless implementing your own event loop in another thread.

Great - tahnks for advices I have solved it with g_idle_add()

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