segmentation fault on clicking a GtkButton - c

Depending on the location of the init_prog(user) call in my program I get a segmentation fault, I don't understand the reason. If I put the call in the start() callback function after clicking btn_go it crashes:
Thread 1 "./a.out" received signal SIGSEGV, Segmentation fault.
0x00007ffff7812526 in gdk_window_get_display (window=0x55555555b1c0) at ../../../../gdk/gdkwindow.c:2303
2303 ../../../../gdk/gdkwindow.c: No such file or directory.
This is the back trace:
Thread 1 "./a.out" received signal SIGSEGV, Segmentation fault.
0x00007ffff7812526 in gdk_window_get_display (window=0x55555555b1c0) at ../../../../gdk/gdkwindow.c:2303
2303 ../../../../gdk/gdkwindow.c: No such file or directory.
(gdb) bt
#0 0x00007ffff7812526 in gdk_window_get_display (window=0x55555555b1c0) at ../../../../gdk/gdkwindow.c:2303
#1 0x00007ffff78022ce in event_get_display (event=0x7fffe800add0) at ../../../../gdk/gdkevents.c:457
#2 0x00007ffff78022ce in gdk_event_free (event=0x7fffe800add0) at ../../../../gdk/gdkevents.c:839
#3 0x00007ffff783311a in gdk_event_source_dispatch
(source=<optimized out>, callback=<optimized out>, user_data=<optimized out>)
at ../../../../../gdk/x11/gdkeventsource.c:369
#4 0x00007ffff730cf2e in g_main_context_dispatch () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#5 0x00007ffff730d1c8 in () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#6 0x00007ffff730d4c2 in g_main_loop_run () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#7 0x00007ffff7affb15 in gtk_main () at ../../../../gtk/gtkmain.c:1323
#8 0x0000555555556da1 in create_window () at gui.c:118
#9 0x000055555555644d in main (argc=1, argv=0x7fffffffe328) at main.c:26
This is the code:
#include <glib.h>
#include <stdio.h>
#include <gtk/gtk.h>
void start (GtkWidget *widget, struct prog_data *user);
void create_window() {
GtkWidget *window;
GtkWidget *headbar;
GtkWidget *vbox;
GtkWidget *hbox_superself;
GtkWidget *hbox_my_struct;
GtkWidget *hbox_self;
GtkWidget *btn_about;
GtkWidget *btn_go;
GtkWidget *evnt_box[3];
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
headbar = gtk_header_bar_new();
btn_about = gtk_button_new_with_label("About");
btn_go = gtk_button_new_with_label("Start");
evnt_box[0] = gtk_evnt_box_new ();
evnt_box[1] = gtk_evnt_box_new ();
evnt_box[2] = gtk_evnt_box_new ();
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
hbox_superself = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 35);
hbox_my_struct = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
hbox_self = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 35);
my_struct.label_user[USR0] = gtk_label_new ("0");
my_struct.label_user[USR1] = gtk_label_new ("0");
my_struct.lbl_pings_left = gtk_label_new ("");
my_struct.img_show[0] = gtk_image_new ();
my_struct.img_show[1] = gtk_image_new ();
my_struct.image_deck_pile = gtk_image_new_from_file ("1.png");
my_struct.self_image[0] = gtk_image_new_from_file ("2.png");
my_struct.self_image[1] = gtk_image_new_from_file ("2.png");
my_struct.self_image[2] = gtk_image_new_from_file ("2.png");
my_struct.image_orca = gtk_image_new ();
my_struct.super_self[0] = gtk_image_new();
my_struct.super_self[1] = gtk_image_new();
my_struct.super_self[2] = gtk_image_new();
gtk_header_bar_set_title (GTK_HEADER_BAR (headbar), "Orca");
gtk_window_set_title (GTK_WINDOW (window), "Orca");
gtk_window_set_titlebar (GTK_WINDOW (window), headbar);
gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (headbar), TRUE);
gtk_window_maximize (GTK_WINDOW (window));
GtkCssProvider *css_provider = gtk_css_provider_new();
gtk_css_provider_load_from_path (css_provider, "style.css", NULL);
GdkScreen *myScreen = gdk_screen_get_default();
gtk_style_context_add_provider_for_screen (myScreen, GTK_STYLE_PROVIDER (css_provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
struct prog_data user[2];
gtk_container_add(GTK_CONTAINER (headbar), btn_about);
gtk_container_add(GTK_CONTAINER (window), vbox);
gtk_container_add(GTK_CONTAINER (vbox), hbox_superself);
gtk_container_add(GTK_CONTAINER (vbox), hbox_my_struct);
gtk_container_add(GTK_CONTAINER (vbox), hbox_self);
gtk_container_add(GTK_CONTAINER (hbox_superself), my_struct.self_image[0]);
gtk_container_add(GTK_CONTAINER (hbox_superself), my_struct.self_image[1]);
gtk_container_add(GTK_CONTAINER (hbox_superself), my_struct.self_image[2]);
gtk_container_add(GTK_CONTAINER (hbox_superself), my_struct.label_user[USR1]);
gtk_container_add(GTK_CONTAINER (hbox_my_struct), my_struct.image_orca);
gtk_container_add(GTK_CONTAINER (hbox_my_struct), my_struct.image_deck_pile);
gtk_container_add(GTK_CONTAINER (hbox_my_struct), my_struct.lbl_pings_left);
gtk_container_add(GTK_CONTAINER (hbox_my_struct), btn_go);
gtk_container_add(GTK_CONTAINER (hbox_my_struct), my_struct.img_show[0]);
gtk_container_add(GTK_CONTAINER (hbox_my_struct), my_struct.img_show[1]);
gtk_container_add(GTK_CONTAINER (hbox_self), evnt_box[0]);
gtk_container_add(GTK_CONTAINER (hbox_self), evnt_box[1]);
gtk_container_add(GTK_CONTAINER (hbox_self), evnt_box[2]);
gtk_container_add(GTK_CONTAINER (evnt_box[0]), my_struct.super_self[0]);
gtk_container_add(GTK_CONTAINER (evnt_box[1]), my_struct.super_self[1]);
gtk_container_add(GTK_CONTAINER (evnt_box[2]), my_struct.super_self[2]);
gtk_container_add(GTK_CONTAINER (hbox_self), my_struct.label_user[USR0]);
GtkStyleContext *context1;
context1 = gtk_widget_get_style_context(hbox_self);
gtk_style_context_add_class(context1, "my_hbox_self");
GtkStyleContext *context2;
context2 = gtk_widget_get_style_context(hbox_superself);
gtk_style_context_add_class(context2, "my_hbox_superself");
GtkStyleContext *context3;
context3 = gtk_widget_get_style_context(hbox_my_struct);
gtk_style_context_add_class(context3, "my_hbox_my_struct");
gtk_widget_set_name (my_struct.img_show[0], "user1");
g_signal_connect (btn_about, "clicked", G_CALLBACK (activate_about), NULL);
g_signal_connect (G_OBJECT (evnt_box[0]), "button_press_event", G_CALLBACK (ping1_clicked), user);
g_signal_connect (G_OBJECT (evnt_box[1]), "button_press_event", G_CALLBACK (ping2_clicked), user);
g_signal_connect (G_OBJECT (evnt_box[2]), "button_press_event", G_CALLBACK (ping3_clicked), user);
g_signal_connect (G_OBJECT (btn_go), "button_press_event", G_CALLBACK (start), user);
g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL);
gtk_widget_show_all (window);
gtk_main();
}
void start (GtkWidget *btn_go, struct prog_data *user) {
gtk_widget_hide(btn_go);
printf("Right\n");
init_prog(user);
}
If I move the call init_prog(user) in the create_window() function after gtk_widget_show_all (window);, I do not experience any crash. I've tested the init_prot(user) function separately and it works well.

