GTK+ Forums

Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
It is currently Wed Nov 26, 2014 6:37 pm

All times are UTC




Post new topic Reply to topic  [ 10 posts ] 
Author Message
 Post subject: Drawing in GtkDrawingArea
PostPosted: Mon Aug 11, 2014 7:18 pm 
Offline
Familiar Face

Joined: Mon Jul 07, 2014 7:55 pm
Posts: 5
Hello everyone!

What I am trying to do for a project is to collect data and plot the data points onto a GtkDrawingArea. The coding environment that I am using is Anjuta. With this being said, I am collecting the data inside a new thread that collects data every 3 seconds. However, at the end of the thread, I try to plot the data into a drawing area, but nothing is being displayed. Currently, I am simply trying to draw different shapes into the drawing area with the following code:

Code:
static void do_drawing(cairo_t *);

int points[11][2] = {
    { 0, 85 },
    { 75, 75 },
    { 100, 10 },
    { 125, 75 },
    { 200, 85 },
    { 150, 125 },
    { 160, 190 },
    { 100, 150 },
    { 40, 190 },
    { 50, 125 },
    { 0, 85 }
};


static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
    gpointer user_data)
{
  do_drawing(cr);
   printf("call draw \n");
  return FALSE;
}

static void do_drawing(cairo_t *cr)
{
   cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
   cairo_set_line_width(cr, 1);

  gint i;
  for (i = 0; i < 10; i++) {
      cairo_line_to(cr, points[i][0], points[i][1]);
  }

  cairo_close_path(cr);
  cairo_stroke_preserve(cr);

  cairo_move_to(cr, 240, 40);
  cairo_line_to(cr, 240, 160);
  cairo_line_to(cr, 350, 160);
  cairo_close_path(cr);

  cairo_stroke_preserve(cr);
  cairo_fill(cr);

  cairo_move_to(cr, 380, 40);
  cairo_line_to(cr, 380, 160);
  cairo_line_to(cr, 450, 160);
  cairo_curve_to(cr, 440, 155, 380, 145, 380, 40);

  cairo_stroke_preserve(cr);
  cairo_fill(cr); 

   cairo_move_to(cr,275,5);
   cairo_line_to(cr,275,350);
   cairo_move_to(cr,5,175);
   cairo_line_to(cr,550,175);
}


First of all, when a new window is created, I declare the drawing area and give it a name "drawingarea1". The drawing area is also declared in a struct that is created automatically by Anjuta:

Code:
/* ANJUTA: Macro MENGTEST_APPLICATION gets Mengtest - DO NOT REMOVE */
struct _MengtestPrivate
{
   /* ANJUTA: Widgets declaration for mengtest.ui - DO NOT REMOVE */
   GtkWidget* drawingarea1;
};

/* Create a new window loading a file */
static void
mengtest_new_window (GApplication *app,
                           GFile        *file)
{
   GtkWidget *window;

   GtkBuilder *builder;
   GError* error = NULL;

   priv = MENGTEST_APPLICATION(app)->priv;

   /* Load UI from file */
   builder = gtk_builder_new ();
   if (!gtk_builder_add_from_file (builder, UI_FILE, &error))
   {
      g_critical ("Couldn't load builder file: %s", error->message);
      g_error_free (error);
   }

   /* Auto-connect signal handlers */
   gtk_builder_connect_signals (builder, app);

   /* Get the window object from the ui file */
   window = GTK_WIDGET (gtk_builder_get_object (builder, TOP_WINDOW));
        if (!window)
        {
      g_critical ("Widget \"%s\" is missing in file %s.",
            TOP_WINDOW,
            UI_FILE);
        }

   
   /* ANJUTA: Widgets initialization for mengtest.ui - DO NOT REMOVE */
   priv->drawingarea1 = GTK_WIDGET (gtk_builder_get_object(builder, "drawingarea1"));
   
   g_object_unref (builder);


   //g_signal_connect(G_OBJECT(priv->drawingarea1), "draw", G_CALLBACK(on_draw_event), NULL);
   //g_timeout_add( 500, G_CALLBACK(on_draw_event), NULL);
   
   
   gtk_window_set_application (GTK_WINDOW (window), GTK_APPLICATION (app));
   if (file != NULL)
   {
      /* TODO: Add code here to open the file in the new window */
   }

   gtk_widget_show_all (GTK_WIDGET (window));
}


