How Automatically Update Two or Several GtkDrawAreas in C - c

I'm trying to develop a little Supervision System with two GtkDrawarea Widgets and update them simultaneously whenever I toogle the buttons regarded for each Drawarea. A little example I made for ploting two sinoides.
However just the first GtkDrawarea Widget are updated in did, the other remains freezed until I rezise the GtkWindow. I tried use g_timeout_add_full but I seens to work only with one GtkDrawArea.
I'm sending an image of my test aplication.
If someone could help me I will be very thankful.
PS: Sorry for my English :-)
Here is my code:
#include <stdlib.h>
#include <gtk/gtk.h>
#include <glib.h>
#include <cairo.h>
#include <math.h>
#include <unistd.h>
#include <stdlib.h>
GtkWidget *window;
GtkWidget *darea1;
GtkWidget *darea2;
double w_larg = 1600;
double w_alt = 1200;
bool toggle_stat1 = false;
bool toggle_stat2 = false;
int width, height;
double fase1 = 2;
double amp1 = 1.25;
double fase2 = 4;
double amp2 = 1.25;
gboolean flag_amp1 = TRUE;
gboolean flag_amp2 = TRUE;
static gboolean invalidate_drawing1(gpointer data);
static gboolean invalidate_drawing2(gpointer data);
//*******************************************************************************
static gboolean on_toggled1(GtkWidget *widget, gpointer data)
{
if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
{toggle_stat1 = true;
printf("ToggleButton01 --> Acionado / toggle_stat1 = %d\n",toggle_stat1);
g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE,250,invalidate_drawing1,darea1,NULL); // Variação atualizada da linha acima :-)
}
else
{toggle_stat1 = false;
printf("ToggleButton01 --> Liberado / toggle_stat1 = %d\n",toggle_stat1);
}
return FALSE;
}
//*******************************************************************************
static gboolean on_toggled2(GtkWidget *widget, gpointer data)
{
if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
{toggle_stat2 = true;
printf("ToggleButton02 --> Acionado / toggle_stat2 = %d\n",toggle_stat2);
g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE,250,invalidate_drawing2,darea2,NULL); // Variação atualizada da linha acima :-)
}
else
{toggle_stat2 = false;
printf("ToggleButton02 --> Liberado / toggle_stat2 = %d\n",toggle_stat2);
}
return FALSE;
}
//*******************************************************************************
//*******************************************************************************
//*******************************************************************************
//*******************************************************************************
static gboolean draw_darea1(GtkWidget *widget, cairo_t *cr, gpointer data)
{
int valor1;
double valor2;
static const double dashed1[] = {4.0, 21.0, 2.0};
static const double dashed3[] = {2.0};
cr = gdk_cairo_create(gtk_widget_get_window(widget));
cairo_set_source_rgba(cr, 0.45, 0.45, 0.45, 1);
cairo_rectangle(cr,0 , 0, widget->allocation.width, widget->allocation.height);
cairo_fill(cr);
double i = widget->allocation.width;
double j = widget->allocation.height;
double sc = fase1*M_PI/i;
double y;
double h = 0;
if (amp1 != 0) h = h + j/amp1;
//---------------------------------------------------------------------------
cairo_set_source_rgba(cr, 0, 0, 1, 1);
cairo_set_line_width(cr, 1.5);
cairo_move_to(cr, 0, (j/2)+(sin( (-i/2)*sc )*(h/2)) );
for(double x=(-i/2);x<=(i/2);x=x+2)
{
valor1 = rand()%5;
valor2 = rand()%50;
y=x*sc;
if (valor1 < 3 ) cairo_line_to(cr,x+(i/2),(j/2)+(sin(y)*(h/2)) + valor2 );
if (valor1 == 3) cairo_line_to(cr,x+(i/2),(j/2)+(sin(y)*(h/2)) );
if (valor1 > 3 ) cairo_line_to(cr,x+(i/2),(j/2)+(sin(y)*(h/2)) - valor2 );
}
cairo_stroke(cr);
//---------------------------------------------------------------------------
cairo_set_source_rgba(cr, 1, 1, 0, 1);
cairo_set_dash(cr,dashed1, 1, 0 );
cairo_set_line_width(cr, 1.5);
cairo_move_to(cr, 0, (j/2)+(sin( (-i/2)*sc )*(h/2)) );
for(double x=(-i/2);x<=(i/2);x=x+10)
{
y=x*sc;
cairo_line_to(cr,x+(i/2),(j/2)+(sin(y)*(h/2)) );
}
cairo_stroke(cr);
//---------------------------------------------------------------------------
cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1);
cairo_set_dash(cr,dashed3, 1, 0 );
cairo_set_line_width(cr, 1.0);
cairo_move_to(cr,0,(j/2));
cairo_line_to(cr,i,(j/2));
cairo_move_to(cr,(i/2),0);
cairo_line_to(cr,(i/2),j);
cairo_stroke(cr);
cairo_destroy(cr);
return TRUE;
}
//*******************************************************************************
//*******************************************************************************
//*******************************************************************************
//*******************************************************************************
static gboolean draw_darea2(GtkWidget *widget, cairo_t *cr, gpointer data)
{
int valor1;
double valor2;
static const double dashed1[] = {4.0, 21.0, 2.0};
static const double dashed3[] = {2.0};
cr = gdk_cairo_create(gtk_widget_get_window(widget));
cairo_set_source_rgba(cr, 0.45, 0.45, 0.45, 1);
cairo_rectangle(cr,0 , 0, widget->allocation.width, widget->allocation.height);
cairo_fill(cr);
double i = widget->allocation.width;
double j = widget->allocation.height;
double sc = fase2*M_PI/i;
double y;
double h = 0;
if (amp2 != 0) h = h + j/amp2;
//---------------------
cairo_set_source_rgba(cr, 0, 0, 1, 1);
cairo_set_line_width(cr, 1.5);
cairo_move_to(cr, 0, (j/2)+(sin( (-i/2)*sc )*(h/2)) );
for(double x=(-i/2);x<=(i/2);x=x+2)
{
valor1 = rand()%5;
valor2 = rand()%50;
y=x*sc;
if (valor1 < 3 ) cairo_line_to(cr,x+(i/2),(j/2)+(sin(y)*(h/2)) + valor2 );
if (valor1 == 3) cairo_line_to(cr,x+(i/2),(j/2)+(sin(y)*(h/2)) );
if (valor1 > 3 ) cairo_line_to(cr,x+(i/2),(j/2)+(sin(y)*(h/2)) - valor2 );
}
cairo_stroke(cr);
//---------------------
cairo_set_source_rgba(cr, 0, 1, 0, 1);
cairo_set_dash(cr,dashed1, 1, 0 );
cairo_set_line_width(cr, 1.5);
cairo_move_to(cr, 0, (j/2)+(sin( (-i/2)*sc )*(h/2)) );
for(double x=(-i/2);x<=(i/2);x=x+10)
{
y=x*sc;
cairo_line_to(cr,x+(i/2),(j/2)+(sin(y)*(h/2)) );
}
cairo_stroke(cr);
//---------------------
cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1);
cairo_set_dash(cr,dashed3, 1, 0 );
cairo_set_line_width(cr, 1.0);
cairo_move_to(cr,0,(j/2));
cairo_line_to(cr,i,(j/2));
cairo_move_to(cr,(i/2),0);
cairo_line_to(cr,(i/2),j);
cairo_stroke(cr);
cairo_destroy(cr);
return TRUE;
}
//*******************************************************************************
//*******************************************************************************
//*******************************************************************************
//*******************************************************************************
static gboolean invalidate_drawing1(gpointer data)
{
GdkWindow *win;
g_print("T_Signal-1 | amp1 = %2.3f | ",amp1);
if (toggle_stat1==true)
{
if ((flag_amp1==TRUE)&&(amp1 <= 3))
amp1=amp1+0.25;
else
flag_amp1=FALSE;
if ((flag_amp1==FALSE)&&(amp1 >= 1.25))
amp1=amp1-0.25;
else
flag_amp1=TRUE;
}
//---------------------
win = gtk_widget_get_window(GTK_WIDGET(data));
if (win) {
GtkAllocation allocation;
gtk_widget_get_allocation(GTK_WIDGET(data), &allocation);
gdk_window_invalidate_rect(win, &allocation, FALSE);
}
if (flag_amp1 == TRUE)
return TRUE;
else
return FALSE;
}
//**********************
//**********************
//**********************
static gboolean invalidate_drawing2(gpointer data)
{
GdkWindow *win;
//---------------------
g_print("T_Signal-2 | amp2 = %2.3f\n",amp2);
if (toggle_stat2==true)
{
if ((flag_amp2==TRUE)&&(amp2 <= 3))
amp2=amp2+0.25;
else
flag_amp2=FALSE;
if ((flag_amp2==FALSE)&&(amp2 >= 1.25))
amp2=amp2-0.25;
else
flag_amp2=TRUE;
}
//---------------------
win = gtk_widget_get_window(GTK_WIDGET(data));
if (win) {
GtkAllocation allocation;
gtk_widget_get_allocation(GTK_WIDGET(data), &allocation);
gdk_window_invalidate_rect(win, &allocation, FALSE);
}
if (flag_amp2 == TRUE)
return TRUE;
else
return FALSE;
}
//**********************
//**********************
//**********************
int main (int argc, char *argv[])
{
GtkBuilder *builder;
GtkWidget *togglebutton1;
GtkWidget *togglebutton2;
GtkWidget *togglebutton3;
GtkWidget *button1; // Amp+
GtkWidget *button2; // Amp-
gtk_init (&argc, &argv);
builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, "GTK_Glade_2DrawArea01-R00.glade", NULL); //Carrega as informações do projeto glade para o GtkBuilder
window = GTK_WIDGET(gtk_builder_get_object (builder, "window1")); //Retorna o objeto Window, para mostrá-lo mais tarde
darea1 = GTK_WIDGET(gtk_builder_get_object (builder, "drawingarea1")); //Retorna o objeto DrawingArea, para mostrá-lo mais tarde
darea2 = GTK_WIDGET(gtk_builder_get_object (builder, "drawingarea2")); //Retorna o objeto DrawingArea, para mostrá-lo mais tarde
togglebutton1 = GTK_WIDGET(gtk_builder_get_object (builder, "togglebutton1")); //Retorna o objeto togglebutton1, para mostrá-lo mais tarde
togglebutton2 = GTK_WIDGET(gtk_builder_get_object (builder, "togglebutton2")); //Retorna o objeto togglebutton1, para mostrá-lo mais tarde
togglebutton3 = GTK_WIDGET(gtk_builder_get_object (builder, "togglebutton3")); //Retorna o objeto togglebutton1, para mostrá-lo mais tarde
button1 = GTK_WIDGET(gtk_builder_get_object (builder, "button1")); //Retorna o objeto button1, para mostrá-lo mais tarde
button2 = GTK_WIDGET(gtk_builder_get_object (builder, "button2")); //Retorna o objeto button2, para mostrá-lo mais tarde
gtk_window_set_title(GTK_WINDOW(window), "GTK 2 Viewports DrawArea 01");
gtk_builder_connect_signals (builder, NULL); //Conecta todos os eventos dentro do projeto do glade.
g_object_unref (G_OBJECT (builder)); //Exclui o GtkBuilder, pois não iremos mais usá-lo nesse exemplo.
g_signal_connect(G_OBJECT(togglebutton1) , "toggled" , G_CALLBACK(on_toggled1) , NULL);
g_signal_connect(G_OBJECT(togglebutton2) , "toggled" , G_CALLBACK(on_toggled2) , NULL);
g_signal_connect(G_OBJECT(darea1), "expose-event", G_CALLBACK(draw_darea1), NULL);
g_signal_connect(G_OBJECT(darea2), "expose-event", G_CALLBACK(draw_darea2), NULL);
g_signal_connect_swapped(G_OBJECT(window) , "destroy", G_CALLBACK(gtk_main_quit) , G_OBJECT(window));
gtk_widget_show_all(window); //Mostra a janela com seus objetos
gtk_main ();
return 0;
}
Here's the code fixed (below) after the suggestion andlabs and wogsland. Thank you.
#include <stdlib.h>
#include <gtk/gtk.h>
#include <glib.h>
#include <cairo.h>
#include <math.h>
#include <unistd.h>
#include <stdlib.h>
GtkWidget *window;
GtkWidget *darea1;
GtkWidget *darea2;
bool toggle_stat1 = false;
bool toggle_stat2 = false;
double fase1 = 2;
double amp1 = 1.25;
double fase2 = 4;
double amp2 = 1.25;
gboolean flag_amp1 = TRUE;
gboolean flag_amp2 = TRUE;
//*******************************************************************************
static gboolean on_toggled1(GtkWidget *widget, gpointer data)
{
if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
{toggle_stat1 = true;
printf("ToggleButton01 --> Acionado / toggle_stat1 = %d\n",toggle_stat1);
}
else
{toggle_stat1 = false;
printf("ToggleButton01 --> Liberado / toggle_stat1 = %d\n",toggle_stat1);
}
return FALSE;
}
//*******************************************************************************
static gboolean on_toggled2(GtkWidget *widget, gpointer data)
{
if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
{toggle_stat2 = true;
printf("ToggleButton02 --> Acionado / toggle_stat2 = %d\n",toggle_stat2);
}
else
{toggle_stat2 = false;
printf("ToggleButton02 --> Liberado / toggle_stat2 = %d\n",toggle_stat2);
}
return FALSE;
}
//*******************************************************************************
//*******************************************************************************
static gboolean draw_darea1(GtkWidget *widget, cairo_t *cr, gpointer data)
{
static const double dashed1[] = {4.0, 21.0, 2.0};
cr = gdk_cairo_create(gtk_widget_get_window(widget));
cairo_set_source_rgba(cr, 0.45, 0.45, 0.45, 1);
cairo_rectangle(cr,0 , 0, widget->allocation.width, widget->allocation.height);
cairo_fill(cr);
double i = widget->allocation.width;
double j = widget->allocation.height;
double sc = fase1*M_PI/i;
double y;
double h = 0;
if (amp1 != 0) h = h + j/amp1;
//---------------------------------------------------------------------------
cairo_set_source_rgba(cr, 1, 1, 0, 1);
cairo_set_dash(cr,dashed1, 1, 0 );
cairo_set_line_width(cr, 1.5);
cairo_move_to(cr, 0, (j/2)+(sin( (-i/2)*sc )*(h/2)) );
for(double x=(-i/2);x<=(i/2);x=x+10)
{
y=x*sc;
cairo_line_to(cr,x+(i/2),(j/2)+(sin(y)*(h/2)) );
}
cairo_stroke(cr);
return TRUE;
}
//*******************************************************************************
//*******************************************************************************
static gboolean draw_darea2(GtkWidget *widget, cairo_t *cr, gpointer data)
{
static const double dashed1[] = {4.0, 21.0, 2.0};
cr = gdk_cairo_create(gtk_widget_get_window(widget));
cairo_set_source_rgba(cr, 0.45, 0.45, 0.45, 1);
cairo_rectangle(cr,0 , 0, widget->allocation.width, widget->allocation.height);
cairo_fill(cr);
double i = widget->allocation.width;
double j = widget->allocation.height;
double sc = fase2*M_PI/i;
double y;
double h = 0;
if (amp2 != 0) h = h + j/amp2;
//---------------------
cairo_set_source_rgba(cr, 0, 1, 0, 1);
cairo_set_dash(cr,dashed1, 1, 0 );
cairo_set_line_width(cr, 1.5);
cairo_move_to(cr, 0, (j/2)+(sin( (-i/2)*sc )*(h/2)) );
for(double x=(-i/2);x<=(i/2);x=x+10)
{
y=x*sc;
cairo_line_to(cr,x+(i/2),(j/2)+(sin(y)*(h/2)) );
}
cairo_stroke(cr);
return TRUE;
}
//*******************************************************************************
//*******************************************************************************
static gboolean invalidate_drawing1(GtkWidget *widget)
{
g_print("T_Signal-1 | amp1 = %2.3f | ",amp1);
if (toggle_stat1==true)
{
if ((flag_amp1==TRUE)&&(amp1 <= 3))
amp1=amp1+0.25;
else
flag_amp1=FALSE;
if ((flag_amp1==FALSE)&&(amp1 >= 1.25))
amp1=amp1-0.25;
else
flag_amp1=TRUE;
}
//---------------------
gtk_widget_queue_draw(widget);
return TRUE;
}
//**********************
//**********************
static gboolean invalidate_drawing2(GtkWidget *widget)
{
g_print("T_Signal-2 | amp2 = %2.3f\n",amp2);
if (toggle_stat2==true)
{
if ((flag_amp2==TRUE)&&(amp2 <= 3))
amp2=amp2+0.25;
else
flag_amp2=FALSE;
if ((flag_amp2==FALSE)&&(amp2 >= 1.25))
amp2=amp2-0.25;
else
flag_amp2=TRUE;
}
//---------------------
gtk_widget_queue_draw(widget);
return TRUE;
}
//**********************
int main (int argc, char *argv[])
{
GtkBuilder *builder;
GtkWidget *togglebutton1;
GtkWidget *togglebutton2;
gtk_init (&argc, &argv);
builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, "GTK_Glade_2DrawArea01-R00.glade", NULL); //Carrega as informações do projeto glade para o GtkBuilder
window = GTK_WIDGET(gtk_builder_get_object (builder, "window1")); //Retorna o objeto Window, para mostrá-lo mais tarde
darea1 = GTK_WIDGET(gtk_builder_get_object (builder, "drawingarea1")); //Retorna o objeto DrawingArea, para mostrá-lo mais tarde
darea2 = GTK_WIDGET(gtk_builder_get_object (builder, "drawingarea2")); //Retorna o objeto DrawingArea, para mostrá-lo mais tarde
togglebutton1 = GTK_WIDGET(gtk_builder_get_object (builder, "togglebutton1")); //Retorna o objeto togglebutton1, para mostrá-lo mais tarde
togglebutton2 = GTK_WIDGET(gtk_builder_get_object (builder, "togglebutton2")); //Retorna o objeto togglebutton1, para mostrá-lo mais tarde
gtk_window_set_title(GTK_WINDOW(window), "GTK 2 Viewports DrawArea 01");
gtk_builder_connect_signals (builder, NULL); //Conecta todos os eventos dentro do projeto do glade.
g_object_unref (G_OBJECT (builder)); //Exclui o GtkBuilder, pois não iremos mais usá-lo nesse exemplo.
g_signal_connect(G_OBJECT(togglebutton1) , "toggled" , G_CALLBACK(on_toggled1) , NULL);
g_signal_connect(G_OBJECT(togglebutton2) , "toggled" , G_CALLBACK(on_toggled2) , NULL);
g_signal_connect(G_OBJECT(darea1), "expose-event", G_CALLBACK(draw_darea1), NULL);
g_signal_connect(G_OBJECT(darea2), "expose-event", G_CALLBACK(draw_darea2), NULL);
g_signal_connect_swapped(G_OBJECT(window) , "destroy", G_CALLBACK(gtk_main_quit) , G_OBJECT(window));
g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE,250,(GSourceFunc)invalidate_drawing1,(gpointer)darea1,NULL); // Variação atualizada da linha acima :-)
g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE,250,(GSourceFunc)invalidate_drawing2,(gpointer)darea2,NULL); // Variação atualizada da linha acima :-)
gtk_widget_show_all(window); //Mostra a janela com seus objetos
gtk_main ();
return 0;
}
And the Final Image.

