tags:

views:

68

answers:

2

I'm trying to redraw a GtkDrawingArea using the gtk_widget_queue_draw function, but the widget is not redrawing.

Here's the code, the gtk_widget_queue_draw is inside a button-press-event callback function.

static gboolean click(GtkWidget *board,GdkEventButton *event,gpointer parentWindow){
    static int origen = -1;
    static int destino = -1;

    if(origen == -1){
        mapeo(&origen, event->x, event->y);
    }else{
       mapeo(&destino, event->x, event->y);
    if(!movimiento_fichas(JUGADOR_DOS, origen - 1, destino - 1)){
        dialogoMovInvalido(parentWindow); //displays a warning dialog
        g_print("%d %d", origen, destino); //debugging console output
        origen = -1; destino = -1;
    }else{
        g_print("%d %d", origen, destino); //debugging console output
        gtk_widget_queue_draw(board); //Here's where the redrawing is supossed to occur.
       }
    }

    return 0;
}

Expose-event callback

static gboolean onExposeEvent(GtkWidget *widget,GdkEventExpose *event,gpointer data){
    cairo_t *cr;
    cairo_surface_t *fondo;
    cairo_surface_t *ficha_roja;
    cairo_surface_t *ficha_blanca;

gint i,j;

cr = gdk_cairo_create(widget->window);

fondo = cairo_image_surface_create_from_png("interfaz.png");
ficha_roja = cairo_image_surface_create_from_png("ficha_roja.png");
ficha_blanca = cairo_image_surface_create_from_png("ficha_blanca.png");

cairo_set_source_surface(cr, fondo, 0, 0);
cairo_paint(cr);

for(i=0; i<24; i++){
    if(tablero[i].player == JUGADOR_UNO){
        cairo_set_source_surface(cr, ficha_blanca, posiciones[i].x, posiciones[i].y);
        for(j=1; j<=tablero[i].num; j++){
            cairo_paint(cr);
            cairo_set_source_surface(cr, ficha_blanca, posiciones[i].x, posiciones[i].y);
            if(i < 12)
                cairo_set_source_surface(cr, ficha_blanca, posiciones[i].x, posiciones[i].y - (j*25));
            else
                cairo_set_source_surface(cr, ficha_blanca, posiciones[i].x, posiciones[i].y + (j*25));
        }
    }else if(tablero[i].player == JUGADOR_DOS){
        cairo_set_source_surface(cr, ficha_roja, posiciones[i].x, posiciones[i].y);
        for(j=1; j<=tablero[i].num; j++){
            cairo_paint(cr);
            if(i < 12)
                cairo_set_source_surface(cr, ficha_roja, posiciones[i].x, posiciones[i].y - (j*25));
            else
                cairo_set_source_surface(cr, ficha_roja, posiciones[i].x, posiciones[i].y + (j*25));
        }
    }
}

cairo_destroy(cr);

return 0;
}

Expose-event & button-press-event connections (both inside the function that creates the top level window).

  g_signal_connect(G_OBJECT(board),"expose-event",G_CALLBACK(onExposeEvent),NULL);
  g_signal_connect(G_OBJECT(board),"button-press-event",G_CALLBACK(click),window);

Main function.

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

    mainWindow(); //Creates the main window

    gtk_main();

    return 0;
}
+2  A: 

It is not possible to tell conclusively what's wrong, since you didn't paste all the relevant code. Anyway, I think there might be two errors/misunderstanding that result in your problem.

  • You should draw only in expose-event signal handler. While drawing outside it is possible, such drawing will not be updated and might get completely lost for any number of reasons, including such self-initiated redrawing.
  • Redrawing will happen asynchronously. I.e. in a different main loop run. This might be problematic if you run the main loop in a non-standard way, e.g. using gtk_events_pending()/gtk_main_iteration().

Finally, check that board is actually the widget you intend to redraw. Might be that you passed wrong user data when connecting click().

doublep
Drawing is done inside an expose-event callback function, and it works since the initial drawing occurs. The thing is that I need to redraw the GtkDrawingArea after mouse clicks (I did it in the past, haven't touched gtk for a while so I'm kind of rusty)
dallen
@dailen: Is `onExposeEvent` called after scheduling redrawal? How do you run main loop?
doublep
The main loop is fairly simple. My program goes like this, in mainWindow() is all the code regarding the window properties, signal connections, plus all the other widgets (sons of the toplevel window) stuff. I just want to be able to update a GtkDrawingArea after some clicks, since as afaik gtk_widget_queue_draw is supossed to call an "expose-event" callback an redraw the widget.
dallen
@dallen: It's not supposed to call, but schedule a redrawal, to be run in a separate main loop iteration. Is callback called at all (meaning signal is emitted) or not even called? Do you use custom main loop iteration code?
doublep
The first time the window is created the onExposeEvent() function does all the drawing it is supossed to. After gtk_widget_queue_draw() is called it does not.
dallen
I use the custom gtk main loop.
dallen
@dallen: Well, I'm out of ideas. If you e.g. minimize/restore the window, is your expose callback called again?
doublep
nope, does not work by minimizing, moving, resizing. And the worst is that I found this tutorial http://zetcode.com/tutorials/cairographicstutorial/basicdrawing/ that uses the exact same technique I'm using and IT WORKS..
dallen
@dallen: Well, in this case it looks your handler is not connected somehow (anymore, since the very first time it works). Check that the drawing area in `click` is the same as the one you connected `onExposeEvent` to. Also, verify any handler disconnection or blocking you might have.
doublep
The data structure containing the positions of drawings inside the GtkDrawingArea was not being changed after the click. So gtk_widget_queue_draw() was drawing the same thing over and over causing me to think that it wasn't being redraw. This kind of bug makes you feel so dumb.. haha..
dallen
A: 

Found the answer, there's nothing wrong with the gtk code. Code specific to my program was causing the error.

dallen