#include "config.h"
#endif
-#define G_LOG_DOMAIN "freeglut-cursor"
-
#include "../include/GL/freeglut.h"
#include "freeglut_internal.h"
#if TARGET_HOST_UNIX_X11
- #include <X11/cursorfont.h>
+ #include <X11/cursorfont.h>
#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,
/* -- INTERNAL FUNCTIONS --------------------------------------------------- */
-/*
- * Display the mouse cursor using OpenGL calls
- */
-void fgDisplayCursor( void )
+#if TARGET_HOST_UNIX_X11
+
+int fgGetCursorError( Cursor cursor )
{
- /*
- * Do nothing for the moment
- */
+ int ret = 0;
+ char buf[ 256 ];
+
+ switch( cursor )
+ {
+ case BadAlloc:
+ case BadFont:
+ case BadMatch:
+ case BadPixmap:
+ case BadValue:
+ XGetErrorText( fgDisplay.Display, cursor, buf, sizeof buf );
+ fgWarning( "Error in setting cursor:\n %s.", buf );
+ ret = cursor;
+ break;
+ default:
+ /* no error */
+ break;
+ }
+
+ return ret;
}
+#endif
+
/* -- INTERFACE FUNCTIONS -------------------------------------------------- */
*/
void FGAPIENTRY glutSetCursor( int cursorID )
{
+ freeglut_assert_ready; /* XXX WHY do we need the timer active for this? */
+ freeglut_assert_window;
+
+#if TARGET_HOST_UNIX_X11
/*
- * Make sure freeglut is ready and there is a current window set
+ * Open issues:
+ * (a) Partial error checking. Is that a problem?
+ * Is fgGetCursorError() 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?
*/
- freeglut_assert_ready; freeglut_assert_window;
+ {
+ Cursor cursor = None;
+ Pixmap no_cursor = None ; /* Used for GLUT_CURSOR_NONE */
+ int error = 0;
-#if TARGET_HOST_UNIX_X11
- {
- 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;
-
- switch( cursorID )
- {
- MAP_CURSOR( GLUT_CURSOR_RIGHT_ARROW, XC_left_ptr );
- MAP_CURSOR( GLUT_CURSOR_LEFT_ARROW, XC_right_ptr );
- MAP_CURSOR( GLUT_CURSOR_INFO, XC_question_arrow );
- MAP_CURSOR( GLUT_CURSOR_DESTROY, XC_target );
- MAP_CURSOR( GLUT_CURSOR_HELP, XC_question_arrow );
- MAP_CURSOR( GLUT_CURSOR_CYCLE, XC_circle );
- MAP_CURSOR( GLUT_CURSOR_SPRAY, XC_spraycan );
- MAP_CURSOR( GLUT_CURSOR_WAIT, XC_watch );
- MAP_CURSOR( GLUT_CURSOR_TEXT, XC_draft_large );
- MAP_CURSOR( GLUT_CURSOR_CROSSHAIR, XC_crosshair );
- MAP_CURSOR( GLUT_CURSOR_NONE, XC_trek );
-
- default:
- MAP_CURSOR( GLUT_CURSOR_UP_DOWN, XC_arrow );
- }
-
- /*
- * Define a window's cursor now
- */
- XDefineCursor( fgDisplay.Display, fgStructure.Window->Window.Handle, cursor );
- }
+#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_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 unsigned 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:
+ break;
+
+ default:
+ fgWarning( "Unknown cursor type: %d\n", cursorID );
+ return;
+ }
+
+ error = fgGetCursorError( 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 );
+ }
+ }
#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); \
+
+ /*
+ * 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;
- 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.Window->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_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 );
+ }
#endif
- /*
- * Remember the currently selected cursor
- */
fgStructure.Window->State.Cursor = cursorID;
}
*/
void FGAPIENTRY glutWarpPointer( int x, int y )
{
- freeglut_assert_ready; freeglut_assert_window;
+ freeglut_assert_ready; /* XXX WHY do we need the timer active for this? */
+ freeglut_assert_window;
#if TARGET_HOST_UNIX_X11
- /*
- * Move the mouse pointer to given window coordinates
- */
+
XWarpPointer(
fgDisplay.Display,
None,
0, 0, 0, 0,
x, y
);
-
- XFlush( fgDisplay.Display );
+ XFlush( fgDisplay.Display ); /* XXX Is this really necessary? */
#elif TARGET_HOST_WIN32
+
{
POINT coords = { x, y };
-
/*
- * First of all, we need to find the new screen-relative coordinates of the mouse cursor
+ * ClientToScreen() translates {coords} for us.
*/
ClientToScreen( fgStructure.Window->Window.Handle, &coords );
-
- /*
- * Now set the new mouse cursor position...
- */
SetCursorPos( coords.x, coords.y );
}