Don't use gdk_window_invalidate_rect(). Use gtk_widget_queue_draw() or gtk_widget_queue_draw_area().

Related

Text and Background not showing (sdl2 and sdl2_ttf) in C

I'm creating a menu in my game (available when I hit escape on the keyboard)
But the black background created with SDL_Rect and the text aren't showing and I don't understand why.
When I run my program I can change the background images by pressing on the arrows (up, down, left and right), and when I hit esc, i can't do anything until I hit esc another time, and then I can continue changing the background color with the arrows on my keyboard.
Does anybody can help me with this?
#include <SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <SDL_image.h>
#include <SDL2/SDL_ttf.h>
#define CHOICEMENU 2
void errorMessage(const char *message);
void errorMessageImg(const char *message);
void errorMessageTtf(const char *message);
int printTextTtf(SDL_Surface* window, TTF_Font* mainFont, const char* text);
int displayMenu(SDL_Surface* window, TTF_Font* font);
int main( int argc, char **argv)
{
//Pointeurs de la SDL :
SDL_Window *window = NULL;
SDL_Surface *windowSurface = NULL;
SDL_Surface *image1,*image2, *image3, *image4 = NULL;
SDL_Surface *currentImage = NULL;
SDL_Surface *icon = NULL;
SDL_Renderer *renderer = NULL;
int menu;
int running;
TTF_Init(); //initialisation des textes
TTF_Font *mainFont = NULL;
mainFont = TTF_OpenFont("couriernew.ttf",30);
icon = IMG_Load("img/flask.png");
SDL_SetWindowIcon(window,icon);
if(SDL_Init(SDL_INIT_VIDEO) != 0){ //retourne 0 si Ok
errorMessage("Erreur lors de la creation de la fenêtre et du rendu");
}
window = SDL_CreateWindow("Jeu Antoine et Robin", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
windowSurface = SDL_GetWindowSurface(window);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED |
SDL_RENDERER_PRESENTVSYNC);
//texture = SDL_LoadBMP("ici.bmp");
image1 = SDL_LoadBMP("img/image1.bmp");
if(image1 == NULL){
SDL_DestroyWindow(window);
errorMessage("Impossible de charger l'image 1");
}
image2 = SDL_LoadBMP("img/image2.bmp");
if(image2 == NULL){
SDL_DestroyWindow(window);
errorMessage("Impossible de charger l'image 2");
}
image3 = SDL_LoadBMP("img/image3.bmp");
if(image3 == NULL){
SDL_DestroyWindow(window);
errorMessage("Impossible de charger l'image 3");
}
image4 = SDL_LoadBMP("img/image4.bmp");
if(image4 == NULL){
SDL_DestroyWindow(window);
errorMessage("Impossible de charger l'image 4");
}
currentImage = image1;
int isRunning = 1;
SDL_Event ev;
while(isRunning == 1){
while(SDL_PollEvent(&ev) != 0 ){
if(ev.type == SDL_QUIT){
isRunning = false;
}else if(ev.type == SDL_KEYDOWN){
switch(ev.key.keysym.sym){
case SDLK_UP:
currentImage = image1;
break;
case SDLK_RIGHT:
currentImage = image2;
break;
case SDLK_LEFT:
currentImage = image3;
break;
case SDLK_DOWN:
currentImage = image4;
break;
case SDL_QUIT:
isRunning = 0;
break;
case SDLK_ESCAPE:
menu = displayMenu(windowSurface,mainFont);
if(menu == 1){
isRunning = false;
}
break;
}
}
}
SDL_BlitSurface(currentImage, NULL, windowSurface, NULL);
SDL_UpdateWindowSurface(window);
}
TTF_CloseFont(mainFont);
SDL_FreeSurface(image1);
SDL_FreeSurface(image2);
SDL_FreeSurface(image3);
SDL_FreeSurface(image4);
SDL_DestroyWindow(window);
SDL_FreeSurface(icon);
SDL_DestroyRenderer(renderer);
currentImage = image1 = image2 = image3 = NULL;
window = NULL;
SDL_Quit();
return 0;
}
int displayMenu(SDL_Surface* window, TTF_Font* font){
int x,y; // coordonées de la souris
int i;
int nMenu = CHOICEMENU; //nb de choix
const char* choice[CHOICEMENU] = {"Continuer","Quitter"};
SDL_Surface* menus[CHOICEMENU]; // surface des menus
int selected[CHOICEMENU]={0,0}; // 0 car aucun selectionné pour le moment
SDL_Color colorMenu[2]={{127,122,204},{49,100,226}};
menus[0] = TTF_RenderText_Solid(font, choice[0], colorMenu[0]);
menus[1] = TTF_RenderText_Solid(font, choice[1], colorMenu[1]);
SDL_Rect pos[CHOICEMENU];
pos[0].x = window->clip_rect.w/2 /*= centre */ - menus[0]->clip_rect.w/2;
pos[0].y = window->clip_rect.h/2 - menus[0]->clip_rect.h;
pos[1].x = window->clip_rect.w/2 - menus[0]->clip_rect.w/2;
pos[1].y = window->clip_rect.h/2 + menus[0]->clip_rect.h;
SDL_FillRect(window,&window->clip_rect,SDL_MapRGB(window-
>format,0x00,0x00,0x00));
SDL_Event ev;
while(1){
while(SDL_PollEvent(&ev)){
switch(ev.type){
case SDL_QUIT:
for(i = 0; i < CHOICEMENU ; i++){
SDL_FreeSurface(menus[i]);
}
return 1;
case SDL_MOUSEMOTION: // coordonée souris
x = ev.motion.x;
y = ev.motion.y;
for(i = 0; i < CHOICEMENU; i++){
if(x >= pos[i].x && x<= pos[i].x+pos[i].w && y>=pos[i].y &&
y<=pos[i].y+pos[i].h){
if(!selected[i]){
selected[i] = 1;
SDL_FreeSurface(menus[i]); // on suppr l'ancienne
surface
menus[i] = TTF_RenderText_Solid(font, choice[i],
colorMenu[1]);
} else {
if(selected[i]){
selected[i] = 0;
SDL_FreeSurface(menus[i]); // on suppr
l'ancienne surface
menus[i] = TTF_RenderText_Solid(font, choice[i],
colorMenu[0]);
}
}
}
case SDL_MOUSEBUTTONDOWN: //si qqn a cliquer sur la souris :
x = ev.button.x;
y = ev.button.y;
for (i = 0; i < CHOICEMENU; i+=1){
if(x >= pos[i].x && x<= pos[i].x+pos[i].w && y>=pos[i].y &&
y<=pos[i].y+pos[i].h){
for(i = 0 ;i < CHOICEMENU; i++){
SDL_FreeSurface(menus[i]);
}
return i; // On retourne la valeur actuelle : ex : si je
clique sur "continue" ça return 1
}
}
break;
case SDL_KEYDOWN:
if(ev.key.keysym.sym == SDLK_ESCAPE){
for(i = 0 ;i < CHOICEMENU; i++){
SDL_FreeSurface(menus[i]);
}
return 0;
}
}
}
for(i = 0; i < CHOICEMENU; i+=1){
SDL_BlitSurface(menus[i],NULL,window,&pos[i]);
}
}
}
}

