This is the paradigm I use in all my drawing apps that has served me well:

    1) Do all drawing to one or more background pixmaps.
    2) Do all drawing in routines separate from your configure handler or
your expose handler.
    3) Call your drawing routine(s) from the configure handler.
    4) Once your drawing routine has completed its task, call
gtk_widget_queue_draw_area() to force the expose event.
    5) Do no drawing in your expose event except to gtk_draw_drawable(),
rendering your background pixmap to the physical display.
    6) Use temporary pixmaps liberally when rendering a "temporary" state
to the screen.  (For example, display of cross-hairs and coordinates
when user is simply dragging the mouse (no buttons down) across the
drawing area.)

You will notice, here, that there is no actual drawing to the physical
screen except to render your pixmap.  This is the fastest possible manner
in which to draw to the screen.  As well, the expose handler is called
whenever your drawing area is exposed by the window manager, say if it has
been partially obscured by other windows and the user brings it to the
front.  By using gtk_draw_drawable(), you can use the same (x,y)
parameters passed to the callback to render only that part of the pixmap
requiring exposure, i.e., making it as fast as possible.  (Not to mention
that to use these (x,y) parameters to programmatically figure out what
should be re-drawn is practically impossible.)

By maintaining all drawing activity in separate routines, you are able to:

    1) have multiple routines responsible for drawing a picture to a
single drawing area, determining programmatically which routine should
be called at any given moment.  These separate routines can draw to
separate backing store pixmaps.
    2) easily call any drawing routine from anywhere else in your
application, including background threads (via g_idle_add()), thus
making it trivial to maintain a multi-threaded graphical application.
    3) maintain, possibly, multiple backing store pixmaps that can be
easily referenced for redrawing without having to go through an entire
redraw.  (For example, to maintain "before" and "after" states of a
drawing action.  It is much easier to simply re-render a pixmap as
part of an Undo operation than to have to "remember" and redraw the
previous state.)

Basically, in de-coupling your configure and expose events from actual
drawing, you gain much more power in managing all the requirements of your
drawing area than if you use a single drawing area that is the screen. 
Not to mention that drawing directly to the screen is absolutely the
slower of the two options.

As John's post indicates, there is no single way to do all this; gtk gives
you way more than enough rope.  The trick is finding the method that works
for you and your specific requirements.



On Nov 29, 2007 4:30 AM, Stewart Weiss <stewart weiss acm org> wrote:

    Many thanks for these posts. They are moving me closer to a better
    understanding of the right way to tackle the drawing issues.
    I still need a bit of clarification.

    1. I am assuming that when I queue a draw for the old position of
    the rubberbanded line, I am using XOR to draw it, so that it is in
    effect, an erasing, right?

    2. You say in the post referenced below that we should really draw
    only in the expose event handler, not in the motion or button event
    Right now, my function to draw a line uses gdk_draw_line into the pixmap
    and then calls gdk_window_invalidate_rect to send the expose event later.
    If I actually call the gdk_draw_line in the expose event handler,
    into the pixmap, would I then use gdk_draw_drawable to copy the pixmap
    the window?   I know I can't queue a drawing event in the handler or else
    I have an infinite indirect recursive loop. Is this how?


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]