source: mainline/uspace/lib/gui/terminal.c@ be1be2c7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since be1be2c7 was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

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