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 */
409 /* Computes position of corners of window Rect (outer position including
410 * decorations) based on the provided client rect and based on the style
411 * of the window in question.
412 * If posIsOutside is set to true, the input client Rect is taken to follow
413 * freeGLUT's window specification convention in which the top-left corner
414 * is at the outside of the window, while the size
415 * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable
418 void fghComputeWindowRectFromClientArea_UseStyle( RECT *clientRect, const DWORD windowStyle, const DWORD windowExStyle, BOOL posIsOutside )
420 RECT windowRect = {0,0,0,0};
421 CopyRect(&windowRect,clientRect);
423 /* Get rect including non-client area */
424 AdjustWindowRectEx(&windowRect,windowStyle,FALSE,windowExStyle);
426 /* Move window right and down by non-client area extent on left and top, if wanted */
429 windowRect.right += clientRect->left-windowRect.left;
430 windowRect.bottom += clientRect->top -windowRect.top;
431 windowRect.left = clientRect->left;
432 windowRect.top = clientRect->top;
435 /* done, copy windowRect to output */
436 CopyRect(clientRect,&windowRect);
439 /* Computes position of corners of window Rect (outer position including
440 * decorations) based on the provided client rect and based on the style
441 * of the window in question. If the window pointer or the window handle
442 * is NULL, a fully decorated window (caption and border) is assumed.
443 * Furthermore, if posIsOutside is set to true, the input client Rect is
444 * taken to follow freeGLUT's window specification convention in which the
445 * top-left corner is at the outside of the window, while the size
446 * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable
449 void fghComputeWindowRectFromClientArea_QueryWindow( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside )
451 DWORD windowStyle = 0, windowExStyle = 0;
452 fghGetStyleFromWindow(window,&windowStyle,&windowExStyle);
454 fghComputeWindowRectFromClientArea_UseStyle(clientRect, windowStyle, windowExStyle, posIsOutside);
457 /* Gets the rect describing the client area (drawable area) of the
458 * specified window. Output is position of corners of client area (drawable area) on the screen.
459 * Does not touch clientRect if window pointer or window handle is NULL.
460 * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable area.
462 void fghGetClientArea( RECT *clientRect, const SFG_Window *window )
464 POINT topLeftClient = {0,0};
466 freeglut_return_if_fail((window && window->Window.Handle));
468 /* Get size of client rect */
469 GetClientRect(window->Window.Handle, clientRect);
470 /* Get position of top-left of client area on the screen */
471 ClientToScreen(window->Window.Handle,&topLeftClient);
472 /* Add top-left offset */
473 OffsetRect(clientRect,topLeftClient.x,topLeftClient.y);
485 static BOOL CALLBACK m_proc(HMONITOR mon,
490 m_proc_t *dp=(m_proc_t *)data;
493 info.cbSize=sizeof(info);
494 res=GetMonitorInfo(mon,(LPMONITORINFO)&info);
497 if( strcmp(dp->name,info.szDevice)==0 )
499 *(dp->x)=info.rcMonitor.left;
500 *(dp->y)=info.rcMonitor.top;
508 * this function returns the origin of the screen identified by
509 * fgDisplay.pDisplay.DisplayName, and 0 otherwise.
510 * This is used in fgOpenWindow to open the gamemode window on the screen
511 * identified by the -display command line argument. The function should
512 * not be called otherwise.
515 static void get_display_origin(int *xp,int *yp)
520 if( fgDisplay.pDisplay.DisplayName )
525 st.name=fgDisplay.pDisplay.DisplayName;
526 EnumDisplayMonitors(0,0,m_proc,(LPARAM)&st);
530 #pragma message( "-display parameter only works if compiled with WINVER >= 0x0500")
532 static void get_display_origin(int *xp,int *yp)
537 if( fgDisplay.pDisplay.DisplayName )
539 fgWarning( "for working -display support FreeGLUT must be compiled with WINVER >= 0x0500");
547 * Opens a window. Requires a SFG_Window object created and attached
548 * to the freeglut structure. OpenGL context is created here.
550 void fgPlatformOpenWindow( SFG_Window* window, const char* title,
551 GLboolean positionUse, int x, int y,
552 GLboolean sizeUse, int w, int h,
553 GLboolean gameMode, GLboolean isSubWindow )
561 /* Grab the window class we have registered on glutInit(): */
562 atom = GetClassInfo( fgDisplay.pDisplay.Instance, _T("FREEGLUT"), &wc );
563 FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Info Not Found",
566 /* Determine window style flags*/
569 FREEGLUT_INTERNAL_ERROR_EXIT ( window->Parent == NULL,
570 "Game mode being invoked on a subwindow",
574 * Set the window creation flags appropriately to make the window
577 flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
581 flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
584 * There's a small difference between creating the top, child and
587 if ( window->IsMenu )
590 exFlags |= WS_EX_TOOLWINDOW;
592 #if defined(_WIN32_WCE)
593 /* no decorations for windows CE */
595 /* if this is not a subwindow (child), set its style based on the requested window decorations */
596 else if( window->Parent == NULL )
597 fghGetDefaultWindowStyle(&flags);
600 /* subwindows always have no decoration, but are marked as a child window to the OS */
604 /* determine window size and position */
607 /* if in gamemode, query the origin of specified by the -display
608 * command line parameter (if any) and offset the upper-left corner
609 * of the window so we create the window on that screen.
610 * The -display argument doesn't do anything if not trying to enter
614 get_display_origin(&xoff,&yoff);
625 if( ! window->IsMenu )
630 else /* fail safe - Windows can make a window of size (0, 0) */
631 w = h = 300; /* default window size */
633 /* store requested client area width and height */
634 window->State.Width = w;
635 window->State.Height = h;
637 #if !defined(_WIN32_WCE) /* no decorations for windows CE */
642 * Update the window dimensions, taking the window decorations
643 * into account. FreeGLUT is to create the window with the
644 * topleft outside corner at (x,y) and with client area
646 * note: don't need to do this when w=h=CW_USEDEFAULT, so in the
647 * if( sizeUse ) here is convenient.
651 windowRect.right = x+w;
652 windowRect.bottom = y+h;
654 fghComputeWindowRectFromClientArea_UseStyle(&windowRect,flags,exFlags,TRUE);
656 /* NB: w and h are now width and height of window including non-client area! */
657 w = windowRect.right - windowRect.left;
658 h = windowRect.bottom- windowRect.top;
660 #endif /* !defined(_WIN32_WCE) */
662 #if defined(_WIN32_WCE)
664 wchar_t* wstr = fghWstrFromStr(title);
666 window->Window.Handle = CreateWindow(
669 WS_VISIBLE | WS_POPUP,
673 fgDisplay.pDisplay.Instance,
679 SHFullScreen(window->Window.Handle, SHFS_HIDESTARTICON);
680 SHFullScreen(window->Window.Handle, SHFS_HIDESIPBUTTON);
681 SHFullScreen(window->Window.Handle, SHFS_HIDETASKBAR);
682 MoveWindow(window->Window.Handle, 0, 0, 240, 320, TRUE);
683 ShowWindow(window->Window.Handle, SW_SHOW);
684 UpdateWindow(window->Window.Handle);
687 window->Window.Handle = CreateWindowEx(
693 (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle,
695 fgDisplay.pDisplay.Instance,
698 #endif /* defined(_WIN32_WCE) */
700 if( !( window->Window.Handle ) )
701 fgError( "Failed to create a window (%s)!", title );
705 window->State.pWState.WindowTitle = malloc (strlen(title) + 1);
706 strcpy(window->State.pWState.WindowTitle, title);
709 #if !defined(_WIN32_WCE)
710 /* Need to set requested style again, apparently Windows doesn't listen when requesting windows without title bar or borders */
711 SetWindowLong(window->Window.Handle, GWL_STYLE, flags);
712 SetWindowPos(window->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
713 #endif /* defined(_WIN32_WCE) */
715 /* Make a menu window always on top - fix Feature Request 947118 */
716 if( window->IsMenu || gameMode )
718 window->Window.Handle,
721 SWP_NOMOVE | SWP_NOSIZE
724 /* Enable multitouch: additional flag TWF_FINETOUCH, TWF_WANTPALM */
726 if (fghRegisterTouchWindow == (pRegisterTouchWindow)0xDEADBEEF)
727 fghRegisterTouchWindow = (pRegisterTouchWindow)GetProcAddress(GetModuleHandle("user32"),"RegisterTouchWindow");
728 if (fghRegisterTouchWindow)
729 fghRegisterTouchWindow( window->Window.Handle, TWF_FINETOUCH | TWF_WANTPALM );
732 #if defined(_WIN32_WCE)
733 ShowWindow( window->Window.Handle, SW_SHOW );
735 ShowWindow( window->Window.Handle,
736 fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOWNORMAL );
737 #endif /* defined(_WIN32_WCE) */
743 void fgPlatformDisplayWindow ( SFG_Window *window )
746 window->Window.Handle, NULL, NULL,
747 RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW
752 void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height )
758 * Before we do anything else, check if this is a newly created window
759 * that did not have its windowStatus/visibility func called yet
760 * we do that on first paint, but because I want to keep the paint
761 * operation as lean as possible, we do it here. The first paint
762 * goes together with a first resize call before the display callback
763 * is called, so this is just in time. Shitty place to do it, but this
764 * is the only reliable way I can think of to call the callback upon
765 * first draw of the window.
766 * More broadly speaking, I know this is an ugly hack, but I'm not sure
767 * what else to do about it. Depending on WM_ACTIVATE would not work
768 * as not all windows get this when you are opening multiple before the
769 * mainloop starts. WM_SHOWWINDOW looked like an interesting candidate,
770 * but it is generated and processed before glutCreate(Sub)Window
771 * returns, so no callback can yet be set on the window.
773 /* Check windowStatus/visibility func has been notified that window is visible (deferred from creation time to give user opportunity to register callbacks) */
774 if (!window->State.pWState.WindowFuncCalled)
776 fghNotifyWindowStatus(window);
777 window->State.pWState.WindowFuncCalled = GL_TRUE;
781 * For windowed mode, get the current position of the
782 * window and resize taking the size of the frame
783 * decorations into account.
785 * Note on maximizing behavior of Windows: the resize borders are off
786 * the screen such that the client area extends all the way from the
787 * leftmost corner to the rightmost corner to maximize screen real
788 * estate. A caption is still shown however to allow interaction with
789 * the window controls. This is default behavior of Windows that
790 * FreeGLUT sticks with. To alter, one would have to check if
791 * WS_MAXIMIZE style is set when a resize event is triggered, and
792 * then manually correct the windowRect to put the borders back on
796 /* "GetWindowRect" returns the pixel coordinates of the outside of the window */
797 GetWindowRect( window->Window.Handle, &windowRect );
799 /* Create rect in FreeGLUT format, (X,Y) topleft outside window, WxH of client area */
800 windowRect.right = windowRect.left+width;
801 windowRect.bottom = windowRect.top+height;
803 if (window->Parent == NULL)
804 /* get the window rect from this to feed to SetWindowPos, correct for window decorations */
805 fghComputeWindowRectFromClientArea_QueryWindow(&windowRect,window,TRUE);
808 /* correct rect for position client area of parent window
809 * (SetWindowPos input for child windows is in coordinates
810 * relative to the parent's client area).
811 * Child windows don't have decoration, so no need to correct
815 fghGetClientArea( &parentRect, window->Parent );
816 OffsetRect(&windowRect,-parentRect.left,-parentRect.top);
819 /* Do the actual resizing */
820 SetWindowPos( window->Window.Handle,
822 windowRect.left, windowRect.top,
823 windowRect.right - windowRect.left,
824 windowRect.bottom- windowRect.top,
825 SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
829 /* Set new width and height so we can test for that in WM_SIZE message handler and don't do anything if not needed */
830 window->State.Width = width;
831 window->State.Height = height;
836 * Closes a window, destroying the frame and OpenGL context
838 void fgPlatformCloseWindow( SFG_Window* window )
840 /* Make sure we don't close a window with current context active */
841 if( fgStructure.CurrentWindow == window )
842 wglMakeCurrent( NULL, NULL );
845 * Step through the list of windows. If the rendering context
846 * is not being used by another window, then we delete it.
852 for( iter = (SFG_Window *)fgStructure.Windows.First;
854 iter = (SFG_Window *)iter->Node.Next )
856 if( ( iter->Window.Context == window->Window.Context ) &&
862 wglDeleteContext( window->Window.Context );
865 DestroyWindow( window->Window.Handle );
867 /* clean up copied title text(s) */
868 if (window->State.pWState.WindowTitle)
869 free(window->State.pWState.WindowTitle);
870 if (window->State.pWState.IconTitle)
871 free(window->State.pWState.IconTitle);
877 * This function makes the current window visible
879 void fgPlatformGlutShowWindow( void )
881 ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_SHOW );
885 * This function hides the current window
887 void fgPlatformGlutHideWindow( void )
889 ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_HIDE );
893 * Iconify the current window (top-level windows only)
895 void fgPlatformGlutIconifyWindow( void )
897 SFG_Window *win = fgStructure.CurrentWindow;
899 /* Call on parent window */
903 /* Visibility status of window gets updated in the WM_SHOWWINDOW handler */
904 ShowWindow(win->Window.Handle, SW_MINIMIZE);
908 * Set the current window's title
910 void fgPlatformGlutSetWindowTitle( const char* title )
914 wchar_t* wstr = fghWstrFromStr(title);
915 SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr );
919 SetWindowText( fgStructure.CurrentWindow->Window.Handle, title );
922 /* Make copy of string to refer to later */
923 if (fgStructure.CurrentWindow->State.pWState.WindowTitle)
924 free(fgStructure.CurrentWindow->State.pWState.WindowTitle);
925 fgStructure.CurrentWindow->State.pWState.WindowTitle = malloc (strlen(title) + 1);
926 strcpy(fgStructure.CurrentWindow->State.pWState.WindowTitle, title);
930 * Set the current window's iconified title
932 void fgPlatformGlutSetIconTitle( const char* title )
934 /* Make copy of string to refer to later */
935 if (fgStructure.CurrentWindow->State.pWState.IconTitle)
936 free(fgStructure.CurrentWindow->State.pWState.IconTitle);
937 fgStructure.CurrentWindow->State.pWState.IconTitle = malloc (strlen(title) + 1);
938 strcpy(fgStructure.CurrentWindow->State.pWState.IconTitle, title);
942 * Change the current window's position
944 void fgPlatformGlutPositionWindow( int x, int y )
948 /* "GetWindowRect" returns the pixel coordinates of the outside of the window */
949 GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect );
951 fgStructure.CurrentWindow->Window.Handle,
954 winRect.right - winRect.left,
955 winRect.bottom - winRect.top,
961 * Lowers the current window (by Z order change)
963 void fgPlatformGlutPushWindow( void )
966 fgStructure.CurrentWindow->Window.Handle,
969 SWP_NOSIZE | SWP_NOMOVE
974 * Raises the current window (by Z order change)
976 void fgPlatformGlutPopWindow( void )
979 fgStructure.CurrentWindow->Window.Handle,
982 SWP_NOSIZE | SWP_NOMOVE
987 * Resize the current window so that it fits the whole screen
989 void fgPlatformGlutFullScreen( SFG_Window *win )
991 #if !defined(_WIN32_WCE) /* FIXME: what about WinCE */
993 if (glutGet(GLUT_FULL_SCREEN))
995 /* Leave full screen state before entering fullscreen again (resizing?) */
996 glutLeaveFullScreen();
1000 #if(WINVER >= 0x0500) /* Windows 2000 or later */
1005 /* For fullscreen mode, first remove all window decoration
1006 * and set style to popup so it will overlap the taskbar
1007 * then force to maximize on the screen on which it has the most
1012 /* save current window rect, style, exstyle and maximized state */
1013 win->State.pWState.OldMaximized = !!IsZoomed(win->Window.Handle);
1014 if (win->State.pWState.OldMaximized)
1015 /* We force the window into restored mode before going
1016 * fullscreen because Windows doesn't seem to hide the
1017 * taskbar if the window is in the maximized state.
1019 SendMessage(win->Window.Handle, WM_SYSCOMMAND, SC_RESTORE, 0);
1021 GetWindowRect( win->Window.Handle, &win->State.pWState.OldRect );
1022 win->State.pWState.OldStyle = GetWindowLong(win->Window.Handle, GWL_STYLE);
1023 win->State.pWState.OldStyleEx = GetWindowLong(win->Window.Handle, GWL_EXSTYLE);
1025 /* remove decorations from style */
1026 SetWindowLong(win->Window.Handle, GWL_STYLE,
1027 win->State.pWState.OldStyle & ~(WS_CAPTION | WS_THICKFRAME));
1028 SetWindowLong(win->Window.Handle, GWL_EXSTYLE,
1029 win->State.pWState.OldStyleEx & ~(WS_EX_DLGMODALFRAME |
1030 WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
1032 /* For fullscreen mode, find the monitor that is covered the most
1033 * by the window and get its rect as the resize target.
1035 hMonitor= MonitorFromRect(&win->State.pWState.OldRect, MONITOR_DEFAULTTONEAREST);
1036 mi.cbSize = sizeof(mi);
1037 GetMonitorInfo(hMonitor, &mi);
1038 rect = mi.rcMonitor;
1039 #else /* if (WINVER >= 0x0500) */
1042 /* For fullscreen mode, force the top-left corner to 0,0
1043 * and adjust the window rectangle so that the client area
1044 * covers the whole screen.
1049 rect.right = fgDisplay.ScreenWidth;
1050 rect.bottom = fgDisplay.ScreenHeight;
1052 AdjustWindowRect ( &rect, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS |
1053 WS_CLIPCHILDREN, FALSE );
1054 #endif /* (WINVER >= 0x0500) */
1057 * then resize window
1058 * SWP_NOACTIVATE Do not activate the window
1059 * SWP_NOOWNERZORDER Do not change position in z-order
1060 * SWP_NOSENDCHANGING Suppress WM_WINDOWPOSCHANGING message
1061 * SWP_NOZORDER Retains the current Z order (ignore 2nd param)
1063 SetWindowPos( fgStructure.CurrentWindow->Window.Handle,
1067 rect.right - rect.left,
1068 rect.bottom - rect.top,
1069 SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
1073 win->State.IsFullscreen = GL_TRUE;
1079 * If we are fullscreen, resize the current window back to its original size
1081 void fgPlatformGlutLeaveFullScreen( SFG_Window *win )
1083 #if !defined(_WIN32_WCE) /* FIXME: what about WinCE */
1084 if (!glutGet(GLUT_FULL_SCREEN))
1090 /* restore style of window before making it fullscreen */
1091 SetWindowLong(win->Window.Handle, GWL_STYLE, win->State.pWState.OldStyle);
1092 SetWindowLong(win->Window.Handle, GWL_EXSTYLE, win->State.pWState.OldStyleEx);
1095 SetWindowPos(win->Window.Handle,
1097 win->State.pWState.OldRect.left,
1098 win->State.pWState.OldRect.top,
1099 win->State.pWState.OldRect.right - win->State.pWState.OldRect.left,
1100 win->State.pWState.OldRect.bottom - win->State.pWState.OldRect.top,
1101 SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
1105 if (win->State.pWState.OldMaximized)
1106 SendMessage(win->Window.Handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
1108 win->State.IsFullscreen = GL_FALSE;
1113 * Toggle the window's full screen state.
1115 void fgPlatformGlutFullScreenToggle( SFG_Window *win )
1117 if (!win->State.IsFullscreen)
1120 glutLeaveFullScreen();
1124 /* -- PLATFORM-SPECIFIC INTERFACE FUNCTION -------------------------------------------------- */
1126 int FGAPIENTRY __glutCreateWindowWithExit( const char *title, void (__cdecl *exit_function)(int) )
1128 __glutExitFunc = exit_function;
1129 return glutCreateWindow( title );