Switch to ANSI C comments.
[freeglut] / freeglut-1.3 / freeglut_structure.c
index af851f1..335168a 100644 (file)
@@ -32,7 +32,7 @@
 #define  G_LOG_DOMAIN  "freeglut-structure"
 
 #include "../include/GL/freeglut.h"
-#include "../include/GL/freeglut_internal.h"
+#include "freeglut_internal.h"
 
 
 /* -- GLOBAL EXPORTS ------------------------------------------------------- */
@@ -52,19 +52,19 @@ SFG_Structure fgStructure;
  *
  * If parent is set to NULL, the window created will be a topmost one.
  */
-SFG_Window* fgCreateWindow( SFG_Window* parent, const gchar* title, gint x, gint y, gint w, gint h, gboolean gameMode )
+SFG_Window* fgCreateWindow( SFG_Window* parent, const char* title, int x, int y, int w, int h, GLboolean gameMode )
 {
     /*
      * Have the window object created
      */
-    SFG_Window* window = g_new0( SFG_Window, 1 );
-    gint fakeArgc = 0;
+    SFG_Window* window = calloc( sizeof(SFG_Window), 1 );
+    int fakeArgc = 0;
 
     /*
      * If the freeglut internals haven't been initialized yet,
      * do it now. Hack's idea courtesy of Chris Purnell...
      */
-    if( fgState.Timer == NULL )
+    if( !fgState.Time.Set )
         glutInit( &fakeArgc, NULL );
 
     /*
@@ -73,6 +73,11 @@ SFG_Window* fgCreateWindow( SFG_Window* parent, const gchar* title, gint x, gint
     window->ID = ++fgStructure.WindowID;
 
     /*
+     * Initialize the children list
+     */
+    fgListInit( &window->Children );
+
+    /*
      * Does this window have a parent?
      */
     if( parent != NULL )
@@ -80,7 +85,7 @@ SFG_Window* fgCreateWindow( SFG_Window* parent, const gchar* title, gint x, gint
         /*
          * That's quite right, attach this windows as a child window
          */
-        parent->Children = g_list_append( parent->Children, window );
+       fgListAppend( &parent->Children, &window->Node );
         window->Parent = parent;
     }
     else
@@ -88,7 +93,7 @@ SFG_Window* fgCreateWindow( SFG_Window* parent, const gchar* title, gint x, gint
         /*
          * Otherwise add the newly created window to the topmost windows list
          */
-        fgStructure.Windows = g_list_append( fgStructure.Windows, window );
+       fgListAppend( &fgStructure.Windows, &window->Node );
     }
 
     /*
@@ -101,7 +106,7 @@ SFG_Window* fgCreateWindow( SFG_Window* parent, const gchar* title, gint x, gint
      * Open the window now. The fgOpenWindow() function is system
      * dependant, and resides in freeglut_window.c. Uses fgState.
      */
-    fgOpenWindow( window, title, x, y, w, h, gameMode );
+    fgOpenWindow( window, title, x, y, w, h, gameMode, (parent != NULL) ? TRUE : FALSE );
 
     /*
      * Return a pointer to the newly created window
@@ -117,14 +122,14 @@ SFG_Menu* fgCreateMenu( FGCBmenu menuCallback )
     /*
      * Have the menu object created
      */
-    SFG_Menu* menu = g_new0( SFG_Menu, 1 );
-    gint fakeArgc = 0;
+    SFG_Menu* menu = calloc( sizeof(SFG_Menu), 1 );
+    int fakeArgc = 0;
 
     /*
      * If the freeglut internals haven't been initialized yet,
      * do it now. Hack's idea courtesy of Chris Purnell...
      */
-    if( fgState.Timer == NULL )
+    if( !fgState.Time.Set )
         glutInit( &fakeArgc, NULL );
 
     /*
@@ -134,9 +139,14 @@ SFG_Menu* fgCreateMenu( FGCBmenu menuCallback )
     menu->Callback = menuCallback;
 
     /*
+     * Initialize the entries list
+     */
+    fgListInit( &menu->Entries );
+
+    /*
      * Add it to the menu structure hierarchy
      */
-    fgStructure.Menus = g_list_append( fgStructure.Menus, menu );
+    fgListAppend( &fgStructure.Menus, &menu->Node );
 
     /*
      * Newly created menus implicitly become current ones
@@ -150,105 +160,151 @@ SFG_Menu* fgCreateMenu( FGCBmenu menuCallback )
 }
 
 /*
- * This function destroys a window and all of it's subwindows. Actually,
+ * Linked list of windows to destroy ... this is so we don't destroy a window from the middle of
+ * its callback.  Some C compilers take an extremely dim view of this.
+ */
+
+static SFG_WindowList* WindowsToDestroy = (SFG_WindowList*)NULL ;
+
+/*
+ * Function to add a window to the linked list of windows to destroy.  Subwindows are automatically
+ * added because they hang from the window structure.
+ */
+void fgAddToWindowDestroyList ( SFG_Window* window, GLboolean needToClose )
+{
+  SFG_WindowList *new_list_entry = (SFG_WindowList*)malloc ( sizeof(SFG_WindowList) ) ;
+  new_list_entry->window = window ;
+  new_list_entry->needToClose = needToClose ;
+  new_list_entry->next = WindowsToDestroy ;
+  WindowsToDestroy = new_list_entry ;
+
+  /*
+   * Check if the window is the current one...
+   */
+  if ( fgStructure.Window == window )
+    fgStructure.Window = NULL;
+
+  /*
+   * If the destroyed window has the highest window ID number, decrement the window ID number
+   */
+  if ( window->ID == fgStructure.WindowID ) fgStructure.WindowID-- ;
+
+  /*
+   * Check the execution state.  If this has been called from "glutDestroyWindow",
+   * a statement in that function will reset the "ExecState" after this function returns.
+   */
+  if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
+  {
+    /*
+     * Set the execution state flag to drop out of the main loop.
+     */
+    if ( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
+      fgState.ExecState = GLUT_EXEC_STATE_STOP ;
+  }
+}
+
+/*
+ * Function to close down all the windows in the "WindowsToDestroy" list
+ */
+void fgCloseWindows ()
+{
+  SFG_WindowList *window_ptr = WindowsToDestroy ;
+  WindowsToDestroy = (SFG_WindowList*)NULL ;  /* In case the destroy callbacks cause more windows to be closed */
+
+  while ( window_ptr )
+  {
+    SFG_WindowList *next = window_ptr->next ;
+    fgDestroyWindow ( window_ptr->window, window_ptr->needToClose ) ;
+    free ( window_ptr ) ;
+    window_ptr = next ;
+
+    if ( !window_ptr )
+    {
+      window_ptr = WindowsToDestroy ;
+      WindowsToDestroy = (SFG_WindowList*)NULL ;
+    }
+  }
+}
+
+/*
+ * This function destroys a window and all of its subwindows. Actually,
  * another function, defined in freeglut_window.c is called, but this is
  * a whole different story...
  */
-void fgDestroyWindow( SFG_Window* window, gboolean needToClose )
+void fgDestroyWindow( SFG_Window* window, GLboolean needToClose )
 {
-    int i;
+    SFG_Window* subWindow;
 
-    g_assert( window != NULL );
+    assert( window != NULL );
     freeglut_assert_ready;
 
     /*
      * Does this window have any subwindows?
      */
-    if( window->Children != NULL )
+    while ( (subWindow = window->Children.First) != NULL )
     {
         /*
-         * OKi, while there are any subwindows left...
+         * Destroy the first window in the list (possibly destroying
+         * its subwindows too). This is not very effective, but works
          */
-        while( g_list_first( window->Children ) != NULL )
-        {
-            SFG_Window* subWindow = g_list_first( window->Children )->data;
-
-            /*
-             * Destroy the first window in the list (possibly destroying
-             * it's subwindows too. This is not very effective, but works
-             */
-            fgDestroyWindow( subWindow, TRUE );
-
-            /*
-             * Remove the just destroyed node from the subwindows list
-             */
-            window->Children = g_list_remove( window->Children, subWindow );
-        }
-
-        /*
-         * Have the list freed now (probably it already is, but you can
-         * never be sure with no GLib documentation on your hdd...)
-         */
-        g_list_free( window->Children );
-        window->Children = NULL;
+        fgDestroyWindow( subWindow, needToClose );
     }
 
     /*
-     * Now we should remove the reference to this window from it's parent
-     */
-    if( window->Parent != NULL )
-        window->Parent->Children = g_list_remove( window->Parent->Children, window );
-
-    /*
-     * OK, this window seems disconnected from the structure enough
-     * in order to be closed without any bigger risks...
+     * If the programmer defined a destroy callback, call it
      */
-       if( needToClose == TRUE )
-               fgCloseWindow( window );
+    if ( window->Callbacks.Destroy != NULL )
+      window->Callbacks.Destroy () ;
 
     /*
-     * Try removing the window from the parents list in fgStructure.
-     * This might fail as the window is not guaranteed to be there:
+     * Now we should remove the reference to this window from its parent
      */
-    fgStructure.Windows = g_list_remove( fgStructure.Windows, window );
+    if ( window->Parent != NULL )
+        fgListRemove( &window->Parent->Children, &window->Node );
+    else
+        fgListRemove( &fgStructure.Windows, &window->Node );
 
     /*
-     * Check if the window is the current one...
+     * OK, this window seems disconnected from the structure enough
+     * in order to be closed without any bigger risks...
      */
-    if( fgStructure.Window == window )
-        fgStructure.Window = NULL;
+    if( needToClose == TRUE )
+        fgCloseWindow( window );
 
     /*
      * Finally, we can delete the window's object. It hopefully does
      * have everything inside it freed and we do not have to care...
      */
-    g_free( window );
+    free( window );
 }
 
 /*
- * This is a helper static function that removes a menu (given it's pointer)
+ * This is a helper static function that removes a menu (given its pointer)
  * from any windows that can be accessed from a given parent...
  */
 static void fghRemoveMenuFromWindow( SFG_Window* window, SFG_Menu* menu )
 {
-    gint i;
+    SFG_Window *subWindow;
+    int i;
 
     /*
      * Check if the menu is attached to the current window,
      * if so, have it detached (by overwriting with a NULL):
      */
     for( i=0; i<3; i++ )
+    {
         if( window->Menu[ i ] == menu )
             window->Menu[ i ] = NULL;
+    }
 
     /*
      * Call this function for all of the window's children recursively:
      */
-    for( i=0; i<(gint) g_list_length( window->Children ); i++ )
-        fghRemoveMenuFromWindow(
-            (SFG_Window *) g_list_nth( window->Children, i )->data,
-            menu
-        );
+    for( subWindow = window->Children.First; subWindow;
+         subWindow = subWindow->Node.Next)
+    {
+        fghRemoveMenuFromWindow( subWindow, menu );
+    }
 }
 
 /*
@@ -257,49 +313,15 @@ static void fghRemoveMenuFromWindow( SFG_Window* window, SFG_Menu* menu )
  */
 static void fghRemoveMenuFromMenu( SFG_Menu* from, SFG_Menu* menu )
 {
-    gboolean found = FALSE;
+  SFG_MenuEntry *entry;
 
-    /*
-     * Do not allow removing a menu from itself...
-     */
-    if( from == menu )
-        return;
-
-    /*
-     * Look up for the first entry that matches the given
-     * menu and have it removed, then search again and again:
-     */
-    do
+  for( entry = from->Entries.First; entry; entry = entry->Node.Next )
+  {
+    if (entry->SubMenu == menu)
     {
-        /*
-         * Try searching for the incriminated menu entry
-         */
-        GList* where = g_list_find( from->Entries, menu );
-
-        /*
-         * Make sure we still have a list to be searched
-         */
-        if( where != NULL )
-        {
-            /*
-             * Did we actually find the menu entry we want to remove?
-             */
-            found = ((SFG_Menu *) where->data == menu);
-
-            /*
-             * Need to check that, as the search might have failed
-             */
-            if( found )
-                from->Entries = g_list_remove( from->Entries, menu );
-        }
-        else
-        {
-            /*
-             * It would be nice if we had a stop rule ;-)
-             */
-            found = FALSE;
-        }
-    } while( found == TRUE );
+      entry->SubMenu = NULL;
+    }
+  }
 }
 
 /*
@@ -308,69 +330,63 @@ static void fghRemoveMenuFromMenu( SFG_Menu* from, SFG_Menu* menu )
  */
 void fgDestroyMenu( SFG_Menu* menu )
 {
-    gint i;
-
-    g_assert( menu != NULL );
-    freeglut_assert_ready;
-
-    /*
-     * First of all, have all references to this menu removed from all windows:
-     */
-    for( i=0; i<(gint) g_list_length( fgStructure.Windows ); i++ )
-        fghRemoveMenuFromWindow(
-            (SFG_Window *) g_list_nth( fgStructure.Windows, i )->data,
-            menu
-        );
-
-    /*
-     * Now proceed with removing menu entries that lead to this menu
-     */
-    for( i=0; i<(gint) g_list_length( fgStructure.Menus ); i++ )
-        fghRemoveMenuFromMenu(
-            (SFG_Menu *) g_list_nth( fgStructure.Menus, i )->data,
-            menu
-        );
-
-    /*
-     * Now we are pretty sure the menu is not used anywhere
-     * and that we can remove all of it's entries
-     */
-    for( i=0; i<(gint) g_list_length( menu->Entries ); i++ )
-    {
-        SFG_MenuEntry* entry = (SFG_MenuEntry *) g_list_nth( menu->Entries, i )->data;
-
-        /*
-         * There might be a string allocated, have it freed:
-         */
-        g_string_free( entry->Text, TRUE );
-
-        /*
-         * Deallocate the entry itself:
-         */
-        g_free( entry );
-    }
-
-    /*
-     * Deallocate the entries list
-     */
-    g_list_free( menu->Entries );
-    menu->Entries = NULL;
-
-    /*
-     * Remove the menu from the menus list
-     */
-    fgStructure.Menus = g_list_remove( fgStructure.Menus, menu );
-
-    /*
-     * If that menu was the current one...
-     */
-    if( fgStructure.Menu == menu )
-        fgStructure.Menu = NULL;
-
-    /*
-     * Have the menu structure freed
-     */
-    g_free( menu );
+  SFG_Window *window;
+  SFG_Menu *from;
+  SFG_MenuEntry *entry;
+
+  assert( menu != NULL );
+  freeglut_assert_ready;
+
+  /*
+   * First of all, have all references to this menu removed from all windows:
+   */
+  for( window = fgStructure.Windows.First; window; window = window->Node.Next )
+  {
+    fghRemoveMenuFromWindow( window, menu );
+  }
+
+  /*
+   * Now proceed with removing menu entries that lead to this menu
+   */
+  for( from = fgStructure.Menus.First; from; from = from->Node.Next )
+  {
+    fghRemoveMenuFromMenu( from, menu );
+  }
+
+  /*
+   * Now we are pretty sure the menu is not used anywhere
+   * and that we can remove all of its entries
+   */
+  while( (entry = menu->Entries.First) != NULL )
+  {
+    fgListRemove(&menu->Entries, &entry->Node);
+
+    /*
+     * There might be a string allocated, have it freed:
+     */
+    free( entry->Text );
+
+    /*
+     * Deallocate the entry itself:
+     */
+    free( entry );
+  }
+
+  /*
+   * Remove the menu from the menus list
+   */
+  fgListRemove( &fgStructure.Menus, &menu->Node );
+
+  /*
+   * If that menu was the current one...
+   */
+  if( fgStructure.Menu == menu )
+    fgStructure.Menu = NULL;
+
+  /*
+   * Have the menu structure freed
+   */
+  free( menu );
 }
 
 /*
@@ -381,12 +397,14 @@ void fgDestroyMenu( SFG_Menu* menu )
  */
 void fgCreateStructure( void )
 {
-    /*
-     * We will be needing two lists: the first containing windows, and the second
-        * containing the user-defined menus. However we do not need allocating anything, 
-        * as it is done automagically by GLib when appending new entries to both of them. 
-        * Also, no current window/menu is set, as none has been created yet.
-     */
+  /*
+   * We will be needing two lists: the first containing windows,
+   * and the second containing the user-defined menus.
+   * Also, no current window/menu is set, as none has been created yet.
+   */
+
+  fgListInit(&fgStructure.Windows);
+  fgListInit(&fgStructure.Menus);
 }
 
 /*
@@ -395,86 +413,90 @@ void fgCreateStructure( void )
  */
 void fgDestroyStructure( void )
 {
-       /*
-        * Just make sure we are not called in vain...
-        */
-    freeglut_assert_ready;
-
-    /*
-     * Make sure all windows and menus have been deallocated
-     */
-    while( fgStructure.Windows != NULL )
-        fgDestroyWindow( (SFG_Window *) g_list_first( fgStructure.Windows )->data, TRUE );
-
-    while( fgStructure.Menus != NULL )
-        fgDestroyMenu( (SFG_Menu *) g_list_first( fgStructure.Menus )->data );
+  SFG_Window *window;
+  SFG_Menu *menu;
+
+  /*
+   * Just make sure we are not called in vain...
+   */
+  freeglut_assert_ready;
+
+  /*
+   * Make sure all windows and menus have been deallocated
+   */
+  while( (window = fgStructure.Windows.First) != NULL )
+    fgDestroyWindow( window, TRUE );
+
+  while( (menu = fgStructure.Menus.First) != NULL )
+    fgDestroyMenu( menu );
 }
 
 /*
  * Helper function to enumerate through all registered top-level windows
  */
-void fgEnumWindows( GFunc enumCallback, SFG_Enumerator* enumerator )
+void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator )
 {
-    gint i;
+  SFG_Window *window;
 
-    g_assert( (enumCallback != NULL) && (enumerator != NULL) );
-    freeglut_assert_ready;
+  assert( (enumCallback != NULL) && (enumerator != NULL) );
+  freeglut_assert_ready;
 
+  /*
+   * Check every of the top-level windows
+   */
+  for( window = fgStructure.Windows.First; window;
+       window = window->Node.Next )
+  {
     /*
-     * Check every of the top-level windows
+     * Execute the callback...
      */
-    for( i=0; i<(gint) g_list_length( fgStructure.Windows ); i++ )
-    {
-        /*
-         * Execute the callback...
-         */
-        enumCallback( (gpointer) g_list_nth( fgStructure.Windows, i )->data, (gpointer) enumerator );
+    enumCallback( window, enumerator );
 
-        /*
-         * If it has been marked as 'found', stop searching
-         */
-        if( enumerator->found == TRUE )
-            return;
-    }
+    /*
+     * If it has been marked as 'found', stop searching
+     */
+    if( enumerator->found == TRUE )
+      return;
+  }
 }
 
 /*
  * Helper function to enumerate through all a window's subwindows (single level descent)
  */