In the block of code above, there are 2 lines of code that are commented out:

Code:
   //g_signal_connect(G_OBJECT(priv->drawingarea1), "draw", G_CALLBACK(on_draw_event), NULL);
   //g_timeout_add( 500, G_CALLBACK(on_draw_event), NULL);


If these lines are uncommented, then the shapes that I am drawing will appear in drawingarea1. However, I want this drawing area to update continuously (when new data is collected). This is why I tried to put these lines of code in the thread that collects data. As said earlier, the problem is that the drawing area does not display any drawings. The code that was used in the thread is shown below:

Code:
static gpointer
thread_func( gpointer data )
{
   /* used for g_convert (did not use)
   gchar *utf8;
   GError *err = NULL;
   gsize *bytes_read = NULL;
   gsize *bytes_written = NULL;*/

   struct netcommand netcommand_buf;
   uint16_t samples[UINT16_MAX][4];
   FILE *out_fd;
   char *time_string;
   time_t now;
   char file_name[50];
   unsigned int i,j;
   unsigned int k = 0;

   time(&now);
   time_string = ctime(&now);

   strcpy (file_name, "sampled/");
   strcat (file_name, time_string);
   file_name[strlen(file_name)-1]='\0';
   strcat (file_name, ".csv");   

      FILE *out_fd_most_recent;
      char file_name_most_recent[50];

      strcpy (file_name_most_recent, "sampled/");
      strcat (file_name_most_recent, time_string);
      file_name_most_recent[strlen(file_name_most_recent)-1]='\0';
      strcat (file_name_most_recent, "_most_recent.csv");

   g_signal_connect( G_OBJECT( priv->StopScanB ), "clicked",G_CALLBACK( cb_clicked ), NULL );

   //g_signal_connect(G_OBJECT(priv->drawingarea1), "draw", G_CALLBACK(on_draw_event), NULL);
   //g_timeout_add( 1000, G_CALLBACK(on_draw_event), NULL);
   
   GtkTextBuffer *textbuffer1;
   while(stop==0){
      sleep(3);
      gdk_threads_enter();
      
      out_fd = fopen(file_name, "w");
      out_fd_most_recent = fopen(file_name_most_recent, "w");
      //printf("%s",file_name);

      if(out_fd == NULL){
         printf("Problem openning file\n");
         exit(123);
      }

      if(out_fd_most_recent == NULL){
         printf("Problem openning file\n");
         exit(123);
      }
   
      netcommand_buf.type = set_reportOpt;
      netcommand_buf.addr = 0;
      netcommand_buf.command = htonl(0);

      
      
      textbuffer1 = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->textview1));
      
      send(sock_fd, &netcommand_buf, sizeof(netcommand_buf), 0);
      if(recv(sock_fd, &samples, sizeof(samples), 0) == 512){
         //while(fscanf(out_fd,"%s",&final) != EOF)
            for(i = 0; i<64; i++){
               for(j=0; j<4; j++){
                  //storage[i][j] = samples[i][j];
                  //printf(" %d ", samples[i][j]);

                     // /* disable the text view while loading the buffer with the text */
                     /*gtk_widget_set_sensitive (priv->textview1, FALSE);
                     textbuffer1 = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->textview1));

                     //utf8 = g_convert(&samples[i][j], -1, "UTF-8", "us-ascii", bytes_read, bytes_written, &err);
                     //gtk_text_buffer_set_text (textbuffer1, utf8, -1);
                  
                     gtk_text_buffer_set_text (textbuffer1, &samples[i][j], -1);
                     gtk_text_buffer_set_modified (textbuffer1, FALSE);*/
                  
                  //gtk_text_buffer_set_text (textbuffer1, &storage[i][j], -1);
                  //fprintf(out_fd, "%d,", (samples[i][j]));
                  fprintf(out_fd_most_recent, "%d,", (samples[i][j]));
               }
               //printf("\n");
               //printf("%d, %d, %d, %d \n", samples[i][j]);
               //fprintf(out_fd, "\n");
               fprintf(out_fd_most_recent, "\n");
            }
      }
      



      
      
      unsigned int l = 0;
      //unsigned int m,n;
      while (storage[l][0] != NULL){
         l++;
      }
      //printf("%d\n\n\n",l);
      for(i = 0; i<64; i++){
         for(j=0; j<4; j++){
            storage[l][j] = samples[i][j];
            //fprintf(out_fd_most_recent, "%d,", (samples[i][j]));      
         }
         //fprintf(out_fd_most_recent, "\n");
         l++;
      }
      unsigned int n = 0;
      while (storage[n][0] != NULL){
         for (j = 0; j < 4; j++){
            fprintf(out_fd, "%d,", (storage[n][j]));      
         }
            fprintf(out_fd, "\n");
            n++;
         
      }
      
      fclose(out_fd);
      fclose(out_fd_most_recent);
   
      /*
      int final;
      unsigned int l = 0;
      while(fscanf(file_name,"%s",&final) != EOF){
         l++;
      }*/
      
      //  textbuffer1 = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->textview1));
      //  gtk_text_buffer_set_text (textbuffer1, "thread", -1);
      
      
      //textbuffer1 = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->textview1));
      //gtk_text_buffer_set_text (textbuffer1, samples[0][0], -1);

      //printf("thread");

      
      GError *err=NULL;
      gchar *status;
      gchar *text;
      gboolean result;
      GtkTextBuffer *textbuffer1;
   
      result = g_file_get_contents (file_name_most_recent, &text, NULL, &err);
      if (result == FALSE) {
         // error loading file, show message to user
         printf("cannot load file");
         g_error_free (err);
          g_free (text);
      }

        //disable the text view while loading the buffer with the text
      gtk_widget_set_sensitive (priv->textview1, FALSE);
      textbuffer1 = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->textview1));
      gtk_text_buffer_set_text (textbuffer1, text, -1);
      gtk_text_buffer_set_modified (textbuffer1, FALSE);
      g_free (text);

      g_signal_connect(G_OBJECT(priv->drawingarea1), "draw", G_CALLBACK(on_draw_event), NULL);
      g_timeout_add( 1000, G_CALLBACK(on_draw_event), NULL);
      
      gdk_threads_leave();

      
      
   }
    return( NULL );
}


