X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Fmswin%2Ffg_main_mswin.c;h=6d286e75142f2225d7e5c0178647791f0f5cdd56;hb=226cd5ccd0f86cc1f2741e686fcf8e4846acf867;hp=f3d2005ba40ce12c9da9810f17713d1ae086cc6f;hpb=bda964327e9939b534cef499bbdb06f1af76d190;p=freeglut diff --git a/src/mswin/fg_main_mswin.c b/src/mswin/fg_main_mswin.c index f3d2005..6d286e7 100644 --- a/src/mswin/fg_main_mswin.c +++ b/src/mswin/fg_main_mswin.c @@ -1,5 +1,5 @@ /* - * freeglut_main_mswin.c + * fg_main_mswin.c * * The Windows-specific mouse cursor related stuff. * @@ -39,7 +39,7 @@ extern void fgNewWGLCreateContext( SFG_Window* window ); extern GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, unsigned char layer_type ); -extern void fgPlatformCheckMenuDeactivate(); +extern void fgPlatformCheckMenuDeactivate(HWND newFocusWnd); #ifdef WM_TOUCH typedef BOOL (WINAPI *pGetTouchInputInfo)(HTOUCHINPUT,UINT,PTOUCHINPUT,int); @@ -62,6 +62,389 @@ 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, @@ -91,7 +474,7 @@ fg_time_t fgPlatformSystemTime ( void ) /* Check if we just wrapped */ if (currTime32 < lastTime32) timeEpoch++; - + lastTime32 = currTime32; return currTime32 | timeEpoch << 32; @@ -159,7 +542,7 @@ static void fghPlatformOnWindowStatusNotify(SFG_Window *window, GLboolean visSta { SFG_Window *saved_window = fgStructure.CurrentWindow; - /* On win32 we only have two states, window displayed and window not displayed (iconified) + /* 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 ) ); @@ -195,13 +578,21 @@ 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, 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 @@ -210,65 +601,65 @@ static LRESULT fghWindowProcKeyPress(SFG_Window *window, UINT uMsg, GLboolean ke */ 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 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: */ @@ -324,7 +715,7 @@ static LRESULT fghWindowProcKeyPress(SFG_Window *window, UINT uMsg, GLboolean ke keypress = GLUT_KEY_F4; } #endif - + if( keypress != -1 ) if (keydown) INVOKE_WCB( *window, Special, @@ -361,9 +752,11 @@ 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); 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 */ { @@ -395,8 +788,8 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR if ( ( window == NULL ) && ( uMsg != WM_CREATE ) ) return DefWindowProc( hWnd, uMsg, wParam, lParam ); - /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0, - uMsg, wParam, lParam ); */ + /* printf ( "Window %3d message %s (<%04x>) %12d %12d\n", window?window->ID:0, + WMMsg2Str(uMsg), uMsg, wParam, lParam ); */ switch( uMsg ) { @@ -481,7 +874,7 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR /* Update visibility state of the window */ if (wParam==SIZE_MINIMIZED) fghPlatformOnWindowStatusNotify(window,GL_FALSE,GL_FALSE); - else if (wParam==SIZE_RESTORED && !window->State.Visible) + else if ((wParam==SIZE_RESTORED || wParam == SIZE_MAXIMIZED) && !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 */ @@ -495,7 +888,7 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR 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); } @@ -510,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); @@ -542,21 +935,23 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR 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 + * 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 = {windowRect.left,windowRect.top}; + POINT topleft; + topleft.x = windowRect.left; + topleft.y = windowRect.top; ScreenToClient(window->Parent->Window.Handle,&topleft); windowRect.left = topleft.x; @@ -586,12 +981,37 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); /* Check if there are any open menus that need to be closed */ - fgPlatformCheckMenuDeactivate(); + 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)); + /* 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, @@ -611,7 +1031,7 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR { TRACKMOUSEEVENT tme; - /* Cursor just entered window, set cursor look */ + /* Cursor just entered window, set cursor look */ fgSetCursor ( window, window->State.Cursor ) ; /* If an EntryFunc callback is specified by the user, also @@ -629,7 +1049,7 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR tme.hwndTrack = window->Window.Handle; TrackMouseEvent(&tme); - window->State.pWState.MouseTracking = GL_TRUE; + window->State.pWState.MouseTracking = TRUE; } } } @@ -648,7 +1068,7 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) ); fgSetWindow(saved_window); - window->State.pWState.MouseTracking = GL_FALSE; + window->State.pWState.MouseTracking = FALSE; lRet = 0; /* As per docs, must return zero */ } break; @@ -658,19 +1078,19 @@ 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; 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)) { @@ -684,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 */ } @@ -829,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 () ; @@ -859,7 +1279,7 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR { int wheel_number = 0; /* Only one scroll wheel on windows */ #if defined(_WIN32_WCE) - int modkeys = LOWORD(wParam); + 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) @@ -867,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 ); @@ -876,10 +1296,10 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR window = fghWindowUnderCursor(window); - fgState.MouseWheelTicks += ticks; + fgState.MouseWheelTicks += ticks; if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA ) - { - int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1; + { + int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1; if( ! FETCH_WCB( *window, MouseWheel ) && ! FETCH_WCB( *window, Mouse ) ) @@ -889,7 +1309,7 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR fgState.Modifiers = fgPlatformGetModifiers( ); while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA ) - { + { if( FETCH_WCB( *window, MouseWheel ) ) INVOKE_WCB( *window, MouseWheel, ( wheel_number, @@ -899,7 +1319,7 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR ) ); 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, ... @@ -918,13 +1338,13 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR ( button, GLUT_UP, window->State.MouseX, window->State.MouseY ) ); - } + } - fgState.MouseWheelTicks -= WHEEL_DELTA * direction; - } + fgState.MouseWheelTicks -= WHEEL_DELTA * direction; + } fgState.Modifiers = INVALID_MODIFIERS; - } + } /* Per docs, should return zero */ lRet = 0; } @@ -976,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; @@ -1078,50 +1498,60 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR 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; - } + /* 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 + +#ifdef WM_INPUT + case WM_INPUT: + /* Added by Jinrong Xie for SpaceNavigator support on Windows. Dec 2014 */ + if (fgHasSpaceball()) + { + fgSpaceballHandleWinEvent(hWnd, wParam, lParam); + } + break; #endif default: /* Handle unhandled messages */ @@ -1133,239 +1563,224 @@ 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; - - /* 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; + 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 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 (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); + /* 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 + /* Then set up resize/reposition, unless user already queued up reshape/position work */ + if (!(workMask & GLUT_POSITION_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_POSITION_WORK; + window->State.DesiredXpos = window->State.pWState.OldRect.left; + window->State.DesiredYpos = window->State.pWState.OldRect.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) + if (!(workMask & GLUT_SIZE_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); + 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; } - 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) + /* 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; + DWORD newStyle; + + /* 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 */ + newStyle = window->State.pWState.OldStyle & ~(WS_CAPTION | WS_THICKFRAME); + if (fgState.DisplayMode & GLUT_STEREO) { - 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; + /* stereo mode does not engage on nVidia stereo buffers. This kills child + windows, but we make the guess that those are rare for stereo windows. */ + newStyle |= WS_POPUP; } + SetWindowLong(window->Window.Handle, GWL_STYLE, newStyle); + 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) */ - /* 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) + /* 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) { - 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_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; } } - 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) - cmdShow = SW_SHOWNOACTIVATE; /* Just show, don't activate if its a menu */ - 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 ); +}