update CMake file so that it will generate proper _WIN32_WINNT and WINVER definitions...
[freeglut] / src / mswin / fg_main_mswin.c
index 7e43eaf..20a635b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * freeglut_main_mswin.c
+ * fg_main_mswin.c
  *
  * The Windows-specific mouse cursor related stuff.
  *
@@ -184,7 +184,7 @@ static struct WM_MESSAGE_MAP allMessages[] =
 
 
 
-#   if(_WIN32_WINNT >= 0x0500)
+#   if(_WIN32_WINNT >= 0x0500) && defined(WM_NCXBUTTONDOWN)
         DEFINE_MESSAGE(WM_NCXBUTTONDOWN),
         DEFINE_MESSAGE(WM_NCXBUTTONUP),
         DEFINE_MESSAGE(WM_NCXBUTTONDBLCLK),
@@ -241,7 +241,7 @@ static struct WM_MESSAGE_MAP allMessages[] =
             DEFINE_MESSAGE(WM_UNINITMENUPOPUP),
             DEFINE_MESSAGE(WM_MENUCOMMAND),
 
-#           if(_WIN32_WINNT >= 0x0500)
+#           if(_WIN32_WINNT >= 0x0500) && defined(WM_CHANGEUISTATE)
                 DEFINE_MESSAGE(WM_CHANGEUISTATE),
                 DEFINE_MESSAGE(WM_UPDATEUISTATE),
                 DEFINE_MESSAGE(WM_QUERYUISTATE),
@@ -272,7 +272,7 @@ static struct WM_MESSAGE_MAP allMessages[] =
 #   if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
         DEFINE_MESSAGE(WM_MOUSEWHEEL),
 #   endif
-#   if (_WIN32_WINNT >= 0x0500)
+#   if (_WIN32_WINNT >= 0x0500) && defined(WM_XBUTTONDOWN)
         DEFINE_MESSAGE(WM_XBUTTONDOWN),
         DEFINE_MESSAGE(WM_XBUTTONUP),
         DEFINE_MESSAGE(WM_XBUTTONDBLCLK),
@@ -364,7 +364,7 @@ static struct WM_MESSAGE_MAP allMessages[] =
         DEFINE_MESSAGE(WM_MOUSEHOVER),
         DEFINE_MESSAGE(WM_MOUSELEAVE),
 #   endif
-#   if(WINVER >= 0x0500)
+#   if(WINVER >= 0x0500) && defined(WM_NCMOUSEHOVER)
         DEFINE_MESSAGE(WM_NCMOUSEHOVER),
         DEFINE_MESSAGE(WM_NCMOUSELEAVE),
 #   endif /* WINVER >= 0x0500 */
@@ -398,7 +398,7 @@ static struct WM_MESSAGE_MAP allMessages[] =
         DEFINE_MESSAGE(WM_PRINTCLIENT),
 #   endif /* WINVER >= 0x0400 */
 
-#   if(_WIN32_WINNT >= 0x0500)
+#   if(_WIN32_WINNT >= 0x0500) && defined(WM_APPCOMMAND)
         DEFINE_MESSAGE(WM_APPCOMMAND),
 #   endif /* _WIN32_WINNT >= 0x0500 */
 