You are cheating GTK by providing an incorrect callback function.
The manual tells us how your callback shall look like for "button_press_event":
gboolean
user_function (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
You access event pointer and treat is as user_data pointer. That causes undefined behaviour.
You also fail to provide mandatory boolean return value.
You must adjust the signature of your callback function to match the requirements.
Or maybe you might change to use "clicked" or "pressed" event of the button widget instead of the "button-pressed-event".
You also should check the other callback functions that were not present in the question for the same error.

Related

initialization of GtkImage in c

I'm encountering a Segmentation Fault when I try to make a Gtkwidget point to a memory address where I've load a png from file. I want card[6].image to display the image I've loaded in card[0].image and the I'd like to remove the same image from card[0].image.
struct my_image {
const char *path;
GtkWidget *image;
};
void create_window() {
GtkWidget *window;
GtkWidget *headbar;
GtkWidget *vbox;
GtkWidget *hbox_3;
GtkWidget *hbox_table;
GtkWidget *hbox_1;
GtkWidget *hbox_2;
GtkWidget *about_button;
GtkWidget *event_box1, *event_box2, *event_box3;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
headbar = gtk_header_bar_new();
about_button = gtk_button_new_with_mnemonic("CLick");
event_box1 = gtk_event_box_new ();
event_box2 = gtk_event_box_new ();
event_box3 = gtk_event_box_new ();
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 50);
hbox_3 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 35);
hbox_table = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 35);
hbox_2= gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
hbox_1 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 35);
gtk_header_bar_set_title (GTK_HEADER_BAR (headbar), "Myprogram");
gtk_window_set_title (GTK_WINDOW (window), "Myprogram");
gtk_window_set_titlebar (GTK_WINDOW (window), headbar);
gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (headbar), TRUE);
gtk_window_maximize (GTK_WINDOW (window));
card[0].path = pile[0];
card[1].path = pile[1];
card[2].path = pile[2];
card[0].image = gtk_image_new_from_file (card[0].path);
card[1].image = gtk_image_new_from_file (card[1].path);
card[2].image = gtk_image_new_from_file (card[2].path);
card[3].path = "c/fort.png";
card[4].path = "c/fort.png";
card[5].path = "c/fort.png";
card[3].image = gtk_image_new_from_file (card[3].path);
card[4].image = gtk_image_new_from_file (card[4].path);
card[5].image = gtk_image_new_from_file (card[5].path);
card[6].image = gtk_image_new ();
card[7].image = gtk_image_new ();
printf("card 0 address = %u\n", card[0].image);
printf("card 6 address = %u\n", card[6].image);
card[8].path = pile[39];
card[9].path = "c/mazzo.png";
card[8].image = gtk_image_new_from_file (card[8].path);
card[9].image = gtk_image_new_from_file (card[9].path);
g_signal_connect (about_button, "clicked", G_CALLfort (activate_about), NULL);
g_signal_connect (G_OBJECT (event_box1), "button_press_event", G_CALLfort (card1_clicked), card);
g_signal_connect (G_OBJECT (event_box2), "button_press_event", G_CALLfort (card2_clicked), card);
g_signal_connect (G_OBJECT (event_box3), "button_press_event", G_CALLfort (card3_clicked), card);
g_signal_connect (G_OBJECT (window), "destroy", G_CALLfort (destroy), NULL);
gtk_container_add(GTK_CONTAINER (headbar), about_button);
gtk_container_add(GTK_CONTAINER (window), vbox);
gtk_container_add(GTK_CONTAINER (vbox), hbox_3);
gtk_container_add(GTK_CONTAINER (vbox), hbox_table);
gtk_container_add(GTK_CONTAINER (vbox), hbox_2);
gtk_container_add(GTK_CONTAINER (vbox), hbox_1);
gtk_container_add(GTK_CONTAINER (hbox_2), card[8].image);
gtk_container_add(GTK_CONTAINER (hbox_2), card[9].image);
gtk_container_add(GTK_CONTAINER (hbox_1), event_box1);
gtk_container_add(GTK_CONTAINER (hbox_1), event_box2);
gtk_container_add(GTK_CONTAINER (hbox_1), event_box3);
gtk_container_add(GTK_CONTAINER (event_box1), card[0].image);
gtk_container_add(GTK_CONTAINER (event_box2), card[1].image);
gtk_container_add(GTK_CONTAINER (event_box3), card[2].image);
gtk_container_add(GTK_CONTAINER (hbox_3), card[3].image);
gtk_container_add(GTK_CONTAINER (hbox_3), card[4].image);
gtk_container_add(GTK_CONTAINER (hbox_3), card[5].image);
gtk_container_add(GTK_CONTAINER (hbox_table), card[6].image);
gtk_container_add(GTK_CONTAINER (hbox_table), card[7].image);
gtk_widget_show_all (window);
gtk_main();
}
void card1_clicked (GtkWidget *window, struct my_image *card)
{
printf("%s\n", card[0].path);
card[6].image = card[0].image;
/*gtk_image_set_from_file(GTK_IMAGE(card[6].image), card[0].path);*/
}
the images initially are displayed correclty but when trigger card1_clciked this line card[6].image = card[0].image; produces a Segmentation Fault.
I'm not sure if I'm loading the image correctly and how to load another image using the same widget; I've also tried to use the function /*gtk_image_set_from_file(GTK_IMAGE(card[6].image), card[0].path);* with the same effect.
Your callback function for button_press_event signal is not defined properly.
The manual tells us how it shall look like:
// The “button-press-event” signal
gboolean
user_function (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
In your function you are missing one parameter:
void card1_clicked (GtkWidget *window, struct my_image *card)
This means you are using the event pointer to read your card array which causes some illegal read access.
Besides that you do not provide the required boolean return value.

Pick user's choice on button click

I need to pick the user's choice and store the value in a global variable then after the user has chosen the vbox with the buttons should disappear and control be returned to create_window(). I don't know if it is the best method for such a task.
#include "test.h"
int number_players;
void create_window() {
GtkWidget *window;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "test");
gtk_window_maximize (GTK_WINDOW (window));
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
get_number_players(window);
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (destroy), NULL);
gtk_widget_show_all (window);
g_print("%d\n", number_players);
gtk_main();
}
void get_number_players (GtkWidget *window) {
GtkWidget *vbox, *button_choice1, *button_choice2, *button_choice3;
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
button_choice1 = gtk_button_new_with_label("six Players");
button_choice2 = gtk_button_new_with_label("Seven Players");
button_choice3 = gtk_button_new_with_label("nine Players");
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_container_add (GTK_CONTAINER (vbox), button_choice1);
gtk_container_add (GTK_CONTAINER (vbox), button_choice2);
gtk_container_add (GTK_CONTAINER (vbox), button_choice3);
g_signal_connect(G_OBJECT(button_choice1), "clicked", G_CALLBACK(read_choice), GINT_TO_POINTER(6));
g_signal_connect(G_OBJECT(button_choice2), "clicked", G_CALLBACK(read_choice), GINT_TO_POINTER(7));
g_signal_connect(G_OBJECT(button_choice3), "clicked", G_CALLBACK(read_choice), GINT_TO_POINTER(9));
}
void read_choice (GtkWidget *window, gpointer data) {
number_players = GPOINTER_TO_INT(data);
}
void destroy (GtkWidget *window, gpointer data)
{
gtk_main_quit ();
}
From some reason the global variable number_players is not printed correclty if I print in read_choice though I can see the right value.

