GTK+ Forums

Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
It is currently Sat Jul 26, 2014 1:09 pm

All times are UTC




Post new topic Reply to topic  [ 9 posts ] 
Author Message
 Post subject: Is it possible to declare a Pixbuf array in C?
PostPosted: Tue Apr 24, 2012 3:48 am 
Offline
Familiar Face

Joined: Sun Apr 22, 2012 6:40 am
Posts: 8
Now that I made the initial step I'm trying to get into stage two, having a frame buffer made of pixbufs. But I am getting into a snag.

Declaring a Gdkpixbuf** and trying to malloc it gives me an indefinite type (or something along those lines) gives me an error.

Trying to be more definite and declaring GdxPixbuf *buffer[FRAME_BUFFER_SIZE] gives me these errors.

graphics.c:15: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘*’ token
and the compiler thinks the buffer variable hasn't been instantiated.

So is it possible to have an array of Pixbufs in C?

Thanks

Jason

ps...just in case I have been hit by the stupid virus here is my entire code if the error is elsewhere.

Code:
#include <stdlib.h>
#include <gtk/gtk.h>
#include <math.h>

#include "pixbuf.c"

#define FRAME_DELAY 50
#define FRAME_BUFFER_SIZE 200

/* demo window */
static GtkWidget *window = NULL;

/* Current frame */
static GdkPixbuf *frame;
GdxPixbuf *buffer[FRAME_BUFFER_SIZE];

guchar *row;


/* Widgets */
static GtkWidget *da;

/* Expose callback for the drawing area */
static gint
expose_cb (GtkWidget      *widget,
           GdkEventExpose *event,
           gpointer        data)
{   
   
  guchar *pixels;
  int rowstride;

  rowstride = gdk_pixbuf_get_rowstride (frame);

  pixels = gdk_pixbuf_get_pixels (frame) + rowstride * event->area.y + event->area.x * 3;

  gdk_draw_rgb_image_dithalign (widget->window,
                                widget->style->black_gc,
                                event->area.x, event->area.y,
                                event->area.width, event->area.height,
                                GDK_RGB_DITHER_NORMAL,
                                pixels, rowstride,
                                event->area.x, event->area.y);
                               
  return TRUE;
}

#define CYCLE_LEN 60

static int frame_num;

/* Timeout handler to regenerate the frame */
static gint
timeout (gpointer data)
{
   
   int i, j;   
   if (row == NULL)
      row = malloc(X_RES * sizeof(guchar));
      
   for (i = 0; i < Y_RES; i++) {   
      for (j = 0; j < X_RES; j++) {
            row[j] = rand() % 256;
      }
      put_pixels(frame, i, row);   
   }
   

  gtk_widget_queue_draw (da);

  return TRUE;
}

static guint timeout_id;

static void
cleanup_callback (GtkObject *object,
                  gpointer   data)
{
  g_source_remove (timeout_id);
  timeout_id = 0;
}

int
main(int argc, char *argv[])
{
    int i;
    gtk_init(&argc, &argv);


   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   gtk_window_set_screen (GTK_WINDOW (window),
              gtk_widget_get_screen (window));
   gtk_window_set_title (GTK_WINDOW (window), "Pixbufs");
   gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
   
   g_signal_connect (window, "destroy",
         G_CALLBACK (gtk_widget_destroyed), &window);
   g_signal_connect (window, "destroy",
         G_CALLBACK (cleanup_callback), NULL);
   
   for (i = 0; i < FRAME_BUFFER_SIZE; i++) {
      buffer[i] = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
         FALSE, 8, X_RES, Y_RES);   
   }


  gtk_widget_set_size_request (window, X_RES, Y_RES);

  frame = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, X_RES, Y_RES);

  da = gtk_drawing_area_new ();

  g_signal_connect (da, "expose-event",
          G_CALLBACK (expose_cb), NULL);

  gtk_container_add (GTK_CONTAINER (window), da);

  timeout_id = g_timeout_add (FRAME_DELAY, timeout, NULL);


  if (!gtk_widget_get_visible (window))
    {
      gtk_widget_show_all (window);
    }
  else
    {
      gtk_widget_destroy (window);
      window = NULL;
      g_object_unref (frame);
    }
    gtk_main();

    return 0;
}