@@ -578,6 +578,14 @@ static int fgPlatformGetModifiers (void)
             ( 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,
@@ -598,60 +606,60 @@ static LRESULT fghWindowProcKeyPress(SFG_Window *window, UINT uMsg, GLboolean ke
     fgState.Modifiers = fgPlatformGetModifiers( );
 
     /* Convert the Win32 keystroke codes to GLUTtish way */
-#   define KEY(a,b) case a: keypress = b; break;
+#   define FG_KEY(a,b) case a: keypress = b; break;
 
     switch( wParam )
     {
-        KEY( VK_F1,     GLUT_KEY_F1        );
-        KEY( VK_F2,     GLUT_KEY_F2        );
-        KEY( VK_F3,     GLUT_KEY_F3        );
-        KEY( VK_F4,     GLUT_KEY_F4        );
-        KEY( VK_F5,     GLUT_KEY_F5        );
-        KEY( VK_F6,     GLUT_KEY_F6        );
-        KEY( VK_F7,     GLUT_KEY_F7        );
-        KEY( VK_F8,     GLUT_KEY_F8        );
-        KEY( VK_F9,     GLUT_KEY_F9        );
-        KEY( VK_F10,    GLUT_KEY_F10       );
-        KEY( VK_F11,    GLUT_KEY_F11       );
-        KEY( VK_F12,    GLUT_KEY_F12       );
-        KEY( VK_PRIOR,  GLUT_KEY_PAGE_UP   );
-        KEY( VK_NEXT,   GLUT_KEY_PAGE_DOWN );
-        KEY( VK_HOME,   GLUT_KEY_HOME      );
-        KEY( VK_END,    GLUT_KEY_END       );
-        KEY( VK_LEFT,   GLUT_KEY_LEFT      );
-        KEY( VK_UP,     GLUT_KEY_UP        );
-        KEY( VK_RIGHT,  GLUT_KEY_RIGHT     );
-        KEY( VK_DOWN,   GLUT_KEY_DOWN      );
-        KEY( VK_INSERT, GLUT_KEY_INSERT    );
+        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 ASYNC_KEY_EVENT(winKey,glutKey,keyStateVar)\
-    if (!keyStateVar && GetAsyncKeyState ( winKey ))\
+#define FG_KEY_EVENT(winKey,glutKey,keyStateVar)\
+    if (!keyStateVar && fgGetKeyState ( winKey ))\
     {\
         keypress   = glutKey;\
         keyStateVar = 1;\
     }\
-    else if (keyStateVar && !GetAsyncKeyState ( winKey ))\
+    else if (keyStateVar && !fgGetKeyState ( winKey ))\
     {\
         keypress   = glutKey;\
         keyStateVar = 0;\
     }
     case VK_CONTROL:
-        ASYNC_KEY_EVENT(VK_LCONTROL,GLUT_KEY_CTRL_L,lControl);
-        ASYNC_KEY_EVENT(VK_RCONTROL,GLUT_KEY_CTRL_R,rControl);
+        FG_KEY_EVENT(VK_LCONTROL,GLUT_KEY_CTRL_L,lControl);
+        FG_KEY_EVENT(VK_RCONTROL,GLUT_KEY_CTRL_R,rControl);
         break;
     case VK_SHIFT:
-        ASYNC_KEY_EVENT(VK_LSHIFT,GLUT_KEY_SHIFT_L,lShift);
-        ASYNC_KEY_EVENT(VK_RSHIFT,GLUT_KEY_SHIFT_R,rShift);
+        FG_KEY_EVENT(VK_LSHIFT,GLUT_KEY_SHIFT_L,lShift);
+        FG_KEY_EVENT(VK_RSHIFT,GLUT_KEY_SHIFT_R,rShift);
         break;
     case VK_MENU:
-        ASYNC_KEY_EVENT(VK_LMENU,GLUT_KEY_ALT_L,lAlt);
-        ASYNC_KEY_EVENT(VK_RMENU,GLUT_KEY_ALT_R,rAlt);
+        FG_KEY_EVENT(VK_LMENU,GLUT_KEY_ALT_L,lAlt);
+        FG_KEY_EVENT(VK_RMENU,GLUT_KEY_ALT_R,rAlt);
         break;
-#undef ASYNC_KEY_EVENT
+#undef KEY_EVENT
 
     case VK_DELETE:
         /* The delete key should be treated as an ASCII keypress: */
@@ -744,7 +752,9 @@ SFG_Window* fghWindowUnderCursor(SFG_Window *window)
 
         /* Get mouse position at time of message */
         DWORD mouse_pos_dw = GetMessagePos();
-        POINT mouse_pos = {GET_X_LPARAM(mouse_pos_dw), GET_Y_LPARAM(mouse_pos_dw)};
+        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);
@@ -893,9 +903,9 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
              * force redisplay so display keeps running during dragging.
              * Screen still wont update when not moving the cursor though...
              */
-            /* PRECT prect = (PRECT) lParam; */
             RECT rect;
-            /* printf("WM_SIZING: nc-area: %i,%i\n",prect->right-prect->left,prect->bottom-prect->top); */
+            /* 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);
 
@@ -939,7 +949,9 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
                     /* For child window, we should return relative to upper-left
                      * of parent's client area.
                      */
-                    POINT topleft = {windowRect.left,windowRect.top};
+                    POINT topleft;
+                    topleft.x = windowRect.left;
+                    topleft.y = windowRect.top;
 
                     ScreenToClient(window->Parent->Window.Handle,&topleft);
                     windowRect.left = topleft.x;
@@ -1066,12 +1078,12 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
         if (wParam)
         {
             fghPlatformOnWindowStatusNotify(window, GL_TRUE, GL_FALSE);
-            window->State.Redisplay = GL_TRUE;
+            window->State.WorkMask |= GLUT_DISPLAY_WORK;
         }
         else
         {
             fghPlatformOnWindowStatusNotify(window, GL_FALSE, GL_FALSE);
-            window->State.Redisplay = GL_FALSE;
+            window->State.WorkMask &= ~GLUT_DISPLAY_WORK;
         }
         break;
 
@@ -1092,7 +1104,7 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
             BeginPaint( hWnd, &ps );
             EndPaint( hWnd, &ps );
 
-            window->State.Redisplay = GL_TRUE;
+            window->State.WorkMask |= GLUT_DISPLAY_WORK;
         }
         lRet = 0;   /* As per docs, should return 0 */
     }
@@ -1237,7 +1249,7 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
                 SetCapture ( window->Window.Handle ) ;
             setCaptureActive = 1; /* Set to false in WM_CAPTURECHANGED handler */
         }
-        else if (!GetAsyncKeyState(VK_LBUTTON) && !GetAsyncKeyState(VK_MBUTTON) && !GetAsyncKeyState(VK_RBUTTON))
+        else if (!fgGetKeyState(VK_LBUTTON) && !fgGetKeyState(VK_MBUTTON) && !fgGetKeyState(VK_RBUTTON))
           /* Make sure all mouse buttons are released before releasing capture */
           ReleaseCapture () ;
 
