Addressing bug report 3368139 about warnings under OpenSUSE. I added two explicit...
[freeglut] / src / freeglut_cursor.c
1 /*
2  * freeglut_cursor.c
3  *
4  * The mouse cursor related stuff.
5  *
6  * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7  * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8  * Creation date: Thu Dec 16 1999
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  */
27
28 #include <GL/freeglut.h>
29 #include "freeglut_internal.h"
30
31 /*
32  * TODO BEFORE THE STABLE RELEASE:
33  *  glutSetCursor()     -- Win32 mappings are incomplete.
34  *
35  * It would be good to use custom mouse cursor shapes, and introduce
36  * an option to display them using glBitmap() and/or texture mapping,
37  * apart from the windowing system version.
38  */
39
40 /* -- PRIVATE FUNCTIONS --------------------------------------------------- */
41
42 #if TARGET_HOST_POSIX_X11 || TARGET_HOST_MAC_OSX || TARGET_HOST_SOLARIS
43   #include <X11/cursorfont.h>
44
45 /*
46  * A factory method for an empty cursor
47  */
48 static Cursor getEmptyCursor( void )
49 {
50     static Cursor cursorNone = None;
51     if( cursorNone == None ) {
52         char cursorNoneBits[ 32 ];
53         XColor dontCare;
54         Pixmap cursorNonePixmap;
55         memset( cursorNoneBits, 0, sizeof( cursorNoneBits ) );
56         memset( &dontCare, 0, sizeof( dontCare ) );
57         cursorNonePixmap = XCreateBitmapFromData ( fgDisplay.Display,
58                                                    fgDisplay.RootWindow,
59                                                    cursorNoneBits, 16, 16 );
60         if( cursorNonePixmap != None ) {
61             cursorNone = XCreatePixmapCursor( fgDisplay.Display,
62                                               cursorNonePixmap, cursorNonePixmap,
63                                               &dontCare, &dontCare, 0, 0 );
64             XFreePixmap( fgDisplay.Display, cursorNonePixmap );
65         }
66     }
67     return cursorNone;
68 }
69
70 typedef struct tag_cursorCacheEntry cursorCacheEntry;
71 struct tag_cursorCacheEntry {
72     unsigned int cursorShape;    /* an XC_foo value */
73     Cursor cachedCursor;         /* None if the corresponding cursor has
74                                     not been created yet */
75 };
76
77 /*
78  * Note: The arrangement of the table below depends on the fact that
79  * the "normal" GLUT_CURSOR_* values start a 0 and are consecutive.
80  */ 
81 static cursorCacheEntry cursorCache[] = {
82     { XC_arrow,               None }, /* GLUT_CURSOR_RIGHT_ARROW */
83     { XC_top_left_arrow,      None }, /* GLUT_CURSOR_LEFT_ARROW */
84     { XC_hand1,               None }, /* GLUT_CURSOR_INFO */
85     { XC_pirate,              None }, /* GLUT_CURSOR_DESTROY */
86     { XC_question_arrow,      None }, /* GLUT_CURSOR_HELP */
87     { XC_exchange,            None }, /* GLUT_CURSOR_CYCLE */
88     { XC_spraycan,            None }, /* GLUT_CURSOR_SPRAY */
89     { XC_watch,               None }, /* GLUT_CURSOR_WAIT */
90     { XC_xterm,               None }, /* GLUT_CURSOR_TEXT */
91     { XC_crosshair,           None }, /* GLUT_CURSOR_CROSSHAIR */
92     { XC_sb_v_double_arrow,   None }, /* GLUT_CURSOR_UP_DOWN */
93     { XC_sb_h_double_arrow,   None }, /* GLUT_CURSOR_LEFT_RIGHT */
94     { XC_top_side,            None }, /* GLUT_CURSOR_TOP_SIDE */
95     { XC_bottom_side,         None }, /* GLUT_CURSOR_BOTTOM_SIDE */
96     { XC_left_side,           None }, /* GLUT_CURSOR_LEFT_SIDE */
97     { XC_right_side,          None }, /* GLUT_CURSOR_RIGHT_SIDE */
98     { XC_top_left_corner,     None }, /* GLUT_CURSOR_TOP_LEFT_CORNER */
99     { XC_top_right_corner,    None }, /* GLUT_CURSOR_TOP_RIGHT_CORNER */
100     { XC_bottom_right_corner, None }, /* GLUT_CURSOR_BOTTOM_RIGHT_CORNER */
101     { XC_bottom_left_corner,  None }  /* GLUT_CURSOR_BOTTOM_LEFT_CORNER */
102 };
103
104 static void fghSetCursor ( SFG_Window *window, int cursorID )
105 {
106     Cursor cursor;
107     /*
108      * XXX FULL_CROSSHAIR demotes to plain CROSSHAIR. Old GLUT allows
109      * for this, but if there is a system that easily supports a full-
110      * window (or full-screen) crosshair, we might consider it.
111      */
112     int cursorIDToUse =
113         ( cursorID == GLUT_CURSOR_FULL_CROSSHAIR ) ? GLUT_CURSOR_CROSSHAIR : cursorID;
114
115     if( ( cursorIDToUse >= 0 ) &&
116         ( cursorIDToUse < sizeof( cursorCache ) / sizeof( cursorCache[0] ) ) ) {
117         cursorCacheEntry *entry = &cursorCache[ cursorIDToUse ];
118         if( entry->cachedCursor == None ) {
119             entry->cachedCursor =
120                 XCreateFontCursor( fgDisplay.Display, entry->cursorShape );
121         }
122         cursor = entry->cachedCursor;
123     } else {
124         switch( cursorIDToUse )
125         {
126         case GLUT_CURSOR_NONE:
127             cursor = getEmptyCursor( );
128             break;
129
130         case GLUT_CURSOR_INHERIT:
131             cursor = None;
132             break;
133
134         default:
135             fgError( "Unknown cursor type: %d", cursorIDToUse );
136             return;
137         }
138     }
139
140     if ( cursorIDToUse == GLUT_CURSOR_INHERIT ) {
141         XUndefineCursor( fgDisplay.Display, window->Window.Handle );
142     } else if ( cursor != None ) {
143         XDefineCursor( fgDisplay.Display, window->Window.Handle, cursor );
144     } else if ( cursorIDToUse != GLUT_CURSOR_NONE ) {
145         fgError( "Failed to create cursor" );
146     }
147 }
148
149
150 static void fghWarpPointer ( int x, int y )
151 {
152     XWarpPointer(
153         fgDisplay.Display,
154         None,
155         fgStructure.CurrentWindow->Window.Handle,
156         0, 0, 0, 0,
157         x, y
158     );
159     /* Make the warp visible immediately. */
160     XFlush( fgDisplay.Display );
161 }
162 #endif
163
164
165 #if TARGET_HOST_MS_WINDOWS
166 static void fghSetCursor ( SFG_Window *window, int cursorID )
167 {
168     /*
169      * Joe Krahn is re-writing the following code.
170      */
171     /* Set the cursor AND change it for this window class. */
172 #if !defined(__MINGW64__) && _MSC_VER <= 1200
173 #       define MAP_CURSOR(a,b)                                   \
174         case a:                                                  \
175             SetCursor( LoadCursor( NULL, b ) );                  \
176             SetClassLong( window->Window.Handle,                 \
177                           GCL_HCURSOR,                           \
178                           ( LONG )LoadCursor( NULL, b ) );       \
179         break;
180     /* Nuke the cursor AND change it for this window class. */
181 #       define ZAP_CURSOR(a,b)                                   \
182         case a:                                                  \
183             SetCursor( NULL );                                   \
184             SetClassLong( window->Window.Handle,                 \
185                           GCL_HCURSOR, ( LONG )NULL );           \
186         break;
187 #else
188 #       define MAP_CURSOR(a,b)                                   \
189         case a:                                                  \
190             SetCursor( LoadCursor( NULL, b ) );                  \
191             SetClassLongPtr( window->Window.Handle,              \
192                           GCLP_HCURSOR,                          \
193                           ( LONG )( LONG_PTR )LoadCursor( NULL, b ) );       \
194         break;
195     /* Nuke the cursor AND change it for this window class. */
196 #       define ZAP_CURSOR(a,b)                                   \
197         case a:                                                  \
198             SetCursor( NULL );                                   \
199             SetClassLongPtr( window->Window.Handle,              \
200                           GCLP_HCURSOR, ( LONG )( LONG_PTR )NULL );          \
201         break;
202 #endif
203
204     switch( cursorID )
205     {
206         MAP_CURSOR( GLUT_CURSOR_RIGHT_ARROW,         IDC_ARROW     );
207         MAP_CURSOR( GLUT_CURSOR_LEFT_ARROW,          IDC_ARROW     );
208         MAP_CURSOR( GLUT_CURSOR_INFO,                IDC_HELP      );
209         MAP_CURSOR( GLUT_CURSOR_DESTROY,             IDC_CROSS     );
210         MAP_CURSOR( GLUT_CURSOR_HELP,                IDC_HELP      );
211         MAP_CURSOR( GLUT_CURSOR_CYCLE,               IDC_SIZEALL   );
212         MAP_CURSOR( GLUT_CURSOR_SPRAY,               IDC_CROSS     );
213         MAP_CURSOR( GLUT_CURSOR_WAIT,                IDC_WAIT      );
214         MAP_CURSOR( GLUT_CURSOR_TEXT,                IDC_IBEAM     );
215         MAP_CURSOR( GLUT_CURSOR_CROSSHAIR,           IDC_CROSS     );
216         MAP_CURSOR( GLUT_CURSOR_UP_DOWN,             IDC_SIZENS    );
217         MAP_CURSOR( GLUT_CURSOR_LEFT_RIGHT,          IDC_SIZEWE    );
218         MAP_CURSOR( GLUT_CURSOR_TOP_SIDE,            IDC_ARROW     ); /* XXX ToDo */
219         MAP_CURSOR( GLUT_CURSOR_BOTTOM_SIDE,         IDC_ARROW     ); /* XXX ToDo */
220         MAP_CURSOR( GLUT_CURSOR_LEFT_SIDE,           IDC_ARROW     ); /* XXX ToDo */
221         MAP_CURSOR( GLUT_CURSOR_RIGHT_SIDE,          IDC_ARROW     ); /* XXX ToDo */
222         MAP_CURSOR( GLUT_CURSOR_TOP_LEFT_CORNER,     IDC_SIZENWSE  );
223         MAP_CURSOR( GLUT_CURSOR_TOP_RIGHT_CORNER,    IDC_SIZENESW  );
224         MAP_CURSOR( GLUT_CURSOR_BOTTOM_RIGHT_CORNER, IDC_SIZENWSE  );
225         MAP_CURSOR( GLUT_CURSOR_BOTTOM_LEFT_CORNER,  IDC_SIZENESW  );
226         MAP_CURSOR( GLUT_CURSOR_INHERIT,             IDC_ARROW     ); /* XXX ToDo */
227         ZAP_CURSOR( GLUT_CURSOR_NONE,                NULL          );
228         MAP_CURSOR( GLUT_CURSOR_FULL_CROSSHAIR,      IDC_CROSS     ); /* XXX ToDo */
229
230     default:
231         fgError( "Unknown cursor type: %d", cursorID );
232         break;
233     }
234 }
235
236
237 static void fghWarpPointer ( int x, int y )
238 {
239     POINT coords;
240     coords.x = x;
241     coords.y = y;
242
243     /* ClientToScreen() translates {coords} for us. */
244     ClientToScreen( fgStructure.CurrentWindow->Window.Handle, &coords );
245     SetCursorPos( coords.x, coords.y );
246 }
247 #endif
248
249
250 /* -- INTERNAL FUNCTIONS ---------------------------------------------------- */
251 void fgSetCursor ( SFG_Window *window, int cursorID )
252 {
253     fghSetCursor ( window, cursorID );
254 }
255
256
257 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
258
259 /*
260  * Set the cursor image to be used for the current window
261  */
262 void FGAPIENTRY glutSetCursor( int cursorID )
263 {
264     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetCursor" );
265     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetCursor" );
266
267     fghSetCursor ( fgStructure.CurrentWindow, cursorID );
268     fgStructure.CurrentWindow->State.Cursor = cursorID;
269 }
270
271 /*
272  * Moves the mouse pointer to given window coordinates
273  */
274 void FGAPIENTRY glutWarpPointer( int x, int y )
275 {
276     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWarpPointer" );
277     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutWarpPointer" );
278
279     fghWarpPointer ( x, y );
280 }
281
282 /*** END OF FILE ***/