diff mupdf-source/thirdparty/freeglut/src/mswin/fg_main_mswin.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mupdf-source/thirdparty/freeglut/src/mswin/fg_main_mswin.c	Mon Sep 15 11:43:07 2025 +0200
@@ -0,0 +1,1859 @@
+/*
+ * fg_main_mswin.c
+ *
+ * The Windows-specific mouse cursor related stuff.
+ *
+ * Copyright (c) 2012 Stephen J. Baker. All Rights Reserved.
+ * Written by John F. Fay, <fayjf@sourceforge.net>
+ * Creation date: Sat Jan 21, 2012
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <GL/freeglut.h>
+#include "../fg_internal.h"
+
+#ifndef MAPVK_VK_TO_CHAR
+#define MAPVK_VK_TO_CHAR 2
+#endif
+
+extern void fghRedrawWindow ( SFG_Window *window );
+extern void fghRedrawWindowAndChildren ( SFG_Window *window );
+extern void fghOnReshapeNotify(SFG_Window *window, int width, int height, GLboolean forceNotify);
+extern void fghOnPositionNotify(SFG_Window *window, int x, int y, GLboolean forceNotify);
+extern void fghComputeWindowRectFromClientArea_QueryWindow( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside );
+extern void fghGetClientArea( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside );
+
+extern void fgNewWGLCreateContext( SFG_Window* window );
+extern GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
+                                     unsigned char layer_type );
+
+extern void fgPlatformCheckMenuDeactivate(HWND newFocusWnd);
+
+#ifdef WM_TOUCH
+typedef BOOL (WINAPI *pGetTouchInputInfo)(HTOUCHINPUT,UINT,PTOUCHINPUT,int);
+typedef BOOL (WINAPI *pCloseTouchInputHandle)(HTOUCHINPUT);
+static pGetTouchInputInfo fghGetTouchInputInfo = (pGetTouchInputInfo)0xDEADBEEF;
+static pCloseTouchInputHandle fghCloseTouchInputHandle = (pCloseTouchInputHandle)0xDEADBEEF;
+#endif
+
+#ifdef _WIN32_WCE
+typedef struct GXDisplayProperties GXDisplayProperties;
+typedef struct GXKeyList GXKeyList;
+#include <gx.h>
+
+typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int);
+typedef int (*GXOPENINPUT)();
+
+GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL;
+GXOPENINPUT GXOpenInput_ = NULL;
+
+struct GXKeyList gxKeyList;
+#endif /* _WIN32_WCE */
+
+#ifdef _DEBUG
+/* 
+ * WM_ message to string, for debugging
+ * This is taken from the 8.0 SDK, so Windows 8 API and everything earlier is included
+ */
+struct WM_MESSAGE_MAP
+{
+    UINT    nMsg;
+    LPCSTR  lpszMsg;
+};
+#define DEFINE_MESSAGE(wm){ wm, #wm }
+static struct WM_MESSAGE_MAP allMessages[] =
+{
+    DEFINE_MESSAGE(WM_NULL),
+    DEFINE_MESSAGE(WM_CREATE),
+    DEFINE_MESSAGE(WM_DESTROY),
+    DEFINE_MESSAGE(WM_MOVE),
+    DEFINE_MESSAGE(WM_SIZE),
+
+    DEFINE_MESSAGE(WM_ACTIVATE),
+    DEFINE_MESSAGE(WM_SETFOCUS),
+    DEFINE_MESSAGE(WM_KILLFOCUS),
+    DEFINE_MESSAGE(WM_ENABLE),
+    DEFINE_MESSAGE(WM_SETREDRAW),
+    DEFINE_MESSAGE(WM_SETTEXT),
+    DEFINE_MESSAGE(WM_GETTEXT),
+    DEFINE_MESSAGE(WM_GETTEXTLENGTH),
+    DEFINE_MESSAGE(WM_PAINT),
+    DEFINE_MESSAGE(WM_CLOSE),
+#   ifndef _WIN32_WCE
+        DEFINE_MESSAGE(WM_QUERYENDSESSION),
+        DEFINE_MESSAGE(WM_QUERYOPEN),
+        DEFINE_MESSAGE(WM_ENDSESSION),
+#   endif
+    DEFINE_MESSAGE(WM_QUIT),
+    DEFINE_MESSAGE(WM_ERASEBKGND),
+    DEFINE_MESSAGE(WM_SYSCOLORCHANGE),
+    DEFINE_MESSAGE(WM_SHOWWINDOW),
+    DEFINE_MESSAGE(WM_WININICHANGE),
+
+    DEFINE_MESSAGE(WM_DEVMODECHANGE),
+    DEFINE_MESSAGE(WM_ACTIVATEAPP),
+    DEFINE_MESSAGE(WM_FONTCHANGE),
+    DEFINE_MESSAGE(WM_TIMECHANGE),
+    DEFINE_MESSAGE(WM_CANCELMODE),
+    DEFINE_MESSAGE(WM_SETCURSOR),
+    DEFINE_MESSAGE(WM_MOUSEACTIVATE),
+    DEFINE_MESSAGE(WM_CHILDACTIVATE),
+    DEFINE_MESSAGE(WM_QUEUESYNC),
+
+    DEFINE_MESSAGE(WM_GETMINMAXINFO),
+
+    DEFINE_MESSAGE(WM_PAINTICON),
+    DEFINE_MESSAGE(WM_ICONERASEBKGND),
+    DEFINE_MESSAGE(WM_NEXTDLGCTL),
+    DEFINE_MESSAGE(WM_SPOOLERSTATUS),
+    DEFINE_MESSAGE(WM_DRAWITEM),
+    DEFINE_MESSAGE(WM_MEASUREITEM),
+    DEFINE_MESSAGE(WM_DELETEITEM),
+    DEFINE_MESSAGE(WM_VKEYTOITEM),
+    DEFINE_MESSAGE(WM_CHARTOITEM),
+    DEFINE_MESSAGE(WM_SETFONT),
+    DEFINE_MESSAGE(WM_GETFONT),
+    DEFINE_MESSAGE(WM_SETHOTKEY),
+    DEFINE_MESSAGE(WM_GETHOTKEY),
+    DEFINE_MESSAGE(WM_QUERYDRAGICON),
+    DEFINE_MESSAGE(WM_COMPAREITEM),
+#   if(WINVER >= 0x0500)
+#       ifndef _WIN32_WCE
+            DEFINE_MESSAGE(WM_GETOBJECT),
+    #   endif
+#   endif /* WINVER >= 0x0500 */
+    DEFINE_MESSAGE(WM_COMPACTING),
+    DEFINE_MESSAGE(WM_COMMNOTIFY),
+    DEFINE_MESSAGE(WM_WINDOWPOSCHANGING),
+    DEFINE_MESSAGE(WM_WINDOWPOSCHANGED),
+
+    DEFINE_MESSAGE(WM_POWER),
+
+    DEFINE_MESSAGE(WM_COPYDATA),
+    DEFINE_MESSAGE(WM_CANCELJOURNAL),
+
+#   if(WINVER >= 0x0400)
+        DEFINE_MESSAGE(WM_NOTIFY),
+        DEFINE_MESSAGE(WM_INPUTLANGCHANGEREQUEST),
+        DEFINE_MESSAGE(WM_INPUTLANGCHANGE),
+        DEFINE_MESSAGE(WM_TCARD),
+        DEFINE_MESSAGE(WM_HELP),
+        DEFINE_MESSAGE(WM_USERCHANGED),
+        DEFINE_MESSAGE(WM_NOTIFYFORMAT),
+
+        DEFINE_MESSAGE(WM_CONTEXTMENU),
+        DEFINE_MESSAGE(WM_STYLECHANGING),
+        DEFINE_MESSAGE(WM_STYLECHANGED),
+        DEFINE_MESSAGE(WM_DISPLAYCHANGE),
+        DEFINE_MESSAGE(WM_GETICON),
+        DEFINE_MESSAGE(WM_SETICON),
+#   endif /* WINVER >= 0x0400 */
+
+    DEFINE_MESSAGE(WM_NCCREATE),
+    DEFINE_MESSAGE(WM_NCDESTROY),
+    DEFINE_MESSAGE(WM_NCCALCSIZE),
+    DEFINE_MESSAGE(WM_NCHITTEST),
+    DEFINE_MESSAGE(WM_NCPAINT),
+    DEFINE_MESSAGE(WM_NCACTIVATE),
+    DEFINE_MESSAGE(WM_GETDLGCODE),
+#   ifndef _WIN32_WCE
+        DEFINE_MESSAGE(WM_SYNCPAINT),
+#   endif
+    DEFINE_MESSAGE(WM_NCMOUSEMOVE),
+    DEFINE_MESSAGE(WM_NCLBUTTONDOWN),
+    DEFINE_MESSAGE(WM_NCLBUTTONUP),
+    DEFINE_MESSAGE(WM_NCLBUTTONDBLCLK),
+    DEFINE_MESSAGE(WM_NCRBUTTONDOWN),
+    DEFINE_MESSAGE(WM_NCRBUTTONUP),
+    DEFINE_MESSAGE(WM_NCRBUTTONDBLCLK),
+    DEFINE_MESSAGE(WM_NCMBUTTONDOWN),
+    DEFINE_MESSAGE(WM_NCMBUTTONUP),
+    DEFINE_MESSAGE(WM_NCMBUTTONDBLCLK),
+
+
+
+#   if(_WIN32_WINNT >= 0x0500) && defined(WM_NCXBUTTONDOWN)
+        DEFINE_MESSAGE(WM_NCXBUTTONDOWN),
+        DEFINE_MESSAGE(WM_NCXBUTTONUP),
+        DEFINE_MESSAGE(WM_NCXBUTTONDBLCLK),
+#   endif /* _WIN32_WINNT >= 0x0500 */
+
+
+#   if(_WIN32_WINNT >= 0x0501)
+        DEFINE_MESSAGE(WM_INPUT_DEVICE_CHANGE),
+#   endif /* _WIN32_WINNT >= 0x0501 */
+
+#   if(_WIN32_WINNT >= 0x0501)
+        DEFINE_MESSAGE(WM_INPUT),
+#   endif /* _WIN32_WINNT >= 0x0501 */
+
+    DEFINE_MESSAGE(WM_KEYDOWN),
+    DEFINE_MESSAGE(WM_KEYUP),
+    DEFINE_MESSAGE(WM_CHAR),
+    DEFINE_MESSAGE(WM_DEADCHAR),
+    DEFINE_MESSAGE(WM_SYSKEYDOWN),
+    DEFINE_MESSAGE(WM_SYSKEYUP),
+    DEFINE_MESSAGE(WM_SYSCHAR),
+    DEFINE_MESSAGE(WM_SYSDEADCHAR),
+#   if(_WIN32_WINNT >= 0x0501)
+        DEFINE_MESSAGE(WM_UNICHAR),
+#   endif /* _WIN32_WINNT >= 0x0501 */
+
+#   if(WINVER >= 0x0400)
+        DEFINE_MESSAGE(WM_IME_STARTCOMPOSITION),
+        DEFINE_MESSAGE(WM_IME_ENDCOMPOSITION),
+        DEFINE_MESSAGE(WM_IME_COMPOSITION),
+        DEFINE_MESSAGE(WM_IME_KEYLAST),
+#   endif /* WINVER >= 0x0400 */
+
+    DEFINE_MESSAGE(WM_INITDIALOG),
+    DEFINE_MESSAGE(WM_COMMAND),
+    DEFINE_MESSAGE(WM_SYSCOMMAND),
+    DEFINE_MESSAGE(WM_TIMER),
+    DEFINE_MESSAGE(WM_HSCROLL),
+    DEFINE_MESSAGE(WM_VSCROLL),
+    DEFINE_MESSAGE(WM_INITMENU),
+    DEFINE_MESSAGE(WM_INITMENUPOPUP),
+#   if(WINVER >= 0x0601)
+        DEFINE_MESSAGE(WM_GESTURE),
+        DEFINE_MESSAGE(WM_GESTURENOTIFY),
+#   endif /* WINVER >= 0x0601 */
+    DEFINE_MESSAGE(WM_MENUSELECT),
+    DEFINE_MESSAGE(WM_MENUCHAR),
+    DEFINE_MESSAGE(WM_ENTERIDLE),
+#   if(WINVER >= 0x0500)
+#       ifndef _WIN32_WCE
+            DEFINE_MESSAGE(WM_MENURBUTTONUP),
+            DEFINE_MESSAGE(WM_MENUDRAG),
+            DEFINE_MESSAGE(WM_MENUGETOBJECT),
+            DEFINE_MESSAGE(WM_UNINITMENUPOPUP),
+            DEFINE_MESSAGE(WM_MENUCOMMAND),
+
+#           if(_WIN32_WINNT >= 0x0500) && defined(WM_CHANGEUISTATE)
+                DEFINE_MESSAGE(WM_CHANGEUISTATE),
+                DEFINE_MESSAGE(WM_UPDATEUISTATE),
+                DEFINE_MESSAGE(WM_QUERYUISTATE),
+#           endif /* _WIN32_WINNT >= 0x0500 */
+
+#       endif
+#   endif /* WINVER >= 0x0500 */
+
+    DEFINE_MESSAGE(WM_CTLCOLORMSGBOX),
+    DEFINE_MESSAGE(WM_CTLCOLOREDIT),
+    DEFINE_MESSAGE(WM_CTLCOLORLISTBOX),
+    DEFINE_MESSAGE(WM_CTLCOLORBTN),
+    DEFINE_MESSAGE(WM_CTLCOLORDLG),
+    DEFINE_MESSAGE(WM_CTLCOLORSCROLLBAR),
+    DEFINE_MESSAGE(WM_CTLCOLORSTATIC),
+#   define MN_GETHMENU                     0x01E1
+
+    DEFINE_MESSAGE(WM_MOUSEMOVE),
+    DEFINE_MESSAGE(WM_LBUTTONDOWN),
+    DEFINE_MESSAGE(WM_LBUTTONUP),
+    DEFINE_MESSAGE(WM_LBUTTONDBLCLK),
+    DEFINE_MESSAGE(WM_RBUTTONDOWN),
+    DEFINE_MESSAGE(WM_RBUTTONUP),
+    DEFINE_MESSAGE(WM_RBUTTONDBLCLK),
+    DEFINE_MESSAGE(WM_MBUTTONDOWN),
+    DEFINE_MESSAGE(WM_MBUTTONUP),
+    DEFINE_MESSAGE(WM_MBUTTONDBLCLK),
+#   if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
+        DEFINE_MESSAGE(WM_MOUSEWHEEL),
+#   endif
+#   if (_WIN32_WINNT >= 0x0500) && defined(WM_XBUTTONDOWN)
+        DEFINE_MESSAGE(WM_XBUTTONDOWN),
+        DEFINE_MESSAGE(WM_XBUTTONUP),
+        DEFINE_MESSAGE(WM_XBUTTONDBLCLK),
+#   endif
+#   if (_WIN32_WINNT >= 0x0600)
+        DEFINE_MESSAGE(WM_MOUSEHWHEEL),
+#   endif
+
+
+
+    DEFINE_MESSAGE(WM_PARENTNOTIFY),
+    DEFINE_MESSAGE(WM_ENTERMENULOOP),
+    DEFINE_MESSAGE(WM_EXITMENULOOP),
+
+#   if(WINVER >= 0x0400)
+        DEFINE_MESSAGE(WM_NEXTMENU),
+        DEFINE_MESSAGE(WM_SIZING),
+        DEFINE_MESSAGE(WM_CAPTURECHANGED),
+        DEFINE_MESSAGE(WM_MOVING),
+#   endif /* WINVER >= 0x0400 */
+
+#   if(WINVER >= 0x0400)
+        DEFINE_MESSAGE(WM_POWERBROADCAST),
+        DEFINE_MESSAGE(WM_DEVICECHANGE),
+#   endif /* WINVER >= 0x0400 */
+
+    DEFINE_MESSAGE(WM_MDICREATE),
+    DEFINE_MESSAGE(WM_MDIDESTROY),
+    DEFINE_MESSAGE(WM_MDIACTIVATE),
+    DEFINE_MESSAGE(WM_MDIRESTORE),
+    DEFINE_MESSAGE(WM_MDINEXT),
+    DEFINE_MESSAGE(WM_MDIMAXIMIZE),
+    DEFINE_MESSAGE(WM_MDITILE),
+    DEFINE_MESSAGE(WM_MDICASCADE),
+    DEFINE_MESSAGE(WM_MDIICONARRANGE),
+    DEFINE_MESSAGE(WM_MDIGETACTIVE),
+
+
+    DEFINE_MESSAGE(WM_MDISETMENU),
+    DEFINE_MESSAGE(WM_ENTERSIZEMOVE),
+    DEFINE_MESSAGE(WM_EXITSIZEMOVE),
+    DEFINE_MESSAGE(WM_DROPFILES),
+    DEFINE_MESSAGE(WM_MDIREFRESHMENU),
+
+#   if(WINVER >= 0x0602)
+        DEFINE_MESSAGE(WM_POINTERDEVICECHANGE),
+        DEFINE_MESSAGE(WM_POINTERDEVICEINRANGE),
+        DEFINE_MESSAGE(WM_POINTERDEVICEOUTOFRANGE),
+#   endif /* WINVER >= 0x0602 */
+
+#   if(WINVER >= 0x0601)
+        DEFINE_MESSAGE(WM_TOUCH),
+#   endif /* WINVER >= 0x0601 */
+
+#   if(WINVER >= 0x0602)
+        DEFINE_MESSAGE(WM_NCPOINTERUPDATE),
+        DEFINE_MESSAGE(WM_NCPOINTERDOWN),
+        DEFINE_MESSAGE(WM_NCPOINTERUP),
+        DEFINE_MESSAGE(WM_POINTERUPDATE),
+        DEFINE_MESSAGE(WM_POINTERDOWN),
+        DEFINE_MESSAGE(WM_POINTERUP),
+        DEFINE_MESSAGE(WM_POINTERENTER),
+        DEFINE_MESSAGE(WM_POINTERLEAVE),
+        DEFINE_MESSAGE(WM_POINTERACTIVATE),
+        DEFINE_MESSAGE(WM_POINTERCAPTURECHANGED),
+        DEFINE_MESSAGE(WM_TOUCHHITTESTING),
+        DEFINE_MESSAGE(WM_POINTERWHEEL),
+        DEFINE_MESSAGE(WM_POINTERHWHEEL),
+#   endif /* WINVER >= 0x0602 */
+
+
+#   if(WINVER >= 0x0400)
+        DEFINE_MESSAGE(WM_IME_SETCONTEXT),
+        DEFINE_MESSAGE(WM_IME_NOTIFY),
+        DEFINE_MESSAGE(WM_IME_CONTROL),
+        DEFINE_MESSAGE(WM_IME_COMPOSITIONFULL),
+        DEFINE_MESSAGE(WM_IME_SELECT),
+        DEFINE_MESSAGE(WM_IME_CHAR),
+#   endif /* WINVER >= 0x0400 */
+#   if(WINVER >= 0x0500)
+        DEFINE_MESSAGE(WM_IME_REQUEST),
+#   endif /* WINVER >= 0x0500 */
+#   if(WINVER >= 0x0400)
+        DEFINE_MESSAGE(WM_IME_KEYDOWN),
+        DEFINE_MESSAGE(WM_IME_KEYUP),
+#   endif /* WINVER >= 0x0400 */
+
+#   if((_WIN32_WINNT >= 0x0400) || (WINVER >= 0x0500))
+        DEFINE_MESSAGE(WM_MOUSEHOVER),
+        DEFINE_MESSAGE(WM_MOUSELEAVE),
+#   endif
+#   if(WINVER >= 0x0500) && defined(WM_NCMOUSEHOVER)
+        DEFINE_MESSAGE(WM_NCMOUSEHOVER),
+        DEFINE_MESSAGE(WM_NCMOUSELEAVE),
+#   endif /* WINVER >= 0x0500 */
+
+#   if(_WIN32_WINNT >= 0x0501)
+        DEFINE_MESSAGE(WM_WTSSESSION_CHANGE),
+#   endif /* _WIN32_WINNT >= 0x0501 */
+
+    DEFINE_MESSAGE(WM_CUT),
+    DEFINE_MESSAGE(WM_COPY),
+    DEFINE_MESSAGE(WM_PASTE),
+    DEFINE_MESSAGE(WM_CLEAR),
+    DEFINE_MESSAGE(WM_UNDO),
+    DEFINE_MESSAGE(WM_RENDERFORMAT),
+    DEFINE_MESSAGE(WM_RENDERALLFORMATS),
+    DEFINE_MESSAGE(WM_DESTROYCLIPBOARD),
+    DEFINE_MESSAGE(WM_DRAWCLIPBOARD),
+    DEFINE_MESSAGE(WM_PAINTCLIPBOARD),
+    DEFINE_MESSAGE(WM_VSCROLLCLIPBOARD),
+    DEFINE_MESSAGE(WM_SIZECLIPBOARD),
+    DEFINE_MESSAGE(WM_ASKCBFORMATNAME),
+    DEFINE_MESSAGE(WM_CHANGECBCHAIN),
+    DEFINE_MESSAGE(WM_HSCROLLCLIPBOARD),
+    DEFINE_MESSAGE(WM_QUERYNEWPALETTE),
+    DEFINE_MESSAGE(WM_PALETTEISCHANGING),
+    DEFINE_MESSAGE(WM_PALETTECHANGED),
+    DEFINE_MESSAGE(WM_HOTKEY),
+
+#   if(WINVER >= 0x0400)
+        DEFINE_MESSAGE(WM_PRINT),
+        DEFINE_MESSAGE(WM_PRINTCLIENT),
+#   endif /* WINVER >= 0x0400 */
+
+#   if(_WIN32_WINNT >= 0x0500) && defined(WM_APPCOMMAND)
+        DEFINE_MESSAGE(WM_APPCOMMAND),
+#   endif /* _WIN32_WINNT >= 0x0500 */
+
+#   if(_WIN32_WINNT >= 0x0501)
+        DEFINE_MESSAGE(WM_THEMECHANGED),
+#   endif /* _WIN32_WINNT >= 0x0501 */
+
+
+#   if(_WIN32_WINNT >= 0x0501)
+        DEFINE_MESSAGE(WM_CLIPBOARDUPDATE),
+#   endif /* _WIN32_WINNT >= 0x0501 */
+
+#   if(_WIN32_WINNT >= 0x0600)
+        DEFINE_MESSAGE(WM_DWMCOMPOSITIONCHANGED),
+        DEFINE_MESSAGE(WM_DWMNCRENDERINGCHANGED),
+        DEFINE_MESSAGE(WM_DWMCOLORIZATIONCOLORCHANGED),
+        DEFINE_MESSAGE(WM_DWMWINDOWMAXIMIZEDCHANGE),
+#   endif /* _WIN32_WINNT >= 0x0600 */
+
+#   if(_WIN32_WINNT >= 0x0601)
+        DEFINE_MESSAGE(WM_DWMSENDICONICTHUMBNAIL),
+        DEFINE_MESSAGE(WM_DWMSENDICONICLIVEPREVIEWBITMAP),
+#   endif /* _WIN32_WINNT >= 0x0601 */
+
+
+#   if(WINVER >= 0x0600)
+        DEFINE_MESSAGE(WM_GETTITLEBARINFOEX),
+#   endif /* WINVER >= 0x0600 */
+    { 0, NULL, }    /* end of message list */
+};
+#undef DEFINE_MESSAGE
+
+char* WMMsg2Str(DWORD dwMessage)
+{
+    struct WM_MESSAGE_MAP* pMapMsg = allMessages;
+    for (/*null*/; pMapMsg->lpszMsg != NULL; pMapMsg++)
+    {
+        if (pMapMsg->nMsg == dwMessage )
+        {
+            return (char *)pMapMsg->lpszMsg;
+        }
+    }
+    return "";
+}
+#endif /* _DEBUG */
+
+
+/* Get system time, taking special precautions against 32bit timer wrap.
+   We use timeGetTime and not GetTickCount because of its better stability,
+   and because we can increase its granularity (to 1 ms in
+   fgPlatformInitialize). For that reason we can't use GetTickCount64 which
+   wouldn't have the wrap issue.
+   Credit: this is based on code in glibc (https://mail.gnome.org/archives/commits-list/2011-November/msg04588.html)
+   */
+static fg_time_t lastTime32 = 0;
+static fg_time_t timeEpoch = 0;
+void fgPlatformInitSystemTime()
+{
+#if defined(_WIN32_WCE)
+    lastTime32 = GetTickCount();
+#else
+    lastTime32 = timeGetTime();
+#endif
+}
+fg_time_t fgPlatformSystemTime ( void )
+{
+    fg_time_t currTime32;
+#if defined(_WIN32_WCE)
+    currTime32 = GetTickCount();
+#else
+    currTime32 = timeGetTime();
+#endif
+    /* Check if we just wrapped */
+    if (currTime32 < lastTime32)
+        timeEpoch++;
+    
+    lastTime32 = currTime32;
+
+    return currTime32 | timeEpoch << 32;
+}
+
+extern char *fgClipboardBuffer[3];
+
+void fgPlatformSetClipboard(int selection, const char *text)
+{
+	if (selection == GLUT_PRIMARY)
+	{
+		free(fgClipboardBuffer[GLUT_PRIMARY]);
+		fgClipboardBuffer[GLUT_PRIMARY] = strdup(text);
+	}
+	else if (selection == GLUT_SECONDARY)
+	{
+		free(fgClipboardBuffer[GLUT_SECONDARY]);
+		fgClipboardBuffer[GLUT_SECONDARY] = strdup(text);
+	}
+	else if (selection == GLUT_CLIPBOARD && text)
+	{
+		int n = MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0);
+		if (n > 0)
+		{
+			HANDLE object = GlobalAlloc(0, n * sizeof(WCHAR));
+			if (object)
+			{
+				WCHAR *wtext = GlobalLock(object);
+				if (wtext)
+				{
+					MultiByteToWideChar(CP_UTF8, 0, text, -1, wtext, n);
+					GlobalUnlock(object);
+					if (OpenClipboard(NULL))
+					{
+						EmptyClipboard();
+						SetClipboardData(CF_UNICODETEXT, object);
+						CloseClipboard();
+						object = NULL; /* it is now owned by the system */
+					}
+				}
+				GlobalFree(object);
+			}
+		}
+	}
+}
+
+const char *fgPlatformGetClipboard(int selection)
+{
+	if (selection == GLUT_PRIMARY)
+		return fgClipboardBuffer[GLUT_PRIMARY];
+	if (selection == GLUT_SECONDARY)
+		return fgClipboardBuffer[GLUT_SECONDARY];
+	if (selection == GLUT_CLIPBOARD)
+	{
+		free(fgClipboardBuffer[GLUT_CLIPBOARD]);
+		fgClipboardBuffer[GLUT_CLIPBOARD] = NULL;
+		if (OpenClipboard(NULL))
+		{
+			HANDLE object = GetClipboardData(CF_UNICODETEXT);
+			if (object)
+			{
+				WCHAR *wtext = GlobalLock(object);
+				if (wtext)
+				{
+					int n = WideCharToMultiByte(CP_UTF8, 0, wtext, -1, NULL, 0, NULL, NULL);
+					if (n > 0)
+					{
+						char *text = malloc(n);
+						fgClipboardBuffer[GLUT_CLIPBOARD] = text;
+						WideCharToMultiByte(CP_UTF8, 0, wtext, -1, text, n, NULL, NULL);
+					}
+					GlobalUnlock(object);
+				}
+			}
+			CloseClipboard();
+		}
+		return fgClipboardBuffer[GLUT_CLIPBOARD];
+	}
+	return NULL;
+}
+
+void fgPlatformSleepForEvents( fg_time_t msec )
+{
+    MsgWaitForMultipleObjects( 0, NULL, FALSE, (DWORD) msec, QS_ALLINPUT );
+}
+
+
+void fgPlatformProcessSingleEvent ( void )
+{
+    MSG stMsg;
+
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" );
+
+    while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) )
+    {
+        if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 )
+        {
+            if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
+            {
+                fgDeinitialize( );
+                exit( 0 );
+            }
+            else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS )
+                fgState.ExecState = GLUT_EXEC_STATE_STOP;
+
+            return;
+        }
+
+        TranslateMessage( &stMsg );
+        DispatchMessage( &stMsg );
+    }
+}
+
+
+
+static void fghPlatformOnWindowStatusNotify(SFG_Window *window, GLboolean visState, GLboolean forceNotify)
+{
+    GLboolean notify = GL_FALSE;
+    SFG_Window* child;
+
+    if (window->State.Visible != visState)
+    {
+        window->State.Visible = visState;
+
+        /* If top level window (not a subwindow/child), and icon title text available, switch titles based on visibility state */
+        if (!window->Parent && window->State.pWState.IconTitle)
+        {
+            if (visState)
+                /* visible, set window title */
+                SetWindowText( window->Window.Handle, window->State.pWState.WindowTitle );
+            else
+                /* not visible, set icon title */
+                SetWindowText( window->Window.Handle, window->State.pWState.IconTitle );
+        }
+
+        notify = GL_TRUE;
+    }
+
+    if (notify || forceNotify)
+    {
+        SFG_Window *saved_window = fgStructure.CurrentWindow;
+
+        /* On win32 we only have two states, window displayed and window not displayed (iconified) 
+         * We map these to GLUT_FULLY_RETAINED and GLUT_HIDDEN respectively.
+         */
+        INVOKE_WCB( *window, WindowStatus, ( visState ? GLUT_FULLY_RETAINED:GLUT_HIDDEN ) );
+        fgSetWindow( saved_window );
+    }
+
+    /* Also set windowStatus/visibility state for children */
+    for( child = ( SFG_Window * )window->Children.First;
+         child;
+         child = ( SFG_Window * )child->Node.Next )
+    {
+        fghPlatformOnWindowStatusNotify(child, visState, GL_FALSE); /* No need to propagate forceNotify. Childs get this from their own INIT_WORK */
+    }
+}
+
+void fgPlatformMainLoopPreliminaryWork ( void )
+{
+    /* no-op */
+}
+
+
+/*
+ * Determine a GLUT modifier mask based on MS-WINDOWS system info.
+ */
+static int fgPlatformGetModifiers (void)
+{
+    return
+        ( ( ( GetKeyState( VK_LSHIFT   ) < 0 ) ||
+            ( GetKeyState( VK_RSHIFT   ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) |
+        ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) ||
+            ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL  : 0 ) |
+        ( ( ( GetKeyState( VK_LMENU    ) < 0 ) ||
+            ( GetKeyState( VK_RMENU    ) < 0 )) ? GLUT_ACTIVE_ALT   : 0 );
+}
+
+/* Check whether a button (VK_*BUTTON) is currently depressed. Returns
+ * non-zero (not necessarily 1) if yes. */
+static SHORT fgGetKeyState(int vKey)
+{
+    /* MSDN says: "If the high-order bit is 1, the key is down; otherwise, it is up". */
+    return GetKeyState(vKey) & 0xFF00;
+}
+
+static LRESULT fghWindowProcKeyPress(SFG_Window *window, UINT uMsg, GLboolean keydown, WPARAM wParam, LPARAM lParam)
+{
+    static unsigned char lControl = 0, lShift = 0, lAlt = 0,
+                         rControl = 0, rShift = 0, rAlt = 0;
+
+    int keypress = -1;
+    
+    /* if keydown, check for repeat */
+    /* If repeat is globally switched off, it cannot be switched back on per window.
+     * But if it is globally switched on, it can be switched off per window. This matches
+     * GLUT's behavior on X11, but not Nate Robbins' win32 GLUT, as he didn't implement the
+     * global state switch.
+     */
+    if( keydown && ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
+        return 1;
+    
+    /* Remember the current modifiers state so user can query it from their callback */
+    fgState.Modifiers = fgPlatformGetModifiers( );
+
+    /* Convert the Win32 keystroke codes to GLUTtish way */
+#   define FG_KEY(a,b) case a: keypress = b; break;
+
+    switch( wParam )
+    {
+        FG_KEY( VK_F1,     GLUT_KEY_F1        );
+        FG_KEY( VK_F2,     GLUT_KEY_F2        );
+        FG_KEY( VK_F3,     GLUT_KEY_F3        );
+        FG_KEY( VK_F4,     GLUT_KEY_F4        );
+        FG_KEY( VK_F5,     GLUT_KEY_F5        );
+        FG_KEY( VK_F6,     GLUT_KEY_F6        );
+        FG_KEY( VK_F7,     GLUT_KEY_F7        );
+        FG_KEY( VK_F8,     GLUT_KEY_F8        );
+        FG_KEY( VK_F9,     GLUT_KEY_F9        );
+        FG_KEY( VK_F10,    GLUT_KEY_F10       );
+        FG_KEY( VK_F11,    GLUT_KEY_F11       );
+        FG_KEY( VK_F12,    GLUT_KEY_F12       );
+        FG_KEY( VK_PRIOR,  GLUT_KEY_PAGE_UP   );
+        FG_KEY( VK_NEXT,   GLUT_KEY_PAGE_DOWN );
+        FG_KEY( VK_HOME,   GLUT_KEY_HOME      );
+        FG_KEY( VK_END,    GLUT_KEY_END       );
+        FG_KEY( VK_LEFT,   GLUT_KEY_LEFT      );
+        FG_KEY( VK_UP,     GLUT_KEY_UP        );
+        FG_KEY( VK_RIGHT,  GLUT_KEY_RIGHT     );
+        FG_KEY( VK_DOWN,   GLUT_KEY_DOWN      );
+        FG_KEY( VK_INSERT, GLUT_KEY_INSERT    );
+
+    /* handle control, alt and shift. For GLUT, we want to distinguish between left and right presses.
+     * The VK_L* & VK_R* left and right Alt, Ctrl and Shift virtual keys are however only used as parameters to GetAsyncKeyState() and GetKeyState()
+     * so when we get an alt, shift or control keypress here, we manually check whether it was the left or the right
+     */
+#define FG_KEY_EVENT(winKey,glutKey,keyStateVar)\
+    if (!keyStateVar && fgGetKeyState ( winKey ))\
+    {\
+        keypress   = glutKey;\
+        keyStateVar = 1;\
+    }\
+    else if (keyStateVar && !fgGetKeyState ( winKey ))\
+    {\
+        keypress   = glutKey;\
+        keyStateVar = 0;\
+    }
+    case VK_CONTROL:
+        FG_KEY_EVENT(VK_LCONTROL,GLUT_KEY_CTRL_L,lControl);
+        FG_KEY_EVENT(VK_RCONTROL,GLUT_KEY_CTRL_R,rControl);
+        break;
+    case VK_SHIFT:
+        FG_KEY_EVENT(VK_LSHIFT,GLUT_KEY_SHIFT_L,lShift);
+        FG_KEY_EVENT(VK_RSHIFT,GLUT_KEY_SHIFT_R,rShift);
+        break;
+    case VK_MENU:
+        FG_KEY_EVENT(VK_LMENU,GLUT_KEY_ALT_L,lAlt);
+        FG_KEY_EVENT(VK_RMENU,GLUT_KEY_ALT_R,rAlt);
+        break;
+#undef KEY_EVENT
+
+    case VK_DELETE:
+        /* The delete key should be treated as an ASCII keypress: */
+        if (keydown)
+        {
+            INVOKE_WCB( *window, KeyboardDown,
+                        ( 127, window->State.MouseX, window->State.MouseY )
+            );
+            INVOKE_WCB( *window, KeyboardExt,
+                        ( 127, window->State.MouseX, window->State.MouseY )
+            );
+            INVOKE_WCB( *window, Keyboard,
+                        ( 127, window->State.MouseX, window->State.MouseY )
+            );
+        }
+        else
+            INVOKE_WCB( *window, KeyboardUp,
+                        ( 127, window->State.MouseX, window->State.MouseY )
+            );
+        break;
+
+#if !defined(_WIN32_WCE)
+    default:
+        /* Mapped characters are handled with the WM_CHAR message. Handle low-level ASCII press/release callbacks here. */
+        {
+            UINT ascii = (UINT)MapVirtualKey((UINT)wParam, MAPVK_VK_TO_CHAR);
+            if (ascii >= 32 && ascii < 256)
+            {
+				/* Always send lowercase (unshifted) values */
+				if (ascii >= 'A' && ascii <= 'Z')
+						ascii = ascii - 'A' + 'a';
+                if (keydown)
+                    INVOKE_WCB(*window, KeyboardDown, ((unsigned char)ascii, window->State.MouseX, window->State.MouseY) );
+                else
+                    INVOKE_WCB(*window, KeyboardUp, ((unsigned char)ascii, window->State.MouseX, window->State.MouseY) );
+            }
+        }
+#endif
+    }
+
+#if defined(_WIN32_WCE)
+    if(keydown && !(lParam & 0x40000000)) /* Prevent auto-repeat */
+    {
+        if(wParam==(unsigned)gxKeyList.vkRight)
+            keypress = GLUT_KEY_RIGHT;
+        else if(wParam==(unsigned)gxKeyList.vkLeft)
+            keypress = GLUT_KEY_LEFT;
+        else if(wParam==(unsigned)gxKeyList.vkUp)
+            keypress = GLUT_KEY_UP;
+        else if(wParam==(unsigned)gxKeyList.vkDown)
+            keypress = GLUT_KEY_DOWN;
+        else if(wParam==(unsigned)gxKeyList.vkA)
+            keypress = GLUT_KEY_F1;
+        else if(wParam==(unsigned)gxKeyList.vkB)
+            keypress = GLUT_KEY_F2;
+        else if(wParam==(unsigned)gxKeyList.vkC)
+            keypress = GLUT_KEY_F3;
+        else if(wParam==(unsigned)gxKeyList.vkStart)
+            keypress = GLUT_KEY_F4;
+    }
+#endif
+    
+    if( keypress != -1 )
+        if (keydown)
+            INVOKE_WCB( *window, Special,
+                        ( keypress,
+                            window->State.MouseX, window->State.MouseY )
+            );
+        else
+            INVOKE_WCB( *window, SpecialUp,
+                        ( keypress,
+                            window->State.MouseX, window->State.MouseY )
+            );
+
+    fgState.Modifiers = INVALID_MODIFIERS;
+
+    /* SYSKEY events should be sent to default window proc for system to handle them */
+    if (uMsg==WM_SYSKEYDOWN || uMsg==WM_SYSKEYUP)
+        return DefWindowProc( window->Window.Handle, uMsg, wParam, lParam );
+    else
+        return 1;
+}
+
+SFG_Window* fghWindowUnderCursor(SFG_Window *window)
+{
+    /* Check if the current window that the mouse is over is a child window
+     * of the window the message was sent to. Some events only sent to main window,
+     * and when handling some messages, we need to make sure that we process
+     * callbacks on the child window instead. This mirrors how GLUT does things.
+     * returns either the original window or the found child.
+     */
+    if (window && window->Children.First)   /* This window has childs */
+    {
+        HWND hwnd;
+        SFG_Window* child_window;
+
+        /* Get mouse position at time of message */
+        DWORD mouse_pos_dw = GetMessagePos();
+        POINT mouse_pos;
+        mouse_pos.x = GET_X_LPARAM(mouse_pos_dw);
+        mouse_pos.y = GET_Y_LPARAM(mouse_pos_dw);
+        ScreenToClient( window->Window.Handle, &mouse_pos );
+        
+        hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
+        if (hwnd && hwnd!=window->Window.Handle)   /* can be NULL if mouse outside parent by the time we get here, or can be same as parent if we didn't find a child */
+        {
+            child_window = fgWindowByHandle(hwnd);
+            if (child_window)    /* Verify we got a FreeGLUT window */
+            {
+                /* ChildWindowFromPoint only searches immediate children, so search again to see if actually in grandchild or further descendant */
+                window = fghWindowUnderCursor(child_window);
+            }
+        }
+    }
+
+    return window;
+}
+
+/*
+ * The window procedure for handling Win32 events
+ */
+LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+    SFG_Window *window;
+    LRESULT lRet = 1;
+    static int setCaptureActive = 0;
+
+    FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
+
+    window = fgWindowByHandle( hWnd );
+
+    if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
+      return DefWindowProc( hWnd, uMsg, wParam, lParam );
+
+    /* printf ( "Window %3d message %s (<%04x>) %12d %12d\n", window?window->ID:0,
+             WMMsg2Str(uMsg), uMsg, wParam, lParam ); */
+
+    switch( uMsg )
+    {
+    case WM_CREATE:
+        /* The window structure is passed as the creation structure parameter... */
+        window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
+        FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
+                                       "fgPlatformWindowProc" );
+
+        window->Window.Handle = hWnd;
+        window->Window.pContext.Device = GetDC( hWnd );
+        if( window->IsMenu )
+        {
+            unsigned int current_DisplayMode = fgState.DisplayMode;
+            fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
+#if !defined(_WIN32_WCE)
+            fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
+#endif
+            fgState.DisplayMode = current_DisplayMode;
+
+            if( fgStructure.MenuContext )
+                wglMakeCurrent( window->Window.pContext.Device,
+                                fgStructure.MenuContext->MContext
+                );
+            else
+            {
+                fgStructure.MenuContext =
+                    (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
+                fgStructure.MenuContext->MContext =
+                    wglCreateContext( window->Window.pContext.Device );
+            }
+
+            /* window->Window.Context = wglGetCurrentContext ();   */
+            window->Window.Context = wglCreateContext( window->Window.pContext.Device );
+        }
+        else
+        {
+#if !defined(_WIN32_WCE)
+            fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
+#endif
+
+            if( ! fgState.UseCurrentContext )
+                window->Window.Context =
+                    wglCreateContext( window->Window.pContext.Device );
+            else
+            {
+                window->Window.Context = wglGetCurrentContext( );
+                if( ! window->Window.Context )
+                    window->Window.Context =
+                        wglCreateContext( window->Window.pContext.Device );
+            }
+
+#if !defined(_WIN32_WCE)
+            fgNewWGLCreateContext( window );
+#endif
+        }
+
+        ReleaseDC( window->Window.Handle, window->Window.pContext.Device );
+
+#if defined(_WIN32_WCE)
+        /* Take over button handling */
+        {
+            HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
+            if (dxDllLib)
+            {
+                GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
+                GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
+            }
+
+            if(GXOpenInput_)
+                (*GXOpenInput_)();
+            if(GXGetDefaultKeys_)
+                gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
+        }
+
+#endif /* defined(_WIN32_WCE) */
+        break;
+
+    case WM_SIZE:
+        /* printf("WM_SIZE (ID: %i): wParam: %i, new size: %ix%i \n",window->ID,wParam,LOWORD(lParam),HIWORD(lParam)); */
+
+        /* Update visibility state of the window */
+        if (wParam==SIZE_MINIMIZED)
+            fghPlatformOnWindowStatusNotify(window,GL_FALSE,GL_FALSE);
+        else if (wParam==SIZE_RESTORED && !window->State.Visible)
+            fghPlatformOnWindowStatusNotify(window,GL_TRUE,GL_FALSE);
+
+        /* Check window visible, we don't want do anything when we get a WM_SIZE because the user or glutIconifyWindow minimized the window */
+        if( window->State.Visible )
+        {
+            int width, height;
+#if defined(_WIN32_WCE)
+            width  = HIWORD(lParam);
+            height = LOWORD(lParam);
+#else
+            width  = LOWORD(lParam);
+            height = HIWORD(lParam);
+#endif /* defined(_WIN32_WCE) */
+            
+            /* Update state and call callback, if there was a change */
+            fghOnReshapeNotify(window, width, height, GL_FALSE);
+        }
+
+        /* according to docs, should return 0 */
+        lRet = 0;
+        break;
+
+    case WM_SIZING:
+        {
+            /* User resize-dragging the window, call reshape callback and
+             * force redisplay so display keeps running during dragging.
+             * Screen still wont update when not moving the cursor though...
+             */
+            RECT rect;
+            /* PRECT prect = (PRECT) lParam;
+               printf("WM_SIZING: nc-area: %i,%i\n",prect->right-prect->left,prect->bottom-prect->top); */
+            /* Get client area, the rect in lParam is including non-client area. */
+            fghGetClientArea(&rect,window,FALSE);
+
+            /* We'll get a WM_SIZE as well, but as state has
+             * already been updated here, the fghOnReshapeNotify
+             * in the handler for that message doesn't do anything.
+             */
+            fghOnReshapeNotify(window, rect.right-rect.left, rect.bottom-rect.top, GL_FALSE);
+
+            /* Now directly call the drawing function to update
+             * window and window's childs.
+             * This mimics the WM_PAINT messages that are received during
+             * resizing. Note that we don't have a WM_MOVING handler
+             * as move-dragging doesn't generate WM_MOVE or WM_PAINT
+             * messages until the mouse is released.
+             */
+            fghRedrawWindowAndChildren(window);
+        }
+
+        /* according to docs, should return TRUE */
+        lRet = TRUE;
+        break;
+
+    case WM_MOVE:
+        {
+            /* Check window is minimized, we don't want to call the position callback when the user or glutIconifyWindow minimized the window */
+            if (!IsIconic(window->Window.Handle))
+            {
+                RECT windowRect;
+                
+                /* lParam contains coordinates of top-left of client area.
+                 * Get top-left of non-client area of window, matching coordinates of
+                 * glutInitPosition and glutPositionWindow, but not those of 
+                 * glutGet(GLUT_WINDOW_X) and glutGet(GLUT_WINDOW_Y), which return
+                 * top-left of client area.
+                 */
+                GetWindowRect( window->Window.Handle, &windowRect );
+            
+                if (window->Parent)
+                {
+                    /* For child window, we should return relative to upper-left
+                     * of parent's client area.
+                     */
+                    POINT topleft;
+                    topleft.x = windowRect.left;
+                    topleft.y = windowRect.top;
+
+                    ScreenToClient(window->Parent->Window.Handle,&topleft);
+                    windowRect.left = topleft.x;
+                    windowRect.top  = topleft.y;
+                }
+
+                /* Update state and call callback, if there was a change */
+                fghOnPositionNotify(window, windowRect.left, windowRect.top, GL_FALSE);
+            }
+        }
+
+        /* according to docs, should return 0 */
+        lRet = 0;
+        break;
+
+    case WM_SETFOCUS:
+        /*printf("WM_SETFOCUS: %p\n", window );*/
+        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
+
+        SetActiveWindow( window->Window.Handle );
+        UpdateWindow ( hWnd );
+
+        break;
+
+    case WM_KILLFOCUS:
+        /*printf("WM_KILLFOCUS: %p\n", window ); */
+        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
+
+        /* Check if there are any open menus that need to be closed */
+        fgPlatformCheckMenuDeactivate((HWND)wParam);
+        break;
+
+    case WM_MOUSEACTIVATE:
+        /* Clicks should not activate the menu.
+         * Especially important when clicking on a menu's submenu item which has no effect.
+         */
+        /*printf("WM_MOUSEACTIVATE\n");*/
+        if (window->IsMenu)
+            lRet = MA_NOACTIVATEANDEAT;
+        else
+            lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
+        break;
+
+    case WM_NCLBUTTONDOWN:
+    case WM_NCMBUTTONDOWN:
+    case WM_NCRBUTTONDOWN:
+        {
+            SFG_Menu *menu;
+            if (fgState.ActiveMenus && (menu = fgGetActiveMenu()))
+                /* user clicked non-client area of window while a menu is open. Close menu */
+                fgDeactivateMenu(menu->ParentWindow);
+
+            /* and always pass to DefWindowProc */
+            lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
+        }
+        break;
+
+#if 0
+    case WM_ACTIVATE:
+        /* printf("WM_ACTIVATE: %x (ID: %i) %d %d\n",lParam, window->ID, HIWORD(wParam), LOWORD(wParam)); */
+        if (LOWORD(wParam) != WA_INACTIVE)
+        {
+/*            printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
+                   window->State.Cursor ); */
+            fgSetCursor( window, window->State.Cursor );
+        }
+
+        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
+        break;
+#endif
+
+#if _MSC_VER > 1400
+    case WM_SETCURSOR:
+/*      printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
+        if( LOWORD( lParam ) == HTCLIENT )
+        {
+            if (!window->State.pWState.MouseTracking)
+            {
+                TRACKMOUSEEVENT tme;
+
+                /* Cursor just entered window, set cursor look */ 
+                fgSetCursor ( window, window->State.Cursor ) ;
+
+                /* If an EntryFunc callback is specified by the user, also
+                 * invoke that callback and start mouse tracking so that
+                 * we get a WM_MOUSELEAVE message
+                 */
+                if (FETCH_WCB( *window, Entry ))
+                {
+                    SFG_Window* saved_window = fgStructure.CurrentWindow;
+                    INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
+                    fgSetWindow(saved_window);
+
+                    tme.cbSize = sizeof(TRACKMOUSEEVENT);
+                    tme.dwFlags = TME_LEAVE;
+                    tme.hwndTrack = window->Window.Handle;
+                    TrackMouseEvent(&tme);
+
+                    window->State.pWState.MouseTracking = TRUE;
+                }
+            }
+        }
+        else
+            /* Only pass non-client WM_SETCURSOR to DefWindowProc, or we get WM_SETCURSOR on parents of children as well */
+            lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
+        break;
+#endif
+
+    case WM_MOUSELEAVE:
+        {
+            /* NB: This message is only received when a EntryFunc callback
+             * is specified by the user, as that is the only condition under
+             * which mouse tracking is setup in WM_SETCURSOR handler above
+             */
+            SFG_Window* saved_window = fgStructure.CurrentWindow;
+            INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
+            fgSetWindow(saved_window);
+
+            window->State.pWState.MouseTracking = FALSE;
+            lRet = 0;   /* As per docs, must return zero */
+        }
+        break;
+
+    case WM_SHOWWINDOW:
+        /* printf("WM_SHOWWINDOW, shown? %i, source: %i\n",wParam,lParam); */
+        if (wParam)
+        {
+            fghPlatformOnWindowStatusNotify(window, GL_TRUE, GL_FALSE);
+            window->State.WorkMask |= GLUT_DISPLAY_WORK;
+        }
+        else
+        {
+            fghPlatformOnWindowStatusNotify(window, GL_FALSE, GL_FALSE);
+            window->State.WorkMask &= ~GLUT_DISPLAY_WORK;
+        }
+        break;
+
+    case WM_PAINT:
+    {
+        RECT rect;
+        
+        /* As per docs, upon receiving WM_PAINT, first check if the update region is not empty before you call BeginPaint */
+        if (GetUpdateRect(hWnd,&rect,FALSE))
+        {
+            /* Dummy begin/end paint to validate rect that needs
+             * redrawing, then signal that a redisplay is needed.
+             * This allows us full control about when we do any
+             * redrawing, and is the same as what original GLUT
+             * does.
+             */
+            PAINTSTRUCT ps;
+            BeginPaint( hWnd, &ps );
+            EndPaint( hWnd, &ps );
+
+            window->State.WorkMask |= GLUT_DISPLAY_WORK;
+        }
+        lRet = 0;   /* As per docs, should return 0 */
+    }
+    break;
+
+    case WM_CLOSE:
+        fgDestroyWindow ( window );
+        if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
+            PostQuitMessage(0);
+        break;
+
+    case WM_DESTROY:
+        /*
+         * The window already got destroyed, so don't bother with it.
+         */
+        return 0;
+
+    case WM_MOUSEMOVE:
+    {
+        /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */
+#if defined(_WIN32_WCE)
+        window->State.MouseX = 320-HIWORD( lParam );    /* XXX: Docs say x should be loword and y hiword? */
+        window->State.MouseY = LOWORD( lParam );
+#else
+        window->State.MouseX = GET_X_LPARAM( lParam );
+        window->State.MouseY = GET_Y_LPARAM( lParam );
+#endif /* defined(_WIN32_WCE) */
+        /* Restrict to [-32768, 32767] to match X11 behaviour       */
+        /* See comment in "freeglut_developer" mailing list 10/4/04 */
+        if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
+        if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
+
+        if ( window->ActiveMenu )
+        {
+            fgUpdateMenuHighlight( window->ActiveMenu );
+            break;
+        }
+
+        fgState.Modifiers = fgPlatformGetModifiers( );
+
+        if( ( wParam & MK_LBUTTON ) ||
+            ( wParam & MK_MBUTTON ) ||
+            ( wParam & MK_RBUTTON ) )
+            INVOKE_WCB( *window, Motion, ( window->State.MouseX,
+                                           window->State.MouseY ) );
+        else
+            INVOKE_WCB( *window, Passive, ( window->State.MouseX,
+                                            window->State.MouseY ) );
+
+        fgState.Modifiers = INVALID_MODIFIERS;
+    }
+    break;
+
+    case WM_LBUTTONDOWN:
+    case WM_MBUTTONDOWN:
+    case WM_RBUTTONDOWN:
+    case WM_LBUTTONUP:
+    case WM_MBUTTONUP:
+    case WM_RBUTTONUP:
+    {
+        GLboolean pressed = GL_TRUE;
+        int button;
+
+        /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */
+#if defined(_WIN32_WCE)
+        window->State.MouseX = 320-HIWORD( lParam );    /* XXX: Docs say x should be loword and y hiword? */
+        window->State.MouseY = LOWORD( lParam );
+#else
+        window->State.MouseX = GET_X_LPARAM( lParam );
+        window->State.MouseY = GET_Y_LPARAM( lParam );
+#endif /* defined(_WIN32_WCE) */
+
+        /* Restrict to [-32768, 32767] to match X11 behaviour       */
+        /* See comment in "freeglut_developer" mailing list 10/4/04 */
+        if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
+        if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
+
+        switch( uMsg )
+        {
+        case WM_LBUTTONDOWN:
+            pressed = GL_TRUE;
+            button = GLUT_LEFT_BUTTON;
+            break;
+        case WM_MBUTTONDOWN:
+            pressed = GL_TRUE;
+            button = GLUT_MIDDLE_BUTTON;
+            break;
+        case WM_RBUTTONDOWN:
+            pressed = GL_TRUE;
+            button = GLUT_RIGHT_BUTTON;
+            break;
+        case WM_LBUTTONUP:
+            pressed = GL_FALSE;
+            button = GLUT_LEFT_BUTTON;
+            break;
+        case WM_MBUTTONUP:
+            pressed = GL_FALSE;
+            button = GLUT_MIDDLE_BUTTON;
+            break;
+        case WM_RBUTTONUP:
+            pressed = GL_FALSE;
+            button = GLUT_RIGHT_BUTTON;
+            break;
+        default:
+            pressed = GL_FALSE;
+            button = -1;
+            break;
+        }
+
+#if !defined(_WIN32_WCE)
+        if( GetSystemMetrics( SM_SWAPBUTTON ) )
+        {
+            if( button == GLUT_LEFT_BUTTON )
+                button = GLUT_RIGHT_BUTTON;
+            else
+                if( button == GLUT_RIGHT_BUTTON )
+                    button = GLUT_LEFT_BUTTON;
+        }
+#endif /* !defined(_WIN32_WCE) */
+
+        if( button == -1 )
+            return DefWindowProc( hWnd, uMsg, lParam, wParam );
+
+        /*
+         * Do not execute the application's mouse callback if a menu
+         * is hooked to this button.  In that case an appropriate
+         * private call should be generated.
+         */
+        if( fgCheckActiveMenu( window, button, pressed,
+                               window->State.MouseX, window->State.MouseY ) )
+            break;
+
+        /* Set capture so that the window captures all the mouse messages
+         *
+         * The mouse is not released from the window until all buttons have
+         * been released, even if the user presses a button in another window.
+         * This is consistent with the behavior on X11.
+         */
+        if ( pressed == GL_TRUE )
+        {
+            if (!setCaptureActive)
+                SetCapture ( window->Window.Handle ) ;
+            setCaptureActive = 1; /* Set to false in WM_CAPTURECHANGED handler */
+        }
+        else if (!fgGetKeyState(VK_LBUTTON) && !fgGetKeyState(VK_MBUTTON) && !fgGetKeyState(VK_RBUTTON))
+          /* Make sure all mouse buttons are released before releasing capture */
+          ReleaseCapture () ;
+
+        if( ! FETCH_WCB( *window, Mouse ) )
+            break;
+
+        fgSetWindow( window );
+        fgState.Modifiers = fgPlatformGetModifiers( );
+
+        INVOKE_WCB(
+            *window, Mouse,
+            ( button,
+              pressed ? GLUT_DOWN : GLUT_UP,
+              window->State.MouseX,
+              window->State.MouseY
+            )
+        );
+
+        fgState.Modifiers = INVALID_MODIFIERS;
+
+        /* As per docs, should return zero */
+        lRet = 0;
+    }
+    break;
+
+    case WM_MOUSEWHEEL:
+    {
+        int wheel_number = 0;   /* Only one scroll wheel on windows */
+#if defined(_WIN32_WCE)
+        int modkeys = LOWORD(wParam); 
+        short ticks = (short)HIWORD(wParam);
+        /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first:
+        xPos = LOWORD(lParam);  -- straight from docs, not consistent with mouse nutton and mouse motion above (which i think is wrong)
+        yPos = HIWORD(lParam);
+        */
+#else
+        /* int modkeys = GET_KEYSTATE_WPARAM( wParam ); */
+        short ticks = HIWORD( wParam );
+        /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first:
+        window->State.MouseX = GET_X_LPARAM( lParam );
+        window->State.MouseY = GET_Y_LPARAM( lParam );
+        */
+#endif /* defined(_WIN32_WCE) */
+
+        window = fghWindowUnderCursor(window);
+
+		fgState.MouseWheelTicks += ticks;
+        if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
+		{
+			int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
+
+            if( ! FETCH_WCB( *window, MouseWheel ) &&
+                ! FETCH_WCB( *window, Mouse ) )
+                break;
+
+            fgSetWindow( window );
+            fgState.Modifiers = fgPlatformGetModifiers( );
+
+            while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
+			{
+                if( FETCH_WCB( *window, MouseWheel ) )
+                    INVOKE_WCB( *window, MouseWheel,
+                                ( wheel_number,
+                                  direction,
+                                  window->State.MouseX,
+                                  window->State.MouseY
+                                )
+                    );
+                else  /* No mouse wheel, call the mouse button callback twice */
+				{
+                    /*
+                     * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
+                     *  "    "   one                     +1 to 5, -1 to 6, ...
+                     *
+                     * XXX The below assumes that you have no more than 3 mouse
+                     * XXX buttons.  Sorry.
+                     */
+                    int button = wheel_number * 2 + 3;
+                    if( direction < 0 )
+                        ++button;
+                    INVOKE_WCB( *window, Mouse,
+                                ( button, GLUT_DOWN,
+                                  window->State.MouseX, window->State.MouseY )
+                    );
+                    INVOKE_WCB( *window, Mouse,
+                                ( button, GLUT_UP,
+                                  window->State.MouseX, window->State.MouseY )
+                    );
+				}
+
+				fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
+			}
+
+            fgState.Modifiers = INVALID_MODIFIERS;
+		}
+        /* Per docs, should return zero */
+        lRet = 0;
+    }
+    break ;
+
+    case WM_SYSKEYDOWN:
+    case WM_KEYDOWN:
+    {
+        window = fghWindowUnderCursor(window);
+        lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
+    }
+    break;
+
+    case WM_SYSKEYUP:
+    case WM_KEYUP:
+    {
+        window = fghWindowUnderCursor(window);
+        lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
+    }
+    break;
+
+    case WM_SYSCHAR:
+    case WM_CHAR:
+    {
+      window = fghWindowUnderCursor(window);
+
+      if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
+            break;
+
+        fgState.Modifiers = fgPlatformGetModifiers( );
+        INVOKE_WCB( *window, KeyboardExt,
+                ( (int)wParam, window->State.MouseX, window->State.MouseY )
+        );
+        if (wParam < 256)
+            INVOKE_WCB( *window, Keyboard,
+                    ( (unsigned char)wParam, window->State.MouseX, window->State.MouseY )
+            );
+        fgState.Modifiers = INVALID_MODIFIERS;
+    }
+    break;
+
+    case WM_CAPTURECHANGED:
+        if (!lParam || !fgWindowByHandle((HWND)lParam))
+            /* Capture released or capture taken by non-FreeGLUT window */
+            setCaptureActive = 0;
+        /* Docs advise a redraw */
+        InvalidateRect( hWnd, NULL, GL_FALSE );
+        UpdateWindow(hWnd);
+        lRet = 0;   /* Per docs, should return zero */
+        break;
+
+#if !defined(_WIN32_WCE)
+    case WM_SYNCPAINT:  /* 0x0088 */
+        /* Another window has moved, need to update this one */
+        window->State.WorkMask |= GLUT_DISPLAY_WORK;
+        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
+        /* Help screen says this message must be passed to "DefWindowProc" */
+        break;
+
+    case WM_DISPLAYCHANGE: /* 0x007E */
+        /* The system display resolution/depth has changed */
+        fgDisplay.ScreenWidth = LOWORD(lParam);
+        fgDisplay.ScreenHeight = HIWORD(lParam);
+        break;
+
+    case WM_SYSCOMMAND :  /* 0x0112 */
+        {
+          /*
+           * We have received a system command message.  Try to act on it.
+           * The commands are passed in through the "wParam" parameter:
+           * The least significant digit seems to be which edge of the window
+           * is being used for a resize event:
+           *     4  3  5
+           *     1     2
+           *     7  6  8
+           * Congratulations and thanks to Richard Rauch for figuring this out..
+           */
+            switch ( wParam & 0xfff0 )
+            {
+            case SC_SIZE       :
+                break ;
+
+            case SC_MOVE       :
+                break ;
+
+            case SC_MINIMIZE   :
+                /* User has clicked on the "-" to minimize the window */
+                /* Turning off the visibility is handled in WM_SIZE handler */
+
+                break ;
+
+            case SC_MAXIMIZE   :
+                break ;
+
+            case SC_NEXTWINDOW :
+                break ;
+
+            case SC_PREVWINDOW :
+                break ;
+
+            case SC_CLOSE      :
+                /* Followed very closely by a WM_CLOSE message */
+                break ;
+
+            case SC_VSCROLL    :
+                break ;
+
+            case SC_HSCROLL    :
+                break ;
+
+            case SC_MOUSEMENU  :
+                break ;
+
+            case SC_KEYMENU    :
+                break ;
+
+            case SC_ARRANGE    :
+                break ;
+
+            case SC_RESTORE    :
+                break ;
+
+            case SC_TASKLIST   :
+                break ;
+
+            case SC_SCREENSAVE :
+                break ;
+
+            case SC_HOTKEY     :
+                break ;
+
+#if(WINVER >= 0x0400)
+            case SC_DEFAULT    :
+                break ;
+
+            case SC_MONITORPOWER    :
+                break ;
+
+            case SC_CONTEXTHELP    :
+                break ;
+#endif /* WINVER >= 0x0400 */
+
+            default:
+#if _DEBUG
+                fgWarning( "Unknown wParam type 0x%x", wParam );
+#endif
+                break;
+            }
+        }
+#endif /* !defined(_WIN32_WCE) */
+
+        /* We need to pass the message on to the operating system as well */
+        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
+        break;
+
+#ifdef WM_TOUCH
+	/* handle multi-touch messages */
+	case WM_TOUCH:
+	{
+		unsigned int numInputs = (unsigned int)wParam;
+		unsigned int i = 0;
+		TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
+
+		if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
+		    fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
+		    fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
+		}
+
+		if (!fghGetTouchInputInfo) { 
+			free( (void*)ti );
+			break;
+		}
+
+		if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
+			/* Handle each contact point */
+			for (i = 0; i < numInputs; ++i ) {
+
+				POINT tp;
+				tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
+				tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
+				ScreenToClient( hWnd, &tp );
+
+				ti[i].dwID = ti[i].dwID * 2;
+
+				if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
+					INVOKE_WCB( *window, MultiEntry,  ( ti[i].dwID, GLUT_ENTERED ) );
+					INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
+				} else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
+					INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
+				} else if (ti[i].dwFlags & TOUCHEVENTF_UP)   { 
+					INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
+					INVOKE_WCB( *window, MultiEntry,  ( ti[i].dwID, GLUT_LEFT ) );
+				}
+			}
+		}
+		fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
+		free( (void*)ti );
+		lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
+		break;
+	}
+#endif
+    default:
+        /* Handle unhandled messages */
+        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
+        break;
+    }
+
+    return lRet;
+}
+
+
+/* deal with work list items */
+void fgPlatformInitWork(SFG_Window* window)
+{
+    RECT windowRect;
+
+    /* Notify windowStatus/visibility */
+    fghPlatformOnWindowStatusNotify(window, window->State.Visible, GL_TRUE);
+
+    /* get and notify window's position */
+    GetWindowRect(window->Window.Handle,&windowRect);
+    fghOnPositionNotify(window, windowRect.left, windowRect.top, GL_TRUE);
+
+    /* get and notify window's size */
+    GetClientRect(window->Window.Handle,&windowRect);
+    fghOnReshapeNotify(window, windowRect.right-windowRect.left, windowRect.bottom-windowRect.top, GL_TRUE);
+}
+
+/* On windows we can position, resize and change z order at the same time */
+void fgPlatformPosResZordWork(SFG_Window* window, unsigned int workMask)
+{
+    UINT flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER;
+    HWND insertAfter = HWND_TOP;
+    RECT clientRect;
+
+#if !defined(_WIN32_WCE) /* FIXME: what about WinCE */
+    if (workMask & GLUT_FULL_SCREEN_WORK)
+    {
+        /* This asks us to toggle fullscreen mode */
+        flags |= SWP_FRAMECHANGED;
+
+        if (window->State.IsFullscreen)
+        {
+            /* If we are fullscreen, resize the current window back to its original size */
+            /* printf("OldRect %i,%i to %i,%i\n",window->State.pWState.OldRect.left,window->State.pWState.OldRect.top,window->State.pWState.OldRect.right,window->State.pWState.OldRect.bottom); */
+
+            /* restore style of window before making it fullscreen */
+            SetWindowLong(window->Window.Handle, GWL_STYLE, window->State.pWState.OldStyle);
+            SetWindowLong(window->Window.Handle, GWL_EXSTYLE, window->State.pWState.OldStyleEx);
+
+            /* Then set up resize/reposition, unless user already queued up reshape/position work */
+            if (!(workMask & GLUT_POSITION_WORK))
+            {
+                workMask |= GLUT_POSITION_WORK;
+                window->State.DesiredXpos   = window->State.pWState.OldRect.left;
+                window->State.DesiredYpos   = window->State.pWState.OldRect.top;
+            }
+            if (!(workMask & GLUT_SIZE_WORK))
+            {
+                workMask |= GLUT_SIZE_WORK;
+                window->State.DesiredWidth  = window->State.pWState.OldRect.right  - window->State.pWState.OldRect.left;
+                window->State.DesiredHeight = window->State.pWState.OldRect.bottom - window->State.pWState.OldRect.top;
+            }
+                
+            /* We'll finish off the fullscreen operation below after the other GLUT_POSITION_WORK|GLUT_SIZE_WORK|GLUT_ZORDER_WORK */
+        }
+        else
+        {
+            /* we are currently not fullscreen, go to fullscreen:
+                * remove window decoration and then maximize
+                */
+            RECT rect;
+            HMONITOR hMonitor;
+            MONITORINFO mi;
+        
+            /* save current window rect, style, exstyle and maximized state */
+            window->State.pWState.OldMaximized = !!IsZoomed(window->Window.Handle);
+            if (window->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(window->Window.Handle, WM_SYSCOMMAND, SC_RESTORE, 0);
+
+            fghGetClientArea( &window->State.pWState.OldRect, window, GL_TRUE );
+            window->State.pWState.OldStyle   = GetWindowLong(window->Window.Handle, GWL_STYLE);
+            window->State.pWState.OldStyleEx = GetWindowLong(window->Window.Handle, GWL_EXSTYLE);
+
+            /* remove decorations from style */
+            SetWindowLong(window->Window.Handle, GWL_STYLE,
+                            window->State.pWState.OldStyle & ~(WS_CAPTION | WS_THICKFRAME));
+            SetWindowLong(window->Window.Handle, GWL_EXSTYLE,
+                            window->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.
+	            */
+            hMonitor= MonitorFromWindow(window->Window.Handle, MONITOR_DEFAULTTONEAREST);
+            mi.cbSize = sizeof(mi);
+            GetMonitorInfo(hMonitor, &mi);
+            rect = mi.rcMonitor;
+
+            /* then setup window resize, overwriting other work queued on the window */
+            window->State.WorkMask |= GLUT_POSITION_WORK | GLUT_SIZE_WORK;
+            window->State.WorkMask &= ~GLUT_ZORDER_WORK;
+            window->State.DesiredXpos   = rect.left;
+            window->State.DesiredYpos   = rect.top;
+            window->State.DesiredWidth  = rect.right  - rect.left;
+            window->State.DesiredHeight = rect.bottom - rect.top;
+        }
+    }
+#endif /*!defined(_WIN32_WCE) */
+
+    /* Now deal with normal position, reshape and z order requests (some might have been set when handling GLUT_FULLSCREEN_WORK above */
+    {
+        /* get rect describing window's current position and size, 
+            * in screen coordinates and in FreeGLUT format
+            * (size (right-left, bottom-top) is client area size, top and left
+            * are outside of window including decorations).
+            */
+        fghGetClientArea( &clientRect, window, TRUE );
+
+        if (workMask & GLUT_POSITION_WORK)
+        {
+            flags &= ~SWP_NOMOVE;
+                
+            /* Move rect so that top-left is at requested position */
+            /* This also automatically makes sure that child window requested coordinates are relative
+                * to top-left of parent's client area (needed input for SetWindowPos on child windows),
+                * so no need to further correct rect for child windows below (childs don't have decorations either).
+                */
+            OffsetRect(&clientRect,window->State.DesiredXpos-clientRect.left,window->State.DesiredYpos-clientRect.top);
+        }
+        if (workMask & GLUT_SIZE_WORK)
+        {
+            flags &= ~SWP_NOSIZE;
+                
+            /* 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.
+                */
+
+            /* Set new size of window, WxH specify client area */
+            clientRect.right    = clientRect.left + window->State.DesiredWidth;
+            clientRect.bottom   = clientRect.top  + window->State.DesiredHeight;
+        }
+        if (workMask & GLUT_ZORDER_WORK)
+        {
+            flags &= ~SWP_NOZORDER;
+
+            /* Could change this to push it down or up one window at a time with some
+                * more code using GetWindow with GW_HWNDPREV and GW_HWNDNEXT.
+                * What would be consistent with X11? Win32 GLUT does what we do here...
+                */
+            if (window->State.DesiredZOrder < 0)
+                insertAfter = HWND_BOTTOM;
+        }
+    }
+
+    /* Adjust for window decorations
+        * Child windows don't have decoration, so no need to correct
+        */
+    if (!window->Parent)
+        /* get the window rect from this to feed to SetWindowPos, correct for window decorations */
+        fghComputeWindowRectFromClientArea_QueryWindow(&clientRect,window,TRUE);
+    
+    /* Do the requested positioning, moving, and z order push/pop. */
+    SetWindowPos( window->Window.Handle,
+                    insertAfter,
+                    clientRect.left, clientRect.top,
+                    clientRect.right - clientRect.left,
+                    clientRect.bottom- clientRect.top,
+                    flags
+    );
+
+    /* Finish off the fullscreen operation we were doing, if any */
+    if (workMask & GLUT_FULL_SCREEN_WORK)
+    {
+        if (window->State.IsFullscreen)
+        {
+            /* leaving fullscreen, restore maximized state, if any */
+            if (window->State.pWState.OldMaximized)
+                SendMessage(window->Window.Handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
+
+            window->State.IsFullscreen = GL_FALSE;
+        }
+        else
+            window->State.IsFullscreen = GL_TRUE;
+    }
+}
+
+
+void fgPlatformVisibilityWork(SFG_Window* window)
+{
+    /* Visibility status of window gets updated in the WM_SHOWWINDOW and WM_SIZE handlers */
+    int cmdShow = 0;
+    SFG_Window *win = window;
+    switch (window->State.DesiredVisibility)
+    {
+    case DesireHiddenState:
+        cmdShow = SW_HIDE;
+        break;
+    case DesireIconicState:
+        cmdShow = SW_MINIMIZE;
+        /* Call on top-level window */
+        while (win->Parent)
+            win = win->Parent;
+        break;
+    case DesireNormalState:
+        if (win->IsMenu && !fgStructure.GameModeWindow)
+            cmdShow = SW_SHOWNA;    /* Just show, don't activate window if its a menu. Only exception is when there is a gamemode window as the menu would pop under it when we do this... */
+        else
+            cmdShow = SW_SHOW;
+        break;
+    }
+
+    ShowWindow( win->Window.Handle, cmdShow );
+}