1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      X-Windows mouse module.
12  *
13  *      By Michael Bukin.
14  *
15  *      See readme.txt for copyright information.
16  */
17 
18 
19 #include "allegro.h"
20 #include "allegro/internal/aintern.h"
21 #include "allegro/platform/aintunix.h"
22 #include "xwin.h"
23 #include <X11/cursorfont.h>
24 
25 
26 /* TRUE if the requested mouse range extends beyond the regular
27  * (0, 0, SCREEN_W-1, SCREEN_H-1) range. This is aimed at detecting
28  * whether the user mouse coordinates are relative to the 'screen'
29  * bitmap (semantics associated with scrolling) or to the video page
30  * currently being displayed (semantics associated with page flipping).
31  * We cannot differentiate them properly because both use the same
32  * scroll_screen() method.
33  */
34 int _xwin_mouse_extended_range = FALSE;
35 
36 static int mouse_minx = 0;
37 static int mouse_miny = 0;
38 static int mouse_maxx = 319;
39 static int mouse_maxy = 199;
40 
41 static int mymickey_x = 0;
42 static int mymickey_y = 0;
43 
44 static int mouse_mult = -1;       /* mouse acceleration multiplier */
45 static int mouse_div = -1;        /* mouse acceleration divisor */
46 static int mouse_threshold = -1;  /* mouse acceleration threshold */
47 
48 static int last_xspeed = -1;      /* latest set_mouse_speed() settings */
49 static int last_yspeed = -1;
50 
51 
52 
53 static int _xwin_mousedrv_init(void);
54 static void _xwin_mousedrv_exit(void);
55 static void _xwin_mousedrv_position(int x, int y);
56 static void _xwin_mousedrv_set_range(int x1, int y1, int x2, int y2);
57 static void _xwin_mousedrv_set_speed(int xspeed, int yspeed);
58 static void _xwin_mousedrv_get_mickeys(int *mickeyx, int *mickeyy);
59 static int _xwin_select_system_cursor(AL_CONST int cursor);
60 
61 static void _xwin_set_mouse_speed(int xspeed, int yspeed);
62 
63 static MOUSE_DRIVER mouse_xwin =
64 {
65    MOUSE_XWINDOWS,
66    empty_string,
67    empty_string,
68    "X-Windows mouse",
69    _xwin_mousedrv_init,
70    _xwin_mousedrv_exit,
71    NULL,
72    NULL,
73    _xwin_mousedrv_position,
74    _xwin_mousedrv_set_range,
75    _xwin_mousedrv_set_speed,
76    _xwin_mousedrv_get_mickeys,
77    NULL,
78    _xwin_enable_hardware_cursor,
79    _xwin_select_system_cursor
80 };
81 
82 
83 
84 /* list the available drivers */
85 _DRIVER_INFO _xwin_mouse_driver_list[] =
86 {
87    {  MOUSE_XWINDOWS, &mouse_xwin, TRUE  },
88    {  0,              NULL,        0     }
89 };
90 
91 
92 
93 /* _xwin_mousedrv_handler:
94  *  Mouse "interrupt" handler for mickey-mode driver.
95  */
_xwin_mousedrv_handler(int x,int y,int z,int w,int buttons)96 static void _xwin_mousedrv_handler(int x, int y, int z, int w, int buttons)
97 {
98    _mouse_b = buttons;
99 
100    mymickey_x += x;
101    mymickey_y += y;
102 
103    _mouse_x += x;
104    _mouse_y += y;
105    _mouse_z += z;
106    _mouse_w += w;
107 
108    if ((_mouse_x < mouse_minx) || (_mouse_x > mouse_maxx)
109        || (_mouse_y < mouse_miny) || (_mouse_y > mouse_maxy)) {
110       _mouse_x = CLAMP(mouse_minx, _mouse_x, mouse_maxx);
111       _mouse_y = CLAMP(mouse_miny, _mouse_y, mouse_maxy);
112    }
113 
114    _handle_mouse_input();
115 }
116 
117 
118 
119 /* _xwin_mousedrv_init:
120  *  Initializes the mickey-mode driver.
121  */
_xwin_mousedrv_init(void)122 static int _xwin_mousedrv_init(void)
123 {
124    int num_buttons;
125    unsigned char map[8];
126 
127    num_buttons = _xwin_get_pointer_mapping(map, sizeof(map));
128    num_buttons = CLAMP(2, num_buttons, 3);
129 
130    last_xspeed = -1;
131    last_yspeed = -1;
132 
133    XLOCK();
134 
135    _xwin_mouse_interrupt = _xwin_mousedrv_handler;
136 
137    XUNLOCK();
138 
139    return num_buttons;
140 }
141 
142 
143 
144 /* _xwin_mousedrv_exit:
145  *  Shuts down the mickey-mode driver.
146  */
_xwin_mousedrv_exit(void)147 static void _xwin_mousedrv_exit(void)
148 {
149    XLOCK();
150 
151    if (mouse_mult >= 0)
152       XChangePointerControl(_xwin.display, 1, 1, mouse_mult,
153          mouse_div, mouse_threshold);
154 
155    _xwin_mouse_interrupt = 0;
156 
157    XUNLOCK();
158 }
159 
160 
161 
162 /* _xwin_mousedrv_position:
163  *  Sets the position of the mickey-mode mouse.
164  */
_xwin_mousedrv_position(int x,int y)165 static void _xwin_mousedrv_position(int x, int y)
166 {
167    XLOCK();
168 
169    _mouse_x = x;
170    _mouse_y = y;
171 
172    mymickey_x = mymickey_y = 0;
173 
174    if (_xwin.hw_cursor_ok)
175       XWarpPointer(_xwin.display, _xwin.window, _xwin.window, 0, 0,
176                    _xwin.window_width, _xwin.window_height, x, y);
177    XUNLOCK();
178 
179    _xwin_set_warped_mouse_mode(FALSE);
180 }
181 
182 
183 
184 /* _xwin_mousedrv_set_range:
185  *  Sets the range of the mickey-mode mouse.
186  */
_xwin_mousedrv_set_range(int x1,int y1,int x2,int y2)187 static void _xwin_mousedrv_set_range(int x1, int y1, int x2, int y2)
188 {
189    mouse_minx = x1;
190    mouse_miny = y1;
191    mouse_maxx = x2;
192    mouse_maxy = y2;
193 
194    if ((mouse_maxx >= SCREEN_W) || (mouse_maxy >= SCREEN_H))
195       _xwin_mouse_extended_range = TRUE;
196    else
197       _xwin_mouse_extended_range = FALSE;
198 
199    XLOCK();
200 
201    _mouse_x = CLAMP(mouse_minx, _mouse_x, mouse_maxx);
202    _mouse_y = CLAMP(mouse_miny, _mouse_y, mouse_maxy);
203 
204    XUNLOCK();
205 }
206 
207 
208 
209 /* _xwin_mousedrv_set_speed:
210  *  Sets the speed of the mouse cursor.  We don't set the speed if the cursor
211  *  isn't in the window, but we remember the setting so it will be set the
212  *  next time the cursor enters the window.
213  */
_xwin_mousedrv_set_speed(int xspeed,int yspeed)214 static void _xwin_mousedrv_set_speed(int xspeed, int yspeed)
215 {
216    if (_mouse_on) {
217       _xwin_set_mouse_speed(xspeed, yspeed);
218    }
219 
220    last_xspeed = xspeed;
221    last_yspeed = yspeed;
222 }
223 
224 
225 
226 /* _xwin_mousedrv_get_mickeys:
227  *  Reads the mickey-mode count.
228  */
_xwin_mousedrv_get_mickeys(int * mickeyx,int * mickeyy)229 static void _xwin_mousedrv_get_mickeys(int *mickeyx, int *mickeyy)
230 {
231    int temp_x = mymickey_x;
232    int temp_y = mymickey_y;
233 
234    mymickey_x -= temp_x;
235    mymickey_y -= temp_y;
236 
237    *mickeyx = temp_x;
238    *mickeyy = temp_y;
239 
240    _xwin_set_warped_mouse_mode(TRUE);
241 }
242 
243 
244 
245 /* _xwin_select_system_cursor:
246  *  Select an OS native cursor
247  */
_xwin_select_system_cursor(AL_CONST int cursor)248 static int _xwin_select_system_cursor(AL_CONST int cursor)
249 {
250    switch(cursor) {
251       case MOUSE_CURSOR_ARROW:
252          _xwin.cursor_shape = XC_left_ptr;
253          break;
254       case MOUSE_CURSOR_BUSY:
255          _xwin.cursor_shape = XC_watch;
256          break;
257       case MOUSE_CURSOR_QUESTION:
258          _xwin.cursor_shape = XC_question_arrow;
259          break;
260       case MOUSE_CURSOR_EDIT:
261          _xwin.cursor_shape = XC_xterm;
262          break;
263       default:
264          return 0;
265    }
266 
267    XLOCK();
268 
269    if (_xwin.cursor != None) {
270       XUndefineCursor(_xwin.display, _xwin.window);
271       XFreeCursor(_xwin.display, _xwin.cursor);
272    }
273 
274    _xwin.cursor = XCreateFontCursor(_xwin.display, _xwin.cursor_shape);
275    XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
276 
277    XUNLOCK();
278 
279    return cursor;
280 }
281 
282 
283 
284 /* _xwin_set_mouse_speed:
285  *  The actual function that sets the speed of the mouse cursor.
286  *  Each step slows down or speeds the mouse up by 0.5x.
287  */
_xwin_set_mouse_speed(int xspeed,int yspeed)288 static void _xwin_set_mouse_speed(int xspeed, int yspeed)
289 {
290    int speed;
291    int hundredths;
292 
293    XLOCK();
294 
295    if (mouse_mult < 0)
296       XGetPointerControl(_xwin.display, &mouse_mult, &mouse_div,
297          &mouse_threshold);
298 
299    speed = MAX(1, (xspeed + yspeed) / 2);
300 
301    if (mouse_div == 0)
302       hundredths = mouse_mult * 100;
303    else
304       hundredths = (mouse_mult * 100 / mouse_div);
305    hundredths -= (speed - 2) * 50;
306    if (hundredths < 0)
307       hundredths = 0;
308 
309    XChangePointerControl(_xwin.display, 1, 1, hundredths,
310       100, mouse_threshold);
311 
312    XUNLOCK();
313 }
314 
315 
316 
317 /* _xwin_mouse_leave_notify:
318  *  Reset the mouse speed to its original value when the cursor leave the
319  *  Allegro window.
320  */
_xwin_mouse_leave_notify(void)321 void _xwin_mouse_leave_notify(void)
322 {
323    if (mouse_mult >= 0) {
324       XLOCK();
325       XChangePointerControl(_xwin.display, 1, 1, mouse_mult,
326          mouse_div, mouse_threshold);
327       XUNLOCK();
328    }
329 }
330 
331 
332 
333 /* _xwin_mouse_enter_notify:
334  *  Restore the mouse speed setting when the mouse cursor re-enters the
335  *  Allegro window.
336  */
_xwin_mouse_enter_notify(void)337 void _xwin_mouse_enter_notify(void)
338 {
339    if (last_xspeed >= 0) {
340       _xwin_set_mouse_speed(last_xspeed, last_yspeed);
341    }
342 }
343