#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.
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 ) );
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;
CHECK_NAME(glutCloseFunc);
CHECK_NAME(glutWMCloseFunc);
CHECK_NAME(glutMenuDestroyFunc);
+ CHECK_NAME(glutFullScreenToggle);
CHECK_NAME(glutSetOption);
CHECK_NAME(glutGetModeValues);
CHECK_NAME(glutSetWindowData);
#include <GL/freeglut.h>
#include "freeglut_internal.h"
+#if TARGET_HOST_POSIX_X11
+#include <limits.h> /* LONG_MAX */
+#endif
+
/*
* TODO BEFORE THE STABLE RELEASE:
*
/* -- 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...
*/
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
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
/*
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 ***/
case ReparentNotify:
break; /* XXX Should disable this event */
+ /* Not handled */
+ case GravityNotify:
+ break;
+
default:
fgWarning ("Unknown X event type: %d\n", event.type);
break;
}
#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 -------------------------------------------------- */
/*
return fgState.DirectContext;
break;
+ case GLUT_FULL_SCREEN:
+ return fghCheckFullScreen();
+ break;
+
default:
fgWarning( "glutGet(): missing enum handle %d", eWhat );
break;
#include <GL/freeglut.h>
#include "freeglut_internal.h"
+#if TARGET_HOST_POSIX_X11
+#include <limits.h> /* LONG_MAX */
+#endif
+
#if defined(_WIN32_WCE)
# include <Aygshell.h>
# ifdef FREEGLUT_LIB_PRAGMAS
return fbconfig;
}
}
-#endif
+#endif /* TARGET_HOST_POSIX_X11 */
/*
* Setup the pixel format for a Win32 window
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;
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,
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
}
/*
+ * 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 )