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:
parent
9d2fccf853
commit
4fddcfd08f
@ -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
|
||||||
*/
|
*/
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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 ***/
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user