From e6b149a66a5d6f7539855ca7922791cd22348f43 Mon Sep 17 00:00:00 2001 From: "John F. Fay" Date: Sun, 4 Sep 2011 19:38:32 +0000 Subject: [PATCH] Putting in Diederick Niehorster's fullstreen patch per e-mail from him dated 6/9/2011, updated 9/4/2011 with modified patch. git-svn-id: svn+ssh://svn.code.sf.net/p/freeglut/code/trunk/freeglut/freeglut@929 7f0cb862-5218-0410-a997-914c9d46530a --- include/GL/freeglut_ext.h | 1 + src/freeglut_ext.c | 1 + src/freeglut_internal.h | 17 ++ src/freeglut_main.c | 59 +++--- src/freeglut_state.c | 67 +++---- src/freeglut_structure.c | 2 + src/freeglut_window.c | 471 +++++++++++++++++++++++++++++++++++---------- src/freeglutdll.def | 1 + 8 files changed, 439 insertions(+), 180 deletions(-) diff --git a/include/GL/freeglut_ext.h b/include/GL/freeglut_ext.h index c0fddbf..6bf84b8 100644 --- a/include/GL/freeglut_ext.h +++ b/include/GL/freeglut_ext.h @@ -127,6 +127,7 @@ FGAPI void FGAPIENTRY glutExit ( void ); * Window management functions, see freeglut_window.c */ FGAPI void FGAPIENTRY glutFullScreenToggle( void ); +FGAPI void FGAPIENTRY glutLeaveFullScreen( void ); /* * Window-specific callback functions, see freeglut_callbacks.c diff --git a/src/freeglut_ext.c b/src/freeglut_ext.c index 927cb4e..d8aca45 100644 --- a/src/freeglut_ext.c +++ b/src/freeglut_ext.c @@ -166,6 +166,7 @@ static GLUTproc fghGetGLUTProcAddress( const char* procName ) CHECK_NAME(glutWMCloseFunc); CHECK_NAME(glutMenuDestroyFunc); CHECK_NAME(glutFullScreenToggle); + CHECK_NAME(glutLeaveFullScreen); CHECK_NAME(glutSetOption); CHECK_NAME(glutGetModeValues); CHECK_NAME(glutSetWindowData); diff --git a/src/freeglut_internal.h b/src/freeglut_internal.h index 2a8d89a..0a6ece4 100644 --- a/src/freeglut_internal.h +++ b/src/freeglut_internal.h @@ -449,10 +449,16 @@ struct tagSFG_Context typedef struct tagSFG_WindowState SFG_WindowState; struct tagSFG_WindowState { + /* Note that on Windows, sizes always refer to the client area, thus without the window decorations */ int Width; /* Window's width in pixels */ int Height; /* The same about the height */ +#if TARGET_HOST_POSIX_X11 int OldWidth; /* Window width from before a resize */ int OldHeight; /* " height " " " " */ +#elif TARGET_HOST_MS_WINDOWS + RECT OldRect; /* window rect - stored before the window is made fullscreen */ + DWORD OldStyle; /* window style - stored before the window is made fullscreen */ +#endif GLboolean Redisplay; /* Do we have to redisplay? */ GLboolean Visible; /* Is the window visible now */ @@ -926,6 +932,17 @@ void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator ); void fgEnumSubWindows( SFG_Window* window, FGCBenumerator enumCallback, SFG_Enumerator* enumerator ); +/* + * Helper functions for getting client area from the window rect + * and the window rect from the client area given the style of the window + * (or a valid window pointer from which the style can be queried). + */ +void fghComputeWindowRectFromClientArea_UseStyle ( const DWORD windowStyle , RECT *clientRect, BOOL posIsOutside ); +void fghComputeWindowRectFromClientArea_QueryWindow( const SFG_Window *window, RECT *clientRect, BOOL posIsOutside ); +void fghComputeClientAreaFromWindowRect ( const SFG_Window *window, RECT *windowRect, BOOL wantPosOutside ); +RECT fghGetClientArea ( const SFG_Window *window, BOOL wantPosOutside ); +void fghGetBorderWidth(const DWORD windowStyle, int* xBorderWidth, int* yBorderWidth); + /* * fgWindowByHandle returns a (SFG_Window *) value pointing to the * first window in the queue matching the specified window handle. diff --git a/src/freeglut_main.c b/src/freeglut_main.c index 5d18440..5f9b0a5 100644 --- a/src/freeglut_main.c +++ b/src/freeglut_main.c @@ -109,8 +109,7 @@ static void fghReshapeWindow ( SFG_Window *window, int width, int height ) #elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) { - RECT winRect; - int x, y, w, h; + RECT windowRect; /* * For windowed mode, get the current position of the @@ -119,51 +118,43 @@ static void fghReshapeWindow ( SFG_Window *window, int width, int height ) */ /* "GetWindowRect" returns the pixel coordinates of the outside of the window */ - GetWindowRect( window->Window.Handle, &winRect ); - x = winRect.left; - y = winRect.top; - w = width; - h = height; + GetWindowRect( window->Window.Handle, &windowRect ); - if ( window->Parent == NULL ) - { - if ( ! window->IsMenu && (window != fgStructure.GameModeWindow) && - !( fgState.DisplayMode & GLUT_BORDERLESS )) - { - w += GetSystemMetrics( SM_CXSIZEFRAME ) * 2; - h += GetSystemMetrics( SM_CYSIZEFRAME ) * 2 + - GetSystemMetrics( SM_CYCAPTION ); - } - } + /* Create rect in FreeGLUT format, (X,Y) topleft outside window, WxH of client area */ + windowRect.right = windowRect.left+width; + windowRect.bottom = windowRect.top+height; + + if (window->Parent == NULL) + /* get the window rect from this to feed to SetWindowPos, correct for window decorations */ + fghComputeWindowRectFromClientArea_QueryWindow(window,&windowRect,TRUE); else { + /* correct rect for position client area of parent window + * (SetWindowPos input for child windows is in coordinates + * relative to the parent's client area). + * Child windows don't have decoration, so no need to correct + * for them. + */ RECT parentRect; - GetWindowRect( window->Parent->Window.Handle, &parentRect ); - x -= parentRect.left + GetSystemMetrics( SM_CXSIZEFRAME ) * 2; - y -= parentRect.top + GetSystemMetrics( SM_CYSIZEFRAME ) * 2 + - GetSystemMetrics( SM_CYCAPTION ); + parentRect = fghGetClientArea( window->Parent, FALSE ); + windowRect.left -= parentRect.left; + windowRect.right -= parentRect.left; + windowRect.top -= parentRect.top; + windowRect.bottom -= parentRect.top; } - - /* - * SWP_NOACTIVATE Do not activate the window - * SWP_NOOWNERZORDER Do not change position in z-order - * SWP_NOSENDCHANGING Supress WM_WINDOWPOSCHANGING message - * SWP_NOZORDER Retains the current Z order (ignore 2nd param) - */ - + + /* Do the actual resizing */ SetWindowPos( window->Window.Handle, HWND_TOP, - x, y, w, h, + windowRect.left, windowRect.top, + windowRect.right - windowRect.left, + windowRect.bottom- windowRect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOZORDER ); } #endif - /* - * XXX Should update {window->State.OldWidth, window->State.OldHeight} - * XXX to keep in lockstep with POSIX_X11 code. - */ if( FETCH_WCB( *window, Reshape ) ) INVOKE_WCB( *window, Reshape, ( width, height ) ); else diff --git a/src/freeglut_state.c b/src/freeglut_state.c index 1cabb9d..9e3a627 100644 --- a/src/freeglut_state.c +++ b/src/freeglut_state.c @@ -64,16 +64,6 @@ static int fghGetConfig( int attribute ) } #endif -/* Check if the window is in full screen state. */ -static int fghCheckFullScreen(void) -{ -#if TARGET_HOST_POSIX_X11 - return fgStructure.CurrentWindow->State.IsFullscreen; -#else - return 0; -#endif -} - /* -- INTERFACE FUNCTIONS -------------------------------------------------- */ /* @@ -458,25 +448,11 @@ int FGAPIENTRY glutGet( GLenum eWhat ) freeglut_return_val_if_fail( fgStructure.CurrentWindow != NULL, 0 ); - /* - * We need to call GetWindowRect() first... - * (this returns the pixel coordinates of the outside of the window) - */ +#if defined(_WIN32_WCE) GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect ); - - /* ...then we've got to correct the results we've just received... */ - -#if !defined(_WIN32_WCE) - if ( ( fgStructure.GameModeWindow != fgStructure.CurrentWindow ) && ( fgStructure.CurrentWindow->Parent == NULL ) && - ( ! fgStructure.CurrentWindow->IsMenu ) && - !( fgState.DisplayMode & GLUT_BORDERLESS )) - { - winRect.left += GetSystemMetrics( SM_CXSIZEFRAME ); - winRect.right -= GetSystemMetrics( SM_CXSIZEFRAME ); - winRect.top += GetSystemMetrics( SM_CYSIZEFRAME ) + GetSystemMetrics( SM_CYCAPTION ); - winRect.bottom -= GetSystemMetrics( SM_CYSIZEFRAME ); - } -#endif /* !defined(_WIN32_WCE) */ +#else + winRect = fghGetClientArea(fgStructure.CurrentWindow, FALSE); +#endif /* defined(_WIN32_WCE) */ switch( eWhat ) { @@ -489,21 +465,32 @@ int FGAPIENTRY glutGet( GLenum eWhat ) break; case GLUT_WINDOW_BORDER_WIDTH : -#if defined(_WIN32_WCE) - return 0; -#else - if ( fgState.DisplayMode & GLUT_BORDERLESS ) - return 0; - return GetSystemMetrics( SM_CXSIZEFRAME ); -#endif /* !defined(_WIN32_WCE) */ - case GLUT_WINDOW_HEADER_HEIGHT : #if defined(_WIN32_WCE) return 0; #else - if ( fgState.DisplayMode & GLUT_BORDERLESS ) - return 0; - return GetSystemMetrics( SM_CYCAPTION ); + { + DWORD windowStyle; + + if (fgStructure.CurrentWindow && fgStructure.CurrentWindow->Window.Handle) + windowStyle = GetWindowLong(fgStructure.CurrentWindow->Window.Handle, GWL_STYLE); + else + /* If no window, return sizes for a default window with title bar and border */ + windowStyle = WS_OVERLAPPEDWINDOW; + + switch( eWhat ) + { + case GLUT_WINDOW_BORDER_WIDTH: + { + int xBorderWidth, yBorderWidth; + fghGetBorderWidth(windowStyle, &xBorderWidth, &yBorderWidth); + return xBorderWidth; + } + case GLUT_WINDOW_HEADER_HEIGHT: + /* Need to query for WS_MAXIMIZEBOX to see if we have a title bar, the WS_CAPTION query is also true for a WS_DLGFRAME only... */ + return (windowStyle & WS_MAXIMIZEBOX)? GetSystemMetrics( SM_CYCAPTION ) : 0; + } + } #endif /* defined(_WIN32_WCE) */ case GLUT_DISPLAY_MODE_POSSIBLE: @@ -559,7 +546,7 @@ int FGAPIENTRY glutGet( GLenum eWhat ) return fgState.DirectContext; case GLUT_FULL_SCREEN: - return fghCheckFullScreen(); + return fgStructure.CurrentWindow->State.IsFullscreen; case GLUT_AUX: return fgState.AuxiliaryBufferNumber; diff --git a/src/freeglut_structure.c b/src/freeglut_structure.c index ce3869b..c5a2d73 100644 --- a/src/freeglut_structure.c +++ b/src/freeglut_structure.c @@ -79,7 +79,9 @@ SFG_Window* fgCreateWindow( SFG_Window* parent, const char* title, /* Initialize the object properties */ window->ID = ++fgStructure.WindowID; +#if TARGET_HOST_POSIX_X11 window->State.OldHeight = window->State.OldWidth = -1; +#endif fgListInit( &window->Children ); if( parent ) diff --git a/src/freeglut_window.c b/src/freeglut_window.c index f3c509a..897b03c 100644 --- a/src/freeglut_window.c +++ b/src/freeglut_window.c @@ -850,12 +850,167 @@ void fgSetWindow ( SFG_Window *window ) #if TARGET_HOST_MS_WINDOWS +/* Computes position of corners of window Rect (outer position including + * decorations) based on the provided client rect and based on the style + * of the window in question. + * If posIsOutside is set to true, the input client Rect is taken to follow + * freeGLUT's window specification convention in which the top-left corner + * is at the outside of the window, while the size + * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable + * area. + */ +void fghComputeWindowRectFromClientArea_UseStyle( const DWORD windowStyle, RECT *clientRect, BOOL posIsOutside ) +{ + int xBorderWidth = 0, yBorderWidth = 0; + + /* If window has title bar, correct rect for it */ + if (windowStyle & WS_MAXIMIZEBOX) /* Need to query for WS_MAXIMIZEBOX to see if we have a title bar, the WS_CAPTION query is also true for a WS_DLGFRAME only... */ + if (posIsOutside) + clientRect->bottom += GetSystemMetrics( SM_CYCAPTION ); + else + clientRect->top -= GetSystemMetrics( SM_CYCAPTION ); + + /* get width of window's borders (frame), correct rect for it. + * Note, borders can be of zero width if style does not specify borders + */ + fghGetBorderWidth(windowStyle, &xBorderWidth, &yBorderWidth); + if (posIsOutside) + { + clientRect->right += xBorderWidth * 2; + clientRect->bottom += yBorderWidth * 2; + } + else + { + clientRect->left -= xBorderWidth; + clientRect->right += xBorderWidth; + clientRect->top -= yBorderWidth; + clientRect->bottom += yBorderWidth; + } +} + +/* Computes position of corners of window Rect (outer position including + * decorations) based on the provided client rect and based on the style + * of the window in question. If the window pointer or the window handle + * is NULL, a fully decorated window (caption and border) is assumed. + * Furthermore, if posIsOutside is set to true, the input client Rect is + * taken to follow freeGLUT's window specification convention in which the + * top-left corner is at the outside of the window, while the size + * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable + * area. +*/ +void fghComputeWindowRectFromClientArea_QueryWindow( const SFG_Window *window, RECT *clientRect, BOOL posIsOutside ) +{ + DWORD windowStyle = 0; + + if (window && window->Window.Handle) + windowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE); + else + windowStyle = WS_OVERLAPPEDWINDOW; + + fghComputeWindowRectFromClientArea_UseStyle(windowStyle, clientRect, posIsOutside); +} + +/* Computes position of corners of client area (drawable area) of a window + * based on the provided window Rect (outer position including decorations) + * and based on the style of the window in question. If the window pointer + * or the window handle is NULL, a fully decorated window (caption and + * border) is assumed. + * Furthermore, if wantPosOutside is set to true, the output client Rect + * will follow freeGLUT's window specification convention in which the + * top-left corner is at the outside of the window, the size + * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable + * area. + */ +void fghComputeClientAreaFromWindowRect( const SFG_Window *window, RECT *windowRect, BOOL wantPosOutside ) +{ + DWORD windowStyle = 0; + int xBorderWidth = 0, yBorderWidth = 0; + + if (window && window->Window.Handle) + windowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE); + else + windowStyle = WS_OVERLAPPEDWINDOW; + + /* If window has title bar, correct rect for it */ + if (windowStyle & WS_MAXIMIZEBOX) /* Need to query for WS_MAXIMIZEBOX to see if we have a title bar, the WS_CAPTION query is also true for a WS_DLGFRAME only... */ + if (wantPosOutside) + windowRect->bottom -= GetSystemMetrics( SM_CYCAPTION ); + else + windowRect->top += GetSystemMetrics( SM_CYCAPTION ); + + /* get width of window's borders (frame), correct rect for it. + * Note, borders can be of zero width if style does not specify borders + */ + fghGetBorderWidth(windowStyle, &xBorderWidth, &yBorderWidth); + if (wantPosOutside) + { + windowRect->right -= xBorderWidth * 2; + windowRect->bottom -= yBorderWidth * 2; + } + else + { + windowRect->left += xBorderWidth; + windowRect->right -= xBorderWidth; + windowRect->top += yBorderWidth; + windowRect->bottom -= yBorderWidth; + } +} + +/* Gets the rect describing the client area (drawable area) of the + * specified window. + * Returns an empty rect if window pointer or window handle is NULL. + * If wantPosOutside is set to true, the output client Rect + * will follow freeGLUT's window specification convention in which the + * top-left corner is at the outside of the window, while the size + * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable + * area. + */ +RECT fghGetClientArea( const SFG_Window *window, BOOL wantPosOutside ) +{ + RECT windowRect = {0,0,0,0}; + + freeglut_return_val_if_fail((window && window->Window.Handle),windowRect); + + /* + * call GetWindowRect() + * (this returns the pixel coordinates of the outside of the window) + */ + GetWindowRect( window->Window.Handle, &windowRect ); + + /* Then correct the results */ + fghComputeClientAreaFromWindowRect(window, &windowRect, wantPosOutside); + + return windowRect; +} + +/* Returns the width of the window borders based on the window's style. + */ +void fghGetBorderWidth(const DWORD windowStyle, int* xBorderWidth, int* yBorderWidth) +{ + if (windowStyle & WS_THICKFRAME) + { + *xBorderWidth = GetSystemMetrics(SM_CXSIZEFRAME); + *yBorderWidth = GetSystemMetrics(SM_CYSIZEFRAME); + } + else if (windowStyle & WS_DLGFRAME) + { + *xBorderWidth = GetSystemMetrics(SM_CXFIXEDFRAME); + *yBorderWidth = GetSystemMetrics(SM_CYFIXEDFRAME); + } + else + { + *xBorderWidth = 0; + *yBorderWidth = 0; + } +} + #if(WINVER >= 0x500) -typedef struct { +typedef struct +{ int *x; int *y; const char *name; -}m_proc_t ; +} m_proc_t; static BOOL CALLBACK m_proc(HMONITOR mon, HDC hdc, @@ -869,7 +1024,7 @@ static BOOL CALLBACK m_proc(HMONITOR mon, res=GetMonitorInfo(mon,(LPMONITORINFO)&info); if( res ) { - if( !strcmp(dp->name,info.szDevice) ) + if( strcmp(dp->name,info.szDevice)==0 ) { *(dp->x)=info.rcMonitor.left; *(dp->y)=info.rcMonitor.top; @@ -880,13 +1035,18 @@ static BOOL CALLBACK m_proc(HMONITOR mon, } /* - * this function is only used in fgOpenWindow. Currently it only sets - * its output parameters, if the DisplayName is set in fgDisplay - * (and if it is able to recognize the display) + * this function returns the origin of the screen identified by + * fgDisplay.DisplayName, and 0 otherwise. + * This is used in fgOpenWindow to open the gamemode window on the screen + * identified by the -display command line argument. The function should + * not be called otherwise. */ static void get_display_origin(int *xp,int *yp) { + *xp = 0; + *yp = 0; + if( fgDisplay.DisplayName ) { m_proc_t st; @@ -894,13 +1054,16 @@ static void get_display_origin(int *xp,int *yp) st.y=yp; st.name=fgDisplay.DisplayName; EnumDisplayMonitors(0,0,m_proc,(LPARAM)&st); - } + } } #else #pragma message( "-display parameter only works if compiled with WINVER >= 0x0500") static void get_display_origin(int *xp,int *yp) { + *xp = 0; + *yp = 0; + if( fgDisplay.DisplayName ) { fgWarning( "for working -display support FreeGLUT must be compiled with WINVER >= 0x0500"); @@ -1139,16 +1302,16 @@ void fgOpenWindow( SFG_Window* window, const char* title, #elif TARGET_HOST_MS_WINDOWS WNDCLASS wc; - DWORD flags; + DWORD flags = 0; DWORD exFlags = 0; ATOM atom; - int WindowStyle = 0; /* Grab the window class we have registered on glutInit(): */ atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc ); FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Info Not Found", "fgOpenWindow" ); + /* Determine window style flags*/ if( gameMode ) { FREEGLUT_INTERNAL_ERROR_EXIT ( window->Parent == NULL, @@ -1163,64 +1326,100 @@ void fgOpenWindow( SFG_Window* window, const char* title, } else { - int worig = w, horig = h; - -#if !defined(_WIN32_WCE) - if ( ( ! isSubWindow ) && ( ! window->IsMenu ) ) - { - /* - * Update the window dimensions, taking account of window - * decorations. "freeglut" is to create the window with the - * outside of its border at (x,y) and with dimensions (w,h). - */ - w += (GetSystemMetrics( SM_CXSIZEFRAME ) )*2; - h += (GetSystemMetrics( SM_CYSIZEFRAME ) )*2 + - GetSystemMetrics( SM_CYCAPTION ); - } -#endif /* defined(_WIN32_WCE) */ - - if( ! positionUse ) - { - x = CW_USEDEFAULT; - y = CW_USEDEFAULT; - } - /* setting State.Width/Height to call resize callback later */ - if( ! sizeUse ) - { - if( ! window->IsMenu ) - { - w = CW_USEDEFAULT; - h = CW_USEDEFAULT; - } - else /* fail safe - Windows can make a window of size (0, 0) */ - w = h = 300; /* default window size */ - window->State.Width = window->State.Height = -1; - } - else - { - window->State.Width = worig; - window->State.Height = horig; - } + flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; /* * There's a small difference between creating the top, child and - * game mode windows + * menu windows */ - flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; - if ( window->IsMenu ) { flags |= WS_POPUP; exFlags |= WS_EX_TOOLWINDOW; } -#if !defined(_WIN32_WCE) +#if defined(_WIN32_WCE) + /* no decorations for windows CE */ +#else + /* if this is not a subwindow (child), set its style based on the requested display mode */ else if( window->Parent == NULL ) - flags |= WS_OVERLAPPEDWINDOW; + if ( fgState.DisplayMode & GLUT_BORDERLESS ) + { + /* no window decorations needed */ + } + else if ( fgState.DisplayMode & GLUT_CAPTIONLESS ) + /* only window decoration is a border, no title bar or buttons */ + flags |= WS_DLGFRAME; + else + /* window decoration are a border, title bar and buttons. + * NB: we later query whether the window has a title bar or + * not by testing for the maximize button, as the test for + * WS_CAPTION can be true without the window having a title + * bar. This style WS_OVERLAPPEDWINDOW gives you a maximize + * button. */ + flags |= WS_OVERLAPPEDWINDOW; #endif else + /* subwindows always have no decoration, but are marked as a child window to the OS */ flags |= WS_CHILD; } + /* determine window size and position */ + if( gameMode ) + { + /* if in gamemode, query the origin of specified by the -display + * parameter command line (if any) and offset the upper-left corner + * of the window so we create the window on that screen. + * The -display argument doesn't do anything if not trying to enter + * gamemode. + */ + int xoff=0, yoff=0; + get_display_origin(&xoff,&yoff); + x += xoff; + y += yoff; + } + if( !positionUse ) + { + x = CW_USEDEFAULT; + y = CW_USEDEFAULT; + } + if( !sizeUse ) + { + if( ! window->IsMenu ) + { + w = CW_USEDEFAULT; + h = CW_USEDEFAULT; + } + else /* fail safe - Windows can make a window of size (0, 0) */ + w = h = 300; /* default window size */ + } + /* store requested client area width and height */ + window->State.Width = w; + window->State.Height = h; + +#if !defined(_WIN32_WCE) /* no decorations for windows CE */ + if( sizeUse ) + { + RECT windowRect; + /* + * Update the window dimensions, taking the window decorations + * into account. FreeGLUT is to create the window with the + * topleft outside corner at (x,y) and with client area + * dimensions (w,h). + * note: don't need to do this when w=h=CW_USEDEFAULT, so in the + * if( sizeUse ) here is convenient. + */ + windowRect.left = x; + windowRect.top = y; + windowRect.right = x+w; + windowRect.bottom = y+h; + + fghComputeWindowRectFromClientArea_UseStyle(flags,&windowRect,TRUE); + + w = windowRect.right - windowRect.left; + h = windowRect.bottom- windowRect.top; + } +#endif /* !defined(_WIN32_WCE) */ + #if defined(_WIN32_WCE) { wchar_t* wstr = fghWstrFromStr(title); @@ -1246,29 +1445,28 @@ void fgOpenWindow( SFG_Window* window, const char* title, UpdateWindow(window->Window.Handle); } #else - { - /* xoff and yoff are used to place window relative to current display */ - /* The operation of gamemode also depends on this */ - int xoff=0,yoff=0; - get_display_origin(&xoff,&yoff); - - window->Window.Handle = CreateWindowEx( - exFlags, - _T("FREEGLUT"), - title, - flags, - x+xoff, y+yoff, w, h, - (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle, - (HMENU) NULL, - fgDisplay.Instance, - (LPVOID) window - ); - } + window->Window.Handle = CreateWindowEx( + exFlags, + _T("FREEGLUT"), + title, + flags, + x, y, w, h, + (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle, + (HMENU) NULL, + fgDisplay.Instance, + (LPVOID) window + ); #endif /* defined(_WIN32_WCE) */ if( !( window->Window.Handle ) ) fgError( "Failed to create a window (%s)!", title ); +#if !defined(_WIN32_WCE) + /* Need to set requested style again, apparently Windows doesn't listen when requesting windows without title bar or borders */ + SetWindowLong(window->Window.Handle, GWL_STYLE, flags); + SetWindowPos(window->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); +#endif /* defined(_WIN32_WCE) */ + /* Make a menu window always on top - fix Feature Request 947118 */ if( window->IsMenu || gameMode ) SetWindowPos( @@ -1278,23 +1476,6 @@ void fgOpenWindow( SFG_Window* window, const char* title, SWP_NOMOVE | SWP_NOSIZE ); - /* Hack to remove the caption (title bar) and/or border - * and all the system menu controls. - */ - WindowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE); - if ( fgState.DisplayMode & GLUT_CAPTIONLESS ) - { - SetWindowLong ( window->Window.Handle, GWL_STYLE, - WindowStyle & ~(WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)); - } - else if ( fgState.DisplayMode & GLUT_BORDERLESS ) - { - SetWindowLong ( window->Window.Handle, GWL_STYLE, - WindowStyle & ~(WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_DLGFRAME | WS_SIZEBOX)); - } -/* SetWindowPos(window->Window.Handle, NULL, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); */ - /* Enable multitouch: additional flag TWF_FINETOUCH, TWF_WANTPALM */ #ifdef WM_TOUCH if (fghRegisterTouchWindow == (pRegisterTouchWindow)0xDEADBEEF) @@ -1680,7 +1861,7 @@ void FGAPIENTRY glutReshapeWindow( int width, int height ) if (glutGet(GLUT_FULL_SCREEN)) { /* Leave full screen state before resizing. */ - glutFullScreenToggle(); + glutLeaveFullScreen(); } fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE; @@ -1699,7 +1880,7 @@ void FGAPIENTRY glutPositionWindow( int x, int y ) if (glutGet(GLUT_FULL_SCREEN)) { /* Leave full screen state before moving. */ - glutFullScreenToggle(); + glutLeaveFullScreen(); } #if TARGET_HOST_POSIX_X11 @@ -1788,6 +1969,21 @@ void FGAPIENTRY glutFullScreen( void ) win = fgStructure.CurrentWindow; + if (win->Parent) + { + /* Child windows cannot be made fullscreen, consistent with GLUT's behavior + * Also, what would it mean for a child window to be fullscreen, given that it + * is confined to its parent? + */ + fgWarning("glutFullScreen called on a child window, ignoring..."); + return; + } + else if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==win->ID) + { + /* Ignore fullscreen call on GameMode window, those are always fullscreen already */ + return; + } + #if TARGET_HOST_POSIX_X11 if(!glutGet(GLUT_FULL_SCREEN)) { if(fghToggleFullscreen() != -1) { @@ -1799,34 +1995,50 @@ void FGAPIENTRY glutFullScreen( void ) if (glutGet(GLUT_FULL_SCREEN)) { - /* Leave full screen state before resizing. */ - glutFullScreenToggle(); + /* Leave full screen state before entering fullscreen again (resizing?) */ + glutLeaveFullScreen(); } { + DWORD s; RECT rect; + HMONITOR hMonitor; + MONITORINFO mi; - /* For fullscreen mode, force the top-left corner to 0,0 - * and adjust the window rectangle so that the client area - * covers the whole screen. + /* For fullscreen mode, first remove all window decoration + * and set style to popup so it will overlap the taskbar + * then force to maximize on the screen on which it has the most + * overlap. */ - rect.left = 0; - rect.top = 0; - get_display_origin(&rect.left,&rect.top); - rect.right = fgDisplay.ScreenWidth+rect.left; - rect.bottom = fgDisplay.ScreenHeight+rect.top; - - AdjustWindowRect ( &rect, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | - WS_CLIPCHILDREN, FALSE ); + + /* store current window rect */ + GetWindowRect( win->Window.Handle, &win->State.OldRect ); + + /* store current window style */ + win->State.OldStyle = s = GetWindowLong(win->Window.Handle, GWL_STYLE); + + /* remove decorations from style and add popup style*/ + s &= ~WS_OVERLAPPEDWINDOW; + s |= WS_POPUP; + SetWindowLong(win->Window.Handle, GWL_STYLE, s); + SetWindowPos(win->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + + /* For fullscreen mode, find the monitor that is covered the most + * by the window and get its rect as the resize target. + */ + hMonitor= MonitorFromRect(&win->State.OldRect, MONITOR_DEFAULTTONEAREST); + mi.cbSize = sizeof(mi); + GetMonitorInfo(hMonitor, &mi); + rect = mi.rcMonitor; /* + * then resize window * SWP_NOACTIVATE Do not activate the window * SWP_NOOWNERZORDER Do not change position in z-order - * SWP_NOSENDCHANGING Supress WM_WINDOWPOSCHANGING message + * SWP_NOSENDCHANGING Suppress WM_WINDOWPOSCHANGING message * SWP_NOZORDER Retains the current Z order (ignore 2nd param) */ - SetWindowPos( fgStructure.CurrentWindow->Window.Handle, HWND_TOP, rect.left, @@ -1843,6 +2055,51 @@ void FGAPIENTRY glutFullScreen( void ) } /* + * If we are fullscreen, resize the current window back to its original size + */ +void FGAPIENTRY glutLeaveFullScreen( void ) +{ + SFG_Window *win; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" ); + + win = fgStructure.CurrentWindow; + +#if TARGET_HOST_POSIX_X11 + if(glutGet(GLUT_FULL_SCREEN)) { + if(fghToggleFullscreen() != -1) { + win->State.IsFullscreen = GL_FALSE; + } + } + +#elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: what about WinCE */ + if (!glutGet(GLUT_FULL_SCREEN)) + { + /* nothing to do */ + return; + } + + /* restore style of window before making it fullscreen */ + SetWindowLong(win->Window.Handle, GWL_STYLE, win->State.OldStyle); + SetWindowPos(win->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + + /* Then resize */ + SetWindowPos(win->Window.Handle, + HWND_TOP, + win->State.OldRect.left, + win->State.OldRect.top, + win->State.OldRect.right - win->State.OldRect.left, + win->State.OldRect.bottom - win->State.OldRect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | + SWP_NOZORDER + ); + + win->State.IsFullscreen = GL_FALSE; +#endif +} + +/* * Toggle the window's full screen state. */ void FGAPIENTRY glutFullScreenToggle( void ) @@ -1859,8 +2116,10 @@ void FGAPIENTRY glutFullScreenToggle( void ) win->State.IsFullscreen = !win->State.IsFullscreen; } #elif TARGET_HOST_MS_WINDOWS - glutFullScreen(); - win->State.IsFullscreen = !win->State.IsFullscreen; + if (!win->State.IsFullscreen) + glutFullScreen(); + else + glutLeaveFullScreen(); #endif } diff --git a/src/freeglutdll.def b/src/freeglutdll.def index c538c0d..d46ecb6 100644 --- a/src/freeglutdll.def +++ b/src/freeglutdll.def @@ -139,6 +139,7 @@ EXPORTS glutGetProcAddress glutExit glutFullScreenToggle + glutLeaveFullScreen glutGetModeValues glutInitContextFlags glutInitContextVersion -- 1.7.10.4