31af78440ffbc6735e2e061f89660c8c8e0e87b6
[freeglut] / src / Common / freeglut_cursor.c
1 /*\r
2  * freeglut_cursor.c\r
3  *\r
4  * The mouse cursor related stuff.\r
5  *\r
6  * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.\r
7  * Written by Pawel W. Olszta, <olszta@sourceforge.net>\r
8  * Creation date: Thu Dec 16 1999\r
9  *\r
10  * Permission is hereby granted, free of charge, to any person obtaining a\r
11  * copy of this software and associated documentation files (the "Software"),\r
12  * to deal in the Software without restriction, including without limitation\r
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
14  * and/or sell copies of the Software, and to permit persons to whom the\r
15  * Software is furnished to do so, subject to the following conditions:\r
16  *\r
17  * The above copyright notice and this permission notice shall be included\r
18  * in all copies or substantial portions of the Software.\r
19  *\r
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\r
23  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
24  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
26  */\r
27 \r
28 #include <GL/freeglut.h>\r
29 #include "freeglut_internal.h"\r
30 \r
31 /*\r
32  * TODO BEFORE THE STABLE RELEASE:\r
33  *  glutSetCursor()     -- Win32 mappings are incomplete.\r
34  *\r
35  * It would be good to use custom mouse cursor shapes, and introduce\r
36  * an option to display them using glBitmap() and/or texture mapping,\r
37  * apart from the windowing system version.\r
38  */\r
39 \r
40 /* -- PRIVATE FUNCTIONS --------------------------------------------------- */\r
41 \r
42 extern void fgPlatformSetCursor ( SFG_Window *window, int cursorID );\r
43 extern void fgPlatformWarpPointer ( int x, int y );\r
44 \r
45 #if TARGET_HOST_POSIX_X11 || TARGET_HOST_MAC_OSX || TARGET_HOST_SOLARIS\r
46   #include <X11/cursorfont.h>\r
47 \r
48 /*\r
49  * A factory method for an empty cursor\r
50  */\r
51 static Cursor getEmptyCursor( void )\r
52 {\r
53     static Cursor cursorNone = None;\r
54     if( cursorNone == None ) {\r
55         char cursorNoneBits[ 32 ];\r
56         XColor dontCare;\r
57         Pixmap cursorNonePixmap;\r
58         memset( cursorNoneBits, 0, sizeof( cursorNoneBits ) );\r
59         memset( &dontCare, 0, sizeof( dontCare ) );\r
60         cursorNonePixmap = XCreateBitmapFromData ( fgDisplay.Display,\r
61                                                    fgDisplay.RootWindow,\r
62                                                    cursorNoneBits, 16, 16 );\r
63         if( cursorNonePixmap != None ) {\r
64             cursorNone = XCreatePixmapCursor( fgDisplay.Display,\r
65                                               cursorNonePixmap, cursorNonePixmap,\r
66                                               &dontCare, &dontCare, 0, 0 );\r
67             XFreePixmap( fgDisplay.Display, cursorNonePixmap );\r
68         }\r
69     }\r
70     return cursorNone;\r
71 }\r
72 \r
73 typedef struct tag_cursorCacheEntry cursorCacheEntry;\r
74 struct tag_cursorCacheEntry {\r
75     unsigned int cursorShape;    /* an XC_foo value */\r
76     Cursor cachedCursor;         /* None if the corresponding cursor has\r
77                                     not been created yet */\r
78 };\r
79 \r
80 /*\r
81  * Note: The arrangement of the table below depends on the fact that\r
82  * the "normal" GLUT_CURSOR_* values start a 0 and are consecutive.\r
83  */ \r
84 static cursorCacheEntry cursorCache[] = {\r
85     { XC_arrow,               None }, /* GLUT_CURSOR_RIGHT_ARROW */\r
86     { XC_top_left_arrow,      None }, /* GLUT_CURSOR_LEFT_ARROW */\r
87     { XC_hand1,               None }, /* GLUT_CURSOR_INFO */\r
88     { XC_pirate,              None }, /* GLUT_CURSOR_DESTROY */\r
89     { XC_question_arrow,      None }, /* GLUT_CURSOR_HELP */\r
90     { XC_exchange,            None }, /* GLUT_CURSOR_CYCLE */\r
91     { XC_spraycan,            None }, /* GLUT_CURSOR_SPRAY */\r
92     { XC_watch,               None }, /* GLUT_CURSOR_WAIT */\r
93     { XC_xterm,               None }, /* GLUT_CURSOR_TEXT */\r
94     { XC_crosshair,           None }, /* GLUT_CURSOR_CROSSHAIR */\r
95     { XC_sb_v_double_arrow,   None }, /* GLUT_CURSOR_UP_DOWN */\r
96     { XC_sb_h_double_arrow,   None }, /* GLUT_CURSOR_LEFT_RIGHT */\r
97     { XC_top_side,            None }, /* GLUT_CURSOR_TOP_SIDE */\r
98     { XC_bottom_side,         None }, /* GLUT_CURSOR_BOTTOM_SIDE */\r
99     { XC_left_side,           None }, /* GLUT_CURSOR_LEFT_SIDE */\r
100     { XC_right_side,          None }, /* GLUT_CURSOR_RIGHT_SIDE */\r
101     { XC_top_left_corner,     None }, /* GLUT_CURSOR_TOP_LEFT_CORNER */\r
102     { XC_top_right_corner,    None }, /* GLUT_CURSOR_TOP_RIGHT_CORNER */\r
103     { XC_bottom_right_corner, None }, /* GLUT_CURSOR_BOTTOM_RIGHT_CORNER */\r
104     { XC_bottom_left_corner,  None }  /* GLUT_CURSOR_BOTTOM_LEFT_CORNER */\r
105 };\r
106 \r
107 static void fgPlatformSetCursor ( SFG_Window *window, int cursorID )\r
108 {\r
109     Cursor cursor;\r
110     /*\r
111      * XXX FULL_CROSSHAIR demotes to plain CROSSHAIR. Old GLUT allows\r
112      * for this, but if there is a system that easily supports a full-\r
113      * window (or full-screen) crosshair, we might consider it.\r
114      */\r
115     int cursorIDToUse =\r
116         ( cursorID == GLUT_CURSOR_FULL_CROSSHAIR ) ? GLUT_CURSOR_CROSSHAIR : cursorID;\r
117 \r
118     if( ( cursorIDToUse >= 0 ) &&\r
119         ( cursorIDToUse < sizeof( cursorCache ) / sizeof( cursorCache[0] ) ) ) {\r
120         cursorCacheEntry *entry = &cursorCache[ cursorIDToUse ];\r
121         if( entry->cachedCursor == None ) {\r
122             entry->cachedCursor =\r
123                 XCreateFontCursor( fgDisplay.Display, entry->cursorShape );\r
124         }\r
125         cursor = entry->cachedCursor;\r
126     } else {\r
127         switch( cursorIDToUse )\r
128         {\r
129         case GLUT_CURSOR_NONE:\r
130             cursor = getEmptyCursor( );\r
131             break;\r
132 \r
133         case GLUT_CURSOR_INHERIT:\r
134             cursor = None;\r
135             break;\r
136 \r
137         default:\r
138             fgError( "Unknown cursor type: %d", cursorIDToUse );\r
139             return;\r
140         }\r
141     }\r
142 \r
143     if ( cursorIDToUse == GLUT_CURSOR_INHERIT ) {\r
144         XUndefineCursor( fgDisplay.Display, window->Window.Handle );\r
145     } else if ( cursor != None ) {\r
146         XDefineCursor( fgDisplay.Display, window->Window.Handle, cursor );\r
147     } else if ( cursorIDToUse != GLUT_CURSOR_NONE ) {\r
148         fgError( "Failed to create cursor" );\r
149     }\r
150 }\r
151 \r
152 \r
153 static void fgPlatformWarpPointer ( int x, int y )\r
154 {\r
155     XWarpPointer(\r
156         fgDisplay.Display,\r
157         None,\r
158         fgStructure.CurrentWindow->Window.Handle,\r
159         0, 0, 0, 0,\r
160         x, y\r
161     );\r
162     /* Make the warp visible immediately. */\r
163     XFlush( fgDisplay.Display );\r
164 }\r
165 #endif\r
166 \r
167 \r
168 /* -- INTERNAL FUNCTIONS ---------------------------------------------------- */\r
169 void fgSetCursor ( SFG_Window *window, int cursorID )\r
170 {\r
171     fgPlatformSetCursor ( window, cursorID );\r
172 }\r
173 \r
174 \r
175 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */\r
176 \r
177 /*\r
178  * Set the cursor image to be used for the current window\r
179  */\r
180 void FGAPIENTRY glutSetCursor( int cursorID )\r
181 {\r
182     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetCursor" );\r
183     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetCursor" );\r
184 \r
185     fgPlatformSetCursor ( fgStructure.CurrentWindow, cursorID );\r
186     fgStructure.CurrentWindow->State.Cursor = cursorID;\r
187 }\r
188 \r
189 /*\r
190  * Moves the mouse pointer to given window coordinates\r
191  */\r
192 void FGAPIENTRY glutWarpPointer( int x, int y )\r
193 {\r
194     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWarpPointer" );\r
195     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutWarpPointer" );\r
196 \r
197     fgPlatformWarpPointer ( x, y );\r
198 }\r
199 \r
200 /*** END OF FILE ***/\r