Bug 1082: mem_free_set in abort_preloading
[elinks.git] / src / terminal / mouse.c
blob8744cd7ca797eac980fe880d2791f4749039861d
1 /** Support for mouse interface
2 * @file */
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
8 /* TODO: cleanup includes */
10 #include <stdlib.h>
11 #include <string.h>
12 #ifdef HAVE_TERMIOS_H
13 #include <termios.h>
14 #endif
15 #ifdef HAVE_UNISTD_H
16 #include <unistd.h>
17 #endif
18 #ifdef __hpux__
19 #include <limits.h>
20 #define HPUX_PIPE (len > PIPE_BUF || errno != EAGAIN)
21 #else
22 #define HPUX_PIPE 1
23 #endif
25 #include "elinks.h"
27 #include "config/options.h"
28 #include "intl/gettext/libintl.h"
29 #include "main/select.h"
30 #include "main/timer.h"
31 #include "osdep/ascii.h"
32 #include "osdep/osdep.h"
33 #include "terminal/hardio.h"
34 #include "terminal/itrm.h"
35 #include "terminal/kbd.h"
36 #include "terminal/mouse.h"
37 #include "terminal/terminal.h"
38 #include "util/error.h"
39 #include "util/memory.h"
40 #include "util/string.h"
41 #include "util/time.h"
43 extern struct itrm *ditrm;
45 #define write_sequence(fd, seq) \
46 hard_write(fd, seq, sizeof(seq) - 1)
49 #define INIT_TWIN_MOUSE_SEQ "\033[?9h" /**< Send MIT Mouse Row & Column on Button Press */
50 #define INIT_XWIN_MOUSE_SEQ "\033[?1000h" /**< Send Mouse X & Y on button press and release */
52 void
53 send_mouse_init_sequence(int h)
55 write_sequence(h, INIT_TWIN_MOUSE_SEQ);
56 write_sequence(h, INIT_XWIN_MOUSE_SEQ);
59 #define DONE_TWIN_MOUSE_SEQ "\033[?9l" /**< Don't Send MIT Mouse Row & Column on Button Press */
60 #define DONE_XWIN_MOUSE_SEQ "\033[?1000l" /**< Don't Send Mouse X & Y on button press and release */
62 void
63 send_mouse_done_sequence(int h)
65 /* This is a hack to make xterm + alternate screen working,
66 * if we send only DONE_XWIN_MOUSE_SEQ, mouse is not totally
67 * released it seems, in rxvt and xterm... --Zas */
68 write_sequence(h, DONE_TWIN_MOUSE_SEQ);
69 write_sequence(h, DONE_XWIN_MOUSE_SEQ);
72 static int mouse_enabled;
74 void
75 disable_mouse(void)
77 int h = get_output_handle(); /* XXX: Is this all right? -- Miciah */
79 if (!mouse_enabled) return;
81 unhandle_mouse(ditrm->mouse_h);
82 if (is_xterm()) send_mouse_done_sequence(h);
84 mouse_enabled = 0;
87 void
88 enable_mouse(void)
90 int h = get_output_handle(); /* XXX: Is this all right? -- Miciah */
92 if (mouse_enabled) return;
94 if (is_xterm()) send_mouse_init_sequence(h);
95 ditrm->mouse_h = handle_mouse(0, (void (*)(void *, unsigned char *, int)) itrm_queue_event, ditrm);
97 mouse_enabled = 1;
100 void
101 toggle_mouse(void)
103 if (mouse_enabled)
104 disable_mouse();
105 else
106 enable_mouse();
109 static int
110 decode_mouse_position(struct itrm *itrm, int from)
112 int position;
114 position = (unsigned char) (itrm->in.queue.data[from]) - ' ' - 1
115 + ((int) ((unsigned char) (itrm->in.queue.data[from + 1]) - ' ' - 1) << 7);
117 return (position & (1 << 13)) ? 0 : position;
120 #define get_mouse_x_position(itrm, esclen) decode_mouse_position(itrm, (esclen) + 1)
121 #define get_mouse_y_position(itrm, esclen) decode_mouse_position(itrm, (esclen) + 3)
123 #define TW_BUTT_LEFT 1
124 #define TW_BUTT_MIDDLE 2
125 #define TW_BUTT_RIGHT 4
127 /** @returns length of the escape sequence or -1 if the caller needs to set up
128 * the ESC delay timer. */
130 decode_terminal_mouse_escape_sequence(struct itrm *itrm, struct interlink_event *ev,
131 int el, int v)
133 static int xterm_button = -1;
134 struct interlink_event_mouse mouse;
136 if (itrm->in.queue.len - el < 3)
137 return -1;
139 if (v == 5) {
140 if (xterm_button == -1)
141 xterm_button = 0;
143 if (itrm->in.queue.len - el < 5)
144 return -1;
146 mouse.x = get_mouse_x_position(itrm, el);
147 mouse.y = get_mouse_y_position(itrm, el);
149 switch ((itrm->in.queue.data[el] - ' ') ^ xterm_button) { /* Every event changes only one bit */
150 case TW_BUTT_LEFT:
151 mouse.button = B_LEFT | ((xterm_button & TW_BUTT_LEFT) ? B_UP : B_DOWN);
152 break;
153 case TW_BUTT_MIDDLE:
154 mouse.button = B_MIDDLE | ((xterm_button & TW_BUTT_MIDDLE) ? B_UP : B_DOWN);
155 break;
156 case TW_BUTT_RIGHT:
157 mouse.button = B_RIGHT | ((xterm_button & TW_BUTT_RIGHT) ? B_UP : B_DOWN);
158 break;
159 case 0:
160 mouse.button = B_DRAG;
161 break;
162 default:
163 mouse.button = 0; /* shut up warning */
164 /* default : Twin protocol error */
167 xterm_button = itrm->in.queue.data[el] - ' ';
168 el += 5;
170 } else {
171 /* See terminal/mouse.h about details of the mouse reporting
172 * protocol and {struct term_event_mouse->button} bitmask
173 * structure. */
174 mouse.x = itrm->in.queue.data[el+1] - ' ' - 1;
175 mouse.y = itrm->in.queue.data[el+2] - ' ' - 1;
177 /* There are rumours arising from remnants of code dating to
178 * the ancient Mikulas' times that bit 4 indicated B_DRAG.
179 * However, I didn't find on what terminal it should be ever
180 * supposed to work and it conflicts with wheels. So I removed
181 * the last remnants of the code as well. --pasky */
183 mouse.button = (itrm->in.queue.data[el] & 7) | B_DOWN;
184 /* smartglasses1 - rxvt wheel: */
185 if (mouse.button == 3 && xterm_button != -1) {
186 mouse.button = xterm_button | B_UP;
188 /* xterm wheel: */
189 if ((itrm->in.queue.data[el] & 96) == 96) {
190 mouse.button = (itrm->in.queue.data[el] & 1) ? B_WHEEL_DOWN : B_WHEEL_UP;
193 xterm_button = -1;
194 /* XXX: Eterm/aterm uses rxvt-like reporting, but sends the
195 * release sequence for wheel. rxvt itself sends only press
196 * sequence. Since we can't reliably guess what we're talking
197 * with from $TERM, we will rather support Eterm/aterm, as in
198 * rxvt, at least each second wheel up move will work. */
199 if (mouse_action_is(&mouse, B_DOWN))
200 xterm_button = mouse_get_button(&mouse);
202 el += 3;
205 /* Postpone changing of the event type until all sanity
206 * checks have been done. */
207 set_mouse_interlink_event(ev, mouse.x, mouse.y, mouse.button);
209 return el;