/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * X-Windows mouse module. * * By Michael Bukin. * * See readme.txt for copyright information. */ #include "allegro.h" #include "allegro/internal/aintern.h" #include "allegro/platform/aintunix.h" #include "xwin.h" #include /* TRUE if the requested mouse range extends beyond the regular * (0, 0, SCREEN_W-1, SCREEN_H-1) range. This is aimed at detecting * whether the user mouse coordinates are relative to the 'screen' * bitmap (semantics associated with scrolling) or to the video page * currently being displayed (semantics associated with page flipping). * We cannot differentiate them properly because both use the same * scroll_screen() method. */ int _xwin_mouse_extended_range = FALSE; static int mouse_minx = 0; static int mouse_miny = 0; static int mouse_maxx = 319; static int mouse_maxy = 199; static int mymickey_x = 0; static int mymickey_y = 0; static int mouse_mult = -1; /* mouse acceleration multiplier */ static int mouse_div = -1; /* mouse acceleration divisor */ static int mouse_threshold = -1; /* mouse acceleration threshold */ static int last_xspeed = -1; /* latest set_mouse_speed() settings */ static int last_yspeed = -1; static int _xwin_mousedrv_init(void); static void _xwin_mousedrv_exit(void); static void _xwin_mousedrv_position(int x, int y); static void _xwin_mousedrv_set_range(int x1, int y1, int x2, int y2); static void _xwin_mousedrv_set_speed(int xspeed, int yspeed); static void _xwin_mousedrv_get_mickeys(int *mickeyx, int *mickeyy); static int _xwin_select_system_cursor(AL_CONST int cursor); static void _xwin_set_mouse_speed(int xspeed, int yspeed); static MOUSE_DRIVER mouse_xwin = { MOUSE_XWINDOWS, empty_string, empty_string, "X-Windows mouse", _xwin_mousedrv_init, _xwin_mousedrv_exit, NULL, NULL, _xwin_mousedrv_position, _xwin_mousedrv_set_range, _xwin_mousedrv_set_speed, _xwin_mousedrv_get_mickeys, NULL, _xwin_enable_hardware_cursor, _xwin_select_system_cursor }; /* list the available drivers */ _DRIVER_INFO _xwin_mouse_driver_list[] = { { MOUSE_XWINDOWS, &mouse_xwin, TRUE }, { 0, NULL, 0 } }; /* _xwin_mousedrv_handler: * Mouse "interrupt" handler for mickey-mode driver. */ static void _xwin_mousedrv_handler(int x, int y, int z, int w, int buttons) { _mouse_b = buttons; mymickey_x += x; mymickey_y += y; _mouse_x += x; _mouse_y += y; _mouse_z += z; _mouse_w += w; if ((_mouse_x < mouse_minx) || (_mouse_x > mouse_maxx) || (_mouse_y < mouse_miny) || (_mouse_y > mouse_maxy)) { _mouse_x = MID(mouse_minx, _mouse_x, mouse_maxx); _mouse_y = MID(mouse_miny, _mouse_y, mouse_maxy); } _handle_mouse_input(); } /* _xwin_mousedrv_init: * Initializes the mickey-mode driver. */ static int _xwin_mousedrv_init(void) { int num_buttons; unsigned char map[8]; num_buttons = _xwin_get_pointer_mapping(map, sizeof(map)); num_buttons = MID(2, num_buttons, 3); last_xspeed = -1; last_yspeed = -1; XLOCK(); _xwin_mouse_interrupt = _xwin_mousedrv_handler; XUNLOCK(); return num_buttons; } /* _xwin_mousedrv_exit: * Shuts down the mickey-mode driver. */ static void _xwin_mousedrv_exit(void) { XLOCK(); if (mouse_mult >= 0) XChangePointerControl(_xwin.display, 1, 1, mouse_mult, mouse_div, mouse_threshold); _xwin_mouse_interrupt = 0; XUNLOCK(); } /* _xwin_mousedrv_position: * Sets the position of the mickey-mode mouse. */ static void _xwin_mousedrv_position(int x, int y) { XLOCK(); _mouse_x = x; _mouse_y = y; mymickey_x = mymickey_y = 0; if (_xwin.hw_cursor_ok) XWarpPointer(_xwin.display, _xwin.window, _xwin.window, 0, 0, _xwin.window_width, _xwin.window_height, x, y); XUNLOCK(); _xwin_set_warped_mouse_mode(FALSE); } /* _xwin_mousedrv_set_range: * Sets the range of the mickey-mode mouse. */ static void _xwin_mousedrv_set_range(int x1, int y1, int x2, int y2) { mouse_minx = x1; mouse_miny = y1; mouse_maxx = x2; mouse_maxy = y2; if ((mouse_maxx >= SCREEN_W) || (mouse_maxy >= SCREEN_H)) _xwin_mouse_extended_range = TRUE; else _xwin_mouse_extended_range = FALSE; XLOCK(); _mouse_x = MID(mouse_minx, _mouse_x, mouse_maxx); _mouse_y = MID(mouse_miny, _mouse_y, mouse_maxy); XUNLOCK(); } /* _xwin_mousedrv_set_speed: * Sets the speed of the mouse cursor. We don't set the speed if the cursor * isn't in the window, but we remember the setting so it will be set the * next time the cursor enters the window. */ static void _xwin_mousedrv_set_speed(int xspeed, int yspeed) { if (_mouse_on) { _xwin_set_mouse_speed(xspeed, yspeed); } last_xspeed = xspeed; last_yspeed = yspeed; } /* _xwin_mousedrv_get_mickeys: * Reads the mickey-mode count. */ static void _xwin_mousedrv_get_mickeys(int *mickeyx, int *mickeyy) { int temp_x = mymickey_x; int temp_y = mymickey_y; mymickey_x -= temp_x; mymickey_y -= temp_y; *mickeyx = temp_x; *mickeyy = temp_y; _xwin_set_warped_mouse_mode(TRUE); } /* _xwin_select_system_cursor: * Select an OS native cursor */ static int _xwin_select_system_cursor(AL_CONST int cursor) { switch(cursor) { case MOUSE_CURSOR_ARROW: _xwin.cursor_shape = XC_left_ptr; break; case MOUSE_CURSOR_BUSY: _xwin.cursor_shape = XC_watch; break; case MOUSE_CURSOR_QUESTION: _xwin.cursor_shape = XC_question_arrow; break; case MOUSE_CURSOR_EDIT: _xwin.cursor_shape = XC_xterm; break; default: return 0; } XLOCK(); if (_xwin.cursor != None) { XUndefineCursor(_xwin.display, _xwin.window); XFreeCursor(_xwin.display, _xwin.cursor); } _xwin.cursor = XCreateFontCursor(_xwin.display, _xwin.cursor_shape); XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor); XUNLOCK(); return cursor; } /* _xwin_set_mouse_speed: * The actual function that sets the speed of the mouse cursor. * Each step slows down or speeds the mouse up by 0.5x. */ static void _xwin_set_mouse_speed(int xspeed, int yspeed) { int speed; int hundredths; XLOCK(); if (mouse_mult < 0) XGetPointerControl(_xwin.display, &mouse_mult, &mouse_div, &mouse_threshold); speed = MAX(1, (xspeed + yspeed) / 2); if (mouse_div == 0) hundredths = mouse_mult * 100; else hundredths = (mouse_mult * 100 / mouse_div); hundredths -= (speed - 2) * 50; if (hundredths < 0) hundredths = 0; XChangePointerControl(_xwin.display, 1, 1, hundredths, 100, mouse_threshold); XUNLOCK(); } /* _xwin_mouse_leave_notify: * Reset the mouse speed to its original value when the cursor leave the * Allegro window. */ void _xwin_mouse_leave_notify(void) { if (mouse_mult >= 0) { XLOCK(); XChangePointerControl(_xwin.display, 1, 1, mouse_mult, mouse_div, mouse_threshold); XUNLOCK(); } } /* _xwin_mouse_enter_notify: * Restore the mouse speed setting when the mouse cursor re-enters the * Allegro window. */ void _xwin_mouse_enter_notify(void) { if (last_xspeed >= 0) { _xwin_set_mouse_speed(last_xspeed, last_yspeed); } }