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