+/*\r
+ * freeglut_cursor_x11.c\r
+ *\r
+ * The Windows-specific mouse cursor related stuff.\r
+ *\r
+ * Copyright (c) 2012 Stephen J. Baker. All Rights Reserved.\r
+ * Written by John F. Fay, <fayjf@sourceforge.net>\r
+ * Creation date: Sun Feb 5, 2012\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a\r
+ * copy of this software and associated documentation files (the "Software"),\r
+ * to deal in the Software without restriction, including without limitation\r
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
+ * and/or sell copies of the Software, and to permit persons to whom the\r
+ * Software is furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included\r
+ * in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
+ * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ */\r
+\r
+#include <GL/freeglut.h>\r
+#include "../Common/freeglut_internal.h"\r
+\r
+/* This code is for Posix/X11, Solaris, and OSX */\r
+#include <X11/cursorfont.h>\r
+\r
+/*\r
+ * A factory method for an empty cursor\r
+ */\r
+static Cursor getEmptyCursor( void )\r
+{\r
+ static Cursor cursorNone = None;\r
+ if( cursorNone == None ) {\r
+ char cursorNoneBits[ 32 ];\r
+ XColor dontCare;\r
+ Pixmap cursorNonePixmap;\r
+ memset( cursorNoneBits, 0, sizeof( cursorNoneBits ) );\r
+ memset( &dontCare, 0, sizeof( dontCare ) );\r
+ cursorNonePixmap = XCreateBitmapFromData ( fgDisplay.pDisplay.Display,\r
+ fgDisplay.pDisplay.RootWindow,\r
+ cursorNoneBits, 16, 16 );\r
+ if( cursorNonePixmap != None ) {\r
+ cursorNone = XCreatePixmapCursor( fgDisplay.pDisplay.Display,\r
+ cursorNonePixmap, cursorNonePixmap,\r
+ &dontCare, &dontCare, 0, 0 );\r
+ XFreePixmap( fgDisplay.pDisplay.Display, cursorNonePixmap );\r
+ }\r
+ }\r
+ return cursorNone;\r
+}\r
+\r
+typedef struct tag_cursorCacheEntry cursorCacheEntry;\r
+struct tag_cursorCacheEntry {\r
+ unsigned int cursorShape; /* an XC_foo value */\r
+ Cursor cachedCursor; /* None if the corresponding cursor has\r
+ not been created yet */\r
+};\r
+\r
+/*\r
+ * Note: The arrangement of the table below depends on the fact that\r
+ * the "normal" GLUT_CURSOR_* values start a 0 and are consecutive.\r
+ */ \r
+static cursorCacheEntry cursorCache[] = {\r
+ { XC_arrow, None }, /* GLUT_CURSOR_RIGHT_ARROW */\r
+ { XC_top_left_arrow, None }, /* GLUT_CURSOR_LEFT_ARROW */\r
+ { XC_hand1, None }, /* GLUT_CURSOR_INFO */\r
+ { XC_pirate, None }, /* GLUT_CURSOR_DESTROY */\r
+ { XC_question_arrow, None }, /* GLUT_CURSOR_HELP */\r
+ { XC_exchange, None }, /* GLUT_CURSOR_CYCLE */\r
+ { XC_spraycan, None }, /* GLUT_CURSOR_SPRAY */\r
+ { XC_watch, None }, /* GLUT_CURSOR_WAIT */\r
+ { XC_xterm, None }, /* GLUT_CURSOR_TEXT */\r
+ { XC_crosshair, None }, /* GLUT_CURSOR_CROSSHAIR */\r
+ { XC_sb_v_double_arrow, None }, /* GLUT_CURSOR_UP_DOWN */\r
+ { XC_sb_h_double_arrow, None }, /* GLUT_CURSOR_LEFT_RIGHT */\r
+ { XC_top_side, None }, /* GLUT_CURSOR_TOP_SIDE */\r
+ { XC_bottom_side, None }, /* GLUT_CURSOR_BOTTOM_SIDE */\r
+ { XC_left_side, None }, /* GLUT_CURSOR_LEFT_SIDE */\r
+ { XC_right_side, None }, /* GLUT_CURSOR_RIGHT_SIDE */\r
+ { XC_top_left_corner, None }, /* GLUT_CURSOR_TOP_LEFT_CORNER */\r
+ { XC_top_right_corner, None }, /* GLUT_CURSOR_TOP_RIGHT_CORNER */\r
+ { XC_bottom_right_corner, None }, /* GLUT_CURSOR_BOTTOM_RIGHT_CORNER */\r
+ { XC_bottom_left_corner, None } /* GLUT_CURSOR_BOTTOM_LEFT_CORNER */\r
+};\r
+\r
+void fgPlatformSetCursor ( SFG_Window *window, int cursorID )\r
+{\r
+ Cursor cursor;\r
+ /*\r
+ * XXX FULL_CROSSHAIR demotes to plain CROSSHAIR. Old GLUT allows\r
+ * for this, but if there is a system that easily supports a full-\r
+ * window (or full-screen) crosshair, we might consider it.\r
+ */\r
+ int cursorIDToUse =\r
+ ( cursorID == GLUT_CURSOR_FULL_CROSSHAIR ) ? GLUT_CURSOR_CROSSHAIR : cursorID;\r
+\r
+ if( ( cursorIDToUse >= 0 ) &&\r
+ ( cursorIDToUse < sizeof( cursorCache ) / sizeof( cursorCache[0] ) ) ) {\r
+ cursorCacheEntry *entry = &cursorCache[ cursorIDToUse ];\r
+ if( entry->cachedCursor == None ) {\r
+ entry->cachedCursor =\r
+ XCreateFontCursor( fgDisplay.pDisplay.Display, entry->cursorShape );\r
+ }\r
+ cursor = entry->cachedCursor;\r
+ } else {\r
+ switch( cursorIDToUse )\r
+ {\r
+ case GLUT_CURSOR_NONE:\r
+ cursor = getEmptyCursor( );\r
+ break;\r
+\r
+ case GLUT_CURSOR_INHERIT:\r
+ cursor = None;\r
+ break;\r
+\r
+ default:\r
+ fgError( "Unknown cursor type: %d", cursorIDToUse );\r
+ return;\r
+ }\r
+ }\r
+\r
+ if ( cursorIDToUse == GLUT_CURSOR_INHERIT ) {\r
+ XUndefineCursor( fgDisplay.pDisplay.Display, window->Window.Handle );\r
+ } else if ( cursor != None ) {\r
+ XDefineCursor( fgDisplay.pDisplay.Display, window->Window.Handle, cursor );\r
+ } else if ( cursorIDToUse != GLUT_CURSOR_NONE ) {\r
+ fgError( "Failed to create cursor" );\r
+ }\r
+}\r
+\r
+\r
+void fgPlatformWarpPointer ( int x, int y )\r
+{\r
+ XWarpPointer(\r
+ fgDisplay.pDisplay.Display,\r
+ None,\r
+ fgStructure.CurrentWindow->Window.Handle,\r
+ 0, 0, 0, 0,\r
+ x, y\r
+ );\r
+ /* Make the warp visible immediately. */\r
+ XFlush( fgDisplay.pDisplay.Display );\r
+}\r
+\r