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 = ¤t_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; }