rControl = 0, rShift = 0, rAlt = 0;
int keypress = -1;
- POINT mouse_pos ;
/* 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( );
- /* Get mouse position roughly at time of keypress */
- GetCursorPos( &mouse_pos );
- ScreenToClient( window->Window.Handle, &mouse_pos );
- window->State.MouseX = mouse_pos.x;
- window->State.MouseY = mouse_pos.y;
-
/* Convert the Win32 keystroke codes to GLUTtish way */
# define KEY(a,b) case a: keypress = b; break;
return 1;
}
+static 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 */
+ {
+ SFG_WindowHandleType 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, *child_window = NULL;
- PAINTSTRUCT ps;
+ SFG_Window *window;
LRESULT lRet = 1;
FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
/* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
uMsg, wParam, lParam ); */
- /* Some events only sent to main window. Check if the current window that
- * the mouse is over is a child window. Below when handling some messages,
- * we make sure that we process callbacks on the child window instead.
- * This mirrors how GLUT does things.
- */
- if (window && window->Children.First)
- {
- POINT mouse_pos;
- SFG_WindowHandleType hwnd;
- SFG_Window* temp_window;
-
- GetCursorPos( &mouse_pos );
- ScreenToClient( window->Window.Handle, &mouse_pos );
- hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
- if (hwnd) /* can be NULL if mouse outside parent by the time we get here */
- {
- temp_window = fgWindowByHandle(hwnd);
- if (temp_window && temp_window->Parent) /* Verify we got a child window */
- child_window = temp_window;
- }
- }
-
switch( uMsg )
{
case WM_CREATE:
lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
- if (child_window)
- {
- /* If we're dealing with a child window, make sure it has input focus instead, set it here. */
- SetFocus(child_window->Window.Handle);
- SetActiveWindow( child_window->Window.Handle );
- INVOKE_WCB( *child_window, Entry, ( GLUT_ENTERED ) );
- UpdateWindow ( child_window->Window.Handle );
- }
- else
- {
- SetActiveWindow( window->Window.Handle );
- INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
- }
- /* Always request update on main window to be safe */
+ SetActiveWindow( window->Window.Handle );
UpdateWindow ( hWnd );
break;
case WM_KILLFOCUS:
{
- SFG_Window* saved_window = fgStructure.CurrentWindow;
/* printf("WM_KILLFOCUS: %p\n", window ); */
lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
- INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
- fgSetWindow(saved_window);
/* Check if there are any open menus that need to be closed */
fgPlatformCheckMenuDeactivate();
#if 0
case WM_ACTIVATE:
+ //printf("WM_ACTIVATE: %x %d %d\n",lParam, HIWORD(wParam), LOWORD(wParam));
if (LOWORD(wParam) != WA_INACTIVE)
{
/* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
case WM_SETCURSOR:
/* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
if( LOWORD( lParam ) == HTCLIENT )
- fgSetCursor ( window, window->State.Cursor ) ;
+ {
+ if (!window->State.pWState.MouseTracking)
+ {
+ TRACKMOUSEEVENT tme;
+
+ /* Cursor just entered window, set cursor look */
+ fgSetCursor ( window, window->State.Cursor ) ;
+
+ /* If an EntryFunc callback is specified by the user, also
+ * invoke that callback and start mouse tracking so that
+ * we get a WM_MOUSELEAVE message
+ */
+ if (FETCH_WCB( *window, Entry ))
+ {
+ INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
+
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = window->Window.Handle;
+ TrackMouseEvent(&tme);
+
+ window->State.pWState.MouseTracking = GL_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 = GL_FALSE;
+ lRet = 0; /* As per docs, must return zero */
+ }
+ break;
+
case WM_SHOWWINDOW:
window->State.Visible = GL_TRUE;
window->State.Redisplay = GL_TRUE;
break;
case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
/* Turn on the visibility in case it was turned off somehow */
window->State.Visible = GL_TRUE;
InvalidateRect( hWnd, NULL, GL_FALSE ); /* Make sure whole window is repainted. Bit of a hack, but a safe one from what google turns up... */
BeginPaint( hWnd, &ps );
fghRedrawWindow( window );
EndPaint( hWnd, &ps );
- break;
+ }
+ break;
case WM_CLOSE:
fgDestroyWindow ( window );
case WM_MOUSEWHEEL:
{
+ SFG_Window *child_window = NULL;
int wheel_number = LOWORD( wParam );
short ticks = ( short )HIWORD( wParam );
- fgState.MouseWheelTicks += ticks;
+ window = fghWindowUnderCursor(window);
+
+ fgState.MouseWheelTicks += ticks;
if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
{
int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
case WM_SYSKEYDOWN:
case WM_KEYDOWN:
- if (child_window)
- window = child_window;
+ {
+ window = fghWindowUnderCursor(window);
lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
+ }
break;
case WM_SYSKEYUP:
case WM_KEYUP:
- if (child_window)
- window = child_window;
+ {
+ window = fghWindowUnderCursor(window);
lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
+ }
break;
case WM_SYSCHAR:
case WM_CHAR:
{
- if (child_window)
- window = child_window;
+ window = fghWindowUnderCursor(window);
if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
break;
case WM_CAPTURECHANGED:
/* User has finished resizing the window, force a redraw */
INVOKE_WCB( *window, Display, ( ) );
-
- /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */
+ lRet = 0; /* Per docs, should return zero */
break;
/* Other messages that I have seen and which are not handled already */