Commit | Line | Data |
---|---|---|
984263bc MD |
1 | /*- |
2 | * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer as | |
10 | * the first lines of this file unmodified. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * | |
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR | |
16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
18 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
25 | * | |
26 | * $FreeBSD: src/sys/dev/syscons/scmouse.c,v 1.12.2.3 2001/07/28 12:51:47 yokota Exp $ | |
27 | */ | |
28 | ||
29 | #include "opt_syscons.h" | |
30 | ||
984263bc MD |
31 | #include <sys/param.h> |
32 | #include <sys/systm.h> | |
c3ab84cc | 33 | #include <sys/kernel.h> |
984263bc MD |
34 | #include <sys/conf.h> |
35 | #include <sys/signalvar.h> | |
36 | #include <sys/proc.h> | |
37 | #include <sys/tty.h> | |
76b8f52a | 38 | #include <sys/thread2.h> |
984263bc MD |
39 | |
40 | #include <machine/console.h> | |
62770245 | 41 | #include <sys/mouse.h> |
984263bc | 42 | |
1f2de5d4 | 43 | #include "syscons.h" |
984263bc MD |
44 | |
45 | #ifdef SC_TWOBUTTON_MOUSE | |
46 | #define SC_MOUSE_PASTEBUTTON MOUSE_BUTTON3DOWN /* right button */ | |
47 | #define SC_MOUSE_EXTENDBUTTON MOUSE_BUTTON2DOWN /* not really used */ | |
48 | #else | |
49 | #define SC_MOUSE_PASTEBUTTON MOUSE_BUTTON2DOWN /* middle button */ | |
50 | #define SC_MOUSE_EXTENDBUTTON MOUSE_BUTTON3DOWN /* right button */ | |
51 | #endif /* SC_TWOBUTTON_MOUSE */ | |
52 | ||
53 | #define SC_WAKEUP_DELTA 20 | |
54 | ||
984263bc MD |
55 | #ifndef SC_NO_SYSMOUSE |
56 | ||
984263bc MD |
57 | static int cut_buffer_size; |
58 | static u_char *cut_buffer; | |
59 | ||
60 | /* local functions */ | |
c3ab84cc VS |
61 | static void sc_mouse_init(void *); |
62 | static void sc_mouse_uninit(void *); | |
63 | ||
984263bc MD |
64 | static void set_mouse_pos(scr_stat *scp); |
65 | #ifndef SC_NO_CUTPASTE | |
66 | static int skip_spc_right(scr_stat *scp, int p); | |
67 | static int skip_spc_left(scr_stat *scp, int p); | |
68 | static void mouse_cut(scr_stat *scp); | |
69 | static void mouse_cut_start(scr_stat *scp); | |
70 | static void mouse_cut_end(scr_stat *scp); | |
71 | static void mouse_cut_word(scr_stat *scp); | |
72 | static void mouse_cut_line(scr_stat *scp); | |
73 | static void mouse_cut_extend(scr_stat *scp); | |
74 | static void mouse_paste(scr_stat *scp); | |
75 | #endif /* SC_NO_CUTPASTE */ | |
76 | ||
481d12aa MD |
77 | static struct lwkt_token scmouse_tok = LWKT_TOKEN_INITIALIZER(scmouse_tok); |
78 | ||
984263bc MD |
79 | #ifndef SC_NO_CUTPASTE |
80 | /* allocate a cut buffer */ | |
81 | void | |
82 | sc_alloc_cut_buffer(scr_stat *scp, int wait) | |
83 | { | |
84 | u_char *p; | |
85 | ||
86 | if ((cut_buffer == NULL) | |
87 | || (cut_buffer_size < scp->xsize * scp->ysize + 1)) { | |
88 | p = cut_buffer; | |
89 | cut_buffer = NULL; | |
90 | if (p != NULL) | |
efda3bd0 | 91 | kfree(p, M_SYSCONS); |
984263bc | 92 | cut_buffer_size = scp->xsize * scp->ysize + 1; |
efda3bd0 | 93 | p = kmalloc(cut_buffer_size, M_SYSCONS, (wait) ? M_WAITOK : M_NOWAIT); |
984263bc MD |
94 | if (p != NULL) |
95 | p[0] = '\0'; | |
96 | cut_buffer = p; | |
97 | } | |
98 | } | |
99 | #endif /* SC_NO_CUTPASTE */ | |
100 | ||
101 | /* move mouse */ | |
102 | void | |
103 | sc_mouse_move(scr_stat *scp, int x, int y) | |
104 | { | |
6bc31f17 | 105 | crit_enter(); |
984263bc MD |
106 | scp->mouse_xpos = scp->mouse_oldxpos = x; |
107 | scp->mouse_ypos = scp->mouse_oldypos = y; | |
219917ca | 108 | if (scp->font_height <= 0) |
984263bc MD |
109 | scp->mouse_pos = scp->mouse_oldpos = 0; |
110 | else | |
111 | scp->mouse_pos = scp->mouse_oldpos = | |
219917ca SW |
112 | (y / scp->font_height - scp->yoff) * scp->xsize + |
113 | x / scp->font_width - scp->xoff; | |
984263bc | 114 | scp->status |= MOUSE_MOVED; |
6bc31f17 | 115 | crit_exit(); |
984263bc MD |
116 | } |
117 | ||
118 | /* adjust mouse position */ | |
119 | static void | |
120 | set_mouse_pos(scr_stat *scp) | |
121 | { | |
219917ca SW |
122 | if (scp->mouse_xpos < scp->xoff * scp->font_width) |
123 | scp->mouse_xpos = scp->xoff * scp->font_width; | |
124 | if (scp->mouse_ypos < scp->yoff * scp->font_height) | |
125 | scp->mouse_ypos = scp->yoff * scp->font_height; | |
984263bc | 126 | if (ISGRAPHSC(scp)) { |
219917ca SW |
127 | if (scp->mouse_xpos > scp->xpixel - 1) |
128 | scp->mouse_xpos = scp->xpixel - 1; | |
129 | if (scp->mouse_ypos > scp->ypixel - 1) | |
130 | scp->mouse_ypos = scp->ypixel - 1; | |
984263bc MD |
131 | return; |
132 | } else { | |
219917ca SW |
133 | if (scp->mouse_xpos > (scp->xsize + scp->xoff) * scp->font_width - 1) |
134 | scp->mouse_xpos = (scp->xsize + scp->xoff) * scp->font_width - 1; | |
135 | if (scp->mouse_ypos > (scp->ysize + scp->yoff) * scp->font_height - 1) | |
136 | scp->mouse_ypos = (scp->ysize + scp->yoff) * scp->font_height - 1; | |
984263bc MD |
137 | } |
138 | ||
219917ca SW |
139 | if (scp->mouse_xpos != scp->mouse_oldxpos || |
140 | scp->mouse_ypos != scp->mouse_oldypos) { | |
984263bc MD |
141 | scp->status |= MOUSE_MOVED; |
142 | scp->mouse_pos = | |
219917ca SW |
143 | (scp->mouse_ypos / scp->font_height - scp->yoff) * scp->xsize + |
144 | scp->mouse_xpos / scp->font_width - scp->xoff; | |
984263bc MD |
145 | #ifndef SC_NO_CUTPASTE |
146 | if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING)) | |
147 | mouse_cut(scp); | |
148 | #endif | |
149 | } | |
150 | } | |
151 | ||
152 | #ifndef SC_NO_CUTPASTE | |
153 | ||
154 | void | |
155 | sc_draw_mouse_image(scr_stat *scp) | |
156 | { | |
157 | if (ISGRAPHSC(scp)) | |
158 | return; | |
159 | ||
7ae6dbf0 | 160 | atomic_add_int(&scp->sc->videoio_in_progress, 1); |
984263bc MD |
161 | (*scp->rndr->draw_mouse)(scp, scp->mouse_xpos, scp->mouse_ypos, TRUE); |
162 | scp->mouse_oldpos = scp->mouse_pos; | |
163 | scp->mouse_oldxpos = scp->mouse_xpos; | |
164 | scp->mouse_oldypos = scp->mouse_ypos; | |
165 | scp->status |= MOUSE_VISIBLE; | |
7ae6dbf0 | 166 | atomic_add_int(&scp->sc->videoio_in_progress, -1); |
984263bc MD |
167 | } |
168 | ||
169 | void | |
170 | sc_remove_mouse_image(scr_stat *scp) | |
171 | { | |
172 | int size; | |
173 | int i; | |
174 | ||
175 | if (ISGRAPHSC(scp)) | |
176 | return; | |
177 | ||
7ae6dbf0 | 178 | atomic_add_int(&scp->sc->videoio_in_progress, 1); |
984263bc | 179 | (*scp->rndr->draw_mouse)(scp, |
219917ca SW |
180 | (scp->mouse_oldpos%scp->xsize + scp->xoff) * |
181 | scp->font_width, | |
182 | (scp->mouse_oldpos/scp->xsize + scp->yoff) * | |
183 | scp->font_height, | |
984263bc | 184 | FALSE); |
219917ca | 185 | size = scp->xsize * scp->ysize; |
984263bc MD |
186 | i = scp->mouse_oldpos; |
187 | mark_for_update(scp, i); | |
188 | mark_for_update(scp, i); | |
984263bc MD |
189 | if (i + scp->xsize + 1 < size) { |
190 | mark_for_update(scp, i + scp->xsize + 1); | |
191 | } else if (i + scp->xsize < size) { | |
192 | mark_for_update(scp, i + scp->xsize); | |
193 | } else if (i + 1 < size) { | |
194 | mark_for_update(scp, i + 1); | |
195 | } | |
984263bc | 196 | scp->status &= ~MOUSE_VISIBLE; |
7ae6dbf0 | 197 | atomic_add_int(&scp->sc->videoio_in_progress, -1); |
984263bc MD |
198 | } |
199 | ||
200 | int | |
201 | sc_inside_cutmark(scr_stat *scp, int pos) | |
202 | { | |
203 | int start; | |
204 | int end; | |
205 | ||
206 | if (scp->mouse_cut_end < 0) | |
207 | return FALSE; | |
208 | if (scp->mouse_cut_start <= scp->mouse_cut_end) { | |
209 | start = scp->mouse_cut_start; | |
210 | end = scp->mouse_cut_end; | |
211 | } else { | |
212 | start = scp->mouse_cut_end; | |
213 | end = scp->mouse_cut_start - 1; | |
214 | } | |
215 | return ((start <= pos) && (pos <= end)); | |
216 | } | |
217 | ||
218 | void | |
219 | sc_remove_cutmarking(scr_stat *scp) | |
220 | { | |
6bc31f17 | 221 | crit_enter(); |
984263bc MD |
222 | if (scp->mouse_cut_end >= 0) { |
223 | mark_for_update(scp, scp->mouse_cut_start); | |
224 | mark_for_update(scp, scp->mouse_cut_end); | |
225 | } | |
226 | scp->mouse_cut_start = scp->xsize*scp->ysize; | |
227 | scp->mouse_cut_end = -1; | |
6bc31f17 | 228 | crit_exit(); |
984263bc MD |
229 | scp->status &= ~MOUSE_CUTTING; |
230 | } | |
231 | ||
232 | void | |
233 | sc_remove_all_cutmarkings(sc_softc_t *sc) | |
234 | { | |
235 | scr_stat *scp; | |
236 | int i; | |
237 | ||
238 | /* delete cut markings in all vtys */ | |
239 | for (i = 0; i < sc->vtys; ++i) { | |
240 | scp = SC_STAT(sc->dev[i]); | |
241 | if (scp == NULL) | |
242 | continue; | |
243 | sc_remove_cutmarking(scp); | |
244 | } | |
245 | } | |
246 | ||
247 | void | |
248 | sc_remove_all_mouse(sc_softc_t *sc) | |
249 | { | |
250 | scr_stat *scp; | |
251 | int i; | |
252 | ||
253 | for (i = 0; i < sc->vtys; ++i) { | |
254 | scp = SC_STAT(sc->dev[i]); | |
255 | if (scp == NULL) | |
256 | continue; | |
257 | if (scp->status & MOUSE_VISIBLE) { | |
258 | scp->status &= ~MOUSE_VISIBLE; | |
259 | mark_all(scp); | |
260 | } | |
261 | } | |
262 | } | |
263 | ||
264 | #define IS_SPACE_CHAR(c) (((c) & 0xff) == ' ') | |
265 | ||
266 | /* skip spaces to right */ | |
267 | static int | |
268 | skip_spc_right(scr_stat *scp, int p) | |
269 | { | |
270 | int c; | |
271 | int i; | |
272 | ||
273 | for (i = p % scp->xsize; i < scp->xsize; ++i) { | |
274 | c = sc_vtb_getc(&scp->vtb, p); | |
275 | if (!IS_SPACE_CHAR(c)) | |
276 | break; | |
277 | ++p; | |
278 | } | |
279 | return i; | |
280 | } | |
281 | ||
282 | /* skip spaces to left */ | |
283 | static int | |
284 | skip_spc_left(scr_stat *scp, int p) | |
285 | { | |
286 | int c; | |
287 | int i; | |
288 | ||
289 | for (i = p-- % scp->xsize - 1; i >= 0; --i) { | |
290 | c = sc_vtb_getc(&scp->vtb, p); | |
291 | if (!IS_SPACE_CHAR(c)) | |
292 | break; | |
293 | --p; | |
294 | } | |
295 | return i; | |
296 | } | |
297 | ||
298 | /* copy marked region to the cut buffer */ | |
299 | static void | |
300 | mouse_cut(scr_stat *scp) | |
301 | { | |
302 | int start; | |
303 | int end; | |
304 | int from; | |
305 | int to; | |
306 | int blank; | |
307 | int c; | |
308 | int p; | |
984263bc MD |
309 | int i; |
310 | ||
311 | start = scp->mouse_cut_start; | |
984263bc MD |
312 | if (scp->mouse_pos >= start) { |
313 | from = start; | |
314 | to = end = scp->mouse_pos; | |
315 | } else { | |
316 | from = end = scp->mouse_pos; | |
317 | to = start - 1; | |
318 | } | |
319 | for (p = from, i = blank = 0; p <= to; ++p) { | |
320 | cut_buffer[i] = sc_vtb_getc(&scp->vtb, p); | |
321 | /* remember the position of the last non-space char */ | |
322 | if (!IS_SPACE_CHAR(cut_buffer[i++])) | |
323 | blank = i; /* the first space after the last non-space */ | |
324 | /* trim trailing blank when crossing lines */ | |
325 | if ((p % scp->xsize) == (scp->xsize - 1)) { | |
326 | cut_buffer[blank] = '\r'; | |
327 | i = blank + 1; | |
328 | } | |
329 | } | |
330 | cut_buffer[i] = '\0'; | |
331 | ||
332 | /* scan towards the end of the last line */ | |
333 | --p; | |
334 | for (i = p % scp->xsize; i < scp->xsize; ++i) { | |
335 | c = sc_vtb_getc(&scp->vtb, p); | |
336 | if (!IS_SPACE_CHAR(c)) | |
337 | break; | |
338 | ++p; | |
339 | } | |
340 | /* if there is nothing but blank chars, trim them, but mark towards eol */ | |
341 | if (i >= scp->xsize) { | |
342 | if (end >= start) | |
343 | to = end = p - 1; | |
344 | else | |
345 | to = start = p; | |
346 | cut_buffer[blank++] = '\r'; | |
347 | cut_buffer[blank] = '\0'; | |
348 | } | |
349 | ||
350 | /* remove the current marking */ | |
6bc31f17 | 351 | crit_enter(); |
984263bc MD |
352 | if (scp->mouse_cut_start <= scp->mouse_cut_end) { |
353 | mark_for_update(scp, scp->mouse_cut_start); | |
354 | mark_for_update(scp, scp->mouse_cut_end); | |
355 | } else if (scp->mouse_cut_end >= 0) { | |
356 | mark_for_update(scp, scp->mouse_cut_end); | |
357 | mark_for_update(scp, scp->mouse_cut_start); | |
358 | } | |
359 | ||
360 | /* mark the new region */ | |
361 | scp->mouse_cut_start = start; | |
362 | scp->mouse_cut_end = end; | |
363 | mark_for_update(scp, from); | |
364 | mark_for_update(scp, to); | |
6bc31f17 | 365 | crit_exit(); |
984263bc MD |
366 | } |
367 | ||
368 | /* a mouse button is pressed, start cut operation */ | |
369 | static void | |
370 | mouse_cut_start(scr_stat *scp) | |
371 | { | |
372 | int i; | |
373 | int j; | |
984263bc MD |
374 | |
375 | if (scp->status & MOUSE_VISIBLE) { | |
376 | i = scp->mouse_cut_start; | |
377 | j = scp->mouse_cut_end; | |
378 | sc_remove_all_cutmarkings(scp->sc); | |
379 | if (scp->mouse_pos == i && i == j) { | |
380 | cut_buffer[0] = '\0'; | |
381 | } else if (skip_spc_right(scp, scp->mouse_pos) >= scp->xsize) { | |
382 | /* if the pointer is on trailing blank chars, mark towards eol */ | |
383 | i = skip_spc_left(scp, scp->mouse_pos) + 1; | |
6bc31f17 | 384 | crit_enter(); |
ed183f8c | 385 | scp->mouse_cut_start = rounddown(scp->mouse_pos, scp->xsize) + i; |
984263bc MD |
386 | scp->mouse_cut_end = |
387 | (scp->mouse_pos / scp->xsize + 1) * scp->xsize - 1; | |
6bc31f17 | 388 | crit_exit(); |
984263bc MD |
389 | cut_buffer[0] = '\r'; |
390 | cut_buffer[1] = '\0'; | |
391 | scp->status |= MOUSE_CUTTING; | |
392 | } else { | |
6bc31f17 | 393 | crit_enter(); |
984263bc MD |
394 | scp->mouse_cut_start = scp->mouse_pos; |
395 | scp->mouse_cut_end = scp->mouse_cut_start; | |
6bc31f17 | 396 | crit_exit(); |
984263bc MD |
397 | cut_buffer[0] = sc_vtb_getc(&scp->vtb, scp->mouse_cut_start); |
398 | cut_buffer[1] = '\0'; | |
399 | scp->status |= MOUSE_CUTTING; | |
400 | } | |
401 | mark_all(scp); /* this is probably overkill XXX */ | |
402 | } | |
403 | } | |
404 | ||
405 | /* end of cut operation */ | |
406 | static void | |
407 | mouse_cut_end(scr_stat *scp) | |
408 | { | |
409 | if (scp->status & MOUSE_VISIBLE) | |
410 | scp->status &= ~MOUSE_CUTTING; | |
411 | } | |
412 | ||
413 | /* copy a word under the mouse pointer */ | |
414 | static void | |
415 | mouse_cut_word(scr_stat *scp) | |
416 | { | |
417 | int start; | |
418 | int end; | |
419 | int sol; | |
420 | int eol; | |
421 | int c; | |
984263bc MD |
422 | int i; |
423 | int j; | |
424 | ||
425 | /* | |
426 | * Because we don't have locale information in the kernel, | |
427 | * we only distinguish space char and non-space chars. Punctuation | |
428 | * chars, symbols and other regular chars are all treated alike. | |
429 | */ | |
430 | if (scp->status & MOUSE_VISIBLE) { | |
431 | /* remove the current cut mark */ | |
6bc31f17 | 432 | crit_enter(); |
984263bc MD |
433 | if (scp->mouse_cut_start <= scp->mouse_cut_end) { |
434 | mark_for_update(scp, scp->mouse_cut_start); | |
435 | mark_for_update(scp, scp->mouse_cut_end); | |
436 | } else if (scp->mouse_cut_end >= 0) { | |
437 | mark_for_update(scp, scp->mouse_cut_end); | |
438 | mark_for_update(scp, scp->mouse_cut_start); | |
439 | } | |
440 | scp->mouse_cut_start = scp->xsize*scp->ysize; | |
441 | scp->mouse_cut_end = -1; | |
6bc31f17 | 442 | crit_exit(); |
984263bc | 443 | |
ed183f8c | 444 | sol = rounddown(scp->mouse_pos, scp->xsize); |
984263bc MD |
445 | eol = sol + scp->xsize; |
446 | c = sc_vtb_getc(&scp->vtb, scp->mouse_pos); | |
447 | if (IS_SPACE_CHAR(c)) { | |
448 | /* blank space */ | |
449 | for (j = scp->mouse_pos; j >= sol; --j) { | |
450 | c = sc_vtb_getc(&scp->vtb, j); | |
451 | if (!IS_SPACE_CHAR(c)) | |
452 | break; | |
453 | } | |
454 | start = ++j; | |
455 | for (j = scp->mouse_pos; j < eol; ++j) { | |
456 | c = sc_vtb_getc(&scp->vtb, j); | |
457 | if (!IS_SPACE_CHAR(c)) | |
458 | break; | |
459 | } | |
460 | end = j - 1; | |
461 | } else { | |
462 | /* non-space word */ | |
463 | for (j = scp->mouse_pos; j >= sol; --j) { | |
464 | c = sc_vtb_getc(&scp->vtb, j); | |
465 | if (IS_SPACE_CHAR(c)) | |
466 | break; | |
467 | } | |
468 | start = ++j; | |
469 | for (j = scp->mouse_pos; j < eol; ++j) { | |
470 | c = sc_vtb_getc(&scp->vtb, j); | |
471 | if (IS_SPACE_CHAR(c)) | |
472 | break; | |
473 | } | |
474 | end = j - 1; | |
475 | } | |
476 | ||
477 | /* copy the found word */ | |
478 | for (i = 0, j = start; j <= end; ++j) | |
479 | cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j); | |
480 | cut_buffer[i] = '\0'; | |
481 | scp->status |= MOUSE_CUTTING; | |
482 | ||
483 | /* mark the region */ | |
6bc31f17 | 484 | crit_enter(); |
984263bc MD |
485 | scp->mouse_cut_start = start; |
486 | scp->mouse_cut_end = end; | |
487 | mark_for_update(scp, start); | |
488 | mark_for_update(scp, end); | |
6bc31f17 | 489 | crit_exit(); |
984263bc MD |
490 | } |
491 | } | |
492 | ||
493 | /* copy a line under the mouse pointer */ | |
494 | static void | |
495 | mouse_cut_line(scr_stat *scp) | |
496 | { | |
984263bc MD |
497 | int i; |
498 | int j; | |
499 | ||
500 | if (scp->status & MOUSE_VISIBLE) { | |
501 | /* remove the current cut mark */ | |
6bc31f17 | 502 | crit_enter(); |
984263bc MD |
503 | if (scp->mouse_cut_start <= scp->mouse_cut_end) { |
504 | mark_for_update(scp, scp->mouse_cut_start); | |
505 | mark_for_update(scp, scp->mouse_cut_end); | |
506 | } else if (scp->mouse_cut_end >= 0) { | |
507 | mark_for_update(scp, scp->mouse_cut_end); | |
508 | mark_for_update(scp, scp->mouse_cut_start); | |
509 | } | |
510 | ||
511 | /* mark the entire line */ | |
ed183f8c | 512 | scp->mouse_cut_start = rounddown(scp->mouse_pos, scp->xsize); |
984263bc MD |
513 | scp->mouse_cut_end = scp->mouse_cut_start + scp->xsize - 1; |
514 | mark_for_update(scp, scp->mouse_cut_start); | |
515 | mark_for_update(scp, scp->mouse_cut_end); | |
6bc31f17 | 516 | crit_exit(); |
984263bc MD |
517 | |
518 | /* copy the line into the cut buffer */ | |
519 | for (i = 0, j = scp->mouse_cut_start; j <= scp->mouse_cut_end; ++j) | |
520 | cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j); | |
521 | cut_buffer[i++] = '\r'; | |
522 | cut_buffer[i] = '\0'; | |
523 | scp->status |= MOUSE_CUTTING; | |
524 | } | |
525 | } | |
526 | ||
527 | /* extend the marked region to the mouse pointer position */ | |
528 | static void | |
529 | mouse_cut_extend(scr_stat *scp) | |
530 | { | |
531 | int start; | |
532 | int end; | |
984263bc MD |
533 | |
534 | if ((scp->status & MOUSE_VISIBLE) && !(scp->status & MOUSE_CUTTING) | |
535 | && (scp->mouse_cut_end >= 0)) { | |
536 | if (scp->mouse_cut_start <= scp->mouse_cut_end) { | |
537 | start = scp->mouse_cut_start; | |
538 | end = scp->mouse_cut_end; | |
539 | } else { | |
540 | start = scp->mouse_cut_end; | |
541 | end = scp->mouse_cut_start - 1; | |
542 | } | |
6bc31f17 | 543 | crit_enter(); |
984263bc MD |
544 | if (scp->mouse_pos > end) { |
545 | scp->mouse_cut_start = start; | |
546 | scp->mouse_cut_end = end; | |
547 | } else if (scp->mouse_pos < start) { | |
548 | scp->mouse_cut_start = end + 1; | |
549 | scp->mouse_cut_end = start; | |
550 | } else { | |
551 | if (scp->mouse_pos - start > end + 1 - scp->mouse_pos) { | |
552 | scp->mouse_cut_start = start; | |
553 | scp->mouse_cut_end = end; | |
554 | } else { | |
555 | scp->mouse_cut_start = end + 1; | |
556 | scp->mouse_cut_end = start; | |
557 | } | |
558 | } | |
6bc31f17 | 559 | crit_exit(); |
984263bc MD |
560 | mouse_cut(scp); |
561 | scp->status |= MOUSE_CUTTING; | |
562 | } | |
563 | } | |
564 | ||
565 | /* paste cut buffer contents into the current vty */ | |
566 | static void | |
567 | mouse_paste(scr_stat *scp) | |
568 | { | |
569 | if (scp->status & MOUSE_VISIBLE) | |
570 | sc_paste(scp, cut_buffer, strlen(cut_buffer)); | |
571 | } | |
572 | ||
573 | #endif /* SC_NO_CUTPASTE */ | |
574 | ||
c3ab84cc VS |
575 | static void |
576 | sc_mouse_exit1_proc(struct proc *p) | |
577 | { | |
578 | scr_stat *scp; | |
579 | ||
580 | scp = p->p_drv_priv; | |
581 | KKASSERT(scp != NULL); | |
582 | ||
481d12aa | 583 | lwkt_gettoken(&scmouse_tok); |
c3ab84cc VS |
584 | KKASSERT(scp->mouse_proc == p); |
585 | KKASSERT(scp->mouse_pid == p->p_pid); | |
586 | ||
587 | scp->mouse_signal = 0; | |
588 | scp->mouse_proc = NULL; | |
589 | scp->mouse_pid = 0; | |
481d12aa | 590 | lwkt_reltoken(&scmouse_tok); |
c3ab84cc VS |
591 | |
592 | PRELE(p); | |
593 | p->p_flags &= ~P_SCMOUSE; | |
594 | p->p_drv_priv = NULL; | |
595 | } | |
596 | ||
597 | /* | |
598 | * sc_mouse_exit1: | |
599 | * | |
600 | * Handle exit1 for processes registered as MOUSE_MODE handlers. | |
601 | * We must remove a process hold, established when MOUSE_MODE | |
602 | * was enabled. | |
603 | */ | |
604 | static void | |
605 | sc_mouse_exit1(struct thread *td) | |
606 | { | |
607 | struct proc *p; | |
608 | ||
609 | p = td->td_proc; | |
610 | KKASSERT(p != NULL); | |
611 | ||
612 | if ((p->p_flags & P_SCMOUSE) == 0) | |
613 | return; | |
614 | ||
615 | ||
616 | sc_mouse_exit1_proc(p); | |
617 | } | |
618 | ||
984263bc | 619 | int |
fef8985e | 620 | sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag) |
984263bc MD |
621 | { |
622 | mouse_info_t *mouse; | |
984263bc MD |
623 | scr_stat *cur_scp; |
624 | scr_stat *scp; | |
984263bc MD |
625 | int f; |
626 | ||
627 | scp = SC_STAT(tp->t_dev); | |
628 | ||
629 | switch (cmd) { | |
630 | ||
631 | case CONS_MOUSECTL: /* control mouse arrow */ | |
c3ab84cc | 632 | mouse = (mouse_info_t*) data; |
984263bc MD |
633 | cur_scp = scp->sc->cur_scp; |
634 | ||
635 | switch (mouse->operation) { | |
c3ab84cc VS |
636 | /* |
637 | * Setup a process to receive signals on mouse events. | |
638 | */ | |
984263bc | 639 | case MOUSE_MODE: |
481d12aa | 640 | lwkt_gettoken(&scmouse_tok); |
c3ab84cc VS |
641 | |
642 | if (!ISSIGVALID(mouse->u.mode.signal)) { | |
643 | /* Setting MOUSE_MODE w/ an invalid signal is used to disarm */ | |
644 | if (scp->mouse_proc == curproc) { | |
645 | sc_mouse_exit1_proc(curproc); | |
481d12aa | 646 | lwkt_reltoken(&scmouse_tok); |
c3ab84cc VS |
647 | return 0; |
648 | } else { | |
481d12aa | 649 | lwkt_reltoken(&scmouse_tok); |
c3ab84cc VS |
650 | return EINVAL; |
651 | } | |
58c2553a | 652 | } else { |
c3ab84cc VS |
653 | /* Only one mouse process per syscons */ |
654 | if (scp->mouse_proc) { | |
481d12aa | 655 | lwkt_reltoken(&scmouse_tok); |
c3ab84cc VS |
656 | return EINVAL; |
657 | } | |
658 | ||
659 | /* Only one syscons signal source per process */ | |
660 | if (curproc->p_flags & P_SCMOUSE) { | |
481d12aa | 661 | lwkt_reltoken(&scmouse_tok); |
c3ab84cc VS |
662 | return EINVAL; |
663 | } | |
664 | ||
665 | /* | |
666 | * Process is stabilized by a hold, which is removed from | |
667 | * sc_mouse_exit1. scp's mouse_{signal,proc,pid} fields | |
668 | * are synchronized by the MP Lock. | |
669 | */ | |
670 | scp->mouse_signal = mouse->u.mode.signal; | |
671 | scp->mouse_proc = curproc; | |
672 | scp->mouse_pid = curproc->p_pid; | |
673 | curproc->p_flags |= P_SCMOUSE; | |
674 | KKASSERT(curproc->p_drv_priv == NULL); | |
675 | curproc->p_drv_priv = scp; | |
676 | PHOLD(curproc); | |
677 | ||
481d12aa | 678 | lwkt_reltoken(&scmouse_tok); |
c3ab84cc VS |
679 | return 0; |
680 | } | |
681 | /*NOTREACHED*/ | |
682 | break; | |
984263bc MD |
683 | |
684 | case MOUSE_SHOW: | |
6bc31f17 | 685 | crit_enter(); |
984263bc MD |
686 | if (!(scp->sc->flags & SC_MOUSE_ENABLED)) { |
687 | scp->sc->flags |= SC_MOUSE_ENABLED; | |
688 | cur_scp->status &= ~MOUSE_HIDDEN; | |
689 | if (!ISGRAPHSC(cur_scp)) | |
690 | mark_all(cur_scp); | |
6bc31f17 | 691 | crit_exit(); |
984263bc MD |
692 | return 0; |
693 | } else { | |
6bc31f17 | 694 | crit_exit(); |
984263bc MD |
695 | return EINVAL; |
696 | } | |
697 | break; | |
698 | ||
699 | case MOUSE_HIDE: | |
6bc31f17 | 700 | crit_enter(); |
984263bc MD |
701 | if (scp->sc->flags & SC_MOUSE_ENABLED) { |
702 | scp->sc->flags &= ~SC_MOUSE_ENABLED; | |
703 | sc_remove_all_mouse(scp->sc); | |
6bc31f17 | 704 | crit_exit(); |
984263bc MD |
705 | return 0; |
706 | } else { | |
6bc31f17 | 707 | crit_exit(); |
984263bc MD |
708 | return EINVAL; |
709 | } | |
710 | break; | |
711 | ||
712 | case MOUSE_MOVEABS: | |
6bc31f17 | 713 | crit_enter(); |
984263bc MD |
714 | scp->mouse_xpos = mouse->u.data.x; |
715 | scp->mouse_ypos = mouse->u.data.y; | |
716 | set_mouse_pos(scp); | |
6bc31f17 | 717 | crit_exit(); |
984263bc MD |
718 | break; |
719 | ||
720 | case MOUSE_MOVEREL: | |
6bc31f17 | 721 | crit_enter(); |
984263bc MD |
722 | scp->mouse_xpos += mouse->u.data.x; |
723 | scp->mouse_ypos += mouse->u.data.y; | |
724 | set_mouse_pos(scp); | |
6bc31f17 | 725 | crit_exit(); |
984263bc MD |
726 | break; |
727 | ||
728 | case MOUSE_GETINFO: | |
729 | mouse->u.data.x = scp->mouse_xpos; | |
730 | mouse->u.data.y = scp->mouse_ypos; | |
731 | mouse->u.data.z = 0; | |
732 | mouse->u.data.buttons = scp->mouse_buttons; | |
733 | return 0; | |
734 | ||
735 | case MOUSE_ACTION: | |
736 | case MOUSE_MOTION_EVENT: | |
737 | /* send out mouse event on /dev/sysmouse */ | |
738 | #if 0 | |
739 | /* this should maybe only be settable from /dev/consolectl SOS */ | |
740 | if (SC_VTY(tp->t_dev) != SC_CONSOLECTL) | |
741 | return ENOTTY; | |
742 | #endif | |
6bc31f17 | 743 | crit_enter(); |
984263bc MD |
744 | if (mouse->u.data.x != 0 || mouse->u.data.y != 0) { |
745 | cur_scp->mouse_xpos += mouse->u.data.x; | |
746 | cur_scp->mouse_ypos += mouse->u.data.y; | |
747 | set_mouse_pos(cur_scp); | |
748 | } | |
749 | f = 0; | |
750 | if (mouse->operation == MOUSE_ACTION) { | |
751 | f = cur_scp->mouse_buttons ^ mouse->u.data.buttons; | |
752 | cur_scp->mouse_buttons = mouse->u.data.buttons; | |
753 | } | |
6bc31f17 | 754 | crit_exit(); |
984263bc MD |
755 | |
756 | if (sysmouse_event(mouse) == 0) | |
757 | return 0; | |
758 | ||
759 | /* | |
760 | * If any buttons are down or the mouse has moved a lot, | |
761 | * stop the screen saver. | |
762 | */ | |
763 | if (((mouse->operation == MOUSE_ACTION) && mouse->u.data.buttons) | |
764 | || (mouse->u.data.x*mouse->u.data.x | |
765 | + mouse->u.data.y*mouse->u.data.y | |
766 | >= SC_WAKEUP_DELTA*SC_WAKEUP_DELTA)) { | |
767 | sc_touch_scrn_saver(); | |
768 | } | |
769 | ||
770 | cur_scp->status &= ~MOUSE_HIDDEN; | |
771 | ||
481d12aa | 772 | lwkt_gettoken(&scmouse_tok); |
984263bc | 773 | if (cur_scp->mouse_signal) { |
c3ab84cc VS |
774 | KKASSERT(cur_scp->mouse_proc != NULL); |
775 | ksignal(cur_scp->mouse_proc, cur_scp->mouse_signal); | |
481d12aa | 776 | lwkt_reltoken(&scmouse_tok); |
c3ab84cc | 777 | break; |
984263bc | 778 | } |
481d12aa | 779 | lwkt_reltoken(&scmouse_tok); |
984263bc MD |
780 | |
781 | if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL)) | |
782 | break; | |
783 | ||
784 | #ifndef SC_NO_CUTPASTE | |
785 | if ((mouse->operation == MOUSE_ACTION) && f) { | |
786 | /* process button presses */ | |
787 | if (cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN) | |
788 | mouse_cut_start(cur_scp); | |
789 | else | |
790 | mouse_cut_end(cur_scp); | |
791 | if (cur_scp->mouse_buttons & MOUSE_BUTTON2DOWN || | |
792 | cur_scp->mouse_buttons & MOUSE_BUTTON3DOWN) | |
793 | mouse_paste(cur_scp); | |
794 | } | |
795 | #endif /* SC_NO_CUTPASTE */ | |
796 | break; | |
797 | ||
798 | case MOUSE_BUTTON_EVENT: | |
799 | if ((mouse->u.event.id & MOUSE_BUTTONS) == 0) | |
800 | return EINVAL; | |
801 | if (mouse->u.event.value < 0) | |
802 | return EINVAL; | |
803 | #if 0 | |
804 | /* this should maybe only be settable from /dev/consolectl SOS */ | |
805 | if (SC_VTY(tp->t_dev) != SC_CONSOLECTL) | |
806 | return ENOTTY; | |
807 | #endif | |
808 | if (mouse->u.event.value > 0) | |
809 | cur_scp->mouse_buttons |= mouse->u.event.id; | |
810 | else | |
811 | cur_scp->mouse_buttons &= ~mouse->u.event.id; | |
812 | ||
813 | if (sysmouse_event(mouse) == 0) | |
814 | return 0; | |
815 | ||
816 | /* if a button is held down, stop the screen saver */ | |
817 | if (mouse->u.event.value > 0) | |
818 | sc_touch_scrn_saver(); | |
819 | ||
820 | cur_scp->status &= ~MOUSE_HIDDEN; | |
821 | ||
481d12aa | 822 | lwkt_gettoken(&scmouse_tok); |
984263bc | 823 | if (cur_scp->mouse_signal) { |
c3ab84cc VS |
824 | KKASSERT(cur_scp->mouse_proc != NULL); |
825 | ksignal(cur_scp->mouse_proc, cur_scp->mouse_signal); | |
481d12aa | 826 | lwkt_reltoken(&scmouse_tok); |
c3ab84cc | 827 | break; |
984263bc | 828 | } |
481d12aa | 829 | lwkt_reltoken(&scmouse_tok); |
984263bc MD |
830 | |
831 | if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL)) | |
832 | break; | |
833 | ||
834 | #ifndef SC_NO_CUTPASTE | |
835 | switch (mouse->u.event.id) { | |
836 | case MOUSE_BUTTON1DOWN: | |
837 | switch (mouse->u.event.value % 4) { | |
838 | case 0: /* up */ | |
839 | mouse_cut_end(cur_scp); | |
840 | break; | |
841 | case 1: /* single click: start cut operation */ | |
842 | mouse_cut_start(cur_scp); | |
843 | break; | |
844 | case 2: /* double click: cut a word */ | |
845 | mouse_cut_word(cur_scp); | |
846 | mouse_cut_end(cur_scp); | |
847 | break; | |
848 | case 3: /* triple click: cut a line */ | |
849 | mouse_cut_line(cur_scp); | |
850 | mouse_cut_end(cur_scp); | |
851 | break; | |
852 | } | |
853 | break; | |
854 | case SC_MOUSE_PASTEBUTTON: | |
855 | switch (mouse->u.event.value) { | |
856 | case 0: /* up */ | |
857 | break; | |
858 | default: | |
859 | mouse_paste(cur_scp); | |
860 | break; | |
861 | } | |
862 | break; | |
863 | case SC_MOUSE_EXTENDBUTTON: | |
864 | switch (mouse->u.event.value) { | |
865 | case 0: /* up */ | |
866 | if (!(cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN)) | |
867 | mouse_cut_end(cur_scp); | |
868 | break; | |
869 | default: | |
870 | mouse_cut_extend(cur_scp); | |
871 | break; | |
872 | } | |
873 | break; | |
874 | } | |
875 | #endif /* SC_NO_CUTPASTE */ | |
876 | break; | |
877 | ||
878 | case MOUSE_MOUSECHAR: | |
879 | if (mouse->u.mouse_char < 0) { | |
880 | mouse->u.mouse_char = scp->sc->mouse_char; | |
881 | } else { | |
1f2de5d4 | 882 | if (mouse->u.mouse_char >= (unsigned char)-1 - 4) |
984263bc | 883 | return EINVAL; |
6bc31f17 | 884 | crit_enter(); |
984263bc MD |
885 | sc_remove_all_mouse(scp->sc); |
886 | #ifndef SC_NO_FONT_LOADING | |
887 | if (ISTEXTSC(cur_scp) && (cur_scp->font != NULL)) | |
219917ca SW |
888 | sc_load_font(cur_scp, 0, cur_scp->font_height, |
889 | cur_scp->font, | |
984263bc MD |
890 | cur_scp->sc->mouse_char, 4); |
891 | #endif | |
892 | scp->sc->mouse_char = mouse->u.mouse_char; | |
6bc31f17 | 893 | crit_exit(); |
984263bc MD |
894 | } |
895 | break; | |
896 | ||
897 | default: | |
898 | return EINVAL; | |
899 | } | |
900 | ||
901 | return 0; | |
902 | } | |
903 | ||
904 | return ENOIOCTL; | |
905 | } | |
906 | ||
c3ab84cc VS |
907 | void |
908 | sc_mouse_init(void *unused) | |
909 | { | |
910 | at_exit(sc_mouse_exit1); | |
911 | } | |
912 | ||
913 | void | |
914 | sc_mouse_uninit(void *unused) | |
915 | { | |
916 | } | |
917 | ||
918 | SYSINIT(sc_mouse_init, SI_SUB_DRIVERS, SI_ORDER_ANY, sc_mouse_init, NULL); | |
919 | SYSUNINIT(sc_mouse_uninit, SI_SUB_DRIVERS, SI_ORDER_ANY, sc_mouse_uninit, NULL); | |
920 | ||
984263bc | 921 | #endif /* SC_NO_SYSMOUSE */ |