Re: [AD] Using system mouse cursor

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


On Friday 27 August 2004 11:44, Evert Glebbeek wrote:
> Unfortunately, simply checking the _xwin.mouse_warped flag isn't going to 
> do the trick since the X11 mouse driver sets this to non-zero initially 
> and there's no way currently (bar hacking) to tell Allegro to switch to a 
> hardware or software cursor.

The attached patch includes a fix. It adds an additional flag that can be 
used to allow or disallow the hardware cursor. Initially, this is set to 
TRUE, but it is set to false when the mouse is switched to mickey mode and 
set back to TRUE if the mouse leaves mickey mode.
If a hardware cursor is available and a cursor is being displayed on the 
screen, the code will change between the hardware and software cursor by 
calling show_mouse(_mouse_screen).
Tested using the exmouse and test programmes.

Evert
Index: aclocal.m4
===================================================================
RCS file: /cvsroot/alleg/allegro/aclocal.m4,v
retrieving revision 1.67
diff -u -r1.67 aclocal.m4
--- aclocal.m4	24 Aug 2004 18:34:07 -0000	1.67
+++ aclocal.m4	27 Aug 2004 12:11:12 -0000
@@ -257,6 +257,19 @@
     AC_DEFINE(ALLEGRO_XWINDOWS_WITH_XPM,1,[Define if xpm bitmap support is available.])
     ])
    )