-void fgEnumSubWindows( SFG_Window* window, GFunc enumCallback, SFG_Enumerator* enumerator )
+void fgEnumSubWindows( SFG_Window* window, FGCBenumerator enumCallback, SFG_Enumerator* enumerator )
 {
-    gint i;
+  SFG_Window *child;
 
-    g_assert( (enumCallback != NULL) && (enumerator != NULL) );
-    freeglut_assert_ready;
+  assert( (enumCallback != NULL) && (enumerator != NULL) );
+  freeglut_assert_ready;
 
+  /*
+   * Check every of the window's children:
+   */
+  for( child = window->Children.First; child; child = child->Node.Next )
+  {
     /*
-     * Check every of the window's children:
+     * Execute the callback...
      */
-    for( i=0; i<(gint) g_list_length( window->Children ); i++ )
-    {
-        /*
-         * Execute the callback...
-         */
-        enumCallback( (gpointer) g_list_nth( window->Children, i )->data, (gpointer) enumerator );
+    enumCallback( child, enumerator );
 
-        /*
-         * If it has been marked as 'found', stop searching
-         */
-        if( enumerator->found == TRUE )
-            return;
-    }
+    /*
+     * If it has been marked as 'found', stop searching
+     */
+    if( enumerator->found == TRUE )
+      return;
+  }
 }
 
 /*
- * A static helper function to look for a window given it's handle
+ * A static helper function to look for a window given its handle
  */
