void fgSpaceballHandleXEvent(const XEvent *xev) { spnav_event sev; if(!sball_initialized) { fgInitialiseSpaceball(); if(!sball_initialized) { return; } } if(spnav_x11_event(xev, &sev)) { switch(sev.type) { case SPNAV_EVENT_MOTION: if(sev.motion.x | sev.motion.y | sev.motion.z) { INVOKE_WCB(*spnav_win, SpaceMotion, (sev.motion.x, sev.motion.y, sev.motion.z)); } if(sev.motion.rx | sev.motion.ry | sev.motion.rz) { INVOKE_WCB(*spnav_win, SpaceRotation, (sev.motion.rx, sev.motion.ry, sev.motion.rz)); } spnav_remove_events(SPNAV_EVENT_MOTION); break; case SPNAV_EVENT_BUTTON: INVOKE_WCB(*spnav_win, SpaceButton, (sev.button.bnum, sev.button.press ? GLUT_DOWN : GLUT_UP)); break; default: break; } } }
void fgPlatformHandleKeyboardHeight(SFG_Window* window, int height) { int size[2]; int screenHeight; int nScreenHeight = -1; screenHeight = glutGet(GLUT_WINDOW_HEIGHT); //Using this takes rotation into account if(height == 0) { nScreenHeight = screenHeight; } else if(!screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_POSITION, size)) { /* Calculate the new screen size */ //XXX Make sure to use display size instead of screen size nScreenHeight = ((size[1] + screenHeight) - height) - size[1]; } if(nScreenHeight != -1) { /* If nScreenHeight is less then zero then window is covered. If nScreenHeight == height, then no change in size. Else, change in size */ int screenWidth = glutGet(GLUT_WINDOW_WIDTH); if(nScreenHeight < 0) { LOGI("fgPlatformHandleKeyboardHeight: Covered window state"); window->State.Visible = GL_FALSE; window->State.pWState.windowCovered = GL_TRUE; INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_COVERED)); fghOnReshapeNotify(window, screenWidth, 0, GL_FALSE); } else { if(window->State.pWState.windowCovered == GL_TRUE) { LOGI("fgPlatformHandleKeyboardHeight: Resetting window state"); /* Reset window status if it was previously covered */ switch(window->State.pWState.windowState) { case NAVIGATOR_WINDOW_FULLSCREEN: window->State.Visible = GL_TRUE; INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_RETAINED)); break; case NAVIGATOR_WINDOW_THUMBNAIL: window->State.Visible = GL_TRUE; INVOKE_WCB(*window, WindowStatus, (GLUT_PARTIALLY_RETAINED)); break; case NAVIGATOR_WINDOW_INVISIBLE: window->State.Visible = GL_FALSE; INVOKE_WCB(*window, WindowStatus, (GLUT_HIDDEN)); break; } window->State.pWState.windowCovered = GL_FALSE; } fghOnReshapeNotify(window, screenWidth, nScreenHeight, GL_FALSE); } } }
static void fghPointerMotion( void* data, struct wl_pointer* pointer, uint32_t time, wl_fixed_t x_w, wl_fixed_t y_w ) { SFG_Window* win = fgStructure.CurrentWindow; win->State.MouseX = wl_fixed_to_int( x_w ); win->State.MouseY = wl_fixed_to_int( y_w ); if ( win->Window.pContext.pointer_button_pressed ) INVOKE_WCB( *win, Motion, ( win->State.MouseX, win->State.MouseY ) ); else INVOKE_WCB( *win, Passive, ( win->State.MouseX, win->State.MouseY ) ); }
static void fghPointerLeave( void* data, struct wl_pointer* pointer, uint32_t serial, struct wl_surface* surface ) { SFG_Window* win = fgStructure.CurrentWindow; INVOKE_WCB( *win, Entry, ( GLUT_LEFT ) ); }
static void fghUpdateWindowStatus(SFG_Window *window, GLboolean visState) { SFG_Window* child; if (window->State.Visible != visState) { window->State.Visible = visState; /* 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 ) ); /* 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 ); } } /* Also set visibility state for children */ for( child = ( SFG_Window * )window->Children.First; child; child = ( SFG_Window * )child->Node.Next ) { fghUpdateWindowStatus(child, visState); } }
static void fghKeyboardEnter( void* data, struct wl_keyboard* keyboard, uint32_t serial, struct wl_surface* surface, struct wl_array* keys ) { SFG_Window* win = fgStructure.CurrentWindow; INVOKE_WCB( *win, Entry, ( GLUT_ENTERED ) ); }
void fgPlatformMainLoopPreliminaryWork ( void ) { SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ; /* * Processing before the main loop: If there is a window which is open and * which has a visibility callback, call it. I know this is an ugly hack, * but I'm not sure what else to do about it. Ideally we should leave * something uninitialized in the create window code and initialize it in * the main loop, and have that initialization create a "WM_ACTIVATE" * message. Then we would put the visibility callback code in the * "case WM_ACTIVATE" block below. - John Fay -- 10/24/02 */ while( window ) { if ( FETCH_WCB( *window, Visibility ) ) { SFG_Window *current_window = fgStructure.CurrentWindow ; INVOKE_WCB( *window, Visibility, ( window->State.Visible ) ); fgSetWindow( current_window ); } window = (SFG_Window *)window->Node.Next ; } }
void fghOnReshapeNotify(SFG_Window *window, int width, int height, GLboolean forceNotify) { GLboolean notify = GL_FALSE; if( width != window->State.Width || height != window->State.Height ) { window->State.Width = width; window->State.Height = height; notify = GL_TRUE; } if (notify || forceNotify) { SFG_Window *saved_window = fgStructure.CurrentWindow; INVOKE_WCB( *window, Reshape, ( width, height ) ); /* * Force a window redraw. In Windows at least this is only a partial * solution: if the window is increasing in size in either dimension, * the already-drawn part does not get drawn again and things look funny. * But without this we get this bad behaviour whenever we resize the * window. * DN: Hmm.. the above sounds like a concern only in single buffered mode... */ window->State.WorkMask |= GLUT_DISPLAY_WORK; if( window->IsMenu ) fgSetWindow( saved_window ); } }
static void fghPointerButton( void* data, struct wl_pointer* pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state ) { SFG_Window* win = fgStructure.CurrentWindow; int button_f; switch( button ) { case BTN_LEFT: button_f = GLUT_LEFT_BUTTON; break; case BTN_RIGHT: button_f = GLUT_RIGHT_BUTTON; break; case BTN_MIDDLE: button_f = GLUT_MIDDLE_BUTTON; break; } win->Window.pContext.pointer_button_pressed = state ? GL_TRUE : GL_FALSE; INVOKE_WCB( *win, Mouse, ( button_f, state ? GLUT_DOWN : GLUT_UP , win->State.MouseX, win->State.MouseY ) ); }
/* * Polls the joystick and executes the joystick callback hooked to the * window specified in the function's parameter: */ void fgJoystickPollWindow( SFG_Window* window ) { float axes[ _JS_MAX_AXES ]; int buttons; glutes_return_if_fail( fgJoystick ); glutes_return_if_fail( window ); glutes_return_if_fail( FETCH_WCB( *window, Joystick ) ); fghJoystickRead( fgJoystick, &buttons, axes ); INVOKE_WCB( *window, Joystick, ( buttons, (int) (axes[ 0 ] * 1000.0f ), (int) (axes[ 1 ] * 1000.0f ), (int) (axes[ 2 ] * 1000.0f ) ) ); /* * fgSetWindow (window); * window->Callbacks.Joystick( * buttons, * (int) (axes[ 0 ] * 1000.0f), * (int) (axes[ 1 ] * 1000.0f), * (int) (axes[ 2 ] * 1000.0f) * ); */ }
static void fghTouchUp( void* data, struct wl_touch* touch, uint32_t serial, uint32_t time, int32_t id ) { SFG_Window* win = fgStructure.CurrentWindow; INVOKE_WCB( *win, Mouse, ( GLUT_LEFT_BUTTON, GLUT_UP, win->State.MouseX, win->State.MouseY ) ); }
static void fghTouchMotion( void* data, struct wl_touch* touch, uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w ) { SFG_Window* win = fgStructure.CurrentWindow; win->State.MouseX = wl_fixed_to_int( x_w ); win->State.MouseY = wl_fixed_to_int( y_w ); INVOKE_WCB( *win, Motion, ( win->State.MouseX, win->State.MouseY ) ); }
/* * Sets the Visibility callback for the current window. */ static void fghVisibility( int status ) { int glut_status = GLUT_VISIBLE; glutes_assert_ready; glutes_return_if_fail( fgStructure.Window ); if( ( GLUT_HIDDEN == status ) || ( GLUT_FULLY_COVERED == status ) ) glut_status = GLUT_NOT_VISIBLE; INVOKE_WCB( *( fgStructure.Window ), Visibility, ( glut_status ) ); }
/* * Sets the Visibility callback for the current window. */ static void fghVisibility( int status ) { int glut_status = GLUT_VISIBLE; FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Visibility Callback" ); freeglut_return_if_fail( fgStructure.CurrentWindow ); if( ( GLUT_HIDDEN == status ) || ( GLUT_FULLY_COVERED == status ) ) glut_status = GLUT_NOT_VISIBLE; INVOKE_WCB( *( fgStructure.CurrentWindow ), Visibility, ( glut_status ) ); }
/* * Pointer (mouse) section */ static void fghPointerEnter( void* data, struct wl_pointer* pointer, uint32_t serial, struct wl_surface* surface, wl_fixed_t x_w, wl_fixed_t y_w ) { SFG_Window* win = fgStructure.CurrentWindow; fghPointerSetCursor( win, pointer, serial ); win->State.MouseX = wl_fixed_to_int( x_w ); win->State.MouseY = wl_fixed_to_int( y_w ); INVOKE_WCB( *win, Entry, ( GLUT_ENTERED ) ); }
/* * This function is used by glutVisibilityFunc() as a callback for * another function. */ static void oghVisibility( const int status ) { int glut_status = GLUT_VISIBLE; freeglut_assert_ready; if( !ogStructure.Window ) return; if( ( GLUT_HIDDEN == status ) || ( GLUT_FULLY_COVERED == status ) ) glut_status = GLUT_NOT_VISIBLE; INVOKE_WCB( *( ogStructure.Window ), Visibility, ( glut_status ) ); }
static void fghPointerAxis( void* data, struct wl_pointer* pointer, uint32_t time, uint32_t axis, wl_fixed_t value ) { SFG_Window* win = fgStructure.CurrentWindow; int direction = wl_fixed_to_int( value ); INVOKE_WCB( *win, MouseWheel, ( 0, direction , win->State.MouseX, win->State.MouseY ) ); }
/* * Touchscreen section * For now, let us pretend it is a mouse with only one button */ static void fghTouchDown( void* data, struct wl_touch* touch, uint32_t serial, uint32_t time, struct wl_surface* surface, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w ) { SFG_Window* win = fgStructure.CurrentWindow; win->State.MouseX = wl_fixed_to_int( x_w ); win->State.MouseY = wl_fixed_to_int( y_w ); INVOKE_WCB( *win, Mouse, ( GLUT_LEFT_BUTTON, GLUT_DOWN, win->State.MouseX, win->State.MouseY ) ); }
/* * Sets the Visibility callback for the current window. * NB: the Visibility func is deprecated in favor of the WindowStatus func, * which provides more detail. The visibility func callback is implemented * as a translation step from the windowStatus func. When the user sets the * windowStatus func, any visibility func is overwritten. * DEVELOPER NOTE: in the library, only invoke the window status func, this * gets automatically translated to the visibility func if thats what the * user has set. * window status is kind of anemic on win32 as there are no window messages * to notify us that the window is covered by other windows or not. * Should one want to query this, see * http://stackoverflow.com/questions/5445889/get-which-process-window-is-actually-visible-in-c-sharp * for an implementation outline (but it would be polling based, not push based). */ static void fghVisibility( int status ) { int vis_status; FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Visibility Callback" ); freeglut_return_if_fail( fgStructure.CurrentWindow ); /* Translate window status func states to visibility states */ if( ( GLUT_HIDDEN == status ) || ( GLUT_FULLY_COVERED == status ) ) vis_status = GLUT_NOT_VISIBLE; else /* GLUT_FULLY_RETAINED, GLUT_PARTIALLY_RETAINED */ vis_status = GLUT_VISIBLE; INVOKE_WCB( *( fgStructure.CurrentWindow ), Visibility, ( vis_status ) ); }
void fgPlatformProcessSingleEvent ( void ) { static int32_t last_width = -1; static int32_t last_height = -1; /* When the screen is resized, the window handle still points to the old window until the next SwapBuffer, while it's crucial to set the size (onShape) correctly before the next onDisplay callback. Plus we don't know if the next SwapBuffer already occurred at the time we process the event (e.g. during onDisplay). */ /* So we do the check each time rather than on event. */ /* Interestingly, on a Samsung Galaxy S/PowerVR SGX540 GPU/Android 2.3, that next SwapBuffer is fake (but still necessary to get the new size). */ SFG_Window* window = fgDisplay.pDisplay.single_window; if (window != NULL && window->Window.Handle != NULL) { int32_t width = ANativeWindow_getWidth(window->Window.Handle); int32_t height = ANativeWindow_getHeight(window->Window.Handle); if (width != last_width || height != last_height) { last_width = width; last_height = height; LOGI("width=%d, height=%d", width, height); if( FETCH_WCB( *window, Reshape ) ) INVOKE_WCB( *window, Reshape, ( width, height ) ); else glViewport( 0, 0, width, height ); glutPostRedisplay(); } } /* Read pending event. */ int ident; int events; struct android_poll_source* source; /* This is called "ProcessSingleEvent" but this means we'd only process ~60 (screen Hz) mouse events per second, plus other ports are processing all events already. So let's process all pending events. */ /* if ((ident=ALooper_pollOnce(0, NULL, &events, (void**)&source)) >= 0) { */ while ((ident=ALooper_pollAll(0, NULL, &events, (void**)&source)) >= 0) { /* Process this event. */ if (source != NULL) { source->process(source->app, source); } } }
void fghOnPositionNotify(SFG_Window *window, int x, int y, GLboolean forceNotify) { GLboolean notify = GL_FALSE; if( x != window->State.Xpos || y != window->State.Ypos ) { window->State.Xpos = x; window->State.Ypos = y; notify = GL_TRUE; } if (notify || forceNotify) { SFG_Window *saved_window = fgStructure.CurrentWindow; INVOKE_WCB( *window, Position, ( x, y ) ); fgSetWindow( saved_window ); } }
/* * The window procedure for handling Win32 events */ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { static unsigned char lControl = 0, rControl = 0, lShift = 0, rShift = 0, lAlt = 0, rAlt = 0; SFG_Window* window; PAINTSTRUCT ps; LRESULT lRet = 1; 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 <%04x> %12d %12d\n", window?window->ID:0, uMsg, wParam, lParam ); */ if ( window ) { /* 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; } if ( !rShift && GetAsyncKeyState ( VK_RSHIFT ) ) { INVOKE_WCB ( *window, Special, ( GLUT_KEY_SHIFT_R, window->State.MouseX, window->State.MouseY ) ); rShift = 1; } if ( !lAlt && GetAsyncKeyState ( VK_LMENU ) ) { INVOKE_WCB ( *window, Special, ( GLUT_KEY_ALT_L, window->State.MouseX, window->State.MouseY ) ); lAlt = 1; } if ( !rAlt && GetAsyncKeyState ( VK_RMENU ) ) { INVOKE_WCB ( *window, Special, ( GLUT_KEY_ALT_R, window->State.MouseX, window->State.MouseY ) ); rAlt = 1; } /* 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; } if ( lAlt && !GetAsyncKeyState ( VK_LMENU ) ) { INVOKE_WCB ( *window, SpecialUp, ( GLUT_KEY_ALT_L, window->State.MouseX, window->State.MouseY ) ); lAlt = 0; } if ( rAlt && !GetAsyncKeyState ( VK_RMENU ) ) { INVOKE_WCB ( *window, SpecialUp, ( GLUT_KEY_ALT_R, window->State.MouseX, window->State.MouseY ) ); rAlt = 0; } } 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 } window->State.NeedToResize = GL_TRUE; /* if we used CW_USEDEFAULT (thats a negative value) for the size * of the window, query the window now for the size at which it * was created. */ if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) ) { SFG_Window *current_window = fgStructure.CurrentWindow; fgSetWindow( window ); window->State.Width = glutGet( GLUT_WINDOW_WIDTH ); window->State.Height = glutGet( GLUT_WINDOW_HEIGHT ); fgSetWindow( current_window ); } 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: /* * If the window is visible, then it is the user manually resizing it. * If it is not, then it is the system sending us a dummy resize with * zero dimensions on a "glutIconifyWindow" call. */ if( window->State.Visible ) { window->State.NeedToResize = GL_TRUE; #if defined(_WIN32_WCE) window->State.Width = HIWORD(lParam); window->State.Height = LOWORD(lParam); #else window->State.Width = LOWORD(lParam); window->State.Height = HIWORD(lParam); #endif /* defined(_WIN32_WCE) */ } break; case WM_SETFOCUS: /* printf("WM_SETFOCUS: %p\n", window ); */ lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) ); 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 ); break; #if 0 case WM_ACTIVATE: 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 ) fgSetCursor ( window, window->State.Cursor ) ; else lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); break; case WM_SHOWWINDOW: window->State.Visible = GL_TRUE; window->State.Redisplay = GL_TRUE; break; case WM_PAINT: /* Turn on the visibility in case it was turned off somehow */ window->State.Visible = GL_TRUE; BeginPaint( hWnd, &ps ); fghRedrawWindow( window ); EndPaint( hWnd, &ps ); 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: { #if defined(_WIN32_WCE) window->State.MouseX = 320-HIWORD( lParam ); window->State.MouseY = LOWORD( lParam ); #else window->State.MouseX = LOWORD( lParam ); window->State.MouseY = HIWORD( 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; } SetFocus(window->Window.Handle); 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; #if defined(_WIN32_WCE) window->State.MouseX = 320-HIWORD( lParam ); window->State.MouseY = LOWORD( lParam ); #else window->State.MouseX = LOWORD( lParam ); window->State.MouseY = HIWORD( 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 */ /* * XXX - Multiple button support: Under X11, the mouse is not released * XXX - from the window until all buttons have been released, even if the * XXX - user presses a button in another window. This will take more * XXX - code changes than I am up to at the moment (10/5/04). The present * XXX - is a 90 percent solution. */ if ( pressed == GL_TRUE ) SetCapture ( window->Window.Handle ) ; else 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; } break; case 0x020a: /* Should be WM_MOUSEWHEEL but my compiler doesn't recognize it */ { 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 ) { int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1; if( ! FETCH_WCB( *window, MouseWheel ) && ! FETCH_WCB( *window, Mouse ) ) break; fgSetWindow( window ); fgState.Modifiers = fgPlatformGetModifiers( ); /* * XXX Should use WHEEL_DELTA instead of 120 */ while( abs ( fgState.MouseWheelTicks ) > 120 ) { 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 ) ); } /* * XXX Should use WHEEL_DELTA instead of 120 */ fgState.MouseWheelTicks -= 120 * direction; } fgState.Modifiers = INVALID_MODIFIERS; } } break ; case WM_SYSKEYDOWN: case WM_KEYDOWN: { int keypress = -1; POINT mouse_pos ; if( ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) ) break; /* * Remember the current modifiers state. This is done here in order * to make sure the VK_DELETE keyboard callback is executed properly. */ fgState.Modifiers = fgPlatformGetModifiers( ); 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; 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 ); 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_DELETE: /* The delete key should be treated as an ASCII keypress: */ INVOKE_WCB( *window, Keyboard, ( 127, window->State.MouseX, window->State.MouseY ) ); } #if defined(_WIN32_WCE) if(!(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 ) INVOKE_WCB( *window, Special, ( keypress, window->State.MouseX, window->State.MouseY ) ); fgState.Modifiers = INVALID_MODIFIERS; } break; case WM_SYSKEYUP: case WM_KEYUP: { int keypress = -1; POINT mouse_pos; /* * Remember the current modifiers state. This is done here in order * to make sure the VK_DELETE keyboard callback is executed properly. */ fgState.Modifiers = fgPlatformGetModifiers( ); 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. * "KEY(a,b)" was defined under "WM_KEYDOWN" */ 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 ); 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_DELETE: /* The delete key should be treated as an ASCII keypress: */ INVOKE_WCB( *window, KeyboardUp, ( 127, window->State.MouseX, window->State.MouseY ) ); break; default: { #if !defined(_WIN32_WCE) 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, window->State.MouseX, window->State.MouseY ) ); #endif /* !defined(_WIN32_WCE) */ } } if( keypress != -1 ) INVOKE_WCB( *window, SpecialUp, ( keypress, window->State.MouseX, window->State.MouseY ) ); fgState.Modifiers = INVALID_MODIFIERS; } break; case WM_SYSCHAR: case WM_CHAR: { 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: /* User has finished resizing the window, force a redraw */ INVOKE_WCB( *window, Display, ( ) ); /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */ break; /* Other messages that I have seen and which are not handled already */ case WM_SETTEXT: /* 0x000c */ lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); /* Pass it on to "DefWindowProc" to set the window text */ break; case WM_GETTEXT: /* 0x000d */ /* Ideally we would copy the title of the window into "lParam" */ /* strncpy ( (char *)lParam, "Window Title", wParam ); lRet = ( wParam > 12 ) ? 12 : wParam; */ /* the number of characters copied */ lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); break; case WM_GETTEXTLENGTH: /* 0x000e */ /* Ideally we would get the length of the title of the window */ lRet = 12; /* the number of characters in "Window Title\0" (see above) */ break; case WM_ERASEBKGND: /* 0x0014 */ lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); break; #if !defined(_WIN32_WCE) case WM_SYNCPAINT: /* 0x0088 */ /* Another window has moved, need to update this one */ window->State.Redisplay = GL_TRUE; lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); /* Help screen says this message must be passed to "DefWindowProc" */ break; case WM_NCPAINT: /* 0x0085 */ /* Need to update the border of this window */ lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); /* Pass it on to "DefWindowProc" to repaint a standard border */ 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 */ /* Turn off the visibility */ window->State.Visible = GL_FALSE ; 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; }
/* * Enters the freeglut processing loop. * Stays until the "ExecState" changes to "GLUT_EXEC_STATE_STOP". */ void FGAPIENTRY glutMainLoopMT( void ) { //int action; //MT #if TARGET_HOST_WIN32 || TARGET_HOST_WINCE SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ; #endif FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoop" ); #if TARGET_HOST_WIN32 || TARGET_HOST_WINCE /* * Processing before the main loop: If there is a window which is open and * which has a visibility callback, call it. I know this is an ugly hack, * but I'm not sure what else to do about it. Ideally we should leave * something uninitialized in the create window code and initialize it in * the main loop, and have that initialization create a "WM_ACTIVATE" * message. Then we would put the visibility callback code in the * "case WM_ACTIVATE" block below. - John Fay -- 10/24/02 */ while( window ) { if ( FETCH_WCB( *window, Visibility ) ) { SFG_Window *current_window = fgStructure.CurrentWindow ; INVOKE_WCB( *window, Visibility, ( window->State.Visible ) ); fgSetWindow( current_window ); } window = (SFG_Window *)window->Node.Next ; } #endif fgState.ExecState = GLUT_EXEC_STATE_RUNNING ; while( fgState.ExecState == GLUT_EXEC_STATE_RUNNING ) { SFG_Window *window; glutMainLoopEvent( ); /* * Step through the list of windows, seeing if there are any * that are not menus */ for( window = ( SFG_Window * )fgStructure.Windows.First; window; window = ( SFG_Window * )window->Node.Next ) if ( ! ( window->IsMenu ) ) break; if( ! window ) fgState.ExecState = GLUT_EXEC_STATE_STOP; else { if( fgState.IdleCallback ) { if( fgStructure.CurrentWindow && fgStructure.CurrentWindow->IsMenu ) /* fail safe */ fgSetWindow( window ); fgState.IdleCallback( ); } fghSleepForEvents( ); } } #if 0 //Marc Toussaint /* * When this loop terminates, destroy the display, state and structure * of a freeglut session, so that another glutInit() call can happen * * Save the "ActionOnWindowClose" because "fgDeinitialize" resets it. */ action = fgState.ActionOnWindowClose; fgDeinitialize( ); if( action == GLUT_ACTION_EXIT ) exit( 0 ); #endif }
void fgPlatformProcessSingleEvent ( void ) { SFG_Window* window; XEvent event; /* This code was repeated constantly, so here it goes into a definition: */ #define GETWINDOW(a) \ window = fgWindowByHandle( event.a.window ); \ if( window == NULL ) \ break; #define GETMOUSE(a) \ window->State.MouseX = event.a.x; \ window->State.MouseY = event.a.y; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" ); while( XPending( fgDisplay.pDisplay.Display ) ) { XNextEvent( fgDisplay.pDisplay.Display, &event ); #if _DEBUG fghPrintEvent( &event ); #endif switch( event.type ) { case ClientMessage: if (fgStructure.CurrentWindow) if(fgIsSpaceballXEvent(&event)) { fgSpaceballHandleXEvent(&event); break; } /* Destroy the window when the WM_DELETE_WINDOW message arrives */ if( (Atom) event.xclient.data.l[ 0 ] == fgDisplay.pDisplay.DeleteWindow ) { GETWINDOW( xclient ); fgDestroyWindow ( window ); if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT ) { fgDeinitialize( ); exit( 0 ); } else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS ) fgState.ExecState = GLUT_EXEC_STATE_STOP; return; } break; /* * CreateNotify causes a configure-event so that sub-windows are * handled compatibly with GLUT. Otherwise, your sub-windows * (in freeglut only) will not get an initial reshape event, * which can break things. * * GLUT presumably does this because it generally tries to treat * sub-windows the same as windows. */ case CreateNotify: case ConfigureNotify: { int width, height, x, y; if( event.type == CreateNotify ) { GETWINDOW( xcreatewindow ); width = event.xcreatewindow.width; height = event.xcreatewindow.height; x = event.xcreatewindow.x; y = event.xcreatewindow.y; } else { GETWINDOW( xconfigure ); width = event.xconfigure.width; height = event.xconfigure.height; x = event.xconfigure.x; y = event.xconfigure.y; } /* Update state and call callback, if there was a change */ fghOnPositionNotify(window, x, y, GL_FALSE); /* Update state and call callback, if there was a change */ fghOnReshapeNotify(window, width, height, GL_FALSE); } break; case DestroyNotify: /* * This is sent to confirm the XDestroyWindow call. * * XXX WHY is this commented out? Should we re-enable it? */ /* fgAddToWindowDestroyList ( window ); */ break; case Expose: /* * We are too dumb to process partial exposes... * * XXX Well, we could do it. However, it seems to only * XXX be potentially useful for single-buffered (since * XXX double-buffered does not respect viewport when we * XXX do a buffer-swap). * */ if( event.xexpose.count == 0 ) { GETWINDOW( xexpose ); window->State.WorkMask |= GLUT_DISPLAY_WORK; } break; case MapNotify: break; case UnmapNotify: /* We get this when iconifying a window. */ GETWINDOW( xunmap ); INVOKE_WCB( *window, WindowStatus, ( GLUT_HIDDEN ) ); window->State.Visible = GL_FALSE; break; case MappingNotify: /* * Have the client's keyboard knowledge updated (xlib.ps, * page 206, says that's a good thing to do) */ XRefreshKeyboardMapping( (XMappingEvent *) &event ); break; case VisibilityNotify: { /* * Sending this event, the X server can notify us that the window * has just acquired one of the three possible visibility states: * VisibilityUnobscured, VisibilityPartiallyObscured or * VisibilityFullyObscured. Note that we DO NOT receive a * VisibilityNotify event when iconifying a window, we only get an * UnmapNotify then. */ GETWINDOW( xvisibility ); switch( event.xvisibility.state ) { case VisibilityUnobscured: INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_RETAINED ) ); window->State.Visible = GL_TRUE; break; case VisibilityPartiallyObscured: INVOKE_WCB( *window, WindowStatus, ( GLUT_PARTIALLY_RETAINED ) ); window->State.Visible = GL_TRUE; break; case VisibilityFullyObscured: INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_COVERED ) ); window->State.Visible = GL_FALSE; break; default: fgWarning( "Unknown X visibility state: %d", event.xvisibility.state ); break; } } break; case EnterNotify: case LeaveNotify: GETWINDOW( xcrossing ); GETMOUSE( xcrossing ); if( ( event.type == LeaveNotify ) && window->IsMenu && window->ActiveMenu && window->ActiveMenu->IsActive ) fgUpdateMenuHighlight( window->ActiveMenu ); INVOKE_WCB( *window, Entry, ( ( EnterNotify == event.type ) ? GLUT_ENTERED : GLUT_LEFT ) ); break; case MotionNotify: { /* if GLUT_SKIP_STALE_MOTION_EVENTS is true, then discard all but * the last motion event from the queue */ if(fgState.SkipStaleMotion) { while(XCheckIfEvent(fgDisplay.pDisplay.Display, &event, match_motion, 0)); } GETWINDOW( xmotion ); GETMOUSE( xmotion ); if( window->ActiveMenu ) { if( window == window->ActiveMenu->ParentWindow ) { window->ActiveMenu->Window->State.MouseX = event.xmotion.x_root - window->ActiveMenu->X; window->ActiveMenu->Window->State.MouseY = event.xmotion.y_root - window->ActiveMenu->Y; } fgUpdateMenuHighlight( window->ActiveMenu ); break; } /* * XXX For more than 5 buttons, just check {event.xmotion.state}, * XXX rather than a host of bit-masks? Or maybe we need to * XXX track ButtonPress/ButtonRelease events in our own * XXX bit-mask? */ fgState.Modifiers = fgPlatformGetModifiers( event.xmotion.state ); if ( event.xmotion.state & ( Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) ) { INVOKE_WCB( *window, Motion, ( event.xmotion.x, event.xmotion.y ) ); } else { INVOKE_WCB( *window, Passive, ( event.xmotion.x, event.xmotion.y ) ); } fgState.Modifiers = INVALID_MODIFIERS; } break; case ButtonRelease: case ButtonPress: { GLboolean pressed = GL_TRUE; int button; if( event.type == ButtonRelease ) pressed = GL_FALSE ; /* * A mouse button has been pressed or released. Traditionally, * break if the window was found within the freeglut structures. */ GETWINDOW( xbutton ); GETMOUSE( xbutton ); /* * An X button (at least in XFree86) is numbered from 1. * A GLUT button is numbered from 0. * Old GLUT passed through buttons other than just the first * three, though it only gave symbolic names and official * support to the first three. */ button = event.xbutton.button - 1; /* * 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, event.xbutton.x, event.xbutton.y ) ) break; /* * Check if there is a mouse or mouse wheel callback hooked to the * window */ if( ! FETCH_WCB( *window, Mouse ) && ! FETCH_WCB( *window, MouseWheel ) ) break; fgState.Modifiers = fgPlatformGetModifiers( event.xbutton.state ); /* Finally execute the mouse or mouse wheel callback */ if( ( button < glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS ) ) || ( ! FETCH_WCB( *window, MouseWheel ) ) ) INVOKE_WCB( *window, Mouse, ( button, pressed ? GLUT_DOWN : GLUT_UP, event.xbutton.x, event.xbutton.y ) ); else { /* * Map 4 and 5 to wheel zero; EVEN to +1, ODD to -1 * " 6 and 7 " " one; ... * * XXX This *should* be behind some variables/macros, * XXX since the order and numbering isn't certain * XXX See XFree86 configuration docs (even back in the * XXX 3.x days, and especially with 4.x). * * XXX Note that {button} has already been decremented * XXX in mapping from X button numbering to GLUT. * * XXX Should add support for partial wheel turns as Windows does -- 5/27/11 */ int wheel_number = (button - glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS )) / 2; int direction = -1; if( button % 2 ) direction = 1; if( pressed ) INVOKE_WCB( *window, MouseWheel, ( wheel_number, direction, event.xbutton.x, event.xbutton.y ) ); } fgState.Modifiers = INVALID_MODIFIERS; } break; case KeyRelease: case KeyPress: { FGCBKeyboard keyboard_cb; FGCBSpecial special_cb; GETWINDOW( xkey ); GETMOUSE( xkey ); /* Detect auto repeated keys, if configured globally or per-window */ if ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) { if (event.type==KeyRelease) { /* * Look at X11 keystate to detect repeat mode. * While X11 says the key is actually held down, we'll ignore KeyRelease/KeyPress pairs. */ char keys[32]; XQueryKeymap( fgDisplay.pDisplay.Display, keys ); /* Look at X11 keystate to detect repeat mode */ if ( event.xkey.keycode<256 ) /* XQueryKeymap is limited to 256 keycodes */ { if ( keys[event.xkey.keycode>>3] & (1<<(event.xkey.keycode%8)) ) window->State.pWState.KeyRepeating = GL_TRUE; else window->State.pWState.KeyRepeating = GL_FALSE; } } } else window->State.pWState.KeyRepeating = GL_FALSE; /* Cease processing this event if it is auto repeated */ if (window->State.pWState.KeyRepeating) { if (event.type == KeyPress) window->State.pWState.KeyRepeating = GL_FALSE; break; } if( event.type == KeyPress ) { keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard )); special_cb = (FGCBSpecial) ( FETCH_WCB( *window, Special )); } else { keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp )); special_cb = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp )); } /* Is there a keyboard/special callback hooked for this window? */ if( keyboard_cb || special_cb ) { XComposeStatus composeStatus; char asciiCode[ 32 ]; KeySym keySym; int len; /* Check for the ASCII/KeySym codes associated with the event: */ len = XLookupString( &event.xkey, asciiCode, sizeof(asciiCode), &keySym, &composeStatus ); /* GLUT API tells us to have two separate callbacks... */ if( len > 0 ) { /* ...one for the ASCII translateable keypresses... */ if( keyboard_cb ) { fgSetWindow( window ); fgState.Modifiers = fgPlatformGetModifiers( event.xkey.state ); keyboard_cb( asciiCode[ 0 ], event.xkey.x, event.xkey.y ); fgState.Modifiers = INVALID_MODIFIERS; } } else { int special = -1; /* * ...and one for all the others, which need to be * translated to GLUT_KEY_Xs... */ switch( keySym ) { case XK_F1: special = GLUT_KEY_F1; break; case XK_F2: special = GLUT_KEY_F2; break; case XK_F3: special = GLUT_KEY_F3; break; case XK_F4: special = GLUT_KEY_F4; break; case XK_F5: special = GLUT_KEY_F5; break; case XK_F6: special = GLUT_KEY_F6; break; case XK_F7: special = GLUT_KEY_F7; break; case XK_F8: special = GLUT_KEY_F8; break; case XK_F9: special = GLUT_KEY_F9; break; case XK_F10: special = GLUT_KEY_F10; break; case XK_F11: special = GLUT_KEY_F11; break; case XK_F12: special = GLUT_KEY_F12; break; case XK_KP_Left: case XK_Left: special = GLUT_KEY_LEFT; break; case XK_KP_Right: case XK_Right: special = GLUT_KEY_RIGHT; break; case XK_KP_Up: case XK_Up: special = GLUT_KEY_UP; break; case XK_KP_Down: case XK_Down: special = GLUT_KEY_DOWN; break; case XK_KP_Prior: case XK_Prior: special = GLUT_KEY_PAGE_UP; break; case XK_KP_Next: case XK_Next: special = GLUT_KEY_PAGE_DOWN; break; case XK_KP_Home: case XK_Home: special = GLUT_KEY_HOME; break; case XK_KP_End: case XK_End: special = GLUT_KEY_END; break; case XK_KP_Insert: case XK_Insert: special = GLUT_KEY_INSERT; break; case XK_Num_Lock : special = GLUT_KEY_NUM_LOCK; break; case XK_KP_Begin : special = GLUT_KEY_BEGIN; break; case XK_KP_Delete: special = GLUT_KEY_DELETE; break; case XK_Shift_L: special = GLUT_KEY_SHIFT_L; break; case XK_Shift_R: special = GLUT_KEY_SHIFT_R; break; case XK_Control_L: special = GLUT_KEY_CTRL_L; break; case XK_Control_R: special = GLUT_KEY_CTRL_R; break; case XK_Alt_L: special = GLUT_KEY_ALT_L; break; case XK_Alt_R: special = GLUT_KEY_ALT_R; break; } /* * Execute the callback (if one has been specified), * given that the special code seems to be valid... */ if( special_cb && (special != -1) ) { fgSetWindow( window ); fgState.Modifiers = fgPlatformGetModifiers( event.xkey.state ); special_cb( special, event.xkey.x, event.xkey.y ); fgState.Modifiers = INVALID_MODIFIERS; } } } }
/** * \brief This function is called when an Extension Event is received * and calls the corresponding callback functions for these events. */ void fgHandleExtensionEvents( XEvent* base_ev ) { int i, button = 0; XGenericEventCookie* cookie = (XGenericEventCookie*)&(base_ev->xcookie); if ( XGetEventData( fgDisplay.Display, cookie ) && (cookie->type == GenericEvent) && (cookie->extension == xi_opcode) ) { XIDeviceEvent* event = (XIDeviceEvent*)(cookie->data); /*printf("XI2 event type: %d - %d\n", cookie->evtype, event->type );*/ SFG_Window* window = fgWindowByHandle( event->event ); if (!window) return; switch (cookie->evtype) { case XI_Enter: case XI_Leave: fgState.Modifiers = fghGetXModifiers( ((XIEnterEvent*)event)->mods.base ); INVOKE_WCB( *window, MultiEntry, ( event->deviceid, (event->evtype == XI_Enter ? GLUT_ENTERED : GLUT_LEFT) )); #if _DEBUG fgPrintXILeaveEvent((XILeaveEvent*)event); #endif break; case XI_ButtonPress: case XI_ButtonRelease: fgState.Modifiers = fghGetXModifiers( event->mods.base ); INVOKE_WCB( *window, MultiButton, ( event->deviceid, event->event_x, event->event_y, (event->detail)-1, (event->evtype == XI_ButtonPress ? GLUT_DOWN : GLUT_UP) )); INVOKE_WCB( *window, Mouse, ( (event->detail)-1, (event->evtype == XI_ButtonPress ? GLUT_DOWN : GLUT_UP), event->event_x, event->event_y )); break; case XI_Motion: fgState.Modifiers = fghGetXModifiers( event->mods.base ); for (i = 0; i < event->buttons.mask_len; i++) if (event->buttons.mask[i]) button = 1; if (button) { INVOKE_WCB( *window, MultiMotion, ( event->deviceid, event->event_x, event->event_y ) ); INVOKE_WCB( *window, Motion, ( event->event_x, event->event_y ) ); } else { INVOKE_WCB( *window, MultiPassive, ( event->deviceid, event->event_x, event->event_y ) ); INVOKE_WCB( *window, Passive, ( event->event_x, event->event_y ) ); } #if _DEBUG fgPrintXIDeviceEvent(event); #endif break; default: #if _DEBUG fgWarning( "Unknown XI2 device event:" ); fgPrintXIDeviceEvent( event ); #endif break; } fgState.Modifiers = INVALID_MODIFIERS; } XFreeEventData( fgDisplay.Display, cookie ); }
/* * 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 <%04x> %12d %12d\n", window?window->ID:0, 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 } window->State.NeedToResize = GL_TRUE; /* if we used CW_USEDEFAULT (thats a negative value) for the size * of the window, query the window now for the size at which it * was created. */ if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) ) { SFG_Window *current_window = fgStructure.CurrentWindow; fgSetWindow( window ); window->State.Width = glutGet( GLUT_WINDOW_WIDTH ); window->State.Height = glutGet( GLUT_WINDOW_HEIGHT ); fgSetWindow( current_window ); } 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) fghUpdateWindowStatus(window,GL_FALSE); else if (wParam==SIZE_RESTORED && !window->State.Visible) fghUpdateWindowStatus(window,GL_TRUE); /* Check window visible, we don't want to resize when the user or glutIconifyWindow minimized the window */ if( window->State.Visible ) { /* 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); #else window->State.Width = LOWORD(lParam); window->State.Height = HIWORD(lParam); #endif /* defined(_WIN32_WCE) */ if (width!=window->State.Width || height!=window->State.Height) { SFG_Window* saved_window = fgStructure.CurrentWindow; /* size changed, call reshape callback */ INVOKE_WCB( *window, Reshape, ( width, height ) ); glutPostRedisplay( ); if( window->IsMenu ) fgSetWindow( saved_window ); } } /* according to docs, should return 0 */ lRet = 0; break; case WM_MOVE: { SFG_Window* saved_window = fgStructure.CurrentWindow; RECT windowRect; /* 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)) { /* 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; } INVOKE_WCB( *window, Position, ( windowRect.left, windowRect.top ) ); fgSetWindow(saved_window); } } /* 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(); 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 = 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: /* printf("WM_SHOWWINDOW, shown? %i, source: %i\n",wParam,lParam); */ if (wParam) { fghUpdateWindowStatus(window, GL_TRUE); window->State.Redisplay = GL_TRUE; } else { fghUpdateWindowStatus(window, GL_FALSE); window->State.Redisplay = GL_FALSE; } break; case WM_PAINT: { RECT rect; if (GetUpdateRect(hWnd,&rect,FALSE)) { /* As per docs, upon receiving WM_PAINT, first check if the update region is not empty before you call BeginPaint */ PAINTSTRUCT ps; /* Turn on the visibility in case it was turned off somehow */ window->State.Visible = GL_TRUE; InvalidateRect( hWnd, NULL, GL_FALSE ); BeginPaint( hWnd, &ps ); fghRedrawWindow( window ); EndPaint( hWnd, &ps ); } 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 (!GetAsyncKeyState(VK_LBUTTON) && !GetAsyncKeyState(VK_MBUTTON) && !GetAsyncKeyState(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.Redisplay = GL_TRUE; lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); /* Help screen says this message must be passed to "DefWindowProc" */ 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; }
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 && GetAsyncKeyState ( winKey ))\ {\ keypress = glutKey;\ keyStateVar = 1;\ }\ else if (keyStateVar && !GetAsyncKeyState ( 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, 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; }
void fghNotifyWindowStatus(SFG_Window *window) { INVOKE_WCB( *window, WindowStatus, ( window->State.Visible?GLUT_FULLY_RETAINED:GLUT_HIDDEN ) ); /* Don't notify children, they get their own just before first time they're drawn */ }
/* Check all windows for dialbox callbacks */ static void fghcbEnumDialCallbacks ( SFG_Window *window, SFG_Enumerator *enumerator ) { /* Built-in to INVOKE_WCB(): if window->Callbacks[CB_Dials] */ INVOKE_WCB ( *window,Dials, ( ((int*)enumerator->data)[0], ((int*)enumerator->data)[1]) ); fgEnumSubWindows ( window, fghcbEnumDialCallbacks, enumerator ); }
/** * Process the next input event. */ int32_t handle_input(struct android_app* app, AInputEvent* event) { SFG_Window* window = fgStructure.CurrentWindow; /* FIXME: in Android, when key is repeated, down and up events happen most often at the exact same time. This makes it impossible to animate based on key press time. */ /* e.g. down/up/wait/down/up rather than down/wait/down/wait/up */ if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) { /* LOGI("action: %d", AKeyEvent_getAction(event)); */ /* LOGI("keycode: %d", code); */ int32_t code = AKeyEvent_getKeyCode(event); if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN) { int32_t keypress = 0; unsigned char ascii = 0; if ((keypress = key_a2fg[code]) && FETCH_WCB(*window, Special)) { INVOKE_WCB(*window, Special, (keypress, window->State.MouseX, window->State.MouseY)); return EVENT_HANDLED; } else if ((ascii = key_ascii(app, event)) && FETCH_WCB(*window, Keyboard)) { INVOKE_WCB(*window, Keyboard, (ascii, window->State.MouseX, window->State.MouseY)); return EVENT_HANDLED; } } else if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_UP) { int32_t keypress = 0; unsigned char ascii = 0; if ((keypress = key_a2fg[code]) && FETCH_WCB(*window, Special)) { INVOKE_WCB(*window, SpecialUp, (keypress, window->State.MouseX, window->State.MouseY)); return EVENT_HANDLED; } else if ((ascii = key_ascii(app, event)) && FETCH_WCB(*window, Keyboard)) { INVOKE_WCB(*window, KeyboardUp, (ascii, window->State.MouseX, window->State.MouseY)); return EVENT_HANDLED; } } } if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { int32_t action = AMotionEvent_getAction(event); float x = AMotionEvent_getX(event, 0); float y = AMotionEvent_getY(event, 0); LOGI("motion %.01f,%.01f action=%d", x, y, AMotionEvent_getAction(event)); /* Virtual arrows PAD */ // Don't interfere with existing mouse move event if (!touchscreen.in_mmotion) { struct vpad_state prev_vpad = touchscreen.vpad; touchscreen.vpad.left = touchscreen.vpad.right = touchscreen.vpad.up = touchscreen.vpad.down = false; int32_t width = ANativeWindow_getWidth(window->Window.Handle); int32_t height = ANativeWindow_getHeight(window->Window.Handle); if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_MOVE) { if ((x > 0 && x < 100) && (y > (height - 100) && y < height)) touchscreen.vpad.left = true; if ((x > 200 && x < 300) && (y > (height - 100) && y < height)) touchscreen.vpad.right = true; if ((x > 100 && x < 200) && (y > (height - 100) && y < height)) touchscreen.vpad.down = true; if ((x > 100 && x < 200) && (y > (height - 200) && y < (height - 100))) touchscreen.vpad.up = true; } if (action == AMOTION_EVENT_ACTION_DOWN && (touchscreen.vpad.left || touchscreen.vpad.right || touchscreen.vpad.down || touchscreen.vpad.up)) touchscreen.vpad.on = true; if (action == AMOTION_EVENT_ACTION_UP) touchscreen.vpad.on = false; if (prev_vpad.left != touchscreen.vpad.left || prev_vpad.right != touchscreen.vpad.right || prev_vpad.up != touchscreen.vpad.up || prev_vpad.down != touchscreen.vpad.down || prev_vpad.on != touchscreen.vpad.on) { if (FETCH_WCB(*window, Special)) { if (prev_vpad.left == false && touchscreen.vpad.left == true) INVOKE_WCB(*window, Special, (GLUT_KEY_LEFT, x, y)); else if (prev_vpad.right == false && touchscreen.vpad.right == true) INVOKE_WCB(*window, Special, (GLUT_KEY_RIGHT, x, y)); else if (prev_vpad.up == false && touchscreen.vpad.up == true) INVOKE_WCB(*window, Special, (GLUT_KEY_UP, x, y)); else if (prev_vpad.down == false && touchscreen.vpad.down == true) INVOKE_WCB(*window, Special, (GLUT_KEY_DOWN, x, y)); } if (FETCH_WCB(*window, SpecialUp)) { if (prev_vpad.left == true && touchscreen.vpad.left == false) INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_LEFT, x, y)); if (prev_vpad.right == true && touchscreen.vpad.right == false) INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_RIGHT, x, y)); if (prev_vpad.up == true && touchscreen.vpad.up == false) INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_UP, x, y)); if (prev_vpad.down == true && touchscreen.vpad.down == false) INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_DOWN, x, y)); } return EVENT_HANDLED; } } /* Normal mouse events */ if (!touchscreen.vpad.on) { window->State.MouseX = x; window->State.MouseY = y; LOGI("Changed mouse position: %d,%d", x, y); if (action == AMOTION_EVENT_ACTION_DOWN && FETCH_WCB(*window, Mouse)) { touchscreen.in_mmotion = true; INVOKE_WCB(*window, Mouse, (GLUT_LEFT_BUTTON, GLUT_DOWN, x, y)); } else if (action == AMOTION_EVENT_ACTION_UP && FETCH_WCB(*window, Mouse)) { touchscreen.in_mmotion = false; INVOKE_WCB(*window, Mouse, (GLUT_LEFT_BUTTON, GLUT_UP, x, y)); } else if (action == AMOTION_EVENT_ACTION_MOVE && FETCH_WCB(*window, Motion)) { INVOKE_WCB(*window, Motion, (x, y)); } } return EVENT_HANDLED; } /* Let Android handle other events (e.g. Back and Menu buttons) */ return EVENT_NOT_HANDLED; }