Top
 Profile  
 
 Post subject: Re: Is it possible to declare a Pixbuf array in C?
PostPosted: Tue Apr 24, 2012 5:56 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 733
Location: UK
Hi,

Good to see that you are making headway. I know this may seam simple, but you do have a simple typo.
You typed
Code:
GdxPixbuf *buffer[FRAME_BUFFER_SIZE]

when it should be
Code:
GdkPixbuf *buffer[FRAME_BUFFER_SIZE]


Note Gdk and not Gdx.

_________________
E.


Top
 Profile  
 
 Post subject: Re: Is it possible to declare a Pixbuf array in C?
PostPosted: Tue Apr 24, 2012 5:10 pm 
Offline
Familiar Face

Joined: Sun Apr 22, 2012 6:40 am
Posts: 8
Ah...it was the stupid virus....


Top
 Profile  
 
 Post subject: Re: Is it possible to declare a Pixbuf array in C?
PostPosted: Tue Apr 24, 2012 5:19 pm 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 733
Location: UK
:) The fingers in the wrong keys type.

_________________
E.


Top
 Profile  
 
 Post subject: Re: Is it possible to declare a Pixbuf array in C?
PostPosted: Wed Apr 25, 2012 5:58 am 
Offline
Familiar Face

Joined: Sun Apr 22, 2012 6:40 am
Posts: 8
It WORKS!!!! Thank you so very much for your help Errol! It should be a small thing from here to put in the MPI calls and have an actual simulation!!!!

btw...when you have time...could you tell me the ubuntu/debian packages for gtk 3 production and translate this to gtk 3 (namely cairo)...no rush.

Perhaps some good resources would be great too.

Only made some small changes to pixbuf.c. Instead of static, it now puts a scanning dot across the window.

EDIT: The only problem now is it doesn't release the terminal when I close the window. No biggie.


Code:
#include <stdlib.h>
#include <gtk/gtk.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
#include <pthread.h>

#include "pixbuf.c"

#define CYCLE_LEN 60
#define FRAME_DELAY 35
#define FRAME_BUFFER_SIZE 200

/* demo window */
static GtkWidget *window = NULL;

/* Current frames */
static GdkPixbuf *frame;

int current_master_frame = 0;
int current_thread_frame = 0;

//frame_buffer and row buffer
GdkPixbuf *buffer[FRAME_BUFFER_SIZE];
guchar *row;

/* Widgets */
static GtkWidget *da;

//other
static guint timeout_id;
static int frame_num;

//functions
void *gtk_function(void *arg);
static gint expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data);
static gint timeout (gpointer data);
static void cleanup_callback (GtkObject *object, gpointer data);

int main(int argc, char *argv[])
{
   int res, i, j, n, total, current_frame;
   pthread_t a_thread;
   
   //this might be troublesome
   gtk_init(&argc, &argv);
   
   //init pixbufs
   for (i = 0; i < FRAME_BUFFER_SIZE; i++) {
      buffer[i] = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
         FALSE, 8, X_RES, Y_RES);   
   }
   

   res = pthread_create(&a_thread, NULL, gtk_function, NULL);
   if (res != 0) {
      perror("Thread Creation failed");
      exit(EXIT_FAILURE);
   }
   sleep(1);
   
   total = X_RES*Y_RES;
   if (row == NULL)
      row = malloc(X_RES * sizeof(guchar));
   
   for(n = 0; n<total; n++) {
      if (current_master_frame - current_thread_frame < FRAME_BUFFER_SIZE) {
         current_frame = current_master_frame % FRAME_BUFFER_SIZE;

         for (i = 0; i < Y_RES; i++) {   
            for (j = 0; j < X_RES; j++) {
               if (i == current_master_frame / Y_RES) {
                  if (j == current_master_frame % X_RES)
                     row[j] = 255;
                  else row[j] = 0;
               }
               else row[j] = 0;
            }
            put_pixels(buffer[current_frame], i, row);   
         }
         current_master_frame++;
         
         printf("Current Master Frame: %d, Thread Frame: %d Diff: %d\n",
            current_master_frame, current_thread_frame,
            current_master_frame - current_thread_frame);
      }
      else {
         printf("Other thread stalled\n");
         printf("Current Master Frame: %d, Thread Frame: %d Diff: %d\n",
            current_master_frame, current_thread_frame,
            current_master_frame - current_thread_frame);
         sleep(1);
      }
         
   }

   exit(EXIT_SUCCESS);   
   
}