@@ -1275,7 +1287,7 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
         */
 #else
         /* int modkeys = GET_KEYSTATE_WPARAM( wParam ); */
-        short ticks = GET_WHEEL_DELTA_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 );
@@ -1384,7 +1396,7 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
 #if !defined(_WIN32_WCE)
     case WM_SYNCPAINT:  /* 0x0088 */
         /* Another window has moved, need to update this one */
-        window->State.Redisplay = GL_TRUE;
+        window->State.WorkMask |= GLUT_DISPLAY_WORK;
         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
         /* Help screen says this message must be passed to "DefWindowProc" */
         break;
@@ -1531,6 +1543,16 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
                break;
        }
 #endif
+
+#ifdef WM_INPUT
+       case WM_INPUT:
+        /* Added by Jinrong Xie <stonexjr at gmail.com> for SpaceNavigator support on Windows. Dec 2014 */
+               if (fgHasSpaceball())
+               {
+                       fgSpaceballHandleWinEvent(hWnd, wParam, lParam);
+               }
+               break;
+#endif
     default:
         /* Handle unhandled messages */
         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
@@ -1541,239 +1563,217 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
 }
 
 
-/* Step through the work list */
-void fgPlatformProcessWork(SFG_Window *window)
+/* deal with work list items */
+void fgPlatformInitWork(SFG_Window* window)
 {
-    unsigned int workMask = window->State.WorkMask;
-    /* Now clear it so that any callback generated by the actions below can set work again */
-    window->State.WorkMask = 0;
+    RECT windowRect;
 
-    /* This is before the first display callback: call a few callbacks to inform user of window size, position, etc
-     * we know this is before the first display callback of a window as for all windows GLUT_INIT_WORK is set when
-     * they are opened, and work is done before displaying in the mainloop.
-     */
-    if (workMask & GLUT_INIT_WORK)
-    {
-        RECT windowRect;
+    /* Notify windowStatus/visibility */
+    fghPlatformOnWindowStatusNotify(window, window->State.Visible, GL_TRUE);
 
-        /* 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 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);
-
-        /* Call init context callback */
-        INVOKE_WCB( *window, InitContext, ());
+    /* get and notify window's size */
+    GetClientRect(window->Window.Handle,&windowRect);
+    fghOnReshapeNotify(window, windowRect.right-windowRect.left, windowRect.bottom-windowRect.top, GL_TRUE);
+}
 
-        /* Lastly, check if we have a display callback, error out if not
-         * This is the right place to do it, as the redisplay will be
-         * next right after we exit this function, so there is no more
-         * opportunity for the user to register a callback for this window.
-         */
-        if (!FETCH_WCB(*window, Display))
-            fgError ( "ERROR:  No display callback registered for window %d\n", window->ID );
-    }
+/* 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;
 
-    /* On windows we can position, resize and change z order at the same time */
-    if (workMask & (GLUT_POSITION_WORK|GLUT_SIZE_WORK|GLUT_ZORDER_WORK|GLUT_FULL_SCREEN_WORK))
+#if !defined(_WIN32_WCE) /* FIXME: what about WinCE */
+    if (workMask & GLUT_FULL_SCREEN_WORK)
     {
-        UINT flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER;
-        HWND insertAfter = HWND_TOP;
-        RECT clientRect;
+        /* This asks us to toggle fullscreen mode */
+        flags |= SWP_FRAMECHANGED;
 
-#if !defined(_WIN32_WCE) /* FIXME: what about WinCE */
-        if (workMask & GLUT_FULL_SCREEN_WORK)
+        if (window->State.IsFullscreen)
         {
-            /* 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); */
+            /* 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);
+            /* 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 */
+            /* 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;
             }
-            else
+            if (!(workMask & GLUT_SIZE_WORK))
             {
-                /* 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.
-                    */
-                GetWindowRect(window->Window.Handle, &rect);
-                hMonitor= MonitorFromRect(&rect, 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;
+                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 */
+    /* 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)
         {
-            /* 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;
+            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;
+            /* 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;
-            }
+            /* 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;
         }
-
-        /* 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 (workMask & GLUT_ZORDER_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;
+            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;
         }
     }
 
-    if (workMask & GLUT_VISIBILITY_WORK)
+    /* 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)
     {
-        /* 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)
+        if (window->State.IsFullscreen)
         {
-        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 || win->ActiveMenu->ParentWindow != fgStructure.GameModeWindow))
-                cmdShow = SW_SHOWNA;    /* Just show, don't activate window if its a menu. Only exception is when the parent is a gamemode window as the menu would pop under it when we do this... */
-            else
-                cmdShow = SW_SHOW;
-            break;
+            /* 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;
+    }
+}
+
 
-        ShowWindow( win->Window.Handle, cmdShow );
+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;
     }
-}
\ No newline at end of file
+
+    ShowWindow( win->Window.Handle, cmdShow );
+}