/*
- * freeglut_main_mswin.c
+ * fg_main_mswin.c
*
* The Windows-specific mouse cursor related stuff.
*
#include <GL/freeglut.h>
#include "../fg_internal.h"
-
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);
struct GXKeyList gxKeyList;
#endif /* _WIN32_WCE */
+#ifdef _DEBUG
/*
- * Helper functions for getting client area from the window rect
- * and the window rect from the client area given the style of the window
- * (or a valid window pointer from which the style can be queried).
+ * WM_ message to string, for debugging
+ * This is taken from the 8.0 SDK, so Windows 8 API and everything earlier is included
*/
-extern void fghComputeWindowRectFromClientArea_QueryWindow( const SFG_Window *window, RECT *clientRect, BOOL posIsOutside );
-extern RECT fghGetClientArea ( const SFG_Window *window, BOOL wantPosOutside );
-
-
-void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height )
+struct WM_MESSAGE_MAP
{
- RECT windowRect;
-
- /*
- * For windowed mode, get the current position of the
- * window and resize taking the size of the frame
- * decorations into account.
- */
-
- /* "GetWindowRect" returns the pixel coordinates of the outside of the window */
- GetWindowRect( window->Window.Handle, &windowRect );
-
- /* Create rect in FreeGLUT format, (X,Y) topleft outside window, WxH of client area */
- windowRect.right = windowRect.left+width;
- windowRect.bottom = windowRect.top+height;
-
- if (window->Parent == NULL)
- /* get the window rect from this to feed to SetWindowPos, correct for window decorations */
- fghComputeWindowRectFromClientArea_QueryWindow(window,&windowRect,TRUE);
- else
+ 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++)
{
- /* correct rect for position client area of parent window
- * (SetWindowPos input for child windows is in coordinates
- * relative to the parent's client area).
- * Child windows don't have decoration, so no need to correct
- * for them.
- */
- RECT parentRect;
- parentRect = fghGetClientArea( window->Parent, FALSE );
- windowRect.left -= parentRect.left;
- windowRect.right -= parentRect.left;
- windowRect.top -= parentRect.top;
- windowRect.bottom -= parentRect.top;
+ if (pMapMsg->nMsg == dwMessage )
+ {
+ return (char *)pMapMsg->lpszMsg;
+ }
}
-
- /* Do the actual resizing */
- SetWindowPos( window->Window.Handle,
- HWND_TOP,
- windowRect.left, windowRect.top,
- windowRect.right - windowRect.left,
- windowRect.bottom- windowRect.top,
- SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
- SWP_NOZORDER
- );
+ return "";
}
-
-
-void fgPlatformDisplayWindow ( SFG_Window *window )
+#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()
{
- RedrawWindow(
- window->Window.Handle, NULL, NULL,
- RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW
- );
+#if defined(_WIN32_WCE)
+ lastTime32 = GetTickCount();
+#else
+ lastTime32 = timeGetTime();
+#endif
}
-
-
fg_time_t fgPlatformSystemTime ( void )
{
+ fg_time_t currTime32;
#if defined(_WIN32_WCE)
- return GetTickCount();
+ currTime32 = GetTickCount();
#else
- /* TODO: do this with QueryPerformanceCounter as timeGetTime has
- * insufficient resolution (only about 5 ms on system under low load).
- * See:
- * http://msdn.microsoft.com/en-us/library/windows/desktop/dd757629(v=vs.85).aspx
- * Or maybe QueryPerformanceCounter is not a good idea either, see
- * http://old.nabble.com/Re%3A-glutTimerFunc-does-not-detect-if-system-time-moved-backward-p33479674.html
- * for some other ideas (at bottom)...
- */
- return timeGetTime();
+ currTime32 = timeGetTime();
#endif
+ /* Check if we just wrapped */
+ if (currTime32 < lastTime32)
+ timeEpoch++;
+
+ lastTime32 = currTime32;
+
+ return currTime32 | timeEpoch << 32;
}
-void fgPlatformMainLoopPreliminaryWork ( void )
+static void fghPlatformOnWindowStatusNotify(SFG_Window *window, GLboolean visState, GLboolean forceNotify)
{
- SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ;
-
- /*
- * Processing before the main loop: If there is a window which is open and
- * which has a visibility callback, call it. I know this is an ugly hack,
- * but I'm not sure what else to do about it. Ideally we should leave
- * something uninitialized in the create window code and initialize it in
- * the main loop, and have that initialization create a "WM_ACTIVATE"
- * message. Then we would put the visibility callback code in the
- * "case WM_ACTIVATE" block below. - John Fay -- 10/24/02
- */
- while( window )
+ GLboolean notify = GL_FALSE;
+ SFG_Window* child;
+
+ if (window->State.Visible != visState)
{
- if ( FETCH_WCB( *window, Visibility ) )
- {
- SFG_Window *current_window = fgStructure.CurrentWindow ;
+ window->State.Visible = visState;
- INVOKE_WCB( *window, Visibility, ( window->State.Visible ) );
- fgSetWindow( current_window );
+ /* 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 );
}
- window = (SFG_Window *)window->Node.Next ;
+ 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 modifer mask based on MS-WINDOWS system info.
+ * Determine a GLUT modifier mask based on MS-WINDOWS system info.
*/
static int fgPlatformGetModifiers (void)
{
( GetKeyState( VK_RMENU ) < 0 )) ? GLUT_ACTIVE_ALT : 0 );
}
-/*
- * The window procedure for handling Win32 events
- */
-LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
- LPARAM lParam )
+/* Check whether a button (VK_*BUTTON) is currently depressed. Returns
+ * non-zero (not necessarily 1) if yes. */
+static SHORT fgGetKeyState(int vKey)
{
- static unsigned char lControl = 0, rControl = 0, lShift = 0,
- rShift = 0, lAlt = 0, rAlt = 0;
+ /* MSDN says: "If the high-order bit is 1, the key is down; otherwise, it is up". */
+ return GetKeyState(vKey) & 0xFF00;
+}
- SFG_Window* window;
- PAINTSTRUCT ps;
- LRESULT lRet = 1;
+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;
- FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
+ 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( );
- window = fgWindowByHandle( hWnd );
+ /* Convert the Win32 keystroke codes to GLUTtish way */
+# define FG_KEY(a,b) case a: keypress = b; break;
- if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
- return DefWindowProc( hWnd, uMsg, wParam, lParam );
+ 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, Keyboard,
+ ( 127, window->State.MouseX, window->State.MouseY )
+ );
+ else
+ INVOKE_WCB( *window, KeyboardUp,
+ ( 127, window->State.MouseX, window->State.MouseY )
+ );
+ break;
- /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
- uMsg, wParam, lParam ); */
+#if !defined(_WIN32_WCE)
+ default:
+ /* keydown displayable characters are handled with WM_CHAR message, but no corresponding up is generated. So get that here. */
+ if (!keydown)
+ {
+ BYTE state[ 256 ];
+ WORD code[ 2 ];
+
+ GetKeyboardState( state );
+
+ if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
+ wParam=code[ 0 ];
- /* events only sent to main window. Check if the current window that the mouse
- is over is a child window and if so, make sure we call the callback on that
- child instead.
- */
- if (window && window->Children.First)
+ INVOKE_WCB( *window, KeyboardUp,
+ ( (char)(wParam & 0xFF), /* and with 0xFF to indicate to runtime that we want to strip out higher bits - otherwise we get a runtime error when "Smaller Type Checks" is enabled */
+ window->State.MouseX, window->State.MouseY )
+ );
+ }
+#endif
+ }
+
+#if defined(_WIN32_WCE)
+ if(keydown && !(lParam & 0x40000000)) /* Prevent auto-repeat */
{
- POINT mouse_pos;
- SFG_WindowHandleType hwnd;
+ 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;
+}
- GetCursorPos( &mouse_pos );
+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) /* can be NULL if mouse outside parent by the time we get here */
- window = fgWindowByHandle(hwnd);
+ 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);
+ }
+ }
}
- if ( window )
- {
- fgState.Modifiers = fgPlatformGetModifiers( );
-
- /* Checking for CTRL, ALT, and SHIFT key positions: Key Down! */
- if ( !lControl && GetAsyncKeyState ( VK_LCONTROL ) )
- {
- INVOKE_WCB ( *window, Special,
- ( GLUT_KEY_CTRL_L, window->State.MouseX, window->State.MouseY )
- );
-
- lControl = 1;
- }
-
- if ( !rControl && GetAsyncKeyState ( VK_RCONTROL ) )
- {
- INVOKE_WCB ( *window, Special,
- ( GLUT_KEY_CTRL_R, window->State.MouseX, window->State.MouseY )
- );
-
- rControl = 1;
- }
-
- if ( !lShift && GetAsyncKeyState ( VK_LSHIFT ) )
- {
- INVOKE_WCB ( *window, Special,
- ( GLUT_KEY_SHIFT_L, window->State.MouseX, window->State.MouseY )
- );
-
- lShift = 1;
- }
-
- if ( !rShift && GetAsyncKeyState ( VK_RSHIFT ) )
- {
- INVOKE_WCB ( *window, Special,
- ( GLUT_KEY_SHIFT_R, window->State.MouseX, window->State.MouseY )
- );
-
- rShift = 1;
- }
-
- if ( !lAlt && GetAsyncKeyState ( VK_LMENU ) )
- {
- INVOKE_WCB ( *window, Special,
- ( GLUT_KEY_ALT_L, window->State.MouseX, window->State.MouseY )
- );
-
- lAlt = 1;
- }
-
- if ( !rAlt && GetAsyncKeyState ( VK_RMENU ) )
- {
- INVOKE_WCB ( *window, Special,
- ( GLUT_KEY_ALT_R, window->State.MouseX, window->State.MouseY )
- );
-
- rAlt = 1;
- }
-
- /* Checking for CTRL, ALT, and SHIFT key positions: Key Up! */
- if ( lControl && !GetAsyncKeyState ( VK_LCONTROL ) )
- {
- INVOKE_WCB ( *window, SpecialUp,
- ( GLUT_KEY_CTRL_L, window->State.MouseX, window->State.MouseY )
- );
-
- lControl = 0;
- }
-
- if ( rControl && !GetAsyncKeyState ( VK_RCONTROL ) )
- {
- INVOKE_WCB ( *window, SpecialUp,
- ( GLUT_KEY_CTRL_R, window->State.MouseX, window->State.MouseY )
- );
-
- rControl = 0;
- }
-
- if ( lShift && !GetAsyncKeyState ( VK_LSHIFT ) )
- {
- INVOKE_WCB ( *window, SpecialUp,
- ( GLUT_KEY_SHIFT_L, window->State.MouseX, window->State.MouseY )
- );
-
- lShift = 0;
- }
-
- if ( rShift && !GetAsyncKeyState ( VK_RSHIFT ) )
- {
- INVOKE_WCB ( *window, SpecialUp,
- ( GLUT_KEY_SHIFT_R, window->State.MouseX, window->State.MouseY )
- );
-
- rShift = 0;
- }
-
- if ( lAlt && !GetAsyncKeyState ( VK_LMENU ) )
- {
- INVOKE_WCB ( *window, SpecialUp,
- ( GLUT_KEY_ALT_L, window->State.MouseX, window->State.MouseY )
- );
-
- lAlt = 0;
- }
-
- if ( rAlt && !GetAsyncKeyState ( VK_RMENU ) )
- {
- INVOKE_WCB ( *window, SpecialUp,
- ( GLUT_KEY_ALT_R, window->State.MouseX, window->State.MouseY )
- );
-
- rAlt = 0;
- }
-
- fgState.Modifiers = INVALID_MODIFIERS;
- }
+ 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 )
{
#endif
}
- window->State.NeedToResize = GL_TRUE;
- /* if we used CW_USEDEFAULT (thats a negative value) for the size
- * of the window, query the window now for the size at which it
- * was created.
- */
- if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) )
- {
- SFG_Window *current_window = fgStructure.CurrentWindow;
-
- fgSetWindow( window );
- window->State.Width = glutGet( GLUT_WINDOW_WIDTH );
- window->State.Height = glutGet( GLUT_WINDOW_HEIGHT );
- fgSetWindow( current_window );
- }
-
ReleaseDC( window->Window.Handle, window->Window.pContext.Device );
#if defined(_WIN32_WCE)
break;
case WM_SIZE:
- /*
- * If the window is visible, then it is the user manually resizing it.
- * If it is not, then it is the system sending us a dummy resize with
- * zero dimensions on a "glutIconifyWindow" call.
- */
+ /* 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 )
{
- window->State.NeedToResize = GL_TRUE;
+ int width, height;
#if defined(_WIN32_WCE)
- window->State.Width = HIWORD(lParam);
- window->State.Height = LOWORD(lParam);
+ width = HIWORD(lParam);
+ height = LOWORD(lParam);
#else
- window->State.Width = LOWORD(lParam);
- window->State.Height = HIWORD(lParam);
+ 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 ); */
+ /*printf("WM_SETFOCUS: %p\n", window );*/
lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
- INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
- UpdateWindow ( hWnd );
+ SetActiveWindow( window->Window.Handle );
+ UpdateWindow ( hWnd );
+
break;
case WM_KILLFOCUS:
- {
- SFG_Menu* menu = NULL;
-/* printf("WM_KILLFOCUS (ismenu: %i): %p\n", window->IsMenu, window ); */
+ /*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 );
- INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
+ break;
- /* If we have an open menu, see if the open menu should be closed
- when focus was lost because user either switched
- application or FreeGLUT window (if one is running multiple
- windows). If so, close menu the active menu.
- */
- if ( fgStructure.CurrentMenu )
- menu = fgGetActiveMenu();
-
- if ( menu )
- {
- SFG_Window* wnd = NULL;
- HWND hwnd = GetForegroundWindow(); /* Get window with current focus */
- if (hwnd)
- /* See if its one of our windows */
- wnd = fgWindowByHandle(hwnd);
-
- if (!hwnd || !wnd)
- /* User switched to another application*/
- fgDeactivateMenu(menu->ParentWindow);
- else if (
- ( wnd->IsMenu && wnd->ActiveMenu && wnd->ActiveMenu->ParentWindow!=menu->ParentWindow) || /* Make sure we don't kill the menu when trying to enter a submenu */
- (!wnd->IsMenu && wnd!=menu->ParentWindow)
- )
- /* User switched to another FreeGLUT window */
- fgDeactivateMenu(menu->ParentWindow);
- }
+ 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,
case WM_SETCURSOR:
/* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
if( LOWORD( lParam ) == HTCLIENT )
- fgSetCursor ( window, window->State.Cursor ) ;
+ {
+ 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;
+ 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:
- window->State.Visible = GL_TRUE;
- window->State.Redisplay = GL_TRUE;
+ /* 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:
- /* Turn on the visibility in case it was turned off somehow */
- window->State.Visible = GL_TRUE;
- BeginPaint( hWnd, &ps );
- fghRedrawWindow( window );
- EndPaint( hWnd, &ps );
- break;
+ {
+ 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 );
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 );
+ 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 = LOWORD( lParam );
- window->State.MouseY = HIWORD( lParam );
+ 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 */
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 );
+ 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 = LOWORD( lParam );
- window->State.MouseY = HIWORD( lParam );
+ 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 */
window->State.MouseX, window->State.MouseY ) )
break;
- /* Set capture so that the window captures all the mouse messages */
- /*
- * XXX - Multiple button support: Under X11, the mouse is not released
- * XXX - from the window until all buttons have been released, even if the
- * XXX - user presses a button in another window. This will take more
- * XXX - code changes than I am up to at the moment (10/5/04). The present
- * XXX - is a 90 percent solution.
+ /* 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 )
- SetCapture ( window->Window.Handle ) ;
- else
+ {
+ 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 ) )
);
fgState.Modifiers = INVALID_MODIFIERS;
+
+ /* As per docs, should return zero */
+ lRet = 0;
}
break;
case WM_MOUSEWHEEL:
{
- int wheel_number = LOWORD( wParam );
- short ticks = ( short )HIWORD( wParam );
- fgState.MouseWheelTicks += ticks;
+ 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) */
- /*
- * XXX Should use WHEEL_DELTA instead of 120
- */
- if ( abs ( fgState.MouseWheelTicks ) >= 120 )
+ window = fghWindowUnderCursor(window);
+
+ fgState.MouseWheelTicks += ticks;
+ if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
{
int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
fgSetWindow( window );
fgState.Modifiers = fgPlatformGetModifiers( );
- /*
- * XXX Should use WHEEL_DELTA instead of 120
- */
- while( abs ( fgState.MouseWheelTicks ) >= 120 )
+ while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
{
if( FETCH_WCB( *window, MouseWheel ) )
INVOKE_WCB( *window, MouseWheel,
);
}
- /*
- * XXX Should use WHEEL_DELTA instead of 120
- */
- fgState.MouseWheelTicks -= 120 * direction;
+ fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
}
fgState.Modifiers = INVALID_MODIFIERS;
}
+ /* Per docs, should return zero */
+ lRet = 0;
}
break ;
case WM_SYSKEYDOWN:
case WM_KEYDOWN:
{
- int keypress = -1;
- POINT mouse_pos ;
-
-
- if( ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
- break;
-
- /*
- * Remember the current modifiers state. This is done here in order
- * to make sure the VK_DELETE keyboard callback is executed properly.
- */
- fgState.Modifiers = fgPlatformGetModifiers( );
-
- GetCursorPos( &mouse_pos );
- ScreenToClient( window->Window.Handle, &mouse_pos );
-
- window->State.MouseX = mouse_pos.x;
- window->State.MouseY = mouse_pos.y;
-
- /* Convert the Win32 keystroke codes to GLUTtish way */
-# define 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 );
-
- case VK_LCONTROL: case VK_RCONTROL: case VK_CONTROL:
- case VK_LSHIFT: case VK_RSHIFT: case VK_SHIFT:
- case VK_LMENU: case VK_RMENU: case VK_MENU:
- /* These keypresses and releases are handled earlier in the function */
- break;
-
- case VK_DELETE:
- /* The delete key should be treated as an ASCII keypress: */
- INVOKE_WCB( *window, Keyboard,
- ( 127, window->State.MouseX, window->State.MouseY )
- );
- }
-
-#if defined(_WIN32_WCE)
- if(!(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 )
- INVOKE_WCB( *window, Special,
- ( keypress,
- window->State.MouseX, window->State.MouseY )
- );
-
- fgState.Modifiers = INVALID_MODIFIERS;
+ window = fghWindowUnderCursor(window);
+ lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
}
break;
case WM_SYSKEYUP:
case WM_KEYUP:
{
- int keypress = -1;
- POINT mouse_pos;
-
- /*
- * Remember the current modifiers state. This is done here in order
- * to make sure the VK_DELETE keyboard callback is executed properly.
- */
- fgState.Modifiers = fgPlatformGetModifiers( );
-
- GetCursorPos( &mouse_pos );
- ScreenToClient( window->Window.Handle, &mouse_pos );
-
- window->State.MouseX = mouse_pos.x;
- window->State.MouseY = mouse_pos.y;
-
- /*
- * Convert the Win32 keystroke codes to GLUTtish way.
- * "KEY(a,b)" was defined under "WM_KEYDOWN"
- */
-
- 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 );
-
- case VK_LCONTROL: case VK_RCONTROL: case VK_CONTROL:
- case VK_LSHIFT: case VK_RSHIFT: case VK_SHIFT:
- case VK_LMENU: case VK_RMENU: case VK_MENU:
- /* These keypresses and releases are handled earlier in the function */
- break;
-
- case VK_DELETE:
- /* The delete key should be treated as an ASCII keypress: */
- INVOKE_WCB( *window, KeyboardUp,
- ( 127, window->State.MouseX, window->State.MouseY )
- );
- break;
-
- default:
- {
-#if !defined(_WIN32_WCE)
- BYTE state[ 256 ];
- WORD code[ 2 ];
-
- GetKeyboardState( state );
-
- if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
- wParam=code[ 0 ];
-
- INVOKE_WCB( *window, KeyboardUp,
- ( (char)wParam,
- window->State.MouseX, window->State.MouseY )
- );
-#endif /* !defined(_WIN32_WCE) */
- }
- }
-
- if( keypress != -1 )
- INVOKE_WCB( *window, SpecialUp,
- ( keypress,
- window->State.MouseX, window->State.MouseY )
- );
-
- fgState.Modifiers = INVALID_MODIFIERS;
+ 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;
break;
case WM_CAPTURECHANGED:
- /* User has finished resizing the window, force a redraw */
- INVOKE_WCB( *window, Display, ( ) );
-
- /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */
- break;
-
- /* Other messages that I have seen and which are not handled already */
- case WM_SETTEXT: /* 0x000c */
- lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
- /* Pass it on to "DefWindowProc" to set the window text */
- break;
-
- case WM_GETTEXT: /* 0x000d */
- /* Ideally we would copy the title of the window into "lParam" */
- /* strncpy ( (char *)lParam, "Window Title", wParam );
- lRet = ( wParam > 12 ) ? 12 : wParam; */
- /* the number of characters copied */
- lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
- break;
-
- case WM_GETTEXTLENGTH: /* 0x000e */
- /* Ideally we would get the length of the title of the window */
- lRet = 12;
- /* the number of characters in "Window Title\0" (see above) */
- break;
-
- case WM_ERASEBKGND: /* 0x0014 */
- lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
+ 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.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;
- case WM_NCPAINT: /* 0x0085 */
- /* Need to update the border of this window */
- lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
- /* Pass it on to "DefWindowProc" to repaint a standard border */
+ case WM_DISPLAYCHANGE: /* 0x007E */
+ /* The system display resolution/depth has changed */
+ fgDisplay.ScreenWidth = LOWORD(lParam);
+ fgDisplay.ScreenHeight = HIWORD(lParam);
break;
case WM_SYSCOMMAND : /* 0x0112 */
case SC_MINIMIZE :
/* User has clicked on the "-" to minimize the window */
- /* Turn off the visibility */
- window->State.Visible = GL_FALSE ;
+ /* Turning off the visibility is handled in WM_SIZE handler */
break ;
break;
}
#endif
+ //Added by Jinrong Xie (stonexjr@gmail.com) 12/24/2014
+ //for SpaceNavigator support on Windows.
+ case WM_INPUT:
+ if (fgHasSpaceball())
+ {
+ fgSpaceballHandleWinEvent(hWnd, wParam, lParam);
+ }
+ break;
default:
/* Handle unhandled messages */
lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
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 );
+}