0
votes

I am developing a simple interface which simulates a led using GTK3 and C. When I receive a command the "led" turn on or turn off according to command. I am using Cairo in drawing area to draw a circle representing my led and I am using gtk_widget_queue_draw_area to update screen in my timeout function. After a while my CPU usage increase to 100% in my application.

When I receive a command I call the function below

void update_status_led(int led, int status_led)
{

    g_signal_connect(G_OBJECT(darea[led]), "draw", G_CALLBACK(on_draw_event_leds), GINT_TO_POINTER(status_led));

}

so the callback function "on_draw_event_leds" is called

gboolean on_draw_event_leds(GtkWidget *widget, cairo_t *cr, 
    gpointer user_data)
{ 
  set_status_led(cr, GPOINTER_TO_INT(user_data));
  return FALSE;
}

So it calls the function "set_status_led"

void set_status_led(cairo_t *cr, int status)
{
    printf("update status led: %d\n", countref++);
    cairo_reference(cr);
    cairo_set_line_width(cr, 2);  
    cairo_set_source_rgb(cr, 0, 0, 0);
    cairo_arc(cr, 9, 9, 7, 0, 2 * M_PI);
    if (status>0)
    {
      cairo_set_source_rgb(cr, 1, 0, 0); //red
    }
    else
    {
      cairo_set_source_rgb(cr, 0, 0, 0); //black
    }
    cairo_fill(cr);
    cairo_stroke(cr);
    cairo_destroy(cr);
}

I am using "printf("update status led: %d\n", countref++);" to know how many times my function is called and my log is printed below

New Connection from 127.0.0.1:34589
1 Command Received
update status led: 6
update status led: 7
1 Command Received
update status led: 8
update status led: 9
update status led: 10
1 Command Received
update status led: 11
update status led: 12
update status led: 13
update status led: 14
1 Command Received
update status led: 15
update status led: 16
update status led: 17
update status led: 18
update status led: 19
1 Command Received
update status led: 20
update status led: 21
update status led: 22
update status led: 23
update status led: 24
update status led: 25
1 Command Received
...

As can be seen, I receive only one command and my callback function on_draw_event_leds is called many times and always increase 1 more call each received command as previous cairo was not deleted and gtk_widget_queue_draw_area render them all again.

Can someone help me?

Thanks,

1
Not sure if this will fix it, but you have two big mistakes. First, do not call cairo_reference() and cairo_destroy(); you do not own the cairo_t that you get from the draw callback. Second, cairo_fill() clears the current path, so your cairo_stroke() draws nothing. Use ciaro_fill_preserve() instead. I'll take a closer look later today.andlabs
Thanks for your help, I fixed that you said, but this didn't fix my problem. My callback function is still called many times and increasing 1 more call each received command.J. Paulo
Ah, I see. You are calling update_status_led() on every change. g_signal_connect() does NOT replace any existing connection with a new one; rather, it adds a new connection to the list of existing connections. So all the signal handlers you connected before are still there. You will need to change your code to only call g_signal_connect() once. Perhaps store the current state in a global variable or a shared variable passed around through the last gpointer parameter to the signal function and use gtk_widget_queue_draw() to schedule a redraw.andlabs
Just curious, @andlabs, why do you like to answer in comments? Nothing wrong with it, I just wanted to know if you don't want the rep or something.oldtechaa
To not waste answers on things that are actually wrong if I'm not fully sure of what's going on. (I think it's this. Does this solve it? Yes it does. Okay, here's the answer, in a more fleshed-out and detailed form.) Also partially a habit from the winapi tag. Admittedly this question should be answered by what I said; I can write up a more thorough answer too, but right now I'm busy with IRL stuff.andlabs

1 Answers

0
votes

The g_signal_connect() function just says "when this event happens, do this function". You were likely confusing it for gtk_widget_queue_draw(), which is the function that actually causes a widget to be redrawn.

Somewhat counter-intuitively, signal connections are many-many. This means that any number of functions can connect to the same signal, and all of them will be called when that signal is emitted. Because you call g_signal_connect() repeatedly, you get multiple connections to your drawing function, and that drawing function will thus be called multiple times.

So what you want to do is move the g_signal_connect() to your initialization code instead, as that's usually where signals are connected anyway, and have gtk_widget_queue_draw() (or a similar function) in update_status_led().