-static void fghcbWindowByHandle( gpointer window, gpointer enumerator )
+static void fghcbWindowByHandle( SFG_Window *window, SFG_Enumerator *enumerator )
 {
     /*
      * Make sure we do not overwrite our precious results...
      */
-    freeglut_return_if_fail( ((SFG_Enumerator *) enumerator)->found == FALSE );
+    freeglut_return_if_fail( enumerator->found == FALSE );
 
 #if TARGET_HOST_UNIX_X11
     #define WBHANDLE (Window)
@@ -485,10 +507,10 @@ static void fghcbWindowByHandle( gpointer window, gpointer enumerator )
     /*
      * Check the window's handle. Hope this works. Looks ugly. That's for sure.
      */
-    if( ((SFG_Window *) window)->Window.Handle == (WBHANDLE ((SFG_Enumerator *) enumerator)->data) )
+    if( window->Window.Handle == WBHANDLE (enumerator->data) )
     {
-        ((SFG_Enumerator *) enumerator)->found = TRUE;
-        ((SFG_Enumerator *) enumerator)->data = (gpointer) window;
+        enumerator->found = TRUE;
+        enumerator->data = window;
 
         return;
     }
@@ -496,7 +518,7 @@ static void fghcbWindowByHandle( gpointer window, gpointer enumerator )
     /*
      * Otherwise, check this window's children
      */
-    fgEnumSubWindows( (SFG_Window *) window, fghcbWindowByHandle, enumerator );
+    fgEnumSubWindows( window, fghcbWindowByHandle, enumerator );
 
 #undef WBHANDLE
 }
