Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/terminal/terminal.c

    re273e9e r77ffa01  
    11/*
    2  * Copyright (c) 2024 Jiri Svoboda
     2 * Copyright (c) 2021 Jiri Svoboda
    33 * Copyright (c) 2012 Petr Koupy
    44 * All rights reserved.
     
    4040#include <errno.h>
    4141#include <fbfont/font-8x16.h>
    42 #include <fibril.h>
     42#include <io/chargrid.h>
    4343#include <gfx/bitmap.h>
    4444#include <gfx/context.h>
     
    4848#include <io/console.h>
    4949#include <io/pixelmap.h>
    50 #include <macros.h>
     50#include <task.h>
    5151#include <stdarg.h>
    5252#include <stdio.h>
    5353#include <stdlib.h>
    54 #include <str_error.h>
    5554#include <str.h>
    56 #include <task.h>
    5755#include <ui/resource.h>
    5856#include <ui/ui.h>
     
    7068
    7169#define TERM_CAPS \
    72         (CONSOLE_CAP_CURSORCTL | CONSOLE_CAP_STYLE | CONSOLE_CAP_INDEXED | \
    73         CONSOLE_CAP_RGB)
    74 
    75 #define SCROLLBACK_MAX_LINES 1000
    76 #define MIN_WINDOW_COLS 8
    77 #define MIN_WINDOW_ROWS 4
     70        (CONSOLE_CAP_STYLE | CONSOLE_CAP_INDEXED | CONSOLE_CAP_RGB)
    7871
    7972static LIST_INITIALIZE(terms);
    80 
    81 #define COLOR_BRIGHT 8
    82 
    83 static const pixel_t _basic_colors[16] = {
    84         [COLOR_BLACK]       = PIXEL(255, 0, 0, 0),
    85         [COLOR_RED]         = PIXEL(255, 170, 0, 0),
    86         [COLOR_GREEN]       = PIXEL(255, 0, 170, 0),
    87         [COLOR_YELLOW]      = PIXEL(255, 170, 85, 0),
    88         [COLOR_BLUE]        = PIXEL(255, 0, 0, 170),
    89         [COLOR_MAGENTA]     = PIXEL(255, 170, 0, 170),
    90         [COLOR_CYAN]        = PIXEL(255, 0, 170, 170),
    91         [COLOR_WHITE]       = PIXEL(255, 170, 170, 170),
    92 
    93         [COLOR_BLACK   | COLOR_BRIGHT] = PIXEL(255, 85, 85, 85),
    94         [COLOR_RED     | COLOR_BRIGHT] = PIXEL(255, 255, 85, 85),
    95         [COLOR_GREEN   | COLOR_BRIGHT] = PIXEL(255, 85, 255, 85),
    96         [COLOR_YELLOW  | COLOR_BRIGHT] = PIXEL(255, 255, 255, 85),
    97         [COLOR_BLUE    | COLOR_BRIGHT] = PIXEL(255, 85, 85, 255),
    98         [COLOR_MAGENTA | COLOR_BRIGHT] = PIXEL(255, 255, 85, 255),
    99         [COLOR_CYAN    | COLOR_BRIGHT] = PIXEL(255, 85, 255, 255),
    100         [COLOR_WHITE   | COLOR_BRIGHT] = PIXEL(255, 255, 255, 255),
    101 };
    10273
    10374static errno_t term_open(con_srvs_t *, con_srv_t *);
     
    11687static void term_set_rgb_color(con_srv_t *, pixel_t, pixel_t);
    11788static void term_set_cursor_visibility(con_srv_t *, bool);
    118 static errno_t term_set_caption(con_srv_t *, const char *);
    11989static errno_t term_get_event(con_srv_t *, cons_event_t *);
    12090static errno_t term_map(con_srv_t *, sysarg_t, sysarg_t, charfield_t **);
     
    138108        .set_rgb_color = term_set_rgb_color,
    139109        .set_cursor_visibility = term_set_cursor_visibility,
    140         .set_caption = term_set_caption,
    141110        .get_event = term_get_event,
    142111        .map = term_map,
     
    146115
    147116static void terminal_close_event(ui_window_t *, void *);
    148 static void terminal_focus_event(ui_window_t *, void *, unsigned);
    149 static void terminal_resize_event(ui_window_t *, void *);
     117static void terminal_focus_event(ui_window_t *, void *);
    150118static void terminal_kbd_event(ui_window_t *, void *, kbd_event_t *);
    151119static void terminal_pos_event(ui_window_t *, void *, pos_event_t *);
    152 static void terminal_unfocus_event(ui_window_t *, void *, unsigned);
    153 static void terminal_maximize_event(ui_window_t *, void *);
    154 static void terminal_unmaximize_event(ui_window_t *, void *);
     120static void terminal_unfocus_event(ui_window_t *, void *);
    155121
    156122static ui_window_cb_t terminal_window_cb = {
    157123        .close = terminal_close_event,
    158124        .focus = terminal_focus_event,
    159         .resize = terminal_resize_event,
    160125        .kbd = terminal_kbd_event,
    161126        .pos = terminal_pos_event,
    162         .unfocus = terminal_unfocus_event,
    163         .maximize = terminal_maximize_event,
    164         .unmaximize = terminal_unmaximize_event,
     127        .unfocus = terminal_unfocus_event
    165128};
    166129
    167 static errno_t terminal_wait_fibril(void *);
    168 
    169130static terminal_t *srv_to_terminal(con_srv_t *srv)
    170131{
     
    172133}
    173134
    174 static errno_t getterm(task_wait_t *wait, const char *svc, const char *app)
    175 {
    176         return task_spawnl(NULL, wait, APP_GETTERM, APP_GETTERM, svc,
     135static void getterm(const char *svc, const char *app)
     136{
     137        task_spawnl(NULL, NULL, APP_GETTERM, APP_GETTERM, svc,
    177138            LOCFS_MOUNT_POINT, "--msg", "--wait", "--", app, NULL);
    178139}
    179140
    180 static pixel_t termui_color_to_pixel(termui_color_t c)
    181 {
    182         uint8_t r, g, b;
    183         termui_color_to_rgb(c, &r, &g, &b);
    184         return PIXEL(255, r, g, b);
    185 }
    186 
    187 static termui_color_t termui_color_from_pixel(pixel_t pixel)
    188 {
    189         return termui_color_from_rgb(RED(pixel), GREEN(pixel), BLUE(pixel));
    190 }
    191 
    192 static termui_cell_t charfield_to_termui_cell(terminal_t *term, const charfield_t *cf)
    193 {
    194         termui_cell_t cell = { };
    195 
    196         cell.glyph_idx = fb_font_glyph(cf->ch, NULL);
    197 
    198         switch (cf->attrs.type) {
     141static pixel_t color_table[16] = {
     142        [COLOR_BLACK]       = PIXEL(255, 0, 0, 0),
     143        [COLOR_BLUE]        = PIXEL(255, 0, 0, 240),
     144        [COLOR_GREEN]       = PIXEL(255, 0, 240, 0),
     145        [COLOR_CYAN]        = PIXEL(255, 0, 240, 240),
     146        [COLOR_RED]         = PIXEL(255, 240, 0, 0),
     147        [COLOR_MAGENTA]     = PIXEL(255, 240, 0, 240),
     148        [COLOR_YELLOW]      = PIXEL(255, 240, 240, 0),
     149        [COLOR_WHITE]       = PIXEL(255, 240, 240, 240),
     150
     151        [COLOR_BLACK + 8]   = PIXEL(255, 0, 0, 0),
     152        [COLOR_BLUE + 8]    = PIXEL(255, 0, 0, 255),
     153        [COLOR_GREEN + 8]   = PIXEL(255, 0, 255, 0),
     154        [COLOR_CYAN + 8]    = PIXEL(255, 0, 255, 255),
     155        [COLOR_RED + 8]     = PIXEL(255, 255, 0, 0),
     156        [COLOR_MAGENTA + 8] = PIXEL(255, 255, 0, 255),
     157        [COLOR_YELLOW + 8]  = PIXEL(255, 255, 255, 0),
     158        [COLOR_WHITE + 8]   = PIXEL(255, 255, 255, 255),
     159};
     160
     161static inline void attrs_rgb(char_attrs_t attrs, pixel_t *bgcolor, pixel_t *fgcolor)
     162{
     163        switch (attrs.type) {
    199164        case CHAR_ATTR_STYLE:
    200                 switch (cf->attrs.val.style) {
     165                switch (attrs.val.style) {
    201166                case STYLE_NORMAL:
    202                         cell.bgcolor = term->default_bgcolor;
    203                         cell.fgcolor = term->default_fgcolor;
     167                        *bgcolor = color_table[COLOR_WHITE];
     168                        *fgcolor = color_table[COLOR_BLACK];
    204169                        break;
    205170                case STYLE_EMPHASIS:
    206                         cell.bgcolor = term->emphasis_bgcolor;
    207                         cell.fgcolor = term->emphasis_fgcolor;
     171                        *bgcolor = color_table[COLOR_WHITE];
     172                        *fgcolor = color_table[COLOR_RED];
    208173                        break;
    209174                case STYLE_INVERTED:
    210                         cell.bgcolor = term->default_bgcolor;
    211                         cell.fgcolor = term->default_fgcolor;
    212                         cell.inverted = 1;
     175                        *bgcolor = color_table[COLOR_BLACK];
     176                        *fgcolor = color_table[COLOR_WHITE];
    213177                        break;
    214178                case STYLE_SELECTED:
    215                         cell.bgcolor = term->selection_bgcolor;
    216                         cell.fgcolor = term->selection_fgcolor;
     179                        *bgcolor = color_table[COLOR_RED];
     180                        *fgcolor = color_table[COLOR_WHITE];
    217181                        break;
    218182                }
    219183                break;
    220 
    221184        case CHAR_ATTR_INDEX:
    222                 char_attr_index_t index = cf->attrs.val.index;
    223 
    224                 int bright = (index.attr & CATTR_BRIGHT) ? COLOR_BRIGHT : 0;
    225                 pixel_t bgcolor = _basic_colors[index.bgcolor];
    226                 pixel_t fgcolor = _basic_colors[index.fgcolor | bright];
    227                 cell.bgcolor = termui_color_from_pixel(bgcolor);
    228                 cell.fgcolor = termui_color_from_pixel(fgcolor);
    229 
    230                 if (index.attr & CATTR_BLINK)
    231                         cell.blink = 1;
    232 
     185                *bgcolor = color_table[(attrs.val.index.bgcolor & 7) |
     186                    ((attrs.val.index.attr & CATTR_BRIGHT) ? 8 : 0)];
     187                *fgcolor = color_table[(attrs.val.index.fgcolor & 7) |
     188                    ((attrs.val.index.attr & CATTR_BRIGHT) ? 8 : 0)];
    233189                break;
    234 
    235190        case CHAR_ATTR_RGB:
    236                 cell.bgcolor = termui_color_from_pixel(cf->attrs.val.rgb.bgcolor);
    237                 cell.fgcolor = termui_color_from_pixel(cf->attrs.val.rgb.fgcolor);
     191                *bgcolor = 0xff000000 | attrs.val.rgb.bgcolor;
     192                *fgcolor = 0xff000000 | attrs.val.rgb.fgcolor;
    238193                break;
    239194        }
    240 
    241         return cell;
    242195}
    243196
     
    257210}
    258211
    259 static void term_draw_cell(terminal_t *term, pixelmap_t *pixelmap, int col, int row, const termui_cell_t *cell)
    260 {
    261         termui_color_t bg = cell->bgcolor;
    262         if (bg == TERMUI_COLOR_DEFAULT)
    263                 bg = term->default_bgcolor;
    264 
    265         termui_color_t fg = cell->fgcolor;
    266         if (fg == TERMUI_COLOR_DEFAULT)
    267                 fg = term->default_fgcolor;
    268 
    269         pixel_t bgcolor = termui_color_to_pixel(bg);
    270         pixel_t fgcolor = termui_color_to_pixel(fg);
    271 
    272         int bx = col * FONT_WIDTH;
    273         int by = row * FONT_SCANLINES;
    274 
    275         // TODO: support bold/italic/underline/strike/blink styling
    276 
    277         if (cell->inverted ^ cell->cursor) {
    278                 pixel_t tmp = bgcolor;
    279                 bgcolor = fgcolor;
    280                 fgcolor = tmp;
    281         }
    282 
    283         uint32_t glyph = cell->glyph_idx;
    284         assert(glyph < FONT_GLYPHS);
    285 
    286         if (glyph == 0)
    287                 glyph = fb_font_glyph(U' ', NULL);
     212static void term_update_char(terminal_t *term, pixelmap_t *pixelmap,
     213    sysarg_t sx, sysarg_t sy, sysarg_t col, sysarg_t row)
     214{
     215        charfield_t *field =
     216            chargrid_charfield_at(term->backbuf, col, row);
     217
     218        bool inverted = chargrid_cursor_at(term->backbuf, col, row);
     219
     220        sysarg_t bx = sx + (col * FONT_WIDTH);
     221        sysarg_t by = sy + (row * FONT_SCANLINES);
     222
     223        pixel_t bgcolor = 0;
     224        pixel_t fgcolor = 0;
     225
     226        if (inverted)
     227                attrs_rgb(field->attrs, &fgcolor, &bgcolor);
     228        else
     229                attrs_rgb(field->attrs, &bgcolor, &fgcolor);
     230
     231        // FIXME: Glyph type should be actually uint32_t
     232        //        for full UTF-32 coverage.
     233
     234        uint16_t glyph = fb_font_glyph(field->ch, NULL);
    288235
    289236        for (unsigned int y = 0; y < FONT_SCANLINES; y++) {
     
    297244                }
    298245        }
    299 
    300246        term_update_region(term, bx, by, FONT_WIDTH, FONT_SCANLINES);
    301247}
    302248
    303 static void term_render(terminal_t *term)
    304 {
    305         (void) gfx_bitmap_render(term->bmp, &term->update, &term->off);
    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 
    313 static 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 
    320 static 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 
    328 static pixelmap_t term_get_pixelmap(terminal_t *term)
    329 {
    330         pixelmap_t pixelmap = { };
     249static bool term_update_scroll(terminal_t *term, pixelmap_t *pixelmap,
     250    sysarg_t sx, sysarg_t sy)
     251{
     252        sysarg_t top_row = chargrid_get_top_row(term->frontbuf);
     253
     254        if (term->top_row == top_row) {
     255                return false;
     256        }
     257
     258        term->top_row = top_row;
     259
     260        for (sysarg_t row = 0; row < term->rows; row++) {
     261                for (sysarg_t col = 0; col < term->cols; col++) {
     262                        charfield_t *front_field =
     263                            chargrid_charfield_at(term->frontbuf, col, row);
     264                        charfield_t *back_field =
     265                            chargrid_charfield_at(term->backbuf, col, row);
     266                        bool update = false;
     267
     268                        if (front_field->ch != back_field->ch) {
     269                                back_field->ch = front_field->ch;
     270                                update = true;
     271                        }
     272
     273                        if (!attrs_same(front_field->attrs, back_field->attrs)) {
     274                                back_field->attrs = front_field->attrs;
     275                                update = true;
     276                        }
     277
     278                        front_field->flags &= ~CHAR_FLAG_DIRTY;
     279
     280                        if (update) {
     281                                term_update_char(term, pixelmap, sx, sy, col, row);
     282                        }
     283                }
     284        }
     285
     286        return true;
     287}
     288
     289static bool term_update_cursor(terminal_t *term, pixelmap_t *pixelmap,
     290    sysarg_t sx, sysarg_t sy)
     291{
     292        bool update = false;
     293
     294        sysarg_t front_col;
     295        sysarg_t front_row;
     296        chargrid_get_cursor(term->frontbuf, &front_col, &front_row);
     297
     298        sysarg_t back_col;
     299        sysarg_t back_row;
     300        chargrid_get_cursor(term->backbuf, &back_col, &back_row);
     301
     302        bool front_visibility =
     303            chargrid_get_cursor_visibility(term->frontbuf) &&
     304            term->is_focused;
     305        bool back_visibility =
     306            chargrid_get_cursor_visibility(term->backbuf);
     307
     308        if (front_visibility != back_visibility) {
     309                chargrid_set_cursor_visibility(term->backbuf,
     310                    front_visibility);
     311                term_update_char(term, pixelmap, sx, sy, back_col, back_row);
     312                update = true;
     313        }
     314
     315        if ((front_col != back_col) || (front_row != back_row)) {
     316                chargrid_set_cursor(term->backbuf, front_col, front_row);
     317                term_update_char(term, pixelmap, sx, sy, back_col, back_row);
     318                term_update_char(term, pixelmap, sx, sy, front_col, front_row);
     319                update = true;
     320        }
     321
     322        return update;
     323}
     324
     325static void term_update(terminal_t *term)
     326{
     327        pixelmap_t pixelmap;
    331328        gfx_bitmap_alloc_t alloc;
    332 
    333         errno_t rc = gfx_bitmap_get_alloc(term->bmp, &alloc);
    334         if (rc != EOK)
    335                 return pixelmap;
    336 
     329        gfx_coord2_t pos;
     330        errno_t rc;
     331
     332        rc = gfx_bitmap_get_alloc(term->bmp, &alloc);
     333        if (rc != EOK) {
     334                return;
     335        }
     336
     337        fibril_mutex_lock(&term->mtx);
    337338        pixelmap.width = term->w;
    338339        pixelmap.height = term->h;
    339340        pixelmap.data = alloc.pixels;
    340         return pixelmap;
    341 }
    342 
    343 static void term_clear_bitmap(terminal_t *term, pixel_t color)
    344 {
    345         pixelmap_t pixelmap = term_get_pixelmap(term);
    346         if (pixelmap.data == NULL)
     341
     342        bool update = false;
     343        sysarg_t sx = 0;
     344        sysarg_t sy = 0;
     345
     346        if (term_update_scroll(term, &pixelmap, sx, sy)) {
     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, sx, sy, x, y);
     375                                        update = true;
     376                                }
     377                        }
     378                }
     379        }
     380
     381        if (term_update_cursor(term, &pixelmap, sx, sy))
     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
     398static 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");
    347407                return;
    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 
    356 static 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]);
     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        sysarg_t sx = 0;
     417        sysarg_t sy = 0;
     418
     419        if (!term_update_scroll(term, &pixelmap, sx, sy)) {
     420                for (sysarg_t y = 0; y < term->rows; y++) {
     421                        for (sysarg_t x = 0; x < term->cols; x++) {
     422                                charfield_t *front_field =
     423                                    chargrid_charfield_at(term->frontbuf, x, y);
     424                                charfield_t *back_field =
     425                                    chargrid_charfield_at(term->backbuf, x, y);
     426
     427                                back_field->ch = front_field->ch;
     428                                back_field->attrs = front_field->attrs;
     429                                front_field->flags &= ~CHAR_FLAG_DIRTY;
     430
     431                                term_update_char(term, &pixelmap, sx, sy, x, y);
     432                        }
     433                }
     434        }
     435
     436        term_update_cursor(term, &pixelmap, sx, sy);
     437
     438        fibril_mutex_unlock(&term->mtx);
    366439}
    367440
     
    403476                if (pos < size) {
    404477                        link_t *link = prodcons_consume(&term->input_pc);
    405                         terminal_event_t *qevent = list_get_instance(link,
    406                             terminal_event_t, link);
    407                         cons_event_t *event = &qevent->ev;
     478                        cons_event_t *event = list_get_instance(link, cons_event_t, link);
    408479
    409480                        /* Accept key presses of printable chars only. */
     
    419490                        }
    420491
    421                         free(qevent);
     492                        free(event);
    422493                }
    423494        }
     
    429500static void term_write_char(terminal_t *term, wchar_t ch)
    430501{
     502        sysarg_t updated = 0;
     503
     504        fibril_mutex_lock(&term->mtx);
     505
    431506        switch (ch) {
    432         case L'\n':
    433                 termui_put_crlf(term->termui);
     507        case '\n':
     508                updated = chargrid_newline(term->frontbuf);
    434509                break;
    435         case L'\r':
    436                 termui_put_cr(term->termui);
     510        case '\r':
    437511                break;
    438         case L'\t':
    439                 termui_put_tab(term->termui);
     512        case '\t':
     513                updated = chargrid_tabstop(term->frontbuf, 8);
    440514                break;
    441         case L'\b':
    442                 termui_put_backspace(term->termui);
     515        case '\b':
     516                updated = chargrid_backspace(term->frontbuf);
    443517                break;
    444518        default:
    445                 // TODO: For some languages, we might need support for combining
    446                 //       characters. Currently, we assume every unicode code point is
    447                 //       an individual printed character, which is not always the case.
    448                 termui_put_glyph(term->termui, fb_font_glyph(ch, NULL), 1);
    449                 break;
    450         }
     519                updated = chargrid_putuchar(term->frontbuf, ch, true);
     520        }
     521
     522        fibril_mutex_unlock(&term->mtx);
     523
     524        if (updated > 1)
     525                term_update(term);
    451526}
    452527
     
    454529{
    455530        terminal_t *term = srv_to_terminal(srv);
    456 
    457         fibril_mutex_lock(&term->mtx);
    458531
    459532        size_t off = 0;
     
    461534                term_write_char(term, str_decode(data, &off, size));
    462535
    463         fibril_mutex_unlock(&term->mtx);
    464 
    465         term_render(term);
    466536        gfx_update(term->gc);
    467537        *nwritten = size;
    468 
    469538        return EOK;
    470539}
     
    474543        terminal_t *term = srv_to_terminal(srv);
    475544
    476         term_render(term);
     545        term_update(term);
    477546        gfx_update(term->gc);
    478547}
     
    483552
    484553        fibril_mutex_lock(&term->mtx);
    485         termui_clear_screen(term->termui);
    486         fibril_mutex_unlock(&term->mtx);
    487 
    488         term_render(term);
     554        chargrid_clear(term->frontbuf);
     555        fibril_mutex_unlock(&term->mtx);
     556
     557        term_update(term);
    489558        gfx_update(term->gc);
    490559}
     
    495564
    496565        fibril_mutex_lock(&term->mtx);
    497         termui_set_pos(term->termui, col, row);
    498         fibril_mutex_unlock(&term->mtx);
    499 
    500         term_render(term);
     566        chargrid_set_cursor(term->frontbuf, col, row);
     567        fibril_mutex_unlock(&term->mtx);
     568
     569        term_update(term);
    501570        gfx_update(term->gc);
    502571}
     
    507576
    508577        fibril_mutex_lock(&term->mtx);
    509         int irow, icol;
    510         termui_get_pos(term->termui, &icol, &irow);
    511         fibril_mutex_unlock(&term->mtx);
    512 
    513         *col = icol;
    514         *row = irow;
     578        chargrid_get_cursor(term->frontbuf, col, row);
     579        fibril_mutex_unlock(&term->mtx);
    515580
    516581        return EOK;
     
    522587
    523588        fibril_mutex_lock(&term->mtx);
    524         *cols = termui_get_cols(term->termui);
    525         *rows = termui_get_rows(term->termui);
     589        *cols = term->cols;
     590        *rows = term->rows;
    526591        fibril_mutex_unlock(&term->mtx);
    527592
     
    541606        terminal_t *term = srv_to_terminal(srv);
    542607
    543         termui_cell_t cellstyle = { };
    544 
    545         switch (style) {
    546         case STYLE_NORMAL:
    547                 cellstyle.bgcolor = term->default_bgcolor;
    548                 cellstyle.fgcolor = term->default_fgcolor;
    549                 break;
    550         case STYLE_EMPHASIS:
    551                 cellstyle.bgcolor = term->emphasis_bgcolor;
    552                 cellstyle.fgcolor = term->emphasis_fgcolor;
    553                 break;
    554         case STYLE_INVERTED:
    555                 cellstyle.bgcolor = term->default_bgcolor;
    556                 cellstyle.fgcolor = term->default_fgcolor;
    557                 cellstyle.inverted = 1;
    558                 break;
    559         case STYLE_SELECTED:
    560                 cellstyle.bgcolor = term->selection_bgcolor;
    561                 cellstyle.fgcolor = term->selection_fgcolor;
    562                 break;
    563         }
    564 
    565         fibril_mutex_lock(&term->mtx);
    566         termui_set_style(term->termui, cellstyle);
     608        fibril_mutex_lock(&term->mtx);
     609        chargrid_set_style(term->frontbuf, style);
    567610        fibril_mutex_unlock(&term->mtx);
    568611}
     
    573616        terminal_t *term = srv_to_terminal(srv);
    574617
    575         int bright = (attr & CATTR_BRIGHT) ? COLOR_BRIGHT : 0;
    576 
    577         termui_cell_t cellstyle = { };
    578         cellstyle.bgcolor = termui_color_from_pixel(_basic_colors[bgcolor]);
    579         cellstyle.fgcolor = termui_color_from_pixel(_basic_colors[fgcolor | bright]);
    580 
    581         if (attr & CATTR_BLINK)
    582                 cellstyle.blink = 1;
    583 
    584         fibril_mutex_lock(&term->mtx);
    585         termui_set_style(term->termui, cellstyle);
     618        fibril_mutex_lock(&term->mtx);
     619        chargrid_set_color(term->frontbuf, bgcolor, fgcolor, attr);
    586620        fibril_mutex_unlock(&term->mtx);
    587621}
     
    591625{
    592626        terminal_t *term = srv_to_terminal(srv);
    593         termui_cell_t cellstyle = {
    594                 .bgcolor = termui_color_from_pixel(bgcolor),
    595                 .fgcolor = termui_color_from_pixel(fgcolor),
    596         };
    597 
    598         fibril_mutex_lock(&term->mtx);
    599         termui_set_style(term->termui, cellstyle);
     627
     628        fibril_mutex_lock(&term->mtx);
     629        chargrid_set_rgb_color(term->frontbuf, bgcolor, fgcolor);
    600630        fibril_mutex_unlock(&term->mtx);
    601631}
     
    606636
    607637        fibril_mutex_lock(&term->mtx);
    608         termui_set_cursor_visibility(term->termui, visible);
    609         fibril_mutex_unlock(&term->mtx);
    610 
    611         term_render(term);
     638        chargrid_set_cursor_visibility(term->frontbuf, visible);
     639        fibril_mutex_unlock(&term->mtx);
     640
     641        term_update(term);
    612642        gfx_update(term->gc);
    613643}
    614644
    615 static errno_t term_set_caption(con_srv_t *srv, const char *caption)
    616 {
    617         terminal_t *term = srv_to_terminal(srv);
    618         const char *cap;
    619 
    620         fibril_mutex_lock(&term->mtx);
    621 
    622         if (str_size(caption) > 0)
    623                 cap = caption;
    624         else
    625                 cap = "Terminal";
    626 
    627         ui_window_set_caption(term->window, cap);
    628         fibril_mutex_unlock(&term->mtx);
    629 
    630         term_render(term);
    631         gfx_update(term->gc);
    632         return EOK;
    633 }
    634 
    635645static errno_t term_get_event(con_srv_t *srv, cons_event_t *event)
    636646{
    637647        terminal_t *term = srv_to_terminal(srv);
    638648        link_t *link = prodcons_consume(&term->input_pc);
    639         terminal_event_t *ev = list_get_instance(link, terminal_event_t, link);
    640 
    641         *event = ev->ev;
     649        cons_event_t *ev = list_get_instance(link, cons_event_t, link);
     650
     651        *event = *ev;
    642652        free(ev);
    643653        return EOK;
     
    676686        term->urows = rows;
    677687        term->ubuf = buf;
    678 
    679         /* Scroll back to active screen. */
    680         termui_history_scroll(term->termui, INT_MAX);
    681 
    682688        fibril_mutex_unlock(&term->mtx);
    683689
     
    700706        term->ubuf = NULL;
    701707
    702         termui_wipe_screen(term->termui, 0);
    703 
    704         fibril_mutex_unlock(&term->mtx);
    705 
    706         /* Update terminal */
    707         term_render(term);
    708         gfx_update(term->gc);
    709 
    710708        if (buf != NULL)
    711709                as_area_destroy(buf);
     710
     711        fibril_mutex_unlock(&term->mtx);
    712712}
    713713
     
    724724{
    725725        terminal_t *term = srv_to_terminal(srv);
     726        charfield_t *ch;
     727        sysarg_t col, row;
    726728
    727729        fibril_mutex_lock(&term->mtx);
     
    733735
    734736        /* Make sure we have meaningful coordinates, within bounds */
    735         c1 = min(c1, term->ucols);
    736         c1 = min(c1, (sysarg_t) termui_get_cols(term->termui));
    737         r1 = min(r1, term->urows);
    738         r1 = min(r1, (sysarg_t) termui_get_rows(term->termui));
    739 
    740         if (c0 >= c1 || r0 >= r1) {
     737
     738        if (c1 > term->ucols)
     739                c1 = term->ucols;
     740        if (c1 > term->cols)
     741                c1 = term->cols;
     742        if (c0 >= c1) {
    741743                fibril_mutex_unlock(&term->mtx);
    742744                return;
    743745        }
     746        if (r1 > term->urows)
     747                r1 = term->urows;
     748        if (r1 > term->rows)
     749                r1 = term->rows;
     750        if (r0 >= r1) {
     751                fibril_mutex_unlock(&term->mtx);
     752                return;
     753        }
    744754
    745755        /* Update front buffer from user buffer */
    746756
    747         for (sysarg_t row = r0; row < r1; row++) {
    748                 termui_cell_t *cells = termui_get_active_row(term->termui, row);
    749 
    750                 for (sysarg_t col = c0; col < c1; col++) {
    751                         cells[col] = charfield_to_termui_cell(term, &term->ubuf[row * term->ucols + col]);
     757        for (row = r0; row < r1; row++) {
     758                for (col = c0; col < c1; col++) {
     759                        ch = chargrid_charfield_at(term->frontbuf, col, row);
     760                        *ch = term->ubuf[row * term->ucols + col];
    752761                }
    753 
    754                 termui_update_cb(term, c0, row, &cells[c0], c1 - c0);
    755762        }
    756763
     
    758765
    759766        /* Update terminal */
    760         term_render(term);
     767        term_update(term);
    761768        gfx_update(term->gc);
    762769}
    763770
    764 static errno_t terminal_window_resize(terminal_t *term)
    765 {
     771static void deinit_terminal(terminal_t *term)
     772{
     773        list_remove(&term->link);
     774
     775        if (term->frontbuf)
     776                chargrid_destroy(term->frontbuf);
     777
     778        if (term->backbuf)
     779                chargrid_destroy(term->backbuf);
     780}
     781
     782void terminal_destroy(terminal_t *term)
     783{
     784        deinit_terminal(term);
     785        free(term);
     786}
     787
     788static void terminal_queue_cons_event(terminal_t *term, cons_event_t *ev)
     789{
     790        /* Got key press/release event */
     791        cons_event_t *event =
     792            (cons_event_t *) malloc(sizeof(cons_event_t));
     793        if (event == NULL)
     794                return;
     795
     796        *event = *ev;
     797        link_initialize(&event->link);
     798
     799        prodcons_produce(&term->input_pc, &event->link);
     800}
     801
     802/** Handle window close event. */
     803static void terminal_close_event(ui_window_t *window, void *arg)
     804{
     805        terminal_t *term = (terminal_t *) arg;
     806
     807        (void) term;
     808
     809        // XXX This is not really a clean way of terminating
     810        exit(0);
     811}
     812
     813/** Handle window focus event. */
     814static void terminal_focus_event(ui_window_t *window, void *arg)
     815{
     816        terminal_t *term = (terminal_t *) arg;
     817
     818        term->is_focused = true;
     819        term_update(term);
     820        gfx_update(term->gc);
     821}
     822
     823/** Handle window keyboard event */
     824static void terminal_kbd_event(ui_window_t *window, void *arg,
     825    kbd_event_t *kbd_event)
     826{
     827        terminal_t *term = (terminal_t *) arg;
     828        cons_event_t event;
     829
     830        event.type = CEV_KEY;
     831        event.ev.key = *kbd_event;
     832
     833        terminal_queue_cons_event(term, &event);
     834}
     835
     836/** Handle window position event */
     837static void terminal_pos_event(ui_window_t *window, void *arg, pos_event_t *event)
     838{
     839        cons_event_t cevent;
     840        terminal_t *term = (terminal_t *) arg;
     841
     842        sysarg_t sx = -term->off.x;
     843        sysarg_t sy = -term->off.y;
     844
     845        if (event->type == POS_PRESS || event->type == POS_RELEASE) {
     846                cevent.type = CEV_POS;
     847                cevent.ev.pos.type = event->type;
     848                cevent.ev.pos.pos_id = event->pos_id;
     849                cevent.ev.pos.btn_num = event->btn_num;
     850
     851                cevent.ev.pos.hpos = (event->hpos - sx) / FONT_WIDTH;
     852                cevent.ev.pos.vpos = (event->vpos - sy) / FONT_SCANLINES;
     853                terminal_queue_cons_event(term, &cevent);
     854        }
     855}
     856
     857/** Handle window unfocus event. */
     858static void terminal_unfocus_event(ui_window_t *window, void *arg)
     859{
     860        terminal_t *term = (terminal_t *) arg;
     861
     862        term->is_focused = false;
     863        term_update(term);
     864        gfx_update(term->gc);
     865}
     866
     867static void term_connection(ipc_call_t *icall, void *arg)
     868{
     869        terminal_t *term = NULL;
     870
     871        list_foreach(terms, link, terminal_t, cur) {
     872                if (cur->dsid == (service_id_t) ipc_get_arg2(icall)) {
     873                        term = cur;
     874                        break;
     875                }
     876        }
     877
     878        if (term == NULL) {
     879                async_answer_0(icall, ENOENT);
     880                return;
     881        }
     882
     883        if (!atomic_flag_test_and_set(&term->refcnt))
     884                chargrid_set_cursor_visibility(term->frontbuf, true);
     885
     886        con_conn(icall, &term->srvs);
     887}
     888
     889errno_t terminal_create(const char *display_spec, sysarg_t width,
     890    sysarg_t height, terminal_flags_t flags, terminal_t **rterm)
     891{
     892        terminal_t *term;
     893        gfx_bitmap_params_t params;
     894        ui_wnd_params_t wparams;
    766895        gfx_rect_t rect;
    767         ui_window_get_app_rect(term->window, &rect);
    768 
    769         int width = rect.p1.x - rect.p0.x;
    770         int height = rect.p1.y - rect.p0.y;
    771 
    772         if (!term->gc)
    773                 term->gc = ui_window_get_gc(term->window);
    774         else
    775                 assert(term->gc == ui_window_get_gc(term->window));
    776 
    777         if (!term->ui_res)
    778                 term->ui_res = ui_window_get_res(term->window);
    779         else
    780                 assert(term->ui_res == ui_window_get_res(term->window));
    781 
    782         gfx_bitmap_t *new_bmp;
    783         gfx_bitmap_params_t params;
     896        gfx_coord2_t off;
     897        gfx_rect_t wrect;
     898        errno_t rc;
     899
     900        term = calloc(1, sizeof(terminal_t));
     901        if (term == NULL) {
     902                printf("Out of memory.\n");
     903                return ENOMEM;
     904        }
     905
     906        link_initialize(&term->link);
     907        fibril_mutex_initialize(&term->mtx);
     908        atomic_flag_clear(&term->refcnt);
     909
     910        prodcons_initialize(&term->input_pc);
     911        term->char_remains_len = 0;
     912
     913        term->w = width;
     914        term->h = height;
     915
     916        term->cols = width / FONT_WIDTH;
     917        term->rows = height / FONT_SCANLINES;
     918
     919        term->frontbuf = NULL;
     920        term->backbuf = NULL;
     921
     922        term->frontbuf = chargrid_create(term->cols, term->rows,
     923            CHARGRID_FLAG_NONE);
     924        if (!term->frontbuf) {
     925                printf("Error creating front buffer.\n");
     926                rc = ENOMEM;
     927                goto error;
     928        }
     929
     930        term->backbuf = chargrid_create(term->cols, term->rows,
     931            CHARGRID_FLAG_NONE);
     932        if (!term->backbuf) {
     933                printf("Error creating back buffer.\n");
     934                rc = ENOMEM;
     935                goto error;
     936        }
     937
     938        rect.p0.x = 0;
     939        rect.p0.y = 0;
     940        rect.p1.x = width;
     941        rect.p1.y = height;
     942
     943        ui_wnd_params_init(&wparams);
     944        wparams.caption = "Terminal";
     945        if ((flags & tf_topleft) != 0)
     946                wparams.placement = ui_wnd_place_top_left;
     947
     948        /*
     949         * Compute window rectangle such that application area corresponds
     950         * to rect
     951         */
     952        ui_wdecor_rect_from_app(wparams.style, &rect, &wrect);
     953        off = wrect.p0;
     954        gfx_rect_rtranslate(&off, &wrect, &wparams.rect);
     955
     956        term->off = off;
     957
     958        rc = ui_create(display_spec, &term->ui);
     959        if (rc != EOK) {
     960                printf("Error creating UI on %s.\n", display_spec);
     961                goto error;
     962        }
     963
     964        rc = ui_window_create(term->ui, &wparams, &term->window);
     965        if (rc != EOK) {
     966                printf("Error creating window.\n");
     967                goto error;
     968        }
     969
     970        term->gc = ui_window_get_gc(term->window);
     971        term->ui_res = ui_window_get_res(term->window);
     972
     973        ui_window_set_cb(term->window, &terminal_window_cb, (void *) term);
     974
    784975        gfx_bitmap_params_init(&params);
    785976        params.rect.p0.x = 0;
     
    788979        params.rect.p1.y = height;
    789980
    790         errno_t rc = gfx_bitmap_create(term->gc, &params, NULL, &new_bmp);
     981        rc = gfx_bitmap_create(term->gc, &params, NULL, &term->bmp);
    791982        if (rc != EOK) {
    792                 fprintf(stderr, "Error allocating new screen bitmap: %s\n", str_error(rc));
    793                 return rc;
    794         }
    795 
    796         if (term->bmp) {
    797                 rc = gfx_bitmap_destroy(term->bmp);
    798                 if (rc != EOK)
    799                         fprintf(stderr, "Error deallocating old screen bitmap: %s\n", str_error(rc));
    800         }
    801 
    802         term->bmp = new_bmp;
    803         term->w = width;
    804         term->h = height;
    805 
    806         term_clear_bitmap(term, termui_color_to_pixel(term->default_bgcolor));
    807 
    808         return EOK;
    809 }
    810 
    811 void terminal_destroy(terminal_t *term)
    812 {
    813         list_remove(&term->link);
    814 
    815         termui_destroy(term->termui);
    816 
    817         if (term->ubuf)
    818                 as_area_destroy(term->ubuf);
    819 
    820         ui_destroy(term->ui);
    821         free(term);
    822 }
    823 
    824 static void terminal_queue_cons_event(terminal_t *term, cons_event_t *ev)
    825 {
    826         /* Got key press/release event */
    827         terminal_event_t *event =
    828             (terminal_event_t *) malloc(sizeof(terminal_event_t));
    829         if (event == NULL)
    830                 return;
    831 
    832         event->ev = *ev;
    833         link_initialize(&event->link);
    834 
    835         prodcons_produce(&term->input_pc, &event->link);
    836 }
    837 
    838 /** Handle window close event. */
    839 static void terminal_close_event(ui_window_t *window, void *arg)
    840 {
    841         terminal_t *term = (terminal_t *) arg;
    842 
    843         ui_quit(term->ui);
    844 }
    845 
    846 /** Handle window focus event. */
    847 static void terminal_focus_event(ui_window_t *window, void *arg,
    848     unsigned nfocus)
    849 {
    850         terminal_t *term = (terminal_t *) arg;
    851 
    852         (void)nfocus;
    853         term->is_focused = true;
    854         term_render(term);
    855         gfx_update(term->gc);
    856 }
    857 
    858 static void terminal_resize_handler(ui_window_t *window, void *arg)
    859 {
    860         terminal_t *term = (terminal_t *) arg;
    861 
    862         fibril_mutex_lock(&term->mtx);
    863 
    864         errno_t rc = terminal_window_resize(term);
    865         if (rc == EOK) {
    866                 (void) termui_resize(term->termui, term->w / FONT_WIDTH, term->h / FONT_SCANLINES, SCROLLBACK_MAX_LINES);
    867                 termui_refresh_cb(term);
    868                 term_render(term);
    869                 gfx_update(term->gc);
    870 
    871                 cons_event_t event = { .type = CEV_RESIZE };
    872                 terminal_queue_cons_event(term, &event);
    873         }
    874 
    875         fibril_mutex_unlock(&term->mtx);
    876 }
    877 
    878 static void terminal_resize_event(ui_window_t *window, void *arg)
    879 {
    880         ui_window_def_resize(window);
    881         terminal_resize_handler(window, arg);
    882 }
    883 
    884 static void terminal_maximize_event(ui_window_t *window, void *arg)
    885 {
    886         ui_window_def_maximize(window);
    887         terminal_resize_handler(window, arg);
    888 }
    889 
    890 static void terminal_unmaximize_event(ui_window_t *window, void *arg)
    891 {
    892         ui_window_def_unmaximize(window);
    893         terminal_resize_handler(window, arg);
    894 }
    895 
    896 /** Handle window keyboard event */
    897 static void terminal_kbd_event(ui_window_t *window, void *arg,
    898     kbd_event_t *kbd_event)
    899 {
    900         terminal_t *term = (terminal_t *) arg;
    901         cons_event_t event;
    902 
    903         event.type = CEV_KEY;
    904         event.ev.key = *kbd_event;
    905 
    906         const int PAGE_ROWS = (termui_get_rows(term->termui) * 2) / 3;
    907 
    908         fibril_mutex_lock(&term->mtx);
    909 
    910         if (!term->ubuf && kbd_event->type == KEY_PRESS &&
    911             (kbd_event->key == KC_PAGE_UP || kbd_event->key == KC_PAGE_DOWN)) {
    912 
    913                 termui_history_scroll(term->termui,
    914                     (kbd_event->key == KC_PAGE_UP) ? -PAGE_ROWS : PAGE_ROWS);
    915 
    916                 term_render(term);
    917                 gfx_update(term->gc);
    918         } else {
    919                 terminal_queue_cons_event(term, &event);
    920         }
    921 
    922         fibril_mutex_unlock(&term->mtx);
    923 }
    924 
    925 /** Handle window position event */
    926 static void terminal_pos_event(ui_window_t *window, void *arg, pos_event_t *event)
    927 {
    928         cons_event_t cevent;
    929         terminal_t *term = (terminal_t *) arg;
    930 
    931         switch (event->type) {
    932         case POS_UPDATE:
    933                 return;
    934 
    935         case POS_PRESS:
    936         case POS_RELEASE:
    937         case POS_DCLICK:
    938         }
    939 
    940         /* Ignore mouse events when we're in scrollback mode. */
    941         if (termui_scrollback_is_active(term->termui))
    942                 return;
    943 
    944         sysarg_t sx = term->off.x;
    945         sysarg_t sy = term->off.y;
    946 
    947         if (event->hpos < sx || event->vpos < sy)
    948                 return;
    949 
    950         cevent.type = CEV_POS;
    951         cevent.ev.pos.type = event->type;
    952         cevent.ev.pos.pos_id = event->pos_id;
    953         cevent.ev.pos.btn_num = event->btn_num;
    954 
    955         cevent.ev.pos.hpos = (event->hpos - sx) / FONT_WIDTH;
    956         cevent.ev.pos.vpos = (event->vpos - sy) / FONT_SCANLINES;
    957 
    958         /* Filter out events outside the terminal area. */
    959         int cols = termui_get_cols(term->termui);
    960         int rows = termui_get_rows(term->termui);
    961 
    962         if (cevent.ev.pos.hpos < (sysarg_t) cols && cevent.ev.pos.vpos < (sysarg_t) rows)
    963                 terminal_queue_cons_event(term, &cevent);
    964 }
    965 
    966 /** Handle window unfocus event. */
    967 static void terminal_unfocus_event(ui_window_t *window, void *arg,
    968     unsigned nfocus)
    969 {
    970         terminal_t *term = (terminal_t *) arg;
    971 
    972         if (nfocus == 0) {
    973                 term->is_focused = false;
    974                 term_render(term);
    975                 gfx_update(term->gc);
    976         }
    977 }
    978 
    979 static void term_connection(ipc_call_t *icall, void *arg)
    980 {
    981         terminal_t *term = NULL;
    982 
    983         list_foreach(terms, link, terminal_t, cur) {
    984                 if (cur->dsid == (service_id_t) ipc_get_arg2(icall)) {
    985                         term = cur;
    986                         break;
    987                 }
    988         }
    989 
    990         if (term == NULL) {
    991                 async_answer_0(icall, ENOENT);
    992                 return;
    993         }
    994 
    995         if (!atomic_flag_test_and_set(&term->refcnt))
    996                 termui_set_cursor_visibility(term->termui, true);
    997 
    998         con_conn(icall, &term->srvs);
    999 }
    1000 
    1001 static errno_t term_init_window(terminal_t *term, const char *display_spec,
    1002     gfx_coord_t width, gfx_coord_t height,
    1003     gfx_coord_t min_width, gfx_coord_t min_height,
    1004     terminal_flags_t flags)
    1005 {
    1006         gfx_rect_t min_rect = { { 0, 0 }, { min_width, min_height } };
    1007         gfx_rect_t wmin_rect;
    1008         gfx_rect_t wrect;
    1009 
    1010         errno_t rc = ui_create(display_spec, &term->ui);
    1011         if (rc != EOK) {
    1012                 printf("Error creating UI on %s.\n", display_spec);
    1013                 return rc;
    1014         }
    1015 
    1016         ui_wnd_params_t wparams;
    1017         ui_wnd_params_init(&wparams);
    1018         wparams.caption = "Terminal";
    1019         wparams.style |= ui_wds_maximize_btn | ui_wds_resizable;
    1020 
    1021         if ((flags & tf_topleft) != 0)
    1022                 wparams.placement = ui_wnd_place_top_left;
    1023 
    1024         if (ui_is_fullscreen(term->ui)) {
    1025                 wparams.placement = ui_wnd_place_full_screen;
    1026                 wparams.style &= ~ui_wds_decorated;
    1027         }
    1028 
    1029         /* Compute wrect such that application area corresponds to rect. */
    1030         ui_wdecor_rect_from_app(term->ui, wparams.style, &min_rect, &wrect);
    1031         gfx_rect_rtranslate(&wrect.p0, &wrect, &wmin_rect);
    1032         wparams.min_size = wmin_rect.p1;
    1033 
    1034         gfx_rect_t rect = { { 0, 0 }, { width, height } };
    1035         ui_wdecor_rect_from_app(term->ui, wparams.style, &rect, &rect);
    1036         term->off.x = -rect.p0.x;
    1037         term->off.y = -rect.p0.y;
    1038         printf("off=%d,%d\n", term->off.x, term->off.y);
    1039         gfx_rect_translate(&term->off, &rect, &wparams.rect);
    1040         printf("wparams.rect=%d,%d,%d,%d\n",
    1041             wparams.rect.p0.x,
    1042             wparams.rect.p1.x,
    1043             wparams.rect.p0.y,
    1044             wparams.rect.p1.y);
    1045 
    1046         rc = ui_window_create(term->ui, &wparams, &term->window);
    1047         if (rc != EOK)
    1048                 return rc;
    1049 
    1050         ui_window_set_cb(term->window, &terminal_window_cb, (void *) term);
    1051         return terminal_window_resize(term);
    1052 }
    1053 
    1054 errno_t terminal_create(const char *display_spec, sysarg_t width,
    1055     sysarg_t height, terminal_flags_t flags, const char *command,
    1056     terminal_t **rterm)
    1057 {
    1058         errno_t rc;
    1059 
    1060         terminal_t *term = calloc(1, sizeof(terminal_t));
    1061         if (term == NULL) {
    1062                 printf("Out of memory.\n");
    1063                 return ENOMEM;
    1064         }
    1065 
    1066         link_initialize(&term->link);
    1067         fibril_mutex_initialize(&term->mtx);
    1068         atomic_flag_clear(&term->refcnt);
    1069 
    1070         prodcons_initialize(&term->input_pc);
    1071         term->char_remains_len = 0;
    1072 
    1073         term->default_bgcolor = termui_color_from_pixel(_basic_colors[COLOR_WHITE | COLOR_BRIGHT]);
    1074         term->default_fgcolor = termui_color_from_pixel(_basic_colors[COLOR_BLACK]);
    1075 
    1076         term->emphasis_bgcolor = termui_color_from_pixel(_basic_colors[COLOR_WHITE | COLOR_BRIGHT]);
    1077         term->emphasis_fgcolor = termui_color_from_pixel(_basic_colors[COLOR_RED | COLOR_BRIGHT]);
    1078 
    1079         term->selection_bgcolor = termui_color_from_pixel(_basic_colors[COLOR_RED | COLOR_BRIGHT]);
    1080         term->selection_fgcolor = termui_color_from_pixel(_basic_colors[COLOR_WHITE | COLOR_BRIGHT]);
    1081 
    1082         rc = term_init_window(term, display_spec, width, height,
    1083             MIN_WINDOW_COLS * FONT_WIDTH, MIN_WINDOW_ROWS * FONT_SCANLINES, flags);
    1084         if (rc != EOK) {
    1085                 printf("Error creating window (%s).\n", str_error(rc));
     983                printf("Error allocating screen bitmap.\n");
    1086984                goto error;
    1087985        }
    1088986
    1089         term->termui = termui_create(term->w / FONT_WIDTH,
    1090             term->h / FONT_SCANLINES, SCROLLBACK_MAX_LINES);
    1091         if (!term->termui) {
    1092                 printf("Error creating terminal UI.\n");
    1093                 rc = ENOMEM;
    1094                 goto error;
    1095         }
    1096 
    1097         termui_set_refresh_cb(term->termui, termui_refresh_cb, term);
    1098         termui_set_scroll_cb(term->termui, termui_scroll_cb, term);
    1099         termui_set_update_cb(term->termui, termui_update_cb, term);
     987        chargrid_clear(term->frontbuf);
     988        chargrid_clear(term->backbuf);
     989        term->top_row = 0;
    1100990
    1101991        async_set_fallback_port_handler(term_connection, NULL);
     
    1104994        term->srvs.sarg = term;
    1105995
    1106         rc = loc_server_register(NAME, &term->srv);
     996        rc = loc_server_register(NAME);
    1107997        if (rc != EOK) {
    1108998                printf("Error registering server.\n");
     
    11151005            task_get_id());
    11161006
    1117         rc = loc_service_register(term->srv, vc, &term->dsid);
     1007        rc = loc_service_register(vc, &term->dsid);
    11181008        if (rc != EOK) {
    11191009                printf("Error registering service.\n");
     
    11231013
    11241014        list_append(&term->link, &terms);
    1125         rc = getterm(&term->wait, vc, command);
    1126         if (rc != EOK)
    1127                 goto error;
    1128 
    1129         term->wfid = fibril_create(terminal_wait_fibril, term);
    1130         if (term->wfid == 0)
    1131                 goto error;
    1132 
    1133         fibril_add_ready(term->wfid);
     1015        getterm(vc, "/app/bdsh");
    11341016
    11351017        term->is_focused = true;
    11361018
    1137         termui_refresh_cb(term);
     1019        term->update.p0.x = 0;
     1020        term->update.p0.y = 0;
     1021        term->update.p1.x = 0;
     1022        term->update.p1.y = 0;
     1023
     1024        term_repaint(term);
    11381025
    11391026        *rterm = term;
    11401027        return EOK;
    11411028error:
    1142         if (term->dsid != 0)
    1143                 loc_service_unregister(term->srv, term->dsid);
    1144         if (term->srv != NULL)
    1145                 loc_server_unregister(term->srv);
    11461029        if (term->window != NULL)
    11471030                ui_window_destroy(term->window);
    11481031        if (term->ui != NULL)
    11491032                ui_destroy(term->ui);
    1150         if (term->termui != NULL)
    1151                 termui_destroy(term->termui);
     1033        if (term->frontbuf != NULL)
     1034                chargrid_destroy(term->frontbuf);
     1035        if (term->backbuf != NULL)
     1036                chargrid_destroy(term->backbuf);
    11521037        free(term);
    11531038        return rc;
    11541039}
    11551040
    1156 static errno_t terminal_wait_fibril(void *arg)
    1157 {
    1158         terminal_t *term = (terminal_t *)arg;
    1159         task_exit_t texit;
    1160         int retval;
    1161 
    1162         /*
    1163          * XXX There is no way to break the sleep if the task does not
    1164          * exit.
    1165          */
    1166         (void) task_wait(&term->wait, &texit, &retval);
    1167         ui_quit(term->ui);
    1168         return EOK;
    1169 }
    1170 
    11711041/** @}
    11721042 */
Note: See TracChangeset for help on using the changeset viewer.