Include freeglut header via <GL/freeglut.h> rather than "../include/GL/freeglut.h"
[freeglut] / src / freeglut_cursor.c
index 9d519c0..23839a5 100644 (file)
 #include "config.h"
 #endif
 
-#define  G_LOG_DOMAIN  "freeglut-cursor"
-
-#include "../include/GL/freeglut.h"
+#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 -------------------------------------------------- */
 
@@ -69,81 +83,151 @@ void fgDisplayCursor( void )
  */
 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;
 }
 
@@ -152,12 +236,11 @@ void FGAPIENTRY glutSetCursor( int 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,
@@ -165,21 +248,19 @@ void FGAPIENTRY glutWarpPointer( int x, int y )
         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 };
+        POINT coords;
+        coords.x = x;
+        coords.y = 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 );
     }