Adding "glutFullScreenToggle" for X11 -- still needs implementation in Windows (e-mail by Jocelyn Frechot, Sun 11/25/2007 11:29 AM)

git-svn-id: https://svn.code.sf.net/p/freeglut/code/trunk@738 7f0cb862-5218-0410-a997-914c9d46530a
This commit is contained in:
fayjf 2007-12-02 03:50:29 +00:00
parent 9d2fccf853
commit 4fddcfd08f
8 changed files with 299 additions and 6 deletions

View File

@ -68,6 +68,8 @@
#define GLUT_RENDERING_CONTEXT 0x01FD #define GLUT_RENDERING_CONTEXT 0x01FD
#define GLUT_DIRECT_RENDERING 0x01FE #define GLUT_DIRECT_RENDERING 0x01FE
#define GLUT_FULL_SCREEN 0x01FF
/* /*
* New tokens for glutInitDisplayMode. * New tokens for glutInitDisplayMode.
* Only one GLUT_AUXn bit may be used at a time. * Only one GLUT_AUXn bit may be used at a time.
@ -88,6 +90,11 @@ FGAPI void FGAPIENTRY glutMainLoopEvent( void );
FGAPI void FGAPIENTRY glutLeaveMainLoop( void ); FGAPI void FGAPIENTRY glutLeaveMainLoop( void );
FGAPI void FGAPIENTRY glutExit ( 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 * Window-specific callback functions, see freeglut_callbacks.c
*/ */

View File

@ -48,6 +48,10 @@ void FGAPIENTRY glutSwapBuffers( void )
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSwapBuffers" ); FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSwapBuffers" );
FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSwapBuffers" ); FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSwapBuffers" );
/*
* "glXSwapBuffers" already performs an implicit call to "glFlush". What
* about "SwapBuffers"?
*/
glFlush( ); glFlush( );
if( ! fgStructure.CurrentWindow->Window.DoubleBuffered ) if( ! fgStructure.CurrentWindow->Window.DoubleBuffered )
return; return;

View File

@ -160,6 +160,7 @@ static GLUTproc fghGetProcAddress( const char* procName )
CHECK_NAME(glutCloseFunc); CHECK_NAME(glutCloseFunc);
CHECK_NAME(glutWMCloseFunc); CHECK_NAME(glutWMCloseFunc);
CHECK_NAME(glutMenuDestroyFunc); CHECK_NAME(glutMenuDestroyFunc);
CHECK_NAME(glutFullScreenToggle);
CHECK_NAME(glutSetOption); CHECK_NAME(glutSetOption);
CHECK_NAME(glutGetModeValues); CHECK_NAME(glutGetModeValues);
CHECK_NAME(glutSetWindowData); CHECK_NAME(glutSetWindowData);

View File

@ -28,6 +28,10 @@
#include <GL/freeglut.h> #include <GL/freeglut.h>
#include "freeglut_internal.h" #include "freeglut_internal.h"
#if TARGET_HOST_POSIX_X11
#include <limits.h> /* LONG_MAX */
#endif
/* /*
* TODO BEFORE THE STABLE RELEASE: * TODO BEFORE THE STABLE RELEASE:
* *
@ -87,6 +91,144 @@ SFG_State fgState = { { -1, -1, GL_FALSE }, /* Position */
/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ /* -- 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... * 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 ); fgDisplay.Connection = ConnectionNumber( fgDisplay.Display );
/* Create the window deletion atom */ /* Create the window deletion atom */
fgDisplay.DeleteWindow = XInternAtom( fgDisplay.DeleteWindow = fghGetAtom("WM_DELETE_WINDOW");
fgDisplay.Display,
"WM_DELETE_WINDOW", /* Create the state and full screen atoms */
FALSE 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 #elif TARGET_HOST_MS_WINDOWS

View File

@ -317,6 +317,8 @@ struct tagSFG_Display
Window RootWindow; /* The screen's root window. */ Window RootWindow; /* The screen's root window. */
int Connection; /* The display's connection number */ int Connection; /* The display's connection number */
Atom DeleteWindow; /* The window deletion atom */ Atom DeleteWindow; /* The window deletion atom */
Atom State; /* The state atom */
Atom StateFullScreen; /* The full screen atom */
#ifdef X_XF86VidModeGetModeLine #ifdef X_XF86VidModeGetModeLine
/* /*
@ -902,6 +904,13 @@ void fgListInsert(SFG_List *list, SFG_Node *next, SFG_Node *node);
void fgError( const char *fmt, ... ); void fgError( const char *fmt, ... );
void fgWarning( 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 */ #endif /* FREEGLUT_INTERNAL_H */
/*** END OF FILE ***/ /*** END OF FILE ***/

View File

@ -1392,6 +1392,10 @@ void FGAPIENTRY glutMainLoopEvent( void )
case ReparentNotify: case ReparentNotify:
break; /* XXX Should disable this event */ break; /* XXX Should disable this event */
/* Not handled */
case GravityNotify:
break;
default: default:
fgWarning ("Unknown X event type: %d\n", event.type); fgWarning ("Unknown X event type: %d\n", event.type);
break; break;

View File

@ -64,6 +64,30 @@ static int fghGetConfig( int attribute )
} }
#endif #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 -------------------------------------------------- */ /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
/* /*
@ -512,6 +536,10 @@ int FGAPIENTRY glutGet( GLenum eWhat )
return fgState.DirectContext; return fgState.DirectContext;
break; break;
case GLUT_FULL_SCREEN:
return fghCheckFullScreen();
break;
default: default:
fgWarning( "glutGet(): missing enum handle %d", eWhat ); fgWarning( "glutGet(): missing enum handle %d", eWhat );
break; break;

View File

@ -28,6 +28,10 @@
#include <GL/freeglut.h> #include <GL/freeglut.h>
#include "freeglut_internal.h" #include "freeglut_internal.h"
#if TARGET_HOST_POSIX_X11
#include <limits.h> /* LONG_MAX */
#endif
#if defined(_WIN32_WCE) #if defined(_WIN32_WCE)
# include <Aygshell.h> # include <Aygshell.h>
# ifdef FREEGLUT_LIB_PRAGMAS # ifdef FREEGLUT_LIB_PRAGMAS
@ -250,7 +254,7 @@ GLXFBConfig* fgChooseFBConfig( void )
return fbconfig; return fbconfig;
} }
} }
#endif #endif /* TARGET_HOST_POSIX_X11 */
/* /*
* Setup the pixel format for a Win32 window * 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_NOT_INITIALISED ( "glutReshapeWindow" );
FREEGLUT_EXIT_IF_NO_WINDOW ( "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.NeedToResize = GL_TRUE;
fgStructure.CurrentWindow->State.Width = width ; fgStructure.CurrentWindow->State.Width = width ;
fgStructure.CurrentWindow->State.Height = height; 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_NOT_INITIALISED ( "glutPositionWindow" );
FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" ); FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" );
if (glutGet(GLUT_FULL_SCREEN))
{
/* Leave full screen state before moving. */
glutFullScreenToggle();
}
#if TARGET_HOST_POSIX_X11 #if TARGET_HOST_POSIX_X11
XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle, XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle,
@ -1313,6 +1329,12 @@ void FGAPIENTRY glutFullScreen( void )
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" ); FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" );
FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" ); FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" );
if (glutGet(GLUT_FULL_SCREEN))
{
/* Leave full screen state before resizing. */
glutFullScreenToggle();
}
{ {
#if TARGET_HOST_POSIX_X11 #if TARGET_HOST_POSIX_X11
@ -1369,6 +1391,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 * A.Donev: Set and retrieve the window's user data
*/ */