clear window workmask when queuing up window for destruction. All callbacks (except...
[freeglut] / src / fg_structure.c
index 1e05653..0fee95d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * freeglut_structure.c
+ * fg_structure.c
  *
  * Windows and menus need tree structure
  *
@@ -49,6 +49,7 @@ SFG_Structure fgStructure = { { NULL, NULL },  /* The list of windows       */
 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
 
 extern void fgPlatformCreateWindow ( SFG_Window *window );
+extern void fghDefaultReshape(int width, int height, FGCBUserData userData);
 
 static void fghClearCallBacks( SFG_Window *window )
 {
@@ -56,7 +57,10 @@ static void fghClearCallBacks( SFG_Window *window )
     {
         int i;
         for( i = 0; i < TOTAL_CALLBACKS; ++i )
+        {
             window->CallBacks[ i ] = NULL;
+            window->CallbackDatas[ i ] = NULL;
+        }
     }
 }
 
@@ -72,11 +76,17 @@ SFG_Window* fgCreateWindow( SFG_Window* parent, const char* title,
                             GLboolean gameMode, GLboolean isMenu )
 {
     /* Have the window object created */
-    SFG_Window *window = (SFG_Window *)calloc( sizeof(SFG_Window), 1 );
+    SFG_Window *window = (SFG_Window *)calloc( 1, sizeof(SFG_Window) );
+
+    if( !window )
+    {
+        fgError( "Out of memory. Could not create window." );
+    }
 
        fgPlatformCreateWindow ( window );
 
     fghClearCallBacks( window );
+    SET_WCB( *window, Reshape, fghDefaultReshape, NULL);
 
     /* Initialize the object properties */
     window->ID = ++fgStructure.WindowID;
@@ -90,18 +100,15 @@ SFG_Window* fgCreateWindow( SFG_Window* parent, const char* title,
     else
         fgListAppend( &fgStructure.Windows, &window->Node );
 
-    /* Set the default mouse cursor and reset the modifiers value */
+    /* Set the default mouse cursor */
     window->State.Cursor    = GLUT_CURSOR_INHERIT;
 
-    window->IsMenu = isMenu;
-
-    window->State.IgnoreKeyRepeat = GL_FALSE;
-    window->State.KeyRepeating    = GL_FALSE;
-    window->State.IsFullscreen    = GL_FALSE;
+    /* Mark window as menu if a menu is to be created */
+    window->IsMenu          = isMenu;
 
     /*
      * Open the window now. The fgOpenWindow() function is system
-     * dependant, and resides in freeglut_window.c. Uses fgState.
+     * dependent, and resides in fg_window.c. Uses fgState.
      */
     fgOpenWindow( window, title, positionUse, x, y, sizeUse, w, h, gameMode,
                   (GLboolean)(parent ? GL_TRUE : GL_FALSE) );
@@ -112,9 +119,8 @@ SFG_Window* fgCreateWindow( SFG_Window* parent, const char* title,
 /*
  * This private function creates a menu and adds it to the menus list
  */
-SFG_Menu* fgCreateMenu( FGCBMenu menuCallback )
+SFG_Menu* fgCreateMenu( FGCBMenuUC menuCallback, FGCBUserData userData )
 {
-    int x = 100, y = 100, w = 1, h = 1;
     SFG_Window *current_window = fgStructure.CurrentWindow;
 
     /* Have the menu object created */
@@ -123,19 +129,19 @@ SFG_Menu* fgCreateMenu( FGCBMenu menuCallback )
     menu->ParentWindow = NULL;
 
     /* Create a window for the menu to reside in. */
-
-    fgCreateWindow( NULL, "freeglut menu", GL_TRUE, x, y, GL_TRUE, w, h,
+    fgCreateWindow( NULL, "freeglut menu", GL_FALSE, 0, 0, GL_FALSE, 0, 0,
                     GL_FALSE, GL_TRUE );
     menu->Window = fgStructure.CurrentWindow;
     glutDisplayFunc( fgDisplayMenu );
 
-    glutHideWindow( );  /* Hide the window for now */
     fgSetWindow( current_window );
 
     /* Initialize the object properties: */
-    menu->ID       = ++fgStructure.MenuID;
-    menu->Callback = menuCallback;
-    menu->ActiveEntry = NULL;
+    menu->ID           = ++fgStructure.MenuID;
+    menu->Callback     = menuCallback;
+    menu->CallbackData = userData;
+    menu->ActiveEntry  = NULL;
+    menu->Font         = fgState.MenuFont;
 
     fgListInit( &menu->Entries );
     fgListAppend( &fgStructure.Menus, &menu->Node );
@@ -171,10 +177,16 @@ void fgAddToWindowDestroyList( SFG_Window* window )
      * to ensure that they are no longer called after this point.
      */
     {
-        FGCBDestroy destroy = (FGCBDestroy)FETCH_WCB( *window, Destroy );
+        FGCBDestroyUC destroy = (FGCBDestroyUC)FETCH_WCB( *window, Destroy );
+        FGCBUserData destroyData = FETCH_USER_DATA_WCB( *window, Destroy );
         fghClearCallBacks( window );
-        SET_WCB( *window, Destroy, destroy );
+        SET_WCB( *window, Destroy, destroy, destroyData );
     }
+
+       /*
+        * Similarly, clear all work set for the window, none of this has to be executed anymore
+        */
+       window->State.WorkMask = 0;
 }
 
 /*
@@ -193,7 +205,7 @@ void fgCloseWindows( )
 
 /*
  * This function destroys a window and all of its subwindows. Actually,
- * another function, defined in freeglut_window.c is called, but this is
+ * another function, defined in fg_window.c is called, but this is
  * a whole different story...
  */
 void fgDestroyWindow( SFG_Window* window )
@@ -300,7 +312,7 @@ void fgDestroyMenu( SFG_Menu* menu )
     {
         SFG_Menu *activeMenu=fgStructure.CurrentMenu;
         fgStructure.CurrentMenu = menu;
-        menu->Destroy( );
+        menu->Destroy( menu->DestroyData );
         fgStructure.CurrentMenu = activeMenu;
     }
 
@@ -335,7 +347,7 @@ void fgDestroyMenu( SFG_Menu* menu )
  * This function should be called on glutInit(). It will prepare the internal
  * structure of freeglut to be used in the application. The structure will be
  * destroyed using fgDestroyStructure() on glutMainLoop() return. In that
- * case further use of freeglut should be preceeded with a glutInit() call.
+ * case further use of freeglut should be preceded with a glutInit() call.
  */
 void fgCreateStructure( void )
 {
@@ -378,7 +390,7 @@ void fgDestroyStructure( void )
 /*
  * Helper function to enumerate through all registered top-level windows
  */
-void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator )
+void fgEnumWindows( FGCBWindowEnumerator enumCallback, SFG_Enumerator* enumerator )
 {
     SFG_Window *window;
 
@@ -398,10 +410,32 @@ void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator )
 }
 
 /*
+* Helper function to enumerate through all registered top-level windows
+*/
+void fgEnumMenus( FGCBMenuEnumerator enumCallback, SFG_Enumerator* enumerator )
+{
+    SFG_Menu *menu;
+
+    FREEGLUT_INTERNAL_ERROR_EXIT ( enumCallback && enumerator,
+        "Enumerator or callback missing from window enumerator call",
+        "fgEnumWindows" );
+
+    /* It's enough to check all entries in fgStructure.Menus... */
+    for( menu = (SFG_Menu *)fgStructure.Menus.First;
+        menu;
+        menu = (SFG_Menu *)menu->Node.Next )
+    {
+        enumCallback( menu, enumerator );
+        if( enumerator->found )
+            return;
+    }
+}
+
+/*
  * Helper function to enumerate through all a window's subwindows
  * (single level descent)
  */
-void fgEnumSubWindows( SFG_Window* window, FGCBenumerator enumCallback,
+void fgEnumSubWindows( SFG_Window* window, FGCBWindowEnumerator enumCallback,
                        SFG_Enumerator* enumerator )
 {
     SFG_Window *child;
@@ -446,7 +480,7 @@ static void fghcbWindowByHandle( SFG_Window *window,
 /*
  * fgWindowByHandle returns a (SFG_Window *) value pointing to the
  * first window in the queue matching the specified window handle.
- * The function is defined in freeglut_structure.c file.
+ * The function is defined in fg_structure.c file.
  */
 SFG_Window* fgWindowByHandle ( SFG_WindowHandleType hWindow )
 {
@@ -485,15 +519,15 @@ static void fghcbWindowByID( SFG_Window *window, SFG_Enumerator *enumerator )
 }
 
 /*
- * This function is similiar to the previous one, except it is
+ * This function is similar to the previous one, except it is
  * looking for a specified (sub)window identifier. The function
- * is defined in freeglut_structure.c file.
+ * is defined in fg_structure.c file.
  */
 SFG_Window* fgWindowByID( int windowID )
 {
     SFG_Enumerator enumerator;
 
-    /* Uses a method very similiar for fgWindowByHandle... */
+    /* Uses a method very similar for fgWindowByHandle... */
     enumerator.found = GL_FALSE;
     enumerator.data = ( void * )&windowID;
     fgEnumWindows( fghcbWindowByID, &enumerator );
@@ -503,19 +537,78 @@ SFG_Window* fgWindowByID( int windowID )
 }
 
 /*
- * Looks up a menu given its ID. This is easier that fgWindowByXXX
+ * A static helper function to look for a menu given its ID
+ */
+static void fghcbMenuByID( SFG_Menu *menu,
+    SFG_Enumerator *enumerator )
+{
+    if ( enumerator->found )
+        return;
+
+    /* Check the menu's ID. */
+    if( menu->ID == *( int *)(enumerator->data) )
+    {
+        enumerator->found = GL_TRUE;
+        enumerator->data = menu;
+
+        return;
+    }
+}
+
+/*
+ * Looks up a menu given its ID. This is easier than fgWindowByXXX
  * as all menus are placed in one doubly linked list...
  */
 SFG_Menu* fgMenuByID( int menuID )
 {
-    SFG_Menu *menu = NULL;
+    SFG_Enumerator enumerator;
+
+    /* This is easy and makes use of the menus enumeration defined above */
+    enumerator.found = GL_FALSE;
+    enumerator.data = (void *)&menuID;
+    fgEnumMenus( fghcbMenuByID, &enumerator );
+
+    if( enumerator.found )
+        return( SFG_Menu *) enumerator.data;
+
+    return NULL;
+}
+
+/*
+ * A static helper function to look for an active menu
+ */
+static void fghcbGetActiveMenu( SFG_Menu *menu,
+    SFG_Enumerator *enumerator )
+{
+    if ( enumerator->found )
+        return;
+
+    /* Check the menu's is active */
+    if( menu->IsActive )
+    {
+        enumerator->found = GL_TRUE;
+        enumerator->data = menu;
+
+        return;
+    }
+}
+
+/*
+ * Returns active menu, if any. Assumption: only one menu active throughout application at any one time.
+ * This is false when a submenu is also open.
+ * This is easier than fgWindowByXXX as all menus are placed in one doubly linked list...
+ */
+SFG_Menu* fgGetActiveMenu( )
+{
+    SFG_Enumerator enumerator;
+
+    /* This is easy and makes use of the menus enumeration defined above */
+    enumerator.found = GL_FALSE;
+    fgEnumMenus( fghcbGetActiveMenu, &enumerator );
+
+    if( enumerator.found )
+        return( SFG_Menu *) enumerator.data;
 
-    /* It's enough to check all entries in fgStructure.Menus... */
-    for( menu = (SFG_Menu *)fgStructure.Menus.First;
-         menu;
-         menu = (SFG_Menu *)menu->Node.Next )
-        if( menu->ID == menuID )
-            return menu;
     return NULL;
 }