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