How to cancel infinite task properly? (original) (raw)

Hello. I created a simple function cb that runs infinitely in a thread. It increments and integer value and shows it in a GtkTextView widget. I want to stop the task with a button.
The code I have right now freezes the whole app when the button is pressed and the program becomes unresponsive. What should I change to make the button stop the cb function and the thread it runs in without freezing the whole app?

GtkWidget *dataView;
GTask *task;
GCancellable *cancellable;
GObject *object;

int main (int argc, char *argv[]) {
  //starting application
  return startApp("exe.taskTest", G_APPLICATION_DEFAULT_FLAGS, activateApp, argc, argv);
}
int startApp(char *id, GApplicationFlags flags, void (*activateFunc), int argc, char *argv[]) {
    GtkApplication *app;
    int stat;

    app=gtk_application_new(id, flags);
    g_signal_connect(app, "activate", G_CALLBACK(activateFunc), NULL);
    stat=g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return stat;
}
tatic void activateApp (GApplication *app) {
    
    //let's imagine that we created gtkApplicationWindow here
    //and GtkGrid to store widgets below inside of it
    
    ...
    
    //just a part of GtkTextView initialisation
    dataView=gtk_text_view_new();
    GtkTextBuffer *dataViewBuffer;
    dataViewBuffer=gtk_text_buffer_new(NULL);
    gtk_text_view_set_buffer(GTK_TEXT_VIEW(dataView), dataViewBuffer);
    
    ...
    
    //just a button initialisation
    GtkWidget *cancelTaskButton;
    cancelTaskButton=initButton("Cancel", cancelTaskCallback, portValues);
     
    //I skipped over adding those elements to the grid
    ... 
    
  //TASK CODE
      object=g_object_new(G_TYPE_OBJECT, NULL);
      cancellable=g_cancellable_new();
      task=g_task_new(object, cancellable, cb, NULL);

      g_task_set_task_data(task, NULL, cbDestroy);
      g_task_run_in_thread(task, (void *)cb);

      g_object_unref(cancellable);
      g_object_unref(object);
      g_object_unref(task);
  //TASK CODE END
  
  gtk_window_present(GTK_WINDOW(win));
}
void cb() {

    char infoString[50];
    static int x=0;

    do {
        sprintf(infoString, "%d", x);
        static void *data[2];
            data[0]=dataView;
            data[1]=infoString;
        g_idle_add_once((void *)setText, data);
        g_usleep(1); //needed, otherwise the program crashes
        x++;
    }
    while (1);
}
void cbDestroy() {
    //nothing to free(?)
}
void setText(void* data[]) {
    setTextInTextView(data[0], data[1]);
}
void setTextInTextView(GtkWidget *textView, char *text) {
    GtkTextBuffer *infoBuffer=gtk_text_buffer_new(NULL);
    gtk_text_buffer_set_text(GTK_TEXT_BUFFER(infoBuffer), text, strlen(text));
    gtk_text_view_set_buffer(GTK_TEXT_VIEW(textView), infoBuffer);
}
static void cancelTaskCallback(GtkButton *button, void *data[]) {
    g_task_set_return_on_cancel(task, TRUE);
    g_cancellable_cancel(cancellable);
}