#define G_LOG_DOMAIN "freeglut-structure"
#include "../include/GL/freeglut.h"
-#include "../include/GL/freeglut_internal.h"
+#include "freeglut_internal.h"
/* -- GLOBAL EXPORTS ------------------------------------------------------- */
*
* 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 );
/*
window->ID = ++fgStructure.WindowID;
/*
+ * Initialize the children list
+ */
+ fgListInit( &window->Children );
+
+ /*
* Does this window have a parent?
*/
if( parent != NULL )
/*
* 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
/*
* Otherwise add the newly created window to the topmost windows list
*/
- fgStructure.Windows = g_list_append( fgStructure.Windows, window );
+ fgListAppend( &fgStructure.Windows, &window->Node );
}
/*
* 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
/*
* 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 );
/*
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
}
/*
- * 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 );
+ }
}
/*
*/
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;
+ }
+ }
}
/*
*/
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 );
}
/*
*/
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);
}
/*
*/
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)
/*
* 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;
}
/*
* Otherwise, check this window's children
*/
- fgEnumSubWindows( (SFG_Window *) window, fghcbWindowByHandle, enumerator );
+ fgEnumSubWindows( window, fghcbWindowByHandle, enumerator );
#undef WBHANDLE
}
* 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:
}
/*
- * 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;
}
/*
* Otherwise, check this window's children
*/
- fgEnumSubWindows( (SFG_Window *) window, fghcbWindowByID, enumerator );
+ fgEnumSubWindows( window, fghcbWindowByID, 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;
* Uses a method very similiar for fgWindowByHandle...
*/
enumerator.found = FALSE;
- enumerator.data = (gpointer) windowID;
+ enumerator.data = (void *) windowID;
/*
* Start the enumeration now:
}
/*
- * 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 )
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 ***/