Jump to content

Gtk + timer + sockets + cairo


Dr_Lion
 Share

Recommended Posts

Consegui um código mais perto do que estava á procura utilizando um timer, para de segundo a segundo desenhar numa janela em gtk uma figura geométrica, e até aqui tudo bem. A figura é uma circunferência de radio "radius", este valor é suposto ser enviado numa mensagem, e para isso uso sockets. Até aqui tudo bem, no entanto, não sei onde colocar o socket a ler e tratar essa informação.

Pensei colocar o código para tratar a informação na funcão main, mas o programa fica pendurado na janela e apenas quando fechasse a janela é que executa o restante código.

E eu precisava que este estivesse constantemente a ler o socket e de x em x tempo, ou cada vez que chegue um valor novo, também é uma opção, ser desenhada a figura na janela.

Já sei que no main estou a colocar mal o código, alguma ideia onde devo colocar? Porque parece-me que entre cada segundo em que é feito o desenho o programa fica pendurado no timer.

Ou também me surgiu outra ideia que seria criar duas threads, e numa punha o socket a receber dados, e no outro, a janela do gtk a desenhar.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <cairo.h>
#include <gtk/gtk.h>
#include <time.h>


#define M_PI 3.1415
#define MYPORT "4950"    // the port users will be connecting to
#define MAX_EST 70 
#define MAXBUFLEN 100

double radius1 = 100.0;

static char buffer[256];

static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
double xc1 = 300.0;
double yc1 = 225.0;


double angle1 = 0.0  * (M_PI/180.0);  /* angles are specified */
double angle2 = 360.0 * (M_PI/180.0);  /* in radians           */

cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 500, 500);
//cairo_t *cr = cairo_create (surface);

cairo_t *cr;
cr = gdk_cairo_create(widget->window);

//circ 1 
cairo_set_line_width (cr, 10.0);
cairo_arc (cr, xc1, yc1, radius1, angle1, angle2);
cairo_stroke (cr);

cairo_destroy(cr);

  return FALSE;
}


static gboolean time_handler(GtkWidget *widget)
{
  if (widget->window == NULL) return FALSE;

  time_t curtime;
  struct tm *loctime;

  curtime = time(NULL);
  loctime = localtime(&curtime);
  strftime(buffer, 256, "%T", loctime);
  
//printf("\n %f", radius1);
  gtk_widget_queue_draw(widget);
  return TRUE;
}

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main (int argc, char *argv[])
{

int sockfd;
    struct addrinfo hints, *servinfo, *p;
    int rv;
    int numbytes;
    struct sockaddr_storage their_addr;
    char buf[MAXBUFLEN];
    socklen_t addr_len;
    char s[iNET6_ADDRSTRLEN];
    
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_flags = AI_PASSIVE; // use my IP

    if ((rv = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }

    // loop through all the results and bind to the first we can
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->ai_protocol)) == -1) {
            perror("listener: socket");
            continue;
        }

        if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
            close(sockfd);
            perror("listener: bind");
            continue;
        }

        break;
    }
    
    if (p == NULL) {
        fprintf(stderr, "listener: failed to bind socket\n");
        return 2;
    }

    freeaddrinfo(servinfo);

  GtkWidget *window;
  GtkWidget *darea;

  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(darea, "expose-event",
      G_CALLBACK(on_expose_event), NULL);
  g_signal_connect(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), 600, 600);

  gtk_window_set_title(GTK_WINDOW(window), "timer");
  g_timeout_add(1000, (GSourceFunc) time_handler, (gpointer) window);
  gtk_widget_show_all(window);
  time_handler(window);

  gtk_main();
  
  //codigo socket
  
   printf("listener: waiting to recvfrom...\n");

while (1) {	
	printf("dentro do while\n");
	addr_len = sizeof their_addr;
	if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0, (struct sockaddr *) &their_addr, &addr_len)) == -1) {
		perror("recvfrom");
		exit(1);
	}


	printf("listener: got packet from %s\n", inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *) &their_addr), s, sizeof s));

	printf("listener: packet is %d bytes long\n", numbytes);
	buf[numbytes] = '\0';
	printf("RECEBIDO: \"%s\"\n", buf);

	radius1 = atoi(buf);

	printf("\n %f", radius1);

}
  
  //fim do codigo socket

  return 0;
}
Link to comment
Share on other sites

Duas perguntas:

1) se enquanto estas a desenhar o circulo recebes outro radius, o que queres que aconteca ao desenho incompleto?

2) no fim de desenhar o circulo, o que vais fazer?

Sugestao: usa "blocking input", isto e, input que bloqueia e nao faz nada enquanto espera pela valor do radius.

What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Link to comment
Share on other sites

1- A minha ideia é serem duas tarefas separadas em que estou constantemente a receber valores do radius, e de segundo a segundo é feito o desenho com o valor presente nessa altura. Se receber mais valores a meio do desenho só teria efeito na próxima iteração de desenho.

2- No fim de desenhar o circulo a ideia é continuar a receber o valor proveniente do socket.

Link to comment
Share on other sites

Para realizares duas tarefas separadas ao mesmo tempo tens que utilizar as Threads.

Uma Thread é uma função que corre ao mesmo tempo que o programa principal. São utilizadas quando essas funções são loops de eventos (no teu caso o gtk_main()) ou são processos muito demorados (descompressão ou desencriptação).

Já que que vais utilizar o gtk, sugiro que utilizes a Thread do glib. http://developer.gnome.org/glib/2.30/glib-Threads.html

Boa sorte, porque estas cenas são um bocado dificeis de perceber à primeira. 😁

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.