@@ -519,7 +541,7 @@ SFG_Window* fgWindowByHandle
      * This is easy and makes use of the windows enumeration defined above
      */
     enumerator.found = FALSE;
-    enumerator.data = (gpointer) hWindow;
+    enumerator.data = (void *)hWindow;
 
     /*
      * Start the enumeration now:
@@ -539,22 +561,22 @@ SFG_Window* fgWindowByHandle
 }
 
 /*
- * A static helper function to look for a window given it's ID
+ * A static helper function to look for a window given its ID
  */
-static void fghcbWindowByID( gpointer window, gpointer enumerator )
+static void fghcbWindowByID( SFG_Window *window, SFG_Enumerator *enumerator )
 {
     /*
      * Make sure we do not overwrite our precious results...
      */
-    g_return_if_fail( ((SFG_Enumerator *) enumerator)->found == FALSE );
+    freeglut_return_if_fail( enumerator->found == FALSE );
 
     /*
      * Check the window's handle. Hope this works. Looks ugly. That's for sure.
      */
-    if( ((SFG_Window *) window)->ID == (gint) (((SFG_Enumerator *) enumerator)->data) )
+    if( window->ID == (int) (enumerator->data) )
     {
-        ((SFG_Enumerator *) enumerator)->found = TRUE;
-        ((SFG_Enumerator *) enumerator)->data = (gpointer) window;
+        enumerator->found = TRUE;
+        enumerator->data = window;
 
         return;
     }
@@ -562,7 +584,7 @@ static void fghcbWindowByID( gpointer window, gpointer enumerator )
     /*
      * Otherwise, check this window's children
      */
-    fgEnumSubWindows( (SFG_Window *) window, fghcbWindowByID, enumerator );
+    fgEnumSubWindows( window, fghcbWindowByID, enumerator );
 }
 
 /*
@@ -570,7 +592,7 @@ static void fghcbWindowByID( gpointer window, gpointer enumerator )
  * looking for a specified (sub)window identifier. The function
  * is defined in freeglut_structure.c file.
  */
