2 * freeglut_window_x11.c
4 * Window management methods for X11
6 * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7 * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8 * Copied for Platform code by Evan Felix <karcaw at gmail.com>
9 * Creation date: Thur Feb 2 2012
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
25 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 #define FREEGLUT_BUILDING_LIB
30 #include <GL/freeglut.h>
31 #include <limits.h> /* LONG_MAX */
32 #include <unistd.h> /* usleep */
33 #include "../fg_internal.h"
35 extern void fghRedrawWindow(SFG_Window *window);
37 #ifdef EGL_VERSION_1_0
38 #include "egl/fg_window_egl.h"
39 #define fghCreateNewContext fghCreateNewContextEGL
41 #include "x11/fg_window_x11_glx.h"
44 static int fghResizeFullscrToggle(void)
46 XWindowAttributes attributes;
48 if(glutGet(GLUT_FULL_SCREEN)) {
49 /* restore original window size */
50 SFG_Window *win = fgStructure.CurrentWindow;
51 fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE;
52 fgStructure.CurrentWindow->State.Width = win->State.pWState.OldWidth;
53 fgStructure.CurrentWindow->State.Height = win->State.pWState.OldHeight;
56 /* resize the window to cover the entire screen */
57 XGetWindowAttributes(fgDisplay.pDisplay.Display,
58 fgStructure.CurrentWindow->Window.Handle,
62 * The "x" and "y" members of "attributes" are the window's coordinates
63 * relative to its parent, i.e. to the decoration window.
65 XMoveResizeWindow(fgDisplay.pDisplay.Display,
66 fgStructure.CurrentWindow->Window.Handle,
69 fgDisplay.ScreenWidth,
70 fgDisplay.ScreenHeight);
75 #define _NET_WM_STATE_TOGGLE 2
76 static int fghEwmhFullscrToggle(void)
79 long evmask = SubstructureRedirectMask | SubstructureNotifyMask;
81 if(!fgDisplay.pDisplay.State || !fgDisplay.pDisplay.StateFullScreen) {
85 xev.type = ClientMessage;
86 xev.xclient.window = fgStructure.CurrentWindow->Window.Handle;
87 xev.xclient.message_type = fgDisplay.pDisplay.State;
88 xev.xclient.format = 32;
89 xev.xclient.data.l[0] = _NET_WM_STATE_TOGGLE;
90 xev.xclient.data.l[1] = fgDisplay.pDisplay.StateFullScreen;
91 xev.xclient.data.l[2] = 0; /* no second property to toggle */
92 xev.xclient.data.l[3] = 1; /* source indication: application */
93 xev.xclient.data.l[4] = 0; /* unused */
95 if(!XSendEvent(fgDisplay.pDisplay.Display, fgDisplay.pDisplay.RootWindow, 0, evmask, &xev)) {
101 static int fghToggleFullscreen(void)
103 /* first try the EWMH (_NET_WM_STATE) method ... */
104 if(fghEwmhFullscrToggle() != -1) {
108 /* fall back to resizing the window */
109 if(fghResizeFullscrToggle() != -1) {
115 static Bool fghWindowIsVisible( Display *display, XEvent *event, XPointer arg)
117 Window window = (Window)arg;
118 return (event->type == MapNotify) && (event->xmap.window == window);
122 * Opens a window. Requires a SFG_Window object created and attached
123 * to the freeglut structure. OpenGL context is created here.
125 void fgPlatformOpenWindow( SFG_Window* window, const char* title,
126 GLboolean positionUse, int x, int y,
127 GLboolean sizeUse, int w, int h,
128 GLboolean gameMode, GLboolean isSubWindow )
130 XVisualInfo * visualInfo = NULL;
131 XSetWindowAttributes winAttr;
132 XTextProperty textProperty;
133 XSizeHints sizeHints;
135 XEvent eventReturnBuffer; /* return buffer required for a call */
137 unsigned int current_DisplayMode = fgState.DisplayMode ;
138 XConfigureEvent fakeEvent = {0};
140 /* Save the display mode if we are creating a menu window */
141 if( window->IsMenu && ( ! fgStructure.MenuContext ) )
142 fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB ;
144 #ifdef EGL_VERSION_1_0
145 #define WINDOW_CONFIG window->Window.pContext.egl.Config
147 #define WINDOW_CONFIG window->Window.pContext.FBConfig
149 fghChooseConfig(&WINDOW_CONFIG);
151 if( window->IsMenu && ( ! fgStructure.MenuContext ) )
152 fgState.DisplayMode = current_DisplayMode ;
154 if( ! WINDOW_CONFIG )
157 * The "fghChooseConfig" returned a null meaning that the visual
158 * context is not available.
159 * Try a couple of variations to see if they will work.
161 #ifndef EGL_VERSION_1_0
162 if( !( fgState.DisplayMode & GLUT_DOUBLE ) )
164 fgState.DisplayMode |= GLUT_DOUBLE ;
165 fghChooseConfig(&WINDOW_CONFIG);
166 fgState.DisplayMode &= ~GLUT_DOUBLE;
170 if( fgState.DisplayMode & GLUT_MULTISAMPLE )
172 fgState.DisplayMode &= ~GLUT_MULTISAMPLE ;
173 fghChooseConfig(&WINDOW_CONFIG);
174 fgState.DisplayMode |= GLUT_MULTISAMPLE;
178 FREEGLUT_INTERNAL_ERROR_EXIT( WINDOW_CONFIG != NULL,
179 "FBConfig with necessary capabilities not found", "fgOpenWindow" );
181 /* Get the X visual. */
182 #ifdef EGL_VERSION_1_0
184 XVisualInfo visualTemplate;
186 if (!eglGetConfigAttrib(fgDisplay.pDisplay.egl.Display, window->Window.pContext.egl.Config, EGL_NATIVE_VISUAL_ID, &vid))
187 fgError("eglGetConfigAttrib(EGL_NATIVE_VISUAL_ID) failed");
188 visualTemplate.visualid = vid;
189 visualInfo = XGetVisualInfo(fgDisplay.pDisplay.Display, VisualIDMask, &visualTemplate, &num_visuals);
191 visualInfo = glXGetVisualFromFBConfig( fgDisplay.pDisplay.Display,
192 window->Window.pContext.FBConfig );
195 FREEGLUT_INTERNAL_ERROR_EXIT( visualInfo != NULL,
196 "visualInfo could not be retrieved from FBConfig", "fgOpenWindow" );
199 * XXX HINT: the masks should be updated when adding/removing callbacks.
200 * XXX This might speed up message processing. Is that true?
202 * XXX A: Not appreciably, but it WILL make it easier to debug.
203 * XXX Try tracing old GLUT and try tracing freeglut. Old GLUT
204 * XXX turns off events that it doesn't need and is a whole lot
205 * XXX more pleasant to trace. (Think mouse-motion! Tons of
206 * XXX ``bonus'' GUI events stream in.)
209 StructureNotifyMask | SubstructureNotifyMask | ExposureMask |
210 ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
211 VisibilityChangeMask | EnterWindowMask | LeaveWindowMask |
212 PointerMotionMask | ButtonMotionMask;
213 winAttr.background_pixmap = None;
214 winAttr.background_pixel = 0;
215 winAttr.border_pixel = 0;
217 winAttr.colormap = XCreateColormap(
218 fgDisplay.pDisplay.Display, fgDisplay.pDisplay.RootWindow,
219 visualInfo->visual, AllocNone
222 mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
224 if( window->IsMenu || ( gameMode == GL_TRUE ) )
226 winAttr.override_redirect = True;
227 mask |= CWOverrideRedirect;
231 x = y = -1; /* default window position */
233 w = h = 300; /* default window size */
235 window->Window.Handle = XCreateWindow(
236 fgDisplay.pDisplay.Display,
237 window->Parent == NULL ? fgDisplay.pDisplay.RootWindow :
238 window->Parent->Window.Handle,
240 visualInfo->depth, InputOutput,
241 visualInfo->visual, mask,
245 /* Fake configure event to force viewport setup
246 * even with no window manager.
248 fakeEvent.type = ConfigureNotify;
249 fakeEvent.display = fgDisplay.pDisplay.Display;
250 fakeEvent.window = window->Window.Handle;
254 fakeEvent.height = h;
255 XPutBackEvent(fgDisplay.pDisplay.Display, (XEvent*)&fakeEvent);
258 * The GLX context creation, possibly trying the direct context rendering
259 * or else use the current context if the user has so specified
265 * If there isn't already an OpenGL rendering context for menu
268 if( !fgStructure.MenuContext )
270 fgStructure.MenuContext =
271 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
272 fgStructure.MenuContext->MContext = fghCreateNewContext( window );
275 /* window->Window.Context = fgStructure.MenuContext->MContext; */
276 window->Window.Context = fghCreateNewContext( window );
278 else if( fgState.UseCurrentContext )
281 #ifdef EGL_VERSION_1_0
282 window->Window.Context = eglGetCurrentContext( );
284 window->Window.Context = glXGetCurrentContext( );
287 if( ! window->Window.Context )
288 window->Window.Context = fghCreateNewContext( window );
291 window->Window.Context = fghCreateNewContext( window );
293 #if !defined( __FreeBSD__ ) && !defined( __NetBSD__ ) && !defined(EGL_VERSION_1_0)
294 if( !glXIsDirect( fgDisplay.pDisplay.Display, window->Window.Context ) )
296 if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT )
297 fgError( "Unable to force direct context rendering for window '%s'",
303 * XXX Assume the new window is visible by default
304 * XXX Is this a safe assumption?
306 window->State.Visible = GL_TRUE;
310 sizeHints.flags |= USPosition;
312 sizeHints.flags |= USSize;
315 * Fill in the size hints values now (the x, y, width and height
316 * settings are obsolete, are there any more WMs that support them?)
317 * Unless the X servers actually stop supporting these, we should
318 * continue to fill them in. It is *not* our place to tell the user
319 * that they should replace a window manager that they like, and which
320 * works, just because *we* think that it's not "modern" enough.
325 sizeHints.height = h;
327 wmHints.flags = StateHint;
328 wmHints.initial_state = fgState.ForceIconic ? IconicState : NormalState;
329 /* Prepare the window and iconified window names... */
330 XStringListToTextProperty( (char **) &title, 1, &textProperty );
333 fgDisplay.pDisplay.Display,
334 window->Window.Handle,
343 XFree( textProperty.value );
345 XSetWMProtocols( fgDisplay.pDisplay.Display, window->Window.Handle,
346 &fgDisplay.pDisplay.DeleteWindow, 1 );
348 #ifdef EGL_VERSION_1_0
349 fghPlatformOpenWindowEGL(window);
351 glXMakeContextCurrent(
352 fgDisplay.pDisplay.Display,
353 window->Window.Handle,
354 window->Window.Handle,
355 window->Window.Context
359 /* register extension events _before_ window is mapped */
360 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
361 fgRegisterDevices( fgDisplay.pDisplay.Display, &(window->Window.Handle) );
364 XMapWindow( fgDisplay.pDisplay.Display, window->Window.Handle );
369 XPeekIfEvent( fgDisplay.pDisplay.Display, &eventReturnBuffer, &fghWindowIsVisible, (XPointer)(window->Window.Handle) );
375 * Request a window resize
377 void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height )
379 XResizeWindow( fgDisplay.pDisplay.Display, window->Window.Handle,
381 XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */
386 * A static helper function to execute display callback for a window
388 void fgPlatformDisplayWindow ( SFG_Window *window )
390 fghRedrawWindow ( window ) ;
395 * Closes a window, destroying the frame and OpenGL context
397 void fgPlatformCloseWindow( SFG_Window* window )
399 #ifdef EGL_VERSION_1_0
400 fghPlatformCloseWindowEGL(window);
402 if( window->Window.Context )
403 glXDestroyContext( fgDisplay.pDisplay.Display, window->Window.Context );
404 window->Window.pContext.FBConfig = NULL;
407 if( window->Window.Handle ) {
408 XDestroyWindow( fgDisplay.pDisplay.Display, window->Window.Handle );
410 /* XFlush( fgDisplay.pDisplay.Display ); */ /* XXX Shouldn't need this */
415 * This function makes the current window visible
417 void fgPlatformGlutShowWindow( void )
419 XMapWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle );
420 XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */
424 * This function hides the current window
426 void fgPlatformGlutHideWindow( void )
428 if( fgStructure.CurrentWindow->Parent == NULL )
429 XWithdrawWindow( fgDisplay.pDisplay.Display,
430 fgStructure.CurrentWindow->Window.Handle,
431 fgDisplay.pDisplay.Screen );
433 XUnmapWindow( fgDisplay.pDisplay.Display,
434 fgStructure.CurrentWindow->Window.Handle );
435 XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */
439 * Iconify the current window (top-level windows only)
441 void fgPlatformGlutIconifyWindow( void )
443 XIconifyWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle,
444 fgDisplay.pDisplay.Screen );
445 XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */
449 * Set the current window's title
451 void fgPlatformGlutSetWindowTitle( const char* title )
455 text.value = (unsigned char *) title;
456 text.encoding = XA_STRING;
458 text.nitems = strlen( title );
461 fgDisplay.pDisplay.Display,
462 fgStructure.CurrentWindow->Window.Handle,
466 XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */
470 * Set the current window's iconified title
472 void fgPlatformGlutSetIconTitle( const char* title )
476 text.value = (unsigned char *) title;
477 text.encoding = XA_STRING;
479 text.nitems = strlen( title );
482 fgDisplay.pDisplay.Display,
483 fgStructure.CurrentWindow->Window.Handle,
487 XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */
491 * Change the current window's position
493 void fgPlatformGlutPositionWindow( int x, int y )
495 XMoveWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle,
497 XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */
501 * Lowers the current window (by Z order change)
503 void fgPlatformGlutPushWindow( void )
505 XLowerWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle );
509 * Raises the current window (by Z order change)
511 void fgPlatformGlutPopWindow( void )
513 XRaiseWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle );
517 * Resize the current window so that it fits the whole screen
519 void fgPlatformGlutFullScreen( SFG_Window *win )
521 if(!glutGet(GLUT_FULL_SCREEN)) {
522 if(fghToggleFullscreen() != -1) {
523 win->State.IsFullscreen = GL_TRUE;
529 * If we are fullscreen, resize the current window back to its original size
531 void fgPlatformGlutLeaveFullScreen( SFG_Window *win )
533 if(glutGet(GLUT_FULL_SCREEN)) {
534 if(fghToggleFullscreen() != -1) {
535 win->State.IsFullscreen = GL_FALSE;
541 * Toggle the window's full screen state.
543 void fgPlatformGlutFullScreenToggle( SFG_Window *win )
545 if(fghToggleFullscreen() != -1) {
546 win->State.IsFullscreen = !win->State.IsFullscreen;