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