Support setting the colors of cursors for the VGA renderer.

Advertise this by changing the defaults to mostly red.  If you don't like
this, change them (almost) back using:
   vidcontrol -c charcolors,base=7,height=0
   vidcontrol -c mousecolors,base=0[,height=15]

The (graphics mode only) mouse cursor colors were hard-coded to a black
border and lightwhite interior.  Black for the border is the worst
possible default, since it is the same as the default black background
and not good for any dark background.  Reversing this gives the better
default of X Windows.  Coloring everything works better still.  Now
the coloring defaults to a lightwhite border and red interior.

Coloring for the character cursor is more complicated and mode
dependent.  The new coloring doesn't apply for hardware cursors.  For
non-block cursors, it only applies in graphics mode.  In text mode,
the cursor color was usually a hard-coded (dull)white for the background
only, unless the foreground was white when it was a hard-coded black
for the background only, unless the foreground was white and the
background was black it was reverse video.  In graphics mode, it was
always reverse video for the block cursor.  Reverse video is worse,
especially over cutmarking regions, since cutmarking still uses simple
reverse video (nothing better is possible in text mode) and double
reverse video for the cursor gives normal video.  Now, graphics mode
uses the same algorithm as the best case for text mode in all cases
for graphics mode.  The hard-coded sequence { white, black, } for the
background is now { red, white, blue, } where the first 2 colors can
be configured.  The blue color at the end is a sentinel which prevents
reverse video being used in most cases but breaks the compatibility
setting for white on black and black on white characters.  This will
be fixed later.  The compatibility setting is most needed for mono modes.

The previous commit to syscons.c changed sc_cnterm() to be more careful.
It followed null pointers in some cases.  But sc_cnterm() has been
unreachable for 15+ years since changes for multiple consoles turned
off calls to the the cnterm destructor for all console drivers.  Before
them, it was only called at boot time.  So no driver with an attached
console has ever been unloadable and not even the non-console destructors
have been tested much.
This commit is contained in:
Bruce Evans 2017-08-25 07:04:41 +00:00
parent 0012e436e3
commit 9bc7c36337
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=322878
6 changed files with 123 additions and 41 deletions

View file