How to switch between windows in GTK3 (C Language)

I have an App which as some point Opens a new Window and works fine.
Then After I'm done with it, I need to switch back to the main window.
I understood that I need the function:
gtk_widget_hide();
but I cant figure out how to hide the main Window, to print only the second one and again after I click the button in the second window to go back to the first one.
This is what I have so far:
#include <stdio.h>
#include <gtk/gtk.h>
static void crete_new_wind (GtkWidget *widget);
gboolean destroy (GtkWidget *window);
int main (int argc, char *argv[]){
GtkWidget *window, *button, *box;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "First Window");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
gtk_widget_set_size_request (window, 300, 300);
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
button = gtk_button_new_with_label ("Go to Window B");
g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (crete_new_wind), (gpointer) window);
box = gtk_box_new (TRUE, 1);
gtk_box_pack_end (GTK_BOX (box), button, TRUE, TRUE, 1);
gtk_container_add (GTK_CONTAINER (window), box);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
void crete_new_wind (GtkWidget *widget){
GtkWidget *window, *button, *box;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Second Window");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
gtk_widget_set_size_request (window, 300, 300);
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);;
g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), widget);
button = gtk_button_new_with_label ("Go back to Window A");
g_signal_connect (G_OBJECT (button), "destroy", G_CALLBACK (destroy), NULL);
gtk_widget_hide(widget);
box = gtk_box_new (TRUE, 1);
gtk_box_pack_end (GTK_BOX (box), button, TRUE, TRUE, 1);
gtk_container_add (GTK_CONTAINER (window), box);
gtk_widget_show_all (window);
}
gboolean destroy (GtkWidget *widget){
gtk_widget_destroy (widget);
return TRUE;
}
If I click on the button(Go to Window B) I have this:
But the main window is still there, avaible to the user which is not what I need.
Thats because the clicked callback wants two parameters
Change the prototype and the function to
static void crete_new_wind(GtkButton *dummy, gpointer widget);
static void crete_new_wind(GtkButton *dummy, gpointer widget) {
in order to use the second parameter in your function.

How to make gtk_window_set_position of gtk work?

I want to set the position of the window using gtk_window_set_position
but it seems that after the window is created, the gtk_window_set_position will not take effect.
I'm wondering how to call gtk_window_set_position after the window shows up, i.e. a button event?
I just wrote a minimal working example that implements two approaches. One approach uses gtk_window_move and the other gtk_window_set_position.
If you have the gtk+ reference at hand the code should be self explanatory.
#include <gtk/gtk.h>
#include <glib.h>
void
button1_clicked_cb (GtkWidget * widget, GtkWindow * window)
{
GdkWindow *root;
gint width, height, rwidth, rheight;
gtk_window_get_size (window, &width, &height);
root = gtk_widget_get_root_window (GTK_WIDGET (window));
gdk_window_get_geometry (root, NULL, NULL, &rwidth,
&rheight);
gtk_window_move (window, (rwidth - width) / 2,
(rheight - height) / 2);
}
void
button2_clicked_cb (GtkWidget * widget, GtkWindow * window)
{
gtk_widget_hide (GTK_WIDGET (window));
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_widget_show_all (GTK_WIDGET (window));
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *box;
GtkWidget *button1;
GtkWidget *button2;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
button1 = gtk_button_new_with_label ("approach 1");
button2 = gtk_button_new_with_label ("approach 2");
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
gtk_box_pack_start (GTK_BOX (box), button1, TRUE, TRUE,
10);
gtk_box_pack_start (GTK_BOX (box), button2, TRUE, TRUE,
10);
gtk_container_add (GTK_CONTAINER (window), box);
gtk_widget_show_all (window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect (button1, "clicked",
G_CALLBACK (button1_clicked_cb),
window);
g_signal_connect (button2, "clicked",
G_CALLBACK (button2_clicked_cb),
window);
gtk_main ();
return 0;
}

Problem about GThread and file copy

// gcc -o 0 $(pkg-config --cflags --libs gtk+-2.0) 1.c
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
struct tst
{
GtkWidget *win, *w2, *hb, *vb, *ent, *btn, *b2, *pbar;
GtkAccelGroup *acc;
};
GCancellable *can1;
GError *err1;
GThread *t1;
static void t1_stop (struct tst *prg)
{
g_cancellable_cancel (can1);
can1 = NULL;
}
gpointer t1_do (gpointer ptr1)
{
struct tst *prg = (gpointer)ptr1;
g_file_copy (g_file_new_for_path ("/1.avi"), g_file_new_for_path ("/2.avi"), G_FILE_COPY_NOFOLLOW_SYMLINKS, can1, NULL, NULL, &err1);
if (err1 != NULL) g_error_free (err1);
gtk_widget_destroy (prg->w2);
}
static void window_pbar (struct tst *prg)
{
prg->w2 = gtk_window_new (GTK_WINDOW_TOPLEVEL);
prg->hb = gtk_hbox_new (FALSE, 0);
prg->pbar = gtk_progress_bar_new ();
prg->b2 = gtk_button_new_with_label ("Cancel");
gtk_container_add (GTK_CONTAINER (prg->w2), GTK_WIDGET (prg->hb));
gtk_window_set_position (GTK_WINDOW (prg->w2), GTK_WIN_POS_CENTER);
gtk_box_pack_start (GTK_BOX (prg->hb), GTK_WIDGET (prg->pbar), FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (prg->hb), GTK_WIDGET (prg->b2), FALSE, FALSE, 0);
g_signal_connect_swapped (prg->w2, "delete_event", G_CALLBACK (t1_stop), prg);
g_signal_connect_swapped (prg->b2, "clicked", G_CALLBACK (t1_stop), prg);
gtk_widget_show_all (GTK_WIDGET (prg->w2));
can1 = g_cancellable_new ();
err1 = NULL;
t1 = g_thread_create (t1_do, (gpointer)prg, TRUE, NULL);
}
static void window_new ()
{
struct tst *prg = g_new0 (struct tst, 1);
prg->win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
prg->vb = gtk_vbox_new (FALSE, 0);
prg->btn = gtk_button_new_with_label ("start");
gtk_container_add (GTK_CONTAINER (prg->win), GTK_WIDGET (prg->vb));
gtk_box_pack_start (GTK_BOX (prg->vb), GTK_WIDGET (prg->btn), FALSE, FALSE, 0);
g_signal_connect (prg->win, "delete_event", G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect_swapped (prg->btn, "clicked", G_CALLBACK (window_pbar), prg);
gtk_window_set_title (GTK_WINDOW (prg->win), "Test program");
gtk_window_set_position (GTK_WINDOW (prg->win), GTK_WIN_POS_CENTER);
gtk_widget_show_all (GTK_WIDGET (prg->win));
gtk_main ();
}
int main (int argc, char *argv[])
{
gtk_init (&argc, &argv);
window_new ();
return 0;
}
This program is an example. When 'start' button is clicked the program creates a window with progress bar and 'cancel' button, and make a thread to copy /1.avi to /2.avi, but because of /1.avi doesn't exist the program will write 'Error!' on terminal and close the progress bar window.
But there is one problem in this program. While I click 'start' button many times somewhen the program writes another error messages on terminal. Sometimes the messages are about GDK, sometimes about GObject, and sometimes about GTK+. And sometimes program itself is freezed or crashed.
// gcc -o 0 $(pkg-config --cflags --libs gtk+-2.0) 1.c
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
struct tst
{
GtkWidget *win, *w2, *hb, *vb, *ent, *btn, *b2, *pbar;
GtkAccelGroup *acc;
};
GCancellable *can1;
GError *err1;
GThread *t1;
static void t1_stop (struct tst *prg)
{
g_cancellable_cancel (can1);
can1 = NULL;
}
gpointer t1_do (gpointer ptr1)
{
struct tst *prg = (gpointer)ptr1;
g_file_copy (g_file_new_for_path ("/1.avi"), g_file_new_for_path ("/2.avi"), G_FILE_COPY_NOFOLLOW_SYMLINKS, can1, NULL, NULL, &err1);
if (err1 != NULL) g_error_free (err1);
gtk_widget_destroy (prg->w2);
}
static void window_pbar (struct tst *prg)
{
prg->w2 = gtk_window_new (GTK_WINDOW_TOPLEVEL);
prg->hb = gtk_hbox_new (FALSE, 0);
prg->pbar = gtk_progress_bar_new ();
prg->b2 = gtk_button_new_with_label ("Cancel");
gtk_container_add (GTK_CONTAINER (prg->w2), GTK_WIDGET (prg->hb));
gtk_window_set_position (GTK_WINDOW (prg->w2), GTK_WIN_POS_CENTER);
gtk_box_pack_start (GTK_BOX (prg->hb), GTK_WIDGET (prg->pbar), FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (prg->hb), GTK_WIDGET (prg->b2), FALSE, FALSE, 0);
g_signal_connect_swapped (prg->w2, "delete_event", G_CALLBACK (t1_stop), prg);
g_signal_connect_swapped (prg->b2, "clicked", G_CALLBACK (t1_stop), prg);
gtk_widget_show_all (GTK_WIDGET (prg->w2));
can1 = g_cancellable_new ();
err1 = NULL;
t1 = g_thread_create (t1_do, (gpointer)prg, TRUE, NULL);
g_thread_join (t1);
}
static void window_new ()
{
struct tst *prg = g_new0 (struct tst, 1);
prg->win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
prg->vb = gtk_vbox_new (FALSE, 0);
prg->btn = gtk_button_new_with_label ("start");
gtk_container_add (GTK_CONTAINER (prg->win), GTK_WIDGET (prg->vb));
gtk_box_pack_start (GTK_BOX (prg->vb), GTK_WIDGET (prg->btn), FALSE, FALSE, 0);
g_signal_connect (prg->win, "delete_event", G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect_swapped (prg->btn, "clicked", G_CALLBACK (window_pbar), prg);
gtk_window_set_title (GTK_WINDOW (prg->win), "Test program");
gtk_window_set_position (GTK_WINDOW (prg->win), GTK_WIN_POS_CENTER);
gtk_widget_show_all (GTK_WIDGET (prg->win));
gtk_main ();
}
int main (int argc, char *argv[])
{
gtk_init (&argc, &argv);
window_new ();
return 0;
}
So I modified some parts of program. Now the problem not occurs though I click 'start' button many times, but I met another problem. When I can copy /1.avi to /2.avi, if I click 'start' button then program copies /1.avi to /2.avi but during this process the program window freezes, and progress bar window doesn't appear(On first example this problem isn't occured).
What should I do to make this program to meet neither of two problems?
The immediate problem I can see with your code is that you are calling a Gtk function in t1_do which is run from the secondary thread without enclosing it in gtk_thread_enter (); gtk_thread_leave ();
The general rule is that you should never call a UI function from a thread that isn't the main UI thread. Until you fix that problem you could just get completely random errors and behaviour

Resources