The thread works properly, as data is being collected every 3 seconds, which is expected. In the on_draw_event and do_drawing functions, I also tried placing printf statements to see if these functions are actually being called. Turns out that they are being called properly. With this being said, the functions should be executing, but I am not sure why nothing is being drawn into the drawing area that I created.

Does anyone have an idea? Thank you all so much!


Top
 Profile  
 
 Post subject: Re: Drawing in GtkDrawingArea
PostPosted: Tue Aug 12, 2014 12:22 am 
Offline
GTK+ Geek

Joined: Sat Jul 26, 2014 11:43 pm
Posts: 62
Not sure here. You should be able to get the values to draw with cairo every three seconds or so. They are in the storage array? If you have an array of values you can do something like this.

Code:
//gcc -Wall  `pkg-config --cflags gtk+-3.0` DrawPointsCairo.c -o DrawPointsCairo `pkg-config --libs gtk+-3.0`

#include <gtk/gtk.h>

static double test_numbers[100];

static void get_random_numbers(void)
  {
    int i=0;
    GRand *rand1=g_rand_new();
    for(i=0;i<100;i++) test_numbers[i]=200*g_rand_double(rand1);
    g_rand_free(rand1);
  }
static void draw_points(GtkWidget *widget)
  { 
    int i=0;
    cairo_t *graph=NULL;
    cairo_t *points=NULL;
 
    GdkWindow *DefaultWindow=gtk_widget_get_window(GTK_WIDGET(widget));
    graph=gdk_cairo_create(DefaultWindow);
    points=gdk_cairo_create(DefaultWindow);

    cairo_translate(graph, 250, 250);
    cairo_set_source_rgb(graph, 0.0, 1.0, 0.0);
    cairo_set_line_width(graph, 3.0);
    cairo_move_to(graph, -200, 0);
    cairo_line_to(graph, 200, 0);
    cairo_move_to(graph, 0, -200);
    cairo_line_to(graph, 0, 200);
    cairo_stroke(graph);

    cairo_translate(points, 250, 50);
    cairo_set_source_rgb(points, 0.0, 0.0, 1.0);
    cairo_set_line_width(points, 5.0);
    cairo_set_line_cap(points, CAIRO_LINE_CAP_ROUND);
    for(i=0;i<100;i+=2)
       {
         cairo_move_to(points, test_numbers[i], test_numbers[i+1]);
         cairo_line_to(points, test_numbers[i], test_numbers[i+1]);
       }
    cairo_stroke(points);

    cairo_destroy(graph);
    cairo_destroy(points);
  }
