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