+   
+  dnl Test for Xcursor library.
+  AC_CHECK_LIB(Xcursor, XcursorImageCreate,
+    AC_TRY_COMPILE([#include <X11/Xlib.h>
+                    #include <X11/Xcursor/Xcursor.h>], 
+                   [XcursorImage *xcursor_image;
+                    XcursorImageLoadCursor(0, xcursor_image);
+                    XcursorSupportsARGB(0);
+                   ],
+      [LIBS="-lXcursor $LIBS"
+      AC_DEFINE(ALLEGRO_XWINDOWS_WITH_XCURSOR,1,[Define if XCursor ARGB extension is available.])
+      ])
+   )
 
   dnl Test for SHM extension.
   if test -n "$allegro_enable_xwin_shm"; then
Index: include/xalleg.h
===================================================================
RCS file: /cvsroot/alleg/allegro/include/xalleg.h,v
retrieving revision 1.16
diff -u -r1.16 xalleg.h
--- include/xalleg.h	15 Nov 2002 11:07:48 -0000	1.16
+++ include/xalleg.h	27 Aug 2004 12:11:12 -0000
@@ -49,6 +49,11 @@
 #include <X11/extensions/xf86dga.h>
 #endif
 
+#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
+#include <X11/Xcursor/Xcursor.h>
+#endif
+
+
 
 #ifdef __cplusplus
    extern "C" {
@@ -65,8 +70,13 @@
    Visual *visual;
    Colormap colormap;
    XImage *ximage;
+#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
+   XcursorImage *xcursor_image;
+   XcursorBool support_argb_cursor;
+#endif
    Cursor cursor;
    int cursor_shape;
+   int hw_cursor_ok;
 
    void (*bank_switch)(int line);
    void (*screen_to_buffer)(int sx, int sy, int sw, int sh);
Index: src/x/xgfxdrv.c
===================================================================
RCS file: /cvsroot/alleg/allegro/src/x/xgfxdrv.c,v
retrieving revision 1.14
diff -u -r1.14 xgfxdrv.c
--- src/x/xgfxdrv.c	18 Aug 2004 12:45:53 -0000	1.14
+++ src/x/xgfxdrv.c	27 Aug 2004 12:11:14 -0000
@@ -39,7 +39,14 @@
    NULL, NULL, NULL,
    NULL, NULL, NULL, NULL,
    NULL, NULL,
+#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
+   _xwin_set_mouse_sprite,
+   _xwin_show_mouse,
+   _xwin_hide_mouse,
+   _xwin_move_mouse,
+#else
    NULL, NULL, NULL, NULL,
+#endif
    _xwin_drawing_mode,
    NULL, NULL,
    NULL,
@@ -71,7 +78,14 @@
    NULL, NULL, NULL,
    NULL, NULL, NULL, NULL,
    NULL, NULL,
+#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
+   _xwin_set_mouse_sprite,
+   _xwin_show_mouse,
+   _xwin_hide_mouse,
+   _xwin_move_mouse,
+#else
    NULL, NULL, NULL, NULL,
+#endif
    _xwin_drawing_mode,
    NULL, NULL,
    _xwin_fetch_mode_list,
Index: src/x/xwin.c
===================================================================
RCS file: /cvsroot/alleg/allegro/src/x/xwin.c,v
retrieving revision 1.67
diff -u -r1.67 xwin.c
--- src/x/xwin.c	24 Aug 2004 14:06:22 -0000	1.67
+++ src/x/xwin.c	27 Aug 2004 12:11:16 -0000
@@ -48,6 +48,10 @@
 #include <X11/extensions/xf86dga.h>
 #endif
 
+#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
+#include <X11/Xcursor/Xcursor.h>
+#endif
+
 
 #ifdef ALLEGRO_XWINDOWS_WITH_XPM
 #include <X11/xpm.h>
@@ -70,8 +74,13 @@
    0,           /* visual */
    None,        /* colormap */
    0,           /* ximage */
+#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
+   None,        /* ARGB cursor image */
+   XcursorFalse,/* Are ARGB cursors supported? */
+#endif
    None,        /* cursor */
    XC_heart,    /* cursor_shape */
+   1,           /* hw_cursor_ok */
 
    0,           /* bank_switch */
    0,           /* screen_to_buffer */
@@ -351,6 +360,42 @@
 
 
 
+/* _xwin_hide_x_mouse:
+ * Create invisible X cursor
+ */
+static void _xwin_hide_x_mouse(void)
+{
+   unsigned long gcmask;
+   XGCValues gcvalues;
+   Pixmap pixmap;
+   
+   pixmap = XCreatePixmap(_xwin.display, _xwin.window, 1, 1, 1);
+   if (pixmap != None) {
+      GC temp_gc;
+      XColor color;
+
+      gcmask = GCFunction | GCForeground | GCBackground;
+      gcvalues.function = GXcopy;
+      gcvalues.foreground = 0;
+      gcvalues.background = 0;
+      temp_gc = XCreateGC(_xwin.display, pixmap, gcmask, &gcvalues);
+      XDrawPoint(_xwin.display, pixmap, temp_gc, 0, 0);
+      XFreeGC(_xwin.display, temp_gc);
+      color.pixel = 0;
+      color.red = color.green = color.blue = 0;
+      color.flags = DoRed | DoGreen | DoBlue;
+      _xwin.cursor = XCreatePixmapCursor(_xwin.display, pixmap, pixmap, &color, &color, 0, 0);
+      XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
+      XFreePixmap(_xwin.display, pixmap);
+   }
+   else {
+      _xwin.cursor = XCreateFontCursor(_xwin.display, _xwin.cursor_shape);
+      XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
+   }
+}
+
+
+
 /* _xwin_create_window:
  *  Wrapper for XCreateWindow.
  */
@@ -360,7 +405,6 @@
    XGCValues gcvalues;
    XSetWindowAttributes setattr;
    XWindowAttributes getattr;
-   Pixmap pixmap;
 
    if (_xwin.display == 0)
       return -1;
@@ -412,30 +456,16 @@
    _xwin.gc = XCreateGC(_xwin.display, _xwin.window, gcmask, &gcvalues);
 
    /* Create invisible X cursor.  */
-   pixmap = XCreatePixmap(_xwin.display, _xwin.window, 1, 1, 1);
-   if (pixmap != None) {
-      GC temp_gc;
-      XColor color;
-
-      gcmask = GCFunction | GCForeground | GCBackground;
-      gcvalues.function = GXcopy;
-      gcvalues.foreground = 0;
-      gcvalues.background = 0;
-      temp_gc = XCreateGC(_xwin.display, pixmap, gcmask, &gcvalues);
-      XDrawPoint(_xwin.display, pixmap, temp_gc, 0, 0);
-      XFreeGC(_xwin.display, temp_gc);
-      color.pixel = 0;
-      color.red = color.green = color.blue = 0;
-      color.flags = DoRed | DoGreen | DoBlue;
-      _xwin.cursor = XCreatePixmapCursor(_xwin.display, pixmap, pixmap, &color, &color, 0, 0);
-      XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
-      XFreePixmap(_xwin.display, pixmap);
-   }
-   else {
-      _xwin.cursor = XCreateFontCursor(_xwin.display, _xwin.cursor_shape);
-      XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
-   }
-
+   _xwin_hide_x_mouse();
+   
+#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
+   /* Detect if ARGB cursors are supported */
+   _xwin.support_argb_cursor = XcursorSupportsARGB(_xwin.display);
+   _xwin.hw_cursor_ok = 1;
+#else
+   _xwin.hw_cursor_ok = 0;
+#endif
+   
    return 0;
 }
 
@@ -1582,6 +1612,147 @@
 
 
 
+#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
+
+/* _xwin_set_mouse_sprite:
+ *  Set custom X cursor (if supported)
+ */
+int _xwin_set_mouse_sprite(struct BITMAP *sprite, int x, int y)
+{
+#define GET_PIXEL_DATA(depth, getpix)                                \
+               case depth:                                           \
+                  c = 0;                                             \
+                  for(iy=0; iy<mouse_sprite->h; iy++) {              \
+                     for(ix=0; ix<mouse_sprite->w;  ix++) {          \
+                        col = getpix(mouse_sprite, ix, iy);          \
+                        if (col == (MASK_COLOR_ ## depth)) {         \
+                           r = g = b = a = 0;                        \
+                        }                                            \
+                        else {                                       \
+                           r = getr ## depth(col);                   \
+                           g = getg ## depth(col);                   \
+                           b = getb ## depth(col);                   \
+                           a = 255;                                  \
+                        }                                            \
+                        _xwin.xcursor_image->pixels[c++] =           \
+                                    (a<<24)|(r<<16)|(g<<8)|(b);      \
+                     }                                               \
+                  }
+
+   if (!_xwin.support_argb_cursor) {
+      return -1;
+   }
+   
+   if (_xwin.xcursor_image != None) {
+      XLOCK();
+      XcursorImageDestroy(_xwin.xcursor_image);
+      XUNLOCK();
+      _xwin.xcursor_image = None;
+   }
+   
+   if (sprite) {
+      int ix, iy;
+      int r = 0, g = 0, b = 0, a = 0, c, col;
+
+      _xwin.xcursor_image = XcursorImageCreate(sprite->w, sprite->h);
+      if (_xwin.xcursor_image == None) {
+         return -1;
+      }
+      
+      
+      switch(bitmap_color_depth(mouse_sprite)) {
+         GET_PIXEL_DATA(8, _getpixel)
+            break;
+                  
+         GET_PIXEL_DATA(15, _getpixel15)
+            break;
+
+         GET_PIXEL_DATA(16, _getpixel16)
+            break;
+
+         GET_PIXEL_DATA(24, _getpixel24)
+            break;
+
+         GET_PIXEL_DATA(32, _getpixel32)
+            break;
+      } /* End switch */
+      
+      _xwin.xcursor_image->xhot = mouse_x_focus;
+      _xwin.xcursor_image->yhot = mouse_y_focus;
+      
+      return 0;
+   }
+   
+#undef GET_PIXEL_DATA
+
+   return -1;  
+}
+
+
+
+/* _xwin_show_mouse:
+ *  Show the custom X cursor (if supported)
+ */
+int _xwin_show_mouse(struct BITMAP *bmp, int x, int y)
+{
+   /* Only draw on screen */
+   if (!is_same_bitmap(bmp, screen))
+      return -1;
+      
+   if (!_xwin.support_argb_cursor) {
+      return -1;
+   }
+
+   if (_xwin.xcursor_image == None) {
+      return -1;
+   }
+
+   /* Hardware cursor is disabled (mickey mode) */   
+   if (!_xwin.hw_cursor_ok) {
+      return -1;
+   }
+
+   XLOCK();
+   if (_xwin.cursor != None) {
+      XUndefineCursor(_xwin.display, _xwin.window);
+      XFreeCursor(_xwin.display, _xwin.cursor);
+   }   
+
+   _xwin.cursor = XcursorImageLoadCursor(_xwin.display, _xwin.xcursor_image);
+   XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
+
+   XUNLOCK();   
+   return 0;
+}
+
+
+
+/* _xwin_hide_mouse:
+ *  Hide the custom X cursor (if supported)
+ */
+void _xwin_hide_mouse(void)
+{
+   if (_xwin.support_argb_cursor) {
+      XLOCK();
+      _xwin_hide_x_mouse();
+      XUNLOCK();
+   }
+   return;
+}
+
+
+
+/* _xwin_move_mouse:
+ *  Move the custom X cursor. This is actually done automatically.
+ */
+void _xwin_move_mouse(int x, int y)
+{
+}
+
+#endif   /* ALLEGRO_XWINDOWS_WITH_XCURSOR */
+
+
+
 #ifdef ALLEGRO_XWINDOWS_WITH_XF86DGA
 
 /* _xdga_fast_visual_depth:
@@ -2385,6 +2556,14 @@
 		      0, 0, _xwin.window_width, _xwin.window_height,
 		      _mouse_x - (_xwin_mouse_extended_range ? _xwin.scroll_x : 0),
 		      _mouse_y - (_xwin_mouse_extended_range ? _xwin.scroll_y : 0));
+         /* Re-enable hardware cursor */
+         _xwin.hw_cursor_ok = 1;
+#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
+         if (_xwin.support_argb_cursor && (_xwin.xcursor_image != None) && is_same_bitmap(_mouse_screen, screen)) {
+            show_mouse(_mouse_screen);
+         }
+#endif
+         
       }
 #ifdef ALLEGRO_XWINDOWS_WITH_XF86DGA
    }
