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));