Is this simplification of GTK+ code correct?

I found the following GTK+3 code in Zetcode. It creates an animation using the cairo library while displaying an image:
#include <cairo.h>
#include <gtk/gtk.h>
/* compile with
*
* gcc spectrum.c -o spectrum `pkg-config --cflags --libs gtk+-3.0`
*
* */
static void do_drawing(cairo_t *);
struct {
gboolean timer;
cairo_surface_t *image;
cairo_surface_t *surface;
gint img_width;
gint img_height;
} glob;
static void init_vars()
{
glob.image = cairo_image_surface_create_from_png("beckov.png");
glob.img_width = cairo_image_surface_get_width(glob.image);
glob.img_height = cairo_image_surface_get_height(glob.image);
glob.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
glob.img_width, glob.img_height);
glob.timer = TRUE;
}
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
gpointer user_data)
{
do_drawing(cr);
return FALSE;
}
static void do_drawing(cairo_t *cr)
{
cairo_t *ic;
static gint count = 0;
ic = cairo_create(glob.surface);
gint i, j;
for (i = 0; i <= glob.img_height; i+=7) {
for (j = 0 ; j < count; j++) {
cairo_move_to(ic, 0, i+j);
cairo_line_to(ic, glob.img_width, i+j);
}
}
count++;
if (count == 8) glob.timer = FALSE;
cairo_set_source_surface(cr, glob.image, 10, 10);
cairo_mask_surface(cr, glob.surface, 10, 10);
cairo_stroke(ic);
cairo_destroy(ic);
}
static gboolean time_handler(GtkWidget *widget)
{
if (!glob.timer) return FALSE;
gtk_widget_queue_draw(widget);
return TRUE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;
init_vars();
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER (window), darea);
g_signal_connect(G_OBJECT(darea), "draw",
G_CALLBACK(on_draw_event), NULL);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 325, 250);
gtk_window_set_title(GTK_WINDOW(window), "Spectrum");
g_timeout_add(400, (GSourceFunc) time_handler, (gpointer) window);
gtk_widget_show_all(window);
gtk_main();
cairo_surface_destroy(glob.image);
cairo_surface_destroy(glob.surface);
return 0;
}
I achieve exatly the same result if I remove the do_drawing() function and move its code to the on_draw_event(), like:
#include <cairo.h>
#include <gtk/gtk.h>
/* compile with
*
* gcc spectrum.c -o spectrum `pkg-config --cflags --libs gtk+-3.0`
*
* */
struct {
gboolean timer;
cairo_surface_t *image;
cairo_surface_t *surface;
gint img_width;
gint img_height;
} glob;
static void init_vars()
{
glob.image = cairo_image_surface_create_from_png("beckov.png");
glob.img_width = cairo_image_surface_get_width(glob.image);
glob.img_height = cairo_image_surface_get_height(glob.image);
glob.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
glob.img_width, glob.img_height);
glob.timer = TRUE;
}
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
gpointer user_data)
{
cairo_t *ic;
static gint count = 0;
ic = cairo_create(glob.surface);
gint i, j;
for (i = 0; i <= glob.img_height; i+=7) {
for (j = 0 ; j < count; j++) {
cairo_move_to(ic, 0, i+j);
cairo_line_to(ic, glob.img_width, i+j);
}
}
count++;
if (count == 8) glob.timer = FALSE;
cairo_set_source_surface(cr, glob.image, 10, 10);
cairo_mask_surface(cr, glob.surface, 10, 10);
cairo_stroke(ic);
cairo_destroy(ic);
return FALSE;
}
static gboolean time_handler(GtkWidget *widget)
{
if (!glob.timer) return FALSE;
gtk_widget_queue_draw(widget);
return TRUE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;
init_vars();
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER (window), darea);
g_signal_connect(G_OBJECT(darea), "draw",
G_CALLBACK(on_draw_event), NULL);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 325, 250);
gtk_window_set_title(GTK_WINDOW(window), "Spectrum");
g_timeout_add(400, (GSourceFunc) time_handler, (gpointer) window);
gtk_widget_show_all(window);
gtk_main();
cairo_surface_destroy(glob.image);
cairo_surface_destroy(glob.surface);
return 0;
}
So... I wonder... Am I missing something here (loss of generality)?
Or was the call to do_drawing() in function on_draw_event() of the original code redundant?
Thanks
Yes. It's correct on compiler's side.
But it's a good practice for functions to solve exactly one task. do_drawing is busy with drawing lines and pixels, on_draw_event is busy with processing events. Probably in this code snippet there is no real reason to make a separate function, but usually on_draw_event would be much more complicated.

