Changeset 7e38970d in mainline for uspace/app/terminal/terminal.c


Ignore:
Timestamp:
2020-12-07T00:08:37Z (3 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
25f26600
Parents:
7a873f0 (diff), 8596474 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'jxsvoboda-gfx' into master

File:
1 moved

Legend:

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

    r7a873f0 r7e38970d  
    11/*
     2 * Copyright (c) 2020 Jiri Svoboda
    23 * Copyright (c) 2012 Petr Koupy
    34 * All rights reserved.
     
    2728 */
    2829
    29 /** @addtogroup gui
     30/** @addtogroup terminal
    3031 * @{
    3132 */
    3233/**
    33  * @file
     34 * @file Terminal application
    3435 */
    3536
     37#include <adt/list.h>
     38#include <adt/prodcons.h>
    3639#include <errno.h>
    37 #include <stdlib.h>
     40#include <fbfont/font-8x16.h>
    3841#include <io/chargrid.h>
    39 #include <draw/surface.h>
    40 #include <draw/gfx.h>
     42#include <gfx/bitmap.h>
     43#include <gfx/context.h>
    4144#include <io/con_srv.h>
    4245#include <io/concaps.h>
    4346#include <io/console.h>
    44 #include <loc.h>
     47#include <io/pixelmap.h>
    4548#include <task.h>
    46 #include <adt/list.h>
    47 #include <adt/prodcons.h>
    4849#include <stdarg.h>
     50#include <stdlib.h>
    4951#include <str.h>
    50 #include "window.h"
     52#include <ui/resource.h>
     53#include <ui/ui.h>
     54#include <ui/wdecor.h>
     55#include <ui/window.h>
     56
    5157#include "terminal.h"
    5258
    53 #define NAME       "vterm"
    54 #define NAMESPACE  "vterm"
     59#define NAME       "terminal"
     60#define NAMESPACE  "terminal"
    5561
    5662#define LOCFS_MOUNT_POINT  "/loc"
     
    96102        .set_cursor_visibility = term_set_cursor_visibility,
    97103        .get_event = term_get_event
     104};
     105
     106static void terminal_close_event(ui_window_t *, void *);
     107static void terminal_focus_event(ui_window_t *, void *);
     108static void terminal_kbd_event(ui_window_t *, void *, kbd_event_t *);
     109static void terminal_pos_event(ui_window_t *, void *, pos_event_t *);
     110static void terminal_unfocus_event(ui_window_t *, void *);
     111
     112static ui_window_cb_t terminal_window_cb = {
     113        .close = terminal_close_event,
     114        .focus = terminal_focus_event,
     115        .kbd = terminal_kbd_event,
     116        .pos = terminal_pos_event,
     117        .unfocus = terminal_unfocus_event
    98118};
    99119
     
    165185}
    166186
    167 static void term_update_char(terminal_t *term, surface_t *surface,
     187static void term_update_region(terminal_t *term, sysarg_t x, sysarg_t y,
     188    sysarg_t w, sysarg_t h)
     189{
     190        gfx_rect_t rect;
     191        gfx_rect_t nupdate;
     192
     193        rect.p0.x = x;
     194        rect.p0.y = y;
     195        rect.p1.x = x + w;
     196        rect.p1.y = y + h;
     197
     198        gfx_rect_envelope(&term->update, &rect, &nupdate);
     199        term->update = nupdate;
     200}
     201
     202static void term_update_char(terminal_t *term, pixelmap_t *pixelmap,
    168203    sysarg_t sx, sysarg_t sy, sysarg_t col, sysarg_t row)
    169204{
     
    190225
    191226        for (unsigned int y = 0; y < FONT_SCANLINES; y++) {
    192                 pixel_t *dst = pixelmap_pixel_at(
    193                     surface_pixmap_access(surface), bx, by + y);
    194                 pixel_t *dst_max = pixelmap_pixel_at(
    195                     surface_pixmap_access(surface), bx + FONT_WIDTH - 1, by + y);
     227                pixel_t *dst = pixelmap_pixel_at(pixelmap, bx, by + y);
     228                pixel_t *dst_max = pixelmap_pixel_at(pixelmap, bx + FONT_WIDTH - 1, by + y);
    196229                if (!dst || !dst_max)
    197230                        continue;
     
    201234                }
    202235        }
    203         surface_add_damaged_region(surface, bx, by, FONT_WIDTH, FONT_SCANLINES);
    204 }
    205 
    206 static bool term_update_scroll(terminal_t *term, surface_t *surface,
     236        term_update_region(term, bx, by, FONT_WIDTH, FONT_SCANLINES);
     237}
     238
     239static bool term_update_scroll(terminal_t *term, pixelmap_t *pixelmap,
    207240    sysarg_t sx, sysarg_t sy)
    208241{
    209242        sysarg_t top_row = chargrid_get_top_row(term->frontbuf);
    210243
    211         if (term->top_row == top_row)
     244        if (term->top_row == top_row) {
    212245                return false;
     246        }
    213247
    214248        term->top_row = top_row;
     
    234268                        front_field->flags &= ~CHAR_FLAG_DIRTY;
    235269
    236                         if (update)
    237                                 term_update_char(term, surface, sx, sy, col, row);
     270                        if (update) {
     271                                term_update_char(term, pixelmap, sx, sy, col, row);
     272                        }
    238273                }
    239274        }
     
    242277}
    243278
    244 static bool term_update_cursor(terminal_t *term, surface_t *surface,
     279static bool term_update_cursor(terminal_t *term, pixelmap_t *pixelmap,
    245280    sysarg_t sx, sysarg_t sy)
    246281{
    247         bool damage = false;
     282        bool update = false;
    248283
    249284        sysarg_t front_col;
     
    257292        bool front_visibility =
    258293            chargrid_get_cursor_visibility(term->frontbuf) &&
    259             term->widget.window->is_focused;
     294            term->is_focused;
    260295        bool back_visibility =
    261296            chargrid_get_cursor_visibility(term->backbuf);
     
    264299                chargrid_set_cursor_visibility(term->backbuf,
    265300                    front_visibility);
    266                 term_update_char(term, surface, sx, sy, back_col, back_row);
    267                 damage = true;
     301                term_update_char(term, pixelmap, sx, sy, back_col, back_row);
     302                update = true;
    268303        }
    269304
    270305        if ((front_col != back_col) || (front_row != back_row)) {
    271306                chargrid_set_cursor(term->backbuf, front_col, front_row);
    272                 term_update_char(term, surface, sx, sy, back_col, back_row);
    273                 term_update_char(term, surface, sx, sy, front_col, front_row);
    274                 damage = true;
    275         }
    276 
    277         return damage;
     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;
    278313}
    279314
    280315static void term_update(terminal_t *term)
    281316{
    282         fibril_mutex_lock(&term->mtx);
    283 
    284         surface_t *surface = window_claim(term->widget.window);
    285         if (!surface) {
    286                 window_yield(term->widget.window);
    287                 fibril_mutex_unlock(&term->mtx);
     317        pixelmap_t pixelmap;
     318        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) {
    288324                return;
    289325        }
    290326
    291         bool damage = false;
    292         sysarg_t sx = term->widget.hpos;
    293         sysarg_t sy = term->widget.vpos;
    294 
    295         if (term_update_scroll(term, surface, sx, sy)) {
    296                 damage = true;
     327        fibril_mutex_lock(&term->mtx);
     328        pixelmap.width = term->w;
     329        pixelmap.height = term->h;
     330        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;
    297338        } else {
    298339                for (sysarg_t y = 0; y < term->rows; y++) {
     
    321362
    322363                                if (update) {
    323                                         term_update_char(term, surface, sx, sy, x, y);
    324                                         damage = true;
     364                                        term_update_char(term, &pixelmap, sx, sy, x, y);
     365                                        update = true;
    325366                                }
    326367                        }
     
    328369        }
    329370
    330         if (term_update_cursor(term, surface, sx, sy))
    331                 damage = true;
    332 
    333         window_yield(term->widget.window);
    334 
    335         if (damage)
    336                 window_damage(term->widget.window);
    337 
    338         fibril_mutex_unlock(&term->mtx);
    339 }
    340 
    341 static void term_damage(terminal_t *term)
    342 {
    343         fibril_mutex_lock(&term->mtx);
    344 
    345         surface_t *surface = window_claim(term->widget.window);
    346         if (!surface) {
    347                 window_yield(term->widget.window);
    348                 fibril_mutex_unlock(&term->mtx);
     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
     388static 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");
    349397                return;
    350398        }
    351399
    352         sysarg_t sx = term->widget.hpos;
    353         sysarg_t sy = term->widget.vpos;
    354 
    355         if (!term_update_scroll(term, surface, sx, sy)) {
     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)) {
    356410                for (sysarg_t y = 0; y < term->rows; y++) {
    357411                        for (sysarg_t x = 0; x < term->cols; x++) {
     
    365419                                front_field->flags &= ~CHAR_FLAG_DIRTY;
    366420
    367                                 term_update_char(term, surface, sx, sy, x, y);
     421                                term_update_char(term, &pixelmap, sx, sy, x, y);
    368422                        }
    369423                }
    370424        }
    371425
    372         term_update_cursor(term, surface, sx, sy);
    373 
    374         window_yield(term->widget.window);
    375         window_damage(term->widget.window);
     426        term_update_cursor(term, &pixelmap, sx, sy);
    376427
    377428        fibril_mutex_unlock(&term->mtx);
     
    437488}
    438489
    439 static void term_write_char(terminal_t *term, char32_t ch)
     490static void term_write_char(terminal_t *term, wchar_t ch)
    440491{
    441492        sysarg_t updated = 0;
     
    588639}
    589640
    590 void deinit_terminal(terminal_t *term)
     641static void deinit_terminal(terminal_t *term)
    591642{
    592643        list_remove(&term->link);
    593         widget_deinit(&term->widget);
    594644
    595645        if (term->frontbuf)
     
    600650}
    601651
    602 static void terminal_destroy(widget_t *widget)
    603 {
    604         terminal_t *term = (terminal_t *) widget;
    605 
     652void terminal_destroy(terminal_t *term)
     653{
    606654        deinit_terminal(term);
    607655        free(term);
    608 }
    609 
    610 static void terminal_reconfigure(widget_t *widget)
    611 {
    612         /* No-op */
    613 }
    614 
    615 static void terminal_rearrange(widget_t *widget, sysarg_t hpos, sysarg_t vpos,
    616     sysarg_t width, sysarg_t height)
    617 {
    618         terminal_t *term = (terminal_t *) widget;
    619 
    620         widget_modify(widget, hpos, vpos, width, height);
    621         widget->width_ideal = width;
    622         widget->height_ideal = height;
    623 
    624         term_damage(term);
    625 }
    626 
    627 static void terminal_repaint(widget_t *widget)
    628 {
    629         terminal_t *term = (terminal_t *) widget;
    630 
    631         term_damage(term);
    632656}
    633657
     
    646670}
    647671
    648 /* Got key press/release event */
    649 static void terminal_handle_keyboard_event(widget_t *widget,
    650     kbd_event_t kbd_event)
    651 {
    652         terminal_t *term = (terminal_t *) widget;
     672/** Handle window close event. */
     673static void terminal_close_event(ui_window_t *window, void *arg)
     674{
     675        terminal_t *term = (terminal_t *) arg;
     676
     677        (void) term;
     678
     679        // XXX This is not really a clean way of terminating
     680        exit(0);
     681}
     682
     683/** Handle window focus event. */
     684static void terminal_focus_event(ui_window_t *window, void *arg)
     685{
     686        terminal_t *term = (terminal_t *) arg;
     687
     688        term->is_focused = true;
     689        term_update(term);
     690}
     691
     692/** Handle window keyboard event */
     693static void terminal_kbd_event(ui_window_t *window, void *arg,
     694    kbd_event_t *kbd_event)
     695{
     696        terminal_t *term = (terminal_t *) arg;
    653697        cons_event_t event;
    654698
    655699        event.type = CEV_KEY;
    656         event.ev.key = kbd_event;
     700        event.ev.key = *kbd_event;
    657701
    658702        terminal_queue_cons_event(term, &event);
    659703}
    660704
    661 static void terminal_handle_position_event(widget_t *widget, pos_event_t pos_event)
    662 {
    663         cons_event_t event;
    664         terminal_t *term = (terminal_t *) widget;
    665         sysarg_t sx = term->widget.hpos;
    666         sysarg_t sy = term->widget.vpos;
    667 
    668         if (pos_event.type == POS_PRESS) {
    669                 event.type = CEV_POS;
    670                 event.ev.pos.type = pos_event.type;
    671                 event.ev.pos.pos_id = pos_event.pos_id;
    672                 event.ev.pos.btn_num = pos_event.btn_num;
    673 
    674                 event.ev.pos.hpos = (pos_event.hpos - sx) / FONT_WIDTH;
    675                 event.ev.pos.vpos = (pos_event.vpos - sy) / FONT_SCANLINES;
    676                 terminal_queue_cons_event(term, &event);
    677         }
     705/** Handle window position event */
     706static void terminal_pos_event(ui_window_t *window, void *arg, pos_event_t *event)
     707{
     708        cons_event_t cevent;
     709        terminal_t *term = (terminal_t *) arg;
     710
     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;
     722                terminal_queue_cons_event(term, &cevent);
     723        }
     724}
     725
     726/** Handle window unfocus event. */
     727static void terminal_unfocus_event(ui_window_t *window, void *arg)
     728{
     729        terminal_t *term = (terminal_t *) arg;
     730
     731        term->is_focused = false;
     732        term_update(term);
    678733}
    679734
     
    700755}
    701756
    702 bool init_terminal(terminal_t *term, widget_t *parent, const void *data,
    703     sysarg_t width, sysarg_t height)
    704 {
    705         widget_init(&term->widget, parent, data);
     757errno_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;
     766        errno_t rc;
     767
     768        term = calloc(1, sizeof(terminal_t));
     769        if (term == NULL) {
     770                printf("Out of memory.\n");
     771                return ENOMEM;
     772        }
    706773
    707774        link_initialize(&term->link);
     
    712779        term->char_remains_len = 0;
    713780
    714         term->widget.width = width;
    715         term->widget.height = height;
    716         term->widget.width_ideal = width;
    717         term->widget.height_ideal = height;
    718 
    719         term->widget.destroy = terminal_destroy;
    720         term->widget.reconfigure = terminal_reconfigure;
    721         term->widget.rearrange = terminal_rearrange;
    722         term->widget.repaint = terminal_repaint;
    723         term->widget.handle_keyboard_event = terminal_handle_keyboard_event;
    724         term->widget.handle_position_event = terminal_handle_position_event;
     781        term->w = width;
     782        term->h = height;
    725783
    726784        term->cols = width / FONT_WIDTH;
     
    733791            CHARGRID_FLAG_NONE);
    734792        if (!term->frontbuf) {
    735                 widget_deinit(&term->widget);
    736                 return false;
     793                printf("Error creating front buffer.\n");
     794                rc = ENOMEM;
     795                goto error;
    737796        }
    738797
     
    740799            CHARGRID_FLAG_NONE);
    741800        if (!term->backbuf) {
    742                 widget_deinit(&term->widget);
    743                 return false;
     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;
    744853        }
    745854
     
    753862        term->srvs.sarg = term;
    754863
    755         errno_t rc = loc_server_register(NAME);
     864        rc = loc_server_register(NAME);
    756865        if (rc != EOK) {
    757                 widget_deinit(&term->widget);
    758                 return false;
     866                printf("Error registering server.\n");
     867                rc = EIO;
     868                goto error;
    759869        }
    760870
     
    765875        rc = loc_service_register(vc, &term->dsid);
    766876        if (rc != EOK) {
    767                 widget_deinit(&term->widget);
    768                 return false;
     877                printf("Error registering service.\n");
     878                rc = EIO;
     879                goto error;
    769880        }
    770881
     
    772883        getterm(vc, "/app/bdsh");
    773884
    774         return true;
    775 }
    776 
    777 terminal_t *create_terminal(widget_t *parent, const void *data, sysarg_t width,
    778     sysarg_t height)
    779 {
    780         terminal_t *term = (terminal_t *) malloc(sizeof(terminal_t));
    781         if (!term)
    782                 return NULL;
    783 
    784         bool ret = init_terminal(term, parent, data, width, height);
    785         if (!ret) {
    786                 free(term);
    787                 return NULL;
    788         }
    789 
    790         return term;
     885        term->is_focused = true;
     886
     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);
     893
     894        *rterm = term;
     895        return EOK;
     896error:
     897        if (term->window != NULL)
     898                ui_window_destroy(term->window);
     899        if (term->ui != NULL)
     900                ui_destroy(term->ui);
     901        if (term->frontbuf != NULL)
     902                chargrid_destroy(term->frontbuf);
     903        if (term->backbuf != NULL)
     904                chargrid_destroy(term->backbuf);
     905        free(term);
     906        return rc;
    791907}
    792908
Note: See TracChangeset for help on using the changeset viewer.