static void start_drawing(GtkWidget *drawing_area, gpointer data)
  {   
    get_random_numbers();
    g_print("Draw\n"); 
    draw_points(GTK_WIDGET(drawing_area));
  }
static gboolean invalidate_drawing(gpointer data)
  {
    g_print("Invalidate\n");
    //Clear window to re-draw.
    gtk_widget_queue_draw_area(GTK_WIDGET(data), 0, 0, 500, 500);
    return TRUE;
  }
int main (int argc, char *argv[])
  {
    gtk_init(&argc, &argv);
   
    GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_default_size(GTK_WINDOW(window), 500, 500);
    gtk_window_set_title(GTK_WINDOW(window), "Draw Points");
    g_signal_connect_swapped(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    GtkWidget *drawing_area = gtk_drawing_area_new();
    gtk_widget_set_size_request(drawing_area, 500, 500);
   
    g_signal_connect(G_OBJECT(drawing_area), "draw", G_CALLBACK(start_drawing), NULL); 

    gtk_container_add(GTK_CONTAINER(window), drawing_area);

    g_timeout_add(3000, invalidate_drawing, drawing_area);

    gtk_widget_show_all(window);
    gtk_main();

    return 0;
  }


Top
 Profile  
 
 Post subject: Re: Drawing in GtkDrawingArea
PostPosted: Tue Aug 12, 2014 5:19 pm 
Offline
Familiar Face

Joined: Mon Jul 07, 2014 7:55 pm
Posts: 5
Hi! Thank you for the prompt response!

Yes, in the end the values will be in the storage array. However, right now, all I want to do is to draw a few shapes into the drawing area. In the new thread that was created in the code, I use:

Code:
g_signal_connect(G_OBJECT(priv->drawingarea1), "draw", G_CALLBACK(on_draw_event), NULL);
g_timeout_add( 1000, G_CALLBACK(on_draw_event), NULL);


Which to my understanding calls the "on_draw_event" function. The "on_draw_event" function is:

Code:
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
    gpointer user_data)
{
  do_drawing(cr);
   printf("call draw \n");
  return FALSE;
}


This function calls the "do_drawing" function, which is:

Code:
static void do_drawing(cairo_t *cr)
{
   cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
   cairo_set_line_width(cr, 1);

  gint i;
  for (i = 0; i < 10; i++) {
      cairo_line_to(cr, points[i][0], points[i][1]);
  }

  cairo_close_path(cr);
  cairo_stroke_preserve(cr);

  cairo_move_to(cr, 240, 40);
  cairo_line_to(cr, 240, 160);
  cairo_line_to(cr, 350, 160);
  cairo_close_path(cr);

  cairo_stroke_preserve(cr);
  cairo_fill(cr);

  cairo_move_to(cr, 380, 40);
  cairo_line_to(cr, 380, 160);
  cairo_line_to(cr, 450, 160);
  cairo_curve_to(cr, 440, 155, 380, 145, 380, 40);

  cairo_stroke_preserve(cr);
  cairo_fill(cr); 

   cairo_move_to(cr,275,5);
   cairo_line_to(cr,275,350);
   cairo_move_to(cr,5,175);
   cairo_line_to(cr,550,175);
}


With this being said, a few shapes should be drawn into the drawing area that was created. However, even though these functions are being called properly, nothing is being drawn into the drawing area and I have no idea why...


