4 * Windows and menus need tree structure
6 * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7 * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8 * Creation date: Sat Dec 18 1999
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 #define G_LOG_DOMAIN "freeglut-structure"
34 #include "../include/GL/freeglut.h"
35 #include "../include/GL/freeglut_internal.h"
38 /* -- GLOBAL EXPORTS ------------------------------------------------------- */
41 * The SFG_Structure container holds information about windows and menus
42 * created between glutInit() and glutMainLoop() return.
44 SFG_Structure fgStructure;
47 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
50 * This private function creates, opens and adds to the hierarchy
51 * a freeglut window complete with OpenGL context and stuff...
53 * If parent is set to NULL, the window created will be a topmost one.
55 SFG_Window* fgCreateWindow( SFG_Window* parent, const gchar* title, gint x, gint y, gint w, gint h, gboolean gameMode )
58 * Have the window object created
60 SFG_Window* window = g_new0( SFG_Window, 1 );
64 * If the freeglut internals haven't been initialized yet,
65 * do it now. Hack's idea courtesy of Chris Purnell...
67 if( fgState.Timer == NULL )
68 glutInit( &fakeArgc, NULL );
71 * Initialize the object properties
73 window->ID = ++fgStructure.WindowID;
76 * Does this window have a parent?
81 * That's quite right, attach this windows as a child window
83 parent->Children = g_list_append( parent->Children, window );
84 window->Parent = parent;
89 * Otherwise add the newly created window to the topmost windows list
91 fgStructure.Windows = g_list_append( fgStructure.Windows, window );
95 * Set the default mouse cursor and reset the modifiers value
97 window->State.Cursor = GLUT_CURSOR_INHERIT;
98 window->State.Modifiers = 0xffffffff;
101 * Open the window now. The fgOpenWindow() function is system
102 * dependant, and resides in freeglut_window.c. Uses fgState.
104 fgOpenWindow( window, title, x, y, w, h, gameMode );
107 * Return a pointer to the newly created window
113 * This private function creates a menu and adds it to the menus list
115 SFG_Menu* fgCreateMenu( FGCBmenu menuCallback )
118 * Have the menu object created
120 SFG_Menu* menu = g_new0( SFG_Menu, 1 );
124 * If the freeglut internals haven't been initialized yet,
125 * do it now. Hack's idea courtesy of Chris Purnell...
127 if( fgState.Timer == NULL )
128 glutInit( &fakeArgc, NULL );
131 * Initialize the object properties:
133 menu->ID = ++fgStructure.MenuID;
134 menu->Callback = menuCallback;
137 * Add it to the menu structure hierarchy
139 fgStructure.Menus = g_list_append( fgStructure.Menus, menu );
142 * Newly created menus implicitly become current ones
144 fgStructure.Menu = menu;
147 * Return the result to the caller
153 * This function destroys a window and all of it's subwindows. Actually,
154 * another function, defined in freeglut_window.c is called, but this is
155 * a whole different story...
157 void fgDestroyWindow( SFG_Window* window, gboolean needToClose )
161 g_assert( window != NULL );
162 freeglut_assert_ready;
165 * Does this window have any subwindows?
167 if( window->Children != NULL )
170 * OKi, while there are any subwindows left...
172 while( g_list_first( window->Children ) != NULL )
174 SFG_Window* subWindow = g_list_first( window->Children )->data;
177 * Destroy the first window in the list (possibly destroying
178 * it's subwindows too. This is not very effective, but works
180 fgDestroyWindow( subWindow, TRUE );
183 * Remove the just destroyed node from the subwindows list
185 window->Children = g_list_remove( window->Children, subWindow );
189 * Have the list freed now (probably it already is, but you can
190 * never be sure with no GLib documentation on your hdd...)
192 g_list_free( window->Children );
193 window->Children = NULL;
197 * Now we should remove the reference to this window from it's parent
199 if( window->Parent != NULL )
200 window->Parent->Children = g_list_remove( window->Parent->Children, window );
203 * OK, this window seems disconnected from the structure enough
204 * in order to be closed without any bigger risks...
206 if( needToClose == TRUE )
207 fgCloseWindow( window );
210 * Try removing the window from the parents list in fgStructure.
211 * This might fail as the window is not guaranteed to be there:
213 fgStructure.Windows = g_list_remove( fgStructure.Windows, window );
216 * Check if the window is the current one...
218 if( fgStructure.Window == window )
219 fgStructure.Window = NULL;
222 * Finally, we can delete the window's object. It hopefully does
223 * have everything inside it freed and we do not have to care...
229 * This is a helper static function that removes a menu (given it's pointer)
230 * from any windows that can be accessed from a given parent...
232 static void fghRemoveMenuFromWindow( SFG_Window* window, SFG_Menu* menu )
237 * Check if the menu is attached to the current window,
238 * if so, have it detached (by overwriting with a NULL):
241 if( window->Menu[ i ] == menu )
242 window->Menu[ i ] = NULL;
245 * Call this function for all of the window's children recursively:
247 for( i=0; i<(gint) g_list_length( window->Children ); i++ )
248 fghRemoveMenuFromWindow(
249 (SFG_Window *) g_list_nth( window->Children, i )->data,
255 * This is a static helper function that removes menu references
256 * from another menu, given two pointers to them...
258 static void fghRemoveMenuFromMenu( SFG_Menu* from, SFG_Menu* menu )
260 gboolean found = FALSE;
263 * Do not allow removing a menu from itself...
269 * Look up for the first entry that matches the given
270 * menu and have it removed, then search again and again:
275 * Try searching for the incriminated menu entry
277 GList* where = g_list_find( from->Entries, menu );
280 * Make sure we still have a list to be searched
285 * Did we actually find the menu entry we want to remove?
287 found = ((SFG_Menu *) where->data == menu);
290 * Need to check that, as the search might have failed
293 from->Entries = g_list_remove( from->Entries, menu );
298 * It would be nice if we had a stop rule ;-)
302 } while( found == TRUE );
306 * This function destroys a menu specified by the parameter. All menus
307 * and windows are updated to make sure no ill pointers hang around.
309 void fgDestroyMenu( SFG_Menu* menu )
313 g_assert( menu != NULL );
314 freeglut_assert_ready;
317 * First of all, have all references to this menu removed from all windows:
319 for( i=0; i<(gint) g_list_length( fgStructure.Windows ); i++ )
320 fghRemoveMenuFromWindow(
321 (SFG_Window *) g_list_nth( fgStructure.Windows, i )->data,
326 * Now proceed with removing menu entries that lead to this menu
328 for( i=0; i<(gint) g_list_length( fgStructure.Menus ); i++ )
329 fghRemoveMenuFromMenu(
330 (SFG_Menu *) g_list_nth( fgStructure.Menus, i )->data,
335 * Now we are pretty sure the menu is not used anywhere
336 * and that we can remove all of it's entries
338 for( i=0; i<(gint) g_list_length( menu->Entries ); i++ )
340 SFG_MenuEntry* entry = (SFG_MenuEntry *) g_list_nth( menu->Entries, i )->data;
343 * There might be a string allocated, have it freed:
345 g_string_free( entry->Text, TRUE );
348 * Deallocate the entry itself:
354 * Deallocate the entries list
356 g_list_free( menu->Entries );
357 menu->Entries = NULL;
360 * Remove the menu from the menus list
362 fgStructure.Menus = g_list_remove( fgStructure.Menus, menu );
365 * If that menu was the current one...
367 if( fgStructure.Menu == menu )
368 fgStructure.Menu = NULL;
371 * Have the menu structure freed
377 * This function should be called on glutInit(). It will prepare the internal
378 * structure of freeglut to be used in the application. The structure will be
379 * destroyed using fgDestroyStructure() on glutMainLoop() return. In that
380 * case further use of freeglut should be preceeded with a glutInit() call.
382 void fgCreateStructure( void )
385 * We will be needing two lists: the first containing windows, and the second
386 * containing the user-defined menus. However we do not need allocating anything,
387 * as it is done automagically by GLib when appending new entries to both of them.
388 * Also, no current window/menu is set, as none has been created yet.
393 * This function is automatically called on glutMainLoop() return. It should deallocate
394 * and destroy all remnants of previous glutInit()-enforced structure initialization...
396 void fgDestroyStructure( void )
399 * Just make sure we are not called in vain...
401 freeglut_assert_ready;
404 * Make sure all windows and menus have been deallocated
406 while( fgStructure.Windows != NULL )
407 fgDestroyWindow( (SFG_Window *) g_list_first( fgStructure.Windows )->data, TRUE );
409 while( fgStructure.Menus != NULL )
410 fgDestroyMenu( (SFG_Menu *) g_list_first( fgStructure.Menus )->data );
414 * Helper function to enumerate through all registered top-level windows
416 void fgEnumWindows( GFunc enumCallback, SFG_Enumerator* enumerator )
420 g_assert( (enumCallback != NULL) && (enumerator != NULL) );
421 freeglut_assert_ready;
424 * Check every of the top-level windows
426 for( i=0; i<(gint) g_list_length( fgStructure.Windows ); i++ )
429 * Execute the callback...
431 enumCallback( (gpointer) g_list_nth( fgStructure.Windows, i )->data, (gpointer) enumerator );
434 * If it has been marked as 'found', stop searching
436 if( enumerator->found == TRUE )
442 * Helper function to enumerate through all a window's subwindows (single level descent)
444 void fgEnumSubWindows( SFG_Window* window, GFunc enumCallback, SFG_Enumerator* enumerator )
448 g_assert( (enumCallback != NULL) && (enumerator != NULL) );
449 freeglut_assert_ready;
452 * Check every of the window's children:
454 for( i=0; i<(gint) g_list_length( window->Children ); i++ )
457 * Execute the callback...
459 enumCallback( (gpointer) g_list_nth( window->Children, i )->data, (gpointer) enumerator );
462 * If it has been marked as 'found', stop searching
464 if( enumerator->found == TRUE )
470 * A static helper function to look for a window given it's handle
472 static void fghcbWindowByHandle( gpointer window, gpointer enumerator )
475 * Make sure we do not overwrite our precious results...
477 freeglut_return_if_fail( ((SFG_Enumerator *) enumerator)->found == FALSE );
479 #if TARGET_HOST_UNIX_X11
480 #define WBHANDLE (Window)
481 #elif TARGET_HOST_WIN32
482 #define WBHANDLE (HWND)
486 * Check the window's handle. Hope this works. Looks ugly. That's for sure.
488 if( ((SFG_Window *) window)->Window.Handle == (WBHANDLE ((SFG_Enumerator *) enumerator)->data) )
490 ((SFG_Enumerator *) enumerator)->found = TRUE;
491 ((SFG_Enumerator *) enumerator)->data = (gpointer) window;
497 * Otherwise, check this window's children
499 fgEnumSubWindows( (SFG_Window *) window, fghcbWindowByHandle, enumerator );
505 * fgWindowByHandle returns a (SFG_Window *) value pointing to the
506 * first window in the queue matching the specified window handle.
507 * The function is defined in freeglut_structure.c file.
509 SFG_Window* fgWindowByHandle
510 #if TARGET_HOST_UNIX_X11
512 #elif TARGET_HOST_WIN32
516 SFG_Enumerator enumerator;
519 * This is easy and makes use of the windows enumeration defined above
521 enumerator.found = FALSE;
522 enumerator.data = (gpointer) hWindow;
525 * Start the enumeration now:
527 fgEnumWindows( fghcbWindowByHandle, &enumerator );
530 * Check if the window has been found or not:
532 if( enumerator.found == TRUE )
533 return( (SFG_Window *) enumerator.data );
536 * Otherwise return NULL to mark the failure
542 * A static helper function to look for a window given it's ID
544 static void fghcbWindowByID( gpointer window, gpointer enumerator )
547 * Make sure we do not overwrite our precious results...
549 g_return_if_fail( ((SFG_Enumerator *) enumerator)->found == FALSE );
552 * Check the window's handle. Hope this works. Looks ugly. That's for sure.
554 if( ((SFG_Window *) window)->ID == (gint) (((SFG_Enumerator *) enumerator)->data) )
556 ((SFG_Enumerator *) enumerator)->found = TRUE;
557 ((SFG_Enumerator *) enumerator)->data = (gpointer) window;
563 * Otherwise, check this window's children
565 fgEnumSubWindows( (SFG_Window *) window, fghcbWindowByID, enumerator );
569 * This function is similiar to the previous one, except it is
570 * looking for a specified (sub)window identifier. The function
571 * is defined in freeglut_structure.c file.
573 SFG_Window* fgWindowByID( gint windowID )
575 SFG_Enumerator enumerator;
578 * Uses a method very similiar for fgWindowByHandle...
580 enumerator.found = FALSE;
581 enumerator.data = (gpointer) windowID;
584 * Start the enumeration now:
586 fgEnumWindows( fghcbWindowByID, &enumerator );
589 * Check if the window has been found or not:
591 if( enumerator.found == TRUE )
592 return( (SFG_Window *) enumerator.data );
595 * Otherwise return NULL to mark the failure
601 * Looks up a menu given it's ID. This is easier that fgWindowByXXX
602 * as all menus are placed in a single doubly linked list...
604 SFG_Menu* fgMenuByID( gint menuID )
606 SFG_Menu *menu = NULL;
609 freeglut_assert_ready;
612 * It's enough to check all entries in fgStructure.Menus...
614 for( i=0; i<(gint) g_list_length( fgStructure.Menus ); i++ )
617 * Grab the n-th element of the menu objects list...
619 menu = (SFG_Menu *) g_list_nth( fgStructure.Menus, i )->data;
622 * Does the ID number match?
624 if( menu->ID == menuID )
629 * We have not found the requested menu ID
634 /*** END OF FILE ***/