extern GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
unsigned char layer_type );
+extern void fgPlatformCheckMenuDeactivate();
+
#ifdef WM_TOUCH
typedef BOOL (WINAPI *pGetTouchInputInfo)(HTOUCHINPUT,UINT,PTOUCHINPUT,int);
typedef BOOL (WINAPI *pCloseTouchInputHandle)(HTOUCHINPUT);
* and the window rect from the client area given the style of the window
* (or a valid window pointer from which the style can be queried).
*/
-extern void fghComputeWindowRectFromClientArea_QueryWindow( const SFG_Window *window, RECT *clientRect, BOOL posIsOutside );
-extern RECT fghGetClientArea ( const SFG_Window *window, BOOL wantPosOutside );
+extern void fghComputeWindowRectFromClientArea_QueryWindow( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside );
+extern void fghGetClientArea ( RECT *clientRect, const SFG_Window *window, BOOL wantPosOutside );
void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height )
* For windowed mode, get the current position of the
* window and resize taking the size of the frame
* decorations into account.
+ *
+ * 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.
*/
/* "GetWindowRect" returns the pixel coordinates of the outside of the window */
if (window->Parent == NULL)
/* get the window rect from this to feed to SetWindowPos, correct for window decorations */
- fghComputeWindowRectFromClientArea_QueryWindow(window,&windowRect,TRUE);
+ fghComputeWindowRectFromClientArea_QueryWindow(&windowRect,window,TRUE);
else
{
/* correct rect for position client area of parent window
* for them.
*/
RECT parentRect;
- parentRect = fghGetClientArea( window->Parent, FALSE );
- windowRect.left -= parentRect.left;
- windowRect.right -= parentRect.left;
- windowRect.top -= parentRect.top;
- windowRect.bottom -= parentRect.top;
+ fghGetClientArea( &parentRect, window->Parent, FALSE );
+ OffsetRect(&windowRect,-parentRect.left,-parentRect.top);
}
/* Do the actual resizing */
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
SWP_NOZORDER
);
+
+ /* Set new width and height so we can test for that in WM_SIZE message handler and don't do anything if not needed */
+ window->State.Width = width;
+ window->State.Height = height;
}
/*
- * Determine a GLUT modifer mask based on MS-WINDOWS system info.
+ * Determine a GLUT modifier mask based on MS-WINDOWS system info.
*/
static int fgPlatformGetModifiers (void)
{
static unsigned char lControl = 0, rControl = 0, lShift = 0,
rShift = 0, lAlt = 0, rAlt = 0;
- SFG_Window* window;
+ SFG_Window *window, *child_window = NULL;
PAINTSTRUCT ps;
LRESULT lRet = 1;
/* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
uMsg, wParam, lParam ); */
- if ( window )
+ /* 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)
{
- /* Checking for CTRL, ALT, and SHIFT key positions: Key Down! */
- if ( !lControl && GetAsyncKeyState ( VK_LCONTROL ) )
- {
- INVOKE_WCB ( *window, Special,
- ( GLUT_KEY_CTRL_L, window->State.MouseX, window->State.MouseY )
- );
-
- lControl = 1;
- }
-
- if ( !rControl && GetAsyncKeyState ( VK_RCONTROL ) )
- {
- INVOKE_WCB ( *window, Special,
- ( GLUT_KEY_CTRL_R, window->State.MouseX, window->State.MouseY )
- );
-
- rControl = 1;
- }
-
- if ( !lShift && GetAsyncKeyState ( VK_LSHIFT ) )
- {
- INVOKE_WCB ( *window, Special,
- ( GLUT_KEY_SHIFT_L, window->State.MouseX, window->State.MouseY )
- );
-
- lShift = 1;
- }
+ POINT mouse_pos;
+ SFG_WindowHandleType hwnd;
+ SFG_Window* temp_window;
- if ( !rShift && GetAsyncKeyState ( VK_RSHIFT ) )
- {
- INVOKE_WCB ( *window, Special,
- ( GLUT_KEY_SHIFT_R, window->State.MouseX, window->State.MouseY )
- );
+ 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->Parent) /* Verify we got a child window */
+ child_window = temp_window;
+ }
+ }
- rShift = 1;
- }
+ if ( window )
+ {
+ SFG_Window* temp_window = child_window?child_window:window;
- if ( !lAlt && GetAsyncKeyState ( VK_LMENU ) )
- {
- INVOKE_WCB ( *window, Special,
- ( GLUT_KEY_ALT_L, window->State.MouseX, window->State.MouseY )
- );
+ fgState.Modifiers = fgPlatformGetModifiers( );
- lAlt = 1;
+ /* Checking for CTRL, ALT, and SHIFT key positions: Key Down! */
+#define SPECIAL_KEY_DOWN(winKey,glutKey,winProcVar)\
+ if ( !winProcVar && GetAsyncKeyState ( winKey ) )\
+ {\
+ INVOKE_WCB ( *temp_window, Special,\
+ ( glutKey, temp_window->State.MouseX, temp_window->State.MouseY )\
+ );\
+ winProcVar = 1;\
}
- if ( !rAlt && GetAsyncKeyState ( VK_RMENU ) )
- {
- INVOKE_WCB ( *window, Special,
- ( GLUT_KEY_ALT_R, window->State.MouseX, window->State.MouseY )
- );
-
- rAlt = 1;
- }
+ SPECIAL_KEY_DOWN(VK_LCONTROL,GLUT_KEY_CTRL_L ,lControl);
+ SPECIAL_KEY_DOWN(VK_RCONTROL,GLUT_KEY_CTRL_R ,rControl);
+ SPECIAL_KEY_DOWN(VK_LSHIFT ,GLUT_KEY_SHIFT_L,lShift);
+ SPECIAL_KEY_DOWN(VK_RSHIFT ,GLUT_KEY_SHIFT_R,rShift);
+ SPECIAL_KEY_DOWN(VK_LMENU ,GLUT_KEY_ALT_L ,lAlt);
+ SPECIAL_KEY_DOWN(VK_RMENU ,GLUT_KEY_ALT_R ,rAlt);
+#undef SPECIAL_KEY_DOWN
/* Checking for CTRL, ALT, and SHIFT key positions: Key Up! */
- if ( lControl && !GetAsyncKeyState ( VK_LCONTROL ) )
- {
- INVOKE_WCB ( *window, SpecialUp,
- ( GLUT_KEY_CTRL_L, window->State.MouseX, window->State.MouseY )
- );
-
- lControl = 0;
- }
-
- if ( rControl && !GetAsyncKeyState ( VK_RCONTROL ) )
- {
- INVOKE_WCB ( *window, SpecialUp,
- ( GLUT_KEY_CTRL_R, window->State.MouseX, window->State.MouseY )
- );
-
- rControl = 0;
- }
-
- if ( lShift && !GetAsyncKeyState ( VK_LSHIFT ) )
- {
- INVOKE_WCB ( *window, SpecialUp,
- ( GLUT_KEY_SHIFT_L, window->State.MouseX, window->State.MouseY )
- );
-
- lShift = 0;
- }
-
- if ( rShift && !GetAsyncKeyState ( VK_RSHIFT ) )
- {
- INVOKE_WCB ( *window, SpecialUp,
- ( GLUT_KEY_SHIFT_R, window->State.MouseX, window->State.MouseY )
- );
-
- rShift = 0;
+#define SPECIAL_KEY_UP(winKey,glutKey,winProcVar)\
+ if ( winProcVar && !GetAsyncKeyState ( winKey ) )\
+ {\
+ INVOKE_WCB ( *temp_window, SpecialUp,\
+ ( glutKey, temp_window->State.MouseX, temp_window->State.MouseY )\
+ );\
+ winProcVar = 0;\
}
- if ( lAlt && !GetAsyncKeyState ( VK_LMENU ) )
- {
- INVOKE_WCB ( *window, SpecialUp,
- ( GLUT_KEY_ALT_L, window->State.MouseX, window->State.MouseY )
- );
-
- lAlt = 0;
- }
+ SPECIAL_KEY_UP(VK_LCONTROL,GLUT_KEY_CTRL_L ,lControl);
+ SPECIAL_KEY_UP(VK_RCONTROL,GLUT_KEY_CTRL_R ,rControl);
+ SPECIAL_KEY_UP(VK_LSHIFT ,GLUT_KEY_SHIFT_L,lShift);
+ SPECIAL_KEY_UP(VK_RSHIFT ,GLUT_KEY_SHIFT_R,rShift);
+ SPECIAL_KEY_UP(VK_LMENU ,GLUT_KEY_ALT_L ,lAlt);
+ SPECIAL_KEY_UP(VK_RMENU ,GLUT_KEY_ALT_R ,rAlt);
+#undef SPECIAL_KEY_UP
- if ( rAlt && !GetAsyncKeyState ( VK_RMENU ) )
- {
- INVOKE_WCB ( *window, SpecialUp,
- ( GLUT_KEY_ALT_R, window->State.MouseX, window->State.MouseY )
- );
-
- rAlt = 0;
- }
+ fgState.Modifiers = INVALID_MODIFIERS;
}
switch( uMsg )
*/
if( window->State.Visible )
{
- window->State.NeedToResize = GL_TRUE;
+ /* get old values first to compare to below */
+ int width = window->State.Width, height=window->State.Height;
#if defined(_WIN32_WCE)
window->State.Width = HIWORD(lParam);
window->State.Height = LOWORD(lParam);
window->State.Width = LOWORD(lParam);
window->State.Height = HIWORD(lParam);
#endif /* defined(_WIN32_WCE) */
+
+ if (width!=window->State.Width || height!=window->State.Height)
+ /* Something changed, need to resize */
+ window->State.NeedToResize = GL_TRUE;
}
break;
+ case WM_MOVE:
+ {
+ SFG_Window* saved_window = fgStructure.CurrentWindow;
+ RECT windowRect;
+ 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;
+ }
+
+ INVOKE_WCB( *window, Position, ( windowRect.left, windowRect.top ) );
+ fgSetWindow(saved_window);
+ }
+ break;
+
case WM_SETFOCUS:
/* printf("WM_SETFOCUS: %p\n", window ); */
+
lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
- INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
- UpdateWindow ( hWnd );
+ 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 */
+ UpdateWindow ( hWnd );
+
break;
case WM_KILLFOCUS:
-/* printf("WM_KILLFOCUS: %p\n", window ); */
- lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
- INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
-
- if( window->IsMenu &&
- window->ActiveMenu && window->ActiveMenu->IsActive )
- fgUpdateMenuHighlight( window->ActiveMenu );
+ {
+ 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();
+ }
break;
#if 0
case WM_PAINT:
/* 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 );
fgUpdateMenuHighlight( window->ActiveMenu );
break;
}
- SetFocus(window->Window.Handle);
fgState.Modifiers = fgPlatformGetModifiers( );
}
break;
- case 0x020a:
- /* Should be WM_MOUSEWHEEL but my compiler doesn't recognize it */
+ case WM_MOUSEWHEEL:
{
int wheel_number = LOWORD( wParam );
short ticks = ( short )HIWORD( wParam );
fgState.MouseWheelTicks += ticks;
- /*
- * XXX Should use WHEEL_DELTA instead of 120
- */
- if ( abs ( fgState.MouseWheelTicks ) > 120 )
+ if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
{
int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
fgSetWindow( window );
fgState.Modifiers = fgPlatformGetModifiers( );
- /*
- * XXX Should use WHEEL_DELTA instead of 120
- */
- while( abs ( fgState.MouseWheelTicks ) > 120 )
+ while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
{
if( FETCH_WCB( *window, MouseWheel ) )
INVOKE_WCB( *window, MouseWheel,
);
}
- /*
- * XXX Should use WHEEL_DELTA instead of 120
- */
- fgState.MouseWheelTicks -= 120 * direction;
+ fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
}
fgState.Modifiers = INVALID_MODIFIERS;
int keypress = -1;
POINT mouse_pos ;
+ if (child_window)
+ window = child_window;
+
if( ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
break;
KEY( VK_RIGHT, GLUT_KEY_RIGHT );
KEY( VK_DOWN, GLUT_KEY_DOWN );
KEY( VK_INSERT, GLUT_KEY_INSERT );
- KEY( VK_LCONTROL, GLUT_KEY_CTRL_L );
- KEY( VK_RCONTROL, GLUT_KEY_CTRL_R );
- KEY( VK_LSHIFT, GLUT_KEY_SHIFT_L );
- KEY( VK_RSHIFT, GLUT_KEY_SHIFT_R );
- KEY( VK_LMENU, GLUT_KEY_ALT_L );
- KEY( VK_RMENU, GLUT_KEY_ALT_R );
+
+ case VK_LCONTROL: case VK_RCONTROL: case VK_CONTROL:
+ case VK_LSHIFT: case VK_RSHIFT: case VK_SHIFT:
+ case VK_LMENU: case VK_RMENU: case VK_MENU:
+ /* These keypresses and releases are handled earlier in the function */
+ break;
case VK_DELETE:
/* The delete key should be treated as an ASCII keypress: */
int keypress = -1;
POINT mouse_pos;
+ if (child_window)
+ window = child_window;
+
/*
* Remember the current modifiers state. This is done here in order
* to make sure the VK_DELETE keyboard callback is executed properly.
KEY( VK_RIGHT, GLUT_KEY_RIGHT );
KEY( VK_DOWN, GLUT_KEY_DOWN );
KEY( VK_INSERT, GLUT_KEY_INSERT );
- KEY( VK_LCONTROL, GLUT_KEY_CTRL_L );
- KEY( VK_RCONTROL, GLUT_KEY_CTRL_R );
- KEY( VK_LSHIFT, GLUT_KEY_SHIFT_L );
- KEY( VK_RSHIFT, GLUT_KEY_SHIFT_R );
- KEY( VK_LMENU, GLUT_KEY_ALT_L );
- KEY( VK_RMENU, GLUT_KEY_ALT_R );
+
+ case VK_LCONTROL: case VK_RCONTROL: case VK_CONTROL:
+ case VK_LSHIFT: case VK_RSHIFT: case VK_SHIFT:
+ case VK_LMENU: case VK_RMENU: case VK_MENU:
+ /* These keypresses and releases are handled earlier in the function */
+ break;
case VK_DELETE:
/* The delete key should be treated as an ASCII keypress: */
case WM_SYSCHAR:
case WM_CHAR:
{
+ if (child_window)
+ window = child_window;
+
if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
break;