Create a Rounded image in gtk

How can I make an image round?
I tried setting border-radius to gtk image. But it does not work. Here is my code.
GdkPixbuf *pixbuf;
pixbuf=gdk_pixbuf_new_from_file_at_size ("sample.jpg", 48, 48, NULL);
GtkWidget *image = GTK_WIDGET(gtk_builder_get_object(builder,"image"));;
gtk_image_set_from_pixbuf(GTK_IMAGE(image),pixbuf);
g_object_unref (pixbuf);
I want to round the image widget. Is there any option in glade to round the image? I don't find any.
Thanks.
As pointed out by #iharob in comments, you need a cairo surface .
Change the radius (in this example 40) to the desired size:
#include <cairo.h>
#include <gtk/gtk.h>
#include <math.h>
#include <stdlib.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
static void do_drawing(cairo_t *, GtkWidget *);
struct {
cairo_surface_t *image;
} glob;
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
gpointer user_data)
{
do_drawing(cr, widget);
return FALSE;
}
static void do_drawing(cairo_t *cr, GtkWidget *widget)
{
GtkWidget *win = gtk_widget_get_toplevel(widget);
gint width, height;
gtk_window_get_size(GTK_WINDOW(win), &width, &height);
cairo_set_source_surface(cr, glob.image, 1, 1);
cairo_arc(cr, /*x*/ 128, /* y */ 128, /* radius */ 40, 0, 2*M_PI);
cairo_clip(cr);
cairo_paint(cr);
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;
gint width, height;
glob.image = cairo_image_surface_create_from_png("image.png");
width = cairo_image_surface_get_width(glob.image);
height = cairo_image_surface_get_height(glob.image);
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER (window), darea);
g_signal_connect(G_OBJECT(darea), "draw",
G_CALLBACK(on_draw_event), NULL);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), width+2, height+2);
gtk_window_set_title(GTK_WINDOW(window), "Round image");
gtk_widget_show_all(window);
gtk_main();
cairo_surface_destroy(glob.image);
return 0;
}
// compila con valac --pkg cairo nombre_archivo.gs
uses Cairo
init
// crea una superficie (una imagen de 256x256) y un contexto
surface: Cairo.ImageSurface = new Cairo.ImageSurface (Cairo.Format.ARGB32, 256, 256)
context: Cairo.Context = new Cairo.Context (surface)
// arco
context.arc (128.0, 128.0, 76.8, 0, 2*Math.PI)
context.clip () // recorta el arco
context.new_path () // después de clip, la ruta se borró
// imagen de origen (ruta y formato)
image_path:string = GLib.Path.build_filename (GLib.Path.get_dirname (args[0]) , "paisaje.png")
image: Cairo.ImageSurface = new Cairo.ImageSurface.from_png (image_path)
// escala
w:int = image.get_width ()
h:int= image.get_height ()
context.scale (256.0/w, 256.0/h)
context.set_source_surface (image, 0, 0)
context.paint ()
// guarda la nueva imagen
surface.write_to_png ("paisaje_arco.png")
More examples of Genie + Gtk + Cairo in http://genie.webierta.skn1.com

