// 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
Related
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.
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.
Using GTK3 in C, I have an interface with buttons. I want a user with a mouse to be able to press a button OR use press a single button on the keyboard to do the same thing.
MWE (modified from GTK3 Hello World example):
/*
* Ignore keyboard cursor in GTK3 C
*/
#include <gtk/gtk.h>
void thing() {
printf("did a thing\n");
}
void otherthing() {
printf("did something different\n");
}
static gboolean key_event(GtkWidget *widget, GdkEventKey *event) {
gchar* val = gdk_keyval_name (event->keyval);
if (strcmp(val, "Left") == 0) {
thing();
}
return 0;
}
static void activate (GtkApplication *app, gpointer user_data) {
GtkWidget *window;
GtkWidget *button;
GtkWidget *button2;
GtkWidget *button_box;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (window), button_box);
button = gtk_button_new_with_label ("Do the thing");
button2 = gtk_button_new_with_label ("xxx");
g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
g_signal_connect (button, "clicked", G_CALLBACK (thing), window);
g_signal_connect (button2, "clicked", G_CALLBACK (otherthing), window);
gtk_container_add (GTK_CONTAINER (button_box), button2);
gtk_container_add (GTK_CONTAINER (button_box), button);
gtk_widget_show_all (window);
}
int main (int argc, char **argv) {
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.example", 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;
}
In this program, the user can press the left arrow key to execute thing. The user can also click on the gui button to execute thing. However, hitting certain keyboard keys such as space or enter will "click" on the gui button to execute thing.
How do I prevent the keyboard from "clicking" on a button which the keyboard cursor is on in this case?
Fake Button Hack
I have hacked a workaround into my code for now using a useless button. I will not be marking this answer as solved since it is very sloppy, but it does the job until something better becomes available.
Description
This hack adds another button with no functions assigned. Using gtk_widget_grab_focus, we force this useless "fakebutton" to hold keyboard focus. We reissue this command every time a button is pressed.
Problems
Grabbing focus back to the fakebutton is slow. The user can issue a quick succession of commands (in the case of the MWE by pressing Left and Space to erroneously issue the otherthing function).
MWE
/*
* Ignore keyboard cursor in GTK3 C
*/
#include <gtk/gtk.h>
GtkWidget *fakebutton;
void thing() {
printf("did a thing\n");
}
void otherthing() {
printf("did something different\n");
}
static gboolean key_event(GtkWidget *widget, GdkEventKey *event) {
gchar* val = gdk_keyval_name (event->keyval);
if (strcmp(val, "Left") == 0) {
thing();
gtk_widget_grab_focus(fakebutton);
} else {
gtk_widget_grab_focus(fakebutton);
}
return 0;
}
static void activate (GtkApplication *app, gpointer user_data) {
GtkWidget *window;
GtkWidget *button;
GtkWidget *button2;
GtkWidget *button_box;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (window), button_box);
button = gtk_button_new_with_label ("Do the thing");
button2 = gtk_button_new_with_label ("xxx");
fakebutton = gtk_button_new();
g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
g_signal_connect (button, "clicked", G_CALLBACK (thing), window);
g_signal_connect (button2, "clicked", G_CALLBACK (otherthing), window);
gtk_container_add (GTK_CONTAINER (button_box), button2);
gtk_container_add (GTK_CONTAINER (button_box), fakebutton);
gtk_container_add (GTK_CONTAINER (button_box), button);
gtk_widget_show_all (window);
}
int main (int argc, char **argv) {
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.example", 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;
}
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.
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;
}