Top
 Profile  
 
 Post subject: Re: Drawing in GtkDrawingArea
PostPosted: Tue Aug 12, 2014 6:09 pm 
Offline
GTK+ Geek

Joined: Sat Jul 26, 2014 11:43 pm
Posts: 62
This is outside of my expertise. I have used threads to speed up computations but have always returned to the main GTK thread to trigger any events and do drawings. After doing the long running calculations I would end up with some sort of container accessible from the main thread without any concurrency issues.

I did notice that your timer function is returning false which will end your timer. If you call it and return true the timer will keep calling it. Also you want your timer to invalidate or clear your drawing in the function that it calls and then trigger a draw event. If they aren't separate you might just be always clearing the drawing after it has been drawn. Have done that sort of thing myself several times.


Top
 Profile  
 
 Post subject: Re: Drawing in GtkDrawingArea
PostPosted: Tue Aug 12, 2014 10:26 pm 
Offline
GTK+ Geek

Joined: Sat Jul 26, 2014 11:43 pm
Posts: 62
OK, another try at it. Moved the clear into the Cairo draw function and test a bunch of points with g_timeout_add and gdk_threads_add_timeout_full. I think this is closer to getting it to work well during a long re-draw.

Code:
//gcc -Wall  `pkg-config --cflags gtk+-3.0` DrawPointsCairo.c -o DrawPointsCairo `pkg-config --libs gtk+-3.0`

#include <gtk/gtk.h>
#include <gdk/gdk.h>

static double test_numbers[30000];

static void get_random_numbers(void)
  {
    int i=0;
    GRand *rand1=g_rand_new();
    for(i=0;i<30000;i++) test_numbers[i]=200*g_rand_double(rand1);
    g_rand_free(rand1);
  }
static void draw_points(GtkWidget *widget)
  { 
    int i=0;
    cairo_t *graph=NULL;
    cairo_t *points=NULL;
 
    GdkWindow *DefaultWindow=gtk_widget_get_window(GTK_WIDGET(widget));
    graph=gdk_cairo_create(DefaultWindow);
    points=gdk_cairo_create(DefaultWindow);
   
    //Clear the surface.
    cairo_set_source_rgba(graph, 1.0, 1.0, 1.0, 1.0);
    cairo_paint(graph);
   
    cairo_translate(graph, 250, 250);
    cairo_set_source_rgb(graph, 0.0, 1.0, 0.0);
    cairo_set_line_width(graph, 3.0);
    cairo_move_to(graph, -200, 0);
    cairo_line_to(graph, 200, 0);
    cairo_move_to(graph, 0, -200);
    cairo_line_to(graph, 0, 200);
    cairo_stroke(graph);

    cairo_translate(points, 250, 50);
    cairo_set_source_rgb(points, 0.0, 0.0, 1.0);
    cairo_set_line_width(points, 5.0);
    cairo_set_line_cap(points, CAIRO_LINE_CAP_ROUND);
    for(i=0;i<30000;i+=2)
       {
         cairo_move_to(points, test_numbers[i], test_numbers[i+1]);
         cairo_line_to(points, test_numbers[i], test_numbers[i+1]);
       }
    cairo_stroke(points);

    cairo_destroy(graph);
    cairo_destroy(points);
  }
static void start_drawing(GtkWidget *drawing_area, gpointer data)
  { 
    g_print("Draw Signal\n");   
    get_random_numbers(); 
    draw_points(GTK_WIDGET(drawing_area));
  }
static gboolean invalidate_drawing(gpointer data)
  {
    g_print("Timer Signal\n");
    get_random_numbers();
    draw_points(GTK_WIDGET(data));
    return TRUE;
  }