void *gtk_function(void *arg) {
    int i;
   
//    gtk_init((int*) arg, NULL);
   
   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   gtk_window_set_screen (GTK_WINDOW (window),
              gtk_widget_get_screen (window));
   gtk_window_set_title (GTK_WINDOW (window), "Pixbufs");
   gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
   
   g_signal_connect (window, "destroy",
         G_CALLBACK (gtk_widget_destroyed), &window);
   g_signal_connect (window, "destroy",
         G_CALLBACK (cleanup_callback), NULL);
   


  gtk_widget_set_size_request (window, X_RES, Y_RES);

  frame = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, X_RES, Y_RES);

  da = gtk_drawing_area_new ();

  g_signal_connect (da, "expose-event",
          G_CALLBACK (expose_cb), NULL);

  gtk_container_add (GTK_CONTAINER (window), da);

  timeout_id = g_timeout_add (FRAME_DELAY, timeout, NULL);


  if (!gtk_widget_get_visible (window))
    {
      gtk_widget_show_all (window);
    }
  else
    {
      gtk_widget_destroy (window);
      window = NULL;
      g_object_unref (frame);
    }
    gtk_main();

    pthread_exit("GTK done.");   
}

/* Expose callback for the drawing area */
static gint
expose_cb (GtkWidget      *widget,
           GdkEventExpose *event,
           gpointer        data)
{   
   
  guchar *pixels;
  int rowstride;

  rowstride = gdk_pixbuf_get_rowstride (frame);

  pixels = gdk_pixbuf_get_pixels (frame) + rowstride * event->area.y + event->area.x * 3;

  gdk_draw_rgb_image_dithalign (widget->window,
                                widget->style->black_gc,
                                event->area.x, event->area.y,
                                event->area.width, event->area.height,
                                GDK_RGB_DITHER_NORMAL,
                                pixels, rowstride,
                                event->area.x, event->area.y);
                               
  return TRUE;
}



/* Timeout handler to regenerate the frame */
static gint
timeout (gpointer data)
{
  int catch_up = current_master_frame - current_thread_frame;
  if(catch_up > 0) {   
     int current_frame = current_thread_frame % FRAME_BUFFER_SIZE;
     gdk_pixbuf_copy_area(buffer[current_frame], 0, 0, X_RES, Y_RES,
        frame, 0, 0);

     gtk_widget_queue_draw (da);
     current_thread_frame++;
  }
  return TRUE;
}



static void
cleanup_callback (GtkObject *object,
                  gpointer   data)
{
  g_source_remove (timeout_id);
  timeout_id = 0;
}


Top
 Profile  
 
 Post subject: Re: Is it possible to declare a Pixbuf array in C?
PostPosted: Thu Apr 26, 2012 6:52 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 733
Location: UK
Just having a quick scan of your code I can see that you have made many mistakes. The major one is with thread safety. You are accessing variables without locking them, this can cause data corruption. Also you are calling the GTK/GDK API from both your threads, but it is not thread safe to do so and will corrupt the internal data structures.

Once I have the time I will come up with some sort of solution for you.

_________________
E.


Top
 Profile  
 
 Post subject: Re: Is it possible to declare a Pixbuf array in C?
PostPosted: Wed May 02, 2012 7:20 am 
Offline
Familiar Face

Joined: Sun Apr 22, 2012 6:40 am
Posts: 8
It works...and yes I don't have locks (well, the master and thread frame counts serve as a rough one.) I would think the end result is that the gdk based arrays (namedly the GDKbuffer) are not written to at the same time if the two counters are within one of each other.


