source: mainline/uspace/app/terminal/terminal.c@ 26653c9

lfn serial ticket/834-toolchain-update topic/fix-logger-deadlock topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 26653c9 was 26653c9, checked in by Jiri Svoboda <jiri@…>, 6 years ago

Move fixed width font to its own library, libfbfont

We've actually three copies, one in kernel/, one in output server
(not used anymorei, removed), one in libdraw (now moved to separate library
libfbfont). So we are left with two copies, that could be coalesced
somehow in the future.

  • Property mode set to 100644
File size: 20.5 KB
Line 
1/*
2 * Copyright (c) 2019 Jiri Svoboda
3 * Copyright (c) 2012 Petr Koupy
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup terminal
31 * @{
32 */
33/**
34 * @file Terminal application using display service for output
35 */
36
37#include <adt/list.h>
38#include <adt/prodcons.h>
39#include <errno.h>
40#include <fbfont/font-8x16.h>
41#include <io/chargrid.h>
42#include <gfx/bitmap.h>
43#include <gfx/context.h>
44#include <io/con_srv.h>
45#include <io/concaps.h>
46#include <io/console.h>
47#include <io/pixelmap.h>
48#include <task.h>
49#include <stdarg.h>
50#include <stdlib.h>
51#include <str.h>
52
53#include "terminal.h"
54
55#define NAME "terminal"
56#define NAMESPACE "terminal"
57
58#define LOCFS_MOUNT_POINT "/loc"
59
60#define APP_GETTERM "/app/getterm"
61
62#define TERM_CAPS \
63 (CONSOLE_CAP_STYLE | CONSOLE_CAP_INDEXED | CONSOLE_CAP_RGB)
64
65static LIST_INITIALIZE(terms);
66
67static errno_t term_open(con_srvs_t *, con_srv_t *);
68static errno_t term_close(con_srv_t *);
69static errno_t term_read(con_srv_t *, void *, size_t, size_t *);
70static errno_t term_write(con_srv_t *, void *, size_t, size_t *);
71static void term_sync(con_srv_t *);
72static void term_clear(con_srv_t *);
73static void term_set_pos(con_srv_t *, sysarg_t col, sysarg_t row);
74static errno_t term_get_pos(con_srv_t *, sysarg_t *, sysarg_t *);
75static errno_t term_get_size(con_srv_t *, sysarg_t *, sysarg_t *);
76static errno_t term_get_color_cap(con_srv_t *, console_caps_t *);
77static void term_set_style(con_srv_t *, console_style_t);
78static void term_set_color(con_srv_t *, console_color_t, console_color_t,
79 console_color_attr_t);
80static void term_set_rgb_color(con_srv_t *, pixel_t, pixel_t);
81static void term_set_cursor_visibility(con_srv_t *, bool);
82static errno_t term_get_event(con_srv_t *, cons_event_t *);
83
84static con_ops_t con_ops = {
85 .open = term_open,
86 .close = term_close,
87 .read = term_read,
88 .write = term_write,
89 .sync = term_sync,
90 .clear = term_clear,
91 .set_pos = term_set_pos,
92 .get_pos = term_get_pos,
93 .get_size = term_get_size,
94 .get_color_cap = term_get_color_cap,
95 .set_style = term_set_style,
96 .set_color = term_set_color,
97 .set_rgb_color = term_set_rgb_color,
98 .set_cursor_visibility = term_set_cursor_visibility,
99 .get_event = term_get_event
100};
101
102static void terminal_kbd_event(void *, kbd_event_t *);
103
104static display_wnd_cb_t terminal_wnd_cb = {
105 .kbd_event = terminal_kbd_event
106};
107
108static terminal_t *srv_to_terminal(con_srv_t *srv)
109{
110 return srv->srvs->sarg;
111}
112
113static void getterm(const char *svc, const char *app)
114{
115 task_spawnl(NULL, NULL, APP_GETTERM, APP_GETTERM, svc,
116 LOCFS_MOUNT_POINT, "--msg", "--wait", "--", app, NULL);
117}
118
119static pixel_t color_table[16] = {
120 [COLOR_BLACK] = PIXEL(255, 0, 0, 0),
121 [COLOR_BLUE] = PIXEL(255, 0, 0, 240),
122 [COLOR_GREEN] = PIXEL(255, 0, 240, 0),
123 [COLOR_CYAN] = PIXEL(255, 0, 240, 240),
124 [COLOR_RED] = PIXEL(255, 240, 0, 0),
125 [COLOR_MAGENTA] = PIXEL(255, 240, 0, 240),
126 [COLOR_YELLOW] = PIXEL(255, 240, 240, 0),
127 [COLOR_WHITE] = PIXEL(255, 240, 240, 240),
128
129 [COLOR_BLACK + 8] = PIXEL(255, 0, 0, 0),
130 [COLOR_BLUE + 8] = PIXEL(255, 0, 0, 255),
131 [COLOR_GREEN + 8] = PIXEL(255, 0, 255, 0),
132 [COLOR_CYAN + 8] = PIXEL(255, 0, 255, 255),
133 [COLOR_RED + 8] = PIXEL(255, 255, 0, 0),
134 [COLOR_MAGENTA + 8] = PIXEL(255, 255, 0, 255),
135 [COLOR_YELLOW + 8] = PIXEL(255, 255, 255, 0),
136 [COLOR_WHITE + 8] = PIXEL(255, 255, 255, 255),
137};
138
139static inline void attrs_rgb(char_attrs_t attrs, pixel_t *bgcolor, pixel_t *fgcolor)
140{
141 switch (attrs.type) {
142 case CHAR_ATTR_STYLE:
143 switch (attrs.val.style) {
144 case STYLE_NORMAL:
145 *bgcolor = color_table[COLOR_WHITE];
146 *fgcolor = color_table[COLOR_BLACK];
147 break;
148 case STYLE_EMPHASIS:
149 *bgcolor = color_table[COLOR_WHITE];
150 *fgcolor = color_table[COLOR_RED];
151 break;
152 case STYLE_INVERTED:
153 *bgcolor = color_table[COLOR_BLACK];
154 *fgcolor = color_table[COLOR_WHITE];
155 break;
156 case STYLE_SELECTED:
157 *bgcolor = color_table[COLOR_RED];
158 *fgcolor = color_table[COLOR_WHITE];
159 break;
160 }
161 break;
162 case CHAR_ATTR_INDEX:
163 *bgcolor = color_table[(attrs.val.index.bgcolor & 7) |
164 ((attrs.val.index.attr & CATTR_BRIGHT) ? 8 : 0)];
165 *fgcolor = color_table[(attrs.val.index.fgcolor & 7) |
166 ((attrs.val.index.attr & CATTR_BRIGHT) ? 8 : 0)];
167 break;
168 case CHAR_ATTR_RGB:
169 *bgcolor = 0xff000000 | attrs.val.rgb.bgcolor;
170 *fgcolor = 0xff000000 | attrs.val.rgb.fgcolor;
171 break;
172 }
173}
174
175static void term_update_region(terminal_t *term, sysarg_t x, sysarg_t y,
176 sysarg_t w, sysarg_t h)
177{
178 gfx_rect_t rect;
179 gfx_rect_t nupdate;
180
181 rect.p0.x = x;
182 rect.p0.y = y;
183 rect.p1.x = x + w;
184 rect.p1.y = y + h;
185
186 gfx_rect_envelope(&term->update, &rect, &nupdate);
187 term->update = nupdate;
188}
189
190static void term_update_char(terminal_t *term, pixelmap_t *pixelmap,
191 sysarg_t sx, sysarg_t sy, sysarg_t col, sysarg_t row)
192{
193 charfield_t *field =
194 chargrid_charfield_at(term->backbuf, col, row);
195
196 bool inverted = chargrid_cursor_at(term->backbuf, col, row);
197
198 sysarg_t bx = sx + (col * FONT_WIDTH);
199 sysarg_t by = sy + (row * FONT_SCANLINES);
200
201 pixel_t bgcolor = 0;
202 pixel_t fgcolor = 0;
203
204 if (inverted)
205 attrs_rgb(field->attrs, &fgcolor, &bgcolor);
206 else
207 attrs_rgb(field->attrs, &bgcolor, &fgcolor);
208
209 // FIXME: Glyph type should be actually uint32_t
210 // for full UTF-32 coverage.
211
212 uint16_t glyph = fb_font_glyph(field->ch, NULL);
213
214 for (unsigned int y = 0; y < FONT_SCANLINES; y++) {
215 pixel_t *dst = pixelmap_pixel_at(pixelmap, bx, by + y);
216 pixel_t *dst_max = pixelmap_pixel_at(pixelmap, bx + FONT_WIDTH - 1, by + y);
217 if (!dst || !dst_max)
218 continue;
219 int count = FONT_WIDTH;
220 while (count-- != 0) {
221 *dst++ = (fb_font[glyph][y] & (1 << count)) ? fgcolor : bgcolor;
222 }
223 }
224 term_update_region(term, bx, by, FONT_WIDTH, FONT_SCANLINES);
225}
226
227static bool term_update_scroll(terminal_t *term, pixelmap_t *pixelmap,
228 sysarg_t sx, sysarg_t sy)
229{
230 sysarg_t top_row = chargrid_get_top_row(term->frontbuf);
231
232 if (term->top_row == top_row) {
233 return false;
234 }
235
236 term->top_row = top_row;
237
238 for (sysarg_t row = 0; row < term->rows; row++) {
239 for (sysarg_t col = 0; col < term->cols; col++) {
240 charfield_t *front_field =
241 chargrid_charfield_at(term->frontbuf, col, row);
242 charfield_t *back_field =
243 chargrid_charfield_at(term->backbuf, col, row);
244 bool update = false;
245
246 if (front_field->ch != back_field->ch) {
247 back_field->ch = front_field->ch;
248 update = true;
249 }
250
251 if (!attrs_same(front_field->attrs, back_field->attrs)) {
252 back_field->attrs = front_field->attrs;
253 update = true;
254 }
255
256 front_field->flags &= ~CHAR_FLAG_DIRTY;
257
258 if (update) {
259 term_update_char(term, pixelmap, sx, sy, col, row);
260 }
261 }
262 }
263
264 return true;
265}
266
267static bool term_update_cursor(terminal_t *term, pixelmap_t *pixelmap,
268 sysarg_t sx, sysarg_t sy)
269{
270 bool update = false;
271
272 sysarg_t front_col;
273 sysarg_t front_row;
274 chargrid_get_cursor(term->frontbuf, &front_col, &front_row);
275
276 sysarg_t back_col;
277 sysarg_t back_row;
278 chargrid_get_cursor(term->backbuf, &back_col, &back_row);
279
280 bool front_visibility =
281 chargrid_get_cursor_visibility(term->frontbuf) &&
282 /*term->widget.window->is_focused*/true;
283 bool back_visibility =
284 chargrid_get_cursor_visibility(term->backbuf);
285
286 if (front_visibility != back_visibility) {
287 chargrid_set_cursor_visibility(term->backbuf,
288 front_visibility);
289 term_update_char(term, pixelmap, sx, sy, back_col, back_row);
290 update = true;
291 }
292
293 if ((front_col != back_col) || (front_row != back_row)) {
294 chargrid_set_cursor(term->backbuf, front_col, front_row);
295 term_update_char(term, pixelmap, sx, sy, back_col, back_row);
296 term_update_char(term, pixelmap, sx, sy, front_col, front_row);
297 update = true;
298 }
299
300 return update;
301}
302
303static void term_update(terminal_t *term)
304{
305 pixelmap_t pixelmap;
306 gfx_bitmap_alloc_t alloc;
307 errno_t rc;
308
309 rc = gfx_bitmap_get_alloc(term->bmp, &alloc);
310 if (rc != EOK) {
311 return;
312 }
313
314 fibril_mutex_lock(&term->mtx);
315 pixelmap.width = term->w;
316 pixelmap.height = term->h;
317 pixelmap.data = alloc.pixels;
318
319 bool update = false;
320 sysarg_t sx = 0/*term->widget.hpos*/;
321 sysarg_t sy = 0/*term->widget.vpos*/;
322
323 if (term_update_scroll(term, &pixelmap, sx, sy)) {
324 update = true;
325 } else {
326 for (sysarg_t y = 0; y < term->rows; y++) {
327 for (sysarg_t x = 0; x < term->cols; x++) {
328 charfield_t *front_field =
329 chargrid_charfield_at(term->frontbuf, x, y);
330 charfield_t *back_field =
331 chargrid_charfield_at(term->backbuf, x, y);
332 bool update = false;
333
334 if ((front_field->flags & CHAR_FLAG_DIRTY) ==
335 CHAR_FLAG_DIRTY) {
336 if (front_field->ch != back_field->ch) {
337 back_field->ch = front_field->ch;
338 update = true;
339 }
340
341 if (!attrs_same(front_field->attrs,
342 back_field->attrs)) {
343 back_field->attrs = front_field->attrs;
344 update = true;
345 }
346
347 front_field->flags &= ~CHAR_FLAG_DIRTY;
348 }
349
350 if (update) {
351 term_update_char(term, &pixelmap, sx, sy, x, y);
352 update = true;
353 }
354 }
355 }
356 }
357
358 if (term_update_cursor(term, &pixelmap, sx, sy))
359 update = true;
360
361 if (update) {
362 (void) gfx_bitmap_render(term->bmp, &term->update, NULL);
363
364 term->update.p0.x = 0;
365 term->update.p0.y = 0;
366 term->update.p1.x = 0;
367 term->update.p1.y = 0;
368 }
369
370 fibril_mutex_unlock(&term->mtx);
371}
372
373static void term_repaint(terminal_t *term)
374{
375 pixelmap_t pixelmap;
376 gfx_bitmap_alloc_t alloc;
377 errno_t rc;
378
379 rc = gfx_bitmap_get_alloc(term->bmp, &alloc);
380 if (rc != EOK) {
381 printf("Error getting bitmap allocation info.\n");
382 return;
383 }
384
385 fibril_mutex_lock(&term->mtx);
386
387 pixelmap.width = term->w;
388 pixelmap.height = term->h;
389 pixelmap.data = alloc.pixels;
390
391 sysarg_t sx = 0;
392 sysarg_t sy = 0;
393
394 if (!term_update_scroll(term, &pixelmap, sx, sy)) {
395 for (sysarg_t y = 0; y < term->rows; y++) {
396 for (sysarg_t x = 0; x < term->cols; x++) {
397 charfield_t *front_field =
398 chargrid_charfield_at(term->frontbuf, x, y);
399 charfield_t *back_field =
400 chargrid_charfield_at(term->backbuf, x, y);
401
402 back_field->ch = front_field->ch;
403 back_field->attrs = front_field->attrs;
404 front_field->flags &= ~CHAR_FLAG_DIRTY;
405
406 term_update_char(term, &pixelmap, sx, sy, x, y);
407 }
408 }
409 }
410
411 term_update_cursor(term, &pixelmap, sx, sy);
412
413 fibril_mutex_unlock(&term->mtx);
414}
415
416static errno_t term_open(con_srvs_t *srvs, con_srv_t *srv)
417{
418 return EOK;
419}
420
421static errno_t term_close(con_srv_t *srv)
422{
423 return EOK;
424}
425
426static errno_t term_read(con_srv_t *srv, void *buf, size_t size, size_t *nread)
427{
428 terminal_t *term = srv_to_terminal(srv);
429 uint8_t *bbuf = buf;
430 size_t pos = 0;
431
432 /*
433 * Read input from keyboard and copy it to the buffer.
434 * We need to handle situation when wchar is split by 2 following
435 * reads.
436 */
437 while (pos < size) {
438 /* Copy to the buffer remaining characters. */
439 while ((pos < size) && (term->char_remains_len > 0)) {
440 bbuf[pos] = term->char_remains[0];
441 pos++;
442
443 /* Unshift the array. */
444 for (size_t i = 1; i < term->char_remains_len; i++)
445 term->char_remains[i - 1] = term->char_remains[i];
446
447 term->char_remains_len--;
448 }
449
450 /* Still not enough? Then get another key from the queue. */
451 if (pos < size) {
452 link_t *link = prodcons_consume(&term->input_pc);
453 cons_event_t *event = list_get_instance(link, cons_event_t, link);
454
455 /* Accept key presses of printable chars only. */
456 if (event->type == CEV_KEY && event->ev.key.type == KEY_PRESS &&
457 event->ev.key.c != 0) {
458 char32_t tmp[2] = {
459 event->ev.key.c,
460 0
461 };
462
463 wstr_to_str(term->char_remains, UTF8_CHAR_BUFFER_SIZE, tmp);
464 term->char_remains_len = str_size(term->char_remains);
465 }
466
467 free(event);
468 }
469 }
470
471 *nread = size;
472 return EOK;
473}
474
475static void term_write_char(terminal_t *term, wchar_t ch)
476{
477 sysarg_t updated = 0;
478
479 fibril_mutex_lock(&term->mtx);
480
481 switch (ch) {
482 case '\n':
483 updated = chargrid_newline(term->frontbuf);
484 break;
485 case '\r':
486 break;
487 case '\t':
488 updated = chargrid_tabstop(term->frontbuf, 8);
489 break;
490 case '\b':
491 updated = chargrid_backspace(term->frontbuf);
492 break;
493 default:
494 updated = chargrid_putuchar(term->frontbuf, ch, true);
495 }
496
497 fibril_mutex_unlock(&term->mtx);
498
499 if (updated > 1)
500 term_update(term);
501}
502
503static errno_t term_write(con_srv_t *srv, void *data, size_t size, size_t *nwritten)
504{
505 terminal_t *term = srv_to_terminal(srv);
506
507 size_t off = 0;
508 while (off < size)
509 term_write_char(term, str_decode(data, &off, size));
510
511 *nwritten = size;
512 return EOK;
513}
514
515static void term_sync(con_srv_t *srv)
516{
517 terminal_t *term = srv_to_terminal(srv);
518
519 term_update(term);
520}
521
522static void term_clear(con_srv_t *srv)
523{
524 terminal_t *term = srv_to_terminal(srv);
525
526 fibril_mutex_lock(&term->mtx);
527 chargrid_clear(term->frontbuf);
528 fibril_mutex_unlock(&term->mtx);
529
530 term_update(term);
531}
532
533static void term_set_pos(con_srv_t *srv, sysarg_t col, sysarg_t row)
534{
535 terminal_t *term = srv_to_terminal(srv);
536
537 fibril_mutex_lock(&term->mtx);
538 chargrid_set_cursor(term->frontbuf, col, row);
539 fibril_mutex_unlock(&term->mtx);
540
541 term_update(term);
542}
543
544static errno_t term_get_pos(con_srv_t *srv, sysarg_t *col, sysarg_t *row)
545{
546 terminal_t *term = srv_to_terminal(srv);
547
548 fibril_mutex_lock(&term->mtx);
549 chargrid_get_cursor(term->frontbuf, col, row);
550 fibril_mutex_unlock(&term->mtx);
551
552 return EOK;
553}
554
555static errno_t term_get_size(con_srv_t *srv, sysarg_t *cols, sysarg_t *rows)
556{
557 terminal_t *term = srv_to_terminal(srv);
558
559 fibril_mutex_lock(&term->mtx);
560 *cols = term->cols;
561 *rows = term->rows;
562 fibril_mutex_unlock(&term->mtx);
563
564 return EOK;
565}
566
567static errno_t term_get_color_cap(con_srv_t *srv, console_caps_t *caps)
568{
569 (void) srv;
570 *caps = TERM_CAPS;
571
572 return EOK;
573}
574
575static void term_set_style(con_srv_t *srv, console_style_t style)
576{
577 terminal_t *term = srv_to_terminal(srv);
578
579 fibril_mutex_lock(&term->mtx);
580 chargrid_set_style(term->frontbuf, style);
581 fibril_mutex_unlock(&term->mtx);
582}
583
584static void term_set_color(con_srv_t *srv, console_color_t bgcolor,
585 console_color_t fgcolor, console_color_attr_t attr)
586{
587 terminal_t *term = srv_to_terminal(srv);
588
589 fibril_mutex_lock(&term->mtx);
590 chargrid_set_color(term->frontbuf, bgcolor, fgcolor, attr);
591 fibril_mutex_unlock(&term->mtx);
592}
593
594static void term_set_rgb_color(con_srv_t *srv, pixel_t bgcolor,
595 pixel_t fgcolor)
596{
597 terminal_t *term = srv_to_terminal(srv);
598
599 fibril_mutex_lock(&term->mtx);
600 chargrid_set_rgb_color(term->frontbuf, bgcolor, fgcolor);
601 fibril_mutex_unlock(&term->mtx);
602}
603
604static void term_set_cursor_visibility(con_srv_t *srv, bool visible)
605{
606 terminal_t *term = srv_to_terminal(srv);
607
608 fibril_mutex_lock(&term->mtx);
609 chargrid_set_cursor_visibility(term->frontbuf, visible);
610 fibril_mutex_unlock(&term->mtx);
611
612 term_update(term);
613}
614
615static errno_t term_get_event(con_srv_t *srv, cons_event_t *event)
616{
617 terminal_t *term = srv_to_terminal(srv);
618 link_t *link = prodcons_consume(&term->input_pc);
619 cons_event_t *ev = list_get_instance(link, cons_event_t, link);
620
621 *event = *ev;
622 free(ev);
623 return EOK;
624}
625
626static void deinit_terminal(terminal_t *term)
627{
628 list_remove(&term->link);
629
630 if (term->frontbuf)
631 chargrid_destroy(term->frontbuf);
632
633 if (term->backbuf)
634 chargrid_destroy(term->backbuf);
635}
636
637void terminal_destroy(terminal_t *term)
638{
639 deinit_terminal(term);
640 free(term);
641}
642
643static void terminal_queue_cons_event(terminal_t *term, cons_event_t *ev)
644{
645 /* Got key press/release event */
646 cons_event_t *event =
647 (cons_event_t *) malloc(sizeof(cons_event_t));
648 if (event == NULL)
649 return;
650
651 *event = *ev;
652 link_initialize(&event->link);
653
654 prodcons_produce(&term->input_pc, &event->link);
655}
656
657/* Got key press/release event */
658static void terminal_kbd_event(void *arg, kbd_event_t *kbd_event)
659{
660 terminal_t *term = (terminal_t *) arg;
661 cons_event_t event;
662
663 event.type = CEV_KEY;
664 event.ev.key = *kbd_event;
665
666 terminal_queue_cons_event(term, &event);
667}
668
669#if 0
670static void terminal_handle_position_event(widget_t *widget, pos_event_t pos_event)
671{
672 cons_event_t event;
673 terminal_t *term = (terminal_t *) widget;
674 sysarg_t sx = term->widget.hpos;
675 sysarg_t sy = term->widget.vpos;
676
677 if (pos_event.type == POS_PRESS) {
678 event.type = CEV_POS;
679 event.ev.pos.type = pos_event.type;
680 event.ev.pos.pos_id = pos_event.pos_id;
681 event.ev.pos.btn_num = pos_event.btn_num;
682
683 event.ev.pos.hpos = (pos_event.hpos - sx) / FONT_WIDTH;
684 event.ev.pos.vpos = (pos_event.vpos - sy) / FONT_SCANLINES;
685 terminal_queue_cons_event(term, &event);
686 }
687}
688#endif
689
690static void term_connection(ipc_call_t *icall, void *arg)
691{
692 terminal_t *term = NULL;
693
694 list_foreach(terms, link, terminal_t, cur) {
695 if (cur->dsid == (service_id_t) ipc_get_arg2(icall)) {
696 term = cur;
697 break;
698 }
699 }
700
701 if (term == NULL) {
702 async_answer_0(icall, ENOENT);
703 return;
704 }
705
706 if (!atomic_flag_test_and_set(&term->refcnt))
707 chargrid_set_cursor_visibility(term->frontbuf, true);
708
709 con_conn(icall, &term->srvs);
710}
711
712errno_t terminal_create(display_t *display, sysarg_t width, sysarg_t height,
713 terminal_t **rterm)
714{
715 terminal_t *term;
716 gfx_bitmap_params_t params;
717 display_wnd_params_t wparams;
718 errno_t rc;
719
720 term = calloc(1, sizeof(terminal_t));
721 if (term == NULL) {
722 printf("Out of memory.\n");
723 return ENOMEM;
724 }
725
726 link_initialize(&term->link);
727 fibril_mutex_initialize(&term->mtx);
728 atomic_flag_clear(&term->refcnt);
729
730 prodcons_initialize(&term->input_pc);
731 term->char_remains_len = 0;
732
733 term->w = width;
734 term->h = height;
735
736 term->cols = width / FONT_WIDTH;
737 term->rows = height / FONT_SCANLINES;
738
739 term->frontbuf = NULL;
740 term->backbuf = NULL;
741
742 term->frontbuf = chargrid_create(term->cols, term->rows,
743 CHARGRID_FLAG_NONE);
744 if (!term->frontbuf) {
745 printf("Error creating front buffer.\n");
746 rc = ENOMEM;
747 goto error;
748 }
749
750 term->backbuf = chargrid_create(term->cols, term->rows,
751 CHARGRID_FLAG_NONE);
752 if (!term->backbuf) {
753 printf("Error creating back buffer.\n");
754 rc = ENOMEM;
755 goto error;
756 }
757
758 display_wnd_params_init(&wparams);
759 wparams.rect.p0.x = 0;
760 wparams.rect.p0.y = 0;
761 wparams.rect.p1.x = width;
762 wparams.rect.p1.y = height;
763
764 rc = display_window_create(display, &wparams, &terminal_wnd_cb,
765 (void *) term, &term->window);
766 if (rc != EOK) {
767 printf("Error creating window.\n");
768 goto error;
769 }
770
771 rc = display_window_get_gc(term->window, &term->gc);
772 if (rc != EOK) {
773 printf("Error getting window GC.\n");
774 goto error;
775 }
776
777 gfx_bitmap_params_init(&params);
778 params.rect.p0.x = 0;
779 params.rect.p0.y = 0;
780 params.rect.p1.x = width;
781 params.rect.p1.y = height;
782
783 rc = gfx_bitmap_create(term->gc, &params, NULL, &term->bmp);
784 if (rc != EOK) {
785 printf("Error allocating screen bitmap.\n");
786 goto error;
787 }
788
789 chargrid_clear(term->frontbuf);
790 chargrid_clear(term->backbuf);
791 term->top_row = 0;
792
793 async_set_fallback_port_handler(term_connection, NULL);
794 con_srvs_init(&term->srvs);
795 term->srvs.ops = &con_ops;
796 term->srvs.sarg = term;
797
798 rc = loc_server_register(NAME);
799 if (rc != EOK) {
800 printf("Error registering server.\n");
801 rc = EIO;
802 goto error;
803 }
804
805 char vc[LOC_NAME_MAXLEN + 1];
806 snprintf(vc, LOC_NAME_MAXLEN, "%s/%" PRIu64, NAMESPACE,
807 task_get_id());
808
809 rc = loc_service_register(vc, &term->dsid);
810 if (rc != EOK) {
811 printf("Error registering service.\n");
812 rc = EIO;
813 goto error;
814 }
815
816 list_append(&term->link, &terms);
817 getterm(vc, "/app/bdsh");
818
819 term_repaint(term);
820
821 term->update.p0.x = 0;
822 term->update.p0.y = 0;
823 term->update.p1.x = 0;
824 term->update.p1.y = 0;
825
826 *rterm = term;
827 return EOK;
828error:
829 if (term->gc != NULL)
830 gfx_context_delete(term->gc);
831 if (term->window != NULL)
832 display_window_destroy(term->window);
833 if (term->frontbuf != NULL)
834 chargrid_destroy(term->frontbuf);
835 if (term->backbuf != NULL)
836 chargrid_destroy(term->backbuf);
837 free(term);
838 return rc;
839}
840
841/** @}
842 */
Note: See TracBrowser for help on using the repository browser.