Re: [AD] Using system mouse cursor

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


On Friday 27 August 2004 01:12, Peter Wang wrote:
> In the first screen of exmouse: Move your mouse to the edge of the 
> window, such that the mouse_x,y values stop changing, e.g. at 319,199.  
> If you keep pushing at the edge of the screen, the mouse mickey values 
> are supposed to keep changing and the mouse cursor remains trapped 
> inside the window.

Ah, right. I see what you mean.
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.
I can make it so that calling set_mouse_position() has the implicit effect 
of enableing the hardware cursor and get_mouse_mickeys() has the effect of 
disableing it the next time show_mouse_sprite() is called.
I'll leave this for the moment to think about a bit more. The attached 
patch should fix the transparency problems Peter was having (and add some 
optimizations/code cleanup). 

I am tempted to agree with Chris that the user should be responsible for 
positioning the mouse in the centre of the screen to get a reliable mickey 
count, or at least document that the mickeycount can be unreliable across 
platforms. The main problem with this would be that it breaks current 
behavior.

Under fullscreen X, the mouse stops generating movement events when it hits 
the edge of the screen. While I could argue that it's ok for the mouse to 
stop generating mickeys when it leaves the client window, for a fullscreen 
application I don't like this.

I noticed that the Windows GDI driver also has a hardware cursor (or claims 
to have one). I'll have a look at what it does there to see if there's a 
similar issue.

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 09:29:05 -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 09:29:06 -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,6 +70,10 @@
    Visual *visual;
    Colormap colormap;
    XImage *ximage;
+#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
+   XcursorImage *xcursor_image;
+   XcursorBool support_argb_cursor;
+#endif
    Cursor cursor;
    int cursor_shape;
 
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 09:29:07 -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 09:29:10 -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,6 +74,10 @@
    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 */
 
@@ -351,6 +359,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 +404,6 @@
    XGCValues gcvalues;
    XSetWindowAttributes setattr;
    XWindowAttributes getattr;
-   Pixmap pixmap;
 
    if (_xwin.display == 0)
       return -1;
@@ -412,30 +455,13 @@
    _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);
+#endif
+   
    return 0;
 }
 
@@ -1582,6 +1608,142 @@
 
 
 
+#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;
+   }
+
+   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:
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 09:29:10 -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/