C LIBCHAMPLAIN SegFault?

I had a programm with C and libchamplain which showed a map. worked fine. Now i wanted to integrate it into an gtk application. But at running, i get a segfault:
#include <stdio.h>
#include <gtk/gtk.h>
#include <champlain/champlain.h>
#include <champlain-gtk/champlain-gtk.h>
#include <clutter-gtk/clutter-gtk.h>
#include <math.h>
#include "GPS_stub.h"
#define MARKER_SIZE 10
#define MAX_SIZ 4096
static gboolean draw_center(ClutterCanvas *canvas, cairo_t *cr, int width, int height){
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_arc(cr, MARKER_SIZE / 2.0, MARKER_SIZE / 2.0, MARKER_SIZE / 2.0, 0, 2 * M_PI);
cairo_close_path(cr);
cairo_set_source_rgba(cr, 0.1, 0.1, 0.9, 1.0);
cairo_fill(cr);
return TRUE;
}
static ClutterActor *create_marker(void){
ClutterActor *marker;
ClutterActor *bg;
ClutterContent *canvas;
ClutterTransition *transition;
marker = champlain_custom_marker_new();
canvas = clutter_canvas_new();
clutter_canvas_set_size(CLUTTER_CANVAS(canvas), MARKER_SIZE, MARKER_SIZE);
g_signal_connect(canvas, "draw", G_CALLBACK(draw_center), NULL);
bg = clutter_actor_new();
clutter_actor_set_size(bg, MARKER_SIZE, MARKER_SIZE);
clutter_actor_set_content(bg, canvas);
clutter_content_invalidate(canvas);
g_object_unref(canvas);
clutter_actor_add_child(marker, bg);
clutter_actor_set_pivot_point(bg, 0.5, 0.5);
clutter_actor_set_position(bg, -MARKER_SIZE, -MARKER_SIZE);
transition = clutter_property_transition_new("opacity");
clutter_actor_set_easing_mode(bg, CLUTTER_EASE_OUT_SINE);
clutter_timeline_set_duration(CLUTTER_TIMELINE(transition), 1000);
clutter_timeline_set_repeat_count(CLUTTER_TIMELINE(transition), -1);
clutter_transition_set_from(transition, G_TYPE_UINT, 255);
clutter_transition_set_to(transition, G_TYPE_UINT, 0);
clutter_actor_add_transition(bg, "animate-opacity", transition);
transition = clutter_property_transition_new("scale-x");
clutter_actor_set_easing_mode(bg, CLUTTER_EASE_OUT_SINE);
clutter_timeline_set_duration(CLUTTER_TIMELINE(transition), 1000);
clutter_timeline_set_repeat_count(CLUTTER_TIMELINE(transition), -1);
clutter_transition_set_from(transition, G_TYPE_FLOAT, 0.5);
clutter_transition_set_to(transition, G_TYPE_FLOAT, 1.0);
clutter_actor_add_transition(bg, "animate-scale-x", transition);
transition = clutter_property_transition_new("scale-y");
clutter_actor_set_easing_mode(bg, CLUTTER_EASE_OUT_SINE);
clutter_timeline_set_duration(CLUTTER_TIMELINE(transition), 1000);
clutter_timeline_set_repeat_count(CLUTTER_TIMELINE(transition), -1);
clutter_transition_set_from(transition, G_TYPE_FLOAT, 0.5);
clutter_transition_set_to(transition, G_TYPE_FLOAT, 1.0);
clutter_actor_add_transition(bg, "animate-scale-y", transition);
return marker;
}
static gboolean gps_callback(ChamplainMarker *marker[MAX_SIZ]){
return TRUE;
}
typedef struct{
double lat;
double lng;
} GpsCallbackData;
static void load_map(GpsCallbackData *data){
ClutterActor *actor, *stage;
ChamplainMarkerLayer *layer;
ClutterActor *marker[MAX_SIZ];
stage = clutter_stage_new();
clutter_actor_set_size(stage, 800, 600);
g_signal_connect(stage, "destroy", G_CALLBACK(clutter_main_quit), NULL);
actor = champlain_view_new();
clutter_actor_set_size(CLUTTER_ACTOR(actor), 800, 600);
clutter_actor_add_child(stage, actor);
layer = champlain_marker_layer_new_full(CHAMPLAIN_SELECTION_SINGLE);
clutter_actor_show(CLUTTER_ACTOR(layer));
champlain_view_add_layer(CHAMPLAIN_VIEW(actor), CHAMPLAIN_LAYER(layer));
for(int i = 0; i < MAX_SIZ/40; i++){
marker[i] = create_marker();
champlain_marker_layer_add_marker(layer, CHAMPLAIN_MARKER(marker[i]));
champlain_location_set_location(CHAMPLAIN_LOCATION(marker[i]), data->lat+i/10, data->lng+i/10);
}
g_object_set(G_OBJECT(actor), "zoom-level", 2, "kinetic-mode", TRUE, NULL);
champlain_view_center_on(CHAMPLAIN_VIEW(actor), 40, 0);
g_timeout_add(1000, (GSourceFunc) gps_callback, CHAMPLAIN_MARKER(marker));
clutter_actor_show(stage);
clutter_main();
}
int main(int argc, char *argv[]){
GtkWidget *window, *button;
GpsCallbackData *gps;
double lat, lng;
gtk_clutter_init(&argc, &argv);
hs_init(&argc, &argv);
getGPS("166.82.21.200", &lat, &lng);
printf("GPS: %f %f\n", lat, lng);
gps->lat = lat;
gps->lng = lng;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
button = gtk_button_new_with_label("Load Map");
g_signal_connect(button, "clicked", G_CALLBACK(load_map), &gps);
gtk_container_add(GTK_CONTAINER(window), button);
gtk_widget_show(window);
gtk_main();
hs_exit();
return 0;
}
like you can see in main , it prints out coordinates. This works fine. But then after the printing i'm getting an segfault.
Why?
I have a same problem on ARM Linux from here.
stage = clutter_stage_new();
clutter_actor_set_size(stage, 800, 600);
When I removed or blocked "clutter_actor_set", there's no seg fault error.
actor is O.K, but stage is matter.
But on X86 Ubuntu desktop, it's O.K.

