2 * freeglut_window_mswin.c
4 * The Windows-specific mouse cursor related stuff.
6 * Copyright (c) 2012 Stephen J. Baker. All Rights Reserved.
7 * Written by John F. Fay, <fayjf@sourceforge.net>
8 * Creation date: Sun Jan 22, 2012
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #define FREEGLUT_BUILDING_LIB
29 #include <GL/freeglut.h>
30 #include "../fg_internal.h"
33 /* The following include file is available from SGI but is not standard:
34 * #include <GL/wglext.h>
35 * So we copy the necessary parts out of it.
36 * XXX: should local definitions for extensions be put in a separate include file?
38 typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc);
40 typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
42 #define WGL_DRAW_TO_WINDOW_ARB 0x2001
43 #define WGL_ACCELERATION_ARB 0x2003
44 #define WGL_SUPPORT_OPENGL_ARB 0x2010
45 #define WGL_DOUBLE_BUFFER_ARB 0x2011
46 #define WGL_COLOR_BITS_ARB 0x2014
47 #define WGL_ALPHA_BITS_ARB 0x201B
48 #define WGL_DEPTH_BITS_ARB 0x2022
49 #define WGL_STENCIL_BITS_ARB 0x2023
50 #define WGL_FULL_ACCELERATION_ARB 0x2027
52 #define WGL_SAMPLE_BUFFERS_ARB 0x2041
53 #define WGL_SAMPLES_ARB 0x2042
55 #define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0
57 #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9
59 #ifndef WGL_ARB_create_context
60 #define WGL_ARB_create_context 1
61 #ifdef WGL_WGLEXT_PROTOTYPES
62 extern HGLRC WINAPI wglCreateContextAttribsARB (HDC, HGLRC, const int *);
63 #endif /* WGL_WGLEXT_PROTOTYPES */
64 typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList);
66 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
67 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
68 #define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
69 #define WGL_CONTEXT_FLAGS_ARB 0x2094
70 #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
72 #define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
73 #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
75 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
76 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
78 #define ERROR_INVALID_VERSION_ARB 0x2095
79 #define ERROR_INVALID_PROFILE_ARB 0x2096
81 /* End of copying the necessary parts out of it. */
84 typedef BOOL (WINAPI *pRegisterTouchWindow)(HWND,ULONG);
85 static pRegisterTouchWindow fghRegisterTouchWindow = (pRegisterTouchWindow)0xDEADBEEF;
87 extern void fghNotifyWindowStatus(SFG_Window *window);
91 * Setup the pixel format for a Win32 window
94 #if defined(_WIN32_WCE)
95 static wchar_t* fghWstrFromStr(const char* str)
97 int i,len=strlen(str);
98 wchar_t* wstr = (wchar_t*)malloc(2*len+2);
104 #endif /* defined(_WIN32_WCE) */
107 static void fghFillContextAttributes( int *attributes ) {
108 int where = 0, contextFlags, contextProfile;
110 ATTRIB_VAL( WGL_CONTEXT_MAJOR_VERSION_ARB, fgState.MajorVersion );
111 ATTRIB_VAL( WGL_CONTEXT_MINOR_VERSION_ARB, fgState.MinorVersion );
114 fghMapBit( fgState.ContextFlags, GLUT_DEBUG, WGL_CONTEXT_DEBUG_BIT_ARB ) |
115 fghMapBit( fgState.ContextFlags, GLUT_FORWARD_COMPATIBLE, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB );
116 if ( contextFlags != 0 ) {
117 ATTRIB_VAL( WGL_CONTEXT_FLAGS_ARB, contextFlags );
121 fghMapBit( fgState.ContextProfile, GLUT_CORE_PROFILE, WGL_CONTEXT_CORE_PROFILE_BIT_ARB ) |
122 fghMapBit( fgState.ContextProfile, GLUT_COMPATIBILITY_PROFILE, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB );
123 if ( contextProfile != 0 ) {
124 ATTRIB_VAL( WGL_CONTEXT_PROFILE_MASK_ARB, contextProfile );
130 static int fghIsExtensionSupported( HDC hdc, const char *extension ) {
131 const char *pWglExtString;
132 PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetEntensionsStringARB =
133 (PFNWGLGETEXTENSIONSSTRINGARBPROC) wglGetProcAddress("wglGetExtensionsStringARB");
134 if ( wglGetEntensionsStringARB == NULL )
138 pWglExtString = wglGetEntensionsStringARB( hdc );
139 return ( pWglExtString != NULL ) && ( strstr(pWglExtString, extension) != NULL );
142 void fgNewWGLCreateContext( SFG_Window* window )
146 PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
148 /* If nothing fancy has been required, leave the context as it is */
149 if ( fghIsLegacyContextRequested() )
154 wglMakeCurrent( window->Window.pContext.Device, window->Window.Context );
156 if ( !fghIsExtensionSupported( window->Window.pContext.Device, "WGL_ARB_create_context" ) )
158 /* wglCreateContextAttribsARB not found, yet the user has requested the new context creation */
159 fgWarning( "OpenGL >2.1 context requested but wglCreateContextAttribsARB is not available! Falling back to legacy context creation" );
160 /* Legacy context already created at this point in WM_CREATE path of fgPlatformWindowProc, just return */
164 /* new context creation */
165 fghFillContextAttributes( attributes );
167 wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress( "wglCreateContextAttribsARB" );
168 if ( wglCreateContextAttribsARB == NULL )
170 /* wglCreateContextAttribsARB not found, yet the user has requested the new context creation */
171 fgWarning( "OpenGL >2.1 context requested but wglCreateContextAttribsARB is not available! Falling back to legacy context creation" );
172 /* Legacy context already created at this point in WM_CREATE path of fgPlatformWindowProc, just return */
176 context = wglCreateContextAttribsARB( window->Window.pContext.Device, 0, attributes );
177 if ( context == NULL )
179 fghContextCreationError();
182 wglMakeCurrent( NULL, NULL );
183 wglDeleteContext( window->Window.Context );
184 window->Window.Context = context;
187 #if !defined(_WIN32_WCE)
189 static void fghFillPFD( PIXELFORMATDESCRIPTOR *ppfd, HDC hdc, unsigned char layer_type )
191 int flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
192 if ( fgState.DisplayMode & GLUT_DOUBLE ) {
193 flags |= PFD_DOUBLEBUFFER;
195 if ( fgState.DisplayMode & GLUT_STEREO ) {
199 #if defined(_MSC_VER)
200 #pragma message( "fgSetupPixelFormat(): there is still some work to do here!" )
203 /* Specify which pixel format do we opt for... */
204 ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
206 ppfd->dwFlags = flags;
208 if( fgState.DisplayMode & GLUT_INDEX ) {
209 ppfd->iPixelType = PFD_TYPE_COLORINDEX;
211 ppfd->cGreenBits = 0;
213 ppfd->cAlphaBits = 0;
215 ppfd->iPixelType = PFD_TYPE_RGBA;
217 ppfd->cGreenBits = 8;
219 ppfd->cAlphaBits = ( fgState.DisplayMode & GLUT_ALPHA ) ? 8 : 0;
222 ppfd->cColorBits = 24;
224 ppfd->cGreenShift = 0;
225 ppfd->cBlueShift = 0;
226 ppfd->cAlphaShift = 0;
227 ppfd->cAccumBits = ( fgState.DisplayMode & GLUT_ACCUM ) ? 1 : 0;
228 ppfd->cAccumRedBits = 0;
229 ppfd->cAccumGreenBits = 0;
230 ppfd->cAccumBlueBits = 0;
231 ppfd->cAccumAlphaBits = 0;
233 /* Hmmm, or 32/0 instead of 24/8? */
234 ppfd->cDepthBits = 24;
235 ppfd->cStencilBits = 8;
237 ppfd->cAuxBuffers = fghNumberOfAuxBuffersRequested();
238 ppfd->iLayerType = layer_type;
240 ppfd->dwLayerMask = 0;
241 ppfd->dwVisibleMask = 0;
242 ppfd->dwDamageMask = 0;
244 ppfd->cColorBits = (BYTE) GetDeviceCaps( hdc, BITSPIXEL );
247 static void fghFillPixelFormatAttributes( int *attributes, const PIXELFORMATDESCRIPTOR *ppfd )
251 ATTRIB_VAL( WGL_DRAW_TO_WINDOW_ARB, GL_TRUE );
252 ATTRIB_VAL( WGL_SUPPORT_OPENGL_ARB, GL_TRUE );
253 ATTRIB_VAL( WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB );
255 ATTRIB_VAL( WGL_COLOR_BITS_ARB, ppfd->cColorBits );
256 ATTRIB_VAL( WGL_ALPHA_BITS_ARB, ppfd->cAlphaBits );
257 ATTRIB_VAL( WGL_DEPTH_BITS_ARB, ppfd->cDepthBits );
258 ATTRIB_VAL( WGL_STENCIL_BITS_ARB, ppfd->cStencilBits );
260 ATTRIB_VAL( WGL_DOUBLE_BUFFER_ARB, ( fgState.DisplayMode & GLUT_DOUBLE ) != 0 );
262 if ( fgState.DisplayMode & GLUT_SRGB ) {
263 ATTRIB_VAL( WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, TRUE );
266 ATTRIB_VAL( WGL_SAMPLE_BUFFERS_ARB, GL_TRUE );
267 ATTRIB_VAL( WGL_SAMPLES_ARB, fgState.SampleNumber );
272 GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
273 unsigned char layer_type )
275 #if defined(_WIN32_WCE)
278 PIXELFORMATDESCRIPTOR pfd;
279 PIXELFORMATDESCRIPTOR* ppfd = &pfd;
285 current_hDC = CreateDC(TEXT("DISPLAY"), NULL ,NULL ,NULL);
287 current_hDC = window->Window.pContext.Device;
289 fghFillPFD( ppfd, current_hDC, layer_type );
290 pixelformat = ChoosePixelFormat( current_hDC, ppfd );
292 /* windows hack for multismapling/sRGB */
293 if ( ( fgState.DisplayMode & GLUT_MULTISAMPLE ) ||
294 ( fgState.DisplayMode & GLUT_SRGB ) )
296 HGLRC rc, rc_before=wglGetCurrentContext();
298 HDC hDC, hDC_before=wglGetCurrentDC();
301 /* create a dummy window */
302 ZeroMemory(&wndCls, sizeof(wndCls));
303 wndCls.lpfnWndProc = DefWindowProc;
304 wndCls.hInstance = fgDisplay.pDisplay.Instance;
305 wndCls.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
306 wndCls.lpszClassName = _T("FREEGLUT_dummy");
307 RegisterClass( &wndCls );
309 hWnd=CreateWindow(_T("FREEGLUT_dummy"), _T(""), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW , 0,0,0,0, 0, 0, fgDisplay.pDisplay.Instance, 0 );
311 SetPixelFormat( hDC, pixelformat, ppfd );
313 rc = wglCreateContext( hDC );
314 wglMakeCurrent(hDC, rc);
316 if ( fghIsExtensionSupported( hDC, "WGL_ARB_multisample" ) )
318 PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARBProc =
319 (PFNWGLCHOOSEPIXELFORMATARBPROC) wglGetProcAddress("wglChoosePixelFormatARB");
320 if ( wglChoosePixelFormatARBProc )
325 float fAttributes[] = { 0, 0 };
327 fghFillPixelFormatAttributes( attributes, ppfd );
328 bValid = wglChoosePixelFormatARBProc(hDC, attributes, fAttributes, 1, &iPixelFormat, &numFormats);
330 if ( bValid && numFormats > 0 )
332 pixelformat = iPixelFormat;
337 wglMakeCurrent( hDC_before, rc_before);
338 wglDeleteContext(rc);
339 ReleaseDC(hWnd, hDC);
341 UnregisterClass(_T("FREEGLUT_dummy"), fgDisplay.pDisplay.Instance);
344 success = ( pixelformat != 0 ) && ( checkOnly || SetPixelFormat( current_hDC, pixelformat, ppfd ) );
347 DeleteDC(current_hDC);
350 #endif /* defined(_WIN32_WCE) */
355 void fgPlatformSetWindow ( SFG_Window *window )
357 if ( window != fgStructure.CurrentWindow )
359 if( fgStructure.CurrentWindow )
360 ReleaseDC( fgStructure.CurrentWindow->Window.Handle,
361 fgStructure.CurrentWindow->Window.pContext.Device );
365 window->Window.pContext.Device = GetDC( window->Window.Handle );
367 window->Window.pContext.Device,
368 window->Window.Context
375 void fghGetDefaultWindowStyle(DWORD *flags)
377 if ( fgState.DisplayMode & GLUT_BORDERLESS )
379 /* no window decorations needed, no-op */
381 else if ( fgState.DisplayMode & GLUT_CAPTIONLESS )
382 /* only window decoration is a border, no title bar or buttons */
383 (*flags) |= WS_DLGFRAME;
385 /* window decoration are a border, title bar and buttons. */
386 (*flags) |= WS_OVERLAPPEDWINDOW;
389 /* Get window style and extended window style of a FreeGLUT window
390 * If the window pointer or the window handle is NULL, a fully
391 * decorated window (caption and border) is assumed.
393 void fghGetStyleFromWindow( const SFG_Window *window, DWORD *windowStyle, DWORD *windowExStyle )
395 if (window && window->Window.Handle)
397 *windowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE);
398 *windowExStyle = GetWindowLong(window->Window.Handle, GWL_EXSTYLE);
403 fghGetDefaultWindowStyle(windowStyle);
404 /* WindowExStyle==0 is fine/default, exStyle is currently only used for menu windows */
410 /* Computes position of corners of window Rect (outer position including
411 * decorations) based on the provided client rect and based on the style
412 * of the window in question.
413 * If posIsOutside is set to true, the input client Rect is taken to follow
414 * freeGLUT's window specification convention in which the top-left corner
415 * is at the outside of the window, while the size
416 * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable
419 void fghComputeWindowRectFromClientArea_UseStyle( RECT *clientRect, const DWORD windowStyle, const DWORD windowExStyle, BOOL posIsOutside )
421 RECT windowRect = {0,0,0,0};
422 CopyRect(&windowRect,clientRect);
424 /* Get rect including non-client area */
425 AdjustWindowRectEx(&windowRect,windowStyle,FALSE,windowExStyle);
427 /* Move window right and down by non-client area extent on left and top, if wanted */
430 windowRect.right += clientRect->left-windowRect.left;
431 windowRect.bottom += clientRect->top -windowRect.top;
432 windowRect.left = clientRect->left;
433 windowRect.top = clientRect->top;
436 /* done, copy windowRect to output */
437 CopyRect(clientRect,&windowRect);
440 /* Computes position of corners of window Rect (outer position including
441 * decorations) based on the provided client rect and based on the style
442 * of the window in question. If the window pointer or the window handle
443 * is NULL, a fully decorated window (caption and border) is assumed.
444 * Furthermore, if posIsOutside is set to true, the input client Rect is
445 * taken to follow freeGLUT's window specification convention in which the
446 * top-left corner is at the outside of the window, while the size
447 * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable
450 void fghComputeWindowRectFromClientArea_QueryWindow( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside )
452 DWORD windowStyle = 0, windowExStyle = 0;
453 fghGetStyleFromWindow(window,&windowStyle,&windowExStyle);
455 fghComputeWindowRectFromClientArea_UseStyle(clientRect, windowStyle, windowExStyle, posIsOutside);
459 /* Gets the rect describing the client area (drawable area) of the
460 * specified window. Output is position of corners of client area (drawable area) on the screen.
461 * Does not touch clientRect if window pointer or window handle is NULL.
462 * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable area.
464 void fghGetClientArea( RECT *clientRect, const SFG_Window *window )
466 POINT topLeftClient = {0,0};
467 POINT topLeftWindow = {0,0};
469 freeglut_return_if_fail((window && window->Window.Handle));
471 /* Get size of client rect */
472 GetClientRect(window->Window.Handle, clientRect);
473 /* Get position of top-left of client area on the screen */
474 ClientToScreen(window->Window.Handle,&topLeftClient);
475 /* Add top-left offset */
476 OffsetRect(clientRect,topLeftClient.x,topLeftClient.y);
487 static BOOL CALLBACK m_proc(HMONITOR mon,
492 m_proc_t *dp=(m_proc_t *)data;
495 info.cbSize=sizeof(info);
496 res=GetMonitorInfo(mon,(LPMONITORINFO)&info);
499 if( strcmp(dp->name,info.szDevice)==0 )
501 *(dp->x)=info.rcMonitor.left;
502 *(dp->y)=info.rcMonitor.top;
510 * this function returns the origin of the screen identified by
511 * fgDisplay.pDisplay.DisplayName, and 0 otherwise.
512 * This is used in fgOpenWindow to open the gamemode window on the screen
513 * identified by the -display command line argument. The function should
514 * not be called otherwise.
517 static void get_display_origin(int *xp,int *yp)
522 if( fgDisplay.pDisplay.DisplayName )
527 st.name=fgDisplay.pDisplay.DisplayName;
528 EnumDisplayMonitors(0,0,m_proc,(LPARAM)&st);
532 #pragma message( "-display parameter only works if compiled with WINVER >= 0x0500")
534 static void get_display_origin(int *xp,int *yp)
539 if( fgDisplay.pDisplay.DisplayName )
541 fgWarning( "for working -display support FreeGLUT must be compiled with WINVER >= 0x0500");
549 * Opens a window. Requires a SFG_Window object created and attached
550 * to the freeglut structure. OpenGL context is created here.
552 void fgPlatformOpenWindow( SFG_Window* window, const char* title,
553 GLboolean positionUse, int x, int y,
554 GLboolean sizeUse, int w, int h,
555 GLboolean gameMode, GLboolean isSubWindow )
563 /* Grab the window class we have registered on glutInit(): */
564 atom = GetClassInfo( fgDisplay.pDisplay.Instance, _T("FREEGLUT"), &wc );
565 FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Info Not Found",
568 /* Determine window style flags*/
571 FREEGLUT_INTERNAL_ERROR_EXIT ( window->Parent == NULL,
572 "Game mode being invoked on a subwindow",
576 * Set the window creation flags appropriately to make the window
579 flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
583 flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
586 * There's a small difference between creating the top, child and
589 if ( window->IsMenu )
592 exFlags |= WS_EX_TOOLWINDOW;
594 #if defined(_WIN32_WCE)
595 /* no decorations for windows CE */
597 /* if this is not a subwindow (child), set its style based on the requested window decorations */
598 else if( window->Parent == NULL )
599 fghGetDefaultWindowStyle(&flags);
602 /* subwindows always have no decoration, but are marked as a child window to the OS */
606 /* determine window size and position */
609 /* if in gamemode, query the origin of specified by the -display
610 * command line parameter (if any) and offset the upper-left corner
611 * of the window so we create the window on that screen.
612 * The -display argument doesn't do anything if not trying to enter
616 get_display_origin(&xoff,&yoff);
627 if( ! window->IsMenu )
632 else /* fail safe - Windows can make a window of size (0, 0) */
633 w = h = 300; /* default window size */
635 /* store requested client area width and height */
636 window->State.Width = w;
637 window->State.Height = h;
639 #if !defined(_WIN32_WCE) /* no decorations for windows CE */
644 * Update the window dimensions, taking the window decorations
645 * into account. FreeGLUT is to create the window with the
646 * topleft outside corner at (x,y) and with client area
648 * note: don't need to do this when w=h=CW_USEDEFAULT, so in the
649 * if( sizeUse ) here is convenient.
653 windowRect.right = x+w;
654 windowRect.bottom = y+h;
656 fghComputeWindowRectFromClientArea_UseStyle(&windowRect,flags,exFlags,TRUE);
658 /* NB: w and h are now width and height of window including non-client area! */
659 w = windowRect.right - windowRect.left;
660 h = windowRect.bottom- windowRect.top;
662 #endif /* !defined(_WIN32_WCE) */
664 #if defined(_WIN32_WCE)
666 wchar_t* wstr = fghWstrFromStr(title);
668 window->Window.Handle = CreateWindow(
671 WS_VISIBLE | WS_POPUP,
675 fgDisplay.pDisplay.Instance,
681 SHFullScreen(window->Window.Handle, SHFS_HIDESTARTICON);
682 SHFullScreen(window->Window.Handle, SHFS_HIDESIPBUTTON);
683 SHFullScreen(window->Window.Handle, SHFS_HIDETASKBAR);
684 MoveWindow(window->Window.Handle, 0, 0, 240, 320, TRUE);
685 ShowWindow(window->Window.Handle, SW_SHOW);
686 UpdateWindow(window->Window.Handle);
689 window->Window.Handle = CreateWindowEx(
695 (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle,
697 fgDisplay.pDisplay.Instance,
700 #endif /* defined(_WIN32_WCE) */
702 if( !( window->Window.Handle ) )
703 fgError( "Failed to create a window (%s)!", title );
705 #if !defined(_WIN32_WCE)
706 /* Need to set requested style again, apparently Windows doesn't listen when requesting windows without title bar or borders */
707 SetWindowLong(window->Window.Handle, GWL_STYLE, flags);
708 SetWindowPos(window->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
709 #endif /* defined(_WIN32_WCE) */
711 /* Make a menu window always on top - fix Feature Request 947118 */
712 if( window->IsMenu || gameMode )
714 window->Window.Handle,
717 SWP_NOMOVE | SWP_NOSIZE
720 /* Enable multitouch: additional flag TWF_FINETOUCH, TWF_WANTPALM */
722 if (fghRegisterTouchWindow == (pRegisterTouchWindow)0xDEADBEEF)
723 fghRegisterTouchWindow = (pRegisterTouchWindow)GetProcAddress(GetModuleHandle("user32"),"RegisterTouchWindow");
724 if (fghRegisterTouchWindow)
725 fghRegisterTouchWindow( window->Window.Handle, TWF_FINETOUCH | TWF_WANTPALM );
728 #if defined(_WIN32_WCE)
729 ShowWindow( window->Window.Handle, SW_SHOW );
731 ShowWindow( window->Window.Handle,
732 fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOWNORMAL );
733 #endif /* defined(_WIN32_WCE) */
739 void fgPlatformDisplayWindow ( SFG_Window *window )
742 window->Window.Handle, NULL, NULL,
743 RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW
748 void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height )
754 * Before we do anything else, check if this is a newly created window
755 * that did not have its windowStatus/visibility func called yet
756 * we do that on first paint, but because I want to keep the paint
757 * operation as lean as possible, we do it here. The first paint
758 * goes together with a first resize call before the display callback
759 * is called, so this is just in time. Shitty place to do it, but this
760 * is the only reliable way I can think of to call the callback upon
761 * first draw of the window.
762 * More broadly speaking, I know this is an ugly hack, but I'm not sure
763 * what else to do about it. Depending on WM_ACTIVATE would not work
764 * as not all windows get this when you are opening multiple before the
765 * mainloop starts. WM_SHOWWINDOW looked like an interesting candidate,
766 * but it is generated and processed before glutCreate(Sub)Window
767 * returns, so no callback can yet be set on the window.
769 /* Check windowStatus/visibility func has been notified that window is visible (deferred from creation time to give user opportunity to register callbacks) */
770 if (!window->State.pWState.WindowFuncCalled)
772 fghNotifyWindowStatus(window);
773 window->State.pWState.WindowFuncCalled = GL_TRUE;
777 * For windowed mode, get the current position of the
778 * window and resize taking the size of the frame
779 * decorations into account.
781 * Note on maximizing behavior of Windows: the resize borders are off
782 * the screen such that the client area extends all the way from the
783 * leftmost corner to the rightmost corner to maximize screen real
784 * estate. A caption is still shown however to allow interaction with
785 * the window controls. This is default behavior of Windows that
786 * FreeGLUT sticks with. To alter, one would have to check if
787 * WS_MAXIMIZE style is set when a resize event is triggered, and
788 * then manually correct the windowRect to put the borders back on
792 /* "GetWindowRect" returns the pixel coordinates of the outside of the window */
793 GetWindowRect( window->Window.Handle, &windowRect );
795 /* Create rect in FreeGLUT format, (X,Y) topleft outside window, WxH of client area */
796 windowRect.right = windowRect.left+width;
797 windowRect.bottom = windowRect.top+height;
799 if (window->Parent == NULL)
800 /* get the window rect from this to feed to SetWindowPos, correct for window decorations */
801 fghComputeWindowRectFromClientArea_QueryWindow(&windowRect,window,TRUE);
804 /* correct rect for position client area of parent window
805 * (SetWindowPos input for child windows is in coordinates
806 * relative to the parent's client area).
807 * Child windows don't have decoration, so no need to correct
811 fghGetClientArea( &parentRect, window->Parent );
812 OffsetRect(&windowRect,-parentRect.left,-parentRect.top);
815 /* Do the actual resizing */
816 SetWindowPos( window->Window.Handle,
818 windowRect.left, windowRect.top,
819 windowRect.right - windowRect.left,
820 windowRect.bottom- windowRect.top,
821 SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
825 /* Set new width and height so we can test for that in WM_SIZE message handler and don't do anything if not needed */
826 window->State.Width = width;
827 window->State.Height = height;
832 * Closes a window, destroying the frame and OpenGL context
834 void fgPlatformCloseWindow( SFG_Window* window )
836 /* Make sure we don't close a window with current context active */
837 if( fgStructure.CurrentWindow == window )
838 wglMakeCurrent( NULL, NULL );
841 * Step through the list of windows. If the rendering context
842 * is not being used by another window, then we delete it.
848 for( iter = (SFG_Window *)fgStructure.Windows.First;
850 iter = (SFG_Window *)iter->Node.Next )
852 if( ( iter->Window.Context == window->Window.Context ) &&
858 wglDeleteContext( window->Window.Context );
861 DestroyWindow( window->Window.Handle );
867 * This function makes the current window visible
869 void fgPlatformGlutShowWindow( void )
871 ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_SHOW );
875 * This function hides the current window
877 void fgPlatformGlutHideWindow( void )
879 ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_HIDE );
883 * Iconify the current window (top-level windows only)
885 void fgPlatformGlutIconifyWindow( void )
887 SFG_Window *win = fgStructure.CurrentWindow;
889 /* Call on parent window */
893 /* Visibility status of window gets updated in the WM_SHOWWINDOW handler */
894 ShowWindow(win->Window.Handle, SW_MINIMIZE);
898 * Set the current window's title
900 void fgPlatformGlutSetWindowTitle( const char* title )
904 wchar_t* wstr = fghWstrFromStr(title);
905 SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr );
909 SetWindowText( fgStructure.CurrentWindow->Window.Handle, title );
914 * Set the current window's iconified title
915 * There really isn't a way to set the icon name separate from the
916 * windows name in Win32, so, just set the windows name.
918 void fgPlatformGlutSetIconTitle( const char* title )
922 wchar_t* wstr = fghWstrFromStr(title);
923 SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr );
927 SetWindowText( fgStructure.CurrentWindow->Window.Handle, title );
932 * Change the current window's position
934 void fgPlatformGlutPositionWindow( int x, int y )
938 /* "GetWindowRect" returns the pixel coordinates of the outside of the window */
939 GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect );
941 fgStructure.CurrentWindow->Window.Handle,
944 winRect.right - winRect.left,
945 winRect.bottom - winRect.top,
951 * Lowers the current window (by Z order change)
953 void fgPlatformGlutPushWindow( void )
956 fgStructure.CurrentWindow->Window.Handle,
959 SWP_NOSIZE | SWP_NOMOVE
964 * Raises the current window (by Z order change)
966 void fgPlatformGlutPopWindow( void )
969 fgStructure.CurrentWindow->Window.Handle,
972 SWP_NOSIZE | SWP_NOMOVE
977 * Resize the current window so that it fits the whole screen
979 void fgPlatformGlutFullScreen( SFG_Window *win )
981 #if !defined(_WIN32_WCE) /* FIXME: what about WinCE */
983 if (glutGet(GLUT_FULL_SCREEN))
985 /* Leave full screen state before entering fullscreen again (resizing?) */
986 glutLeaveFullScreen();
990 #if(WINVER >= 0x0500) /* Windows 2000 or later */
995 /* For fullscreen mode, first remove all window decoration
996 * and set style to popup so it will overlap the taskbar
997 * then force to maximize on the screen on which it has the most
1002 /* save current window rect, style, exstyle and maximized state */
1003 win->State.pWState.OldMaximized = !!IsZoomed(win->Window.Handle);
1004 if (win->State.pWState.OldMaximized)
1005 /* We force the window into restored mode before going
1006 * fullscreen because Windows doesn't seem to hide the
1007 * taskbar if the window is in the maximized state.
1009 SendMessage(win->Window.Handle, WM_SYSCOMMAND, SC_RESTORE, 0);
1011 GetWindowRect( win->Window.Handle, &win->State.pWState.OldRect );
1012 win->State.pWState.OldStyle = GetWindowLong(win->Window.Handle, GWL_STYLE);
1013 win->State.pWState.OldStyleEx = GetWindowLong(win->Window.Handle, GWL_EXSTYLE);
1015 /* remove decorations from style */
1016 SetWindowLong(win->Window.Handle, GWL_STYLE,
1017 win->State.pWState.OldStyle & ~(WS_CAPTION | WS_THICKFRAME));
1018 SetWindowLong(win->Window.Handle, GWL_EXSTYLE,
1019 win->State.pWState.OldStyleEx & ~(WS_EX_DLGMODALFRAME |
1020 WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
1022 /* For fullscreen mode, find the monitor that is covered the most
1023 * by the window and get its rect as the resize target.
1025 hMonitor= MonitorFromRect(&win->State.pWState.OldRect, MONITOR_DEFAULTTONEAREST);
1026 mi.cbSize = sizeof(mi);
1027 GetMonitorInfo(hMonitor, &mi);
1028 rect = mi.rcMonitor;
1029 #else /* if (WINVER >= 0x0500) */
1032 /* For fullscreen mode, force the top-left corner to 0,0
1033 * and adjust the window rectangle so that the client area
1034 * covers the whole screen.
1039 rect.right = fgDisplay.ScreenWidth;
1040 rect.bottom = fgDisplay.ScreenHeight;
1042 AdjustWindowRect ( &rect, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS |
1043 WS_CLIPCHILDREN, FALSE );
1044 #endif /* (WINVER >= 0x0500) */
1047 * then resize window
1048 * SWP_NOACTIVATE Do not activate the window
1049 * SWP_NOOWNERZORDER Do not change position in z-order
1050 * SWP_NOSENDCHANGING Suppress WM_WINDOWPOSCHANGING message
1051 * SWP_NOZORDER Retains the current Z order (ignore 2nd param)
1053 SetWindowPos( fgStructure.CurrentWindow->Window.Handle,
1057 rect.right - rect.left,
1058 rect.bottom - rect.top,
1059 SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
1063 win->State.IsFullscreen = GL_TRUE;
1069 * If we are fullscreen, resize the current window back to its original size
1071 void fgPlatformGlutLeaveFullScreen( SFG_Window *win )
1073 #if !defined(_WIN32_WCE) /* FIXME: what about WinCE */
1074 if (!glutGet(GLUT_FULL_SCREEN))
1080 /* restore style of window before making it fullscreen */
1081 SetWindowLong(win->Window.Handle, GWL_STYLE, win->State.pWState.OldStyle);
1082 SetWindowLong(win->Window.Handle, GWL_EXSTYLE, win->State.pWState.OldStyleEx);
1085 SetWindowPos(win->Window.Handle,
1087 win->State.pWState.OldRect.left,
1088 win->State.pWState.OldRect.top,
1089 win->State.pWState.OldRect.right - win->State.pWState.OldRect.left,
1090 win->State.pWState.OldRect.bottom - win->State.pWState.OldRect.top,
1091 SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
1095 if (win->State.pWState.OldMaximized)
1096 SendMessage(win->Window.Handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
1098 win->State.IsFullscreen = GL_FALSE;
1103 * Toggle the window's full screen state.
1105 void fgPlatformGlutFullScreenToggle( SFG_Window *win )
1107 if (!win->State.IsFullscreen)
1110 glutLeaveFullScreen();
1114 /* -- PLATFORM-SPECIFIC INTERFACE FUNCTION -------------------------------------------------- */
1116 int FGAPIENTRY __glutCreateWindowWithExit( const char *title, void (__cdecl *exit_function)(int) )
1118 __glutExitFunc = exit_function;
1119 return glutCreateWindow( title );