Top
 Profile  
 
 Post subject: Re: Is it possible to declare a Pixbuf array in C?
PostPosted: Wed May 02, 2012 7:06 pm 
Offline
Familiar Face

Joined: Sun Apr 22, 2012 6:40 am
Posts: 8
I mean, I suppose I could put mutexes in the incremented variables, at least for writes. I don't see another solution as far as the pixbuf array is concerned. The loop which GTK works probably would have difficulty working with outside interaction.

I ultimately had to make the graphics code a socket server since it would get a "cannot complete display error" when trying to project it through a ssh -X so I had to have the MPI based simulation send character streams over the socket for this code to process. Would that work in the timeout loop, does EVERYTHING GTK based have to be in the GTK thread? I figured that would lead to problems so I isolated the most data intensive parts outside the loop and used the ints to synchronized.

Here is the graphics code, the MPI code is over 1000 lines long, it just sends characters anyway. The pixbuf.c code is largely the same, a modification of the put_pixel example method in the api.

Code:
#include <stdlib.h>
#include <gtk/gtk.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <pthread.h>

#include "pixbuf.c"

#define CYCLE_LEN 35
#define FRAME_DELAY 5
#define FRAME_BUFFER_SIZE 200
#define NUM_GENS 200
#define PORT 3131

/* demo window */
static GtkWidget *window = NULL;

/* Current frames */
static GdkPixbuf *frame;

int current_master_frame = 0;
int current_thread_frame = 0;

//frame_buffer and row buffer
GdkPixbuf *buffer[FRAME_BUFFER_SIZE];
guchar *row;

/* Widgets */
static GtkWidget *da;

//other
static guint timeout_id;
static int frame_num;

//functions
void *gtk_function(void *arg);
static gint expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data);
static gint timeout (gpointer data);
static void cleanup_callback (GtkObject *object, gpointer data);

int main(int argc, char *argv[])
{
   int res, i, j, n, total, current_frame, bytes_read, status;
   pthread_t a_thread;
   
   int server_socket, client_socket;
   struct sockaddr_in server_addr;
   struct sockaddr_in client_addr;
   //this might be troublesome
   gtk_init(&argc, &argv);
   
   
   if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
      fprintf(stderr,"Server: Socket create error: %s\n", strerror(errno));
      return EXIT_FAILURE;
   }

   //Set up socket so port can be immediately reused:
   setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &status, sizeof(i));

   //set up socket particulars
   server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
   server_addr.sin_port = htons(PORT);
   server_addr.sin_family = AF_INET;   
   
   
   if ((bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr))) == -1) {
      fprintf(stderr,"Server: Bind error: %s\n", strerror(errno));
      return EXIT_FAILURE;
   }
   
   if ((listen(server_socket, 5)) == -1) {
      fprintf(stderr,"Server: Listen error: %s\n", strerror(errno));
      return EXIT_FAILURE;
   }   
   
   unsigned int c_len = sizeof(client_addr);
   
   client_addr.sin_port = PORT;
   
   if ((client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &c_len)) == -1) {
      fprintf(stderr,"Server: Connection error: %s\n", strerror(errno));
   }
   
   printf("Connection Accepted.\n");
   
   //init pixbufs
   for (i = 0; i < FRAME_BUFFER_SIZE; i++) {
      buffer[i] = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
         FALSE, 8, X_RES, Y_RES);   
   }
   

   res = pthread_create(&a_thread, NULL, gtk_function, NULL);
   if (res != 0) {
      perror("Thread Creation failed");
      exit(EXIT_FAILURE);
   }
   sleep(2);
   
   char ready = 31;
   if (row == NULL)
      row = malloc(X_RES * sizeof(guchar));
   
   for(n = 0; n<NUM_GENS; n++) {
      if (current_master_frame - current_thread_frame < FRAME_BUFFER_SIZE) {
         current_frame = current_master_frame % FRAME_BUFFER_SIZE;

         for (i = 0; i < Y_RES; i++) {   
            write(client_socket, &ready, 1); //send ready
            if((bytes_read = read(client_socket, row, X_RES)) == -1) {
               fprintf(stderr,"Client: Read Error: %d Bytes read: %s\n",
                  bytes_read, strerror(errno));
               return EXIT_FAILURE;         
            }

//            printf("Read: %d\n", bytes_read);
            put_pixels(buffer[current_frame], i, row);   
            
         }
//         sleep(1);
         current_master_frame++;
         
         printf("Current Master Frame: %d, Thread Frame: %d Diff: %d\n",
            current_master_frame, current_thread_frame,
            current_master_frame - current_thread_frame);
      }
      else {
         printf("Other thread stalled\n");
         printf("Current Master Frame: %d, Thread Frame: %d Diff: %d\n",
            current_master_frame, current_thread_frame,
            current_master_frame - current_thread_frame);
         sleep(1);
      }
         
   }

   exit(EXIT_SUCCESS);   
   
}