GTK2+ Automatically adjusting the font size of a button's label

I'm making a Tic-Tac-Toe game as a school project. I set up 9 buttons in rows of 3, so whenever the user clicks on one of them its label changes to X or O in plain text.
I was wondering if it's possible for the size of the X/O to change depending on the size of the window. Another idea I had was to use an image of an X/O instead of plain text (at least because I assume that if I use a large image it'll automatically scale down); I don't really want to do that though since the function that checks when a player has won the game compares the labels' text.
This is the code responsible for creating and adding the button:
GtkWidget *button;
button = gtk_button_new_with_label("");
gtk_box_pack_start(GTK_BOX(theBox),button,FALSE,TRUE,0);
g_signal_connect(GTK_OBJECT(button),"clicked",GTK_SIGNAL_FUNC(ButtonClicked),EntryBox);
gtk_widget_show(button);
And this is my ButtonClicked function:
void ButtonClicked(GtkButton *button, gpointer data)
{
if (strcmp(gtk_button_get_label(button), "") == 0)
if (count % 2 != 0)
gtk_button_set_label(button, "X");
}
Also, while I'm here, I have another question: I set the window border to 0 but you can still see a very small amount of border, is there any way to get rid of that?
You can try this, I used the "expose-event" to draw the X and O and an empty cell in case the user hasn't clicked it yet and also imlpemented a simple function to check for the winner. The cell value is set by passing data to the event handlers.
The "button-release-event" allows you to do something when a cell is clicked, and then you can change the next turn to the other player and set X or O to the clicked cell depending on which player had the turn when it was clicke.
Check this
#include <gtk/gtk.h>
#include <stdlib.h>
#include <math.h>
enum Player
{
FirstPlayer,
SecondPlayer
};
enum TicTacValue
{
None,
Empty,
Unset,
X,
O
};
struct GameData
{
enum TicTacValue value;
enum Player *player;
struct GameData *data;
gint row;
gint column;
};
enum TicTacValue
evaluate(enum TicTacValue previous, enum TicTacValue next)
{
if (previous == Unset)
return next;
if (previous != next)
return None;
return next;
}
void
check_winner(struct GameData *data)
{
enum TicTacValue rows[3] = {Unset, Unset, Unset};
enum TicTacValue diagonals[2] = {Unset, Unset};
enum TicTacValue columns[3] = {Unset, Unset, Unset};
enum TicTacValue winner;
for (size_t i = 0 ; i < 9 ; ++i)
{
columns[i % 3] = evaluate(columns[i % 3], data[i].value);
rows[i / 3] = evaluate(rows[i / 3], data[i].value);
switch (i)
{
case 4:
diagonals[0] = evaluate(diagonals[0], data[i].value);
diagonals[1] = evaluate(diagonals[1], data[i].value);
break;
case 0:
case 8:
diagonals[0] = evaluate(diagonals[0], data[i].value);
break;
case 2:
case 6:
diagonals[1] = evaluate(diagonals[1], data[i].value);
break;
}
}
winner = diagonals[0] | diagonals[1];
winner = winner | columns[0] | columns[1] | columns[2];
winner = winner | rows[0] | rows[1] | rows[2];
if (winner < Unset)
return;
fprintf(stderr, "Player %d WINS (-)\n", winner - Unset);
}
gboolean
on_click(GtkWidget *widget, GdkEventButton *event, gpointer data)
{
struct GameData *game_data;
game_data = (struct GameData *) data;
if (game_data->value != Empty)
return FALSE;
if (*(game_data->player) == FirstPlayer)
{
game_data->value = X;
*(game_data->player) = SecondPlayer;
}
else
{
game_data->value = O;
*(game_data->player) = FirstPlayer;
}
gtk_widget_queue_draw(widget);
check_winner(game_data->data);
return FALSE;
}
void
draw_delmiter_line(cairo_t *cairo, gint x1, gint y1, gint x2, gint y2)
{
cairo_save(cairo);
cairo_set_source_rgb(cairo, 0.65, 0.65, 0.65);
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_NONE);
cairo_set_line_width(cairo, 1);
cairo_move_to(cairo, x1, y1);
cairo_line_to(cairo, x2, y2);
cairo_stroke(cairo);
cairo_restore(cairo);
}
void
draw_x(cairo_t *cairo, gint width, gint height)
{
gint size;
size = width / 3.5;
cairo_save(cairo);
cairo_set_source_rgb(cairo, 0.25, 0.4, 1.0);
cairo_set_line_width(cairo, 2.5);
cairo_translate(cairo, width / 2, height / 2);
cairo_move_to(cairo, -size, -size);
cairo_line_to(cairo, +size, +size);
cairo_move_to(cairo, +size, -size);
cairo_line_to(cairo, -size, +size);
cairo_stroke(cairo);
cairo_restore(cairo);
}
void
draw_o(cairo_t *cairo, gint width, gint height)
{
cairo_save(cairo);
cairo_set_source_rgb(cairo, 1.0, 0.25, 0.25);
cairo_set_line_width(cairo, 2.5);
cairo_arc(cairo, width / 2, height / 2, width / 3, 0, 2.0 * M_PI);
cairo_stroke(cairo);
cairo_restore(cairo);
}
gboolean
on_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
GdkWindow *window;
cairo_t *cairo;
const struct GameData *game_data;
gint width;
gint height;
window = gtk_widget_get_window(widget);
cairo = gdk_cairo_create(window);
game_data = (const struct GameData *) data;
gdk_window_get_size(window, &width, &height);
if (game_data->row != 2)
draw_delmiter_line(cairo, 0, height, width, height);
if (game_data->column != 3)
draw_delmiter_line(cairo, width, 0, width, height);
if (game_data->value == X)
draw_x(cairo, width, height);
else if (game_data->value == O)
draw_o(cairo, width, height);
cairo_destroy(cairo);
return FALSE;
}
int
main(int argc, char **argv)
{
GtkWidget *window;
GtkWidget *horizontal[3];
GtkWidget *vertical;
struct GameData data[9];
enum Player current_player;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
vertical = gtk_vbox_new(TRUE, 0);
for (size_t i = 0 ; i < 3 ; ++i)
{
horizontal[i] = gtk_hbox_new(TRUE, 0);
gtk_box_pack_start(GTK_BOX(vertical), horizontal[i], TRUE, TRUE, 0);
}
current_player = FirstPlayer;
for (size_t i = 0 ; i < 9 ; ++i)
{
GtkWidget *cell;
cell = gtk_drawing_area_new();
data[i].value = Empty;
data[i].player = &current_player;
data[i].data = data;
data[i].row = i / 3;
data[i].column = i % 3;
g_signal_connect(G_OBJECT(cell), "expose-event", G_CALLBACK(on_expose), &data[i]);
g_signal_connect(G_OBJECT(cell), "button-release-event", G_CALLBACK(on_click), &data[i]);
gtk_widget_add_events(cell, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK);
gtk_box_pack_start(GTK_BOX(horizontal[data[i].row]), cell, TRUE, TRUE, 0);
}
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_container_add(GTK_CONTAINER(window), vertical);
gtk_widget_set_size_request(window, 300, 300);
gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
gtk_widget_show_all(window);
gtk_main();
return 0;
}

Resources