Changeset 899bdfd in mainline


Ignore:
Timestamp:
2024-09-12T13:14:20Z (3 months ago)
Author:
Jiří Zárevúcky <zarevucky.jiri@…>
Branches:
master
Children:
4c2339b
Parents:
dd50aa19
git-author:
Jiří Zárevúcky <zarevucky.jiri@…> (2024-09-12 11:47:56)
git-committer:
Jiří Zárevúcky <zarevucky.jiri@…> (2024-09-12 13:14:20)
Message:

Terminal scrolling and resizing support

Location:
uspace
Files:
5 added
12 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/terminal/meson.build

    rdd50aa19 r899bdfd  
    2727#
    2828
    29 deps = [ 'fbfont', 'display', 'ui' ]
     29deps = [ 'fbfont', 'display', 'ui', 'termui' ]
    3030src = files(
    3131        'main.c',
  • uspace/app/terminal/terminal.c

    rdd50aa19 r899bdfd  
    4040#include <errno.h>
    4141#include <fbfont/font-8x16.h>
    42 #include <io/chargrid.h>
    4342#include <fibril.h>
    4443#include <gfx/bitmap.h>
     
    4948#include <io/console.h>
    5049#include <io/pixelmap.h>
    51 #include <task.h>
     50#include <macros.h>
    5251#include <stdarg.h>
    5352#include <stdio.h>
    5453#include <stdlib.h>
     54#include <str_error.h>
    5555#include <str.h>
     56#include <task.h>
    5657#include <ui/resource.h>
    5758#include <ui/ui.h>
     
    7172        (CONSOLE_CAP_STYLE | CONSOLE_CAP_INDEXED | CONSOLE_CAP_RGB)
    7273
     74#define SCROLLBACK_MAX_LINES 1000
     75#define MIN_WINDOW_COLS 8
     76#define MIN_WINDOW_ROWS 4
     77
    7378static LIST_INITIALIZE(terms);
     79
     80#define COLOR_BRIGHT 8
     81
     82static const pixel_t _basic_colors[16] = {
     83        [COLOR_BLACK]       = PIXEL(255, 0, 0, 0),
     84        [COLOR_RED]         = PIXEL(255, 170, 0, 0),
     85        [COLOR_GREEN]       = PIXEL(255, 0, 170, 0),
     86        [COLOR_YELLOW]      = PIXEL(255, 170, 85, 0),
     87        [COLOR_BLUE]        = PIXEL(255, 0, 0, 170),
     88        [COLOR_MAGENTA]     = PIXEL(255, 170, 0, 170),
     89        [COLOR_CYAN]        = PIXEL(255, 0, 170, 170),
     90        [COLOR_WHITE]       = PIXEL(255, 170, 170, 170),
     91
     92        [COLOR_BLACK   | COLOR_BRIGHT] = PIXEL(255, 85, 85, 85),
     93        [COLOR_RED     | COLOR_BRIGHT] = PIXEL(255, 255, 85, 85),
     94        [COLOR_GREEN   | COLOR_BRIGHT] = PIXEL(255, 85, 255, 85),
     95        [COLOR_YELLOW  | COLOR_BRIGHT] = PIXEL(255, 255, 255, 85),
     96        [COLOR_BLUE    | COLOR_BRIGHT] = PIXEL(255, 85, 85, 255),
     97        [COLOR_MAGENTA | COLOR_BRIGHT] = PIXEL(255, 255, 85, 255),
     98        [COLOR_CYAN    | COLOR_BRIGHT] = PIXEL(255, 85, 255, 255),
     99        [COLOR_WHITE   | COLOR_BRIGHT] = PIXEL(255, 255, 255, 255),
     100};
    74101
    75102static errno_t term_open(con_srvs_t *, con_srv_t *);
     
    119146static void terminal_close_event(ui_window_t *, void *);
    120147static void terminal_focus_event(ui_window_t *, void *, unsigned);
     148static void terminal_resize_event(ui_window_t *, void *);
    121149static void terminal_kbd_event(ui_window_t *, void *, kbd_event_t *);
    122150static void terminal_pos_event(ui_window_t *, void *, pos_event_t *);
    123151static void terminal_unfocus_event(ui_window_t *, void *, unsigned);
     152static void terminal_maximize_event(ui_window_t *, void *);
     153static void terminal_unmaximize_event(ui_window_t *, void *);
    124154
    125155static ui_window_cb_t terminal_window_cb = {
    126156        .close = terminal_close_event,
    127157        .focus = terminal_focus_event,
     158        .resize = terminal_resize_event,
    128159        .kbd = terminal_kbd_event,
    129160        .pos = terminal_pos_event,
    130         .unfocus = terminal_unfocus_event
     161        .unfocus = terminal_unfocus_event,
     162        .maximize = terminal_maximize_event,
     163        .unmaximize = terminal_unmaximize_event,
    131164};
    132165
     
    144177}
    145178
    146 static pixel_t color_table[16] = {
    147         [COLOR_BLACK]       = PIXEL(255, 0, 0, 0),
    148         [COLOR_BLUE]        = PIXEL(255, 0, 0, 170),
    149         [COLOR_GREEN]       = PIXEL(255, 0, 170, 0),
    150         [COLOR_CYAN]        = PIXEL(255, 0, 170, 170),
    151         [COLOR_RED]         = PIXEL(255, 170, 0, 0),
    152         [COLOR_MAGENTA]     = PIXEL(255, 170, 0, 170),
    153         [COLOR_YELLOW]      = PIXEL(255, 170, 85, 0),
    154         [COLOR_WHITE]       = PIXEL(255, 170, 170, 170),
    155 
    156         [COLOR_BLACK + 8]   = PIXEL(255, 85, 85, 85),
    157         [COLOR_BLUE + 8]    = PIXEL(255, 85, 85, 255),
    158         [COLOR_GREEN + 8]   = PIXEL(255, 85, 255, 85),
    159         [COLOR_CYAN + 8]    = PIXEL(255, 85, 255, 255),
    160         [COLOR_RED + 8]     = PIXEL(255, 255, 85, 85),
    161         [COLOR_MAGENTA + 8] = PIXEL(255, 255, 85, 255),
    162         [COLOR_YELLOW + 8]  = PIXEL(255, 255, 255, 85),
    163         [COLOR_WHITE + 8]   = PIXEL(255, 255, 255, 255),
    164 };
    165 
    166 static inline void attrs_rgb(char_attrs_t attrs, pixel_t *bgcolor, pixel_t *fgcolor)
    167 {
    168         switch (attrs.type) {
     179static pixel_t termui_color_to_pixel(termui_color_t c)
     180{
     181        uint8_t r, g, b;
     182        termui_color_to_rgb(c, &r, &g, &b);
     183        return PIXEL(255, r, g, b);
     184}
     185
     186static termui_color_t termui_color_from_pixel(pixel_t pixel)
     187{
     188        return termui_color_from_rgb(RED(pixel), GREEN(pixel), BLUE(pixel));
     189}
     190
     191static termui_cell_t charfield_to_termui_cell(terminal_t *term, const charfield_t *cf)
     192{
     193        termui_cell_t cell = { };
     194
     195        cell.glyph_idx = fb_font_glyph(cf->ch, NULL);
     196
     197        switch (cf->attrs.type) {
    169198        case CHAR_ATTR_STYLE:
    170                 switch (attrs.val.style) {
     199                switch (cf->attrs.val.style) {
    171200                case STYLE_NORMAL:
    172                         *bgcolor = color_table[COLOR_WHITE + 8];
    173                         *fgcolor = color_table[COLOR_BLACK];
     201                        cell.bgcolor = term->default_bgcolor;
     202                        cell.fgcolor = term->default_fgcolor;
    174203                        break;
    175204                case STYLE_EMPHASIS:
    176                         *bgcolor = color_table[COLOR_WHITE + 8];
    177                         *fgcolor = color_table[COLOR_RED + 8];
     205                        cell.bgcolor = term->emphasis_bgcolor;
     206                        cell.fgcolor = term->emphasis_fgcolor;
    178207                        break;
    179208                case STYLE_INVERTED:
    180                         *bgcolor = color_table[COLOR_BLACK];
    181                         *fgcolor = color_table[COLOR_WHITE + 8];
     209                        cell.bgcolor = term->default_bgcolor;
     210                        cell.fgcolor = term->default_fgcolor;
     211                        cell.inverted = 1;
    182212                        break;
    183213                case STYLE_SELECTED:
    184                         *bgcolor = color_table[COLOR_RED + 8];
    185                         *fgcolor = color_table[COLOR_WHITE + 8];
     214                        cell.bgcolor = term->selection_bgcolor;
     215                        cell.fgcolor = term->selection_fgcolor;
    186216                        break;
    187217                }
    188218                break;
     219
    189220        case CHAR_ATTR_INDEX:
    190                 *bgcolor = color_table[(attrs.val.index.bgcolor & 7)];
    191                 *fgcolor = color_table[(attrs.val.index.fgcolor & 7) |
    192                     ((attrs.val.index.attr & CATTR_BRIGHT) ? 8 : 0)];
     221                char_attr_index_t index = cf->attrs.val.index;
     222
     223                int bright = (index.attr & CATTR_BRIGHT) ? COLOR_BRIGHT : 0;
     224                pixel_t bgcolor = _basic_colors[index.bgcolor | bright];
     225                pixel_t fgcolor = _basic_colors[index.fgcolor | bright];
     226                cell.bgcolor = termui_color_from_pixel(bgcolor);
     227                cell.fgcolor = termui_color_from_pixel(fgcolor);
     228
     229                if (index.attr & CATTR_BLINK)
     230                        cell.blink = 1;
     231
    193232                break;
     233
    194234        case CHAR_ATTR_RGB:
    195                 *bgcolor = 0xff000000 | attrs.val.rgb.bgcolor;
    196                 *fgcolor = 0xff000000 | attrs.val.rgb.fgcolor;
     235                cell.bgcolor = termui_color_from_pixel(cf->attrs.val.rgb.bgcolor);
     236                cell.fgcolor = termui_color_from_pixel(cf->attrs.val.rgb.fgcolor);
    197237                break;
    198238        }
     239
     240        return cell;
    199241}
    200242
     
    214256}
    215257
    216 static void term_update_char(terminal_t *term, pixelmap_t *pixelmap,
    217     sysarg_t col, sysarg_t row)
    218 {
    219         charfield_t *field =
    220             chargrid_charfield_at(term->backbuf, col, row);
    221 
    222         bool inverted = chargrid_cursor_at(term->backbuf, col, row);
    223 
    224         sysarg_t bx = col * FONT_WIDTH;
    225         sysarg_t by = row * FONT_SCANLINES;
    226 
    227         pixel_t bgcolor = 0;
    228         pixel_t fgcolor = 0;
    229 
    230         if (inverted)
    231                 attrs_rgb(field->attrs, &fgcolor, &bgcolor);
    232         else
    233                 attrs_rgb(field->attrs, &bgcolor, &fgcolor);
    234 
    235         // FIXME: Glyph type should be actually uint32_t
    236         //        for full UTF-32 coverage.
    237 
    238         uint16_t glyph = fb_font_glyph(field->ch, NULL);
     258static void term_draw_cell(terminal_t *term, pixelmap_t *pixelmap, int col, int row, const termui_cell_t *cell)
     259{
     260        termui_color_t bg = cell->bgcolor;
     261        if (bg == TERMUI_COLOR_DEFAULT)
     262                bg = term->default_bgcolor;
     263
     264        termui_color_t fg = cell->fgcolor;
     265        if (fg == TERMUI_COLOR_DEFAULT)
     266                fg = term->default_fgcolor;
     267
     268        pixel_t bgcolor = termui_color_to_pixel(bg);
     269        pixel_t fgcolor = termui_color_to_pixel(fg);
     270
     271        int bx = col * FONT_WIDTH;
     272        int by = row * FONT_SCANLINES;
     273
     274        // TODO: support bold/italic/underline/strike/blink styling
     275
     276        if (cell->inverted ^ cell->cursor) {
     277                pixel_t tmp = bgcolor;
     278                bgcolor = fgcolor;
     279                fgcolor = tmp;
     280        }
     281
     282        uint32_t glyph = cell->glyph_idx;
     283        assert(glyph < FONT_GLYPHS);
     284
     285        if (glyph == 0)
     286                glyph = fb_font_glyph(U' ', NULL);
    239287
    240288        for (unsigned int y = 0; y < FONT_SCANLINES; y++) {
     
    248296                }
    249297        }
     298
    250299        term_update_region(term, bx, by, FONT_WIDTH, FONT_SCANLINES);
    251300}
    252301
    253 static bool term_update_scroll(terminal_t *term, pixelmap_t *pixelmap)
    254 {
    255         sysarg_t top_row = chargrid_get_top_row(term->frontbuf);
    256 
    257         if (term->top_row == top_row) {
    258                 return false;
    259         }
    260 
    261         term->top_row = top_row;
    262 
    263         for (sysarg_t row = 0; row < term->rows; row++) {
    264                 for (sysarg_t col = 0; col < term->cols; col++) {
    265                         charfield_t *front_field =
    266                             chargrid_charfield_at(term->frontbuf, col, row);
    267                         charfield_t *back_field =
    268                             chargrid_charfield_at(term->backbuf, col, row);
    269                         bool update = false;
    270 
    271                         if (front_field->ch != back_field->ch) {
    272                                 back_field->ch = front_field->ch;
    273                                 update = true;
    274                         }
    275 
    276                         if (!attrs_same(front_field->attrs, back_field->attrs)) {
    277                                 back_field->attrs = front_field->attrs;
    278                                 update = true;
    279                         }
    280 
    281                         front_field->flags &= ~CHAR_FLAG_DIRTY;
    282 
    283                         if (update) {
    284                                 term_update_char(term, pixelmap, col, row);
    285                         }
    286                 }
    287         }
    288 
    289         return true;
    290 }
    291 
    292 static bool term_update_cursor(terminal_t *term, pixelmap_t *pixelmap)
    293 {
    294         bool update = false;
    295 
    296         sysarg_t front_col;
    297         sysarg_t front_row;
    298         chargrid_get_cursor(term->frontbuf, &front_col, &front_row);
    299 
    300         sysarg_t back_col;
    301         sysarg_t back_row;
    302         chargrid_get_cursor(term->backbuf, &back_col, &back_row);
    303 
    304         bool front_visibility =
    305             chargrid_get_cursor_visibility(term->frontbuf) &&
    306             term->is_focused;
    307         bool back_visibility =
    308             chargrid_get_cursor_visibility(term->backbuf);
    309 
    310         if (front_visibility != back_visibility) {
    311                 chargrid_set_cursor_visibility(term->backbuf,
    312                     front_visibility);
    313                 term_update_char(term, pixelmap, back_col, back_row);
    314                 update = true;
    315         }
    316 
    317         if ((front_col != back_col) || (front_row != back_row)) {
    318                 chargrid_set_cursor(term->backbuf, front_col, front_row);
    319                 term_update_char(term, pixelmap, back_col, back_row);
    320                 term_update_char(term, pixelmap, front_col, front_row);
    321                 update = true;
    322         }
    323 
    324         return update;
    325 }
    326 
    327 static void term_update(terminal_t *term)
    328 {
    329         pixelmap_t pixelmap;
     302static void term_render(terminal_t *term)
     303{
     304        gfx_coord2_t pos = { .x = 4, .y = 26 };
     305        (void) gfx_bitmap_render(term->bmp, &term->update, &pos);
     306
     307        term->update.p0.x = 0;
     308        term->update.p0.y = 0;
     309        term->update.p1.x = 0;
     310        term->update.p1.y = 0;
     311}
     312
     313static void termui_refresh_cb(void *userdata)
     314{
     315        terminal_t *term = userdata;
     316
     317        termui_force_viewport_update(term->termui, 0, termui_get_rows(term->termui));
     318}
     319
     320static void termui_scroll_cb(void *userdata, int delta)
     321{
     322        (void) delta;
     323
     324        // Until we have support for hardware accelerated scrolling, just redraw everything.
     325        termui_refresh_cb(userdata);
     326}
     327
     328static pixelmap_t term_get_pixelmap(terminal_t *term)
     329{
     330        pixelmap_t pixelmap = { };
    330331        gfx_bitmap_alloc_t alloc;
    331         gfx_coord2_t pos;
    332         errno_t rc;
    333 
    334         rc = gfx_bitmap_get_alloc(term->bmp, &alloc);
    335         if (rc != EOK) {
    336                 return;
    337         }
    338 
    339         fibril_mutex_lock(&term->mtx);
     332
     333        errno_t rc = gfx_bitmap_get_alloc(term->bmp, &alloc);
     334        if (rc != EOK)
     335                return pixelmap;
     336
    340337        pixelmap.width = term->w;
    341338        pixelmap.height = term->h;
    342339        pixelmap.data = alloc.pixels;
    343 
    344         bool update = false;
    345 
    346         if (term_update_scroll(term, &pixelmap)) {
    347                 update = true;
    348         } else {
    349                 for (sysarg_t y = 0; y < term->rows; y++) {
    350                         for (sysarg_t x = 0; x < term->cols; x++) {
    351                                 charfield_t *front_field =
    352                                     chargrid_charfield_at(term->frontbuf, x, y);
    353                                 charfield_t *back_field =
    354                                     chargrid_charfield_at(term->backbuf, x, y);
    355                                 bool cupdate = false;
    356 
    357                                 if ((front_field->flags & CHAR_FLAG_DIRTY) ==
    358                                     CHAR_FLAG_DIRTY) {
    359                                         if (front_field->ch != back_field->ch) {
    360                                                 back_field->ch = front_field->ch;
    361                                                 cupdate = true;
    362                                         }
    363 
    364                                         if (!attrs_same(front_field->attrs,
    365                                             back_field->attrs)) {
    366                                                 back_field->attrs = front_field->attrs;
    367                                                 cupdate = true;
    368                                         }
    369 
    370                                         front_field->flags &= ~CHAR_FLAG_DIRTY;
    371                                 }
    372 
    373                                 if (cupdate) {
    374                                         term_update_char(term, &pixelmap, x, y);
    375                                         update = true;
    376                                 }
    377                         }
    378                 }
    379         }
    380 
    381         if (term_update_cursor(term, &pixelmap))
    382                 update = true;
    383 
    384         if (update) {
    385                 pos.x = 4;
    386                 pos.y = 26;
    387                 (void) gfx_bitmap_render(term->bmp, &term->update, &pos);
    388 
    389                 term->update.p0.x = 0;
    390                 term->update.p0.y = 0;
    391                 term->update.p1.x = 0;
    392                 term->update.p1.y = 0;
    393         }
    394 
    395         fibril_mutex_unlock(&term->mtx);
    396 }
    397 
    398 static void term_repaint(terminal_t *term)
    399 {
    400         pixelmap_t pixelmap;
    401         gfx_bitmap_alloc_t alloc;
    402         errno_t rc;
    403 
    404         rc = gfx_bitmap_get_alloc(term->bmp, &alloc);
    405         if (rc != EOK) {
    406                 printf("Error getting bitmap allocation info.\n");
     340        return pixelmap;
     341}
     342
     343static void term_clear_bitmap(terminal_t *term, pixel_t color)
     344{
     345        pixelmap_t pixelmap = term_get_pixelmap(term);
     346        if (pixelmap.data == NULL)
    407347                return;
    408         }
    409 
    410         fibril_mutex_lock(&term->mtx);
    411 
    412         pixelmap.width = term->w;
    413         pixelmap.height = term->h;
    414         pixelmap.data = alloc.pixels;
    415 
    416         if (!term_update_scroll(term, &pixelmap)) {
    417                 for (sysarg_t y = 0; y < term->rows; y++) {
    418                         for (sysarg_t x = 0; x < term->cols; x++) {
    419                                 charfield_t *front_field =
    420                                     chargrid_charfield_at(term->frontbuf, x, y);
    421                                 charfield_t *back_field =
    422                                     chargrid_charfield_at(term->backbuf, x, y);
    423 
    424                                 back_field->ch = front_field->ch;
    425                                 back_field->attrs = front_field->attrs;
    426                                 front_field->flags &= ~CHAR_FLAG_DIRTY;
    427 
    428                                 term_update_char(term, &pixelmap, x, y);
    429                         }
    430                 }
    431         }
    432 
    433         term_update_cursor(term, &pixelmap);
    434 
    435         fibril_mutex_unlock(&term->mtx);
     348
     349        sysarg_t pixels = pixelmap.height * pixelmap.width;
     350        for (sysarg_t i = 0; i < pixels; i++)
     351                pixelmap.data[i] = color;
     352
     353        term_update_region(term, 0, 0, pixelmap.width, pixelmap.height);
     354}
     355
     356static void termui_update_cb(void *userdata, int col, int row, const termui_cell_t *cell, int len)
     357{
     358        terminal_t *term = userdata;
     359
     360        pixelmap_t pixelmap = term_get_pixelmap(term);
     361        if (pixelmap.data == NULL)
     362                return;
     363
     364        for (int i = 0; i < len; i++)
     365                term_draw_cell(term, &pixelmap, col + i, row, &cell[i]);
    436366}
    437367
     
    497427static void term_write_char(terminal_t *term, wchar_t ch)
    498428{
    499         sysarg_t updated = 0;
    500 
    501         fibril_mutex_lock(&term->mtx);
    502 
    503429        switch (ch) {
    504         case '\n':
    505                 updated = chargrid_newline(term->frontbuf);
     430        case L'\n':
     431                termui_put_crlf(term->termui);
    506432                break;
    507         case '\r':
     433        case L'\r':
     434                termui_put_cr(term->termui);
    508435                break;
    509         case '\t':
    510                 updated = chargrid_tabstop(term->frontbuf, 8);
     436        case L'\t':
     437                termui_put_tab(term->termui);
    511438                break;
    512         case '\b':
    513                 updated = chargrid_backspace(term->frontbuf);
     439        case L'\b':
     440                termui_put_backspace(term->termui);
    514441                break;
    515442        default:
    516                 updated = chargrid_putuchar(term->frontbuf, ch, true);
    517         }
    518 
    519         fibril_mutex_unlock(&term->mtx);
    520 
    521         if (updated > 1)
    522                 term_update(term);
     443                // TODO: For some languages, we might need support for combining
     444                //       characters. Currently, we assume every unicode code point is
     445                //       an individual printed character, which is not always the case.
     446                termui_put_glyph(term->termui, fb_font_glyph(ch, NULL), 1);
     447                break;
     448        }
    523449}
    524450
     
    526452{
    527453        terminal_t *term = srv_to_terminal(srv);
     454
     455        fibril_mutex_lock(&term->mtx);
    528456
    529457        size_t off = 0;
     
    531459                term_write_char(term, str_decode(data, &off, size));
    532460
     461        fibril_mutex_unlock(&term->mtx);
     462
     463        term_render(term);
    533464        gfx_update(term->gc);
    534465        *nwritten = size;
     466
    535467        return EOK;
    536468}
     
    540472        terminal_t *term = srv_to_terminal(srv);
    541473
    542         term_update(term);
     474        term_render(term);
    543475        gfx_update(term->gc);
    544476}
     
    549481
    550482        fibril_mutex_lock(&term->mtx);
    551         chargrid_clear(term->frontbuf);
    552         fibril_mutex_unlock(&term->mtx);
    553 
    554         term_update(term);
     483        termui_clear_screen(term->termui);
     484        fibril_mutex_unlock(&term->mtx);
     485
     486        term_render(term);
    555487        gfx_update(term->gc);
    556488}
     
    561493
    562494        fibril_mutex_lock(&term->mtx);
    563         chargrid_set_cursor(term->frontbuf, col, row);
    564         fibril_mutex_unlock(&term->mtx);
    565 
    566         term_update(term);
     495        termui_set_pos(term->termui, col, row);
     496        fibril_mutex_unlock(&term->mtx);
     497
     498        term_render(term);
    567499        gfx_update(term->gc);
    568500}
     
    573505
    574506        fibril_mutex_lock(&term->mtx);
    575         chargrid_get_cursor(term->frontbuf, col, row);
    576         fibril_mutex_unlock(&term->mtx);
     507        int irow, icol;
     508        termui_get_pos(term->termui, &icol, &irow);
     509        fibril_mutex_unlock(&term->mtx);
     510
     511        *col = icol;
     512        *row = irow;
    577513
    578514        return EOK;
     
    584520
    585521        fibril_mutex_lock(&term->mtx);
    586         *cols = term->cols;
    587         *rows = term->rows;
     522        *cols = termui_get_cols(term->termui);
     523        *rows = termui_get_rows(term->termui);
    588524        fibril_mutex_unlock(&term->mtx);
    589525
     
    603539        terminal_t *term = srv_to_terminal(srv);
    604540
    605         fibril_mutex_lock(&term->mtx);
    606         chargrid_set_style(term->frontbuf, style);
     541        termui_cell_t cellstyle = { };
     542
     543        switch (style) {
     544        case STYLE_NORMAL:
     545                cellstyle.bgcolor = term->default_bgcolor;
     546                cellstyle.fgcolor = term->default_fgcolor;
     547                break;
     548        case STYLE_EMPHASIS:
     549                cellstyle.bgcolor = term->emphasis_bgcolor;
     550                cellstyle.fgcolor = term->emphasis_fgcolor;
     551                break;
     552        case STYLE_INVERTED:
     553                cellstyle.bgcolor = term->default_bgcolor;
     554                cellstyle.fgcolor = term->default_fgcolor;
     555                cellstyle.inverted = 1;
     556                break;
     557        case STYLE_SELECTED:
     558                cellstyle.bgcolor = term->selection_bgcolor;
     559                cellstyle.fgcolor = term->selection_fgcolor;
     560                break;
     561        }
     562
     563        fibril_mutex_lock(&term->mtx);
     564        termui_set_style(term->termui, cellstyle);
    607565        fibril_mutex_unlock(&term->mtx);
    608566}
     
    613571        terminal_t *term = srv_to_terminal(srv);
    614572
    615         fibril_mutex_lock(&term->mtx);
    616         chargrid_set_color(term->frontbuf, bgcolor, fgcolor, attr);
     573        int bright = (attr & CATTR_BRIGHT) ? COLOR_BRIGHT : 0;
     574
     575        termui_cell_t cellstyle = { };
     576        cellstyle.bgcolor = termui_color_from_pixel(_basic_colors[bgcolor | bright]);
     577        cellstyle.fgcolor = termui_color_from_pixel(_basic_colors[fgcolor | bright]);
     578
     579        if (attr & CATTR_BLINK)
     580                cellstyle.blink = 1;
     581
     582        fibril_mutex_lock(&term->mtx);
     583        termui_set_style(term->termui, cellstyle);
    617584        fibril_mutex_unlock(&term->mtx);
    618585}
     
    622589{
    623590        terminal_t *term = srv_to_terminal(srv);
    624 
    625         fibril_mutex_lock(&term->mtx);
    626         chargrid_set_rgb_color(term->frontbuf, bgcolor, fgcolor);
     591        termui_cell_t cellstyle = {
     592                .bgcolor = termui_color_from_pixel(bgcolor),
     593                .fgcolor = termui_color_from_pixel(fgcolor),
     594        };
     595
     596        fibril_mutex_lock(&term->mtx);
     597        termui_set_style(term->termui, cellstyle);
    627598        fibril_mutex_unlock(&term->mtx);
    628599}
     
    633604
    634605        fibril_mutex_lock(&term->mtx);
    635         chargrid_set_cursor_visibility(term->frontbuf, visible);
    636         fibril_mutex_unlock(&term->mtx);
    637 
    638         term_update(term);
     606        termui_set_cursor_visibility(term->termui, visible);
     607        fibril_mutex_unlock(&term->mtx);
     608
     609        term_render(term);
    639610        gfx_update(term->gc);
    640611}
     
    655626        fibril_mutex_unlock(&term->mtx);
    656627
    657         term_update(term);
     628        term_render(term);
    658629        gfx_update(term->gc);
    659630        return EOK;
     
    703674        term->urows = rows;
    704675        term->ubuf = buf;
     676
     677        /* Scroll back to active screen. */
     678        termui_history_scroll(term->termui, INT_MAX);
     679
    705680        fibril_mutex_unlock(&term->mtx);
    706681
     
    723698        term->ubuf = NULL;
    724699
     700        termui_wipe_screen(term->termui, 0);
     701
     702        fibril_mutex_unlock(&term->mtx);
     703
     704        /* Update terminal */
     705        term_render(term);
     706        gfx_update(term->gc);
     707
    725708        if (buf != NULL)
    726709                as_area_destroy(buf);
    727 
    728         fibril_mutex_unlock(&term->mtx);
    729710}
    730711
     
    741722{
    742723        terminal_t *term = srv_to_terminal(srv);
    743         charfield_t *ch;
    744         sysarg_t col, row;
    745724
    746725        fibril_mutex_lock(&term->mtx);
     
    752731
    753732        /* Make sure we have meaningful coordinates, within bounds */
    754 
    755         if (c1 > term->ucols)
    756                 c1 = term->ucols;
    757         if (c1 > term->cols)
    758                 c1 = term->cols;
    759         if (c0 >= c1) {
     733        c1 = min(c1, term->ucols);
     734        c1 = min(c1, (sysarg_t) termui_get_cols(term->termui));
     735        r1 = min(r1, term->urows);
     736        r1 = min(r1, (sysarg_t) termui_get_rows(term->termui));
     737
     738        if (c0 >= c1 || r0 >= r1) {
    760739                fibril_mutex_unlock(&term->mtx);
    761740                return;
    762741        }
    763         if (r1 > term->urows)
    764                 r1 = term->urows;
    765         if (r1 > term->rows)
    766                 r1 = term->rows;
    767         if (r0 >= r1) {
    768                 fibril_mutex_unlock(&term->mtx);
    769                 return;
    770         }
    771742
    772743        /* Update front buffer from user buffer */
    773744
    774         for (row = r0; row < r1; row++) {
    775                 for (col = c0; col < c1; col++) {
    776                         ch = chargrid_charfield_at(term->frontbuf, col, row);
    777                         *ch = term->ubuf[row * term->ucols + col];
     745        for (sysarg_t row = r0; row < r1; row++) {
     746                termui_cell_t *cells = termui_get_active_row(term->termui, row);
     747
     748                for (sysarg_t col = c0; col < c1; col++) {
     749                        cells[col] = charfield_to_termui_cell(term, &term->ubuf[row * term->ucols + col]);
    778750                }
     751
     752                termui_update_cb(term, c0, row, &cells[c0], c1 - c0);
    779753        }
    780754
     
    782756
    783757        /* Update terminal */
    784         term_update(term);
     758        term_render(term);
    785759        gfx_update(term->gc);
    786760}
    787761
    788 static void deinit_terminal(terminal_t *term)
     762static errno_t terminal_window_resize(terminal_t *term)
     763{
     764        gfx_rect_t rect;
     765        ui_window_get_app_rect(term->window, &rect);
     766
     767        int width = rect.p1.x - rect.p0.x;
     768        int height = rect.p1.y - rect.p0.y;
     769
     770        if (!term->gc)
     771                term->gc = ui_window_get_gc(term->window);
     772        else
     773                assert(term->gc == ui_window_get_gc(term->window));
     774
     775        if (!term->ui_res)
     776                term->ui_res = ui_window_get_res(term->window);
     777        else
     778                assert(term->ui_res == ui_window_get_res(term->window));
     779
     780        gfx_bitmap_t *new_bmp;
     781        gfx_bitmap_params_t params;
     782        gfx_bitmap_params_init(&params);
     783        params.rect.p0.x = 0;
     784        params.rect.p0.y = 0;
     785        params.rect.p1.x = width;
     786        params.rect.p1.y = height;
     787
     788        errno_t rc = gfx_bitmap_create(term->gc, &params, NULL, &new_bmp);
     789        if (rc != EOK) {
     790                fprintf(stderr, "Error allocating new screen bitmap: %s\n", str_error(rc));
     791                return rc;
     792        }
     793
     794        if (term->bmp) {
     795                rc = gfx_bitmap_destroy(term->bmp);
     796                if (rc != EOK)
     797                        fprintf(stderr, "Error deallocating old screen bitmap: %s\n", str_error(rc));
     798        }
     799
     800        term->bmp = new_bmp;
     801        term->w = width;
     802        term->h = height;
     803
     804        term_clear_bitmap(term, termui_color_to_pixel(term->default_bgcolor));
     805
     806        return EOK;
     807}
     808
     809void terminal_destroy(terminal_t *term)
    789810{
    790811        list_remove(&term->link);
    791812
    792         if (term->frontbuf)
    793                 chargrid_destroy(term->frontbuf);
    794 
    795         if (term->backbuf)
    796                 chargrid_destroy(term->backbuf);
    797 }
    798 
    799 void terminal_destroy(terminal_t *term)
    800 {
    801         deinit_terminal(term);
     813        termui_destroy(term->termui);
     814
     815        if (term->ubuf)
     816                as_area_destroy(term->ubuf);
     817
    802818        free(term);
    803819}
     
    833849        (void)nfocus;
    834850        term->is_focused = true;
    835         term_update(term);
     851        term_render(term);
    836852        gfx_update(term->gc);
     853}
     854
     855static void terminal_resize_handler(ui_window_t *window, void *arg)
     856{
     857        terminal_t *term = (terminal_t *) arg;
     858
     859        fibril_mutex_lock(&term->mtx);
     860
     861        errno_t rc = terminal_window_resize(term);
     862        if (rc == EOK) {
     863                (void) termui_resize(term->termui, term->w / FONT_WIDTH, term->h / FONT_SCANLINES, SCROLLBACK_MAX_LINES);
     864                termui_refresh_cb(term);
     865                term_render(term);
     866                gfx_update(term->gc);
     867
     868                cons_event_t event = { .type = CEV_RESIZE };
     869                terminal_queue_cons_event(term, &event);
     870        }
     871
     872        fibril_mutex_unlock(&term->mtx);
     873}
     874
     875static void terminal_resize_event(ui_window_t *window, void *arg)
     876{
     877        ui_window_def_resize(window);
     878        terminal_resize_handler(window, arg);
     879}
     880
     881static void terminal_maximize_event(ui_window_t *window, void *arg)
     882{
     883        ui_window_def_maximize(window);
     884        terminal_resize_handler(window, arg);
     885}
     886
     887static void terminal_unmaximize_event(ui_window_t *window, void *arg)
     888{
     889        ui_window_def_unmaximize(window);
     890        terminal_resize_handler(window, arg);
    837891}
    838892
     
    847901        event.ev.key = *kbd_event;
    848902
    849         terminal_queue_cons_event(term, &event);
     903        const int PAGE_ROWS = (termui_get_rows(term->termui) * 2) / 3;
     904
     905        fibril_mutex_lock(&term->mtx);
     906
     907        if (!term->ubuf && kbd_event->type == KEY_PRESS &&
     908            (kbd_event->key == KC_PAGE_UP || kbd_event->key == KC_PAGE_DOWN)) {
     909
     910                termui_history_scroll(term->termui,
     911                    (kbd_event->key == KC_PAGE_UP) ? -PAGE_ROWS : PAGE_ROWS);
     912
     913                term_render(term);
     914                gfx_update(term->gc);
     915        } else {
     916                terminal_queue_cons_event(term, &event);
     917        }
     918
     919        fibril_mutex_unlock(&term->mtx);
    850920}
    851921
     
    856926        terminal_t *term = (terminal_t *) arg;
    857927
     928        switch (event->type) {
     929        case POS_UPDATE:
     930                return;
     931
     932        case POS_PRESS:
     933        case POS_RELEASE:
     934        case POS_DCLICK:
     935        }
     936
     937        /* Ignore mouse events when we're in scrollback mode. */
     938        if (termui_scrollback_is_active(term->termui))
     939                return;
     940
    858941        sysarg_t sx = -term->off.x;
    859942        sysarg_t sy = -term->off.y;
    860943
    861         if (event->type == POS_PRESS || event->type == POS_RELEASE ||
    862             event->type == POS_DCLICK) {
    863                 cevent.type = CEV_POS;
    864                 cevent.ev.pos.type = event->type;
    865                 cevent.ev.pos.pos_id = event->pos_id;
    866                 cevent.ev.pos.btn_num = event->btn_num;
    867 
    868                 cevent.ev.pos.hpos = (event->hpos - sx) / FONT_WIDTH;
    869                 cevent.ev.pos.vpos = (event->vpos - sy) / FONT_SCANLINES;
     944        if (event->hpos < sx || event->vpos < sy)
     945                return;
     946
     947        cevent.type = CEV_POS;
     948        cevent.ev.pos.type = event->type;
     949        cevent.ev.pos.pos_id = event->pos_id;
     950        cevent.ev.pos.btn_num = event->btn_num;
     951
     952        cevent.ev.pos.hpos = (event->hpos - sx) / FONT_WIDTH;
     953        cevent.ev.pos.vpos = (event->vpos - sy) / FONT_SCANLINES;
     954
     955        /* Filter out events outside the terminal area. */
     956        int cols = termui_get_cols(term->termui);
     957        int rows = termui_get_rows(term->termui);
     958
     959        if (cevent.ev.pos.hpos < (sysarg_t) cols && cevent.ev.pos.vpos < (sysarg_t) rows)
    870960                terminal_queue_cons_event(term, &cevent);
    871         }
    872961}
    873962
     
    880969        if (nfocus == 0) {
    881970                term->is_focused = false;
    882                 term_update(term);
     971                term_render(term);
    883972                gfx_update(term->gc);
    884973        }
     
    902991
    903992        if (!atomic_flag_test_and_set(&term->refcnt))
    904                 chargrid_set_cursor_visibility(term->frontbuf, true);
     993                termui_set_cursor_visibility(term->termui, true);
    905994
    906995        con_conn(icall, &term->srvs);
     996}
     997
     998static errno_t term_init_window(terminal_t *term, const char *display_spec,
     999    gfx_coord_t width, gfx_coord_t height,
     1000    gfx_coord_t min_width, gfx_coord_t min_height,
     1001    terminal_flags_t flags)
     1002{
     1003        gfx_rect_t min_rect = { { 0, 0 }, { min_width, min_height } };
     1004
     1005        ui_wnd_params_t wparams;
     1006        ui_wnd_params_init(&wparams);
     1007        wparams.caption = "Terminal";
     1008        wparams.style |= ui_wds_maximize_btn | ui_wds_resizable;
     1009        if ((flags & tf_topleft) != 0)
     1010                wparams.placement = ui_wnd_place_top_left;
     1011
     1012        errno_t rc = ui_create(display_spec, &term->ui);
     1013        if (rc != EOK) {
     1014                printf("Error creating UI on %s.\n", display_spec);
     1015                return rc;
     1016        }
     1017
     1018        /* Compute wrect such that application area corresponds to rect. */
     1019        gfx_rect_t wrect;
     1020        ui_wdecor_rect_from_app(term->ui, wparams.style, &min_rect, &wrect);
     1021        gfx_rect_rtranslate(&wrect.p0, &wrect, &wparams.rect);
     1022
     1023        rc = ui_window_create(term->ui, &wparams, &term->window);
     1024        if (rc != EOK)
     1025                return rc;
     1026
     1027        gfx_rect_t rect = { { 0, 0 }, { width, height } };
     1028        ui_wdecor_rect_from_app(term->ui, wparams.style, &rect, &rect);
     1029        term->off = rect.p0;
     1030        gfx_rect_rtranslate(&term->off, &rect, &wrect);
     1031
     1032        ui_window_resize(term->window, &wrect);
     1033        ui_window_set_cb(term->window, &terminal_window_cb, (void *) term);
     1034
     1035        return terminal_window_resize(term);
    9071036}
    9081037
     
    9111040    terminal_t **rterm)
    9121041{
    913         terminal_t *term;
    914         gfx_bitmap_params_t params;
    915         ui_wnd_params_t wparams;
    916         gfx_rect_t rect;
    917         gfx_coord2_t off;
    918         gfx_rect_t wrect;
     1042        printf("terminal_create(%zu, %zu)\n", width, height);
     1043
    9191044        errno_t rc;
    9201045
    921         term = calloc(1, sizeof(terminal_t));
     1046        terminal_t *term = calloc(1, sizeof(terminal_t));
    9221047        if (term == NULL) {
    9231048                printf("Out of memory.\n");
     
    9321057        term->char_remains_len = 0;
    9331058
    934         term->w = width;
    935         term->h = height;
    936 
    937         term->cols = width / FONT_WIDTH;
    938         term->rows = height / FONT_SCANLINES;
    939 
    940         term->frontbuf = NULL;
    941         term->backbuf = NULL;
    942 
    943         term->frontbuf = chargrid_create(term->cols, term->rows,
    944             CHARGRID_FLAG_NONE);
    945         if (!term->frontbuf) {
    946                 printf("Error creating front buffer.\n");
     1059        term->default_bgcolor = termui_color_from_pixel(_basic_colors[COLOR_WHITE | COLOR_BRIGHT]);
     1060        term->default_fgcolor = termui_color_from_pixel(_basic_colors[COLOR_BLACK]);
     1061
     1062        term->emphasis_bgcolor = termui_color_from_pixel(_basic_colors[COLOR_WHITE | COLOR_BRIGHT]);
     1063        term->emphasis_fgcolor = termui_color_from_pixel(_basic_colors[COLOR_RED | COLOR_BRIGHT]);
     1064
     1065        term->selection_bgcolor = termui_color_from_pixel(_basic_colors[COLOR_RED | COLOR_BRIGHT]);
     1066        term->selection_fgcolor = termui_color_from_pixel(_basic_colors[COLOR_WHITE | COLOR_BRIGHT]);
     1067
     1068        term->termui = termui_create(width / FONT_WIDTH, height / FONT_SCANLINES,
     1069            SCROLLBACK_MAX_LINES);
     1070        if (!term->termui) {
     1071                printf("Error creating terminal UI.\n");
    9471072                rc = ENOMEM;
    9481073                goto error;
    9491074        }
    9501075
    951         term->backbuf = chargrid_create(term->cols, term->rows,
    952             CHARGRID_FLAG_NONE);
    953         if (!term->backbuf) {
    954                 printf("Error creating back buffer.\n");
    955                 rc = ENOMEM;
     1076        termui_set_refresh_cb(term->termui, termui_refresh_cb, term);
     1077        termui_set_scroll_cb(term->termui, termui_scroll_cb, term);
     1078        termui_set_update_cb(term->termui, termui_update_cb, term);
     1079
     1080        rc = term_init_window(term, display_spec, width, height,
     1081            MIN_WINDOW_COLS * FONT_WIDTH, MIN_WINDOW_ROWS * FONT_SCANLINES, flags);
     1082        if (rc != EOK) {
     1083                printf("Error creating window (%s).\n", str_error(rc));
    9561084                goto error;
    9571085        }
    958 
    959         rect.p0.x = 0;
    960         rect.p0.y = 0;
    961         rect.p1.x = width;
    962         rect.p1.y = height;
    963 
    964         ui_wnd_params_init(&wparams);
    965         wparams.caption = "Terminal";
    966         if ((flags & tf_topleft) != 0)
    967                 wparams.placement = ui_wnd_place_top_left;
    968 
    969         rc = ui_create(display_spec, &term->ui);
    970         if (rc != EOK) {
    971                 printf("Error creating UI on %s.\n", display_spec);
    972                 goto error;
    973         }
    974 
    975         /*
    976          * Compute window rectangle such that application area corresponds
    977          * to rect
    978          */
    979         ui_wdecor_rect_from_app(term->ui, wparams.style, &rect, &wrect);
    980         off = wrect.p0;
    981         gfx_rect_rtranslate(&off, &wrect, &wparams.rect);
    982 
    983         term->off = off;
    984 
    985         rc = ui_window_create(term->ui, &wparams, &term->window);
    986         if (rc != EOK) {
    987                 printf("Error creating window.\n");
    988                 goto error;
    989         }
    990 
    991         term->gc = ui_window_get_gc(term->window);
    992         term->ui_res = ui_window_get_res(term->window);
    993 
    994         ui_window_set_cb(term->window, &terminal_window_cb, (void *) term);
    995 
    996         gfx_bitmap_params_init(&params);
    997         params.rect.p0.x = 0;
    998         params.rect.p0.y = 0;
    999         params.rect.p1.x = width;
    1000         params.rect.p1.y = height;
    1001 
    1002         rc = gfx_bitmap_create(term->gc, &params, NULL, &term->bmp);
    1003         if (rc != EOK) {
    1004                 printf("Error allocating screen bitmap.\n");
    1005                 goto error;
    1006         }
    1007 
    1008         chargrid_clear(term->frontbuf);
    1009         chargrid_clear(term->backbuf);
    1010         term->top_row = 0;
    10111086
    10121087        async_set_fallback_port_handler(term_connection, NULL);
     
    10461121        term->is_focused = true;
    10471122
    1048         term->update.p0.x = 0;
    1049         term->update.p0.y = 0;
    1050         term->update.p1.x = 0;
    1051         term->update.p1.y = 0;
    1052 
    1053         term_repaint(term);
     1123        termui_refresh_cb(term);
    10541124
    10551125        *rterm = term;
     
    10641134        if (term->ui != NULL)
    10651135                ui_destroy(term->ui);
    1066         if (term->frontbuf != NULL)
    1067                 chargrid_destroy(term->frontbuf);
    1068         if (term->backbuf != NULL)
    1069                 chargrid_destroy(term->backbuf);
     1136        if (term->termui != NULL)
     1137                termui_destroy(term->termui);
    10701138        free(term);
    10711139        return rc;
  • uspace/app/terminal/terminal.h

    rdd50aa19 r899bdfd  
    4545#include <gfx/context.h>
    4646#include <gfx/coord.h>
    47 #include <io/chargrid.h>
    4847#include <io/con_srv.h>
    4948#include <loc.h>
     
    5150#include <str.h>
    5251#include <task.h>
     52#include <termui.h>
    5353#include <ui/ui.h>
    5454#include <ui/window.h>
     
    8181        size_t char_remains_len;
    8282
    83         sysarg_t cols;
    84         sysarg_t rows;
    85         chargrid_t *frontbuf;
    86         chargrid_t *backbuf;
    87         sysarg_t top_row;
     83        termui_t *termui;
     84
     85        termui_color_t default_bgcolor;
     86        termui_color_t default_fgcolor;
     87        termui_color_t emphasis_bgcolor;
     88        termui_color_t emphasis_fgcolor;
     89        termui_color_t selection_bgcolor;
     90        termui_color_t selection_fgcolor;
    8891
    8992        sysarg_t ucols;
  • uspace/app/tetris/screen.c

    rdd50aa19 r899bdfd  
    7979static usec_t timeleft = 0;
    8080
     81bool size_changed;
    8182console_ctrl_t *console;
    8283
     
    217218
    218219        fprintf(stderr, "aborting: %s", why);
    219         abort();
     220        exit(1);
    220221}
    221222
     
    410411                        exit(1);
    411412
     413                if (event.type == CEV_RESIZE)
     414                        size_changed = true;
     415
    412416                if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS)
    413417                        c = event.ev.key.c;
  • uspace/app/tetris/screen.h

    rdd50aa19 r899bdfd  
    6767extern console_ctrl_t *console;
    6868extern winsize_t winsize;
     69extern bool size_changed;
    6970
    7071extern void moveto(sysarg_t r, sysarg_t c);
  • uspace/app/tetris/tetris.c

    rdd50aa19 r899bdfd  
    330330
    331331                while (true) {
     332                        if (size_changed) {
     333                                size_changed = false;
     334                                scr_set();
     335                                scr_msg(key_msg, 1);
     336                        }
     337
    332338                        place(curshape, pos, 1);
    333339                        scr_update();
  • uspace/lib/clui/src/tinput.c

    rdd50aa19 r899bdfd  
    113113static void tinput_display_tail(tinput_t *ti, size_t start, size_t pad)
    114114{
    115         char32_t *dbuf = malloc((INPUT_MAX_SIZE + 1) * sizeof(char32_t));
    116         if (!dbuf)
    117                 return;
    118 
     115        char32_t stash;
    119116        size_t sa;
    120117        size_t sb;
    121118        tinput_sel_get_bounds(ti, &sa, &sb);
     119        assert(sa <= sb);
    122120
    123121        tinput_console_set_lpos(ti, ti->text_coord + start);
    124122        console_set_style(ti->console, STYLE_NORMAL);
    125123
    126         size_t p = start;
    127         if (p < sa) {
    128                 memcpy(dbuf, ti->buffer + p, (sa - p) * sizeof(char32_t));
    129                 dbuf[sa - p] = '\0';
    130                 printf("%ls", dbuf);
    131                 p = sa;
    132         }
    133 
    134         if (p < sb) {
     124        sa = max(start, sa);
     125        sb = max(start, sb);
     126
     127        if (start < sa) {
     128                stash = ti->buffer[sa];
     129                ti->buffer[sa] = L'\0';
     130                printf("%ls", &ti->buffer[start]);
     131                ti->buffer[sa] = stash;
     132        }
     133
     134        if (sa < sb) {
    135135                console_flush(ti->console);
    136136                console_set_style(ti->console, STYLE_SELECTED);
    137137
    138                 memcpy(dbuf, ti->buffer + p,
    139                     (sb - p) * sizeof(char32_t));
    140                 dbuf[sb - p] = '\0';
    141                 printf("%ls", dbuf);
    142                 p = sb;
    143         }
     138                stash = ti->buffer[sb];
     139                ti->buffer[sb] = L'\0';
     140                printf("%ls", &ti->buffer[sa]);
     141                ti->buffer[sb] = stash;
     142
     143                console_flush(ti->console);
     144                console_set_style(ti->console, STYLE_NORMAL);
     145        }
     146
     147        if (sb < ti->nc) {
     148                ti->buffer[ti->nc] = L'\0';
     149                printf("%ls", &ti->buffer[sb]);
     150        }
     151
     152        for (; pad > 0; pad--)
     153                putuchar(' ');
    144154
    145155        console_flush(ti->console);
    146         console_set_style(ti->console, STYLE_NORMAL);
    147 
    148         if (p < ti->nc) {
    149                 memcpy(dbuf, ti->buffer + p,
    150                     (ti->nc - p) * sizeof(char32_t));
    151                 dbuf[ti->nc - p] = '\0';
    152                 printf("%ls", dbuf);
    153         }
    154 
    155         for (p = 0; p < pad; p++)
    156                 putuchar(' ');
    157 
    158         console_flush(ti->console);
    159 
    160         free(dbuf);
    161156}
    162157
     
    218213        tinput_display_prompt(ti);
    219214
    220         /* The screen might have scrolled after priting the prompt */
     215        /* The screen might have scrolled after printing the prompt */
    221216        tinput_update_origin_coord(ti, ti->prompt_coord + str_width(ti->prompt));
    222217
     
    237232                return;
    238233
    239         unsigned new_width = LIN_TO_COL(ti, ti->text_coord) + ti->nc + 1;
    240         if (new_width % ti->con_cols == 0) {
    241                 /* Advancing to new line. */
    242                 sysarg_t new_height = (new_width / ti->con_cols) + 1;
    243                 if (new_height >= ti->con_rows) {
    244                         /* Disallow text longer than 1 page for now. */
    245                         return;
    246                 }
    247         }
     234        /* Disallow text longer than 1 page for now. */
     235        unsigned prompt_len = ti->text_coord - ti->prompt_coord;
     236        if (prompt_len + ti->nc + 1 >= ti->con_cols * ti->con_rows)
     237                return;
    248238
    249239        size_t i;
     
    881871}
    882872
     873static errno_t tinput_resize(tinput_t *ti)
     874{
     875        assert(ti->prompt_coord % ti->con_cols == 0);
     876
     877        errno_t rc = console_get_size(ti->console, &ti->con_cols, &ti->con_rows);
     878        if (rc != EOK)
     879                return rc;
     880
     881        sysarg_t col, row;
     882        rc = console_get_pos(ti->console, &col, &row);
     883        if (rc != EOK)
     884                return rc;
     885
     886        assert(ti->prompt_coord <= ti->text_coord);
     887        unsigned prompt_len = ti->text_coord - ti->prompt_coord;
     888
     889        size_t new_caret_coord = row * ti->con_cols + col;
     890
     891        if (prompt_len <= new_caret_coord && ti->pos <= new_caret_coord - prompt_len) {
     892                ti->text_coord = new_caret_coord - ti->pos;
     893                ti->prompt_coord = ti->text_coord - prompt_len;
     894
     895                unsigned prompt_col = ti->prompt_coord % ti->con_cols;
     896                if (prompt_col != 0) {
     897                        /*
     898                         * Prompt doesn't seem to start at column 0, which means
     899                         * the console didn't reflow the line like we expected it to.
     900                         * Change offsets a bit to recover.
     901                         */
     902                        fprintf(stderr, "Unexpected prompt position after resize.\n");
     903                        ti->prompt_coord -= prompt_col;
     904                        ti->text_coord -= prompt_col;
     905
     906                        console_cursor_visibility(ti->console, false);
     907                        tinput_display_prompt(ti);
     908                        tinput_display_tail(ti, 0, prompt_col);
     909                        tinput_position_caret(ti);
     910                        console_cursor_visibility(ti->console, true);
     911                }
     912
     913                assert(ti->prompt_coord % ti->con_cols == 0);
     914        } else {
     915                /*
     916                 * Overflown screen.
     917                 * We will just trim the buffer and rewrite everything.
     918                 */
     919                console_clear(ti->console);
     920
     921                ti->nc = min(ti->nc, ti->con_cols * ti->con_rows - prompt_len - 1);
     922                ti->pos = min(ti->pos, ti->nc);
     923                ti->sel_start = min(ti->sel_start, ti->nc);
     924
     925                ti->prompt_coord = 0;
     926                ti->text_coord = prompt_len;
     927
     928                console_cursor_visibility(ti->console, false);
     929                tinput_display_prompt(ti);
     930                tinput_display_tail(ti, 0, 0);
     931                tinput_position_caret(ti);
     932                console_cursor_visibility(ti->console, true);
     933        }
     934
     935        assert(ti->nc + ti->text_coord < ti->con_cols * ti->con_rows);
     936
     937        return EOK;
     938}
     939
    883940/** Read in one line of input with initial text provided.
    884941 *
     
    927984                        tinput_pos(ti, &ev.ev.pos);
    928985                        break;
     986                case CEV_RESIZE:
     987                        tinput_resize(ti);
     988                        break;
    929989                }
    930990        }
  • uspace/lib/console/include/io/cons_event.h

    rdd50aa19 r899bdfd  
    4444        CEV_KEY,
    4545        /** Position event */
    46         CEV_POS
     46        CEV_POS,
     47        /** Resize event */
     48        CEV_RESIZE,
    4749} cons_event_type_t;
    4850
  • uspace/lib/console/src/con_srv.c

    rdd50aa19 r899bdfd  
    5353                ipc_set_arg4(icall, event->ev.key.mods);
    5454                ipc_set_arg5(icall, event->ev.key.c);
    55                 break;
     55                return EOK;
    5656        case CEV_POS:
    5757                ipc_set_arg2(icall, (event->ev.pos.pos_id << 16) | (event->ev.pos.type & 0xffff));
     
    5959                ipc_set_arg4(icall, event->ev.pos.hpos);
    6060                ipc_set_arg5(icall, event->ev.pos.vpos);
    61                 break;
    62         default:
    63                 return EIO;
    64         }
    65 
    66         return EOK;
     61                return EOK;
     62        case CEV_RESIZE:
     63                ipc_set_arg2(icall, 0);
     64                ipc_set_arg3(icall, 0);
     65                ipc_set_arg4(icall, 0);
     66                ipc_set_arg5(icall, 0);
     67                return EOK;
     68        }
     69
     70        return EIO;
    6771}
    6872
  • uspace/lib/console/src/console.c

    rdd50aa19 r899bdfd  
    193193                event->ev.key.mods = ipc_get_arg4(call);
    194194                event->ev.key.c = ipc_get_arg5(call);
    195                 break;
     195                return EOK;
    196196        case CEV_POS:
    197197                event->ev.pos.pos_id = ipc_get_arg2(call) >> 16;
     
    200200                event->ev.pos.hpos = ipc_get_arg4(call);
    201201                event->ev.pos.vpos = ipc_get_arg5(call);
    202                 break;
    203         default:
    204                 return EIO;
    205         }
    206 
    207         return EOK;
     202                return EOK;
     203        case CEV_RESIZE:
     204                return EOK;
     205        }
     206
     207        return EIO;
    208208}
    209209
  • uspace/lib/meson.build

    rdd50aa19 r899bdfd  
    9191        'sif',
    9292        'tbarcfg',
     93        'termui',
    9394        'trackmod',
    9495        'untar',
  • uspace/lib/ui/src/ui.c

    rdd50aa19 r899bdfd  
    357357
    358358                break;
     359        case CEV_RESIZE:
     360                ui_lock(ui);
     361                ui_window_send_resize(awnd);
     362                ui_unlock(ui);
     363                break;
    359364        }
    360365}
Note: See TracChangeset for help on using the changeset viewer.