fixed mouse events in fb version too
[winnie] / src / fbdev / mouse.cc
1 #ifdef WINNIE_FBDEV
2 #include <errno.h>
3 #include <limits.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include <fcntl.h>
9 #include <sys/ioctl.h>
10 #include <termios.h>
11 #include <unistd.h>
12
13 #include "geom.h"
14 #include "gfx.h"
15 #include "mouse.h"
16 #include "window.h"
17 #include "wm.h"
18
19 #define BN_LEFT         1
20 #define BN_RIGHT        2
21 #define BN_MIDDLE       4
22
23 static int read_mouse();
24
25 static int dev_fd = -1; // file descriptor for /dev/psaux
26 static Rect bounds;
27 static int pointer_x, pointer_y;
28 static int bnstate;
29
30 bool init_mouse()
31 {
32         if((dev_fd = open("/dev/psaux", O_RDONLY | O_NONBLOCK)) == -1) {
33                 fprintf(stderr, "Cannot open /dev/psaux : %s\n", strerror(errno));
34                 return false;
35         }
36
37         set_mouse_bounds(get_screen_size());
38         return true;
39 }
40
41 void destroy_mouse()
42 {
43         if(dev_fd != -1) {
44                 close(dev_fd);
45                 dev_fd = -1;
46         }
47 }
48
49 void set_mouse_bounds(const Rect &rect)
50 {
51         bounds = rect;
52 }
53
54 int get_mouse_fd()
55 {
56         return dev_fd;
57 }
58
59 void process_mouse_event()
60 {
61         /* TODO:
62          * - read all pending events from mouse fd (use O_NONBLOCK so that
63          *   read will return -1 when there are no more events instead of blocking).
64          */
65
66         int prev_state = bnstate;
67         int prev_x = pointer_x;
68         int prev_y = pointer_y;
69
70         if(read_mouse() == -1) {
71                 return;
72         }
73
74         Window *top;
75         if(!(top = wm->get_grab_window())) {
76                 top = wm->get_window_at_pos(pointer_x, pointer_y);
77                 if(top) {
78                         wm->set_focused_window(top);
79                 }
80                 else {
81                         wm->set_focused_window(0);
82                 }
83         }
84
85          /* - send each pointer move and button press/release to the topmost window
86          *   with the pointer on it.
87          */
88
89         int dx = pointer_x - prev_x;
90         int dy = pointer_y - prev_y;
91
92         if((dx || dy) && top) {
93                 MouseMotionFuncType motion_callback = top->get_mouse_motion_callback();
94                 if(motion_callback) {
95                         Rect rect = top->get_absolute_rect();
96                         motion_callback(top, pointer_x - rect.x, pointer_y - rect.y);
97                 }
98         }
99
100         MouseButtonFuncType button_callback;
101         if((bnstate != prev_state) && top && (button_callback = top->get_mouse_button_callback())) {
102                 int num_bits = sizeof bnstate * CHAR_BIT;
103                 for(int i=0; i<num_bits; i++) {
104                         int s = (bnstate >> i) & 1;
105                         int prev_s = (prev_state >> i) & 1;
106                         if(s != prev_s) {
107                                 Rect rect = top->get_absolute_rect();
108                                 button_callback(top, i, s, pointer_x - rect.x, pointer_y - rect.y);
109                         }
110                 }
111         }
112 }
113
114 void get_pointer_pos(int *x, int *y)
115 {
116         *x = pointer_x;
117         *y = pointer_y;
118 }
119
120 int get_button_state()
121 {
122         return bnstate;
123 }
124
125 int get_button(int bn)
126 {
127         if(bn < 0 || bn >= 3) {
128                 return 0;
129         }
130         return (bnstate & (1 << bn)) != 0;
131 }
132
133 static int read_mouse()
134 {
135         int rd;
136         signed char state[3] = {0, 0, 0};
137
138         if((rd = read(dev_fd, state, 3)) == -1) {
139                 fprintf(stderr, "Unable to get mouse state : %s\n", strerror(errno));
140                 return -1;
141         }
142
143         bnstate = state[0] & 7;
144         pointer_x += state[1];
145         pointer_y -= state[2];
146
147         if(pointer_x < bounds.x) {
148                 pointer_x = bounds.x;
149         }
150
151         if(pointer_y < bounds.y) {
152                 pointer_y = bounds.y;
153         }
154
155         if(pointer_x > bounds.x + bounds.width - 1) {
156                 pointer_x = bounds.x + bounds.width - 1;
157         }
158
159         if(pointer_y > bounds.y + bounds.height - 1) {
160                 pointer_y = bounds.y + bounds.height - 1;
161         }
162
163         return 0;
164 }
165 #endif // WINNIE_FBDEV