1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * Mouse input routines.
12 *
13 * By Shawn Hargreaves.
14 *
15 * Mark Wodrich added double-buffered drawing of the mouse pointer and
16 * the set_mouse_sprite_focus() function.
17 *
18 * See readme.txt for copyright information.
19 */
20
21
22 #include "allegro.h"
23 #include "allegro/internal/aintern.h"
24
25
26
27 /* dummy driver for systems without a mouse */
nomouse_init(void)28 static int nomouse_init(void) { return 0; }
nomouse_exit(void)29 static void nomouse_exit(void) { }
30
31 MOUSE_DRIVER mousedrv_none =
32 {
33 MOUSEDRV_NONE,
34 empty_string,
35 empty_string,
36 "No mouse",
37 nomouse_init,
38 nomouse_exit,
39 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
40 };
41
42
43 MOUSE_DRIVER *mouse_driver = NULL; /* the active driver */
44 int _mouse_type = MOUSEDRV_AUTODETECT; /* driver ID */
45 int _mouse_installed = FALSE;
46
47 volatile int mouse_x = 0; /* user-visible position */
48 volatile int mouse_y = 0;
49 volatile int mouse_z = 0;
50 volatile int mouse_w = 0;
51 volatile int mouse_b = 0;
52 volatile int mouse_pos = 0;
53
54 int _mouse_x = 0; /* internal position */
55 int _mouse_y = 0;
56 int _mouse_z = 0;
57 int _mouse_w = 0;
58 int _mouse_b = 0;
59 int _mouse_on = TRUE;
60
61 static int mon = TRUE;
62
63 static int emulate_three = FALSE;
64
65 volatile int freeze_mouse_flag = FALSE;
66
67 void (*mouse_callback)(int flags) = NULL;
68
69 int mouse_x_focus = 1; /* focus point in mouse sprite */
70 int mouse_y_focus = 1;
71
72
73 #define MOUSE_OFFSCREEN -4096 /* somewhere to put unwanted cursors */
74
75
76 /* default mouse cursor sizes */
77 #define DEFAULT_SPRITE_W 16
78 #define DEFAULT_SPRITE_H 16
79
80 /* Default cursor shapes */
81 /* TODO: add other shapes! */
82 static char mouse_arrow_data[DEFAULT_SPRITE_H * DEFAULT_SPRITE_W] =
83 {
84 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
85 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
86 2, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
87 2, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
88 2, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89 2, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
90 2, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0,
91 2, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0,
92 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0,
93 2, 1, 1, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0,
94 2, 1, 1, 2, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
95 2, 1, 2, 0, 2, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0,
96 0, 2, 0, 0, 2, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0,
97 0, 0, 0, 0, 0, 2, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0,
98 0, 0, 0, 0, 0, 2, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0,
99 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0
100 };
101
102 static char mouse_busy_data[DEFAULT_SPRITE_H * DEFAULT_SPRITE_W] =
103 {
104 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0,
105 0, 0, 0, 0, 0, 2, 2, 1, 1, 2, 2, 0, 0, 0, 0, 0,
106 0, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0,
107 0, 0, 0, 2, 1, 1, 1, 0, 0, 1, 1, 1, 2, 0, 0, 0,
108 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0, 0,
109 0, 2, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 2, 0,
110 0, 2, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 2, 0,
111 2, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 2,
112 2, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 2,
113 0, 2, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 2, 0,
114 0, 2, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 2, 0,
115 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0, 0,
116 0, 0, 0, 2, 1, 1, 1, 0, 0, 1, 1, 1, 2, 0, 0, 0,
117 0, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0,
118 0, 0, 0, 0, 0, 2, 2, 1, 1, 2, 2, 0, 0, 0, 0, 0,
119 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0
120 };
121
122
123 BITMAP *_mouse_pointer = NULL; /* default mouse pointer */
124
125 BITMAP *mouse_sprite = NULL; /* current mouse pointer */
126
127 BITMAP *_mouse_screen = NULL; /* where to draw the pointer */
128
129 static BITMAP *default_cursors[AL_NUM_MOUSE_CURSORS];
130 static BITMAP *cursors[AL_NUM_MOUSE_CURSORS];
131
132 static int allow_system_cursor; /* Allow native OS cursor? */
133 static int use_system_cursor = FALSE; /* Use native OS cursor? */
134 static int got_hw_cursor = FALSE; /* hardware pointer available? */
135 static int hw_cursor_dirty = FALSE; /* need to set a new pointer? */
136 static int current_cursor = MOUSE_CURSOR_ALLEGRO;
137
138 static int mx, my; /* previous mouse pointer position */
139 static BITMAP *ms = NULL; /* previous screen data */
140 static BITMAP *mtemp = NULL; /* double-buffer drawing area */
141
142 #define SCARED_SIZE 16 /* for unscare_mouse() */
143
144 static BITMAP *scared_screen[SCARED_SIZE];
145 static int scared_freeze[SCARED_SIZE];
146 static int scared_size = 0;
147
148 static int mouse_polled = FALSE; /* are we in polling mode? */
149
150 static int mouse_semaphore = FALSE; /* reentrant interrupt? */
151
152
153
154 /* draw_mouse_doublebuffer:
155 * Eliminates mouse-cursor flicker by using an off-screen buffer for
156 * updating the cursor, and blitting only the final screen image.
157 * newx and newy contain the new cursor position, and mx and my are
158 * assumed to contain previous cursor pos. This routine is called if
159 * mouse cursor is to be erased and redrawn, and the two position overlap.
160 */
draw_mouse_doublebuffer(int newx,int newy)161 static void draw_mouse_doublebuffer(int newx, int newy)
162 {
163 int x1, y1, w, h;
164
165 /* grab bit of screen containing where we are and where we'll be */
166 x1 = MIN(mx, newx) - mouse_x_focus;
167 y1 = MIN(my, newy) - mouse_y_focus;
168
169 /* get width of area */
170 w = MAX(mx, newx) - MIN(mx, newx) + mouse_sprite->w+1;
171 h = MAX(my, newy) - MIN(my, newy) + mouse_sprite->h+1;
172
173 /* make new co-ords relative to 'mtemp' bitmap co-ords */
174 newx -= mouse_x_focus+x1;
175 newy -= mouse_y_focus+y1;
176
177 /* save screen image in 'mtemp' */
178 blit(_mouse_screen, mtemp, x1, y1, 0, 0, w, h);
179
180 /* blit saved image in 'ms' to corect place in this buffer */
181 blit(ms, mtemp, 0, 0, mx-mouse_x_focus-x1, my-mouse_y_focus-y1,
182 mouse_sprite->w, mouse_sprite->h);
183
184 /* draw mouse at correct place in 'mtemp' */
185 blit(mtemp, ms, newx, newy, 0, 0, mouse_sprite->w, mouse_sprite->h);
186 draw_sprite(mtemp, mouse_sprite, newx, newy);
187
188 /* blit 'mtemp' to screen */
189 blit(mtemp, _mouse_screen, 0, 0, x1, y1, w, h);
190 }
191
192 END_OF_STATIC_FUNCTION(draw_mouse_doublebuffer);
193
194
195
196 /* draw_mouse:
197 * Mouse pointer drawing routine. If remove is set, deletes the old mouse
198 * pointer. If add is set, draws a new one.
199 */
draw_mouse(int remove,int add)200 static void draw_mouse(int remove, int add)
201 {
202 int normal_draw = (remove ^ add);
203
204 int newmx = _mouse_x;
205 int newmy = _mouse_y;
206
207 int cf = _mouse_screen->clip;
208 int cl = _mouse_screen->cl;
209 int cr = _mouse_screen->cr;
210 int ct = _mouse_screen->ct;
211 int cb = _mouse_screen->cb;
212
213 _mouse_screen->clip = TRUE;
214 _mouse_screen->cl = _mouse_screen->ct = 0;
215 _mouse_screen->cr = _mouse_screen->w;
216 _mouse_screen->cb = _mouse_screen->h;
217
218 if (!_mouse_on) {
219 newmx = MOUSE_OFFSCREEN;
220 newmy = MOUSE_OFFSCREEN;
221 mon = FALSE;
222 }
223 else
224 mon = TRUE;
225
226 if (!normal_draw) {
227 if ((newmx <= mx-mouse_sprite->w) || (newmx >= mx+mouse_sprite->w) ||
228 (newmy <= my-mouse_sprite->h) || (newmy >= my+mouse_sprite->h))
229 normal_draw = 1;
230 }
231
232 if (normal_draw) {
233 if (remove)
234 blit(ms, _mouse_screen, 0, 0, mx-mouse_x_focus, my-mouse_y_focus, mouse_sprite->w, mouse_sprite->h);
235
236 if (add) {
237 blit(_mouse_screen, ms, newmx-mouse_x_focus, newmy-mouse_y_focus, 0, 0, mouse_sprite->w, mouse_sprite->h);
238 draw_sprite(_mouse_screen, cursors[current_cursor], newmx-mouse_x_focus, newmy-mouse_y_focus);
239 }
240 }
241 else
242 draw_mouse_doublebuffer(newmx, newmy);
243
244 mx = newmx;
245 my = newmy;
246
247 _mouse_screen->clip = cf;
248 _mouse_screen->cl = cl;
249 _mouse_screen->cr = cr;
250 _mouse_screen->ct = ct;
251 _mouse_screen->cb = cb;
252 }
253
254 END_OF_STATIC_FUNCTION(draw_mouse);
255
256
257
258 /* update_mouse:
259 * Worker function to update the mouse position variables with new values.
260 */
update_mouse(void)261 static void update_mouse(void)
262 {
263 int x, y, z, w, b, flags = 0;
264
265 if (freeze_mouse_flag) {
266 x = mx;
267 y = my;
268 }
269 else {
270 x = _mouse_x;
271 y = _mouse_y;
272 }
273
274 z = _mouse_z;
275 w = _mouse_w;
276 b = _mouse_b;
277
278 if (emulate_three) {
279 if ((b & 3) == 3)
280 b = 4;
281 }
282
283 if ((mouse_x != x) ||
284 (mouse_y != y) ||
285 (mouse_z != z) ||
286 (mouse_w != w) ||
287 (mouse_b != b)) {
288
289 if (mouse_callback) {
290 if ((mouse_x != x) || (mouse_y != y))
291 flags |= MOUSE_FLAG_MOVE;
292
293 if (mouse_z != z)
294 flags |= MOUSE_FLAG_MOVE_Z;
295
296 if (mouse_w != w)
297 flags |= MOUSE_FLAG_MOVE_W;
298
299 if ((b & 1) && !(mouse_b & 1))
300 flags |= MOUSE_FLAG_LEFT_DOWN;
301 else if (!(b & 1) && (mouse_b & 1))
302 flags |= MOUSE_FLAG_LEFT_UP;
303
304 if ((b & 2) && !(mouse_b & 2))
305 flags |= MOUSE_FLAG_RIGHT_DOWN;
306 else if (!(b & 2) && (mouse_b & 2))
307 flags |= MOUSE_FLAG_RIGHT_UP;
308
309 if ((b & 4) && !(mouse_b & 4))
310 flags |= MOUSE_FLAG_MIDDLE_DOWN;
311 else if (!(b & 4) && (mouse_b & 4))
312 flags |= MOUSE_FLAG_MIDDLE_UP;
313
314 mouse_x = x;
315 mouse_y = y;
316 mouse_z = z;
317 mouse_w = w;
318 mouse_b = b;
319 mouse_pos = ((x & 0xFFFF) << 16) | (y & 0xFFFF);
320
321 mouse_callback(flags);
322 }
323 else {
324 mouse_x = x;
325 mouse_y = y;
326 mouse_z = z;
327 mouse_w = w;
328 mouse_b = b;
329 mouse_pos = ((x & 0xFFFF) << 16) | (y & 0xFFFF);
330 }
331 }
332 }
333
334 END_OF_STATIC_FUNCTION(update_mouse);
335
336
337
338 /* mouse_move:
339 * Timer interrupt handler for redrawing the mouse pointer.
340 */
mouse_move(void)341 static void mouse_move(void)
342 {
343 if (mouse_semaphore)
344 return;
345
346 mouse_semaphore = TRUE;
347
348 /* periodic poll */
349 if (mouse_driver->timer_poll) {
350 mouse_driver->timer_poll();
351 if (!mouse_polled)
352 update_mouse();
353 }
354
355 /* redraw pointer */
356 if ((!freeze_mouse_flag) && (_mouse_screen) && ((mx != _mouse_x) || (my != _mouse_y) || (mon != _mouse_on))) {
357 acquire_bitmap(_mouse_screen);
358
359 if (gfx_capabilities & GFX_HW_CURSOR) {
360 if (_mouse_on) {
361 gfx_driver->move_mouse(mx=_mouse_x, my=_mouse_y);
362 mon = TRUE;
363 }
364 else {
365 gfx_driver->move_mouse(mx=MOUSE_OFFSCREEN, my=MOUSE_OFFSCREEN);
366 mon = FALSE;
367 }
368 }
369 else {
370 #ifdef ALLEGRO_DOS
371 /* bodge to avoid using non legacy 386 asm code inside a timer handler */
372 int old_capabilities = cpu_capabilities;
373 cpu_capabilities = 0;
374 #endif
375 draw_mouse(TRUE, TRUE);
376 #ifdef ALLEGRO_DOS
377 cpu_capabilities = old_capabilities;
378 #endif
379 }
380
381 release_bitmap(_mouse_screen);
382 }
383
384 mouse_semaphore = FALSE;
385 }
386
387 END_OF_STATIC_FUNCTION(mouse_move);
388
389
390
391 /* _handle_mouse_input:
392 * Callback for an asynchronous driver to tell us when it has changed the
393 * position.
394 */
_handle_mouse_input(void)395 void _handle_mouse_input(void)
396 {
397 if (!mouse_polled)
398 update_mouse();
399 }
400
401 END_OF_FUNCTION(_handle_mouse_input);
402
403
404
405 /* create_mouse_pointer:
406 * Creates the default arrow mouse sprite using the current color depth
407 * and palette.
408 */
create_mouse_pointer(char * data)409 static BITMAP *create_mouse_pointer(char *data)
410 {
411 BITMAP *bmp;
412 int x, y;
413 int col;
414
415 bmp = create_bitmap(DEFAULT_SPRITE_W, DEFAULT_SPRITE_H);
416
417 for (y=0; y<DEFAULT_SPRITE_H; y++) {
418 for (x=0; x<DEFAULT_SPRITE_W; x++) {
419 switch (data[x+y*DEFAULT_SPRITE_W]) {
420 case 1: col = makecol(255, 255, 255); break;
421 case 2: col = makecol(0, 0, 0); break;
422 default: col = bmp->vtable->mask_color; break;
423 }
424 putpixel(bmp, x, y, col);
425 }
426 }
427
428 return bmp;
429 }
430
431
432
433 /* set_mouse_sprite:
434 * Sets the sprite to be used for the mouse pointer. If the sprite is
435 * NULL, restores the default arrow.
436 */
set_mouse_sprite(struct BITMAP * sprite)437 void set_mouse_sprite(struct BITMAP *sprite)
438 {
439 BITMAP *old_mouse_screen = _mouse_screen;
440 int am_using_sys_cursor = use_system_cursor;
441
442 if (!mouse_driver)
443 return;
444
445 if (_mouse_screen && !am_using_sys_cursor)
446 show_mouse(NULL);
447
448 if (sprite)
449 mouse_sprite = sprite;
450 else {
451 if (_mouse_pointer)
452 destroy_bitmap(_mouse_pointer);
453 _mouse_pointer = create_mouse_pointer(mouse_arrow_data);
454 mouse_sprite = _mouse_pointer;
455 }
456
457 cursors[MOUSE_CURSOR_ALLEGRO] = mouse_sprite;
458
459 lock_bitmap((struct BITMAP*)mouse_sprite);
460
461 /* make sure the ms bitmap is big enough */
462 if ((!ms) || (ms->w < mouse_sprite->w) || (ms->h < mouse_sprite->h) ||
463 (bitmap_color_depth(mouse_sprite) != bitmap_color_depth(ms))) {
464 if (ms) {
465 destroy_bitmap(ms);
466 destroy_bitmap(mtemp);
467 }
468
469 ms = create_bitmap(mouse_sprite->w, mouse_sprite->h);
470 lock_bitmap(ms);
471
472 mtemp = create_bitmap(mouse_sprite->w*2, mouse_sprite->h*2);
473 lock_bitmap(mtemp);
474 }
475
476 mouse_x_focus = 1;
477 mouse_y_focus = 1;
478
479 if (!am_using_sys_cursor)
480 hw_cursor_dirty = TRUE;
481
482 if (old_mouse_screen && !am_using_sys_cursor)
483 show_mouse(old_mouse_screen);
484 }
485
486
487
488 /* select_mouse_cursor:
489 * Selects the shape of the mouse cursor.
490 */
select_mouse_cursor(int cursor)491 void select_mouse_cursor(int cursor)
492 {
493 ASSERT(cursor >= 0);
494 ASSERT(cursor < AL_NUM_MOUSE_CURSORS);
495
496 current_cursor = cursor;
497 }
498
499
500
501 /* set_mouse_cursor_bitmap:
502 * Changes the default Allegro cursor for a mouse cursor
503 */
set_mouse_cursor_bitmap(int cursor,struct BITMAP * bmp)504 void set_mouse_cursor_bitmap(int cursor, struct BITMAP *bmp)
505 {
506 ASSERT(cursor >= 0);
507 ASSERT(cursor != MOUSE_CURSOR_NONE);
508 ASSERT(cursor < AL_NUM_MOUSE_CURSORS);
509
510 cursors[cursor] = bmp?bmp:default_cursors[cursor];
511 }
512
513
514
515 /* set_mouse_sprite_focus:
516 * Sets co-ordinate (x, y) in the sprite to be the mouse location.
517 * Call after set_mouse_sprite(). Doesn't redraw the sprite.
518 */
set_mouse_sprite_focus(int x,int y)519 void set_mouse_sprite_focus(int x, int y)
520 {
521 if (!mouse_driver)
522 return;
523
524 mouse_x_focus = x;
525 mouse_y_focus = y;
526
527 hw_cursor_dirty = TRUE;
528 }
529
530
531
532 /* show_os_cursor:
533 * Tries to display the OS cursor. Returns 0 if a cursor is displayed after the
534 * function returns, else -1. This is similar to calling show_mouse(screen)
535 * after calling enable_hardware_cursor and checking gfx_capabilities for
536 * GFX_HW_CURSOR, but is easier to use in cases where you don't need Allegro's
537 * software cursor even if no os cursor is available.
538 */
show_os_cursor(int cursor)539 int show_os_cursor(int cursor)
540 {
541 int r = -1;
542 if (!mouse_driver)
543 return r;
544
545 remove_int(mouse_move);
546
547 gfx_capabilities &= ~(GFX_HW_CURSOR|GFX_SYSTEM_CURSOR);
548 if (cursor != MOUSE_CURSOR_NONE) {
549
550 if (mouse_driver->enable_hardware_cursor) {
551 mouse_driver->enable_hardware_cursor(TRUE);
552 }
553
554 /* default system cursor? */
555 if (cursor != MOUSE_CURSOR_ALLEGRO) {
556 if (mouse_driver->select_system_cursor) {
557 if (mouse_driver->select_system_cursor(cursor) != 0) {
558 gfx_capabilities |= (GFX_HW_CURSOR|GFX_SYSTEM_CURSOR);
559 r = 0;
560 goto done;
561 }
562 }
563 goto done;
564 }
565 else {
566 /* set custom hardware cursor */
567 if (gfx_driver) {
568 if (gfx_driver->set_mouse_sprite) {
569 if (gfx_driver->set_mouse_sprite(mouse_sprite, mouse_x_focus, mouse_y_focus))
570 goto done;
571 }
572 if (gfx_driver->show_mouse) {
573 if (gfx_driver->show_mouse(screen, mouse_x, mouse_y))
574 goto done;
575 }
576 gfx_capabilities |= GFX_HW_CURSOR;
577 r = 0;
578 goto done;
579 }
580 }
581 }
582 else {
583 if (gfx_driver && gfx_driver->hide_mouse)
584 gfx_driver->hide_mouse();
585 }
586
587 done:
588 if (mouse_driver->timer_poll)
589 install_int(mouse_move, 10);
590 return r;
591 }
592
593
594
595 /* show_mouse:
596 * Tells Allegro to display a mouse pointer. This only works when the timer
597 * module is active. The mouse pointer will be drawn onto the bitmap bmp,
598 * which should normally be the hardware screen. To turn off the mouse
599 * pointer, which you must do before you draw anything onto the screen, call
600 * show_mouse(NULL). If you forget to turn off the mouse pointer when
601 * drawing something, the SVGA bank switching code will become confused and
602 * will produce garbage all over the screen.
603 */
show_mouse(BITMAP * bmp)604 void show_mouse(BITMAP *bmp)
605 {
606 if (!mouse_driver)
607 return;
608
609 remove_int(mouse_move);
610
611 /* Remove the mouse cursor */
612 if (_mouse_screen) {
613 acquire_bitmap(_mouse_screen);
614
615 if (gfx_capabilities & GFX_HW_CURSOR) {
616 gfx_driver->hide_mouse();
617 gfx_capabilities &= ~(GFX_HW_CURSOR|GFX_SYSTEM_CURSOR);
618 hw_cursor_dirty = TRUE;
619 }
620 else
621 draw_mouse(TRUE, FALSE);
622
623 release_bitmap(_mouse_screen);
624 }
625
626 _mouse_screen = bmp;
627
628 if (bmp && (current_cursor != MOUSE_CURSOR_NONE)) {
629 acquire_bitmap(_mouse_screen);
630
631 /* Default system cursor? */
632 if ((current_cursor != MOUSE_CURSOR_ALLEGRO) && allow_system_cursor) {
633 if (mouse_driver && mouse_driver->select_system_cursor) {
634 use_system_cursor = mouse_driver->select_system_cursor(current_cursor);
635 if (use_system_cursor) {
636 gfx_capabilities |= GFX_HW_CURSOR|GFX_SYSTEM_CURSOR;
637 hw_cursor_dirty = FALSE;
638 got_hw_cursor = TRUE;
639 }
640 }
641 }
642 else {
643 use_system_cursor = FALSE;
644 }
645
646 /* Custom hardware cursor? */
647 if (hw_cursor_dirty) {
648 got_hw_cursor = FALSE;
649
650 if ((gfx_driver) && (gfx_driver->set_mouse_sprite) && (!_dispsw_status))
651 if (gfx_driver->set_mouse_sprite(mouse_sprite, mouse_x_focus, mouse_y_focus) == 0)
652 got_hw_cursor = TRUE;
653
654 hw_cursor_dirty = FALSE;
655 }
656
657 /* Try to display hardware (custom or system) cursor */
658 if ((got_hw_cursor) && (is_same_bitmap(bmp, screen)))
659 if (gfx_driver->show_mouse(bmp, mx=mouse_x, my=mouse_y) == 0)
660 gfx_capabilities |= GFX_HW_CURSOR;
661
662 /* Draw cursor manually if we can't do that */
663 if (!(gfx_capabilities & GFX_HW_CURSOR)) {
664 draw_mouse(FALSE, TRUE);
665 use_system_cursor = FALSE;
666 }
667
668 release_bitmap(_mouse_screen);
669
670 install_int(mouse_move, 10);
671 }
672 else {
673 if (mouse_driver->timer_poll)
674 install_int(mouse_move, 10);
675 }
676 }
677
678
679
680 /* scare_mouse:
681 * Removes the mouse pointer prior to a drawing operation, if that is
682 * required (ie. noop if the mouse is on a memory bitmap, or a hardware
683 * cursor is in use). This operation can later be reversed by calling
684 * unscare_mouse().
685 */
scare_mouse(void)686 void scare_mouse(void)
687 {
688 if (!mouse_driver)
689 return;
690
691 if ((is_same_bitmap(screen, _mouse_screen)) && (!(gfx_capabilities & GFX_HW_CURSOR))) {
692 if (scared_size < SCARED_SIZE) {
693 scared_screen[scared_size] = _mouse_screen;
694 scared_freeze[scared_size] = FALSE;
695 }
696 show_mouse(NULL);
697 }
698 else {
699 if (scared_size < SCARED_SIZE) {
700 scared_screen[scared_size] = NULL;
701 scared_freeze[scared_size] = FALSE;
702 }
703 }
704
705 scared_size++;
706 }
707
708
709
710 /* scare_mouse_area:
711 * Removes the mouse pointer prior to a drawing operation, if that is
712 * required (ie. noop if the mouse is on a memory bitmap, or a hardware
713 * cursor is in use, or the mouse lies outside of the specified bounds
714 * (in this last case, the mouse is frozen)). This operation can later
715 * be reversed by calling unscare_mouse().
716 */
scare_mouse_area(int x,int y,int w,int h)717 void scare_mouse_area(int x, int y, int w, int h)
718 {
719 int was_frozen;
720
721 if (!mouse_driver)
722 return;
723
724 if ((is_same_bitmap(screen, _mouse_screen)) && (!(gfx_capabilities & GFX_HW_CURSOR))) {
725 was_frozen = freeze_mouse_flag;
726 freeze_mouse_flag = TRUE;
727
728 if ((mx - mouse_x_focus < x + w) &&
729 (my - mouse_y_focus < y + h) &&
730 (mx - mouse_x_focus + mouse_sprite->w >= x) &&
731 (my - mouse_y_focus + mouse_sprite->h >= y)) {
732
733 if (scared_size < SCARED_SIZE) {
734 scared_screen[scared_size] = _mouse_screen;
735 scared_freeze[scared_size] = FALSE;
736 }
737
738 freeze_mouse_flag = was_frozen;
739 show_mouse(NULL);
740 }
741 else {
742 if (scared_size < SCARED_SIZE) {
743 scared_screen[scared_size] = NULL;
744
745 if (was_frozen) {
746 scared_freeze[scared_size] = FALSE;
747 freeze_mouse_flag = was_frozen;
748 }
749 else
750 scared_freeze[scared_size] = TRUE;
751 }
752 }
753 }
754 else {
755 if (scared_size < SCARED_SIZE) {
756 scared_screen[scared_size] = NULL;
757 scared_freeze[scared_size] = FALSE;
758 }
759 }
760
761 scared_size++;
762 }
763
764
765
766 /* unscare_mouse:
767 * Restores the original mouse state, after a call to scare_mouse() or
768 * scare_mouse_area.
769 */
unscare_mouse(void)770 void unscare_mouse(void)
771 {
772 if (!mouse_driver)
773 return;
774
775 if (scared_size > 0)
776 scared_size--;
777
778 if (scared_size < SCARED_SIZE) {
779 if (scared_screen[scared_size])
780 show_mouse(scared_screen[scared_size]);
781
782 if (scared_freeze[scared_size])
783 freeze_mouse_flag = FALSE;
784
785 scared_screen[scared_size] = NULL;
786 scared_freeze[scared_size] = FALSE;
787 }
788 }
789
790
791
792 /* position_mouse:
793 * Moves the mouse to screen position x, y. This is safe to call even
794 * when a mouse pointer is being displayed.
795 */
position_mouse(int x,int y)796 void position_mouse(int x, int y)
797 {
798 BITMAP *old_mouse_screen = _mouse_screen;
799
800 if (!mouse_driver)
801 return;
802
803 if (_mouse_screen)
804 show_mouse(NULL);
805
806 if (mouse_driver->position) {
807 mouse_driver->position(x, y);
808 }
809 else {
810 _mouse_x = x;
811 _mouse_y = y;
812 }
813
814 update_mouse();
815
816 if (old_mouse_screen)
817 show_mouse(old_mouse_screen);
818 }
819
820
821
822 /* position_mouse_z:
823 * Sets the mouse third axis to position z.
824 */
position_mouse_z(int z)825 void position_mouse_z(int z)
826 {
827 if (!mouse_driver)
828 return;
829
830 _mouse_z = z;
831 update_mouse();
832 }
833
834
835
836 /* position_mouse_w:
837 * Sets the mouse fourth axis to position w.
838 */
position_mouse_w(int w)839 void position_mouse_w(int w)
840 {
841 if (!mouse_driver)
842 return;
843
844 _mouse_w = w;
845 update_mouse();
846 }
847
848
849
850 /* set_mouse_range:
851 * Sets the screen area within which the mouse can move. Pass the top left
852 * corner and the bottom right corner (inclusive). If you don't call this
853 * function the range defaults to (0, 0, SCREEN_W-1, SCREEN_H-1).
854 */
set_mouse_range(int x1,int y1,int x2,int y2)855 void set_mouse_range(int x1, int y1, int x2, int y2)
856 {
857 BITMAP *old_mouse_screen = _mouse_screen;
858 ASSERT(x1 >= 0);
859 ASSERT(y1 >= 0);
860 ASSERT(x2 >= x1);
861 ASSERT(y2 >= y2);
862
863 if (!mouse_driver)
864 return;
865
866 if (_mouse_screen)
867 show_mouse(NULL);
868
869 if (mouse_driver->set_range)
870 mouse_driver->set_range(x1, y1, x2, y2);
871
872 update_mouse();
873
874 if (old_mouse_screen)
875 show_mouse(old_mouse_screen);
876 }
877
878
879
880 /* set_mouse_speed:
881 * Sets the mouse speed. Larger values of xspeed and yspeed represent
882 * slower mouse movement: the default for both is 2.
883 */
set_mouse_speed(int xspeed,int yspeed)884 void set_mouse_speed(int xspeed, int yspeed)
885 {
886 if ((mouse_driver) && (mouse_driver->set_speed))
887 mouse_driver->set_speed(xspeed, yspeed);
888 }
889
890
891
892 /* get_mouse_mickeys:
893 * Measures the mickey count (how far the mouse has moved since the last
894 * call to this function).
895 */
get_mouse_mickeys(int * mickeyx,int * mickeyy)896 void get_mouse_mickeys(int *mickeyx, int *mickeyy)
897 {
898 if ((mouse_driver) && (mouse_driver->get_mickeys)) {
899 mouse_driver->get_mickeys(mickeyx, mickeyy);
900 }
901 else {
902 *mickeyx = 0;
903 *mickeyy = 0;
904 }
905 }
906
907
908
909 /* mouse_on_screen:
910 * Tells whether the mouse pointer position is currently on the screen.
911 * Returns 0 when offscreen, and non-zero otherwise.
912 */
mouse_on_screen()913 int mouse_on_screen()
914 {
915 return _mouse_on;
916 }
917
918
919
920 /* enable_hardware_cursor:
921 * enabels the hardware cursor on platforms where this needs to be done
922 * explicitly and allows system cursors to be used.
923 */
enable_hardware_cursor(void)924 void enable_hardware_cursor(void)
925 {
926 if ((mouse_driver) && (mouse_driver->enable_hardware_cursor)) {
927 mouse_driver->enable_hardware_cursor(TRUE);
928 allow_system_cursor = TRUE;
929 if (is_same_bitmap(_mouse_screen, screen)) {
930 BITMAP *bmp = _mouse_screen;
931 show_mouse(NULL);
932 show_mouse(bmp);
933 }
934 }
935 }
936
937
938
939 /* disable_hardware_cursor:
940 * disables the hardware cursor on platforms where this interferes with
941 * mickeys and disables system cursors.
942 */
disable_hardware_cursor(void)943 void disable_hardware_cursor(void)
944 {
945 if ((mouse_driver) && (mouse_driver->enable_hardware_cursor)) {
946 mouse_driver->enable_hardware_cursor(FALSE);
947 allow_system_cursor = FALSE;
948 if (is_same_bitmap(_mouse_screen, screen)) {
949 BITMAP *bmp = _mouse_screen;
950 show_mouse(NULL);
951 show_mouse(bmp);
952 }
953 }
954 }
955
956
957
958 /* poll_mouse:
959 * Polls the current mouse state, and updates the user-visible information
960 * accordingly. On some drivers this is actually required to get the
961 * input, while on others it is only present to keep compatibility with
962 * systems that do need it. So that people can test their polling code
963 * even on platforms that don't strictly require it, after this function
964 * has been called once, the entire system will switch into polling mode
965 * and will no longer operate asynchronously even if the driver actually
966 * does support that.
967 */
poll_mouse(void)968 int poll_mouse(void)
969 {
970 if (!mouse_driver)
971 return -1;
972
973 if (mouse_driver->poll)
974 mouse_driver->poll();
975
976 update_mouse();
977
978 mouse_polled = TRUE;
979
980 return 0;
981 }
982
983 END_OF_FUNCTION(poll_mouse);
984
985
986
987 /* mouse_needs_poll:
988 * Checks whether the current driver uses polling.
989 */
mouse_needs_poll(void)990 int mouse_needs_poll(void)
991 {
992 return mouse_polled;
993 }
994
995 END_OF_FUNCTION(mouse_needs_poll);
996
997
998
999 /* set_mouse_etc:
1000 * Hook for setting up the motion range, cursor graphic, etc, called by
1001 * the mouse init and whenever we change the graphics mode.
1002 */
set_mouse_etc(void)1003 static void set_mouse_etc(void)
1004 {
1005 if ((!mouse_driver) || (!gfx_driver))
1006 return;
1007
1008 if ((!_mouse_pointer) ||
1009 ((screen) && (_mouse_pointer) &&
1010 (bitmap_color_depth(_mouse_pointer) != bitmap_color_depth(screen))))
1011 set_mouse_sprite(NULL);
1012 else
1013 hw_cursor_dirty = TRUE;
1014
1015 set_mouse_range(0, 0, SCREEN_W-1, SCREEN_H-1);
1016 set_mouse_speed(2, 2);
1017 position_mouse(SCREEN_W/2, SCREEN_H/2);
1018 }
1019
1020
1021
1022 /* install_mouse:
1023 * Installs the Allegro mouse handler. You must do this before using any
1024 * other mouse functions. Return -1 if it can't find a mouse driver,
1025 * otherwise the number of buttons on the mouse.
1026 */
install_mouse(void)1027 int install_mouse(void)
1028 {
1029 _DRIVER_INFO *driver_list;
1030 int num_buttons = -1;
1031 int config_num_buttons;
1032 AL_CONST char *emulate;
1033 char tmp1[64], tmp2[64];
1034 int i;
1035
1036 if (mouse_driver)
1037 return 0;
1038
1039 LOCK_VARIABLE(mouse_driver);
1040 LOCK_VARIABLE(mousedrv_none);
1041 LOCK_VARIABLE(mouse_x);
1042 LOCK_VARIABLE(mouse_y);
1043 LOCK_VARIABLE(mouse_z);
1044 LOCK_VARIABLE(mouse_w);
1045 LOCK_VARIABLE(mouse_b);
1046 LOCK_VARIABLE(mouse_pos);
1047 LOCK_VARIABLE(_mouse_x);
1048 LOCK_VARIABLE(_mouse_y);
1049 LOCK_VARIABLE(_mouse_z);
1050 LOCK_VARIABLE(_mouse_w);
1051 LOCK_VARIABLE(_mouse_b);
1052 LOCK_VARIABLE(_mouse_on);
1053 LOCK_VARIABLE(mon);
1054 LOCK_VARIABLE(emulate_three);
1055 LOCK_VARIABLE(freeze_mouse_flag);
1056 LOCK_VARIABLE(mouse_callback);
1057 LOCK_VARIABLE(mouse_x_focus);
1058 LOCK_VARIABLE(mouse_y_focus);
1059 LOCK_VARIABLE(mouse_sprite);
1060 LOCK_VARIABLE(_mouse_pointer);
1061 LOCK_VARIABLE(_mouse_screen);
1062 LOCK_VARIABLE(mx);
1063 LOCK_VARIABLE(my);
1064 LOCK_VARIABLE(ms);
1065 LOCK_VARIABLE(mtemp);
1066 LOCK_VARIABLE(mouse_polled);
1067 LOCK_VARIABLE(mouse_semaphore);
1068 LOCK_VARIABLE(cursors);
1069 LOCK_FUNCTION(draw_mouse_doublebuffer);
1070 LOCK_FUNCTION(draw_mouse);
1071 LOCK_FUNCTION(update_mouse);
1072 LOCK_FUNCTION(mouse_move);
1073 LOCK_FUNCTION(poll_mouse);
1074 LOCK_FUNCTION(mouse_needs_poll);
1075 LOCK_FUNCTION(_handle_mouse_input);
1076
1077 /* Construct mouse pointers */
1078 if (!default_cursors[MOUSE_CURSOR_ARROW])
1079 default_cursors[MOUSE_CURSOR_ARROW] = create_mouse_pointer(mouse_arrow_data);
1080 if (!default_cursors[MOUSE_CURSOR_BUSY])
1081 default_cursors[MOUSE_CURSOR_BUSY] = create_mouse_pointer(mouse_busy_data);
1082 if (!default_cursors[MOUSE_CURSOR_QUESTION])
1083 default_cursors[MOUSE_CURSOR_QUESTION] = create_mouse_pointer(mouse_arrow_data);
1084 if (!default_cursors[MOUSE_CURSOR_EDIT])
1085 default_cursors[MOUSE_CURSOR_EDIT] = create_mouse_pointer(mouse_arrow_data);
1086
1087 cursors[MOUSE_CURSOR_ARROW] = default_cursors[MOUSE_CURSOR_ARROW];
1088 cursors[MOUSE_CURSOR_BUSY] = default_cursors[MOUSE_CURSOR_BUSY];
1089 cursors[MOUSE_CURSOR_QUESTION] = default_cursors[MOUSE_CURSOR_QUESTION];
1090 cursors[MOUSE_CURSOR_EDIT] = default_cursors[MOUSE_CURSOR_EDIT];
1091
1092 if (system_driver->mouse_drivers)
1093 driver_list = system_driver->mouse_drivers();
1094 else
1095 driver_list = _mouse_driver_list;
1096
1097 if (_mouse_type == MOUSEDRV_AUTODETECT)
1098 _mouse_type = get_config_id(uconvert_ascii("mouse", tmp1), uconvert_ascii("mouse", tmp2), MOUSEDRV_AUTODETECT);
1099
1100 if (_mouse_type != MOUSEDRV_AUTODETECT) {
1101 for (i=0; driver_list[i].driver; i++) {
1102 if (driver_list[i].id == _mouse_type) {
1103 mouse_driver = driver_list[i].driver;
1104 break;
1105 }
1106 }
1107 }
1108
1109 if (mouse_driver) {
1110 mouse_driver->name = mouse_driver->desc = get_config_text(mouse_driver->ascii_name);
1111 num_buttons = mouse_driver->init();
1112 }
1113 else {
1114 for (i=0; num_buttons<0; i++) {
1115 if (!driver_list[i].driver)
1116 break;
1117
1118 mouse_driver = driver_list[i].driver;
1119 mouse_driver->name = mouse_driver->desc = get_config_text(mouse_driver->ascii_name);
1120 num_buttons = mouse_driver->init();
1121 }
1122 }
1123
1124 if (num_buttons < 0) {
1125 mouse_driver = NULL;
1126 return -1;
1127 }
1128
1129 config_num_buttons = get_config_int(uconvert_ascii("mouse", tmp1), uconvert_ascii("num_buttons", tmp2), -1);
1130 emulate = get_config_string(uconvert_ascii("mouse", tmp1), uconvert_ascii("emulate_three", tmp2), NULL);
1131
1132 /* clamp config_num_buttons to zero/positive values */
1133 if (config_num_buttons >= 0)
1134 num_buttons = config_num_buttons;
1135
1136 if ((emulate) && ((i = ugetc(emulate)) != 0)) {
1137 if ((i == 'y') || (i == 'Y') || (i == '1'))
1138 emulate_three = TRUE;
1139 else
1140 emulate_three = FALSE;
1141 }
1142 else {
1143 emulate_three = FALSE;
1144 }
1145
1146 mouse_polled = (mouse_driver->poll) ? TRUE : FALSE;
1147
1148 _mouse_installed = TRUE;
1149
1150 disable_hardware_cursor();
1151
1152 set_mouse_etc();
1153 _add_exit_func(remove_mouse, "remove_mouse");
1154
1155 if (mouse_driver->timer_poll)
1156 install_int(mouse_move, 10);
1157
1158 return num_buttons;
1159 }
1160
1161
1162
1163 /* remove_mouse:
1164 * Removes the mouse handler. You don't normally need to call this, because
1165 * allegro_exit() will do it for you.
1166 */
remove_mouse(void)1167 void remove_mouse(void)
1168 {
1169 if (!mouse_driver)
1170 return;
1171
1172 show_mouse(NULL);
1173 remove_int(mouse_move);
1174
1175 mouse_driver->exit();
1176 mouse_driver = NULL;
1177
1178 _mouse_installed = FALSE;
1179
1180 mouse_x = mouse_y = _mouse_x = _mouse_y = 0;
1181 mouse_z = _mouse_z = 0;
1182 mouse_w = _mouse_w = 0;
1183 mouse_b = _mouse_b = 0;
1184 mouse_pos = 0;
1185
1186 mouse_polled = FALSE;
1187
1188 destroy_bitmap(default_cursors[MOUSE_CURSOR_ARROW]);
1189 destroy_bitmap(default_cursors[MOUSE_CURSOR_BUSY]);
1190 destroy_bitmap(default_cursors[MOUSE_CURSOR_QUESTION]);
1191 destroy_bitmap(default_cursors[MOUSE_CURSOR_EDIT]);
1192
1193 cursors[MOUSE_CURSOR_ARROW] = default_cursors[MOUSE_CURSOR_ARROW] = NULL;
1194 cursors[MOUSE_CURSOR_BUSY] = default_cursors[MOUSE_CURSOR_BUSY] = NULL;
1195 cursors[MOUSE_CURSOR_QUESTION] = default_cursors[MOUSE_CURSOR_QUESTION] = NULL;
1196 cursors[MOUSE_CURSOR_EDIT] = default_cursors[MOUSE_CURSOR_EDIT] = NULL;
1197
1198 if (_mouse_pointer) {
1199 destroy_bitmap(_mouse_pointer);
1200 _mouse_pointer = NULL;
1201 }
1202
1203 if (ms) {
1204 destroy_bitmap(ms);
1205 ms = NULL;
1206
1207 destroy_bitmap(mtemp);
1208 mtemp = NULL;
1209 }
1210
1211 _remove_exit_func(remove_mouse);
1212 }
1213
1214
1215
1216 /* _mouse_constructor:
1217 * Register mouse functions if this object file is linked in.
1218 */
1219 #ifdef ALLEGRO_USE_CONSTRUCTOR
1220 CONSTRUCTOR_FUNCTION(void _mouse_constructor(void));
1221 #endif
1222
1223 static struct _AL_LINKER_MOUSE mouse_linker = {
1224 set_mouse_etc,
1225 show_mouse,
1226 &_mouse_screen
1227 };
1228
_mouse_constructor(void)1229 void _mouse_constructor(void)
1230 {
1231 _al_linker_mouse = &mouse_linker;
1232 }
1233