Looking for comments on how to handle my custom widget



   I would like to write a document about gtkglarea and how to use
it properly in an application, because I am under the impression that
most people don't use it properly, and I am not even sure I am doing
the right thing.

   gtkglarea creates an OpenGL context inside a GTK widget. In the
expose_event callback, and only there, the application can call OpenGL
functions. In particular, it can upload textures to the GPU. The problem
is that when the widget is destroyed, for instance when gtk_main_quit()
is called, it is never exposed again and thus it is impossible to call
cleanup functions related to the OpenGL state.

   For most people, this is not an issue and they simply do not clean
up the GL context. However, in the context of a multiple window
application, or if there is data to retrieve from the GPU such as a
texture that has been rendered to, it has to be taken care of before
the GL context becomes unavailable.

   I successfully intercepted the quit signal by running another level
of gtk_main() in a gtk_quit_add() handler, then exiting properly.
However, this also requires me to add a helper function to the delete
event of the main window because it needs to return TRUE:

     gtk_signal_connect(GTK_OBJECT(window), "delete_event",
                        GTK_SIGNAL_FUNC(delayed_quit), NULL);

     /* ... */

     gboolean delayed_quit(GtkWidget *w, GdkEvent *e, void *data)
     {
         gtk_main_quit();
         return TRUE;
     }

   The important part of the code for the GtkGlArea object is here:

     gboolean shutdown_opengl = FALSE;
     glarea = gtk_gl_area_new(...);
     g_idle_add((GSourceFunc)idle, ...);
     gtk_quit_add(0, (GtkFunction)shutdown, ...); 
     gtk_signal_connect(GTK_OBJECT(glarea), "expose_event",
                        GTK_SIGNAL_FUNC(draw), ...);

     /* ... */

     gboolean idle(...)
     {
         /* If everything has been cleaned up, we can exit properly */
         if (opengl_finished())
         {
             gtk_main_quit();
             return FALSE;
         }

         /* Send expose event to trigger rendering */
         gtk_widget_draw(GTK_WIDGET(glarea), NULL);
         return TRUE;
     }

     gboolean draw(...)
     {
         if (gtk_gl_area_make_current(GTK_GL_AREA(glarea)))
         {
             /* Either proceed with shutdown, or draw the scene */
             if (shutdown_opengl)
                 opengl_shutdown();
             else
                 opengl_draw();
             gtk_gl_area_swapbuffers(GTK_GL_AREA(glarea));
         }

         return TRUE;
     }

     gboolean shutdown()
     {
         shutdown_opengl = TRUE;
         /* Hijack the exit process by adding another level of gtk_main */
         gtk_widget_set_sensitive(gtk_widget_get_toplevel(glarea), FALSE);
         gtk_main();
         return TRUE;
     }

   However, this only works when it is the main window that is
destroyed, not when a random container of the GtkGlArea object is.

   What could be a clean strategy to ensure that, when it is about to
be deleted (ie. when its toplevel or container widget is deleted), the
GtkGlArea widget is given enough GTK main loop iterations to receive
expose events (sent manually or by a timer) and shutdown properly?

Cheers,
-- 
Sam.


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