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.
Related
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.
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.
Screenshot of the output
i am new with gtk+. while learning to create menus in gtk+ i simply copy paste the following code and when i run it....i don't know what is the problem but only it shows window. it does not show any menus or menu bar... help me if anyone has been through this problem...
#include <gtk/gtk.h>
GdkPixbuf *create_pixbuf(const gchar * filename)
{
GdkPixbuf *pixbuf;
GError *error = NULL;
pixbuf = gdk_pixbuf_new_from_file(filename, &error);
if (!pixbuf) {
fprintf(stderr, "%s\n", error->message);
g_error_free(error);
}
return pixbuf;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *icon;
GtkWidget *vbox;
GtkWidget *menubar;
GtkWidget *fileMenu;
GtkWidget *fileMi;
GtkWidget *quitMi;
GtkWidget *text_view;
GtkWidget *buffer;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Write Pad");
gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
icon = create_pixbuf("Web.png");
gtk_window_set_icon(GTK_WINDOW(window), icon);
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
text_view = gtk_text_view_new ();
gtk_box_pack_start (GTK_BOX (vbox), text_view, 1, 1, 0);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
menubar = gtk_menu_bar_new();
fileMenu = gtk_menu_new();
fileMi = gtk_menu_item_new_with_label("File");
quitMi = gtk_menu_item_new_with_label("Quit");
gtk_menu_item_set_submenu(GTK_MENU_ITEM(fileMi), fileMenu);
gtk_menu_shell_append(GTK_MENU_SHELL(fileMenu), quitMi);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), fileMi);
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(quitMi), "activate", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
There are a few problems with the code. All of the variables you declare use the GtkWidget * type, while the functions create_pixbuf and gtk_text_view_get_buffer return data of the GdkPixbuf * and GtkTextBuffer * types. You also use a deprecated function.
Moreover, you call the menu related functions after the GtkTextView related functions, thereby placing the menu at the bottom of the window.
Here is the working code:
#include <gtk/gtk.h>
GdkPixbuf *
create_pixbuf (const gchar *filename)
{
GdkPixbuf *pixbuf;
GError *error = NULL;
pixbuf = gdk_pixbuf_new_from_file (filename, &error);
if (!pixbuf) {
fprintf (stderr, "%s\n", error->message);
g_error_free (error);
}
return pixbuf;
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
GdkPixbuf *icon;
GtkWidget *vbox;
GtkWidget *menubar;
GtkWidget *fileMenu;
GtkWidget *fileMi;
GtkWidget *quitMi;
GtkWidget *text_view;
GtkTextBuffer *buffer;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
icon = create_pixbuf ("Web.png");
gtk_window_set_title (GTK_WINDOW (window), "Write Pad");
gtk_window_set_default_size (GTK_WINDOW (window), 500, 400);
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
gtk_window_set_icon (GTK_WINDOW (window), icon);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (window), vbox);
menubar = gtk_menu_bar_new ();
fileMenu = gtk_menu_new ();
fileMi = gtk_menu_item_new_with_label ("File");
quitMi = gtk_menu_item_new_with_label ("Quit");
gtk_menu_item_set_submenu (GTK_MENU_ITEM (fileMi), fileMenu);
gtk_menu_shell_append (GTK_MENU_SHELL (fileMenu), quitMi);
gtk_menu_shell_append (GTK_MENU_SHELL (menubar), fileMi);
gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0);
text_view = gtk_text_view_new ();
gtk_box_pack_start (GTK_BOX (vbox), text_view, TRUE, TRUE, 0);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect (G_OBJECT (quitMi), "activate", G_CALLBACK (gtk_main_quit), NULL);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
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;
}
// 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