| /* |
| * freeglut_main_mswin.c |
| * |
| * The Windows-specific mouse cursor related stuff. |
| * |
| * Copyright (c) 2012 Stephen J. Baker. All Rights Reserved. |
| * Written by John F. Fay, <fayjf@sourceforge.net> |
| * Creation date: Sat Jan 21, 2012 |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included |
| * in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
| * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #include <GL/freeglut.h> |
| #include "../fg_internal.h" |
| |
| extern void fghRedrawWindow ( SFG_Window *window ); |
| extern void fghRedrawWindowAndChildren ( SFG_Window *window ); |
| extern void fghOnReshapeNotify(SFG_Window *window, int width, int height, GLboolean forceNotify); |
| extern void fghOnPositionNotify(SFG_Window *window, int x, int y, GLboolean forceNotify); |
| extern void fghComputeWindowRectFromClientArea_QueryWindow( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside ); |
| extern void fghGetClientArea( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside ); |
| |
| extern void fgNewWGLCreateContext( SFG_Window* window ); |
| extern GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, |
| unsigned char layer_type ); |
| |
| extern void fgPlatformCheckMenuDeactivate(HWND newFocusWnd); |
| |
| #ifdef WM_TOUCH |
| typedef BOOL (WINAPI *pGetTouchInputInfo)(HTOUCHINPUT,UINT,PTOUCHINPUT,int); |
| typedef BOOL (WINAPI *pCloseTouchInputHandle)(HTOUCHINPUT); |
| static pGetTouchInputInfo fghGetTouchInputInfo = (pGetTouchInputInfo)0xDEADBEEF; |
| static pCloseTouchInputHandle fghCloseTouchInputHandle = (pCloseTouchInputHandle)0xDEADBEEF; |
| #endif |
| |
| #ifdef _WIN32_WCE |
| typedef struct GXDisplayProperties GXDisplayProperties; |
| typedef struct GXKeyList GXKeyList; |
| #include <gx.h> |
| |
| typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int); |
| typedef int (*GXOPENINPUT)(); |
| |
| GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL; |
| GXOPENINPUT GXOpenInput_ = NULL; |
| |
| struct GXKeyList gxKeyList; |
| #endif /* _WIN32_WCE */ |
| |
| #ifdef _DEBUG |
| /* |
| * WM_ message to string, for debugging |
| * This is taken from the 8.0 SDK, so Windows 8 API and everything earlier is included |
| */ |
| struct WM_MESSAGE_MAP |
| { |
| UINT nMsg; |
| LPCSTR lpszMsg; |
| }; |
| #define DEFINE_MESSAGE(wm){ wm, #wm } |
| static struct WM_MESSAGE_MAP allMessages[] = |
| { |
| DEFINE_MESSAGE(WM_NULL), |
| DEFINE_MESSAGE(WM_CREATE), |
| DEFINE_MESSAGE(WM_DESTROY), |
| DEFINE_MESSAGE(WM_MOVE), |
| DEFINE_MESSAGE(WM_SIZE), |
| |
| DEFINE_MESSAGE(WM_ACTIVATE), |
| DEFINE_MESSAGE(WM_SETFOCUS), |
| DEFINE_MESSAGE(WM_KILLFOCUS), |
| DEFINE_MESSAGE(WM_ENABLE), |
| DEFINE_MESSAGE(WM_SETREDRAW), |
| DEFINE_MESSAGE(WM_SETTEXT), |
| DEFINE_MESSAGE(WM_GETTEXT), |
| DEFINE_MESSAGE(WM_GETTEXTLENGTH), |
| DEFINE_MESSAGE(WM_PAINT), |
| DEFINE_MESSAGE(WM_CLOSE), |
| # ifndef _WIN32_WCE |
| DEFINE_MESSAGE(WM_QUERYENDSESSION), |
| DEFINE_MESSAGE(WM_QUERYOPEN), |
| DEFINE_MESSAGE(WM_ENDSESSION), |
| # endif |
| DEFINE_MESSAGE(WM_QUIT), |
| DEFINE_MESSAGE(WM_ERASEBKGND), |
| DEFINE_MESSAGE(WM_SYSCOLORCHANGE), |
| DEFINE_MESSAGE(WM_SHOWWINDOW), |
| DEFINE_MESSAGE(WM_WININICHANGE), |
| |
| DEFINE_MESSAGE(WM_DEVMODECHANGE), |
| DEFINE_MESSAGE(WM_ACTIVATEAPP), |
| DEFINE_MESSAGE(WM_FONTCHANGE), |
| DEFINE_MESSAGE(WM_TIMECHANGE), |
| DEFINE_MESSAGE(WM_CANCELMODE), |
| DEFINE_MESSAGE(WM_SETCURSOR), |
| DEFINE_MESSAGE(WM_MOUSEACTIVATE), |
| DEFINE_MESSAGE(WM_CHILDACTIVATE), |
| DEFINE_MESSAGE(WM_QUEUESYNC), |
| |
| DEFINE_MESSAGE(WM_GETMINMAXINFO), |
| |
| DEFINE_MESSAGE(WM_PAINTICON), |
| DEFINE_MESSAGE(WM_ICONERASEBKGND), |
| DEFINE_MESSAGE(WM_NEXTDLGCTL), |
| DEFINE_MESSAGE(WM_SPOOLERSTATUS), |
| DEFINE_MESSAGE(WM_DRAWITEM), |
| DEFINE_MESSAGE(WM_MEASUREITEM), |
| DEFINE_MESSAGE(WM_DELETEITEM), |
| DEFINE_MESSAGE(WM_VKEYTOITEM), |
| DEFINE_MESSAGE(WM_CHARTOITEM), |
| DEFINE_MESSAGE(WM_SETFONT), |
| DEFINE_MESSAGE(WM_GETFONT), |
| DEFINE_MESSAGE(WM_SETHOTKEY), |
| DEFINE_MESSAGE(WM_GETHOTKEY), |
| DEFINE_MESSAGE(WM_QUERYDRAGICON), |
| DEFINE_MESSAGE(WM_COMPAREITEM), |
| # if(WINVER >= 0x0500) |
| # ifndef _WIN32_WCE |
| DEFINE_MESSAGE(WM_GETOBJECT), |
| # endif |
| # endif /* WINVER >= 0x0500 */ |
| DEFINE_MESSAGE(WM_COMPACTING), |
| DEFINE_MESSAGE(WM_COMMNOTIFY), |
| DEFINE_MESSAGE(WM_WINDOWPOSCHANGING), |
| DEFINE_MESSAGE(WM_WINDOWPOSCHANGED), |
| |
| DEFINE_MESSAGE(WM_POWER), |
| |
| DEFINE_MESSAGE(WM_COPYDATA), |
| DEFINE_MESSAGE(WM_CANCELJOURNAL), |
| |
| # if(WINVER >= 0x0400) |
| DEFINE_MESSAGE(WM_NOTIFY), |
| DEFINE_MESSAGE(WM_INPUTLANGCHANGEREQUEST), |
| DEFINE_MESSAGE(WM_INPUTLANGCHANGE), |
| DEFINE_MESSAGE(WM_TCARD), |
| DEFINE_MESSAGE(WM_HELP), |
| DEFINE_MESSAGE(WM_USERCHANGED), |
| DEFINE_MESSAGE(WM_NOTIFYFORMAT), |
| |
| DEFINE_MESSAGE(WM_CONTEXTMENU), |
| DEFINE_MESSAGE(WM_STYLECHANGING), |
| DEFINE_MESSAGE(WM_STYLECHANGED), |
| DEFINE_MESSAGE(WM_DISPLAYCHANGE), |
| DEFINE_MESSAGE(WM_GETICON), |
| DEFINE_MESSAGE(WM_SETICON), |
| # endif /* WINVER >= 0x0400 */ |
| |
| DEFINE_MESSAGE(WM_NCCREATE), |
| DEFINE_MESSAGE(WM_NCDESTROY), |
| DEFINE_MESSAGE(WM_NCCALCSIZE), |
| DEFINE_MESSAGE(WM_NCHITTEST), |
| DEFINE_MESSAGE(WM_NCPAINT), |
| DEFINE_MESSAGE(WM_NCACTIVATE), |
| DEFINE_MESSAGE(WM_GETDLGCODE), |
| # ifndef _WIN32_WCE |
| DEFINE_MESSAGE(WM_SYNCPAINT), |
| # endif |
| DEFINE_MESSAGE(WM_NCMOUSEMOVE), |
| DEFINE_MESSAGE(WM_NCLBUTTONDOWN), |
| DEFINE_MESSAGE(WM_NCLBUTTONUP), |
| DEFINE_MESSAGE(WM_NCLBUTTONDBLCLK), |
| DEFINE_MESSAGE(WM_NCRBUTTONDOWN), |
| DEFINE_MESSAGE(WM_NCRBUTTONUP), |
| DEFINE_MESSAGE(WM_NCRBUTTONDBLCLK), |
| DEFINE_MESSAGE(WM_NCMBUTTONDOWN), |
| DEFINE_MESSAGE(WM_NCMBUTTONUP), |
| DEFINE_MESSAGE(WM_NCMBUTTONDBLCLK), |
| |
| |
| |
| # if(_WIN32_WINNT >= 0x0500) |
| 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) |
| 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) |
| 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) |
| 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) |
| DEFINE_MESSAGE(WM_APPCOMMAND), |
| # endif /* _WIN32_WINNT >= 0x0500 */ |
| |
| # if(_WIN32_WINNT >= 0x0501) |
| DEFINE_MESSAGE(WM_THEMECHANGED), |
| # endif /* _WIN32_WINNT >= 0x0501 */ |
| |
| |
| # if(_WIN32_WINNT >= 0x0501) |
| DEFINE_MESSAGE(WM_CLIPBOARDUPDATE), |
| # endif /* _WIN32_WINNT >= 0x0501 */ |
| |
| # if(_WIN32_WINNT >= 0x0600) |
| DEFINE_MESSAGE(WM_DWMCOMPOSITIONCHANGED), |
| DEFINE_MESSAGE(WM_DWMNCRENDERINGCHANGED), |
| DEFINE_MESSAGE(WM_DWMCOLORIZATIONCOLORCHANGED), |
| DEFINE_MESSAGE(WM_DWMWINDOWMAXIMIZEDCHANGE), |
| # endif /* _WIN32_WINNT >= 0x0600 */ |
| |
| # if(_WIN32_WINNT >= 0x0601) |
| DEFINE_MESSAGE(WM_DWMSENDICONICTHUMBNAIL), |
| DEFINE_MESSAGE(WM_DWMSENDICONICLIVEPREVIEWBITMAP), |
| # endif /* _WIN32_WINNT >= 0x0601 */ |
| |
| |
| # if(WINVER >= 0x0600) |
| DEFINE_MESSAGE(WM_GETTITLEBARINFOEX), |
| # endif /* WINVER >= 0x0600 */ |
| { 0, NULL, } /* end of message list */ |
| }; |
| #undef DEFINE_MESSAGE |
| |
| char* WMMsg2Str(DWORD dwMessage) |
| { |
| struct WM_MESSAGE_MAP* pMapMsg = allMessages; |
| for (/*null*/; pMapMsg->lpszMsg != NULL; pMapMsg++) |
| { |
| if (pMapMsg->nMsg == dwMessage ) |
| { |
| return (char *)pMapMsg->lpszMsg; |
| } |
| } |
| return ""; |
| } |
| #endif /* _DEBUG */ |
| |
| |
| /* Get system time, taking special precautions against 32bit timer wrap. |
| We use timeGetTime and not GetTickCount because of its better stability, |
| and because we can increase its granularity (to 1 ms in |
| fgPlatformInitialize). For that reason we can't use GetTickCount64 which |
| wouldn't have the wrap issue. |
| Credit: this is based on code in glibc (https://mail.gnome.org/archives/commits-list/2011-November/msg04588.html) |
| */ |
| static fg_time_t lastTime32 = 0; |
| static fg_time_t timeEpoch = 0; |
| void fgPlatformInitSystemTime() |
| { |
| #if defined(_WIN32_WCE) |
| lastTime32 = GetTickCount(); |
| #else |
| lastTime32 = timeGetTime(); |
| #endif |
| } |
| fg_time_t fgPlatformSystemTime ( void ) |
| { |
| fg_time_t currTime32; |
| #if defined(_WIN32_WCE) |
| currTime32 = GetTickCount(); |
| #else |
| currTime32 = timeGetTime(); |
| #endif |
| /* Check if we just wrapped */ |
| if (currTime32 < lastTime32) |
| timeEpoch++; |
| |
| lastTime32 = currTime32; |
| |
| return currTime32 | timeEpoch << 32; |
| } |
| |
| |
| void fgPlatformSleepForEvents( fg_time_t msec ) |
| { |
| MsgWaitForMultipleObjects( 0, NULL, FALSE, (DWORD) msec, QS_ALLINPUT ); |
| } |
| |
| |
| void fgPlatformProcessSingleEvent ( void ) |
| { |
| MSG stMsg; |
| |
| FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" ); |
| |
| while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) ) |
| { |
| if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 ) |
| { |
| if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT ) |
| { |
| fgDeinitialize( ); |
| exit( 0 ); |
| } |
| else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS ) |
| fgState.ExecState = GLUT_EXEC_STATE_STOP; |
| |
| return; |
| } |
| |
| TranslateMessage( &stMsg ); |
| DispatchMessage( &stMsg ); |
| } |
| } |
| |
| |
| |
| static void fghPlatformOnWindowStatusNotify(SFG_Window *window, GLboolean visState, GLboolean forceNotify) |
| { |
| GLboolean notify = GL_FALSE; |
| SFG_Window* child; |
| |
| if (window->State.Visible != visState) |
| { |
| window->State.Visible = visState; |
| |
| /* If top level window (not a subwindow/child), and icon title text available, switch titles based on visibility state */ |
| if (!window->Parent && window->State.pWState.IconTitle) |
| { |
| if (visState) |
| /* visible, set window title */ |
| SetWindowText( window->Window.Handle, window->State.pWState.WindowTitle ); |
| else |
| /* not visible, set icon title */ |
| SetWindowText( window->Window.Handle, window->State.pWState.IconTitle ); |
| } |
| |
| notify = GL_TRUE; |
| } |
| |
| if (notify || forceNotify) |
| { |
| SFG_Window *saved_window = fgStructure.CurrentWindow; |
| |
| /* On win32 we only have two states, window displayed and window not displayed (iconified) |
| * We map these to GLUT_FULLY_RETAINED and GLUT_HIDDEN respectively. |
| */ |
| INVOKE_WCB( *window, WindowStatus, ( visState ? GLUT_FULLY_RETAINED:GLUT_HIDDEN ) ); |
| fgSetWindow( saved_window ); |
| } |
| |
| /* Also set windowStatus/visibility state for children */ |
| for( child = ( SFG_Window * )window->Children.First; |
| child; |
| child = ( SFG_Window * )child->Node.Next ) |
| { |
| fghPlatformOnWindowStatusNotify(child, visState, GL_FALSE); /* No need to propagate forceNotify. Childs get this from their own INIT_WORK */ |
| } |
| } |
| |
| void fgPlatformMainLoopPreliminaryWork ( void ) |
| { |
| /* no-op */ |
| } |
| |
| |
| /* |
| * Determine a GLUT modifier mask based on MS-WINDOWS system info. |
| */ |
| static int fgPlatformGetModifiers (void) |
| { |
| return |
| ( ( ( GetKeyState( VK_LSHIFT ) < 0 ) || |
| ( GetKeyState( VK_RSHIFT ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) | |
| ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) || |
| ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL : 0 ) | |
| ( ( ( GetKeyState( VK_LMENU ) < 0 ) || |
| ( GetKeyState( VK_RMENU ) < 0 )) ? GLUT_ACTIVE_ALT : 0 ); |
| } |
| |
| /* Check whether a button (VK_*BUTTON) is currently depressed. Returns |
| * non-zero (not necessarily 1) if yes. */ |
| static SHORT fgGetAsyncKeyState(int vKey) |
| { |
| /* MSDN says: "If the most significant bit is set, the key is down, and if |
| * the least significant bit is set, the key was pressed after the previous |
| * call to GetAsyncKeyState." This behavior cannot be relied upon however. |
| * Remove this bit so that we can simply test with ! if key is up. |
| */ |
| return GetAsyncKeyState(vKey) & ~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; |
| |
| int keypress = -1; |
| |
| /* if keydown, check for repeat */ |
| /* If repeat is globally switched off, it cannot be switched back on per window. |
| * But if it is globally switched on, it can be switched off per window. This matches |
| * GLUT's behavior on X11, but not Nate Robbins' win32 GLUT, as he didn't implement the |
| * global state switch. |
| */ |
| if( keydown && ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) ) |
| return 1; |
| |
| /* Remember the current modifiers state so user can query it from their callback */ |
| fgState.Modifiers = fgPlatformGetModifiers( ); |
| |
| /* Convert the Win32 keystroke codes to GLUTtish way */ |
| # define 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 ); |
| |
| /* 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 && fgGetAsyncKeyState ( winKey ))\ |
| {\ |
| keypress = glutKey;\ |
| keyStateVar = 1;\ |
| }\ |
| else if (keyStateVar && !fgGetAsyncKeyState ( 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); |
| break; |
| case VK_SHIFT: |
| ASYNC_KEY_EVENT(VK_LSHIFT,GLUT_KEY_SHIFT_L,lShift); |
| ASYNC_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); |
| break; |
| #undef ASYNC_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; |
| |
| #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 ]; |
| |
| 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 */ |
| { |
| if(wParam==(unsigned)gxKeyList.vkRight) |
| keypress = GLUT_KEY_RIGHT; |
| else if(wParam==(unsigned)gxKeyList.vkLeft) |
| keypress = GLUT_KEY_LEFT; |
| else if(wParam==(unsigned)gxKeyList.vkUp) |
| keypress = GLUT_KEY_UP; |
| else if(wParam==(unsigned)gxKeyList.vkDown) |
| keypress = GLUT_KEY_DOWN; |
| else if(wParam==(unsigned)gxKeyList.vkA) |
| keypress = GLUT_KEY_F1; |
| else if(wParam==(unsigned)gxKeyList.vkB) |
| keypress = GLUT_KEY_F2; |
| else if(wParam==(unsigned)gxKeyList.vkC) |
| keypress = GLUT_KEY_F3; |
| else if(wParam==(unsigned)gxKeyList.vkStart) |
| keypress = GLUT_KEY_F4; |
| } |
| #endif |
| |
| if( keypress != -1 ) |
| if (keydown) |
| INVOKE_WCB( *window, Special, |
| ( keypress, |
| window->State.MouseX, window->State.MouseY ) |
| ); |
| else |
| INVOKE_WCB( *window, SpecialUp, |
| ( keypress, |
| window->State.MouseX, window->State.MouseY ) |
| ); |
| |
| fgState.Modifiers = INVALID_MODIFIERS; |
| |
| /* SYSKEY events should be sent to default window proc for system to handle them */ |
| if (uMsg==WM_SYSKEYDOWN || uMsg==WM_SYSKEYUP) |
| return DefWindowProc( window->Window.Handle, uMsg, wParam, lParam ); |
| else |
| return 1; |
| } |
| |
| SFG_Window* fghWindowUnderCursor(SFG_Window *window) |
| { |
| /* Check if the current window that the mouse is over is a child window |
| * of the window the message was sent to. Some events only sent to main window, |
| * and when handling some messages, we need to make sure that we process |
| * callbacks on the child window instead. This mirrors how GLUT does things. |
| * returns either the original window or the found child. |
| */ |
| if (window && window->Children.First) /* This window has childs */ |
| { |
| HWND hwnd; |
| SFG_Window* child_window; |
| |
| /* Get mouse position at time of message */ |
| DWORD mouse_pos_dw = GetMessagePos(); |
| POINT mouse_pos = {GET_X_LPARAM(mouse_pos_dw), GET_Y_LPARAM(mouse_pos_dw)}; |
| ScreenToClient( window->Window.Handle, &mouse_pos ); |
| |
| hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos); |
| if (hwnd && hwnd!=window->Window.Handle) /* can be NULL if mouse outside parent by the time we get here, or can be same as parent if we didn't find a child */ |
| { |
| child_window = fgWindowByHandle(hwnd); |
| if (child_window) /* Verify we got a FreeGLUT window */ |
| { |
| /* ChildWindowFromPoint only searches immediate children, so search again to see if actually in grandchild or further descendant */ |
| window = fghWindowUnderCursor(child_window); |
| } |
| } |
| } |
| |
| return window; |
| } |
| |
| /* |
| * The window procedure for handling Win32 events |
| */ |
| LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) |
| { |
| SFG_Window *window; |
| LRESULT lRet = 1; |
| static int setCaptureActive = 0; |
| |
| FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ; |
| |
| window = fgWindowByHandle( hWnd ); |
| |
| if ( ( window == NULL ) && ( uMsg != WM_CREATE ) ) |
| return DefWindowProc( hWnd, uMsg, wParam, lParam ); |
| |
| /* printf ( "Window %3d message %s (<%04x>) %12d %12d\n", window?window->ID:0, |
| WMMsg2Str(uMsg), uMsg, wParam, lParam ); */ |
| |
| switch( uMsg ) |
| { |
| case WM_CREATE: |
| /* The window structure is passed as the creation structure parameter... */ |
| window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams); |
| FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window", |
| "fgPlatformWindowProc" ); |
| |
| window->Window.Handle = hWnd; |
| window->Window.pContext.Device = GetDC( hWnd ); |
| if( window->IsMenu ) |
| { |
| unsigned int current_DisplayMode = fgState.DisplayMode; |
| fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH; |
| #if !defined(_WIN32_WCE) |
| fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE ); |
| #endif |
| fgState.DisplayMode = current_DisplayMode; |
| |
| if( fgStructure.MenuContext ) |
| wglMakeCurrent( window->Window.pContext.Device, |
| fgStructure.MenuContext->MContext |
| ); |
| else |
| { |
| fgStructure.MenuContext = |
| (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) ); |
| fgStructure.MenuContext->MContext = |
| wglCreateContext( window->Window.pContext.Device ); |
| } |
| |
| /* window->Window.Context = wglGetCurrentContext (); */ |
| window->Window.Context = wglCreateContext( window->Window.pContext.Device ); |
| } |
| else |
| { |
| #if !defined(_WIN32_WCE) |
| fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE ); |
| #endif |
| |
| if( ! fgState.UseCurrentContext ) |
| window->Window.Context = |
| wglCreateContext( window->Window.pContext.Device ); |
| else |
| { |
| window->Window.Context = wglGetCurrentContext( ); |
| if( ! window->Window.Context ) |
| window->Window.Context = |
| wglCreateContext( window->Window.pContext.Device ); |
| } |
| |
| #if !defined(_WIN32_WCE) |
| fgNewWGLCreateContext( window ); |
| #endif |
| } |
| |
| ReleaseDC( window->Window.Handle, window->Window.pContext.Device ); |
| |
| #if defined(_WIN32_WCE) |
| /* Take over button handling */ |
| { |
| HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll")); |
| if (dxDllLib) |
| { |
| GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z")); |
| GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ")); |
| } |
| |
| if(GXOpenInput_) |
| (*GXOpenInput_)(); |
| if(GXGetDefaultKeys_) |
| gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS); |
| } |
| |
| #endif /* defined(_WIN32_WCE) */ |
| break; |
| |
| case WM_SIZE: |
| /* printf("WM_SIZE (ID: %i): wParam: %i, new size: %ix%i \n",window->ID,wParam,LOWORD(lParam),HIWORD(lParam)); */ |
| |
| /* Update visibility state of the window */ |
| if (wParam==SIZE_MINIMIZED) |
| fghPlatformOnWindowStatusNotify(window,GL_FALSE,GL_FALSE); |
| else if (wParam==SIZE_RESTORED && !window->State.Visible) |
| fghPlatformOnWindowStatusNotify(window,GL_TRUE,GL_FALSE); |
| |
| /* Check window visible, we don't want do anything when we get a WM_SIZE because the user or glutIconifyWindow minimized the window */ |
| if( window->State.Visible ) |
| { |
| int width, height; |
| #if defined(_WIN32_WCE) |
| width = HIWORD(lParam); |
| height = LOWORD(lParam); |
| #else |
| width = LOWORD(lParam); |
| height = HIWORD(lParam); |
| #endif /* defined(_WIN32_WCE) */ |
| |
| /* Update state and call callback, if there was a change */ |
| fghOnReshapeNotify(window, width, height, GL_FALSE); |
| } |
| |
| /* according to docs, should return 0 */ |
| lRet = 0; |
| break; |
| |
| case WM_SIZING: |
| { |
| /* User resize-dragging the window, call reshape callback and |
| * force redisplay so display keeps running during dragging. |
| * Screen still wont update when not moving the cursor though... |
| */ |
| RECT rect; |
| /* PRECT prect = (PRECT) lParam; |
| printf("WM_SIZING: nc-area: %i,%i\n",prect->right-prect->left,prect->bottom-prect->top); */ |
| /* Get client area, the rect in lParam is including non-client area. */ |
| fghGetClientArea(&rect,window,FALSE); |
| |
| /* We'll get a WM_SIZE as well, but as state has |
| * already been updated here, the fghOnReshapeNotify |
| * in the handler for that message doesn't do anything. |
| */ |
| fghOnReshapeNotify(window, rect.right-rect.left, rect.bottom-rect.top, GL_FALSE); |
| |
| /* Now directly call the drawing function to update |
| * window and window's childs. |
| * This mimics the WM_PAINT messages that are received during |
| * resizing. Note that we don't have a WM_MOVING handler |
| * as move-dragging doesn't generate WM_MOVE or WM_PAINT |
| * messages until the mouse is released. |
| */ |
| fghRedrawWindowAndChildren(window); |
| } |
| |
| /* according to docs, should return TRUE */ |
| lRet = TRUE; |
| break; |
| |
| case WM_MOVE: |
| { |
| /* Check window is minimized, we don't want to call the position callback when the user or glutIconifyWindow minimized the window */ |
| if (!IsIconic(window->Window.Handle)) |
| { |
| RECT windowRect; |
| |
| /* lParam contains coordinates of top-left of client area. |
| * Get top-left of non-client area of window, matching coordinates of |
| * glutInitPosition and glutPositionWindow, but not those of |
| * glutGet(GLUT_WINDOW_X) and glutGet(GLUT_WINDOW_Y), which return |
| * top-left of client area. |
| */ |
| GetWindowRect( window->Window.Handle, &windowRect ); |
| |
| if (window->Parent) |
| { |
| /* For child window, we should return relative to upper-left |
| * of parent's client area. |
| */ |
| POINT topleft = {windowRect.left,windowRect.top}; |
| |
| ScreenToClient(window->Parent->Window.Handle,&topleft); |
| windowRect.left = topleft.x; |
| windowRect.top = topleft.y; |
| } |
| |
| /* Update state and call callback, if there was a change */ |
| fghOnPositionNotify(window, windowRect.left, windowRect.top, GL_FALSE); |
| } |
| } |
| |
| /* according to docs, should return 0 */ |
| lRet = 0; |
| break; |
| |
| case WM_SETFOCUS: |
| /*printf("WM_SETFOCUS: %p\n", window );*/ |
| lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); |
| |
| SetActiveWindow( window->Window.Handle ); |
| UpdateWindow ( hWnd ); |
| |
| break; |
| |
| case WM_KILLFOCUS: |
| /*printf("WM_KILLFOCUS: %p\n", window ); */ |
| lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); |
| |
| /* Check if there are any open menus that need to be closed */ |
| fgPlatformCheckMenuDeactivate((HWND)wParam); |
| break; |
| |
| case WM_MOUSEACTIVATE: |
| /* Clicks should not activate the menu. |
| * Especially important when clicking on a menu's submenu item which has no effect. |
| */ |
| /*printf("WM_MOUSEACTIVATE\n");*/ |
| if (window->IsMenu) |
| lRet = MA_NOACTIVATEANDEAT; |
| else |
| lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); |
| break; |
| |
| case WM_NCLBUTTONDOWN: |
| case WM_NCMBUTTONDOWN: |
| case WM_NCRBUTTONDOWN: |
| { |
| SFG_Menu *menu; |
| if (fgState.ActiveMenus && (menu = fgGetActiveMenu())) |
| /* user clicked non-client area of window while a menu is open. Close menu */ |
| fgDeactivateMenu(menu->ParentWindow); |
| |
| /* and always pass to DefWindowProc */ |
| lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); |
| } |
| break; |
| |
| #if 0 |
| case WM_ACTIVATE: |
| /* printf("WM_ACTIVATE: %x (ID: %i) %d %d\n",lParam, window->ID, HIWORD(wParam), LOWORD(wParam)); */ |
| if (LOWORD(wParam) != WA_INACTIVE) |
| { |
| /* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window, |
| window->State.Cursor ); */ |
| fgSetCursor( window, window->State.Cursor ); |
| } |
| |
| lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); |
| break; |
| #endif |
| |
| case WM_SETCURSOR: |
| /* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */ |
| if( LOWORD( lParam ) == HTCLIENT ) |
| { |
| if (!window->State.pWState.MouseTracking) |
| { |
| TRACKMOUSEEVENT tme; |
| |
| /* Cursor just entered window, set cursor look */ |
| fgSetCursor ( window, window->State.Cursor ) ; |
| |
| /* If an EntryFunc callback is specified by the user, also |
| * invoke that callback and start mouse tracking so that |
| * we get a WM_MOUSELEAVE message |
| */ |
| if (FETCH_WCB( *window, Entry )) |
| { |
| SFG_Window* saved_window = fgStructure.CurrentWindow; |
| INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) ); |
| fgSetWindow(saved_window); |
| |
| tme.cbSize = sizeof(TRACKMOUSEEVENT); |
| tme.dwFlags = TME_LEAVE; |
| tme.hwndTrack = window->Window.Handle; |
| TrackMouseEvent(&tme); |
| |
| window->State.pWState.MouseTracking = TRUE; |
| } |
| } |
| } |
| else |
| /* Only pass non-client WM_SETCURSOR to DefWindowProc, or we get WM_SETCURSOR on parents of children as well */ |
| lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); |
| break; |
| |
| case WM_MOUSELEAVE: |
| { |
| /* NB: This message is only received when a EntryFunc callback |
| * is specified by the user, as that is the only condition under |
| * which mouse tracking is setup in WM_SETCURSOR handler above |
| */ |
| SFG_Window* saved_window = fgStructure.CurrentWindow; |
| INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) ); |
| fgSetWindow(saved_window); |
| |
| window->State.pWState.MouseTracking = FALSE; |
| lRet = 0; /* As per docs, must return zero */ |
| } |
| break; |
| |
| case WM_SHOWWINDOW: |
| /* printf("WM_SHOWWINDOW, shown? %i, source: %i\n",wParam,lParam); */ |
| if (wParam) |
| { |
| fghPlatformOnWindowStatusNotify(window, GL_TRUE, GL_FALSE); |
| window->State.WorkMask |= GLUT_DISPLAY_WORK; |
| } |
| else |
| { |
| fghPlatformOnWindowStatusNotify(window, GL_FALSE, GL_FALSE); |
| window->State.WorkMask &= ~GLUT_DISPLAY_WORK; |
| } |
| break; |
| |
| case WM_PAINT: |
| { |
| RECT rect; |
| |
| /* As per docs, upon receiving WM_PAINT, first check if the update region is not empty before you call BeginPaint */ |
| if (GetUpdateRect(hWnd,&rect,FALSE)) |
| { |
| /* Dummy begin/end paint to validate rect that needs |
| * redrawing, then signal that a redisplay is needed. |
| * This allows us full control about when we do any |
| * redrawing, and is the same as what original GLUT |
| * does. |
| */ |
| PAINTSTRUCT ps; |
| BeginPaint( hWnd, &ps ); |
| EndPaint( hWnd, &ps ); |
| |
| window->State.WorkMask |= GLUT_DISPLAY_WORK; |
| } |
| lRet = 0; /* As per docs, should return 0 */ |
| } |
| break; |
| |
| case WM_CLOSE: |
| fgDestroyWindow ( window ); |
| if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION ) |
| PostQuitMessage(0); |
| break; |
| |
| case WM_DESTROY: |
| /* |
| * The window already got destroyed, so don't bother with it. |
| */ |
| return 0; |
| |
| case WM_MOUSEMOVE: |
| { |
| /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */ |
| #if defined(_WIN32_WCE) |
| window->State.MouseX = 320-HIWORD( lParam ); /* XXX: Docs say x should be loword and y hiword? */ |
| window->State.MouseY = LOWORD( lParam ); |
| #else |
| window->State.MouseX = GET_X_LPARAM( lParam ); |
| window->State.MouseY = GET_Y_LPARAM( lParam ); |
| #endif /* defined(_WIN32_WCE) */ |
| /* Restrict to [-32768, 32767] to match X11 behaviour */ |
| /* See comment in "freeglut_developer" mailing list 10/4/04 */ |
| if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536; |
| if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536; |
| |
| if ( window->ActiveMenu ) |
| { |
| fgUpdateMenuHighlight( window->ActiveMenu ); |
| break; |
| } |
| |
| fgState.Modifiers = fgPlatformGetModifiers( ); |
| |
| if( ( wParam & MK_LBUTTON ) || |
| ( wParam & MK_MBUTTON ) || |
| ( wParam & MK_RBUTTON ) ) |
| INVOKE_WCB( *window, Motion, ( window->State.MouseX, |
| window->State.MouseY ) ); |
| else |
| INVOKE_WCB( *window, Passive, ( window->State.MouseX, |
| window->State.MouseY ) ); |
| |
| fgState.Modifiers = INVALID_MODIFIERS; |
| } |
| break; |
| |
| case WM_LBUTTONDOWN: |
| case WM_MBUTTONDOWN: |
| case WM_RBUTTONDOWN: |
| case WM_LBUTTONUP: |
| case WM_MBUTTONUP: |
| case WM_RBUTTONUP: |
| { |
| GLboolean pressed = GL_TRUE; |
| int button; |
| |
| /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */ |
| #if defined(_WIN32_WCE) |
| window->State.MouseX = 320-HIWORD( lParam ); /* XXX: Docs say x should be loword and y hiword? */ |
| window->State.MouseY = LOWORD( lParam ); |
| #else |
| window->State.MouseX = GET_X_LPARAM( lParam ); |
| window->State.MouseY = GET_Y_LPARAM( lParam ); |
| #endif /* defined(_WIN32_WCE) */ |
| |
| /* Restrict to [-32768, 32767] to match X11 behaviour */ |
| /* See comment in "freeglut_developer" mailing list 10/4/04 */ |
| if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536; |
| if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536; |
| |
| switch( uMsg ) |
| { |
| case WM_LBUTTONDOWN: |
| pressed = GL_TRUE; |
| button = GLUT_LEFT_BUTTON; |
| break; |
| case WM_MBUTTONDOWN: |
| pressed = GL_TRUE; |
| button = GLUT_MIDDLE_BUTTON; |
| break; |
| case WM_RBUTTONDOWN: |
| pressed = GL_TRUE; |
| button = GLUT_RIGHT_BUTTON; |
| break; |
| case WM_LBUTTONUP: |
| pressed = GL_FALSE; |
| button = GLUT_LEFT_BUTTON; |
| break; |
| case WM_MBUTTONUP: |
| pressed = GL_FALSE; |
| button = GLUT_MIDDLE_BUTTON; |
| break; |
| case WM_RBUTTONUP: |
| pressed = GL_FALSE; |
| button = GLUT_RIGHT_BUTTON; |
| break; |
| default: |
| pressed = GL_FALSE; |
| button = -1; |
| break; |
| } |
| |
| #if !defined(_WIN32_WCE) |
| if( GetSystemMetrics( SM_SWAPBUTTON ) ) |
| { |
| if( button == GLUT_LEFT_BUTTON ) |
| button = GLUT_RIGHT_BUTTON; |
| else |
| if( button == GLUT_RIGHT_BUTTON ) |
| button = GLUT_LEFT_BUTTON; |
| } |
| #endif /* !defined(_WIN32_WCE) */ |
| |
| if( button == -1 ) |
| return DefWindowProc( hWnd, uMsg, lParam, wParam ); |
| |
| /* |
| * Do not execute the application's mouse callback if a menu |
| * is hooked to this button. In that case an appropriate |
| * private call should be generated. |
| */ |
| if( fgCheckActiveMenu( window, button, pressed, |
| window->State.MouseX, window->State.MouseY ) ) |
| break; |
| |
| /* Set capture so that the window captures all the mouse messages |
| * |
| * The mouse is not released from the window until all buttons have |
| * been released, even if the user presses a button in another window. |
| * This is consistent with the behavior on X11. |
| */ |
| if ( pressed == GL_TRUE ) |
| { |
| if (!setCaptureActive) |
| SetCapture ( window->Window.Handle ) ; |
| setCaptureActive = 1; /* Set to false in WM_CAPTURECHANGED handler */ |
| } |
| else if (!fgGetAsyncKeyState(VK_LBUTTON) && !fgGetAsyncKeyState(VK_MBUTTON) && !fgGetAsyncKeyState(VK_RBUTTON)) |
| /* Make sure all mouse buttons are released before releasing capture */ |
| ReleaseCapture () ; |
| |
| if( ! FETCH_WCB( *window, Mouse ) ) |
| break; |
| |
| fgSetWindow( window ); |
| fgState.Modifiers = fgPlatformGetModifiers( ); |
| |
| INVOKE_WCB( |
| *window, Mouse, |
| ( button, |
| pressed ? GLUT_DOWN : GLUT_UP, |
| window->State.MouseX, |
| window->State.MouseY |
| ) |
| ); |
| |
| fgState.Modifiers = INVALID_MODIFIERS; |
| |
| /* As per docs, should return zero */ |
| lRet = 0; |
| } |
| break; |
| |
| case WM_MOUSEWHEEL: |
| { |
| int wheel_number = 0; /* Only one scroll wheel on windows */ |
| #if defined(_WIN32_WCE) |
| int modkeys = LOWORD(wParam); |
| short ticks = (short)HIWORD(wParam); |
| /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first: |
| xPos = LOWORD(lParam); -- straight from docs, not consistent with mouse nutton and mouse motion above (which i think is wrong) |
| yPos = HIWORD(lParam); |
| */ |
| #else |
| /* int modkeys = GET_KEYSTATE_WPARAM( wParam ); */ |
| short ticks = GET_WHEEL_DELTA_WPARAM( wParam ); |
| /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first: |
| window->State.MouseX = GET_X_LPARAM( lParam ); |
| window->State.MouseY = GET_Y_LPARAM( lParam ); |
| */ |
| #endif /* defined(_WIN32_WCE) */ |
| |
| window = fghWindowUnderCursor(window); |
| |
| fgState.MouseWheelTicks += ticks; |
| if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA ) |
| { |
| int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1; |
| |
| if( ! FETCH_WCB( *window, MouseWheel ) && |
| ! FETCH_WCB( *window, Mouse ) ) |
| break; |
| |
| fgSetWindow( window ); |
| fgState.Modifiers = fgPlatformGetModifiers( ); |
| |
| while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA ) |
| { |
| if( FETCH_WCB( *window, MouseWheel ) ) |
| INVOKE_WCB( *window, MouseWheel, |
| ( wheel_number, |
| direction, |
| window->State.MouseX, |
| window->State.MouseY |
| ) |
| ); |
| else /* No mouse wheel, call the mouse button callback twice */ |
| { |
| /* |
| * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4 |
| * " " one +1 to 5, -1 to 6, ... |
| * |
| * XXX The below assumes that you have no more than 3 mouse |
| * XXX buttons. Sorry. |
| */ |
| int button = wheel_number * 2 + 3; |
| if( direction < 0 ) |
| ++button; |
| INVOKE_WCB( *window, Mouse, |
| ( button, GLUT_DOWN, |
| window->State.MouseX, window->State.MouseY ) |
| ); |
| INVOKE_WCB( *window, Mouse, |
| ( button, GLUT_UP, |
| window->State.MouseX, window->State.MouseY ) |
| ); |
| } |
| |
| fgState.MouseWheelTicks -= WHEEL_DELTA * direction; |
| } |
| |
| fgState.Modifiers = INVALID_MODIFIERS; |
| } |
| /* Per docs, should return zero */ |
| lRet = 0; |
| } |
| break ; |
| |
| case WM_SYSKEYDOWN: |
| case WM_KEYDOWN: |
| { |
| window = fghWindowUnderCursor(window); |
| lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam); |
| } |
| break; |
| |
| case WM_SYSKEYUP: |
| case WM_KEYUP: |
| { |
| window = fghWindowUnderCursor(window); |
| lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam); |
| } |
| break; |
| |
| case WM_SYSCHAR: |
| case WM_CHAR: |
| { |
| window = fghWindowUnderCursor(window); |
| |
| if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) ) |
| break; |
| |
| fgState.Modifiers = fgPlatformGetModifiers( ); |
| INVOKE_WCB( *window, Keyboard, |
| ( (char)wParam, |
| window->State.MouseX, window->State.MouseY ) |
| ); |
| fgState.Modifiers = INVALID_MODIFIERS; |
| } |
| break; |
| |
| case WM_CAPTURECHANGED: |
| if (!lParam || !fgWindowByHandle((HWND)lParam)) |
| /* Capture released or capture taken by non-FreeGLUT window */ |
| setCaptureActive = 0; |
| /* Docs advise a redraw */ |
| InvalidateRect( hWnd, NULL, GL_FALSE ); |
| UpdateWindow(hWnd); |
| lRet = 0; /* Per docs, should return zero */ |
| break; |
| |
| #if !defined(_WIN32_WCE) |
| case WM_SYNCPAINT: /* 0x0088 */ |
| /* Another window has moved, need to update this one */ |
| window->State.WorkMask |= GLUT_DISPLAY_WORK; |
| lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); |
| /* Help screen says this message must be passed to "DefWindowProc" */ |
| break; |
| |
| case WM_DISPLAYCHANGE: /* 0x007E */ |
| /* The system display resolution/depth has changed */ |
| fgDisplay.ScreenWidth = LOWORD(lParam); |
| fgDisplay.ScreenHeight = HIWORD(lParam); |
| break; |
| |
| case WM_SYSCOMMAND : /* 0x0112 */ |
| { |
| /* |
| * We have received a system command message. Try to act on it. |
| * The commands are passed in through the "wParam" parameter: |
| * The least significant digit seems to be which edge of the window |
| * is being used for a resize event: |
| * 4 3 5 |
| * 1 2 |
| * 7 6 8 |
| * Congratulations and thanks to Richard Rauch for figuring this out.. |
| */ |
| switch ( wParam & 0xfff0 ) |
| { |
| case SC_SIZE : |
| break ; |
| |
| case SC_MOVE : |
| break ; |
| |
| case SC_MINIMIZE : |
| /* User has clicked on the "-" to minimize the window */ |
| /* Turning off the visibility is handled in WM_SIZE handler */ |
| |
| break ; |
| |
| case SC_MAXIMIZE : |
| break ; |
| |
| case SC_NEXTWINDOW : |
| break ; |
| |
| case SC_PREVWINDOW : |
| break ; |
| |
| case SC_CLOSE : |
| /* Followed very closely by a WM_CLOSE message */ |
| break ; |
| |
| case SC_VSCROLL : |
| break ; |
| |
| case SC_HSCROLL : |
| break ; |
| |
| case SC_MOUSEMENU : |
| break ; |
| |
| case SC_KEYMENU : |
| break ; |
| |
| case SC_ARRANGE : |
| break ; |
| |
| case SC_RESTORE : |
| break ; |
| |
| case SC_TASKLIST : |
| break ; |
| |
| case SC_SCREENSAVE : |
| break ; |
| |
| case SC_HOTKEY : |
| break ; |
| |
| #if(WINVER >= 0x0400) |
| case SC_DEFAULT : |
| break ; |
| |
| case SC_MONITORPOWER : |
| break ; |
| |
| case SC_CONTEXTHELP : |
| break ; |
| #endif /* WINVER >= 0x0400 */ |
| |
| default: |
| #if _DEBUG |
| fgWarning( "Unknown wParam type 0x%x", wParam ); |
| #endif |
| break; |
| } |
| } |
| #endif /* !defined(_WIN32_WCE) */ |
| |
| /* We need to pass the message on to the operating system as well */ |
| lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); |
| break; |
| |
| #ifdef WM_TOUCH |
| /* handle multi-touch messages */ |
| case WM_TOUCH: |
| { |
| unsigned int numInputs = (unsigned int)wParam; |
| unsigned int i = 0; |
| TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs); |
| |
| if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) { |
| fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo"); |
| fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle"); |
| } |
| |
| if (!fghGetTouchInputInfo) { |
| free( (void*)ti ); |
| break; |
| } |
| |
| if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) { |
| /* Handle each contact point */ |
| for (i = 0; i < numInputs; ++i ) { |
| |
| POINT tp; |
| tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x); |
| tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y); |
| ScreenToClient( hWnd, &tp ); |
| |
| ti[i].dwID = ti[i].dwID * 2; |
| |
| if (ti[i].dwFlags & TOUCHEVENTF_DOWN) { |
| INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) ); |
| INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) ); |
| } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) { |
| INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) ); |
| } else if (ti[i].dwFlags & TOUCHEVENTF_UP) { |
| INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) ); |
| INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) ); |
| } |
| } |
| } |
| fghCloseTouchInputHandle((HTOUCHINPUT)lParam); |
| free( (void*)ti ); |
| lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/ |
| break; |
| } |
| #endif |
| default: |
| /* Handle unhandled messages */ |
| lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); |
| break; |
| } |
| |
| return lRet; |
| } |
| |
| |
| /* deal with work list items */ |
| void fgPlatformInitWork(SFG_Window* window) |
| { |
| RECT windowRect; |
| |
| /* Notify windowStatus/visibility */ |
| fghPlatformOnWindowStatusNotify(window, window->State.Visible, GL_TRUE); |
| |
| /* get and notify window's position */ |
| GetWindowRect(window->Window.Handle,&windowRect); |
| fghOnPositionNotify(window, windowRect.left, windowRect.top, GL_TRUE); |
| |
| /* get and notify window's size */ |
| GetClientRect(window->Window.Handle,&windowRect); |
| fghOnReshapeNotify(window, windowRect.right-windowRect.left, windowRect.bottom-windowRect.top, GL_TRUE); |
| } |
| |
| /* On windows we can position, resize and change z order at the same time */ |
| void fgPlatformPosResZordWork(SFG_Window* window, unsigned int workMask) |
| { |
| UINT flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER; |
| HWND insertAfter = HWND_TOP; |
| RECT clientRect; |
| |
| #if !defined(_WIN32_WCE) /* FIXME: what about WinCE */ |
| if (workMask & GLUT_FULL_SCREEN_WORK) |
| { |
| /* This asks us to toggle fullscreen mode */ |
| flags |= SWP_FRAMECHANGED; |
| |
| if (window->State.IsFullscreen) |
| { |
| /* If we are fullscreen, resize the current window back to its original size */ |
| /* printf("OldRect %i,%i to %i,%i\n",window->State.pWState.OldRect.left,window->State.pWState.OldRect.top,window->State.pWState.OldRect.right,window->State.pWState.OldRect.bottom); */ |
| |
| /* restore style of window before making it fullscreen */ |
| SetWindowLong(window->Window.Handle, GWL_STYLE, window->State.pWState.OldStyle); |
| SetWindowLong(window->Window.Handle, GWL_EXSTYLE, window->State.pWState.OldStyleEx); |
| |
| /* Then set up resize/reposition, unless user already queued up reshape/position work */ |
| if (!(workMask & GLUT_POSITION_WORK)) |
| { |
| workMask |= GLUT_POSITION_WORK; |
| window->State.DesiredXpos = window->State.pWState.OldRect.left; |
| window->State.DesiredYpos = window->State.pWState.OldRect.top; |
| } |
| if (!(workMask & GLUT_SIZE_WORK)) |
| { |
| workMask |= GLUT_SIZE_WORK; |
| window->State.DesiredWidth = window->State.pWState.OldRect.right - window->State.pWState.OldRect.left; |
| window->State.DesiredHeight = window->State.pWState.OldRect.bottom - window->State.pWState.OldRect.top; |
| } |
| |
| /* We'll finish off the fullscreen operation below after the other GLUT_POSITION_WORK|GLUT_SIZE_WORK|GLUT_ZORDER_WORK */ |
| } |
| else |
| { |
| /* we are currently not fullscreen, go to fullscreen: |
| * remove window decoration and then maximize |
| */ |
| RECT rect; |
| HMONITOR hMonitor; |
| MONITORINFO mi; |
| |
| /* save current window rect, style, exstyle and maximized state */ |
| window->State.pWState.OldMaximized = !!IsZoomed(window->Window.Handle); |
| if (window->State.pWState.OldMaximized) |
| /* We force the window into restored mode before going |
| * fullscreen because Windows doesn't seem to hide the |
| * taskbar if the window is in the maximized state. |
| */ |
| SendMessage(window->Window.Handle, WM_SYSCOMMAND, SC_RESTORE, 0); |
| |
| fghGetClientArea( &window->State.pWState.OldRect, window, GL_TRUE ); |
| window->State.pWState.OldStyle = GetWindowLong(window->Window.Handle, GWL_STYLE); |
| window->State.pWState.OldStyleEx = GetWindowLong(window->Window.Handle, GWL_EXSTYLE); |
| |
| /* remove decorations from style */ |
| SetWindowLong(window->Window.Handle, GWL_STYLE, |
| window->State.pWState.OldStyle & ~(WS_CAPTION | WS_THICKFRAME)); |
| SetWindowLong(window->Window.Handle, GWL_EXSTYLE, |
| window->State.pWState.OldStyleEx & ~(WS_EX_DLGMODALFRAME | |
| WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)); |
| |
| /* For fullscreen mode, find the monitor that is covered the most |
| * by the window and get its rect as the resize target. |
| */ |
| 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; |
| } |
| } |
| #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 || win->ActiveMenu->ParentWindow != fgStructure.GameModeWindow)) |
| cmdShow = SW_SHOWNA; /* Just show, don't activate window if its a menu. Only exception is when the parent is a gamemode window as the menu would pop under it when we do this... */ |
| else |
| cmdShow = SW_SHOW; |
| break; |
| } |
| |
| ShowWindow( win->Window.Handle, cmdShow ); |
| } |