iwm: Fix S:N reporting in ifconfig(8)
[dragonfly.git] / sys / dev / misc / syscons / scmouse.c
CommitLineData
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
57static int cut_buffer_size;
58static u_char *cut_buffer;
59
60/* local functions */
c3ab84cc
VS
61static void sc_mouse_init(void *);
62static void sc_mouse_uninit(void *);
63
984263bc
MD
64static void set_mouse_pos(scr_stat *scp);
65#ifndef SC_NO_CUTPASTE
66static int skip_spc_right(scr_stat *scp, int p);
67static int skip_spc_left(scr_stat *scp, int p);
68static void mouse_cut(scr_stat *scp);
69static void mouse_cut_start(scr_stat *scp);
70static void mouse_cut_end(scr_stat *scp);
71static void mouse_cut_word(scr_stat *scp);
72static void mouse_cut_line(scr_stat *scp);
73static void mouse_cut_extend(scr_stat *scp);
74static void mouse_paste(scr_stat *scp);
75#endif /* SC_NO_CUTPASTE */
76
481d12aa
MD
77static struct lwkt_token scmouse_tok = LWKT_TOKEN_INITIALIZER(scmouse_tok);
78
984263bc
MD
79#ifndef SC_NO_CUTPASTE
80/* allocate a cut buffer */
81void
82sc_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 */
102void
103sc_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 */
119static void
120set_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
154void
155sc_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
169void
170sc_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
200int
201sc_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
218void
219sc_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
232void
233sc_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
247void
248sc_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 */
267static int
268skip_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 */
283static int
284skip_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 */
299static void
300mouse_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 */
369static void
370mouse_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 */
406static void
407mouse_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 */
414static void
415mouse_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 */
494static void
495mouse_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 */
528static void
529mouse_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 */
566static void
567mouse_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
575static void
576sc_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 */
604static void
605sc_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 619int
fef8985e 620sc_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
907void
908sc_mouse_init(void *unused)
909{
910 at_exit(sc_mouse_exit1);
911}
912
913void
914sc_mouse_uninit(void *unused)
915{
916}
917
918SYSINIT(sc_mouse_init, SI_SUB_DRIVERS, SI_ORDER_ANY, sc_mouse_init, NULL);
919SYSUNINIT(sc_mouse_uninit, SI_SUB_DRIVERS, SI_ORDER_ANY, sc_mouse_uninit, NULL);
920
984263bc 921#endif /* SC_NO_SYSMOUSE */