-SFG_Window* fgWindowByID( gint windowID )
+SFG_Window* fgWindowByID( int windowID )
 {
     SFG_Enumerator enumerator;
 
@@ -578,7 +600,7 @@ SFG_Window* fgWindowByID( gint windowID )
      * Uses a method very similiar for fgWindowByHandle...
      */
     enumerator.found = FALSE;
-    enumerator.data = (gpointer) windowID;
+    enumerator.data = (void *) windowID;
 
     /*
      * Start the enumeration now:
@@ -598,27 +620,21 @@ SFG_Window* fgWindowByID( gint windowID )
 }
 
 /*
- * Looks up a menu given it's ID. This is easier that fgWindowByXXX
+ * Looks up a menu given its ID. This is easier that fgWindowByXXX
  * as all menus are placed in a single doubly linked list...
  */
-SFG_Menu* fgMenuByID( gint menuID )
+SFG_Menu* fgMenuByID( int menuID )
 {
     SFG_Menu *menu = NULL;
-    gint i;
 
     freeglut_assert_ready;
 
     /*
      * It's enough to check all entries in fgStructure.Menus...
      */
-    for( i=0; i<(gint) g_list_length( fgStructure.Menus ); i++ )
+    for( menu = fgStructure.Menus.First; menu; menu = menu->Node.Next )
     {
         /*
-         * Grab the n-th element of the menu objects list...
-         */
-        menu = (SFG_Menu *) g_list_nth( fgStructure.Menus, i )->data;
-
-        /*
          * Does the ID number match?
          */
         if( menu->ID == menuID )
@@ -631,13 +647,57 @@ SFG_Menu* fgMenuByID( gint menuID )
     return( NULL );
 }
 
-/*** END OF FILE ***/
-
+/*
+ * List functions...
+ */
+void fgListInit(SFG_List *list)
+{
+    list->First = NULL;
+    list->Last = NULL;
+}
 
+void fgListAppend(SFG_List *list, SFG_Node *node)
+{
+    SFG_Node *ln;
 
+    if ( (ln = list->Last) != NULL )
+    {
+        ln->Next = node;
+        node->Prev = ln;
+    }
+    else
+    {
+        node->Prev = NULL;
+        list->First = node;
+    }
 
+    node->Next = NULL;
+    list->Last = node;
+}
 
+void fgListRemove(SFG_List *list, SFG_Node *node)
+{
+    SFG_Node *ln;
+
+    if ( (ln = node->Next) != NULL )
+        ln->Prev = node->Prev;
+    if ( (ln = node->Prev) != NULL )
+        ln->Next = node->Next;
+    if ( (ln = list->First) == node )
+        list->First = node->Next;
+    if ( (ln = list->Last) == node )
+        list->Last = node->Prev;
+}
 
+int fgListLength(SFG_List *list)
+{
+    SFG_Node *node;
+    int length = 0;
 
+    for( node = list->First; node; node = node->Next )
+        ++length;
 
+    return( length );
+}
 
+/*** END OF FILE ***/