Description: I'm working on a GTK3 application in C and facing an issue with a specific part of the code. The code involves a callback function (save_enterprise_website) for a "Save" button and a function (create_Enterprise_form) to create a customization form for a company website template.
Problem: Upon clicking the "Save" button, the program encounters a problem. The callback function iterates through an array of GTK widgets (entries), attempting to extract text from each GtkEntry. However, an error occurs, and the message "Element 0 is not a GtkEntry" is printed. Subsequently, the program stops responding.
Attempted Solution: There is a commented-out section in the code where a similar loop is used to check if every element of the entries array is of type GTK_ENTRY. When this loop is uncommented and executed, it successfully prints the text of all the entries.
Request for Assistance: I'm seeking guidance on resolving the issue with the callback function. What steps can I take to ensure that the callback function properly extracts text from GtkEntry widgets without encountering the mentioned problem?
Code:
// Callback function for the "Save" button
void save_enterprise_website(GtkWidget *button, GtkWidget **entries) {
for (int i = 0; i < 12; i++) {
if (GTK_IS_ENTRY(entries[i])) {
const char *text = gtk_entry_get_text(GTK_ENTRY(entries[i]));
g_print("%s\n", text);
} else {
g_print("Element %d is not a GtkEntry\n", i);
}
}
}
// Function to create the customization form for the company website template
GtkWidget *create_Enterprise_form(GtkApplication *app) {
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Enterprise_Website");
gtk_window_set_default_size(GTK_WINDOW(window), 1280, 720);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
GtkWidget *grid = gtk_grid_new();
gtk_container_add(GTK_CONTAINER(window), grid);
const char *parameters[] = {
"Name", "About Us", "Slogan", "Contact",
"Body Color", "Body Font Family",
"Header BG Color", "Header Text Color",
"A Text Color", "Footer BG Color",
"Footer Text Color", "Hero BG Color"
};
// Create an array of widgets to store text entry fields
GtkWidget *entries[G_N_ELEMENTS(parameters)];
const char *default_texts[] = {
"Company Name","A brief description of the company and its history", "A slogan for the company",
"Address, phone number, contact form, etc.", "#f4f4f4", "Arial, sans-serif",
"#333", "#fff", "#fff", "#333", "#fff", "#f4f4f4"
};
for (int i = 0; i < G_N_ELEMENTS(parameters); i++) {
GtkWidget *label = gtk_label_new(parameters[i]);
GtkWidget *entry = gtk_entry_new();
gtk_entry_set_text(GTK_ENTRY(entry), default_texts[i]);
PangoFontDescription *font_desc = pango_font_description_from_string("Sans Bold 14");
gtk_widget_override_font(label, font_desc);
gtk_widget_override_font(entry, font_desc);
pango_font_description_free(font_desc);
int vertical_spacing = 10;
gtk_widget_set_margin_bottom(label, vertical_spacing);
gtk_widget_set_margin_bottom(entry, vertical_spacing);
// Multiply the width of GtkEntry by 3
gtk_widget_set_size_request(entry, 3 * gtk_widget_get_allocated_width(entry), -1);
// Add widgets to GtkGrid with adjustments for font size and vertical space
gtk_grid_attach(GTK_GRID(grid), label, 0, i, 1, 1);
gtk_grid_attach(GTK_GRID(grid), entry, 1, i, 1, 1);
// Store entries in the entries array
entries[i] = entry;
//test if every element of the array is og GTK_ENTRY type
/*
for (int i = 0; i < 12; i++) {
if (GTK_IS_ENTRY(entries[i])) {
const char *text = gtk_entry_get_text(GTK_ENTRY(entries[i]));
g_print("%s\n", text);
} else {
g_print("Element %d is not a GtkEntry\n", i);
}
}*/
}
GtkWidget *submit_button = gtk_button_new_with_label("Save");
g_signal_connect(submit_button, "clicked", G_CALLBACK(save_enterprise_website), entries);
// Add the button to GtkGrid
gtk_grid_attach(GTK_GRID(grid), submit_button, 1, G_N_ELEMENTS(parameters), 1, 1);
gtk_widget_set_halign(grid, GTK_ALIGN_CENTER);
gtk_widget_set_valign(grid, GTK_ALIGN_CENTER);
return window;
}
The problem is that you are declaring the array of widget pointers on the stack, passing a pointer to the array as a callback function argument, and then returning from your function. As soon as the function returns, anything at all can happen to values on the stack; they are commonly overwritten. The callback function is receiving a pointer to the location that used to hold the array, but that now holds some random garbage. As soon as the callback function dereferences that pointer, you are in the realm of undefined behavior; your program will probably crash.
To fix this, you need to allocate the array on the heap, with malloc() or one of the related functions. Objects on the heap stay there until they are free()'d (or the heap is corrupted which is a whole other class of bugs.) A pointer to a value on the stack will only be valid while the function-call in which the value is created is still running (and sometimes not even then, because C lets you corrupt the stack as well...)
Because you don't know (and can't know-- it's undefined behavior) what happens to values on the stack after a function returns, you run into the situation you are seeing: seemingly unrelated code changes seem to make it work. Really what's happening is that the random code change has made it so your values on the stack happen not be overwritten before the callback is invoked, but you can't count on that behavior at all: it may be specific to the particular timing of UI events in GTK's queue, for example.