Reputation: 79
I would like to let user choose two directories and then retrieve their URIs after the click of button so I could pass them to another function. For now I have tried to do something along of:
directory1 = gtk_file_chooser_button_new ("Choose directory 1",GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
The same for directory2. Then put them inside struct
struct directories {
GtkWidget *first;
GtkWidget *second;
};
struct directories directory;
directory.first = directory1;
directory.second = directory2;
And after the click of a button pass it to function which currently does nothing but tries to retrieve URIs and print them.
g_signal_connect(button, "clicked", G_CALLBACK(print_test), &directory);
print_test (struct directories *dirc)
{
g_print("%s\n", gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dirc->first)));
g_print("%s\n", gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dirc->second)));
}
I have also tried replacing GTK_FILE_CHOOSER
with GTK_FILE_CHOOSER_BUTTON
but the result is the same: my program is compiled, I choose some directories and after activating the button it crashes having printed one
(null)
and the following debug info
GLib-GObject-WARNING **: 02:52:03.786: invalid uninstantiatable type 'gchararray' in cast to 'GtkFileChooserButton'
Gtk-CRITICAL **: 02:52:03.786: gtk_file_chooser_get_uri: assertion 'GTK_IS_FILE_CHOOSER (chooser)' failed
I thought that gtk_file_chooser_button was a good solution because it seemed simpler to use than to manually establish dialog but now I started to question whether I am allowed to use it that way or is the failure of my program the fault of wrong method of passing pointers to the print_test. Unfortunately all the examples I found focus on using dialogs so I did not find a good example from which I could learn how to use gtk_file_chooser_button.
EDIT: Per request I present my code sample. I only removed other types of buttons which are not a matter of this question AND performed changes described in the first comment thus you can observe minor differences in two lines compared to the question above.
#include <stdio.h>
#include <gtk/gtk.h>
struct directories {
GtkWidget *first;
GtkWidget *second;
};
static void
print_test (GtkWidget *somewidget, struct directories *dirc)
{
g_print("%s\n", gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dirc->first)));
g_print("%s\n", gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dirc->second)));
}
static void
set_expand (GtkWidget *widget)
{
gtk_widget_set_hexpand(widget, 1);
gtk_widget_set_vexpand(widget, 1);
}
static void
activate (GtkApplication* app,
gpointer user_data)
{
GtkWidget *window;
GtkWidget *grid;
GtkWidget *frame;
GtkWidget *settings;
GtkWidget *directory1;
GtkWidget *directory2;
GtkWidget *button;
//Prepare the window
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Sagger");
gtk_window_set_default_size (GTK_WINDOW (window), 400, 200);
gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
//Prepare the grid
grid = gtk_grid_new();
//gtk_grid_set_column_homogeneous(grid, 1);
//gtk_widget_set_halign (grid, GTK_ALIGN_FILL);
//gtk_widget_set_valign (grid, GTK_ALIGN_FILL);
set_expand(grid);
gtk_container_add(GTK_CONTAINER(window), grid);
//Prepare directory chooser
settings = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
frame = gtk_frame_new("Choose directories");
set_expand(settings);
gtk_container_add(GTK_CONTAINER(frame), settings);
directory1 = gtk_file_chooser_button_new ("Source directory",GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
set_expand(directory1);
gtk_container_add(GTK_CONTAINER(settings), directory1);
directory2 = gtk_file_chooser_button_new ("Target directory",GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
set_expand(directory2);
gtk_container_add(GTK_CONTAINER(settings), directory2);
gtk_grid_attach(grid, frame, 0, 0, 2, 1);
//Prepare the run button
settings = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
gtk_button_box_set_layout(GTK_BUTTON_BOX(settings), GTK_BUTTONBOX_EXPAND);
set_expand(settings);
gtk_grid_attach(grid, settings, 0, 2, 2, 1);
button = gtk_button_new_with_label("RUN");
//Try to pass the chosen directories
struct directories directory;
directory.first = directory1;
directory.second = directory2;
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(print_test), (gpointer) &directory);
gtk_container_add(GTK_CONTAINER(settings), button);
gtk_widget_show_all (window);
}
int
main (int argc,
char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("pl.etua.sagger", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
Upvotes: 0
Views: 266
Reputation: 11020
directory
is local to the activate()
function, and, as mentioned in the comments, will get destroyed when it goes out of scope. Later on, when the print_test()
function is invoked on button click, it will try to access this memory, leading to the segmentation fault.
Two easy ways out:
Make directory
global:
struct directories {
GtkWidget *first;
GtkWidget *second;
};
struct directories directory;
Or make it static in activate()
:
static struct directories directory;
Upvotes: 1