int main (int argc, char *argv[])
  {
    gtk_init(&argc, &argv);
   
    GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_default_size(GTK_WINDOW(window), 500, 500);
    gtk_window_set_title(GTK_WINDOW(window), "Draw Points");
    g_signal_connect_swapped(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    GtkWidget *drawing_area = gtk_drawing_area_new();
    gtk_widget_set_size_request(drawing_area, 500, 500);
   
    g_signal_connect(G_OBJECT(drawing_area), "draw", G_CALLBACK(start_drawing), NULL); 

    gtk_container_add(GTK_CONTAINER(window), drawing_area);

    //g_timeout_add(3000, invalidate_drawing, drawing_area);
    gdk_threads_add_timeout_full(G_PRIORITY_DEFAULT_IDLE,3000,invalidate_drawing,drawing_area,NULL);

    gtk_widget_show_all(window);
    gtk_main();

    return 0;
  }


Top
 Profile  
 
 Post subject: Re: Drawing in GtkDrawingArea
PostPosted: Wed Aug 13, 2014 5:30 pm 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 780
Location: UK
Hello,

cecashon - In your last example you have some errors in your code. The "draw" signal can be called at any time. For example when the window is moved and areas are exposed from under another window.

To correct your code the time-out is called after a wait period of 3 seconds periodically. This collects the random numbers and then requests a redraw of the Drawing Area by invalidating it.

The "draw" call back now uses the Cairo Context that is supplied. This is an already clipped area and no other cairo context is needed to be allocated.

The corrected code is below.
Code:
//gcc -Wall  `pkg-config --cflags gtk+-3.0` DrawPointsCairo.c -o DrawPointsCairo `pkg-config --libs gtk+-3.0`

#include <gtk/gtk.h>
#include <gdk/gdk.h>

static double test_numbers[30000];

static void get_random_numbers(void)
  {
    int i=0;
    GRand *rand1=g_rand_new();
    for(i=0;i<30000;i++) test_numbers[i]=200*g_rand_double(rand1);
    g_rand_free(rand1);
  }

static gboolean draw_points(GtkWidget *widget, cairo_t *cr, gpointer data)
  {
    int i=0;
   
    //Clear the surface.
    cairo_save(cr);
    cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
    cairo_paint(cr);
    cairo_restore(cr);

    cairo_save(cr);
    cairo_translate(cr, 250, 250);
    cairo_set_source_rgb(cr, 0.0, 1.0, 0.0);
    cairo_set_line_width(cr, 3.0);
    cairo_move_to(cr, -200, 0);
    cairo_line_to(cr, 200, 0);
    cairo_move_to(cr, 0, -200);
    cairo_line_to(cr, 0, 200);
    cairo_stroke(cr);
    cairo_restore(cr);

    cairo_translate(cr, 250, 50);
    cairo_set_source_rgb(cr, 0.0, 0.0, 1.0);
    cairo_set_line_width(cr, 5.0);
    cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
    for(i=0;i<30000;i+=2)
       {
         cairo_move_to(cr, test_numbers[i], test_numbers[i+1]);
         cairo_line_to(cr, test_numbers[i], test_numbers[i+1]);
       }
    cairo_stroke(cr);

    return TRUE;
  }

static gboolean invalidate_drawing(gpointer data)
  {
    GdkWindow *win;

    g_print("Timer Signal\n");
    get_random_numbers();

    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);
    }

    return TRUE;
  }

