From 1ee1295c23c6a62b957a8a593639460b592b9b64 Mon Sep 17 00:00:00 2001 From: Marcus Brinkmann Date: Fri, 15 Aug 2003 21:07:31 +0000 Subject: 2003-08-11 Marco Gerards * console.c (cons_vcons_set_dimension): New function. * display.h (display_ops): New interface set_dimension. * ncursesw.c (ncursesw_set_dimension): New function. (ncursesw_displ): Add ncursesw_set_dimension. (ncurses_lock): Make variable static. (current_width): New variable. (current_height): Likewise. (cursor_state): Likewise. (cursor_hidden): Likewise. (driver_ncursesw_ops): Added ncursesw_set_dimension. * vga.c (current_width): New variable. (current_height): Likewise. (vga_display_set_cursor_status): If the cursor is outside the screen, don't change the visibility. (vga_display_set_cursor_pos): Don't set the cursor outside the physical screen. Update cursor_hidden and hide/unhide to match cursor_hidden. Function moved to above vga_display_set_cursor_status. (vga_display_scroll): Report an error when scrolling is not possible. (vga_display_clear): Recalculate cols, rows and length. (vga_display_write): Make it wrap around the edge. (vga_set_dimension): New function. (vga_disp_ops): Added vga_set_dimension. * ncursesw.c (conspad): New variable. (padx): Likewise. (pady): Likewise. (autoscroll): Likewise. (refresh_screen): new function. (input_loop): Use conspad instead of (the default) stdscr. Call console_exit instead of exiting here. Add keybindings 'j, 'k', 'l' and 'i' to scroll the console, add keybinding 'a' to switch autoscroll. (mvwputsn): Use conspad instead of (the default) stdscr. (ncursesw_scroll): Likewise. (ncursesw_write): Likewise. (ncursesw_driver_start): Likewise. Initialize conspad. (ncursesw_update): Call refresh_screen to refresh the console. (ncursesw_set_cursor_pos): Use conspad instead of (the default) stdscr. Make the console autoscroll. * ncursesw.c (ncursesw_driver_start): Remove endwin call at the end of the function. * ncursesw.c (ncursesw_set_cursor_status): If the status can not be set, use another status that can sanely be used instead of the unavailable status. --- console-client/ChangeLog | 51 +++++++++++++ console-client/console.c | 19 ++++- console-client/display.h | 9 ++- console-client/ncursesw.c | 185 +++++++++++++++++++++++++++++++++++++++------- console-client/vga.c | 144 ++++++++++++++++++++++++++++++++---- 5 files changed, 365 insertions(+), 43 deletions(-) diff --git a/console-client/ChangeLog b/console-client/ChangeLog index 94131588..10a5c8af 100644 --- a/console-client/ChangeLog +++ b/console-client/ChangeLog @@ -1,3 +1,54 @@ +2003-08-11 Marco Gerards + + * console.c (cons_vcons_set_dimension): New function. + * display.h (display_ops): New interface set_dimension. + * ncursesw.c (ncursesw_set_dimension): New function. + (ncursesw_displ): Add ncursesw_set_dimension. + (ncurses_lock): Make variable static. + (current_width): New variable. + (current_height): Likewise. + (cursor_state): Likewise. + (cursor_hidden): Likewise. + (driver_ncursesw_ops): Added ncursesw_set_dimension. + * vga.c (current_width): New variable. + (current_height): Likewise. + (vga_display_set_cursor_status): If the cursor is outside the + screen, don't change the visibility. + (vga_display_set_cursor_pos): Don't set the cursor outside the + physical screen. Update cursor_hidden and hide/unhide + to match cursor_hidden. Function moved to above + vga_display_set_cursor_status. + (vga_display_scroll): Report an error when scrolling is not + possible. + (vga_display_clear): Recalculate cols, rows and length. + (vga_display_write): Make it wrap around the edge. + (vga_set_dimension): New function. + (vga_disp_ops): Added vga_set_dimension. + + * ncursesw.c (conspad): New variable. + (padx): Likewise. + (pady): Likewise. + (autoscroll): Likewise. + (refresh_screen): new function. + (input_loop): Use conspad instead of (the default) stdscr. + Call console_exit instead of exiting here. Add keybindings + 'j, 'k', 'l' and 'i' to scroll the console, add keybinding 'a' + to switch autoscroll. + (mvwputsn): Use conspad instead of (the default) stdscr. + (ncursesw_scroll): Likewise. + (ncursesw_write): Likewise. + (ncursesw_driver_start): Likewise. Initialize conspad. + (ncursesw_update): Call refresh_screen to refresh the console. + (ncursesw_set_cursor_pos): Use conspad instead of (the default) + stdscr. Make the console autoscroll. + + * ncursesw.c (ncursesw_driver_start): Remove endwin call at + the end of the function. + + * ncursesw.c (ncursesw_set_cursor_status): If the status can + not be set, use another status that can sanely be used instead + of the unavailable status. + 2003-07-14 Marco Gerards * vga.c: New global variable vga_display_max_glyphs. diff --git a/console-client/console.c b/console-client/console.c index 34573580..0fb3aa97 100644 --- a/console-client/console.c +++ b/console-client/console.c @@ -1,5 +1,5 @@ /* console.c -- A pluggable console client. - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. Written by Marcus Brinkmann. This program is free software; you can redistribute it and/or @@ -354,6 +354,23 @@ cons_vcons_set_scroll_lock (vcons_t vcons, int onoff) mutex_unlock (&global_lock); } + +/* The user must define this function. Clear the existing screen + matrix and set the size of the screen matrix to the dimension COL x + ROW. This call will be immediately followed by a call to + cons_vcons_write that covers the whole new screen matrix. */ +error_t +cons_vcons_set_dimension (vcons_t vcons, uint32_t col, uint32_t row) +{ + mutex_lock (&global_lock); + if (vcons == active_vcons) + display_iterate + if (display->ops->set_dimension) + display->ops->set_dimension (display->handle, col, row); + mutex_unlock (&global_lock); + return 0; +} + /* Console-specific options. */ static const struct argp_option diff --git a/console-client/display.h b/console-client/display.h index 44e62773..3dc97fde 100644 --- a/console-client/display.h +++ b/console-client/display.h @@ -1,5 +1,5 @@ /* display.h - The interface to and for a display driver. - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. Written by Marcus Brinkmann. This file is part of the GNU Hurd. @@ -133,6 +133,13 @@ struct display_ops /* Do not use, do not remove. */ void (*deprecated) (void *handle, int key); + + /* Change the dimension of the physical screen to one that can + display the vcons with the size of WIDTH * HEIGHT and clear the + old screen. If the physical screen already has the right + resolution do nothing. This function is always followed by a + write that covers the whole new screen. */ + error_t (*set_dimension) (void *handle, int width, int height); }; #endif /* _DISPLAY_H_ */ diff --git a/console-client/ncursesw.c b/console-client/ncursesw.c index 215fc9b8..e14abd7c 100644 --- a/console-client/ncursesw.c +++ b/console-client/ncursesw.c @@ -1,5 +1,5 @@ /* ncursesw.c - The ncursesw console driver. - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. Written by Marcus Brinkmann. This program is free software; you can redistribute it and/or @@ -34,7 +34,22 @@ /* ncurses is not thread-safe. This lock protects all calls into the ncurses library. */ -struct mutex ncurses_lock; +static struct mutex ncurses_lock; + +/* The current width and height the ncursesw driver is using. */ +static int current_width; +static int current_height; + +/* The window on which the console is shown. */ +static WINDOW *conspad; + +/* The upper left corner shown in the pad. */ +static int padx; +static int pady; + +/* Autoscroll is on or off. Autoscroll makes scrolling dependant on + the cursor position. */ +static int autoscroll; /* Forward declaration. */ static struct display_ops ncursesw_display_ops; @@ -258,6 +273,17 @@ ucs4_to_altchar (wchar_t chr, chtype *achr) return 1; } +static error_t +refresh_screen (void) +{ + /* It is possible */ + if (!current_width && !current_height) + return 0; + return prefresh (conspad, pady, padx, 0, 0, + (current_height <= LINES ? current_height : LINES) - 1, + (current_width <= COLS ? current_width : COLS) - 1); +} + static any_t input_loop (any_t unused) { @@ -282,7 +308,7 @@ input_loop (any_t unused) size_t size = 0; mutex_lock (&ncurses_lock); - while ((ret = getch ()) != ERR) + while ((ret = wgetch (conspad)) != ERR) { int i; int found; @@ -292,8 +318,8 @@ input_loop (any_t unused) switch (ret) { case 'x': - endwin (); - exit (0); + mutex_unlock (&ncurses_lock); + console_exit (); break; case 23: /* ^W */ assert (size < 100); @@ -313,6 +339,42 @@ input_loop (any_t unused) console_switch (1 + (ret - '1'), 0); mutex_lock (&ncurses_lock); break; + case 'j': + /* Scroll pad to left. */ + if (padx > 0) + { + padx--; + refresh_screen (); + } + break; + case 'k': + /* Scroll pad down. */ + if (pady < current_height - LINES) + { + pady++; + refresh_screen (); + } + break; + case 'l': + /* Scroll pad to right. */ + if (padx < current_width - COLS) + { + padx++; + ncurses_refresh (); + } + break; + case 'i': + /* Scroll pad up. */ + if (pady > 0) + { + pady--; + refresh_screen (); + } + break; + case 'a': + /* Switch autoscroll on/off. */ + autoscroll = !autoscroll; + break; default: break; } @@ -326,13 +388,15 @@ input_loop (any_t unused) break; default: found = 0; - for (i =0; i < sizeof(keycodes) / sizeof(keycodes[0]); i++) + for (i = 0; i < sizeof (keycodes) / sizeof (keycodes[0]); + i++) { if (keycodes[i].curses == ret) { if (keycodes[i].cons) { - assert (size < 101 - strlen(keycodes[i].cons)); + assert (size + < 101 - strlen (keycodes[i].cons)); strcpy (&buf[size], keycodes[i].cons); size += strlen (keycodes[i].cons); } @@ -382,7 +446,7 @@ mvwputsn (conchar_t *str, size_t len, off_t x, off_t y) attr_t attr = conchar_attr_to_attr (str->attr); short color_pair = conchar_attr_to_color_pair (str->attr); - move (y, x); + wmove (conspad, y, x); while (len) { int ret; @@ -396,7 +460,7 @@ mvwputsn (conchar_t *str, size_t len, off_t x, off_t y) } if (ucs4_to_altchar (str->chr, &ac)) - addch (ac | attr | color_pair); + waddch (conspad, ac | attr | color_pair); else { wch[0] = str->chr; @@ -409,7 +473,7 @@ mvwputsn (conchar_t *str, size_t len, off_t x, off_t y) assert (!"Do something if setcchar fails."); } #endif - ret = add_wch (&chr); + ret = wadd_wch (conspad, &chr); #if 0 if (ret == ERR) { @@ -429,7 +493,7 @@ static error_t ncursesw_update (void *handle) { mutex_lock (&ncurses_lock); - refresh (); + refresh_screen (); mutex_unlock (&ncurses_lock); return 0; } @@ -439,7 +503,45 @@ static error_t ncursesw_set_cursor_pos (void *handle, uint32_t col, uint32_t row) { mutex_lock (&ncurses_lock); - move (row, col); + assert (current_width && current_height); + if (autoscroll) + { + /* Autoscroll to the right. */ + if (col > COLS + padx) + { + padx += COLS / 2; + if (padx > COLS + current_width) + padx = current_width - COLS; + ncurses_refresh (); + } + /* Autoscroll to the left. */ + else if (col < padx) + { + padx -= COLS / 2; + if (padx < 0) + padx = 0; + ncurses_refresh (); + } + /* Autoscroll down. */ + if (row > LINES + pady) + { + pady += LINES / 2; + if (pady > LINES + current_height) + pady = current_height - LINES; + ncurses_refresh (); + } + /* Autoscroll up. */ + else if (row < pady) + { + pady -= LINES / 2; + if (pady < 0) + pady = 0; + ncurses_refresh (); + } + } + + wmove (conspad, row, col); + mutex_unlock (&ncurses_lock); return 0; } @@ -449,7 +551,13 @@ static error_t ncursesw_set_cursor_status (void *handle, uint32_t status) { mutex_lock (&ncurses_lock); - curs_set (status ? (status == 1 ? 1 : 2) : 0); + + /* If the cursor is invisible and switching to one visible state is + impossible, switch to the other visible state or else the cursor + will not be shown at all. */ + if (curs_set (status) == -1 && status) + curs_set (status == 1 ? 2 : 1); + mutex_unlock (&ncurses_lock); return 0; } @@ -462,11 +570,11 @@ ncursesw_scroll (void *handle, int delta) assert (delta >= 0); mutex_lock (&ncurses_lock); - idlok (stdscr, TRUE); - scrollok (stdscr, TRUE); - scrl (delta); - idlok (stdscr, FALSE); - scrollok (stdscr, FALSE); + idlok (conspad, TRUE); + scrollok (conspad, TRUE); + wscrl (conspad, delta); + idlok (conspad, FALSE); + scrollok (conspad, FALSE); mutex_unlock (&ncurses_lock); return 0; } @@ -480,9 +588,9 @@ ncursesw_write (void *handle, conchar_t *str, size_t length, int y; mutex_lock (&ncurses_lock); - getyx (stdscr, y, x); + getyx (conspad, y, x); mvwputsn (str, length, col, row); - wmove (stdscr, y, x); + wmove (conspad, y, x); mutex_unlock (&ncurses_lock); return 0; } @@ -531,10 +639,17 @@ ncursesw_driver_start (void *handle) raw (); noecho (); nonl (); - intrflush (stdscr, FALSE); - nodelay (stdscr, TRUE); - timeout (1); - keypad (stdscr, TRUE); + + /* Create a new pad with the size minimal size. This pad will be + resized by ncursesw_set_dimension. */ + conspad = newpad (1, 1); + if (!conspad) + return errno; + + intrflush (conspad, FALSE); + nodelay (conspad, TRUE); + wtimeout (conspad, 1); + keypad (conspad, TRUE); err = driver_add_display (&ncursesw_display_ops, NULL); if (err) @@ -559,9 +674,8 @@ ncursesw_driver_start (void *handle) } cthread_detach (cthread_fork (input_loop, NULL)); - endwin (); - return err; + return 0; } /* Destroy the display HANDLE. */ @@ -579,6 +693,22 @@ ncursesw_driver_fini (void *handle, int force) return 0; } +static error_t +ncursesw_set_dimension (void *handle, int width, int height) +{ + mutex_lock (&ncurses_lock); + if (width != current_width || height != current_height) + { + wresize (conspad, height, width); + padx = 0; + pady = 0; + } + current_width = width; + current_height = height; + mutex_unlock(&ncurses_lock); + return 0; +} + struct driver_ops driver_ncursesw_ops = { @@ -596,7 +726,8 @@ static struct display_ops ncursesw_display_ops = ncursesw_write, ncursesw_update, ncursesw_flash, - NULL + NULL, + ncursesw_set_dimension }; static struct input_ops ncursesw_input_ops = diff --git a/console-client/vga.c b/console-client/vga.c index d1d73e39..7f666494 100644 --- a/console-client/vga.c +++ b/console-client/vga.c @@ -74,6 +74,16 @@ static struct mutex vga_display_lock; /* Forward declaration. */ static struct display_ops vga_display_ops; +/* The current width and height the ncursesw driver is using. */ +static int current_width; +static int current_height; + +/* The cursor state to restore the state to. */ +static int cursor_state; + +/* Is set to 1 if the cursor moved out of the physical screen and the + cursor state should be hidden. */ +static int cursor_hidden; struct refchr { @@ -318,29 +328,54 @@ vga_display_fini (void *handle, int force) } -/* Set the cursor's position on display HANDLE to column COL and row - ROW. */ +/* Set the cursor's state to STATE on display HANDLE. */ static error_t -vga_display_set_cursor_pos (void *handle, uint32_t col, uint32_t row) +vga_display_set_cursor_status (void *handle, uint32_t state) { struct vga_display *disp = handle; - unsigned int pos = row * disp->width + col; - vga_set_cursor_pos (pos); + /* Don't display the cursor if its location is not within the + physical screen. */ + if (!cursor_hidden) + { + if (state != CONS_CURSOR_INVISIBLE) + dynafont_set_cursor (disp->df, state == CONS_CURSOR_VERY_VISIBLE ? 1 : 0); + + vga_display_cursor (state == CONS_CURSOR_INVISIBLE ? 0 : 1); + } + + cursor_state = state; return 0; } -/* Set the cursor's state to STATE on display HANDLE. */ +/* Set the cursor's position on display HANDLE to column COL and row + ROW. */ static error_t -vga_display_set_cursor_status (void *handle, uint32_t state) +vga_display_set_cursor_pos (void *handle, uint32_t col, uint32_t row) { struct vga_display *disp = handle; + unsigned int pos = row * disp->width + col; - if (state != CONS_CURSOR_INVISIBLE) - dynafont_set_cursor (disp->df, state == CONS_CURSOR_VERY_VISIBLE ? 1 : 0); - vga_display_cursor (state == CONS_CURSOR_INVISIBLE ? 0 : 1); + /* Make sure the cursor can only be moved to a position on te + physical screen. */ + if (col < disp->width && row < disp->height) + { + vga_set_cursor_pos (pos); + if (cursor_hidden) + { + /* Restore the cursor. */ + cursor_hidden = 0; + vga_display_set_cursor_status (handle, cursor_state); + } + } + else if (!cursor_hidden) + { + /* Hide the cursor. */ + cursor_hidden = 1; + vga_display_cursor (CONS_CURSOR_INVISIBLE); + } return 0; } @@ -355,7 +390,12 @@ vga_display_scroll (void *handle, int delta) int count = abs(delta) * disp->width; int i; struct refchr *refpos; - + + /* XXX: If the virtual console is bigger than the physical console it is + impossible to scroll because the data to scroll is not in memory. */ + if (current_height > disp->height) + return ENOTSUP; + if (delta > 0) { memmove (vga_videomem, vga_videomem + 2 * count, @@ -485,8 +525,31 @@ static error_t vga_display_clear (void *handle, size_t length, uint32_t col, uint32_t row) { struct vga_display *disp = handle; - struct refchr *refpos = &disp->refmatrix[row][col]; + struct refchr *refpos = &disp->refmatrix[row][0]; + int cols; + /* The column can be outside the physical screen, in that case + adjust the position. */ + if (col >= disp->width) + { + col = disp->width - col; + row++; + } + refpos += col; + + /* The first row is not in the physical screen, nothing has to be + done. */ + if (row >= disp->height) + return 0; + + /* The length cannot be used. Recalculate it to wrap the lines. */ + cols = length / current_width; + length = (length % current_width) + cols * disp->width ; + + /* Make sure the end of length is still in the physical screen. */ + if (length > (disp->width * disp->height - (row * disp->width + col)) - col) + length = disp->width * disp->height - (row * disp->width + col) - col; + while (length > 0) { if (refpos->used) @@ -511,9 +574,21 @@ vga_display_write (void *handle, conchar_t *str, size_t length, uint32_t col, uint32_t row) { struct vga_display *disp = handle; - char *pos = vga_videomem + 2 * (row * disp->width + col); + char *pos; struct refchr *refpos = &disp->refmatrix[row][col]; + /* The starting column is outside the physical screen. */ + if (disp->width < current_width && col >= disp->width) + { + size_t skip = current_width - disp->width; + str += skip; + length -= skip; + col = 0; + row++; + } + + pos = vga_videomem + 2 * (row * disp->width + col); + /* Although all references to the current fgcol or bgcol could have been released here, for example due to a scroll operation, we know that the color slots have not been reused yet, as no routine @@ -524,6 +599,31 @@ vga_display_write (void *handle, conchar_t *str, size_t length, while (length--) { int charval = dynafont_lookup (disp->df, str); + col++; + + /* The virtual console is smaller than the physical screen. */ + if (col > current_width) + { + size_t skip = disp->width - current_width; + pos += skip * 2; + refpos += skip; + col = 1; + row++; + } + /* The virtual console is bigger than the physical console. */ + else if (disp->width < current_width && col == disp->width) + { + size_t skip = current_width - disp->width; + str += skip; + length -= skip; + col = 1; + row++; + } + + /* The screen is filled until the bottom of the screen. */ + if (row >= disp->height) + return 0; + if (!disp->cur_conchar_attr_init || *(uint32_t *) &disp->cur_conchar_attr != *(uint32_t *) &str->attr) { @@ -566,6 +666,21 @@ vga_display_write (void *handle, conchar_t *str, size_t length, return 0; } +static error_t +vga_set_dimension (void *handle, int width, int height) +{ + if (current_width && current_height) + vga_display_clear (handle, current_width * current_height, 0, 0); + + current_width = width; + current_height = height; + + /* FIXME: Should support greater dimensions by changing the video + mode. */ + + return 0; +} + struct driver_ops driver_vga_ops = { @@ -583,5 +698,6 @@ static struct display_ops vga_display_ops = vga_display_write, NULL, vga_display_flash, - NULL + NULL, + vga_set_dimension }; -- cgit v1.2.3