void *gtk_function(void *arg) {
    int i;
   
//    gtk_init((int*) arg, NULL);
   
   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   gtk_window_set_screen (GTK_WINDOW (window),
              gtk_widget_get_screen (window));
   gtk_window_set_title (GTK_WINDOW (window), "Pixbufs");
   gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
   
   g_signal_connect (window, "destroy",
         G_CALLBACK (gtk_widget_destroyed), &window);
   g_signal_connect (window, "destroy",
         G_CALLBACK (cleanup_callback), NULL);
   


  gtk_widget_set_size_request (window, X_RES, Y_RES);

  frame = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, X_RES, Y_RES);

  da = gtk_drawing_area_new ();

  g_signal_connect (da, "expose-event",
          G_CALLBACK (expose_cb), NULL);

  gtk_container_add (GTK_CONTAINER (window), da);

  timeout_id = g_timeout_add (FRAME_DELAY, timeout, NULL);


  if (!gtk_widget_get_visible (window))
    {
      gtk_widget_show_all (window);
    }
  else
    {
      gtk_widget_destroy (window);
      window = NULL;
      g_object_unref (frame);
    }
    gtk_main();

    pthread_exit("GTK done.");   
}

/* Expose callback for the drawing area */
static gint
expose_cb (GtkWidget      *widget,
           GdkEventExpose *event,
           gpointer        data)
{   
   
  guchar *pixels;
  int rowstride;

  rowstride = gdk_pixbuf_get_rowstride (frame);

  pixels = gdk_pixbuf_get_pixels (frame) + rowstride * event->area.y + event->area.x * 3;

  gdk_draw_rgb_image_dithalign (widget->window,
                                widget->style->black_gc,
                                event->area.x, event->area.y,
                                event->area.width, event->area.height,
                                GDK_RGB_DITHER_NORMAL,
                                pixels, rowstride,
                                event->area.x, event->area.y);
                               
  return TRUE;
}



/* Timeout handler to regenerate the frame */
static gint
timeout (gpointer data)
{
  int catch_up = current_master_frame - current_thread_frame;
  if(catch_up > 0) {   
     int current_frame = current_thread_frame % FRAME_BUFFER_SIZE;
     gdk_pixbuf_copy_area(buffer[current_frame], 0, 0, X_RES, Y_RES,
        frame, 0, 0);

     gtk_widget_queue_draw (da);
     current_thread_frame++;
  }
  return TRUE;
}



static void
cleanup_callback (GtkObject *object,
                  gpointer   data)
{
  g_source_remove (timeout_id);
  timeout_id = 0;
}


Top
 Profile  
 
 Post subject: Re: Is it possible to declare a Pixbuf array in C?
PostPosted: Thu May 03, 2012 7:42 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 733
Location: UK
Been a bit busy of late.

Use locks for both reads and write of shared data. This is the only way that data would be complete and correct for both threads. If you do not do this it is possible to have incomplete writes of data (a partial write and hence garbage), a write in one core of a multi processor machine may write and only get as far as the cache before another core tries to read and that core then reads old data.

_________________
E.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 9 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group