b7c96c0d0b
and do some preparations for handling 12x22 fonts (currently lots of code implies and/or hardcodes a font width of 8 pixels). This will be required on sparc64 which uses a default font size of 12x22 in order to add font loading and saving support as well as to use a syscons(4)-supplied mouse pointer image. This API breakage is committed now so it can be MFC'ed in time for 6.0 and later on upcoming framebuffer drivers destined for use on sparc64 and which are expected to rely on using font loading internally and on a syscons(4)-supplied mouse pointer image can be easily MFC'ed to RELENG_6 rather than requiring a backport. Tested on: i386, sparc64, make universe MFC after: 1 week
907 lines
22 KiB
C
907 lines
22 KiB
C
/*-
|
|
* Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer as
|
|
* the first lines of this file unmodified.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include "opt_syscons.h"
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/consio.h>
|
|
#include <sys/fbio.h>
|
|
#include <sys/limits.h>
|
|
#include <sys/lock.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/mouse.h>
|
|
#include <sys/mutex.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/random.h>
|
|
#include <sys/signalvar.h>
|
|
#include <sys/tty.h>
|
|
|
|
#include <dev/syscons/syscons.h>
|
|
|
|
#ifdef SC_TWOBUTTON_MOUSE
|
|
#define SC_MOUSE_PASTEBUTTON MOUSE_BUTTON3DOWN /* right button */
|
|
#define SC_MOUSE_EXTENDBUTTON MOUSE_BUTTON2DOWN /* not really used */
|
|
#else
|
|
#define SC_MOUSE_PASTEBUTTON MOUSE_BUTTON2DOWN /* middle button */
|
|
#define SC_MOUSE_EXTENDBUTTON MOUSE_BUTTON3DOWN /* right button */
|
|
#endif /* SC_TWOBUTTON_MOUSE */
|
|
|
|
#define SC_WAKEUP_DELTA 20
|
|
|
|
/* for backward compatibility */
|
|
#define OLD_CONS_MOUSECTL _IOWR('c', 10, old_mouse_info_t)
|
|
|
|
typedef struct old_mouse_data {
|
|
int x;
|
|
int y;
|
|
int buttons;
|
|
} old_mouse_data_t;
|
|
|
|
typedef struct old_mouse_info {
|
|
int operation;
|
|
union {
|
|
struct old_mouse_data data;
|
|
struct mouse_mode mode;
|
|
} u;
|
|
} old_mouse_info_t;
|
|
|
|
#ifndef SC_NO_SYSMOUSE
|
|
|
|
/* local variables */
|
|
#ifndef SC_NO_CUTPASTE
|
|
static int cut_buffer_size;
|
|
static u_char *cut_buffer;
|
|
#endif
|
|
|
|
/* local functions */
|
|
static void set_mouse_pos(scr_stat *scp);
|
|
#ifndef SC_NO_CUTPASTE
|
|
static int skip_spc_right(scr_stat *scp, int p);
|
|
static int skip_spc_left(scr_stat *scp, int p);
|
|
static void mouse_cut(scr_stat *scp);
|
|
static void mouse_cut_start(scr_stat *scp);
|
|
static void mouse_cut_end(scr_stat *scp);
|
|
static void mouse_cut_word(scr_stat *scp);
|
|
static void mouse_cut_line(scr_stat *scp);
|
|
static void mouse_cut_extend(scr_stat *scp);
|
|
#endif /* SC_NO_CUTPASTE */
|
|
|
|
#ifndef SC_NO_CUTPASTE
|
|
/* allocate a cut buffer */
|
|
void
|
|
sc_alloc_cut_buffer(scr_stat *scp, int wait)
|
|
{
|
|
u_char *p;
|
|
|
|
if ((cut_buffer == NULL)
|
|
|| (cut_buffer_size < scp->xsize * scp->ysize + 1)) {
|
|
p = cut_buffer;
|
|
cut_buffer = NULL;
|
|
if (p != NULL)
|
|
free(p, M_DEVBUF);
|
|
cut_buffer_size = scp->xsize * scp->ysize + 1;
|
|
p = (u_char *)malloc(cut_buffer_size,
|
|
M_DEVBUF, (wait) ? M_WAITOK : M_NOWAIT);
|
|
if (p != NULL)
|
|
p[0] = '\0';
|
|
cut_buffer = p;
|
|
}
|
|
}
|
|
#endif /* SC_NO_CUTPASTE */
|
|
|
|
/* move mouse */
|
|
void
|
|
sc_mouse_move(scr_stat *scp, int x, int y)
|
|
{
|
|
int s;
|
|
|
|
s = spltty();
|
|
scp->mouse_xpos = scp->mouse_oldxpos = x;
|
|
scp->mouse_ypos = scp->mouse_oldypos = y;
|
|
if (scp->font_size <= 0 || scp->font_width <= 0)
|
|
scp->mouse_pos = scp->mouse_oldpos = 0;
|
|
else
|
|
scp->mouse_pos = scp->mouse_oldpos =
|
|
(y/scp->font_size - scp->yoff)*scp->xsize + x/scp->font_width -
|
|
scp->xoff;
|
|
scp->status |= MOUSE_MOVED;
|
|
splx(s);
|
|
}
|
|
|
|
/* adjust mouse position */
|
|
static void
|
|
set_mouse_pos(scr_stat *scp)
|
|
{
|
|
if (scp->mouse_xpos < scp->xoff*scp->font_width)
|
|
scp->mouse_xpos = scp->xoff*scp->font_width;
|
|
if (scp->mouse_ypos < scp->yoff*scp->font_size)
|
|
scp->mouse_ypos = scp->yoff*scp->font_size;
|
|
if (ISGRAPHSC(scp)) {
|
|
if (scp->mouse_xpos > scp->xpixel-1)
|
|
scp->mouse_xpos = scp->xpixel-1;
|
|
if (scp->mouse_ypos > scp->ypixel-1)
|
|
scp->mouse_ypos = scp->ypixel-1;
|
|
return;
|
|
} else {
|
|
if (scp->mouse_xpos > (scp->xsize + scp->xoff)*scp->font_width - 1)
|
|
scp->mouse_xpos = (scp->xsize + scp->xoff)*scp->font_width - 1;
|
|
if (scp->mouse_ypos > (scp->ysize + scp->yoff)*scp->font_size - 1)
|
|
scp->mouse_ypos = (scp->ysize + scp->yoff)*scp->font_size - 1;
|
|
}
|
|
|
|
if ((scp->mouse_xpos != scp->mouse_oldxpos || scp->mouse_ypos != scp->mouse_oldypos)
|
|
&& (scp->font_size != 0 && scp->font_width != 0)) {
|
|
scp->status |= MOUSE_MOVED;
|
|
scp->mouse_pos =
|
|
(scp->mouse_ypos/scp->font_size - scp->yoff)*scp->xsize
|
|
+ scp->mouse_xpos/scp->font_width - scp->xoff;
|
|
#ifndef SC_NO_CUTPASTE
|
|
if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING))
|
|
mouse_cut(scp);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#ifndef SC_NO_CUTPASTE
|
|
|
|
void
|
|
sc_draw_mouse_image(scr_stat *scp)
|
|
{
|
|
if (ISGRAPHSC(scp))
|
|
return;
|
|
|
|
++scp->sc->videoio_in_progress;
|
|
(*scp->rndr->draw_mouse)(scp, scp->mouse_xpos, scp->mouse_ypos, TRUE);
|
|
scp->mouse_oldpos = scp->mouse_pos;
|
|
scp->mouse_oldxpos = scp->mouse_xpos;
|
|
scp->mouse_oldypos = scp->mouse_ypos;
|
|
scp->status |= MOUSE_VISIBLE;
|
|
--scp->sc->videoio_in_progress;
|
|
}
|
|
|
|
void
|
|
sc_remove_mouse_image(scr_stat *scp)
|
|
{
|
|
int size;
|
|
int i;
|
|
|
|
if (ISGRAPHSC(scp))
|
|
return;
|
|
|
|
++scp->sc->videoio_in_progress;
|
|
(*scp->rndr->draw_mouse)(scp,
|
|
(scp->mouse_oldpos%scp->xsize + scp->xoff)
|
|
* scp->font_width,
|
|
(scp->mouse_oldpos/scp->xsize + scp->yoff)
|
|
* scp->font_size,
|
|
FALSE);
|
|
size = scp->xsize*scp->ysize;
|
|
i = scp->mouse_oldpos;
|
|
mark_for_update(scp, i);
|
|
mark_for_update(scp, i);
|
|
#ifndef PC98
|
|
if (i + scp->xsize + 1 < size) {
|
|
mark_for_update(scp, i + scp->xsize + 1);
|
|
} else if (i + scp->xsize < size) {
|
|
mark_for_update(scp, i + scp->xsize);
|
|
} else if (i + 1 < size) {
|
|
mark_for_update(scp, i + 1);
|
|
}
|
|
#endif /* PC98 */
|
|
scp->status &= ~MOUSE_VISIBLE;
|
|
--scp->sc->videoio_in_progress;
|
|
}
|
|
|
|
int
|
|
sc_inside_cutmark(scr_stat *scp, int pos)
|
|
{
|
|
int start;
|
|
int end;
|
|
|
|
if (scp->mouse_cut_end < 0)
|
|
return FALSE;
|
|
if (scp->mouse_cut_start <= scp->mouse_cut_end) {
|
|
start = scp->mouse_cut_start;
|
|
end = scp->mouse_cut_end;
|
|
} else {
|
|
start = scp->mouse_cut_end;
|
|
end = scp->mouse_cut_start - 1;
|
|
}
|
|
return ((start <= pos) && (pos <= end));
|
|
}
|
|
|
|
void
|
|
sc_remove_cutmarking(scr_stat *scp)
|
|
{
|
|
int s;
|
|
|
|
s = spltty();
|
|
if (scp->mouse_cut_end >= 0) {
|
|
mark_for_update(scp, scp->mouse_cut_start);
|
|
mark_for_update(scp, scp->mouse_cut_end);
|
|
}
|
|
scp->mouse_cut_start = scp->xsize*scp->ysize;
|
|
scp->mouse_cut_end = -1;
|
|
splx(s);
|
|
scp->status &= ~MOUSE_CUTTING;
|
|
}
|
|
|
|
void
|
|
sc_remove_all_cutmarkings(sc_softc_t *sc)
|
|
{
|
|
scr_stat *scp;
|
|
int i;
|
|
|
|
/* delete cut markings in all vtys */
|
|
for (i = 0; i < sc->vtys; ++i) {
|
|
scp = SC_STAT(sc->dev[i]);
|
|
if (scp == NULL)
|
|
continue;
|
|
sc_remove_cutmarking(scp);
|
|
}
|
|
}
|
|
|
|
void
|
|
sc_remove_all_mouse(sc_softc_t *sc)
|
|
{
|
|
scr_stat *scp;
|
|
int i;
|
|
|
|
for (i = 0; i < sc->vtys; ++i) {
|
|
scp = SC_STAT(sc->dev[i]);
|
|
if (scp == NULL)
|
|
continue;
|
|
if (scp->status & MOUSE_VISIBLE) {
|
|
scp->status &= ~MOUSE_VISIBLE;
|
|
mark_all(scp);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define IS_SPACE_CHAR(c) (((c) & 0xff) == ' ')
|
|
|
|
#ifdef SC_CUT_SPACES2TABS
|
|
#define IS_BLANK_CHAR(c) (((c) & 0xff) == ' ' || ((c) & 0xff) == '\t')
|
|
#else
|
|
#define IS_BLANK_CHAR(c) IS_SPACE_CHAR(c)
|
|
#endif /* SC_CUT_SPACES2TABS */
|
|
|
|
#ifdef SC_CUT_SEPCHARS
|
|
#define IS_SEP_CHAR(c) (index(SC_CUT_SEPCHARS, (c) & 0xff) != NULL)
|
|
#else
|
|
#define IS_SEP_CHAR(c) IS_SPACE_CHAR(c)
|
|
#endif /* SC_CUT_SEPCHARS */
|
|
|
|
/* skip spaces to right */
|
|
static int
|
|
skip_spc_right(scr_stat *scp, int p)
|
|
{
|
|
int c;
|
|
int i;
|
|
|
|
for (i = p % scp->xsize; i < scp->xsize; ++i) {
|
|
c = sc_vtb_getc(&scp->vtb, p);
|
|
if (!IS_SPACE_CHAR(c))
|
|
break;
|
|
++p;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
/* skip spaces to left */
|
|
static int
|
|
skip_spc_left(scr_stat *scp, int p)
|
|
{
|
|
int c;
|
|
int i;
|
|
|
|
for (i = p-- % scp->xsize - 1; i >= 0; --i) {
|
|
c = sc_vtb_getc(&scp->vtb, p);
|
|
if (!IS_SPACE_CHAR(c))
|
|
break;
|
|
--p;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
static void
|
|
mouse_do_cut(scr_stat *scp, int from, int to)
|
|
{
|
|
int blank;
|
|
int i;
|
|
int leadspaces;
|
|
int p;
|
|
int s;
|
|
|
|
for (p = from, i = blank = leadspaces = 0; p <= to; ++p) {
|
|
cut_buffer[i] = sc_vtb_getc(&scp->vtb, p);
|
|
/* Be prepared that sc_vtb_getc() can return '\0' */
|
|
if (cut_buffer[i] == '\0')
|
|
cut_buffer[i] = ' ';
|
|
#ifdef SC_CUT_SPACES2TABS
|
|
if (leadspaces != -1) {
|
|
if (IS_SPACE_CHAR(cut_buffer[i])) {
|
|
leadspaces++;
|
|
/* Check that we are at tabstop position */
|
|
if ((p % scp->xsize) % 8 == 7) {
|
|
i -= leadspaces - 1;
|
|
cut_buffer[i] = '\t';
|
|
leadspaces = 0;
|
|
}
|
|
} else {
|
|
leadspaces = -1;
|
|
}
|
|
}
|
|
#endif /* SC_CUT_SPACES2TABS */
|
|
/* remember the position of the last non-space char */
|
|
if (!IS_BLANK_CHAR(cut_buffer[i]))
|
|
blank = i + 1; /* the first space after the last non-space */
|
|
++i;
|
|
/* trim trailing blank when crossing lines */
|
|
if ((p % scp->xsize) == (scp->xsize - 1)) {
|
|
cut_buffer[blank++] = '\r';
|
|
i = blank;
|
|
leadspaces = 0;
|
|
}
|
|
}
|
|
cut_buffer[i] = '\0';
|
|
|
|
/* remove the current marking */
|
|
s = spltty();
|
|
if (scp->mouse_cut_start <= scp->mouse_cut_end) {
|
|
mark_for_update(scp, scp->mouse_cut_start);
|
|
mark_for_update(scp, scp->mouse_cut_end);
|
|
} else if (scp->mouse_cut_end >= 0) {
|
|
mark_for_update(scp, scp->mouse_cut_end);
|
|
mark_for_update(scp, scp->mouse_cut_start);
|
|
}
|
|
|
|
/* mark the new region */
|
|
scp->mouse_cut_start = from;
|
|
scp->mouse_cut_end = to;
|
|
mark_for_update(scp, from);
|
|
mark_for_update(scp, to);
|
|
splx(s);
|
|
}
|
|
|
|
/* copy marked region to the cut buffer */
|
|
static void
|
|
mouse_cut(scr_stat *scp)
|
|
{
|
|
int start;
|
|
int end;
|
|
int from;
|
|
int to;
|
|
int c;
|
|
int p;
|
|
int s;
|
|
int i;
|
|
|
|
start = scp->mouse_cut_start;
|
|
end = scp->mouse_cut_end;
|
|
if (scp->mouse_pos >= start) {
|
|
from = start;
|
|
to = end = scp->mouse_pos;
|
|
} else {
|
|
from = end = scp->mouse_pos;
|
|
to = start - 1;
|
|
}
|
|
p = to;
|
|
for (i = p % scp->xsize; i < scp->xsize; ++i) {
|
|
c = sc_vtb_getc(&scp->vtb, p);
|
|
if (!IS_SPACE_CHAR(c))
|
|
break;
|
|
++p;
|
|
}
|
|
/* if there is nothing but blank chars, trim them, but mark towards eol */
|
|
if (i == scp->xsize) {
|
|
if (end >= start)
|
|
to = end = p - 1;
|
|
else
|
|
to = start = p;
|
|
}
|
|
mouse_do_cut(scp, from, to);
|
|
s = spltty();
|
|
scp->mouse_cut_start = start;
|
|
scp->mouse_cut_end = end;
|
|
splx(s);
|
|
}
|
|
|
|
/* a mouse button is pressed, start cut operation */
|
|
static void
|
|
mouse_cut_start(scr_stat *scp)
|
|
{
|
|
int i;
|
|
int s;
|
|
|
|
if (scp->status & MOUSE_VISIBLE) {
|
|
sc_remove_all_cutmarkings(scp->sc);
|
|
if (scp->mouse_pos == scp->mouse_cut_start == scp->mouse_cut_end) {
|
|
cut_buffer[0] = '\0';
|
|
return;
|
|
} else if (skip_spc_right(scp, scp->mouse_pos) >= scp->xsize) {
|
|
/* if the pointer is on trailing blank chars, mark towards eol */
|
|
i = skip_spc_left(scp, scp->mouse_pos) + 1;
|
|
s = spltty();
|
|
scp->mouse_cut_start =
|
|
(scp->mouse_pos / scp->xsize) * scp->xsize + i;
|
|
scp->mouse_cut_end =
|
|
(scp->mouse_pos / scp->xsize + 1) * scp->xsize - 1;
|
|
splx(s);
|
|
cut_buffer[0] = '\r';
|
|
} else {
|
|
s = spltty();
|
|
scp->mouse_cut_start = scp->mouse_pos;
|
|
scp->mouse_cut_end = scp->mouse_cut_start;
|
|
splx(s);
|
|
cut_buffer[0] = sc_vtb_getc(&scp->vtb, scp->mouse_cut_start);
|
|
}
|
|
cut_buffer[1] = '\0';
|
|
scp->status |= MOUSE_CUTTING;
|
|
mark_all(scp); /* this is probably overkill XXX */
|
|
}
|
|
}
|
|
|
|
/* end of cut operation */
|
|
static void
|
|
mouse_cut_end(scr_stat *scp)
|
|
{
|
|
if (scp->status & MOUSE_VISIBLE)
|
|
scp->status &= ~MOUSE_CUTTING;
|
|
}
|
|
|
|
/* copy a word under the mouse pointer */
|
|
static void
|
|
mouse_cut_word(scr_stat *scp)
|
|
{
|
|
int start;
|
|
int end;
|
|
int sol;
|
|
int eol;
|
|
int c;
|
|
int j;
|
|
int len;
|
|
|
|
/*
|
|
* Because we don't have locale information in the kernel,
|
|
* we only distinguish space char and non-space chars. Punctuation
|
|
* chars, symbols and other regular chars are all treated alike
|
|
* unless user specified SC_CUT_SEPCHARS in his kernel config file.
|
|
*/
|
|
if (scp->status & MOUSE_VISIBLE) {
|
|
sol = (scp->mouse_pos / scp->xsize) * scp->xsize;
|
|
eol = sol + scp->xsize;
|
|
c = sc_vtb_getc(&scp->vtb, scp->mouse_pos);
|
|
if (IS_SEP_CHAR(c)) {
|
|
/* blank space */
|
|
for (j = scp->mouse_pos; j >= sol; --j) {
|
|
c = sc_vtb_getc(&scp->vtb, j);
|
|
if (!IS_SEP_CHAR(c))
|
|
break;
|
|
}
|
|
start = ++j;
|
|
for (j = scp->mouse_pos; j < eol; ++j) {
|
|
c = sc_vtb_getc(&scp->vtb, j);
|
|
if (!IS_SEP_CHAR(c))
|
|
break;
|
|
}
|
|
end = j - 1;
|
|
} else {
|
|
/* non-space word */
|
|
for (j = scp->mouse_pos; j >= sol; --j) {
|
|
c = sc_vtb_getc(&scp->vtb, j);
|
|
if (IS_SEP_CHAR(c))
|
|
break;
|
|
}
|
|
start = ++j;
|
|
for (j = scp->mouse_pos; j < eol; ++j) {
|
|
c = sc_vtb_getc(&scp->vtb, j);
|
|
if (IS_SEP_CHAR(c))
|
|
break;
|
|
}
|
|
end = j - 1;
|
|
}
|
|
|
|
/* copy the found word */
|
|
mouse_do_cut(scp, start, end);
|
|
len = strlen(cut_buffer);
|
|
if (cut_buffer[len - 1] == '\r')
|
|
cut_buffer[len - 1] = '\0';
|
|
}
|
|
}
|
|
|
|
/* copy a line under the mouse pointer */
|
|
static void
|
|
mouse_cut_line(scr_stat *scp)
|
|
{
|
|
int len;
|
|
int from;
|
|
|
|
if (scp->status & MOUSE_VISIBLE) {
|
|
from = (scp->mouse_pos / scp->xsize) * scp->xsize;
|
|
mouse_do_cut(scp, from, from + scp->xsize - 1);
|
|
len = strlen(cut_buffer);
|
|
if (cut_buffer[len - 1] == '\r')
|
|
cut_buffer[len - 1] = '\0';
|
|
scp->status |= MOUSE_CUTTING;
|
|
}
|
|
}
|
|
|
|
/* extend the marked region to the mouse pointer position */
|
|
static void
|
|
mouse_cut_extend(scr_stat *scp)
|
|
{
|
|
int start;
|
|
int end;
|
|
int s;
|
|
|
|
if ((scp->status & MOUSE_VISIBLE) && !(scp->status & MOUSE_CUTTING)
|
|
&& (scp->mouse_cut_end >= 0)) {
|
|
if (scp->mouse_cut_start <= scp->mouse_cut_end) {
|
|
start = scp->mouse_cut_start;
|
|
end = scp->mouse_cut_end;
|
|
} else {
|
|
start = scp->mouse_cut_end;
|
|
end = scp->mouse_cut_start - 1;
|
|
}
|
|
s = spltty();
|
|
if (scp->mouse_pos > end) {
|
|
scp->mouse_cut_start = start;
|
|
scp->mouse_cut_end = end;
|
|
} else if (scp->mouse_pos < start) {
|
|
scp->mouse_cut_start = end + 1;
|
|
scp->mouse_cut_end = start;
|
|
} else {
|
|
if (scp->mouse_pos - start > end + 1 - scp->mouse_pos) {
|
|
scp->mouse_cut_start = start;
|
|
scp->mouse_cut_end = end;
|
|
} else {
|
|
scp->mouse_cut_start = end + 1;
|
|
scp->mouse_cut_end = start;
|
|
}
|
|
}
|
|
splx(s);
|
|
mouse_cut(scp);
|
|
scp->status |= MOUSE_CUTTING;
|
|
}
|
|
}
|
|
|
|
/* paste cut buffer contents into the current vty */
|
|
void
|
|
sc_mouse_paste(scr_stat *scp)
|
|
{
|
|
sc_paste(scp, cut_buffer, strlen(cut_buffer));
|
|
}
|
|
|
|
#endif /* SC_NO_CUTPASTE */
|
|
|
|
int
|
|
sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
|
|
struct thread *td)
|
|
{
|
|
mouse_info_t *mouse;
|
|
mouse_info_t buf;
|
|
scr_stat *cur_scp;
|
|
scr_stat *scp;
|
|
struct proc *p1;
|
|
int s;
|
|
int f;
|
|
|
|
scp = SC_STAT(tp->t_dev);
|
|
|
|
switch (cmd) {
|
|
|
|
case CONS_MOUSECTL: /* control mouse arrow */
|
|
case OLD_CONS_MOUSECTL:
|
|
|
|
mouse = (mouse_info_t*)data;
|
|
|
|
random_harvest(mouse, sizeof(mouse_info_t), 2, 0, RANDOM_MOUSE);
|
|
|
|
if (cmd == OLD_CONS_MOUSECTL) {
|
|
static u_char swapb[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
|
|
old_mouse_info_t *old_mouse = (old_mouse_info_t *)data;
|
|
|
|
mouse = &buf;
|
|
mouse->operation = old_mouse->operation;
|
|
switch (mouse->operation) {
|
|
case MOUSE_MODE:
|
|
mouse->u.mode = old_mouse->u.mode;
|
|
break;
|
|
case MOUSE_SHOW:
|
|
case MOUSE_HIDE:
|
|
break;
|
|
case MOUSE_MOVEABS:
|
|
case MOUSE_MOVEREL:
|
|
case MOUSE_ACTION:
|
|
mouse->u.data.x = old_mouse->u.data.x;
|
|
mouse->u.data.y = old_mouse->u.data.y;
|
|
mouse->u.data.z = 0;
|
|
mouse->u.data.buttons = swapb[old_mouse->u.data.buttons & 0x7];
|
|
break;
|
|
case MOUSE_GETINFO:
|
|
old_mouse->u.data.x = scp->mouse_xpos;
|
|
old_mouse->u.data.y = scp->mouse_ypos;
|
|
old_mouse->u.data.buttons = swapb[scp->mouse_buttons & 0x7];
|
|
return 0;
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
}
|
|
|
|
cur_scp = scp->sc->cur_scp;
|
|
|
|
switch (mouse->operation) {
|
|
case MOUSE_MODE:
|
|
if (ISSIGVALID(mouse->u.mode.signal)) {
|
|
scp->mouse_signal = mouse->u.mode.signal;
|
|
scp->mouse_proc = td->td_proc;
|
|
scp->mouse_pid = td->td_proc->p_pid;
|
|
}
|
|
else {
|
|
scp->mouse_signal = 0;
|
|
scp->mouse_proc = NULL;
|
|
scp->mouse_pid = 0;
|
|
}
|
|
return 0;
|
|
|
|
case MOUSE_SHOW:
|
|
s = spltty();
|
|
if (!(scp->sc->flags & SC_MOUSE_ENABLED)) {
|
|
scp->sc->flags |= SC_MOUSE_ENABLED;
|
|
cur_scp->status &= ~MOUSE_HIDDEN;
|
|
if (!ISGRAPHSC(cur_scp))
|
|
mark_all(cur_scp);
|
|
}
|
|
splx(s);
|
|
return 0;
|
|
/* NOTREACHED */
|
|
|
|
case MOUSE_HIDE:
|
|
s = spltty();
|
|
if (scp->sc->flags & SC_MOUSE_ENABLED) {
|
|
scp->sc->flags &= ~SC_MOUSE_ENABLED;
|
|
sc_remove_all_mouse(scp->sc);
|
|
}
|
|
splx(s);
|
|
return 0;
|
|
/* NOTREACHED */
|
|
|
|
case MOUSE_MOVEABS:
|
|
s = spltty();
|
|
scp->mouse_xpos = mouse->u.data.x;
|
|
scp->mouse_ypos = mouse->u.data.y;
|
|
set_mouse_pos(scp);
|
|
splx(s);
|
|
break;
|
|
|
|
case MOUSE_MOVEREL:
|
|
s = spltty();
|
|
scp->mouse_xpos += mouse->u.data.x;
|
|
scp->mouse_ypos += mouse->u.data.y;
|
|
set_mouse_pos(scp);
|
|
splx(s);
|
|
break;
|
|
|
|
case MOUSE_GETINFO:
|
|
mouse->u.data.x = scp->mouse_xpos;
|
|
mouse->u.data.y = scp->mouse_ypos;
|
|
mouse->u.data.z = 0;
|
|
mouse->u.data.buttons = scp->mouse_buttons;
|
|
return 0;
|
|
|
|
case MOUSE_ACTION:
|
|
case MOUSE_MOTION_EVENT:
|
|
/* send out mouse event on /dev/sysmouse */
|
|
#if 0
|
|
/* this should maybe only be settable from /dev/consolectl SOS */
|
|
if (SC_VTY(tp->t_dev) != SC_CONSOLECTL)
|
|
return ENOTTY;
|
|
#endif
|
|
s = spltty();
|
|
if (mouse->u.data.x != 0 || mouse->u.data.y != 0) {
|
|
cur_scp->mouse_xpos += mouse->u.data.x;
|
|
cur_scp->mouse_ypos += mouse->u.data.y;
|
|
set_mouse_pos(cur_scp);
|
|
}
|
|
f = 0;
|
|
if (mouse->operation == MOUSE_ACTION) {
|
|
f = cur_scp->mouse_buttons ^ mouse->u.data.buttons;
|
|
cur_scp->mouse_buttons = mouse->u.data.buttons;
|
|
}
|
|
splx(s);
|
|
|
|
if (sysmouse_event(mouse) == 0)
|
|
return 0;
|
|
|
|
/*
|
|
* If any buttons are down or the mouse has moved a lot,
|
|
* stop the screen saver.
|
|
*/
|
|
if (((mouse->operation == MOUSE_ACTION) && mouse->u.data.buttons)
|
|
|| (mouse->u.data.x*mouse->u.data.x
|
|
+ mouse->u.data.y*mouse->u.data.y
|
|
>= SC_WAKEUP_DELTA*SC_WAKEUP_DELTA)) {
|
|
sc_touch_scrn_saver();
|
|
}
|
|
|
|
cur_scp->status &= ~MOUSE_HIDDEN;
|
|
|
|
if (cur_scp->mouse_signal && cur_scp->mouse_proc) {
|
|
/* has controlling process died? */
|
|
if (cur_scp->mouse_proc != (p1 = pfind(cur_scp->mouse_pid))) {
|
|
cur_scp->mouse_signal = 0;
|
|
cur_scp->mouse_proc = NULL;
|
|
cur_scp->mouse_pid = 0;
|
|
if (p1)
|
|
PROC_UNLOCK(p1);
|
|
} else {
|
|
psignal(cur_scp->mouse_proc, cur_scp->mouse_signal);
|
|
PROC_UNLOCK(cur_scp->mouse_proc);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifndef SC_NO_CUTPASTE
|
|
if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL))
|
|
break;
|
|
|
|
if ((mouse->operation == MOUSE_ACTION) && f) {
|
|
/* process button presses */
|
|
if (cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN)
|
|
mouse_cut_start(cur_scp);
|
|
else
|
|
mouse_cut_end(cur_scp);
|
|
if (cur_scp->mouse_buttons & MOUSE_BUTTON2DOWN ||
|
|
cur_scp->mouse_buttons & MOUSE_BUTTON3DOWN)
|
|
sc_mouse_paste(cur_scp);
|
|
}
|
|
#endif /* SC_NO_CUTPASTE */
|
|
break;
|
|
|
|
case MOUSE_BUTTON_EVENT:
|
|
if ((mouse->u.event.id & MOUSE_BUTTONS) == 0)
|
|
return EINVAL;
|
|
if (mouse->u.event.value < 0)
|
|
return EINVAL;
|
|
#if 0
|
|
/* this should maybe only be settable from /dev/consolectl SOS */
|
|
if (SC_VTY(tp->t_dev) != SC_CONSOLECTL)
|
|
return ENOTTY;
|
|
#endif
|
|
if (mouse->u.event.value > 0)
|
|
cur_scp->mouse_buttons |= mouse->u.event.id;
|
|
else
|
|
cur_scp->mouse_buttons &= ~mouse->u.event.id;
|
|
|
|
if (sysmouse_event(mouse) == 0)
|
|
return 0;
|
|
|
|
/* if a button is held down, stop the screen saver */
|
|
if (mouse->u.event.value > 0)
|
|
sc_touch_scrn_saver();
|
|
|
|
cur_scp->status &= ~MOUSE_HIDDEN;
|
|
|
|
if (cur_scp->mouse_signal && cur_scp->mouse_proc) {
|
|
if (cur_scp->mouse_proc != (p1 = pfind(cur_scp->mouse_pid))){
|
|
cur_scp->mouse_signal = 0;
|
|
cur_scp->mouse_proc = NULL;
|
|
cur_scp->mouse_pid = 0;
|
|
if (p1)
|
|
PROC_UNLOCK(p1);
|
|
} else {
|
|
psignal(cur_scp->mouse_proc, cur_scp->mouse_signal);
|
|
PROC_UNLOCK(cur_scp->mouse_proc);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifndef SC_NO_CUTPASTE
|
|
if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL))
|
|
break;
|
|
|
|
switch (mouse->u.event.id) {
|
|
case MOUSE_BUTTON1DOWN:
|
|
switch (mouse->u.event.value % 4) {
|
|
case 0: /* up */
|
|
mouse_cut_end(cur_scp);
|
|
break;
|
|
case 1: /* single click: start cut operation */
|
|
mouse_cut_start(cur_scp);
|
|
break;
|
|
case 2: /* double click: cut a word */
|
|
mouse_cut_word(cur_scp);
|
|
mouse_cut_end(cur_scp);
|
|
break;
|
|
case 3: /* triple click: cut a line */
|
|
mouse_cut_line(cur_scp);
|
|
mouse_cut_end(cur_scp);
|
|
break;
|
|
}
|
|
break;
|
|
case SC_MOUSE_PASTEBUTTON:
|
|
switch (mouse->u.event.value) {
|
|
case 0: /* up */
|
|
break;
|
|
default:
|
|
sc_mouse_paste(cur_scp);
|
|
break;
|
|
}
|
|
break;
|
|
case SC_MOUSE_EXTENDBUTTON:
|
|
switch (mouse->u.event.value) {
|
|
case 0: /* up */
|
|
if (!(cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN))
|
|
mouse_cut_end(cur_scp);
|
|
break;
|
|
default:
|
|
mouse_cut_extend(cur_scp);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
#endif /* SC_NO_CUTPASTE */
|
|
break;
|
|
|
|
case MOUSE_MOUSECHAR:
|
|
if (mouse->u.mouse_char < 0) {
|
|
mouse->u.mouse_char = scp->sc->mouse_char;
|
|
} else {
|
|
if (mouse->u.mouse_char > UCHAR_MAX - 3)
|
|
return EINVAL;
|
|
s = spltty();
|
|
sc_remove_all_mouse(scp->sc);
|
|
#ifndef SC_NO_FONT_LOADING
|
|
if (ISTEXTSC(cur_scp) && (cur_scp->font != NULL))
|
|
sc_load_font(cur_scp, 0, cur_scp->font_size,
|
|
cur_scp->font_width,
|
|
cur_scp->font + cur_scp->font_size
|
|
* cur_scp->sc->mouse_char,
|
|
cur_scp->sc->mouse_char, 4);
|
|
#endif
|
|
scp->sc->mouse_char = mouse->u.mouse_char;
|
|
splx(s);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
return ENOIOCTL;
|
|
}
|
|
|
|
#endif /* SC_NO_SYSMOUSE */
|