Ignore:
File:
1 edited

Legend:

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

    r266ec54 re273e9e  
    11/*
    2  * Copyright (c) 2020 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * Copyright (c) 2012 Petr Koupy
    44 * All rights reserved.
     
    3737#include <adt/list.h>
    3838#include <adt/prodcons.h>
     39#include <as.h>
    3940#include <errno.h>
    4041#include <fbfont/font-8x16.h>
    41 #include <io/chargrid.h>
     42#include <fibril.h>
    4243#include <gfx/bitmap.h>
    4344#include <gfx/context.h>
     45#include <gfx/render.h>
    4446#include <io/con_srv.h>
    4547#include <io/concaps.h>
    4648#include <io/console.h>
    4749#include <io/pixelmap.h>
     50#include <macros.h>
     51#include <stdarg.h>
     52#include <stdio.h>
     53#include <stdlib.h>
     54#include <str_error.h>
     55#include <str.h>
    4856#include <task.h>
    49 #include <stdarg.h>
    50 #include <stdlib.h>
    51 #include <str.h>
    5257#include <ui/resource.h>
    5358#include <ui/ui.h>
     
    6570
    6671#define TERM_CAPS \
    67         (CONSOLE_CAP_STYLE | CONSOLE_CAP_INDEXED | CONSOLE_CAP_RGB)
     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
    6878
    6979static LIST_INITIALIZE(terms);
     80
     81#define COLOR_BRIGHT 8
     82
     83static 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};
    70102
    71103static errno_t term_open(con_srvs_t *, con_srv_t *);
     
    84116static void term_set_rgb_color(con_srv_t *, pixel_t, pixel_t);
    85117static void term_set_cursor_visibility(con_srv_t *, bool);
     118static errno_t term_set_caption(con_srv_t *, const char *);
    86119static errno_t term_get_event(con_srv_t *, cons_event_t *);
     120static errno_t term_map(con_srv_t *, sysarg_t, sysarg_t, charfield_t **);
     121static void term_unmap(con_srv_t *);
     122static void term_buf_update(con_srv_t *, sysarg_t, sysarg_t, sysarg_t,
     123    sysarg_t);
    87124
    88125static con_ops_t con_ops = {
     
    101138        .set_rgb_color = term_set_rgb_color,
    102139        .set_cursor_visibility = term_set_cursor_visibility,
    103         .get_event = term_get_event
     140        .set_caption = term_set_caption,
     141        .get_event = term_get_event,
     142        .map = term_map,
     143        .unmap = term_unmap,
     144        .update = term_buf_update
    104145};
    105146
    106147static void terminal_close_event(ui_window_t *, void *);
    107 static void terminal_focus_event(ui_window_t *, void *);
     148static void terminal_focus_event(ui_window_t *, void *, unsigned);
     149static void terminal_resize_event(ui_window_t *, void *);
    108150static void terminal_kbd_event(ui_window_t *, void *, kbd_event_t *);
    109151static void terminal_pos_event(ui_window_t *, void *, pos_event_t *);
    110 static void terminal_unfocus_event(ui_window_t *, void *);
     152static void terminal_unfocus_event(ui_window_t *, void *, unsigned);
     153static void terminal_maximize_event(ui_window_t *, void *);
     154static void terminal_unmaximize_event(ui_window_t *, void *);
    111155
    112156static ui_window_cb_t terminal_window_cb = {
    113157        .close = terminal_close_event,
    114158        .focus = terminal_focus_event,
     159        .resize = terminal_resize_event,
    115160        .kbd = terminal_kbd_event,
    116161        .pos = terminal_pos_event,
    117         .unfocus = terminal_unfocus_event
     162        .unfocus = terminal_unfocus_event,
     163        .maximize = terminal_maximize_event,
     164        .unmaximize = terminal_unmaximize_event,
    118165};
    119166
     167static errno_t terminal_wait_fibril(void *);
     168
    120169static terminal_t *srv_to_terminal(con_srv_t *srv)
    121170{
     
    123172}
    124173
    125 static void getterm(const char *svc, const char *app)
    126 {
    127         task_spawnl(NULL, NULL, APP_GETTERM, APP_GETTERM, svc,
     174static 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,
    128177            LOCFS_MOUNT_POINT, "--msg", "--wait", "--", app, NULL);
    129178}
    130179
    131 static pixel_t color_table[16] = {
    132         [COLOR_BLACK]       = PIXEL(255, 0, 0, 0),
    133         [COLOR_BLUE]        = PIXEL(255, 0, 0, 240),
    134         [COLOR_GREEN]       = PIXEL(255, 0, 240, 0),
    135         [COLOR_CYAN]        = PIXEL(255, 0, 240, 240),
    136         [COLOR_RED]         = PIXEL(255, 240, 0, 0),
    137         [COLOR_MAGENTA]     = PIXEL(255, 240, 0, 240),
    138         [COLOR_YELLOW]      = PIXEL(255, 240, 240, 0),
    139         [COLOR_WHITE]       = PIXEL(255, 240, 240, 240),
    140 
    141         [COLOR_BLACK + 8]   = PIXEL(255, 0, 0, 0),
    142         [COLOR_BLUE + 8]    = PIXEL(255, 0, 0, 255),
    143         [COLOR_GREEN + 8]   = PIXEL(255, 0, 255, 0),
    144         [COLOR_CYAN + 8]    = PIXEL(255, 0, 255, 255),
    145         [COLOR_RED + 8]     = PIXEL(255, 255, 0, 0),
    146         [COLOR_MAGENTA + 8] = PIXEL(255, 255, 0, 255),
    147         [COLOR_YELLOW + 8]  = PIXEL(255, 255, 255, 0),
    148         [COLOR_WHITE + 8]   = PIXEL(255, 255, 255, 255),
    149 };
    150 
    151 static inline void attrs_rgb(char_attrs_t attrs, pixel_t *bgcolor, pixel_t *fgcolor)
    152 {
    153         switch (attrs.type) {
     180static 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
     187static 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
     192static 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) {
    154199        case CHAR_ATTR_STYLE:
    155                 switch (attrs.val.style) {
     200                switch (cf->attrs.val.style) {
    156201                case STYLE_NORMAL:
    157                         *bgcolor = color_table[COLOR_WHITE];
    158                         *fgcolor = color_table[COLOR_BLACK];
     202                        cell.bgcolor = term->default_bgcolor;
     203                        cell.fgcolor = term->default_fgcolor;
    159204                        break;
    160205                case STYLE_EMPHASIS:
    161                         *bgcolor = color_table[COLOR_WHITE];
    162                         *fgcolor = color_table[COLOR_RED];
     206                        cell.bgcolor = term->emphasis_bgcolor;
     207                        cell.fgcolor = term->emphasis_fgcolor;
    163208                        break;
    164209                case STYLE_INVERTED:
    165                         *bgcolor = color_table[COLOR_BLACK];
    166                         *fgcolor = color_table[COLOR_WHITE];
     210                        cell.bgcolor = term->default_bgcolor;
     211                        cell.fgcolor = term->default_fgcolor;
     212                        cell.inverted = 1;
    167213                        break;
    168214                case STYLE_SELECTED:
    169                         *bgcolor = color_table[COLOR_RED];
    170                         *fgcolor = color_table[COLOR_WHITE];
     215                        cell.bgcolor = term->selection_bgcolor;
     216                        cell.fgcolor = term->selection_fgcolor;
    171217                        break;
    172218                }
    173219                break;
     220
    174221        case CHAR_ATTR_INDEX:
    175                 *bgcolor = color_table[(attrs.val.index.bgcolor & 7) |
    176                     ((attrs.val.index.attr & CATTR_BRIGHT) ? 8 : 0)];
    177                 *fgcolor = color_table[(attrs.val.index.fgcolor & 7) |
    178                     ((attrs.val.index.attr & CATTR_BRIGHT) ? 8 : 0)];
     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
    179233                break;
     234
    180235        case CHAR_ATTR_RGB:
    181                 *bgcolor = 0xff000000 | attrs.val.rgb.bgcolor;
    182                 *fgcolor = 0xff000000 | attrs.val.rgb.fgcolor;
     236                cell.bgcolor = termui_color_from_pixel(cf->attrs.val.rgb.bgcolor);
     237                cell.fgcolor = termui_color_from_pixel(cf->attrs.val.rgb.fgcolor);
    183238                break;
    184239        }
     240
     241        return cell;
    185242}
    186243
     
    200257}
    201258
    202 static void term_update_char(terminal_t *term, pixelmap_t *pixelmap,
    203     sysarg_t sx, sysarg_t sy, sysarg_t col, sysarg_t row)
    204 {
    205         charfield_t *field =
    206             chargrid_charfield_at(term->backbuf, col, row);
    207 
    208         bool inverted = chargrid_cursor_at(term->backbuf, col, row);
    209 
    210         sysarg_t bx = sx + (col * FONT_WIDTH);
    211         sysarg_t by = sy + (row * FONT_SCANLINES);
    212 
    213         pixel_t bgcolor = 0;
    214         pixel_t fgcolor = 0;
    215 
    216         if (inverted)
    217                 attrs_rgb(field->attrs, &fgcolor, &bgcolor);
    218         else
    219                 attrs_rgb(field->attrs, &bgcolor, &fgcolor);
    220 
    221         // FIXME: Glyph type should be actually uint32_t
    222         //        for full UTF-32 coverage.
    223 
    224         uint16_t glyph = fb_font_glyph(field->ch, NULL);
     259static 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);
    225288
    226289        for (unsigned int y = 0; y < FONT_SCANLINES; y++) {
     
    234297                }
    235298        }
     299
    236300        term_update_region(term, bx, by, FONT_WIDTH, FONT_SCANLINES);
    237301}
    238302
    239 static bool term_update_scroll(terminal_t *term, pixelmap_t *pixelmap,
    240     sysarg_t sx, sysarg_t sy)
    241 {
    242         sysarg_t top_row = chargrid_get_top_row(term->frontbuf);
    243 
    244         if (term->top_row == top_row) {
    245                 return false;
    246         }
    247 
    248         term->top_row = top_row;
    249 
    250         for (sysarg_t row = 0; row < term->rows; row++) {
    251                 for (sysarg_t col = 0; col < term->cols; col++) {
    252                         charfield_t *front_field =
    253                             chargrid_charfield_at(term->frontbuf, col, row);
    254                         charfield_t *back_field =
    255                             chargrid_charfield_at(term->backbuf, col, row);
    256                         bool update = false;
    257 
    258                         if (front_field->ch != back_field->ch) {
    259                                 back_field->ch = front_field->ch;
    260                                 update = true;
    261                         }
    262 
    263                         if (!attrs_same(front_field->attrs, back_field->attrs)) {
    264                                 back_field->attrs = front_field->attrs;
    265                                 update = true;
    266                         }
    267 
    268                         front_field->flags &= ~CHAR_FLAG_DIRTY;
    269 
    270                         if (update) {
    271                                 term_update_char(term, pixelmap, sx, sy, col, row);
    272                         }
    273                 }
    274         }
    275 
    276         return true;
    277 }
    278 
    279 static bool term_update_cursor(terminal_t *term, pixelmap_t *pixelmap,
    280     sysarg_t sx, sysarg_t sy)
    281 {
    282         bool update = false;
    283 
    284         sysarg_t front_col;
    285         sysarg_t front_row;
    286         chargrid_get_cursor(term->frontbuf, &front_col, &front_row);
    287 
    288         sysarg_t back_col;
    289         sysarg_t back_row;
    290         chargrid_get_cursor(term->backbuf, &back_col, &back_row);
    291 
    292         bool front_visibility =
    293             chargrid_get_cursor_visibility(term->frontbuf) &&
    294             term->is_focused;
    295         bool back_visibility =
    296             chargrid_get_cursor_visibility(term->backbuf);
    297 
    298         if (front_visibility != back_visibility) {
    299                 chargrid_set_cursor_visibility(term->backbuf,
    300                     front_visibility);
    301                 term_update_char(term, pixelmap, sx, sy, back_col, back_row);
    302                 update = true;
    303         }
    304 
    305         if ((front_col != back_col) || (front_row != back_row)) {
    306                 chargrid_set_cursor(term->backbuf, front_col, front_row);
    307                 term_update_char(term, pixelmap, sx, sy, back_col, back_row);
    308                 term_update_char(term, pixelmap, sx, sy, front_col, front_row);
    309                 update = true;
    310         }
    311 
    312         return update;
    313 }
    314 
    315 static void term_update(terminal_t *term)
    316 {
    317         pixelmap_t pixelmap;
     303static 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
     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 = { };
    318331        gfx_bitmap_alloc_t alloc;
    319         gfx_coord2_t pos;
    320         errno_t rc;
    321 
    322         rc = gfx_bitmap_get_alloc(term->bmp, &alloc);
    323         if (rc != EOK) {
    324                 return;
    325         }
    326 
    327         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
    328337        pixelmap.width = term->w;
    329338        pixelmap.height = term->h;
    330339        pixelmap.data = alloc.pixels;
    331 
    332         bool update = false;
    333         sysarg_t sx = 0/*term->widget.hpos*/;
    334         sysarg_t sy = 0/*term->widget.vpos*/;
    335 
    336         if (term_update_scroll(term, &pixelmap, sx, sy)) {
    337                 update = true;
    338         } else {
    339                 for (sysarg_t y = 0; y < term->rows; y++) {
    340                         for (sysarg_t x = 0; x < term->cols; x++) {
    341                                 charfield_t *front_field =
    342                                     chargrid_charfield_at(term->frontbuf, x, y);
    343                                 charfield_t *back_field =
    344                                     chargrid_charfield_at(term->backbuf, x, y);
    345                                 bool update = false;
    346 
    347                                 if ((front_field->flags & CHAR_FLAG_DIRTY) ==
    348                                     CHAR_FLAG_DIRTY) {
    349                                         if (front_field->ch != back_field->ch) {
    350                                                 back_field->ch = front_field->ch;
    351                                                 update = true;
    352                                         }
    353 
    354                                         if (!attrs_same(front_field->attrs,
    355                                             back_field->attrs)) {
    356                                                 back_field->attrs = front_field->attrs;
    357                                                 update = true;
    358                                         }
    359 
    360                                         front_field->flags &= ~CHAR_FLAG_DIRTY;
    361                                 }
    362 
    363                                 if (update) {
    364                                         term_update_char(term, &pixelmap, sx, sy, x, y);
    365                                         update = true;
    366                                 }
    367                         }
    368                 }
    369         }
    370 
    371         if (term_update_cursor(term, &pixelmap, sx, sy))
    372                 update = true;
    373 
    374         if (update) {
    375                 pos.x = 4;
    376                 pos.y = 26;
    377                 (void) gfx_bitmap_render(term->bmp, &term->update, &pos);
    378 
    379                 term->update.p0.x = 0;
    380                 term->update.p0.y = 0;
    381                 term->update.p1.x = 0;
    382                 term->update.p1.y = 0;
    383         }
    384 
    385         fibril_mutex_unlock(&term->mtx);
    386 }
    387 
    388 static void term_repaint(terminal_t *term)
    389 {
    390         pixelmap_t pixelmap;
    391         gfx_bitmap_alloc_t alloc;
    392         errno_t rc;
    393 
    394         rc = gfx_bitmap_get_alloc(term->bmp, &alloc);
    395         if (rc != EOK) {
    396                 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)
    397347                return;
    398         }
    399 
    400         fibril_mutex_lock(&term->mtx);
    401 
    402         pixelmap.width = term->w;
    403         pixelmap.height = term->h;
    404         pixelmap.data = alloc.pixels;
    405 
    406         sysarg_t sx = 0;
    407         sysarg_t sy = 0;
    408 
    409         if (!term_update_scroll(term, &pixelmap, sx, sy)) {
    410                 for (sysarg_t y = 0; y < term->rows; y++) {
    411                         for (sysarg_t x = 0; x < term->cols; x++) {
    412                                 charfield_t *front_field =
    413                                     chargrid_charfield_at(term->frontbuf, x, y);
    414                                 charfield_t *back_field =
    415                                     chargrid_charfield_at(term->backbuf, x, y);
    416 
    417                                 back_field->ch = front_field->ch;
    418                                 back_field->attrs = front_field->attrs;
    419                                 front_field->flags &= ~CHAR_FLAG_DIRTY;
    420 
    421                                 term_update_char(term, &pixelmap, sx, sy, x, y);
    422                         }
    423                 }
    424         }
    425 
    426         term_update_cursor(term, &pixelmap, sx, sy);
    427 
    428         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]);
    429366}
    430367
     
    466403                if (pos < size) {
    467404                        link_t *link = prodcons_consume(&term->input_pc);
    468                         cons_event_t *event = list_get_instance(link, cons_event_t, link);
     405                        terminal_event_t *qevent = list_get_instance(link,
     406                            terminal_event_t, link);
     407                        cons_event_t *event = &qevent->ev;
    469408
    470409                        /* Accept key presses of printable chars only. */
     
    480419                        }
    481420
    482                         free(event);
     421                        free(qevent);
    483422                }
    484423        }
     
    490429static void term_write_char(terminal_t *term, wchar_t ch)
    491430{
    492         sysarg_t updated = 0;
    493 
    494         fibril_mutex_lock(&term->mtx);
    495 
    496431        switch (ch) {
    497         case '\n':
    498                 updated = chargrid_newline(term->frontbuf);
     432        case L'\n':
     433                termui_put_crlf(term->termui);
    499434                break;
    500         case '\r':
     435        case L'\r':
     436                termui_put_cr(term->termui);
    501437                break;
    502         case '\t':
    503                 updated = chargrid_tabstop(term->frontbuf, 8);
     438        case L'\t':
     439                termui_put_tab(term->termui);
    504440                break;
    505         case '\b':
    506                 updated = chargrid_backspace(term->frontbuf);
     441        case L'\b':
     442                termui_put_backspace(term->termui);
    507443                break;
    508444        default:
    509                 updated = chargrid_putuchar(term->frontbuf, ch, true);
    510         }
    511 
    512         fibril_mutex_unlock(&term->mtx);
    513 
    514         if (updated > 1)
    515                 term_update(term);
     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        }
    516451}
    517452
     
    519454{
    520455        terminal_t *term = srv_to_terminal(srv);
     456
     457        fibril_mutex_lock(&term->mtx);
    521458
    522459        size_t off = 0;
     
    524461                term_write_char(term, str_decode(data, &off, size));
    525462
     463        fibril_mutex_unlock(&term->mtx);
     464
     465        term_render(term);
     466        gfx_update(term->gc);
    526467        *nwritten = size;
     468
    527469        return EOK;
    528470}
     
    532474        terminal_t *term = srv_to_terminal(srv);
    533475
    534         term_update(term);
     476        term_render(term);
     477        gfx_update(term->gc);
    535478}
    536479
     
    540483
    541484        fibril_mutex_lock(&term->mtx);
    542         chargrid_clear(term->frontbuf);
    543         fibril_mutex_unlock(&term->mtx);
    544 
    545         term_update(term);
     485        termui_clear_screen(term->termui);
     486        fibril_mutex_unlock(&term->mtx);
     487
     488        term_render(term);
     489        gfx_update(term->gc);
    546490}
    547491
     
    551495
    552496        fibril_mutex_lock(&term->mtx);
    553         chargrid_set_cursor(term->frontbuf, col, row);
    554         fibril_mutex_unlock(&term->mtx);
    555 
    556         term_update(term);
     497        termui_set_pos(term->termui, col, row);
     498        fibril_mutex_unlock(&term->mtx);
     499
     500        term_render(term);
     501        gfx_update(term->gc);
    557502}
    558503
     
    562507
    563508        fibril_mutex_lock(&term->mtx);
    564         chargrid_get_cursor(term->frontbuf, col, row);
    565         fibril_mutex_unlock(&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;
    566515
    567516        return EOK;
     
    573522
    574523        fibril_mutex_lock(&term->mtx);
    575         *cols = term->cols;
    576         *rows = term->rows;
     524        *cols = termui_get_cols(term->termui);
     525        *rows = termui_get_rows(term->termui);
    577526        fibril_mutex_unlock(&term->mtx);
    578527
     
    592541        terminal_t *term = srv_to_terminal(srv);
    593542
    594         fibril_mutex_lock(&term->mtx);
    595         chargrid_set_style(term->frontbuf, style);
     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);
    596567        fibril_mutex_unlock(&term->mtx);
    597568}
     
    602573        terminal_t *term = srv_to_terminal(srv);
    603574
    604         fibril_mutex_lock(&term->mtx);
    605         chargrid_set_color(term->frontbuf, bgcolor, fgcolor, attr);
     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);
    606586        fibril_mutex_unlock(&term->mtx);
    607587}
     
    611591{
    612592        terminal_t *term = srv_to_terminal(srv);
    613 
    614         fibril_mutex_lock(&term->mtx);
    615         chargrid_set_rgb_color(term->frontbuf, bgcolor, fgcolor);
     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);
    616600        fibril_mutex_unlock(&term->mtx);
    617601}
     
    622606
    623607        fibril_mutex_lock(&term->mtx);
    624         chargrid_set_cursor_visibility(term->frontbuf, visible);
    625         fibril_mutex_unlock(&term->mtx);
    626 
    627         term_update(term);
     608        termui_set_cursor_visibility(term->termui, visible);
     609        fibril_mutex_unlock(&term->mtx);
     610
     611        term_render(term);
     612        gfx_update(term->gc);
     613}
     614
     615static 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;
    628633}
    629634
     
    632637        terminal_t *term = srv_to_terminal(srv);
    633638        link_t *link = prodcons_consume(&term->input_pc);
    634         cons_event_t *ev = list_get_instance(link, cons_event_t, link);
    635 
    636         *event = *ev;
     639        terminal_event_t *ev = list_get_instance(link, terminal_event_t, link);
     640
     641        *event = ev->ev;
    637642        free(ev);
    638643        return EOK;
    639644}
    640645
    641 static void deinit_terminal(terminal_t *term)
     646/** Create shared buffer for efficient rendering.
     647 *
     648 * @param srv Console server
     649 * @param cols Number of columns in buffer
     650 * @param rows Number of rows in buffer
     651 * @param rbuf Place to store pointer to new sharable buffer
     652 *
     653 * @return EOK on sucess or an error code
     654 */
     655static errno_t term_map(con_srv_t *srv, sysarg_t cols, sysarg_t rows,
     656    charfield_t **rbuf)
     657{
     658        terminal_t *term = srv_to_terminal(srv);
     659        void *buf;
     660
     661        fibril_mutex_lock(&term->mtx);
     662
     663        if (term->ubuf != NULL) {
     664                fibril_mutex_unlock(&term->mtx);
     665                return EBUSY;
     666        }
     667
     668        buf = as_area_create(AS_AREA_ANY, cols * rows * sizeof(charfield_t),
     669            AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE, AS_AREA_UNPAGED);
     670        if (buf == AS_MAP_FAILED) {
     671                fibril_mutex_unlock(&term->mtx);
     672                return ENOMEM;
     673        }
     674
     675        term->ucols = cols;
     676        term->urows = rows;
     677        term->ubuf = buf;
     678
     679        /* Scroll back to active screen. */
     680        termui_history_scroll(term->termui, INT_MAX);
     681
     682        fibril_mutex_unlock(&term->mtx);
     683
     684        *rbuf = buf;
     685        return EOK;
     686}
     687
     688/** Delete shared buffer.
     689 *
     690 * @param srv Console server
     691 */
     692static void term_unmap(con_srv_t *srv)
     693{
     694        terminal_t *term = srv_to_terminal(srv);
     695        void *buf;
     696
     697        fibril_mutex_lock(&term->mtx);
     698
     699        buf = term->ubuf;
     700        term->ubuf = NULL;
     701
     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
     710        if (buf != NULL)
     711                as_area_destroy(buf);
     712}
     713
     714/** Update area of terminal from shared buffer.
     715 *
     716 * @param srv Console server
     717 * @param c0 Column coordinate of top-left corner (inclusive)
     718 * @param r0 Row coordinate of top-left corner (inclusive)
     719 * @param c1 Column coordinate of bottom-right corner (exclusive)
     720 * @param r1 Row coordinate of bottom-right corner (exclusive)
     721 */
     722static void term_buf_update(con_srv_t *srv, sysarg_t c0, sysarg_t r0,
     723    sysarg_t c1, sysarg_t r1)
     724{
     725        terminal_t *term = srv_to_terminal(srv);
     726
     727        fibril_mutex_lock(&term->mtx);
     728
     729        if (term->ubuf == NULL) {
     730                fibril_mutex_unlock(&term->mtx);
     731                return;
     732        }
     733
     734        /* 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) {
     741                fibril_mutex_unlock(&term->mtx);
     742                return;
     743        }
     744
     745        /* Update front buffer from user buffer */
     746
     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]);
     752                }
     753
     754                termui_update_cb(term, c0, row, &cells[c0], c1 - c0);
     755        }
     756
     757        fibril_mutex_unlock(&term->mtx);
     758
     759        /* Update terminal */
     760        term_render(term);
     761        gfx_update(term->gc);
     762}
     763
     764static errno_t terminal_window_resize(terminal_t *term)
     765{
     766        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;
     784        gfx_bitmap_params_init(&params);
     785        params.rect.p0.x = 0;
     786        params.rect.p0.y = 0;
     787        params.rect.p1.x = width;
     788        params.rect.p1.y = height;
     789
     790        errno_t rc = gfx_bitmap_create(term->gc, &params, NULL, &new_bmp);
     791        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
     811void terminal_destroy(terminal_t *term)
    642812{
    643813        list_remove(&term->link);
    644814
    645         if (term->frontbuf)
    646                 chargrid_destroy(term->frontbuf);
    647 
    648         if (term->backbuf)
    649                 chargrid_destroy(term->backbuf);
    650 }
    651 
    652 void terminal_destroy(terminal_t *term)
    653 {
    654         deinit_terminal(term);
     815        termui_destroy(term->termui);
     816
     817        if (term->ubuf)
     818                as_area_destroy(term->ubuf);
     819
     820        ui_destroy(term->ui);
    655821        free(term);
    656822}
     
    659825{
    660826        /* Got key press/release event */
    661         cons_event_t *event =
    662             (cons_event_t *) malloc(sizeof(cons_event_t));
     827        terminal_event_t *event =
     828            (terminal_event_t *) malloc(sizeof(terminal_event_t));
    663829        if (event == NULL)
    664830                return;
    665831
    666         *event = *ev;
     832        event->ev = *ev;
    667833        link_initialize(&event->link);
    668834
     
    675841        terminal_t *term = (terminal_t *) arg;
    676842
    677         (void) term;
    678 
    679         // XXX This is not really a clean way of terminating
    680         exit(0);
     843        ui_quit(term->ui);
    681844}
    682845
    683846/** Handle window focus event. */
    684 static void terminal_focus_event(ui_window_t *window, void *arg)
     847static void terminal_focus_event(ui_window_t *window, void *arg,
     848    unsigned nfocus)
    685849{
    686850        terminal_t *term = (terminal_t *) arg;
    687851
     852        (void)nfocus;
    688853        term->is_focused = true;
    689         term_update(term);
     854        term_render(term);
     855        gfx_update(term->gc);
     856}
     857
     858static 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
     878static 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
     884static 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
     890static void terminal_unmaximize_event(ui_window_t *window, void *arg)
     891{
     892        ui_window_def_unmaximize(window);
     893        terminal_resize_handler(window, arg);
    690894}
    691895
     
    700904        event.ev.key = *kbd_event;
    701905
    702         terminal_queue_cons_event(term, &event);
     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);
    703923}
    704924
     
    709929        terminal_t *term = (terminal_t *) arg;
    710930
    711         sysarg_t sx = -term->off.x;
    712         sysarg_t sy = -term->off.y;
    713 
    714         if (event->type == POS_PRESS) {
    715                 cevent.type = CEV_POS;
    716                 cevent.ev.pos.type = event->type;
    717                 cevent.ev.pos.pos_id = event->pos_id;
    718                 cevent.ev.pos.btn_num = event->btn_num;
    719 
    720                 cevent.ev.pos.hpos = (event->hpos - sx) / FONT_WIDTH;
    721                 cevent.ev.pos.vpos = (event->vpos - sy) / FONT_SCANLINES;
     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)
    722963                terminal_queue_cons_event(term, &cevent);
    723         }
    724964}
    725965
    726966/** Handle window unfocus event. */
    727 static void terminal_unfocus_event(ui_window_t *window, void *arg)
     967static void terminal_unfocus_event(ui_window_t *window, void *arg,
     968    unsigned nfocus)
    728969{
    729970        terminal_t *term = (terminal_t *) arg;
    730971
    731         term->is_focused = false;
    732         term_update(term);
     972        if (nfocus == 0) {
     973                term->is_focused = false;
     974                term_render(term);
     975                gfx_update(term->gc);
     976        }
    733977}
    734978
     
    750994
    751995        if (!atomic_flag_test_and_set(&term->refcnt))
    752                 chargrid_set_cursor_visibility(term->frontbuf, true);
     996                termui_set_cursor_visibility(term->termui, true);
    753997
    754998        con_conn(icall, &term->srvs);
    755999}
    7561000
     1001static 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
    7571054errno_t terminal_create(const char *display_spec, sysarg_t width,
    758     sysarg_t height, terminal_flags_t flags, terminal_t **rterm)
    759 {
    760         terminal_t *term;
    761         gfx_bitmap_params_t params;
    762         ui_wnd_params_t wparams;
    763         gfx_rect_t rect;
    764         gfx_coord2_t off;
    765         gfx_rect_t wrect;
     1055    sysarg_t height, terminal_flags_t flags, const char *command,
     1056    terminal_t **rterm)
     1057{
    7661058        errno_t rc;
    7671059
    768         term = calloc(1, sizeof(terminal_t));
     1060        terminal_t *term = calloc(1, sizeof(terminal_t));
    7691061        if (term == NULL) {
    7701062                printf("Out of memory.\n");
     
    7791071        term->char_remains_len = 0;
    7801072
    781         term->w = width;
    782         term->h = height;
    783 
    784         term->cols = width / FONT_WIDTH;
    785         term->rows = height / FONT_SCANLINES;
    786 
    787         term->frontbuf = NULL;
    788         term->backbuf = NULL;
    789 
    790         term->frontbuf = chargrid_create(term->cols, term->rows,
    791             CHARGRID_FLAG_NONE);
    792         if (!term->frontbuf) {
    793                 printf("Error creating front buffer.\n");
     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));
     1086                goto error;
     1087        }
     1088
     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");
    7941093                rc = ENOMEM;
    7951094                goto error;
    7961095        }
    7971096
    798         term->backbuf = chargrid_create(term->cols, term->rows,
    799             CHARGRID_FLAG_NONE);
    800         if (!term->backbuf) {
    801                 printf("Error creating back buffer.\n");
    802                 rc = ENOMEM;
    803                 goto error;
    804         }
    805 
    806         rect.p0.x = 0;
    807         rect.p0.y = 0;
    808         rect.p1.x = width;
    809         rect.p1.y = height;
    810 
    811         ui_wnd_params_init(&wparams);
    812         wparams.caption = "Terminal";
    813         if ((flags & tf_topleft) != 0)
    814                 wparams.placement = ui_wnd_place_top_left;
    815 
    816         /*
    817          * Compute window rectangle such that application area corresponds
    818          * to rect
    819          */
    820         ui_wdecor_rect_from_app(wparams.style, &rect, &wrect);
    821         off = wrect.p0;
    822         gfx_rect_rtranslate(&off, &wrect, &wparams.rect);
    823 
    824         term->off = off;
    825 
    826         rc = ui_create(display_spec, &term->ui);
    827         if (rc != EOK) {
    828                 printf("Error creating UI on %s.\n", display_spec);
    829                 goto error;
    830         }
    831 
    832         rc = ui_window_create(term->ui, &wparams, &term->window);
    833         if (rc != EOK) {
    834                 printf("Error creating window.\n");
    835                 goto error;
    836         }
    837 
    838         term->gc = ui_window_get_gc(term->window);
    839         term->ui_res = ui_window_get_res(term->window);
    840 
    841         ui_window_set_cb(term->window, &terminal_window_cb, (void *) term);
    842 
    843         gfx_bitmap_params_init(&params);
    844         params.rect.p0.x = 0;
    845         params.rect.p0.y = 0;
    846         params.rect.p1.x = width;
    847         params.rect.p1.y = height;
    848 
    849         rc = gfx_bitmap_create(term->gc, &params, NULL, &term->bmp);
    850         if (rc != EOK) {
    851                 printf("Error allocating screen bitmap.\n");
    852                 goto error;
    853         }
    854 
    855         chargrid_clear(term->frontbuf);
    856         chargrid_clear(term->backbuf);
    857         term->top_row = 0;
     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);
    8581100
    8591101        async_set_fallback_port_handler(term_connection, NULL);
     
    8621104        term->srvs.sarg = term;
    8631105
    864         rc = loc_server_register(NAME);
     1106        rc = loc_server_register(NAME, &term->srv);
    8651107        if (rc != EOK) {
    8661108                printf("Error registering server.\n");
     
    8731115            task_get_id());
    8741116
    875         rc = loc_service_register(vc, &term->dsid);
     1117        rc = loc_service_register(term->srv, vc, &term->dsid);
    8761118        if (rc != EOK) {
    8771119                printf("Error registering service.\n");
     
    8811123
    8821124        list_append(&term->link, &terms);
    883         getterm(vc, "/app/bdsh");
     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);
    8841134
    8851135        term->is_focused = true;
    8861136
    887         term->update.p0.x = 0;
    888         term->update.p0.y = 0;
    889         term->update.p1.x = 0;
    890         term->update.p1.y = 0;
    891 
    892         term_repaint(term);
     1137        termui_refresh_cb(term);
    8931138
    8941139        *rterm = term;
    8951140        return EOK;
    8961141error:
     1142        if (term->dsid != 0)
     1143                loc_service_unregister(term->srv, term->dsid);
     1144        if (term->srv != NULL)
     1145                loc_server_unregister(term->srv);
    8971146        if (term->window != NULL)
    8981147                ui_window_destroy(term->window);
    8991148        if (term->ui != NULL)
    9001149                ui_destroy(term->ui);
    901         if (term->frontbuf != NULL)
    902                 chargrid_destroy(term->frontbuf);
    903         if (term->backbuf != NULL)
    904                 chargrid_destroy(term->backbuf);
     1150        if (term->termui != NULL)
     1151                termui_destroy(term->termui);
    9051152        free(term);
    9061153        return rc;
    9071154}
    9081155
     1156static 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
    9091171/** @}
    9101172 */
Note: See TracChangeset for help on using the changeset viewer.