X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Ffreeglut_cursor.c;h=dccee9130b54b91c8eeb095fd7c04c6b89162b5a;hb=78d46c63a115e0a868d83f365399864b62a4ea7f;hp=2cf4decc32f51a3b2eae0201445f530e3c300344;hpb=6220f13b806ad2b3aff239152b6cb84574d7f8d1;p=freeglut diff --git a/src/freeglut_cursor.c b/src/freeglut_cursor.c index 2cf4dec..dccee91 100644 --- a/src/freeglut_cursor.c +++ b/src/freeglut_cursor.c @@ -25,24 +25,16 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define G_LOG_DOMAIN "freeglut-cursor" - -#include "../include/GL/freeglut.h" +#include #include "freeglut_internal.h" #if TARGET_HOST_UNIX_X11 - #include + #include #endif /* * TODO BEFORE THE STABLE RELEASE: - * - * fgDisplayCursor() -- this waits for better times - * glutSetCursor() -- both X and Win32 mappings are incomplete + * glutSetCursor() -- Win32 mappings are incomplete. * * It would be good to use custom mouse cursor shapes, and introduce * an option to display them using glBitmap() and/or texture mapping, @@ -51,16 +43,66 @@ /* -- INTERNAL FUNCTIONS --------------------------------------------------- */ +#if TARGET_HOST_UNIX_X11 /* - * Display the mouse cursor using OpenGL calls + * A factory method for an empty cursor */ -void fgDisplayCursor( void ) +static Cursor getEmptyCursor( void ) { - /* - * Do nothing for the moment - */ + static Cursor cursorNone = None; + if( cursorNone == None ) { + char cursorNoneBits[ 32 ]; + XColor dontCare; + Pixmap cursorNonePixmap; + memset( cursorNoneBits, 0, sizeof( cursorNoneBits ) ); + memset( &dontCare, 0, sizeof( dontCare ) ); + cursorNonePixmap = XCreateBitmapFromData ( fgDisplay.Display, + fgDisplay.RootWindow, + cursorNoneBits, 16, 16 ); + if( cursorNonePixmap != None ) { + cursorNone = XCreatePixmapCursor( fgDisplay.Display, + cursorNonePixmap, cursorNonePixmap, + &dontCare, &dontCare, 0, 0 ); + XFreePixmap( fgDisplay.Display, cursorNonePixmap ); + } + } + return cursorNone; } +typedef struct tag_cursorCacheEntry cursorCacheEntry; +struct tag_cursorCacheEntry { + unsigned int cursorShape; /* an XC_foo value */ + Cursor cachedCursor; /* None if the corresponding cursor has + not been created yet */ +}; + +/* + * Note: The arrangement of the table below depends on the fact that + * the "normal" GLUT_CURSOR_* values start a 0 and are consecutive. + */ +static cursorCacheEntry cursorCache[] = { + { XC_arrow, None }, /* GLUT_CURSOR_RIGHT_ARROW */ + { XC_top_left_arrow, None }, /* GLUT_CURSOR_LEFT_ARROW */ + { XC_hand1, None }, /* GLUT_CURSOR_INFO */ + { XC_pirate, None }, /* GLUT_CURSOR_DESTROY */ + { XC_question_arrow, None }, /* GLUT_CURSOR_HELP */ + { XC_exchange, None }, /* GLUT_CURSOR_CYCLE */ + { XC_spraycan, None }, /* GLUT_CURSOR_SPRAY */ + { XC_watch, None }, /* GLUT_CURSOR_WAIT */ + { XC_xterm, None }, /* GLUT_CURSOR_TEXT */ + { XC_crosshair, None }, /* GLUT_CURSOR_CROSSHAIR */ + { XC_sb_v_double_arrow, None }, /* GLUT_CURSOR_UP_DOWN */ + { XC_sb_h_double_arrow, None }, /* GLUT_CURSOR_LEFT_RIGHT */ + { XC_top_side, None }, /* GLUT_CURSOR_TOP_SIDE */ + { XC_bottom_side, None }, /* GLUT_CURSOR_BOTTOM_SIDE */ + { XC_left_side, None }, /* GLUT_CURSOR_LEFT_SIDE */ + { XC_right_side, None }, /* GLUT_CURSOR_RIGHT_SIDE */ + { XC_top_left_corner, None }, /* GLUT_CURSOR_TOP_LEFT_CORNER */ + { XC_top_right_corner, None }, /* GLUT_CURSOR_TOP_RIGHT_CORNER */ + { XC_bottom_right_corner, None }, /* GLUT_CURSOR_BOTTOM_RIGHT_CORNER */ + { XC_bottom_left_corner, None } /* GLUT_CURSOR_BOTTOM_LEFT_CORNER */ +}; +#endif /* -- INTERFACE FUNCTIONS -------------------------------------------------- */ @@ -69,104 +111,107 @@ void fgDisplayCursor( void ) */ void FGAPIENTRY glutSetCursor( int cursorID ) { - /* - * Make sure freeglut is ready and there is a current window set - */ - freeglut_assert_ready; freeglut_assert_window; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetCursor" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetCursor" ); #if TARGET_HOST_UNIX_X11 - /* - * Open issues: - * (a) GLUT_CURSOR_NONE doesn't do what it should. - * (b) Are we allocating resources, or causing X to do so? - * If yes, we should arrange to deallocate! - * (c) No error checking. Is that a problem? - */ { - Cursor cursor; - - /* - * For now we'll limit ourselves to the X cursor fonts... - */ -#define MAP_CURSOR(a,b) case a: cursor = XCreateFontCursor( fgDisplay.Display, b ); break; - if( GLUT_CURSOR_FULL_CROSSHAIR == cursorID ) - cursorID = GLUT_CURSOR_CROSSHAIR; - switch( cursorID ) - { - MAP_CURSOR( GLUT_CURSOR_RIGHT_ARROW, XC_right_ptr); - MAP_CURSOR( GLUT_CURSOR_LEFT_ARROW, XC_left_ptr); - MAP_CURSOR( GLUT_CURSOR_INFO, XC_hand1); - MAP_CURSOR( GLUT_CURSOR_DESTROY, XC_pirate); - MAP_CURSOR( GLUT_CURSOR_HELP, XC_question_arrow); - MAP_CURSOR( GLUT_CURSOR_CYCLE, XC_exchange); - MAP_CURSOR( GLUT_CURSOR_SPRAY, XC_spraycan); - MAP_CURSOR( GLUT_CURSOR_WAIT, XC_watch); - MAP_CURSOR( GLUT_CURSOR_TEXT, XC_xterm); - MAP_CURSOR( GLUT_CURSOR_CROSSHAIR, XC_crosshair); - MAP_CURSOR( GLUT_CURSOR_UP_DOWN, XC_sb_v_double_arrow); - MAP_CURSOR( GLUT_CURSOR_LEFT_RIGHT, XC_sb_h_double_arrow); - MAP_CURSOR( GLUT_CURSOR_TOP_SIDE, XC_top_side); - MAP_CURSOR( GLUT_CURSOR_BOTTOM_SIDE, XC_bottom_side); - MAP_CURSOR( GLUT_CURSOR_LEFT_SIDE, XC_left_side); - MAP_CURSOR( GLUT_CURSOR_RIGHT_SIDE, XC_right_side); - MAP_CURSOR( GLUT_CURSOR_TOP_LEFT_CORNER, XC_top_left_corner); - MAP_CURSOR( GLUT_CURSOR_TOP_RIGHT_CORNER, XC_top_right_corner); - MAP_CURSOR( GLUT_CURSOR_BOTTOM_RIGHT_CORNER, XC_bottom_right_corner); - MAP_CURSOR( GLUT_CURSOR_BOTTOM_LEFT_CORNER, XC_bottom_left_corner); - MAP_CURSOR( GLUT_CURSOR_NONE, XC_bogosity); - case GLUT_CURSOR_INHERIT: - break; - default: - return; - } - - /* - * Define a window's cursor now - */ - if( GLUT_CURSOR_INHERIT == cursorID ) - XUndefineCursor( fgDisplay.Display, fgStructure.Window->Window.Handle ); - else - XDefineCursor( fgDisplay.Display, fgStructure.Window->Window.Handle, cursor ); + Cursor cursor; + /* + * XXX FULL_CROSSHAIR demotes to plain CROSSHAIR. Old GLUT allows + * for this, but if there is a system that easily supports a full- + * window (or full-screen) crosshair, we might consider it. + */ + int cursorIDToUse = + ( cursorID == GLUT_CURSOR_FULL_CROSSHAIR ) ? GLUT_CURSOR_CROSSHAIR : cursorID; + + if( ( cursorIDToUse >= 0 ) && + ( cursorIDToUse < sizeof( cursorCache ) / sizeof( cursorCache[0] ) ) ) { + cursorCacheEntry *entry = &cursorCache[ cursorIDToUse ]; + if( entry->cachedCursor == None ) { + entry->cachedCursor = + XCreateFontCursor( fgDisplay.Display, entry->cursorShape ); + } + cursor = entry->cachedCursor; + } else { + switch( cursorIDToUse ) + { + case GLUT_CURSOR_NONE: + cursor = getEmptyCursor( ); + break; + + case GLUT_CURSOR_INHERIT: + cursor = None; + break; + + default: + fgError( "Unknown cursor type: %d", cursorIDToUse ); + return; + } + } + + if ( ( cursorIDToUse != GLUT_CURSOR_NONE ) && ( cursor == None ) ) { + fgError( "Failed to create cursor" ); + } + XDefineCursor( fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, cursor ); } -#elif TARGET_HOST_WIN32 - /* - * This is a temporary solution only... - */ - /* Set the cursor AND change it for this window class. */ -# define MAP_CURSOR(a,b) case a: SetCursor( LoadCursor( NULL, b ) ); \ - SetClassLong(fgStructure.Window->Window.Handle,GCL_HCURSOR,(LONG)LoadCursor(NULL,b)); \ - break; - /* Nuke the cursor AND change it for this window class. */ -# define ZAP_CURSOR(a,b) case a: SetCursor( NULL ); \ - SetClassLong(fgStructure.Window->Window.Handle,GCL_HCURSOR,(LONG)NULL); \ +#elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE + + /* + * This is a temporary solution only... + */ + /* Set the cursor AND change it for this window class. */ +# define MAP_CURSOR(a,b) \ + case a: \ + SetCursor( LoadCursor( NULL, b ) ); \ + SetClassLong( fgStructure.CurrentWindow->Window.Handle, \ + GCL_HCURSOR, \ + ( LONG )LoadCursor( NULL, b ) ); \ break; - switch( cursorID ) - { - MAP_CURSOR( GLUT_CURSOR_RIGHT_ARROW, IDC_ARROW ); - MAP_CURSOR( GLUT_CURSOR_LEFT_ARROW, IDC_ARROW ); - MAP_CURSOR( GLUT_CURSOR_INFO, IDC_HELP ); - MAP_CURSOR( GLUT_CURSOR_DESTROY, IDC_CROSS ); - MAP_CURSOR( GLUT_CURSOR_HELP, IDC_HELP ); - MAP_CURSOR( GLUT_CURSOR_CYCLE, IDC_SIZEALL ); - MAP_CURSOR( GLUT_CURSOR_SPRAY, IDC_CROSS ); - MAP_CURSOR( GLUT_CURSOR_WAIT, IDC_WAIT ); - MAP_CURSOR( GLUT_CURSOR_TEXT, IDC_UPARROW ); - MAP_CURSOR( GLUT_CURSOR_CROSSHAIR, IDC_CROSS ); - /* MAP_CURSOR( GLUT_CURSOR_NONE, IDC_NO ); */ - ZAP_CURSOR( GLUT_CURSOR_NONE, NULL ); - - default: - MAP_CURSOR( GLUT_CURSOR_UP_DOWN, IDC_ARROW ); - } + /* Nuke the cursor AND change it for this window class. */ +# define ZAP_CURSOR(a,b) \ + case a: \ + SetCursor( NULL ); \ + SetClassLong( fgStructure.CurrentWindow->Window.Handle, \ + GCL_HCURSOR, ( LONG )NULL ); \ + break; + switch( cursorID ) + { + MAP_CURSOR( GLUT_CURSOR_RIGHT_ARROW, IDC_ARROW ); + MAP_CURSOR( GLUT_CURSOR_LEFT_ARROW, IDC_ARROW ); + MAP_CURSOR( GLUT_CURSOR_INFO, IDC_HELP ); + MAP_CURSOR( GLUT_CURSOR_DESTROY, IDC_CROSS ); + MAP_CURSOR( GLUT_CURSOR_HELP, IDC_HELP ); + MAP_CURSOR( GLUT_CURSOR_CYCLE, IDC_SIZEALL ); + MAP_CURSOR( GLUT_CURSOR_SPRAY, IDC_CROSS ); + MAP_CURSOR( GLUT_CURSOR_WAIT, IDC_WAIT ); + MAP_CURSOR( GLUT_CURSOR_TEXT, IDC_IBEAM ); + MAP_CURSOR( GLUT_CURSOR_CROSSHAIR, IDC_CROSS ); + MAP_CURSOR( GLUT_CURSOR_UP_DOWN, IDC_SIZENS ); + MAP_CURSOR( GLUT_CURSOR_LEFT_RIGHT, IDC_SIZEWE ); + MAP_CURSOR( GLUT_CURSOR_TOP_SIDE, IDC_ARROW ); /* XXX ToDo */ + MAP_CURSOR( GLUT_CURSOR_BOTTOM_SIDE, IDC_ARROW ); /* XXX ToDo */ + MAP_CURSOR( GLUT_CURSOR_LEFT_SIDE, IDC_ARROW ); /* XXX ToDo */ + MAP_CURSOR( GLUT_CURSOR_RIGHT_SIDE, IDC_ARROW ); /* XXX ToDo */ + MAP_CURSOR( GLUT_CURSOR_TOP_LEFT_CORNER, IDC_SIZENWSE ); + MAP_CURSOR( GLUT_CURSOR_TOP_RIGHT_CORNER, IDC_SIZENESW ); + MAP_CURSOR( GLUT_CURSOR_BOTTOM_RIGHT_CORNER, IDC_SIZENWSE ); + MAP_CURSOR( GLUT_CURSOR_BOTTOM_LEFT_CORNER, IDC_SIZENESW ); + MAP_CURSOR( GLUT_CURSOR_INHERIT, IDC_ARROW ); /* XXX ToDo */ + ZAP_CURSOR( GLUT_CURSOR_NONE, NULL ); + MAP_CURSOR( GLUT_CURSOR_FULL_CROSSHAIR, IDC_CROSS ); /* XXX ToDo */ + + default: + fgError( "Unknown cursor type: %d", cursorID ); + break; + } #endif - /* - * Remember the currently selected cursor - */ - fgStructure.Window->State.Cursor = cursorID; + fgStructure.CurrentWindow->State.Cursor = cursorID; } /* @@ -174,34 +219,30 @@ void FGAPIENTRY glutSetCursor( int cursorID ) */ void FGAPIENTRY glutWarpPointer( int x, int y ) { - freeglut_assert_ready; freeglut_assert_window; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWarpPointer" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutWarpPointer" ); #if TARGET_HOST_UNIX_X11 - /* - * Move the mouse pointer to given window coordinates - */ + XWarpPointer( fgDisplay.Display, None, - fgStructure.Window->Window.Handle, + fgStructure.CurrentWindow->Window.Handle, 0, 0, 0, 0, x, y ); - + /* Make the warp visible immediately. */ XFlush( fgDisplay.Display ); -#elif TARGET_HOST_WIN32 - { - POINT coords = { x, y }; +#elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE - /* - * First of all, we need to find the new screen-relative coordinates of the mouse cursor - */ - ClientToScreen( fgStructure.Window->Window.Handle, &coords ); + { + POINT coords; + coords.x = x; + coords.y = y; - /* - * Now set the new mouse cursor position... - */ + /* ClientToScreen() translates {coords} for us. */ + ClientToScreen( fgStructure.CurrentWindow->Window.Handle, &coords ); SetCursorPos( coords.x, coords.y ); }