@@ -2460,6 +2639,14 @@
 static void _xwin_private_set_warped_mouse_mode(int permanent)
 {
    _xwin.mouse_warped = ((permanent) ? 1 : (MOUSE_WARP_DELAY*7/8));
+   
+   /* Disable hardware cursor in warp mode */
+#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
+   if (_xwin.hw_cursor_ok && permanent && _xwin.support_argb_cursor && (_xwin.xcursor_image != None) && is_same_bitmap(_mouse_screen, screen)) {
+      show_mouse(_mouse_screen);
+   }
+#endif
+   _xwin.hw_cursor_ok = !permanent;
 }
 
 void _xwin_set_warped_mouse_mode(int permanent)
Index: src/x/xwin.h
===================================================================
RCS file: /cvsroot/alleg/allegro/src/x/xwin.h,v
retrieving revision 1.17
diff -u -r1.17 xwin.h
--- src/x/xwin.h	18 Aug 2004 13:03:46 -0000	1.17
+++ src/x/xwin.h	27 Aug 2004 12:11:17 -0000
@@ -51,6 +51,13 @@
 AL_FUNC(int, _xwin_get_pointer_mapping, (unsigned char map[], int nmap));
 AL_FUNC(void, _xwin_init_keyboard_tables, (void));
 
+#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
+AL_FUNC(int, _xwin_set_mouse_sprite, (struct BITMAP *sprite, int x, int y));
+AL_FUNC(int, _xwin_show_mouse, (struct BITMAP *bmp, int x, int y));
+AL_FUNC(void, _xwin_hide_mouse, (void));
+AL_FUNC(void, _xwin_move_mouse, (int x, int y));
+#endif
+
 AL_FUNC(BITMAP*, _xdga_create_screen, (GFX_DRIVER *drv, int w, int h,
 				       int vw, int vh, int depth, int fullscreen));
 AL_FUNC(void, _xdga_destroy_screen, (void));


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/