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