typedef BOOL (WINAPI *pRegisterTouchWindow)(HWND,ULONG);
static pRegisterTouchWindow fghRegisterTouchWindow = (pRegisterTouchWindow)0xDEADBEEF;
#endif
-
-/*
- * 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).
- */
-extern void fghGetBorderWidth(const DWORD windowStyle, int* xBorderWidth, int* yBorderWidth);
+extern void fghNotifyWindowStatus(SFG_Window *window);
/*
}
+void fghGetDefaultWindowStyle(DWORD *flags)
+{
+ if ( fgState.DisplayMode & GLUT_BORDERLESS )
+ {
+ /* no window decorations needed, no-op */
+ }
+ 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. */
+ (*flags) |= WS_OVERLAPPEDWINDOW;
+}
+
+/* Get window style and extended window style of a FreeGLUT window
+ * If the window pointer or the window handle is NULL, a fully
+ * decorated window (caption and border) is assumed.
+ */
+void fghGetStyleFromWindow( const SFG_Window *window, DWORD *windowStyle, DWORD *windowExStyle )
+{
+ if (window && window->Window.Handle)
+ {
+ *windowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE);
+ *windowExStyle = GetWindowLong(window->Window.Handle, GWL_EXSTYLE);
+ }
+ else
+ {
+ *windowStyle = 0;
+ fghGetDefaultWindowStyle(windowStyle);
+ /* WindowExStyle==0 is fine/default, exStyle is currently only used for menu windows */
+ *windowExStyle = 0;
+ }
+}
/* Computes position of corners of window Rect (outer position including
* decorations) based on the provided client rect and based on the style
* (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 )
+void fghComputeWindowRectFromClientArea_UseStyle( RECT *clientRect, const DWORD windowStyle, const DWORD windowExStyle, BOOL posIsOutside )
{
- int xBorderWidth = 0, yBorderWidth = 0;
+ RECT windowRect = {0,0,0,0};
+ CopyRect(&windowRect,clientRect);
- /* 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 rect including non-client area */
+ AdjustWindowRectEx(&windowRect,windowStyle,FALSE,windowExStyle);
- /* 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);
+ /* Move window right and down by non-client area extent on left and top, if wanted */
if (posIsOutside)
{
- clientRect->right += xBorderWidth * 2;
- clientRect->bottom += yBorderWidth * 2;
- }
- else
- {
- clientRect->left -= xBorderWidth;
- clientRect->right += xBorderWidth;
- clientRect->top -= yBorderWidth;
- clientRect->bottom += yBorderWidth;
+ windowRect.right += clientRect->left-windowRect.left;
+ windowRect.bottom += clientRect->top -windowRect.top;
+ windowRect.left = clientRect->left;
+ windowRect.top = clientRect->top;
}
+
+ /* done, copy windowRect to output */
+ CopyRect(clientRect,&windowRect);
}
/* Computes position of corners of window Rect (outer position including
* (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 )
+void fghComputeWindowRectFromClientArea_QueryWindow( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside )
{
- DWORD windowStyle = 0;
+ DWORD windowStyle = 0, windowExStyle = 0;
+ fghGetStyleFromWindow(window,&windowStyle,&windowExStyle);
- 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;
- }
+ fghComputeWindowRectFromClientArea_UseStyle(clientRect, windowStyle, windowExStyle, posIsOutside);
}
/* 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.
+ * specified window. Output is position of corners of client area (drawable area) on the screen.
+ * Does not touch clientRect if window pointer or window handle is NULL.
+ * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable area.
*/
-RECT fghGetClientArea( const SFG_Window *window, BOOL wantPosOutside )
+void fghGetClientArea( RECT *clientRect, const SFG_Window *window )
{
- RECT windowRect = {0,0,0,0};
+ POINT topLeftClient = {0,0};
- freeglut_return_val_if_fail((window && window->Window.Handle),windowRect);
+ freeglut_return_if_fail((window && window->Window.Handle));
- /*
- * 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;
+ /* Get size of client rect */
+ GetClientRect(window->Window.Handle, clientRect);
+ /* Get position of top-left of client area on the screen */
+ ClientToScreen(window->Window.Handle,&topLeftClient);
+ /* Add top-left offset */
+ OffsetRect(clientRect,topLeftClient.x,topLeftClient.y);
}
-/* 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
#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 */
+ /* if this is not a subwindow (child), set its style based on the requested window decorations */
else if( window->Parent == NULL )
- 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;
+ fghGetDefaultWindowStyle(&flags);
#endif
else
/* subwindows always have no decoration, but are marked as a child window to the OS */
windowRect.right = x+w;
windowRect.bottom = y+h;
- fghComputeWindowRectFromClientArea_UseStyle(flags,&windowRect,TRUE);
+ fghComputeWindowRectFromClientArea_UseStyle(&windowRect,flags,exFlags,TRUE);
+ /* NB: w and h are now width and height of window including non-client area! */
w = windowRect.right - windowRect.left;
h = windowRect.bottom- windowRect.top;
}
if( !( window->Window.Handle ) )
fgError( "Failed to create a window (%s)!", title );
+ /* Store title */
+ {
+ window->State.pWState.WindowTitle = malloc (strlen(title) + 1);
+ strcpy(window->State.pWState.WindowTitle, 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);
ShowWindow( window->Window.Handle, SW_SHOW );
#else
ShowWindow( window->Window.Handle,
- fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW );
+ fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOWNORMAL );
#endif /* defined(_WIN32_WCE) */
- UpdateWindow( window->Window.Handle );
- ShowCursor( TRUE ); /* XXX Old comments say "hide cursor"! */
+ ShowCursor( TRUE );
+}
+
+
+void fgPlatformDisplayWindow ( SFG_Window *window )
+{
+ /* This immediately generates a WM_PAINT message upon which we call the display callbacks to redraw the window */
+ RedrawWindow(
+ window->Window.Handle, NULL, NULL,
+ RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW
+ );
+}
+
+
+void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height )
+{
+ RECT windowRect;
+
+ /*
+ * HACK HACK HACK:
+ * Before we do anything else, check if this is a newly created window
+ * that did not have its windowStatus/visibility func called yet
+ * we do that on first paint, but because I want to keep the paint
+ * operation as lean as possible, we do it here. The first paint
+ * goes together with a first resize call before the display callback
+ * is called, so this is just in time. Shitty place to do it, but this
+ * is the only reliable way I can think of to call the callback upon
+ * first draw of the window.
+ * More broadly speaking, I know this is an ugly hack, but I'm not sure
+ * what else to do about it. Depending on WM_ACTIVATE would not work
+ * as not all windows get this when you are opening multiple before the
+ * mainloop starts. WM_SHOWWINDOW looked like an interesting candidate,
+ * but it is generated and processed before glutCreate(Sub)Window
+ * returns, so no callback can yet be set on the window.
+ */
+ /* Check windowStatus/visibility func has been notified that window is visible (deferred from creation time to give user opportunity to register callbacks) */
+ if (!window->State.pWState.WindowFuncCalled)
+ {
+ fghNotifyWindowStatus(window);
+ window->State.pWState.WindowFuncCalled = GL_TRUE;
+ }
+
+ /*
+ * For windowed mode, get the current position of the
+ * window and resize taking the size of the frame
+ * decorations into account.
+ *
+ * Note on maximizing behavior of Windows: the resize borders are off
+ * the screen such that the client area extends all the way from the
+ * leftmost corner to the rightmost corner to maximize screen real
+ * estate. A caption is still shown however to allow interaction with
+ * the window controls. This is default behavior of Windows that
+ * FreeGLUT sticks with. To alter, one would have to check if
+ * WS_MAXIMIZE style is set when a resize event is triggered, and
+ * then manually correct the windowRect to put the borders back on
+ * screen.
+ */
+
+ /* "GetWindowRect" returns the pixel coordinates of the outside of the window */
+ GetWindowRect( window->Window.Handle, &windowRect );
+
+ /* 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(&windowRect,window,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;
+ fghGetClientArea( &parentRect, window->Parent );
+ OffsetRect(&windowRect,-parentRect.left,-parentRect.top);
+ }
+
+ /* Do the actual resizing */
+ SetWindowPos( window->Window.Handle,
+ HWND_TOP,
+ windowRect.left, windowRect.top,
+ windowRect.right - windowRect.left,
+ windowRect.bottom- windowRect.top,
+ SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
+ SWP_NOZORDER
+ );
+
+ /* Set new width and height so we can test for that in WM_SIZE message handler and don't do anything if not needed */
+ window->State.Width = width;
+ window->State.Height = height;
}
}
DestroyWindow( window->Window.Handle );
+
+ /* clean up copied title text(s) */
+ if (window->State.pWState.WindowTitle)
+ free(window->State.pWState.WindowTitle);
+ if (window->State.pWState.IconTitle)
+ free(window->State.pWState.IconTitle);
}
*/
void fgPlatformGlutIconifyWindow( void )
{
- ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_MINIMIZE );
+ SFG_Window *win = fgStructure.CurrentWindow;
+
+ /* Call on parent window */
+ while (win->Parent)
+ win = win->Parent;
+
+ /* Visibility status of window gets updated in the WM_SHOWWINDOW handler */
+ ShowWindow(win->Window.Handle, SW_MINIMIZE);
}
/*
#else
SetWindowText( fgStructure.CurrentWindow->Window.Handle, title );
#endif
+
+ /* Make copy of string to refer to later */
+ if (fgStructure.CurrentWindow->State.pWState.WindowTitle)
+ free(fgStructure.CurrentWindow->State.pWState.WindowTitle);
+ fgStructure.CurrentWindow->State.pWState.WindowTitle = malloc (strlen(title) + 1);
+ strcpy(fgStructure.CurrentWindow->State.pWState.WindowTitle, title);
}
/*
* Set the current window's iconified title
- * There really isn't a way to set the icon name separate from the
- * windows name in Win32, so, just set the windows name.
*/
void fgPlatformGlutSetIconTitle( const char* title )
{
-#ifdef _WIN32_WCE
- {
- wchar_t* wstr = fghWstrFromStr(title);
- SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr );
- free(wstr);
- }
-#else
- SetWindowText( fgStructure.CurrentWindow->Window.Handle, title );
-#endif
+ /* Make copy of string to refer to later */
+ if (fgStructure.CurrentWindow->State.pWState.IconTitle)
+ free(fgStructure.CurrentWindow->State.pWState.IconTitle);
+ fgStructure.CurrentWindow->State.pWState.IconTitle = malloc (strlen(title) + 1);
+ strcpy(fgStructure.CurrentWindow->State.pWState.IconTitle, title);
}
/*
{
#if(WINVER >= 0x0500) /* Windows 2000 or later */
- DWORD s;
RECT rect;
HMONITOR hMonitor;
MONITORINFO mi;
*/
- /* store current window rect */
- GetWindowRect( win->Window.Handle, &win->State.pWState.OldRect );
+ /* save current window rect, style, exstyle and maximized state */
+ win->State.pWState.OldMaximized = !!IsZoomed(win->Window.Handle);
+ if (win->State.pWState.OldMaximized)
+ /* We force the window into restored mode before going
+ * fullscreen because Windows doesn't seem to hide the
+ * taskbar if the window is in the maximized state.
+ */
+ SendMessage(win->Window.Handle, WM_SYSCOMMAND, SC_RESTORE, 0);
- /* store current window style */
- win->State.pWState.OldStyle = s = GetWindowLong(win->Window.Handle, GWL_STYLE);
+ GetWindowRect( win->Window.Handle, &win->State.pWState.OldRect );
+ win->State.pWState.OldStyle = GetWindowLong(win->Window.Handle, GWL_STYLE);
+ win->State.pWState.OldStyleEx = GetWindowLong(win->Window.Handle, GWL_EXSTYLE);
- /* 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);
+ /* remove decorations from style */
+ SetWindowLong(win->Window.Handle, GWL_STYLE,
+ win->State.pWState.OldStyle & ~(WS_CAPTION | WS_THICKFRAME));
+ SetWindowLong(win->Window.Handle, GWL_EXSTYLE,
+ win->State.pWState.OldStyleEx & ~(WS_EX_DLGMODALFRAME |
+ WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
/* For fullscreen mode, find the monitor that is covered the most
* by the window and get its rect as the resize target.
/* restore style of window before making it fullscreen */
SetWindowLong(win->Window.Handle, GWL_STYLE, win->State.pWState.OldStyle);
- SetWindowPos(win->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
+ SetWindowLong(win->Window.Handle, GWL_EXSTYLE, win->State.pWState.OldStyleEx);
/* Then resize */
SetWindowPos(win->Window.Handle,
SWP_NOZORDER
);
+ if (win->State.pWState.OldMaximized)
+ SendMessage(win->Window.Handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
+
win->State.IsFullscreen = GL_FALSE;
#endif
}