@ -356,32 +356,28 @@ vga_flipattr(u_short a, int blink)
}
static u_short
vga_cursorattr_adj(u_short a, int blink)
vga_cursorattr_adj(scr_stat *scp, u_short a, int blink)
{
/*
* !blink means pixel mode, and the cursor attribute in that case
* is simplistic reverse video.
*/
if (!blink)
return (vga_flipattr(a, blink));
int i;
u_short bg, bgmask, fg, newbg;
/*
* The cursor attribute is usually that of the underlying char
* with the bg changed to white. If the bg is already white,
* then the bg is changed to black. The fg is usually not
* changed, but if it is the same as the new bg then it is
* changed to the inverse of the new bg.
* with only the bg changed, to the first preferred color that
* differs from both the fg and bg. If there is no such color,
* use reverse video.
*/
if ((a & 0x7000) == 0x7000) {
a &= 0x8f00;
if ((a & 0x0700) == 0)
a |= 0x0700;
} else {
a |= 0x7000;
if ((a & 0x0700) == 0x0700)
a &= 0xf000;
bgmask = blink ? 0x7000 : 0xf000;
bg = a & bgmask;
fg = a & 0x0f00;
for (i = 0; i < nitems(scp->curs_attr.bg); i++) {
newbg = (scp->curs_attr.bg[i] << 12) & bgmask;
if (newbg != bg && newbg != (fg << 4))
break;
}
return (a);
if (i == nitems(scp->curs_attr.bg))
return (vga_flipattr(a, blink));
return (fg | newbg | (blink ? a & 0x8000 : 0));
}
static void
@ -522,6 +518,12 @@ draw_txtcharcursor(scr_stat *scp, int at, u_short c, u_short a, int flip)
return;
if (flip)
a = vga_flipattr(a, TRUE);
/*
* This clause handles partial-block cursors in text mode.
* We want to change the attribute only under the partial
* block, but in text mode we can only change full blocks.
* Use reverse video instead.
*/
bcopy(font + c*h, font + sc->cursor_char*h, h);
font = font + sc->cursor_char*h;
for (i = imax(h - scp->curs_attr.base - scp->curs_attr.height, 0);
@ -536,7 +538,7 @@ draw_txtcharcursor(scr_stat *scp, int at, u_short c, u_short a, int flip)
{
if (flip)
a = vga_flipattr(a, TRUE);
a = vga_cursorattr_adj(a, TRUE);
a = vga_cursorattr_adj(scp, a, TRUE);
sc_vtb_putc(&scp->scr, at, c, a);
}
}
@ -1026,7 +1028,7 @@ draw_pxlcursor_direct(scr_stat *scp, int at, int on, int flip)
if (flip)
a = vga_flipattr(a, FALSE);
if (on)
a = vga_cursorattr_adj(a, FALSE);
a = vga_cursorattr_adj(scp, a, FALSE);
col1 = (a & 0x0f00) >> 8;
col2 = a >> 12;
@ -1070,7 +1072,7 @@ draw_pxlcursor_planar(scr_stat *scp, int at, int on, int flip)
if (flip)
a = vga_flipattr(a, FALSE);
if (on)
a = vga_cursorattr_adj(a, FALSE);
a = vga_cursorattr_adj(scp, a, FALSE);
col = (a & 0xf000) >> 4;
outw(GDCIDX, col | 0x00); /* set/reset */
outw(GDCIDX, 0xff08); /* bit mask */
@ -1202,7 +1204,7 @@ draw_pxlmouse_planar(scr_stat *scp, int x, int y)
outw(GDCIDX, 0x0003); /* data rotate/function select */
outw(GDCIDX, 0x0f01); /* set/reset enable */
outw(GDCIDX, (0 << 8) | 0x00); /* set/reset */
outw(GDCIDX, (scp->curs_attr.mouse_ba << 8) | 0x00); /* set/reset */
p = scp->sc->adp->va_window + line_width*y + x/8;
for (i = y, j = 0; i < ymax; ++i, ++j) {
m = mdp->md_border[j] << 8 >> xoff;
@ -1221,7 +1223,7 @@ draw_pxlmouse_planar(scr_stat *scp, int x, int y)
}
p += line_width;
}
outw(GDCIDX, (15 << 8) | 0x00); /* set/reset */
outw(GDCIDX, (scp->curs_attr.mouse_ia << 8) | 0x00); /* set/reset */
p = scp->sc->adp->va_window + line_width*y + x/8;
for (i = y, j = 0; i < ymax; ++i, ++j) {
m = mdp->md_interior[j] << 8 >> xoff;
@ -1325,9 +1327,11 @@ vga_pxlmouse_direct(scr_stat *scp, int x, int y, int on)
for (i = 0; i < yend - y; i++, p += line_width)
for (j = xend - x - 1; j >= 0; j--)
if (mdp->md_interior[i] & (1 << (15 - j)))
DRAW_PIXEL(scp, p + j * pixel_size, 15);
DRAW_PIXEL(scp, p + j * pixel_size,
scp->curs_attr.mouse_ia);
else if (mdp->md_border[i] & (1 << (15 - j)))
DRAW_PIXEL(scp, p + j * pixel_size, 0);
DRAW_PIXEL(scp, p + j * pixel_size,
scp->curs_attr.mouse_ba);
}
static void

View file

