cfiledialoggtk4

GTK4 Windows Multiple File Choosing


I want to choose a several files and write their path to TextView widget by click on the button. I have memory leaks and dont understand how to properly free memory. Sometimes my application is not starting at all, sometimes for second click I have segmentation fault. Also there are this errors every time:

GLib-CRITICAL **: 14:48:38.184: g_main_context_pop_thread_default: assertion 'g_queue_peek_head (stack) == context' failed
GLib-CRITICAL **: 14:48:42.576: g_hash_table_contains: assertion 'hash_table != NULL' failed
GLib-CRITICAL **: 14:48:42.586: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed
Segmentation fault

Callback functions in C for file dialog is below:

static void
choseTargetFinish (GObject* source_object, GAsyncResult* res, gpointer data)
{
  GtkFileDialog *dialog = GTK_FILE_DIALOG (source_object);
  GListModel *files = gtk_file_dialog_open_multiple_finish(dialog, res, NULL);
  if (files != NULL)
  {
    GtkTextIter *start;
    GtkTextIter *end;
    gtk_text_buffer_get_start_iter(targetPathBuffer, start);
    gtk_text_buffer_get_end_iter(targetPathBuffer, end);
    gtk_text_buffer_delete(targetPathBuffer, start, end);
    GFile *file;
    char *path;
    int i = 0;
    file = g_list_model_get_item(files, i);
    end = start;
    while (file != NULL)
    {
      path = g_file_get_path(file);
      sprintf(path, "%s\n", path);
      gtk_text_buffer_insert(targetPathBuffer, end, path, -1);
      gtk_text_buffer_get_end_iter(targetPathBuffer, end);
      i++;
      file = g_list_model_get_item(files, i);
    }
    g_free(path);
  }
}

static void
chooseTarget_cb (GtkWidget *widget)
{
  GtkFileDialog *fd = gtk_file_dialog_new();
  GAsyncResult* result;
  gtk_file_dialog_open_multiple(fd, NULL, NULL, choseTargetFinish, NULL);
  g_object_unref(fd);
}

I read docs and it says I should free GListModel and I tried to do it by g_object_unref.


Solution

  • It is always difficult to find a bug if you have only part of the program ahead of you.I have therefore taken my own approach, but it does exactly what is obviously expected by the program. - I hope so :-)

    #include"multible-file.h"
    
    GtkTextBuffer *buffer;
    
    const gchar* list_to_string(GListModel* list) {
        GObject* item;
        GString* result = g_string_new("");
        
        guint i = g_list_model_get_n_items(list);
       
        for (guint i = 0; i < g_list_model_get_n_items(list); i++) 
        {
        
             item  = g_list_model_get_object(list, i);
             const gchar* str = g_file_get_parse_name(G_FILE(item));
             g_string_append(result,"\n");
             g_string_append(result, str);
            
             g_object_unref(item);
        }
        return g_string_free(result, FALSE);
       
    }
    static void
    choseTargetFinish (GObject* source_object, GAsyncResult* res, gpointer data)
    {
      GtkFileDialog *dialog = GTK_FILE_DIALOG (source_object);
      GListModel *files = gtk_file_dialog_open_multiple_finish(dialog, res, NULL);
      const gchar  *content = list_to_string(files);
      gtk_text_buffer_set_text(buffer,content,-1);
      g_free((gpointer)content);
      g_object_unref(files);
    }
    
    static void
    chooseTarget_cb (GtkWidget *widget)
    {
      GtkFileDialog *fd = gtk_file_dialog_new();
      gtk_file_dialog_open_multiple(fd,NULL , NULL, choseTargetFinish, NULL);
      g_object_unref(fd);
    }
    
    void activate (GtkApplication *app, gpointer data)
    {
      GtkWidget *window;
    
      window =gtk_application_window_new(app);
      gtk_widget_set_size_request(window,700,150);
    
      GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL,10);
      GtkWidget * button = gtk_button_new_with_label("FileDialog"); 
      g_signal_connect(button,"clicked",G_CALLBACK(chooseTarget_cb),NULL);
      GtkWidget *textview = gtk_text_view_new();
      buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
      gtk_box_append(GTK_BOX(box),button);
      gtk_box_append(GTK_BOX(box),textview);
      gtk_window_set_child(GTK_WINDOW(window),box);
     
      gtk_widget_set_visible(window,TRUE);
    }
    

    Please note that the ListModel contends objects. In this case GFile-Objects. These must then be parsed to the string. For a better overview, I have this outsourced to its own function.