]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/dev/syscons/scmouse.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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, struct thread *td)
609 {
610     mouse_info_t *mouse;
611     mouse_info_t buf;
612     scr_stat *cur_scp;
613     scr_stat *scp;
614     struct proc *p1;
615     int s;
616     int f;
617
618     scp = SC_STAT(tp);
619
620     switch (cmd) {
621
622     case CONS_MOUSECTL:         /* control mouse arrow */
623     case OLD_CONS_MOUSECTL:
624
625         mouse = (mouse_info_t*)data;
626
627         random_harvest(mouse, sizeof(mouse_info_t), 2, 0, RANDOM_MOUSE);
628
629         if (cmd == OLD_CONS_MOUSECTL) {
630             static u_char swapb[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
631             old_mouse_info_t *old_mouse = (old_mouse_info_t *)data;
632
633             mouse = &buf;
634             mouse->operation = old_mouse->operation;
635             switch (mouse->operation) {
636             case MOUSE_MODE:
637                 mouse->u.mode = old_mouse->u.mode;
638                 break;
639             case MOUSE_SHOW:
640             case MOUSE_HIDE:
641                 break;
642             case MOUSE_MOVEABS:
643             case MOUSE_MOVEREL:
644             case MOUSE_ACTION:
645                 mouse->u.data.x = old_mouse->u.data.x;
646                 mouse->u.data.y = old_mouse->u.data.y;
647                 mouse->u.data.z = 0;
648                 mouse->u.data.buttons = swapb[old_mouse->u.data.buttons & 0x7];
649                 break;
650             case MOUSE_GETINFO:
651                 old_mouse->u.data.x = scp->mouse_xpos;
652                 old_mouse->u.data.y = scp->mouse_ypos;
653                 old_mouse->u.data.buttons = swapb[scp->mouse_buttons & 0x7];
654                 return 0;
655             default:
656                 return EINVAL;
657             }
658         }
659
660         cur_scp = scp->sc->cur_scp;
661
662         switch (mouse->operation) {
663         case MOUSE_MODE:
664             if (ISSIGVALID(mouse->u.mode.signal)) {
665                 scp->mouse_signal = mouse->u.mode.signal;
666                 scp->mouse_proc = td->td_proc;
667                 scp->mouse_pid = td->td_proc->p_pid;
668             }
669             else {
670                 scp->mouse_signal = 0;
671                 scp->mouse_proc = NULL;
672                 scp->mouse_pid = 0;
673             }
674             return 0;
675
676         case MOUSE_SHOW:
677             s = spltty();
678             if (!(scp->sc->flags & SC_MOUSE_ENABLED)) {
679                 scp->sc->flags |= SC_MOUSE_ENABLED;
680                 cur_scp->status &= ~MOUSE_HIDDEN;
681                 if (!ISGRAPHSC(cur_scp))
682                     mark_all(cur_scp);
683             }
684             splx(s);
685             return 0;
686             /* NOTREACHED */
687
688         case MOUSE_HIDE:
689             s = spltty();
690             if (scp->sc->flags & SC_MOUSE_ENABLED) {
691                 scp->sc->flags &= ~SC_MOUSE_ENABLED;
692                 sc_remove_all_mouse(scp->sc);
693             }
694             splx(s);
695             return 0;
696             /* NOTREACHED */
697
698         case MOUSE_MOVEABS:
699             s = spltty();
700             scp->mouse_xpos = mouse->u.data.x;
701             scp->mouse_ypos = mouse->u.data.y;
702             set_mouse_pos(scp);
703             splx(s);
704             break;
705
706         case MOUSE_MOVEREL:
707             s = spltty();
708             scp->mouse_xpos += mouse->u.data.x;
709             scp->mouse_ypos += mouse->u.data.y;
710             set_mouse_pos(scp);
711             splx(s);
712             break;
713
714         case MOUSE_GETINFO:
715             mouse->u.data.x = scp->mouse_xpos;
716             mouse->u.data.y = scp->mouse_ypos;
717             mouse->u.data.z = 0;
718             mouse->u.data.buttons = scp->mouse_buttons;
719             return 0;
720
721         case MOUSE_ACTION:
722         case MOUSE_MOTION_EVENT:
723             /* send out mouse event on /dev/sysmouse */
724 #if 0
725             /* this should maybe only be settable from /dev/consolectl SOS */
726             if (SC_VTY(tp->t_dev) != SC_CONSOLECTL)
727                 return ENOTTY;
728 #endif
729             s = spltty();
730             if (mouse->u.data.x != 0 || mouse->u.data.y != 0) {
731                 cur_scp->mouse_xpos += mouse->u.data.x;
732                 cur_scp->mouse_ypos += mouse->u.data.y;
733                 set_mouse_pos(cur_scp);
734             }
735             f = 0;
736             if (mouse->operation == MOUSE_ACTION) {
737                 f = cur_scp->mouse_buttons ^ mouse->u.data.buttons;
738                 cur_scp->mouse_buttons = mouse->u.data.buttons;
739             }
740             splx(s);
741
742             if (sysmouse_event(mouse) == 0)
743                 return 0;
744
745             /* 
746              * If any buttons are down or the mouse has moved a lot, 
747              * stop the screen saver.
748              */
749             if (((mouse->operation == MOUSE_ACTION) && mouse->u.data.buttons)
750                 || (mouse->u.data.x*mouse->u.data.x
751                         + mouse->u.data.y*mouse->u.data.y
752                         >= SC_WAKEUP_DELTA*SC_WAKEUP_DELTA)) {
753                 sc_touch_scrn_saver();
754             }
755
756             cur_scp->status &= ~MOUSE_HIDDEN;
757
758             if (cur_scp->mouse_signal && cur_scp->mouse_proc) {
759                 /* has controlling process died? */
760                 if (cur_scp->mouse_proc != (p1 = pfind(cur_scp->mouse_pid))) {
761                         cur_scp->mouse_signal = 0;
762                         cur_scp->mouse_proc = NULL;
763                         cur_scp->mouse_pid = 0;
764                         if (p1)
765                             PROC_UNLOCK(p1);
766                 } else {
767                     psignal(cur_scp->mouse_proc, cur_scp->mouse_signal);
768                     PROC_UNLOCK(cur_scp->mouse_proc);
769                     break;
770                 }
771             }
772
773 #ifndef SC_NO_CUTPASTE
774             if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL))
775                 break;
776
777             if ((mouse->operation == MOUSE_ACTION) && f) {
778                 /* process button presses */
779                 if (cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN)
780                     mouse_cut_start(cur_scp);
781                 else
782                     mouse_cut_end(cur_scp);
783                 if (cur_scp->mouse_buttons & MOUSE_BUTTON2DOWN ||
784                     cur_scp->mouse_buttons & MOUSE_BUTTON3DOWN)
785                     sc_mouse_paste(cur_scp);
786             }
787 #endif /* SC_NO_CUTPASTE */
788             break;
789
790         case MOUSE_BUTTON_EVENT:
791             if ((mouse->u.event.id & MOUSE_BUTTONS) == 0)
792                 return EINVAL;
793             if (mouse->u.event.value < 0)
794                 return EINVAL;
795 #if 0
796             /* this should maybe only be settable from /dev/consolectl SOS */
797             if (SC_VTY(tp->t_dev) != SC_CONSOLECTL)
798                 return ENOTTY;
799 #endif
800             if (mouse->u.event.value > 0)
801                 cur_scp->mouse_buttons |= mouse->u.event.id;
802             else
803                 cur_scp->mouse_buttons &= ~mouse->u.event.id;
804
805             if (sysmouse_event(mouse) == 0)
806                 return 0;
807
808             /* if a button is held down, stop the screen saver */
809             if (mouse->u.event.value > 0)
810                 sc_touch_scrn_saver();
811
812             cur_scp->status &= ~MOUSE_HIDDEN;
813
814             if (cur_scp->mouse_signal && cur_scp->mouse_proc) {
815                 if (cur_scp->mouse_proc != (p1 = pfind(cur_scp->mouse_pid))){
816                         cur_scp->mouse_signal = 0;
817                         cur_scp->mouse_proc = NULL;
818                         cur_scp->mouse_pid = 0;
819                         if (p1)
820                             PROC_UNLOCK(p1);
821                 } else {
822                     psignal(cur_scp->mouse_proc, cur_scp->mouse_signal);
823                     PROC_UNLOCK(cur_scp->mouse_proc);
824                     break;
825                 }
826             }
827
828 #ifndef SC_NO_CUTPASTE
829             if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL))
830                 break;
831
832             switch (mouse->u.event.id) {
833             case MOUSE_BUTTON1DOWN:
834                 switch (mouse->u.event.value % 4) {
835                 case 0: /* up */
836                     mouse_cut_end(cur_scp);
837                     break;
838                 case 1: /* single click: start cut operation */
839                     mouse_cut_start(cur_scp);
840                     break;
841                 case 2: /* double click: cut a word */
842                     mouse_cut_word(cur_scp);
843                     mouse_cut_end(cur_scp);
844                     break;
845                 case 3: /* triple click: cut a line */
846                     mouse_cut_line(cur_scp);
847                     mouse_cut_end(cur_scp);
848                     break;
849                 }
850                 break;
851             case SC_MOUSE_PASTEBUTTON:
852                 switch (mouse->u.event.value) {
853                 case 0: /* up */
854                     break;
855                 default:
856                     sc_mouse_paste(cur_scp);
857                     break;
858                 }
859                 break;
860             case SC_MOUSE_EXTENDBUTTON:
861                 switch (mouse->u.event.value) {
862                 case 0: /* up */
863                     if (!(cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN))
864                         mouse_cut_end(cur_scp);
865                     break;
866                 default:
867                     mouse_cut_extend(cur_scp);
868                     break;
869                 }
870                 break;
871             }
872 #endif /* SC_NO_CUTPASTE */
873             break;
874
875         case MOUSE_MOUSECHAR:
876             if (mouse->u.mouse_char < 0) {
877                 mouse->u.mouse_char = scp->sc->mouse_char;
878             } else {
879                 if (mouse->u.mouse_char > UCHAR_MAX - 3)
880                     return EINVAL;
881                 s = spltty();
882                 sc_remove_all_mouse(scp->sc);
883 #ifndef SC_NO_FONT_LOADING
884                 if (ISTEXTSC(cur_scp) && (cur_scp->font != NULL))
885                     sc_load_font(cur_scp, 0, cur_scp->font_size,
886                                  cur_scp->font_width,
887                                  cur_scp->font + cur_scp->font_size
888                                  * cur_scp->sc->mouse_char,
889                                  cur_scp->sc->mouse_char, 4);
890 #endif
891                 scp->sc->mouse_char = mouse->u.mouse_char;
892                 splx(s);
893             }
894             break;
895
896         default:
897             return EINVAL;
898         }
899
900         return 0;
901     }
902
903     return ENOIOCTL;
904 }
905
906 #endif /* SC_NO_SYSMOUSE */