@ -959,8 +959,16 @@ sctty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
cap = &scp->dflt_curs_attr;
break;
}
((int *)data)[1] = cap->base;
((int *)data)[2] = cap->height;
if (((int *)data)[0] & CONS_CHARCURSOR_COLORS) {
((int *)data)[1] = cap->bg[0];
((int *)data)[2] = cap->bg[1];
} else if (((int *)data)[0] & CONS_MOUSECURSOR_COLORS) {
((int *)data)[1] = cap->mouse_ba;
((int *)data)[2] = cap->mouse_ia;
} else {
((int *)data)[1] = cap->base;
((int *)data)[2] = cap->height;
}
((int *)data)[0] = cap->flags;
return 0;
@ -3025,8 +3033,12 @@ sc_set_cursor_image(scr_stat *scp)
static void
sc_adjust_ca(struct cursor_attr *cap, int flags, int base, int height)
{
if (0) {
/* Dummy clause to avoid changing indentation later. */
if (flags & CONS_CHARCURSOR_COLORS) {
cap->bg[0] = base & 0xff;
cap->bg[1] = height & 0xff;
} else if (flags & CONS_MOUSECURSOR_COLORS) {
cap->mouse_ba = base & 0xff;
cap->mouse_ia = height & 0xff;
} else {
if (base >= 0)
cap->base = base;
@ -3243,8 +3255,14 @@ scinit(int unit, int flags)
sc->dflt_curs_attr.base = 0;
sc->dflt_curs_attr.height = howmany(scp->font_size, 8);
sc->dflt_curs_attr.flags = 0;
sc->dflt_curs_attr.bg[0] = FG_RED;
sc->dflt_curs_attr.bg[1] = FG_LIGHTGREY;
sc->dflt_curs_attr.bg[2] = FG_BLUE;
sc->dflt_curs_attr.mouse_ba = FG_WHITE;
sc->dflt_curs_attr.mouse_ia = FG_RED;
sc->curs_attr = sc->dflt_curs_attr;
scp->base_curs_attr = scp->dflt_curs_attr = sc->curs_attr;
scp->curs_attr = scp->base_curs_attr;
#ifndef SC_NO_SYSMOUSE
sc_mouse_move(scp, scp->xpixel/2, scp->ypixel/2);

View file

@ -167,11 +167,14 @@ typedef struct sc_vtb {
int vtb_tail; /* valid for VTB_RINGBUFFER only */
} sc_vtb_t;
/* text cursor attributes */
/* text and some mouse cursor attributes */
struct cursor_attr {
int flags;
int base;
int height;
u_char flags;
u_char base;
u_char height;
u_char bg[3];
u_char mouse_ba;
u_char mouse_ia;
};
/* softc */

View file

@ -187,6 +187,8 @@ typedef struct mouse_info mouse_info_t;
#define CONS_HIDDEN_CURSOR (1 << 2)
#define CONS_CURSOR_ATTRS (CONS_BLINK_CURSOR | CONS_CHAR_CURSOR | \
CONS_HIDDEN_CURSOR)
#define CONS_CHARCURSOR_COLORS (1 << 26)
#define CONS_MOUSECURSOR_COLORS (1 << 27)
#define CONS_DEFAULT_CURSOR (1 << 28)
#define CONS_SHAPEONLY_CURSOR (1 << 29)
#define CONS_RESET_CURSOR (1 << 30)

View file

@ -219,6 +219,50 @@ Set or clear the hidden attribute.
The following (non-sticky) flags control application of the
.Cm setting Ns s :
.Bl -tag -width indent
.It Cm charcolors
Apply
.Cm base
and
.Cm height
to the (character) cursor's list of preferred colors instead of its shape.
Beware that the color numbers are raw VGA palette indexes,
not ANSI color numbers.
The indexes are reduced mod 8, 16 or 256,
or ignored,
depending on the video mode and renderer.
.It Cm mousecolors
Colors for the mouse cursor in graphics mode.
Like
.Cm charcolors ,
except there is no preference or sequence;
.Cm base
gives the mouse border color and
.Cm height
gives the mouse interior color.
Together with
.Cm charcolors ,
this gives 2 selection bits which select between
only 3 of 4 sub-destinations of the 4 destinations selected by
.Cm default
and
.Cm local
(by ignoring
.Cm mousecolors
if
.Cm charcolors
is also set).
.It Cm default
Apply the changes to the default settings and then to the active settings,
instead of only to the active settings.
Together with
.Cm local ,
this gives 2 selection bits which select between 4 destinations.
.It Cm shapeonly
Ignore any changes to the
.Cm block
and
.Cm hidden
attributes.
.It Cm local
Apply the changes to the current vty.
The default is to apply them to a global place
@ -233,10 +277,8 @@ to default local settings.
Otherwise, the current global settings are reset to default
global settings and then copied to the current and default
settings for all vtys.
The global defaults are decided (not quite right) at boot time
and cannot be fixed up.
The local defaults are obtained as above and cannot be fixed up
locally.
.It Cm show
Show the current changes.
.El
.It Fl d
Print out current output screen map.

View file

@ -650,10 +650,21 @@ parse_cursor_params(char *param, struct cshape *shape)
shape->shape[1] = strtol(word + 5, NULL, 0);
else if (strncmp(word, "height=", 7) == 0)
shape->shape[2] = strtol(word + 7, NULL, 0);
else if (strcmp(word, "charcolors") == 0)
type |= CONS_CHARCURSOR_COLORS;
else if (strcmp(word, "mousecolors") == 0)
type |= CONS_MOUSECURSOR_COLORS;
else if (strcmp(word, "default") == 0)
type |= CONS_DEFAULT_CURSOR;
else if (strcmp(word, "shapeonly") == 0)
type |= CONS_SHAPEONLY_CURSOR;
else if (strcmp(word, "local") == 0)
type |= CONS_LOCAL_CURSOR;
else if (strcmp(word, "reset") == 0)
type |= CONS_RESET_CURSOR;
else if (strcmp(word, "show") == 0)
printf("flags %#x, base %d, height %d\n",
type, shape->shape[1], shape->shape[2]);
else {
revert();
errx(1,
@ -676,11 +687,13 @@ set_cursor_type(char *param)
{
struct cshape shape;
/* Determine if the new setting is local (default to non-local). */
/* Dry run to determine color, default and local flags. */
shape.shape[0] = 0;
shape.shape[1] = -1;
shape.shape[2] = -1;
parse_cursor_params(param, &shape);
/* Get the relevant shape (the local flag is the only input arg). */
/* Get the relevant old setting. */
if (ioctl(0, CONS_GETCURSORSHAPE, &shape) != 0) {
revert();
err(1, "ioctl(CONS_GETCURSORSHAPE)");