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