source: mainline/uspace/app/terminal/terminal.c@ 4d9c807

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

Communicate window dimensions to display server

  • 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 <draw/gfx.h>
40#include <errno.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 wchar_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_putwchar(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 params.rect.p0.x = 0;
778 params.rect.p0.y = 0;
779 params.rect.p1.x = width;
780 params.rect.p1.y = height;
781
782 rc = gfx_bitmap_create(term->gc, &params, NULL, &term->bmp);
783 if (rc != EOK) {
784 printf("Error allocating screen bitmap.\n");
785 goto error;
786 }
787
788 chargrid_clear(term->frontbuf);
789 chargrid_clear(term->backbuf);
790 term->top_row = 0;
791
792 async_set_fallback_port_handler(term_connection, NULL);
793 con_srvs_init(&term->srvs);
794 term->srvs.ops = &con_ops;
795 term->srvs.sarg = term;
796
797 rc = loc_server_register(NAME);
798 if (rc != EOK) {
799 printf("Error registering server.\n");
800 rc = EIO;
801 goto error;
802 }
803
804 char vc[LOC_NAME_MAXLEN + 1];
805 snprintf(vc, LOC_NAME_MAXLEN, "%s/%" PRIu64, NAMESPACE,
806 task_get_id());
807
808 rc = loc_service_register(vc, &term->dsid);
809 if (rc != EOK) {
810 printf("Error registering service.\n");
811 rc = EIO;
812 goto error;
813 }
814
815 list_append(&term->link, &terms);
816 getterm(vc, "/app/bdsh");
817
818 term_repaint(term);
819
820 term->update.p0.x = 0;
821 term->update.p0.y = 0;
822 term->update.p1.x = 0;
823 term->update.p1.y = 0;
824
825 *rterm = term;
826 return EOK;
827error:
828 if (term->gc != NULL)
829 gfx_context_delete(term->gc);
830 if (term->window != NULL)
831 display_window_destroy(term->window);
832 if (term->frontbuf != NULL)
833 chargrid_destroy(term->frontbuf);
834 if (term->backbuf != NULL)
835 chargrid_destroy(term->backbuf);
836 free(term);
837 return rc;
838}
839
840/** @}
841 */
Note: See TracBrowser for help on using the repository browser.