From 027fcf9e66356b06563140740f8d1c7bc05c9987 Mon Sep 17 00:00:00 2001 From: "John F. Fay" Date: Sun, 2 Dec 2007 03:50:29 +0000 Subject: [PATCH] Adding "glutFullScreenToggle" for X11 -- still needs implementation in Windows (e-mail by Jocelyn Frechot, Sun 11/25/2007 11:29 AM) git-svn-id: svn+ssh://svn.code.sf.net/p/freeglut/code/trunk/freeglut/freeglut@738 7f0cb862-5218-0410-a997-914c9d46530a --- include/GL/freeglut_ext.h | 7 ++ src/freeglut_display.c | 4 ++ src/freeglut_ext.c | 1 + src/freeglut_init.c | 173 +++++++++++++++++++++++++++++++++++++++++++-- src/freeglut_internal.h | 9 +++ src/freeglut_main.c | 4 ++ src/freeglut_state.c | 28 ++++++++ src/freeglut_window.c | 79 ++++++++++++++++++++- 8 files changed, 299 insertions(+), 6 deletions(-) diff --git a/include/GL/freeglut_ext.h b/include/GL/freeglut_ext.h index 384bfa1..3028994 100644 --- a/include/GL/freeglut_ext.h +++ b/include/GL/freeglut_ext.h @@ -68,6 +68,8 @@ #define GLUT_RENDERING_CONTEXT 0x01FD #define GLUT_DIRECT_RENDERING 0x01FE +#define GLUT_FULL_SCREEN 0x01FF + /* * New tokens for glutInitDisplayMode. * Only one GLUT_AUXn bit may be used at a time. @@ -89,6 +91,11 @@ FGAPI void FGAPIENTRY glutLeaveMainLoop( void ); FGAPI void FGAPIENTRY glutExit ( void ); /* + * Window management functions, see freeglut_window.c + */ +FGAPI void FGAPIENTRY glutFullScreenToggle( void ); + +/* * Window-specific callback functions, see freeglut_callbacks.c */ FGAPI void FGAPIENTRY glutMouseWheelFunc( void (* callback)( int, int, int, int ) ); diff --git a/src/freeglut_display.c b/src/freeglut_display.c index 0626981..601375b 100644 --- a/src/freeglut_display.c +++ b/src/freeglut_display.c @@ -48,6 +48,10 @@ void FGAPIENTRY glutSwapBuffers( void ) FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSwapBuffers" ); FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSwapBuffers" ); + /* + * "glXSwapBuffers" already performs an implicit call to "glFlush". What + * about "SwapBuffers"? + */ glFlush( ); if( ! fgStructure.CurrentWindow->Window.DoubleBuffered ) return; diff --git a/src/freeglut_ext.c b/src/freeglut_ext.c index b920e30..18e1c37 100644 --- a/src/freeglut_ext.c +++ b/src/freeglut_ext.c @@ -160,6 +160,7 @@ static GLUTproc fghGetProcAddress( const char* procName ) CHECK_NAME(glutCloseFunc); CHECK_NAME(glutWMCloseFunc); CHECK_NAME(glutMenuDestroyFunc); + CHECK_NAME(glutFullScreenToggle); CHECK_NAME(glutSetOption); CHECK_NAME(glutGetModeValues); CHECK_NAME(glutSetWindowData); diff --git a/src/freeglut_init.c b/src/freeglut_init.c index 054285e..d602a71 100644 --- a/src/freeglut_init.c +++ b/src/freeglut_init.c @@ -28,6 +28,10 @@ #include #include "freeglut_internal.h" +#if TARGET_HOST_POSIX_X11 +#include /* LONG_MAX */ +#endif + /* * TODO BEFORE THE STABLE RELEASE: * @@ -87,6 +91,144 @@ SFG_State fgState = { { -1, -1, GL_FALSE }, /* Position */ /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ +#if TARGET_HOST_POSIX_X11 + +/* Return the atom associated with "name". */ +static Atom fghGetAtom(const char * name) +{ + return XInternAtom(fgDisplay.Display, name, False); +} + +/* + * Check if "property" is set on "window". The property's values are returned + * through "data". If the property is set and is of type "type", return the + * number of elements in "data". Return zero otherwise. In both cases, use + * "Xfree()" to free "data". + */ +static int fghGetWindowProperty(Window window, + Atom property, + Atom type, + unsigned char ** data) +{ + /* + * Caller always has to use "Xfree()" to free "data", since + * "XGetWindowProperty() always allocates one extra byte in prop_return + * [i.e. "data"] (even if the property is zero length) [..]". + */ + + int status; /* Returned by "XGetWindowProperty". */ + + Atom type_returned; + int temp_format; /* Not used. */ + unsigned long number_of_elements; + unsigned long temp_bytes_after; /* Not used. */ + + + status = XGetWindowProperty(fgDisplay.Display, + window, + property, + 0, + LONG_MAX, + False, + type, + &type_returned, + &temp_format, + &number_of_elements, + &temp_bytes_after, + data); + + FREEGLUT_INTERNAL_ERROR_EXIT(status == Success, + "XGetWindowProperty failled", + "fghGetWindowProperty"); + + if (type_returned != type) + { + number_of_elements = 0; + } + + return number_of_elements; +} + +/* Check if the window manager is NET WM compliant. */ +static int fghNetWMSupported(void) +{ + Atom wm_check; + Window ** window_ptr_1; + + int number_of_windows; + int net_wm_supported; + + + net_wm_supported = 0; + + wm_check = fghGetAtom("_NET_SUPPORTING_WM_CHECK"); + window_ptr_1 = malloc(sizeof(Window *)); + + /* + * Check that the window manager has set this property on the root window. + * The property must be the ID of a child window. + */ + number_of_windows = fghGetWindowProperty(fgDisplay.RootWindow, + wm_check, + XA_WINDOW, + (unsigned char **) window_ptr_1); + if (number_of_windows == 1) + { + Window ** window_ptr_2; + + window_ptr_2 = malloc(sizeof(Window *)); + + /* Check that the window has the same property set to the same value. */ + number_of_windows = fghGetWindowProperty(**window_ptr_1, + wm_check, + XA_WINDOW, + (unsigned char **) window_ptr_2); + if ((number_of_windows == 1) && (**window_ptr_1 == **window_ptr_2)) + { + /* NET WM compliant */ + net_wm_supported = 1; + } + + XFree(*window_ptr_2); + free(window_ptr_2); + } + + XFree(*window_ptr_1); + free(window_ptr_1); + + return net_wm_supported; +} + +/* Check if "hint" is present in "property" for "window". */ +int fgHintPresent(Window window, Atom property, Atom hint) +{ + Atom ** atoms_ptr; + int number_of_atoms; + int supported; + int i; + + supported = 0; + + atoms_ptr = malloc(sizeof(Atom *)); + number_of_atoms = fghGetWindowProperty(window, + property, + XA_ATOM, + (unsigned char **) atoms_ptr); + for (i = 0; i < number_of_atoms; i++) + { + if ((*atoms_ptr)[i] == hint) + { + supported = 1; + break; + } + } + + return supported; +} + +#endif /* TARGET_HOST_POSIX_X11 */ + + /* * A call to this function should initialize all the display stuff... */ @@ -129,11 +271,32 @@ static void fghInitialize( const char* displayName ) fgDisplay.Connection = ConnectionNumber( fgDisplay.Display ); /* Create the window deletion atom */ - fgDisplay.DeleteWindow = XInternAtom( - fgDisplay.Display, - "WM_DELETE_WINDOW", - FALSE - ); + fgDisplay.DeleteWindow = fghGetAtom("WM_DELETE_WINDOW"); + + /* Create the state and full screen atoms */ + fgDisplay.State = None; + fgDisplay.StateFullScreen = None; + + if (fghNetWMSupported()) + { + const Atom supported = fghGetAtom("_NET_SUPPORTED"); + const Atom state = fghGetAtom("_NET_WM_STATE"); + + /* Check if the state hint is supported. */ + if (fgHintPresent(fgDisplay.RootWindow, supported, state)) + { + const Atom full_screen = fghGetAtom("_NET_WM_STATE_FULLSCREEN"); + + fgDisplay.State = state; + + /* Check if the window manager supports full screen. */ + /** Check "_NET_WM_ALLOWED_ACTIONS" on our window instead? **/ + if (fgHintPresent(fgDisplay.RootWindow, supported, full_screen)) + { + fgDisplay.StateFullScreen = full_screen; + } + } + } #elif TARGET_HOST_MS_WINDOWS diff --git a/src/freeglut_internal.h b/src/freeglut_internal.h index 770e908..081ae9c 100644 --- a/src/freeglut_internal.h +++ b/src/freeglut_internal.h @@ -317,6 +317,8 @@ struct tagSFG_Display Window RootWindow; /* The screen's root window. */ int Connection; /* The display's connection number */ Atom DeleteWindow; /* The window deletion atom */ + Atom State; /* The state atom */ + Atom StateFullScreen; /* The full screen atom */ #ifdef X_XF86VidModeGetModeLine /* @@ -902,6 +904,13 @@ void fgListInsert(SFG_List *list, SFG_Node *next, SFG_Node *node); void fgError( const char *fmt, ... ); void fgWarning( const char *fmt, ... ); +/* + * Check if "hint" is present in "property" for "window". See freeglut_init.c + */ +#if TARGET_HOST_POSIX_X11 +int fgHintPresent(Window window, Atom property, Atom hint); +#endif + #endif /* FREEGLUT_INTERNAL_H */ /*** END OF FILE ***/ diff --git a/src/freeglut_main.c b/src/freeglut_main.c index 8aed701..10604d0 100644 --- a/src/freeglut_main.c +++ b/src/freeglut_main.c @@ -1392,6 +1392,10 @@ void FGAPIENTRY glutMainLoopEvent( void ) case ReparentNotify: break; /* XXX Should disable this event */ + /* Not handled */ + case GravityNotify: + break; + default: fgWarning ("Unknown X event type: %d\n", event.type); break; diff --git a/src/freeglut_state.c b/src/freeglut_state.c index cca7b92..cafdfb9 100644 --- a/src/freeglut_state.c +++ b/src/freeglut_state.c @@ -64,6 +64,30 @@ static int fghGetConfig( int attribute ) } #endif +/* Check if the window is in full screen state. */ +static int fghCheckFullScreen(void) +{ +#if TARGET_HOST_POSIX_X11 + + int result; + + result = 0; + if (fgDisplay.StateFullScreen != None) + { + result = fgHintPresent(fgStructure.CurrentWindow->Window.Handle, + fgDisplay.State, + fgDisplay.StateFullScreen); + } + + return result; + +#else + + return 0; + +#endif +} + /* -- INTERFACE FUNCTIONS -------------------------------------------------- */ /* @@ -512,6 +536,10 @@ int FGAPIENTRY glutGet( GLenum eWhat ) return fgState.DirectContext; break; + case GLUT_FULL_SCREEN: + return fghCheckFullScreen(); + break; + default: fgWarning( "glutGet(): missing enum handle %d", eWhat ); break; diff --git a/src/freeglut_window.c b/src/freeglut_window.c index 159b301..125c7e5 100644 --- a/src/freeglut_window.c +++ b/src/freeglut_window.c @@ -28,6 +28,10 @@ #include #include "freeglut_internal.h" +#if TARGET_HOST_POSIX_X11 +#include /* LONG_MAX */ +#endif + #if defined(_WIN32_WCE) # include # ifdef FREEGLUT_LIB_PRAGMAS @@ -250,7 +254,7 @@ GLXFBConfig* fgChooseFBConfig( void ) return fbconfig; } } -#endif +#endif /* TARGET_HOST_POSIX_X11 */ /* * Setup the pixel format for a Win32 window @@ -1218,6 +1222,12 @@ void FGAPIENTRY glutReshapeWindow( int width, int height ) FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" ); FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" ); + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before resizing. */ + glutFullScreenToggle(); + } + fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE; fgStructure.CurrentWindow->State.Width = width ; fgStructure.CurrentWindow->State.Height = height; @@ -1231,6 +1241,12 @@ void FGAPIENTRY glutPositionWindow( int x, int y ) FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" ); FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" ); + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before moving. */ + glutFullScreenToggle(); + } + #if TARGET_HOST_POSIX_X11 XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle, @@ -1313,6 +1329,12 @@ void FGAPIENTRY glutFullScreen( void ) FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" ); FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" ); + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before resizing. */ + glutFullScreenToggle(); + } + { #if TARGET_HOST_POSIX_X11 @@ -1370,6 +1392,61 @@ void FGAPIENTRY glutFullScreen( void ) } /* + * Toggle the window's full screen state. + */ +void FGAPIENTRY glutFullScreenToggle( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreenToggle" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreenToggle" ); + + { +#if TARGET_HOST_POSIX_X11 + + if (fgDisplay.StateFullScreen != None) + { + XEvent xevent; + long event_mask; + int status; + + xevent.type = ClientMessage; + xevent.xclient.type = ClientMessage; + xevent.xclient.serial = 0; + xevent.xclient.send_event = True; + xevent.xclient.display = fgDisplay.Display; + xevent.xclient.window = fgStructure.CurrentWindow->Window.Handle; + xevent.xclient.message_type = fgDisplay.State; + xevent.xclient.format = 32; + xevent.xclient.data.l[0] = 2; /* _NET_WM_STATE_TOGGLE */ + xevent.xclient.data.l[1] = fgDisplay.StateFullScreen; + xevent.xclient.data.l[2] = 0; + xevent.xclient.data.l[3] = 0; + xevent.xclient.data.l[4] = 0; + + /*** Don't really understand how event masks work... ***/ + event_mask = SubstructureRedirectMask | SubstructureNotifyMask; + + status = XSendEvent(fgDisplay.Display, + fgDisplay.RootWindow, + False, + event_mask, + &xevent); + FREEGLUT_INTERNAL_ERROR_EXIT(status != 0, + "XSendEvent failed", + "glutFullScreenToggle"); + } + else +#endif + { + /* + * If the window manager is not Net WM compliant, fall back to legacy + * behaviour. + */ + glutFullScreen(); + } + } +} + +/* * A.Donev: Set and retrieve the window's user data */ void* FGAPIENTRY glutGetWindowData( void ) -- 1.7.10.4