Re: Gtkmm widgets don't always update...



The call to gdk_flush() was an after-the-fact attempt at seeing if it would make any difference; it did not. Although I am quite familiar with the internals of X, I have yet to go through the Gtk / Gdk code to learn its internals. Perhaps I should at this point.

I tried using the technique you listed. Unfortunately, it had no effect on the problem, in fact, it caused the on_expose_event code to run in the same thread as the invalidate function. This is a problem, one should not use OpenGL code in threads other than the thread that created the context.

For example,


       void invalidate()
       {
               gdk_threads_enter();
std::cerr << "In invalidate()." << std::endl;
               Gdk::Rectangle rect = get_allocation();
               get_window()->invalidate_rect(rect, false);

gdk_window_process_updates(get_window()->gobj(), false);
std::cerr << "Done with invalidate()." << std::endl;
               gdk_threads_leave();
       }

bool OglWidget::on_expose_event(GdkEventExpose* event)
{
        std::cerr << "in on_expose_event()" << std::endl;

   // do OpenGL magic

   return true;
}

produces the output on stderr:

In invalidate()
in on_expose_event()
Done with invalidate()

showing that the expose event is clearly being executed within the lock in invalidate(). The results are the same, only the upper leftmost widget is being updated, even in this case. Having the expose event run in the producer thread shows itself as an issue because every 10 frames or so glXMakeCurrent() is failing.

For those who have not been listening, I have example code which shows this issue in both the table and hbox widgets. The example code is derived from the Gtkglextmm distribution's glgears demo program.

http://www.robstoddard.com/~rob/glgears.tgz        <- the table widget
http://www.robstoddard.com/~rob/glgears2.tgz      <- the hbox


Thank you for your assistance

Rob Stoddard




Paul Davis wrote:
On Wed, 2008-01-16 at 14:47 -0800, rob wrote:

The function I use to invalidate the widget from the producer thread is:

        void invalidate()
        {
                gdk_threads_enter();
                Gdk::Rectangle rect = get_allocation();
                get_window()->invalidate_rect(rect, false);
                gdk_flush();
                gdk_threads_leave();
        }

this shows an incorrect understanding of how a toolkit like GTK actually
draws.

when there are events to handle, they are all dispatched. the handler
calltree for each event stands a good chance of invalidating some part
of the window(s) owned by the app.

once the events have all been dispatched, there is a GTK idle handler
which then calls gdk_window_process_all_updates(). this finds all GDK
windows that have had some area invalidated, and invokes
gdk_window_process_updates() on each one, which in turn causes the
delivery of expose events to the window. in the expose event handler,
the window (or the invalidated portion of it) will be redrawn to show
the new content.

the last part of the puzzle is how the redrawn pixels actually get to
the screen. in the case of the X11 backend, this process is
asynchronous, because it involves sending draw requests to the server.
they will show up on screen some time after the request is sent. for
other backends, things are done in a more synchronous fashion - none of
the redraws will appear on screen until the next vertical sync trace
starts, for example.

your call to gdk_flush() does nothing relevant - it simply tells GDK to
make sure that all X11 requests have been sent to the server. but the
invalidate_rect() call didn't cause any X11 requests to be sent. it just
put the window into the update list. the window will not be redrawn
until the global GTK idle update routine kicks in.

there is one way around this cycle of events, and its used by a few
stock GTK widgets. you can call gdk_window_process_updates() yourself
when you want the expose events to be delivered right now (thus ensuring
a reasonable chance the the screen display will change very soon).

note that code that tries to circumvent the usual update cycle is
subject to potentially different behaviour with different GTK/GDK
backends.

--p




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