Reputation: 75
I am making a little project in C and using GTK for UI. I have a problem with freezes and exceptions, which as I assume are triggered by the way my app uses threads. I needed to stop the app (the functions like playersTurn(), leftBotsTurn()), in order to wait for user input(used while(var); loops, var is set to false after the user clicks any button.) For this purposes I started using threads, because if you don't let the window function finish it won't draw the window.
So there are few functions:
Main:
int main (int argc, char **argv){
openMenu(argc, argv);
return 0;}
openMenu
static void openMenu(int argc, char *argv[]){
GtkBuilder *builder;
GtkWidget *window;
gtk_init(&argc, &argv);
builder = gtk_builder_new_from_file("menu_window_glade.glade");
window = GTK_WIDGET(gtk_builder_get_object(builder, "menu_window"));
gtk_builder_connect_signals(builder, NULL);
gtk_widget_show(window);
gtk_main();
}
newGame
void newGame(){
GtkBuilder *builder;
GtkWidget *window;
widgetsPtrs *widgets = (widgetsPtrs *) malloc(sizeof(widgetsPtrs));
builder = gtk_builder_new_from_file("game_glade.glade");
window = GTK_WIDGET(gtk_builder_get_object(builder, "game_glade_window"));
gtk_builder_connect_signals(builder, NULL);
gtk_widget_show(window);
/* Getting PlayersHand, AttackingRow, DefendingRow,TrumpImage pointers. */
for(int i = 0; i < 20; i++){
//The code is hidden, but all it does is uses gtk_builder_get_object and saves pointers
//in "widgets"
}
//g_mutex_init(myMutex); Tried to use mutex, but I couldn't find any example of g_mutex.
GThread *thread;
thread = g_thread_new("gameLoop", gameLoop, widgets);
}
Game loop
void *gameLoop(void *value){
widgetsPtrs *widgets = (widgetsPtrs *)value;
cardsOnTheTable = malloc(sizeof(card));
cardsOnTheTable->next = NULL;
shuffleTheDeck();//allocates a card for the Deck. Shuffles it, makes a SLL out of it.
player = malloc(sizeof(card));
leftBot = malloc(sizeof(card));
rightBot = malloc(sizeof(card));
player->next = NULL;
leftBot->next = NULL;
rightBot->next = NULL;
deal(player);
deal(leftBot);
deal(rightBot);
printPlayersCards(player, leftBot, rightBot);
//g_mutex_lock(myMutex);
//Setting trump image.
card *tmpTrumpCard = getTheLastCard(Deck);
setCardImage(tmpTrumpCard, GTK_IMAGE(widgets->w_trumpImagePtr));
//g_mutex_lock(myMutex);
int a = firstTurnCheck();
int turnResult = 0;
while((Deck->next != NULL) || ((player->next != NULL) && ((leftBot->next != NULL) || (rightBot->next != NULL)) ) ){
//g_mutex_lock(myMutex);
showPlayerCards(widgets);
sleep(1);
if((a % 3) == 0){
puts("PlayersTurn. //GameLoop");
turnResult = playersTurn(widgets);
if(turnResult == 1){
a = 1;
}else{
a = 2;
}
}else if((a % 3) == 1){
puts("LeftbotsTurn. //GameLoop");
turnResult = leftBotsTurn(widgets);
if(turnResult == 1){
a = 2;
}else{
a = 0;
}
}else if((a%3) == 2){
puts("RightbotsTurn. //GameLoop");
turnResult = rightBotsTurn(widgets);
if(turnResult == 1){
a = 0;
}else{
a = 1;
}
}
hidePlayerCards(widgets);
deal(player);
deal(leftBot);
deal(rightBot);
clearTheTable(widgets);
printPlayersCards(player, leftBot, rightBot);
cardsOnTheTable->next = NULL;
//g_mutex_unlock(myMutex);
sleep(1);
}
// while((Deck->next != NULL) || (player->next != NULL && leftBot->next != NULL) || (player->next != NULL && rightBot->next != NULL)){
// gtk_widget_set_sensitive((widgets->w_buttons[2]), true);
// if(a == 0){
// }else if(a == 1){
// }else if(a == 2){
// }
// }
if(player->next == NULL){
puts("You won!");
}else{
puts("Jokes on you. ");
}
//pthread_exit(NULL);
free(player);
free(leftBot);
free(rightBot);
free(Deck);
free(widgets);
free(cardsOnTheTable);
return NULL;}
Errors
[xcb] Unknown request in queue while dequeuing
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
main: ../../src/xcb_io.c:165: dequeue_pending_request: Assertion `!xcb_xlib_unknown_req_in_deq' failed.
Aborted (core dumped)
Can anyone help me resolve this issue??
Upvotes: 0
Views: 643
Reputation: 694
To initialise support for concurrent threads call XInitThreads(); before gtk_init();
you can only update the gui from the main thread. To invoke changes from a different thread you have to call g_idle_add().
#include <gtk/gtk.h>
int counter = 0;
void idleLoop(gpointer data) {
char *yolo = g_strdup_printf("counting ... %d", counter);
gtk_label_set_text(GTK_LABEL(data), yolo);
g_free(yolo);
}
void *gameLoop(gpointer data) {
printf("starting loop \n");
while (1) {
counter++;
/*
#IMPO# putting the ui update command here wont work
char *yolo = g_strdup_printf("counting ... %d", counter);
gtk_label_set_text(GTK_LABEL(data), yolo);
g_free(yolo);
*/
g_usleep(5000);
g_idle_add(idleLoop, data);
}
return NULL;
}
int main(int argc, char *argv[]) {
gtk_init(&argc, &argv);
GtkWidget *win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(win), "Window");
gtk_window_set_resizable(GTK_WINDOW(win), FALSE);
GtkWidget *label = gtk_label_new(
"<big>This is a long text that might need to be wrapped</big>");
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
g_object_set(label, "margin", 20, NULL);
gtk_container_add(GTK_CONTAINER(win), label);
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_label_set_max_width_chars(GTK_LABEL(label), 30);
g_signal_connect(GTK_WIDGET(win), "destroy", gtk_main_quit, NULL);
gtk_widget_show_all(GTK_WIDGET(win));
g_thread_new("gameLoop", gameLoop, label);
gtk_main();
}
https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-idle-add
this will give you a better undestaring of main loop (https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html)
Upvotes: 1