- freeglut_assert_ready;
- freeglut_assert_window;
-
-#if TARGET_HOST_UNIX_X11
- /*
- * Open issues:
- * (a) GLUT_CURSOR_NONE doesn't do what it should. We can probably
- * build an empty pixmap for it, though, quite painlessly.
- * (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?
- * (d) 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.
- * (e) Out-of-range cursor-types are ignored. Should we abort?
- * Print a warning message?
- */
- {
- Cursor 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 )
+ 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 */
+};
+
+static void fghSetCursor ( SFG_Window *window, int cursorID )
+{
+ 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 )