Reworked the X11 part of glutSetCursor, fixing bug #764187 (Variable mouse
pointers don't work) on the way: * Use slightly more compatible cursor shapes for GLUT_CURSOR_RIGHT_ARROW and GLUT_CURSOR_LEFT_ARROW. * Refactored and fixed the erroneous code for GLUT_CURSOR_NONE. * Removed the incorrect use of XFreeCursor and use a cache of cursors instead. Cursors are never freed now, we could do this e.g. via reference countig if this is really needed. * Fixed error handling. * Unknown cursor types are an error now. * Now the window state always corresponds to the wanted cursorID, even in the case of GLUT_CURSOR_FULL_CROSSHAIR. NOTE: I am not sure where the cursor cache should really reside, currently it is simply a file-local variable. git-svn-id: https://svn.code.sf.net/p/freeglut/code/trunk@560 7f0cb862-5218-0410-a997-914c9d46530a
This commit is contained in:
parent
1aa0b5ccf6
commit
ac2e30aecd
@ -905,3 +905,16 @@ a bit to do that.
|
|||||||
|
|
||||||
(235) Fixed part of bug #926883 (Video mode matching code, memory leaks,
|
(235) Fixed part of bug #926883 (Video mode matching code, memory leaks,
|
||||||
fullscreen), i.e. issue warnings when XF86VidModeFOO fails.
|
fullscreen), i.e. issue warnings when XF86VidModeFOO fails.
|
||||||
|
|
||||||
|
(236) Reworked the X11 part of glutSetCursor, fixing bug #764187 (Variable
|
||||||
|
mouse pointers don't work) on the way:
|
||||||
|
* Use slightly more compatible cursor shapes for GLUT_CURSOR_RIGHT_ARROW
|
||||||
|
and GLUT_CURSOR_LEFT_ARROW.
|
||||||
|
* Refactored and fixed the erroneous code for GLUT_CURSOR_NONE.
|
||||||
|
* Removed the incorrect use of XFreeCursor and use a cache of cursors
|
||||||
|
instead. Cursors are never freed now, we could do this e.g. via
|
||||||
|
reference countig if this is really needed.
|
||||||
|
* Fixed error handling.
|
||||||
|
* Unknown cursor types are an error now.
|
||||||
|
* Now the window state always corresponds to the wanted cursorID, even in
|
||||||
|
the case of GLUT_CURSOR_FULL_CROSSHAIR.
|
||||||
|
@ -43,34 +43,64 @@
|
|||||||
|
|
||||||
/* -- INTERNAL FUNCTIONS --------------------------------------------------- */
|
/* -- INTERNAL FUNCTIONS --------------------------------------------------- */
|
||||||
|
|
||||||
#if TARGET_HOST_UNIX_X11
|
/*
|
||||||
|
* A factory method for an empty cursor
|
||||||
static int fghGetCursorError( Cursor cursor )
|
*/
|
||||||
|
static Cursor getEmptyCursor( void )
|
||||||
{
|
{
|
||||||
int ret = 0;
|
static Cursor cursorNone = None;
|
||||||
char buf[ 256 ];
|
if( cursorNone == None ) {
|
||||||
|
char cursorNoneBits[ 32 ];
|
||||||
switch( cursor )
|
XColor dontCare;
|
||||||
{
|
Pixmap cursorNonePixmap;
|
||||||
case BadAlloc:
|
memset( cursorNoneBits, 0, sizeof( cursorNoneBits ) );
|
||||||
case BadFont:
|
memset( &dontCare, 0, sizeof( dontCare ) );
|
||||||
case BadMatch:
|
cursorNonePixmap = XCreateBitmapFromData ( fgDisplay.Display,
|
||||||
case BadPixmap:
|
fgDisplay.RootWindow,
|
||||||
case BadValue:
|
cursorNoneBits, 16, 16 );
|
||||||
XGetErrorText( fgDisplay.Display, cursor, buf, sizeof buf );
|
if( cursorNonePixmap != None ) {
|
||||||
fgWarning( "Error in setting cursor:\n %s.", buf );
|
cursorNone = XCreatePixmapCursor( fgDisplay.Display,
|
||||||
ret = cursor;
|
cursorNonePixmap, cursorNonePixmap,
|
||||||
break;
|
&dontCare, &dontCare, 0, 0 );
|
||||||
default:
|
XFreePixmap( fgDisplay.Display, cursorNonePixmap );
|
||||||
/* no error */
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
return cursorNone;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
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 */
|
||||||
|
};
|
||||||
|
|
||||||
/* -- INTERFACE FUNCTIONS -------------------------------------------------- */
|
/* -- INTERFACE FUNCTIONS -------------------------------------------------- */
|
||||||
|
|
||||||
@ -83,103 +113,46 @@ void FGAPIENTRY glutSetCursor( int cursorID )
|
|||||||
FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetCursor" );
|
FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetCursor" );
|
||||||
|
|
||||||
#if TARGET_HOST_UNIX_X11
|
#if TARGET_HOST_UNIX_X11
|
||||||
/*
|
|
||||||
* Open issues:
|
|
||||||
* (a) Partial error checking. Is that a problem?
|
|
||||||
* Is fghGetCursorError() correct? Should we abort on errors?
|
|
||||||
* Should there be a freeglut-wide X error handler? Should
|
|
||||||
* we use the X error-handler mechanism?
|
|
||||||
* (b) 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.
|
|
||||||
* (c) Out-of-range cursor-types generate warnings. Should we abort?
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
Cursor cursor = None;
|
Cursor cursor;
|
||||||
Pixmap no_cursor = None ; /* Used for GLUT_CURSOR_NONE */
|
/*
|
||||||
int error = 0;
|
* 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;
|
||||||
|
|
||||||
#define MAP_CURSOR(a,b) \
|
if( ( cursorIDToUse >= 0 ) &&
|
||||||
case a: \
|
( cursorIDToUse < sizeof( cursorCache ) / sizeof( cursorCache[0] ) ) ) {
|
||||||
cursor = XCreateFontCursor( fgDisplay.Display, b ); \
|
cursorCacheEntry *entry = &cursorCache[ cursorIDToUse ];
|
||||||
break;
|
if( entry->cachedCursor == None ) {
|
||||||
|
entry->cachedCursor =
|
||||||
|
XCreateFontCursor( fgDisplay.Display, entry->cursorShape );
|
||||||
|
}
|
||||||
|
cursor = entry->cachedCursor;
|
||||||
|
} else {
|
||||||
|
switch( cursorIDToUse )
|
||||||
|
{
|
||||||
|
case GLUT_CURSOR_NONE:
|
||||||
|
cursor = getEmptyCursor( );
|
||||||
|
break;
|
||||||
|
|
||||||
if( GLUT_CURSOR_FULL_CROSSHAIR == cursorID )
|
case GLUT_CURSOR_INHERIT:
|
||||||
cursorID = GLUT_CURSOR_CROSSHAIR;
|
cursor = None;
|
||||||
|
break;
|
||||||
|
|
||||||
switch( cursorID )
|
default:
|
||||||
{
|
fgError( "Unknown cursor type: %d", cursorIDToUse );
|
||||||
MAP_CURSOR( GLUT_CURSOR_RIGHT_ARROW, XC_right_ptr);
|
return;
|
||||||
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_NONE:
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Note that we *never* change {no_cursor_bits} from anything
|
|
||||||
* but all-zeros. It is our image and mask. We also apparently
|
|
||||||
* need to pick a color for foreground/background---but what
|
|
||||||
* one we pick doesn't matter for GLUT_CURSOR_NONE.
|
|
||||||
*/
|
|
||||||
static char no_cursor_bits[ 32 ];
|
|
||||||
XColor black;
|
|
||||||
no_cursor = XCreatePixmapFromBitmapData( fgDisplay.Display,
|
|
||||||
fgDisplay.RootWindow,
|
|
||||||
no_cursor_bits,
|
|
||||||
16, 16,
|
|
||||||
1, 0, 1 );
|
|
||||||
XParseColor( fgDisplay.Display,
|
|
||||||
DefaultColormap( fgDisplay.Display,
|
|
||||||
DefaultScreen( fgDisplay.Display ) ),
|
|
||||||
"black",
|
|
||||||
&black );
|
|
||||||
cursor = XCreatePixmapCursor( fgDisplay.Display,
|
|
||||||
no_cursor, no_cursor,
|
|
||||||
&black, &black,
|
|
||||||
0, 0 );
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case GLUT_CURSOR_INHERIT:
|
if ( ( cursorIDToUse != GLUT_CURSOR_NONE ) && ( cursor == None ) ) {
|
||||||
break;
|
fgError( "Failed to create cursor" );
|
||||||
|
|
||||||
default:
|
|
||||||
fgWarning( "Unknown cursor type: %d", cursorID );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = fghGetCursorError( cursor );
|
|
||||||
|
|
||||||
if( GLUT_CURSOR_INHERIT == cursorID )
|
|
||||||
XUndefineCursor( fgDisplay.Display,
|
|
||||||
fgStructure.Window->Window.Handle );
|
|
||||||
else
|
|
||||||
{
|
|
||||||
XDefineCursor( fgDisplay.Display,
|
|
||||||
fgStructure.Window->Window.Handle, cursor );
|
|
||||||
XFreeCursor( fgDisplay.Display, cursor );
|
|
||||||
if( GLUT_CURSOR_NONE == cursorID )
|
|
||||||
XFreePixmap( fgDisplay.Display, no_cursor );
|
|
||||||
}
|
}
|
||||||
|
XDefineCursor( fgDisplay.Display,
|
||||||
|
fgStructure.Window->Window.Handle, cursor );
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE
|
#elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE
|
||||||
@ -244,7 +217,8 @@ void FGAPIENTRY glutWarpPointer( int x, int y )
|
|||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
x, y
|
x, y
|
||||||
);
|
);
|
||||||
XFlush( fgDisplay.Display ); /* XXX Is this really necessary? */
|
/* Make the warp visible immediately. */
|
||||||
|
XFlush( fgDisplay.Display );
|
||||||
|
|
||||||
#elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE
|
#elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user