int main (int argc, char *argv[])
  {
    gtk_init(&argc, &argv);
   
    GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_default_size(GTK_WINDOW(window), 500, 500);
    gtk_window_set_title(GTK_WINDOW(window), "Draw Points");
    g_signal_connect_swapped(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    GtkWidget *drawing_area = gtk_drawing_area_new();
    gtk_widget_set_size_request(drawing_area, 500, 500);
   
    g_signal_connect(G_OBJECT(drawing_area), "draw", G_CALLBACK(draw_points), NULL);

    gtk_container_add(GTK_CONTAINER(window), drawing_area);

    //g_timeout_add(3000, invalidate_drawing, drawing_area);
    gdk_threads_add_timeout_full(G_PRIORITY_DEFAULT_IDLE,3000,invalidate_drawing,drawing_area,NULL);

    gtk_widget_show_all(window);
    gtk_main();

    return 0;
  }


kjw99 - In your original code you do have a number of problems with the code in the thread section.

- The calling of GTK/GDK API functions in anything but the main thread is now deprecated and you should avoid this.
- You are constantly adding time-out call backs and "draw" signal handlers. This is not needed within the thread.
- You are allocating very large arrays on the stack of the thread. The stack of threads are of fixed size and can be fairly small.
- You make a call to ctime(). This is not thread safe.
- I expect the variable "stop" is global to all threads. Access to this is not protected so you may have a race condition here.

There may be other problems, but I think that may be a start.

_________________
E.


Top
 Profile  
 
 Post subject: Re: Drawing in GtkDrawingArea
PostPosted: Wed Aug 13, 2014 6:15 pm 
Offline
GTK+ Geek

Joined: Sat Jul 26, 2014 11:43 pm
Posts: 62
Thank you for the correction. Very helpful.


Top
 Profile  
 
 Post subject: Re: Drawing in GtkDrawingArea
PostPosted: Wed Aug 13, 2014 10:17 pm 
Offline
Familiar Face

Joined: Mon Jul 07, 2014 7:55 pm
Posts: 5
errol wrote:
kjw99 - In your original code you do have a number of problems with the code in the thread section.

- The calling of GTK/GDK API functions in anything but the main thread is now deprecated and you should avoid this.
- You are constantly adding time-out call backs and "draw" signal handlers. This is not needed within the thread.
- You are allocating very large arrays on the stack of the thread. The stack of threads are of fixed size and can be fairly small.
- You make a call to ctime(). This is not thread safe.
- I expect the variable "stop" is global to all threads. Access to this is not protected so you may have a race condition here.

There may be other problems, but I think that may be a start.

Thank you so much for these pointers! I will try my best to fix these problems!

You said that "The calling of GTK/GDK API functions in anything but the main thread is now deprecated and you should avoid this." Why is this so? Do you mean that you cannot use the API functions in more than one thread at a time?


Also, @cecashon:
Quote:
I did notice that your timer function is returning false which will end your timer. If you call it and return true the timer will keep calling it. Also you want your timer to invalidate or clear your drawing in the function that it calls and then trigger a draw event. If they aren't separate you might just be always clearing the drawing after it has been drawn. Have done that sort of thing myself several times.


You were right about clearing the drawing. When I added a clear, then the points were plotted into the drawing area. But question... you said that "If they aren't separate you might just be always clearing the drawing after it has been drawn." Are you saying that the drawing area automatically clears on each call? How does not explicitly clearing the drawing area make a difference then?

Thank you!


Top
 Profile  
 
 Post subject: Re: Drawing in GtkDrawingArea
PostPosted: Thu Aug 14, 2014 12:19 am 
Offline
GTK+ Geek

Joined: Sat Jul 26, 2014 11:43 pm
Posts: 62
You are going to trip me up on this one. Errol's code is how you want to go about it.

In the GTK3 Drawing Area reference it says,

"Note that GDK automatically clears the exposed area to the background color before sending the expose event, and that drawing is implicitly clipped to the exposed area."

I was thinking that you might want to keep the timer and draw functions separate because you might want an accumulation of points drawn. Better to accumulate data in a container and redraw. Also, with a lot of points you might want to draw something simple like the axis on the initial draw event when the window opens and then draw your long running function with points and graph with the timer. That is easy to do with just a boolean check before you draw all the points. With an explicit clear you can clear the background to any color you want. Really, just giving it a try and changing things around to see what works. I have been working on some similar graphing problems and it was a good learning experience for me.


Top
 Profile  
 
 Post subject: Re: Drawing in GtkDrawingArea
PostPosted: Fri Aug 15, 2014 5:47 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 780
Location: UK
kjw99 - Have a look at https://developer.gnome.org/gdk3/stable/gdk3-Threads.html. This explains a lot more about the deprecation of the use of the "GDK lock" which came about in version 3.6. It has always been good practice not to call GTK/GDK from multiple threads as the port to Microsoft Windows did not support this and would crash unpredictably.

GLib is completely thread safe so you can use that with out problems. But to quote the documentation.
Quote:
GTK+, however, is not thread safe. You should only use GTK+ and GDK from the thread gtk_init() and gtk_main() were called on. This is usually referred to as the “main thread”.

_________________
E.


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

All times are UTC


Who is online

Users browsing this forum: Google Adsense [Bot], Yahoo [Bot] 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:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group