source: mainline/uspace/lib/gui/terminal.c@ 16e9d4df

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 16e9d4df was 6d5e378, checked in by Martin Decky <martin@…>, 13 years ago

cherrypick GUI implementation (originally by Petr Koupy), with several major changes

  • for character-oriented devices a new output server and output protocol was created based on the original fb server
  • DDF visualizer drivers are pixel-oriented only
  • console and compositor can coexist in the same build
  • terminal widget is self-sufficient, no strange console nesting is needed
  • Property mode set to 100644
File size: 19.0 KB
Line 
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>
37#include <malloc.h>
38#include <io/chargrid.h>
39#include <surface.h>
40#include <gfx/font-8x16.h>
41#include <io/console.h>
42#include <ipc/console.h>
43#include <task.h>
44#include <adt/list.h>
45#include <adt/prodcons.h>
46#include <atomic.h>
47#include <stdarg.h>
48#include "window.h"
49#include "terminal.h"
50
51#define NAME "vterm"
52#define NAMESPACE "vterm"
53
54#define LOCFS_MOUNT_POINT "/loc"
55
56#define APP_GETTERM "/app/getterm"
57
58#define TERM_CAPS \
59 (CONSOLE_CAP_STYLE | CONSOLE_CAP_INDEXED | CONSOLE_CAP_RGB)
60
61static LIST_INITIALIZE(terms);
62
63static void getterm(const char *svc, const char *app)
64{
65 char term[LOC_NAME_MAXLEN];
66 snprintf(term, LOC_NAME_MAXLEN, "%s/%s", LOCFS_MOUNT_POINT, svc);
67
68 /* Wait for the terminal service to be ready */
69 service_id_t service_id;
70 int rc = loc_service_get_id(svc, &service_id, IPC_FLAG_BLOCKING);
71 if (rc != EOK)
72 return;
73
74 task_spawnl(NULL, APP_GETTERM, APP_GETTERM, "-w", term, app, NULL);
75}
76
77static pixel_t color_table[16] = {
78 [COLOR_BLACK] = PIXEL(255, 0, 0, 0),
79 [COLOR_BLUE] = PIXEL(255, 0, 0, 240),
80 [COLOR_GREEN] = PIXEL(255, 0, 240, 0),
81 [COLOR_CYAN] = PIXEL(255, 0, 240, 240),
82 [COLOR_RED] = PIXEL(255, 240, 0, 0),
83 [COLOR_MAGENTA] = PIXEL(255, 240, 0, 240),
84 [COLOR_YELLOW] = PIXEL(255, 240, 240, 0),
85 [COLOR_WHITE] = PIXEL(255, 240, 240, 240),
86
87 [COLOR_BLACK + 8] = PIXEL(255, 0, 0, 0),
88 [COLOR_BLUE + 8] = PIXEL(255, 0, 0, 255),
89 [COLOR_GREEN + 8] = PIXEL(255, 0, 255, 0),
90 [COLOR_CYAN + 8] = PIXEL(255, 0, 255, 255),
91 [COLOR_RED + 8] = PIXEL(255, 255, 0, 0),
92 [COLOR_MAGENTA + 8] = PIXEL(255, 255, 0, 255),
93 [COLOR_YELLOW + 8] = PIXEL(255, 255, 255, 0),
94 [COLOR_WHITE + 8] = PIXEL(255, 255, 255, 255),
95};
96
97static inline void attrs_rgb(char_attrs_t attrs, pixel_t *bgcolor, pixel_t *fgcolor)
98{
99 switch (attrs.type) {
100 case CHAR_ATTR_STYLE:
101 switch (attrs.val.style) {
102 case STYLE_NORMAL:
103 *bgcolor = color_table[COLOR_WHITE];
104 *fgcolor = color_table[COLOR_BLACK];
105 break;
106 case STYLE_EMPHASIS:
107 *bgcolor = color_table[COLOR_WHITE];
108 *fgcolor = color_table[COLOR_RED];
109 break;
110 case STYLE_INVERTED:
111 *bgcolor = color_table[COLOR_BLACK];
112 *fgcolor = color_table[COLOR_WHITE];
113 break;
114 case STYLE_SELECTED:
115 *bgcolor = color_table[COLOR_RED];
116 *fgcolor = color_table[COLOR_WHITE];
117 break;
118 }
119 break;
120 case CHAR_ATTR_INDEX:
121 *bgcolor = color_table[(attrs.val.index.bgcolor & 7) |
122 ((attrs.val.index.attr & CATTR_BRIGHT) ? 8 : 0)];
123 *fgcolor = color_table[(attrs.val.index.fgcolor & 7) |
124 ((attrs.val.index.attr & CATTR_BRIGHT) ? 8 : 0)];
125 break;
126 case CHAR_ATTR_RGB:
127 *bgcolor = 0xff000000 | attrs.val.rgb.bgcolor;
128 *fgcolor = 0xff000000 | attrs.val.rgb.fgcolor;
129 break;
130 }
131}
132
133static void term_update_char(terminal_t *term, surface_t *surface,
134 sysarg_t sx, sysarg_t sy, sysarg_t col, sysarg_t row)
135{
136 charfield_t *field =
137 chargrid_charfield_at(term->backbuf, col, row);
138
139 bool inverted = chargrid_cursor_at(term->backbuf, col, row);
140
141 sysarg_t bx = sx + (col * FONT_WIDTH);
142 sysarg_t by = sy + (row * FONT_SCANLINES);
143
144 pixel_t bgcolor = 0;
145 pixel_t fgcolor = 0;
146
147 if (inverted)
148 attrs_rgb(field->attrs, &fgcolor, &bgcolor);
149 else
150 attrs_rgb(field->attrs, &bgcolor, &fgcolor);
151
152 // FIXME: Glyph type should be actually uint32_t
153 // for full UTF-32 coverage.
154
155 uint16_t glyph = fb_font_glyph(field->ch);
156
157 // FIXME: This font drawing routine is shamelessly
158 // suboptimal. It should be optimized for
159 // aligned memory transfers, etc.
160
161 for (unsigned int y = 0; y < FONT_SCANLINES; y++) {
162 for (unsigned int x = 0; x < FONT_WIDTH; x++) {
163 pixel_t pixel =
164 (fb_font[glyph][y] & (1 << (7 - x))) ? fgcolor : bgcolor;
165 surface_put_pixel(surface, bx + x, by + y, pixel);
166 }
167 }
168}
169
170static bool term_update_scroll(terminal_t *term, surface_t *surface,
171 sysarg_t sx, sysarg_t sy)
172{
173 sysarg_t top_row = chargrid_get_top_row(term->frontbuf);
174
175 if (term->top_row == top_row)
176 return false;
177
178 term->top_row = top_row;
179
180 for (sysarg_t row = 0; row < term->rows; row++) {
181 for (sysarg_t col = 0; col < term->cols; col++) {
182 charfield_t *front_field =
183 chargrid_charfield_at(term->frontbuf, col, row);
184 charfield_t *back_field =
185 chargrid_charfield_at(term->backbuf, col, row);
186 bool update = false;
187
188 if (front_field->ch != back_field->ch) {
189 back_field->ch = front_field->ch;
190 update = true;
191 }
192
193 if (!attrs_same(front_field->attrs, back_field->attrs)) {
194 back_field->attrs = front_field->attrs;
195 update = true;
196 }
197
198 front_field->flags &= ~CHAR_FLAG_DIRTY;
199
200 if (update)
201 term_update_char(term, surface, sx, sy, col, row);
202 }
203 }
204
205 return true;
206}
207
208static bool term_update_cursor(terminal_t *term, surface_t *surface,
209 sysarg_t sx, sysarg_t sy)
210{
211 bool damage = false;
212
213 sysarg_t front_col;
214 sysarg_t front_row;
215 chargrid_get_cursor(term->frontbuf, &front_col, &front_row);
216
217 sysarg_t back_col;
218 sysarg_t back_row;
219 chargrid_get_cursor(term->backbuf, &back_col, &back_row);
220
221 bool front_visibility =
222 chargrid_get_cursor_visibility(term->frontbuf);
223 bool back_visibility =
224 chargrid_get_cursor_visibility(term->backbuf);
225
226 if (front_visibility != back_visibility) {
227 chargrid_set_cursor_visibility(term->backbuf,
228 front_visibility);
229 term_update_char(term, surface, sx, sy, back_col, back_row);
230 damage = true;
231 }
232
233 if ((front_col != back_col) || (front_row != back_row)) {
234 chargrid_set_cursor(term->backbuf, front_col, front_row);
235 term_update_char(term, surface, sx, sy, back_col, back_row);
236 term_update_char(term, surface, sx, sy, front_col, front_row);
237 damage = true;
238 }
239
240 return damage;
241}
242
243static void term_update(terminal_t *term)
244{
245 fibril_mutex_lock(&term->mtx);
246
247 surface_t *surface = window_claim(term->widget.window);
248 if (!surface) {
249 window_yield(term->widget.window);
250 fibril_mutex_unlock(&term->mtx);
251 return;
252 }
253
254 bool damage = false;
255 sysarg_t sx = term->widget.hpos;
256 sysarg_t sy = term->widget.vpos;
257
258 if (term_update_scroll(term, surface, sx, sy)) {
259 damage = true;
260 } else {
261 for (sysarg_t y = 0; y < term->rows; y++) {
262 for (sysarg_t x = 0; x < term->cols; x++) {
263 charfield_t *front_field =
264 chargrid_charfield_at(term->frontbuf, x, y);
265 charfield_t *back_field =
266 chargrid_charfield_at(term->backbuf, x, y);
267 bool update = false;
268
269 if ((front_field->flags & CHAR_FLAG_DIRTY) ==
270 CHAR_FLAG_DIRTY) {
271 if (front_field->ch != back_field->ch) {
272 back_field->ch = front_field->ch;
273 update = true;
274 }
275
276 if (!attrs_same(front_field->attrs,
277 back_field->attrs)) {
278 back_field->attrs = front_field->attrs;
279 update = true;
280 }
281
282 front_field->flags &= ~CHAR_FLAG_DIRTY;
283 }
284
285 if (update) {
286 term_update_char(term, surface, sx, sy, x, y);
287 damage = true;
288 }
289 }
290 }
291 }
292
293 if (term_update_cursor(term, surface, sx, sy))
294 damage = true;
295
296 window_yield(term->widget.window);
297
298 if (damage)
299 window_damage(term->widget.window);
300
301 fibril_mutex_unlock(&term->mtx);
302}
303
304static void term_damage(terminal_t *term)
305{
306 fibril_mutex_lock(&term->mtx);
307
308 surface_t *surface = window_claim(term->widget.window);
309 if (!surface) {
310 window_yield(term->widget.window);
311 fibril_mutex_unlock(&term->mtx);
312 return;
313 }
314
315 sysarg_t sx = term->widget.hpos;
316 sysarg_t sy = term->widget.vpos;
317
318 if (!term_update_scroll(term, surface, sx, sy)) {
319 for (sysarg_t y = 0; y < term->rows; y++) {
320 for (sysarg_t x = 0; x < term->cols; x++) {
321 charfield_t *front_field =
322 chargrid_charfield_at(term->frontbuf, x, y);
323 charfield_t *back_field =
324 chargrid_charfield_at(term->backbuf, x, y);
325
326 back_field->ch = front_field->ch;
327 back_field->attrs = front_field->attrs;
328 front_field->flags &= ~CHAR_FLAG_DIRTY;
329
330 term_update_char(term, surface, sx, sy, x, y);
331 }
332 }
333 }
334
335 term_update_cursor(term, surface, sx, sy);
336
337 window_yield(term->widget.window);
338 window_damage(term->widget.window);
339
340 fibril_mutex_unlock(&term->mtx);
341}
342
343static void term_set_cursor(terminal_t *term, sysarg_t col, sysarg_t row)
344{
345 fibril_mutex_lock(&term->mtx);
346 chargrid_set_cursor(term->frontbuf, col, row);
347 fibril_mutex_unlock(&term->mtx);
348
349 term_update(term);
350}
351
352static void term_set_cursor_visibility(terminal_t *term, bool visible)
353{
354 fibril_mutex_lock(&term->mtx);
355 chargrid_set_cursor_visibility(term->frontbuf, visible);
356 fibril_mutex_unlock(&term->mtx);
357
358 term_update(term);
359}
360
361static void term_read(terminal_t *term, ipc_callid_t iid, ipc_call_t *icall)
362{
363 ipc_callid_t callid;
364 size_t size;
365 if (!async_data_read_receive(&callid, &size)) {
366 async_answer_0(callid, EINVAL);
367 async_answer_0(iid, EINVAL);
368 return;
369 }
370
371 char *buf = (char *) malloc(size);
372 if (buf == NULL) {
373 async_answer_0(callid, ENOMEM);
374 async_answer_0(iid, ENOMEM);
375 return;
376 }
377
378 size_t pos = 0;
379
380 /*
381 * Read input from keyboard and copy it to the buffer.
382 * We need to handle situation when wchar is split by 2 following
383 * reads.
384 */
385 while (pos < size) {
386 /* Copy to the buffer remaining characters. */
387 while ((pos < size) && (term->char_remains_len > 0)) {
388 buf[pos] = term->char_remains[0];
389 pos++;
390
391 /* Unshift the array. */
392 for (size_t i = 1; i < term->char_remains_len; i++)
393 term->char_remains[i - 1] = term->char_remains[i];
394
395 term->char_remains_len--;
396 }
397
398 /* Still not enough? Then get another key from the queue. */
399 if (pos < size) {
400 link_t *link = prodcons_consume(&term->input_pc);
401 kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
402
403 /* Accept key presses of printable chars only. */
404 if ((event->type == KEY_PRESS) && (event->c != 0)) {
405 wchar_t tmp[2] = {
406 event->c,
407 0
408 };
409
410 wstr_to_str(term->char_remains, UTF8_CHAR_BUFFER_SIZE, tmp);
411 term->char_remains_len = str_size(term->char_remains);
412 }
413
414 free(event);
415 }
416 }
417
418 (void) async_data_read_finalize(callid, buf, size);
419 async_answer_1(iid, EOK, size);
420 free(buf);
421}
422
423static void term_write_char(terminal_t *term, wchar_t ch)
424{
425 sysarg_t updated = 0;
426
427 fibril_mutex_lock(&term->mtx);
428
429 switch (ch) {
430 case '\n':
431 updated = chargrid_newline(term->frontbuf);
432 break;
433 case '\r':
434 break;
435 case '\t':
436 updated = chargrid_tabstop(term->frontbuf, 8);
437 break;
438 case '\b':
439 updated = chargrid_backspace(term->frontbuf);
440 break;
441 default:
442 updated = chargrid_putchar(term->frontbuf, ch, true);
443 }
444
445 fibril_mutex_unlock(&term->mtx);
446
447 if (updated > 1)
448 term_update(term);
449}
450
451static void term_write(terminal_t *term, ipc_callid_t iid, ipc_call_t *icall)
452{
453 void *buf;
454 size_t size;
455 int rc = async_data_write_accept(&buf, false, 0, 0, 0, &size);
456
457 if (rc != EOK) {
458 async_answer_0(iid, rc);
459 return;
460 }
461
462 size_t off = 0;
463 while (off < size)
464 term_write_char(term, str_decode(buf, &off, size));
465
466 async_answer_1(iid, EOK, size);
467 free(buf);
468}
469
470static void term_clear(terminal_t *term)
471{
472 fibril_mutex_lock(&term->mtx);
473 chargrid_clear(term->frontbuf);
474 fibril_mutex_unlock(&term->mtx);
475
476 term_update(term);
477}
478
479static void term_get_cursor(terminal_t *term, ipc_callid_t iid, ipc_call_t *icall)
480{
481 sysarg_t col;
482 sysarg_t row;
483
484 fibril_mutex_lock(&term->mtx);
485 chargrid_get_cursor(term->frontbuf, &col, &row);
486 fibril_mutex_unlock(&term->mtx);
487
488 async_answer_2(iid, EOK, col, row);
489}
490
491static void term_set_style(terminal_t *term, console_style_t style)
492{
493 fibril_mutex_lock(&term->mtx);
494 chargrid_set_style(term->frontbuf, style);
495 fibril_mutex_unlock(&term->mtx);
496}
497
498static void term_set_color(terminal_t *term, console_color_t bgcolor,
499 console_color_t fgcolor, console_color_attr_t attr)
500{
501 fibril_mutex_lock(&term->mtx);
502 chargrid_set_color(term->frontbuf, bgcolor, fgcolor, attr);
503 fibril_mutex_unlock(&term->mtx);
504}
505
506static void term_set_rgb_color(terminal_t *term, pixel_t bgcolor,
507 pixel_t fgcolor)
508{
509 fibril_mutex_lock(&term->mtx);
510 chargrid_set_rgb_color(term->frontbuf, bgcolor, fgcolor);
511 fibril_mutex_unlock(&term->mtx);
512}
513
514static void term_get_event(terminal_t *term, ipc_callid_t iid, ipc_call_t *icall)
515{
516 link_t *link = prodcons_consume(&term->input_pc);
517 kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
518
519 async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c);
520 free(event);
521}
522
523void deinit_terminal(terminal_t *term)
524{
525 list_remove(&term->link);
526 widget_deinit(&term->widget);
527
528 if (term->frontbuf)
529 chargrid_destroy(term->frontbuf);
530
531 if (term->backbuf)
532 chargrid_destroy(term->backbuf);
533}
534
535static void terminal_destroy(widget_t *widget)
536{
537 terminal_t *term = (terminal_t *) widget;
538
539 deinit_terminal(term);
540 free(term);
541}
542
543static void terminal_reconfigure(widget_t *widget)
544{
545 /* No-op */
546}
547
548static void terminal_rearrange(widget_t *widget, sysarg_t hpos, sysarg_t vpos,
549 sysarg_t width, sysarg_t height)
550{
551 terminal_t *term = (terminal_t *) widget;
552
553 widget_modify(widget, hpos, vpos, width, height);
554 widget->width_ideal = width;
555 widget->height_ideal = height;
556
557 term_damage(term);
558}
559
560static void terminal_repaint(widget_t *widget)
561{
562 terminal_t *term = (terminal_t *) widget;
563
564 term_damage(term);
565}
566
567static void terminal_handle_keyboard_event(widget_t *widget,
568 kbd_event_t kbd_event)
569{
570 terminal_t *term = (terminal_t *) widget;
571
572 /* Got key press/release event */
573 kbd_event_t *event =
574 (kbd_event_t *) malloc(sizeof(kbd_event_t));
575 if (event == NULL)
576 return;
577
578 link_initialize(&event->link);
579 event->type = kbd_event.type;
580 event->key = kbd_event.key;
581 event->mods = kbd_event.mods;
582 event->c = kbd_event.c;
583
584 prodcons_produce(&term->input_pc, &event->link);
585}
586
587static void terminal_handle_position_event(widget_t *widget, pos_event_t event)
588{
589 /*
590 * Mouse events are ignored so far.
591 * There is no consumer for it.
592 */
593}
594
595static void term_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
596{
597 terminal_t *term = NULL;
598
599 list_foreach(terms, link) {
600 terminal_t *cur = list_get_instance(link, terminal_t, link);
601
602 if (cur->dsid == (service_id_t) IPC_GET_ARG1(*icall)) {
603 term = cur;
604 break;
605 }
606 }
607
608 if (term == NULL) {
609 async_answer_0(iid, ENOENT);
610 return;
611 }
612
613 if (atomic_postinc(&term->refcnt) == 0)
614 term_set_cursor_visibility(term, true);
615
616 /* Accept the connection */
617 async_answer_0(iid, EOK);
618
619 while (true) {
620 ipc_call_t call;
621 ipc_callid_t callid = async_get_call(&call);
622
623 if (!IPC_GET_IMETHOD(call))
624 return;
625
626 switch (IPC_GET_IMETHOD(call)) {
627 case VFS_OUT_READ:
628 term_read(term, callid, &call);
629 break;
630 case VFS_OUT_WRITE:
631 term_write(term, callid, &call);
632 break;
633 case VFS_OUT_SYNC:
634 term_update(term);
635 async_answer_0(callid, EOK);
636 break;
637 case CONSOLE_CLEAR:
638 term_clear(term);
639 async_answer_0(callid, EOK);
640 break;
641 case CONSOLE_GOTO:
642 term_set_cursor(term, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
643 async_answer_0(callid, EOK);
644 break;
645 case CONSOLE_GET_POS:
646 term_get_cursor(term, callid, &call);
647 break;
648 case CONSOLE_GET_SIZE:
649 async_answer_2(callid, EOK, term->cols, term->rows);
650 break;
651 case CONSOLE_GET_COLOR_CAP:
652 async_answer_1(callid, EOK, TERM_CAPS);
653 break;
654 case CONSOLE_SET_STYLE:
655 term_set_style(term, IPC_GET_ARG1(call));
656 async_answer_0(callid, EOK);
657 break;
658 case CONSOLE_SET_COLOR:
659 term_set_color(term, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
660 IPC_GET_ARG3(call));
661 async_answer_0(callid, EOK);
662 break;
663 case CONSOLE_SET_RGB_COLOR:
664 term_set_rgb_color(term, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
665 async_answer_0(callid, EOK);
666 break;
667 case CONSOLE_CURSOR_VISIBILITY:
668 term_set_cursor_visibility(term, IPC_GET_ARG1(call));
669 async_answer_0(callid, EOK);
670 break;
671 case CONSOLE_GET_EVENT:
672 term_get_event(term, callid, &call);
673 break;
674 default:
675 async_answer_0(callid, EINVAL);
676 }
677 }
678}
679
680bool init_terminal(terminal_t *term, widget_t *parent, sysarg_t width,
681 sysarg_t height)
682{
683 widget_init(&term->widget, parent);
684
685 link_initialize(&term->link);
686 fibril_mutex_initialize(&term->mtx);
687 atomic_set(&term->refcnt, 0);
688
689 prodcons_initialize(&term->input_pc);
690 term->char_remains_len = 0;
691
692 term->widget.width = width;
693 term->widget.height = height;
694 term->widget.width_ideal = width;
695 term->widget.height_ideal = height;
696
697 term->widget.destroy = terminal_destroy;
698 term->widget.reconfigure = terminal_reconfigure;
699 term->widget.rearrange = terminal_rearrange;
700 term->widget.repaint = terminal_repaint;
701 term->widget.handle_keyboard_event = terminal_handle_keyboard_event;
702 term->widget.handle_position_event = terminal_handle_position_event;
703
704 term->cols = width / FONT_WIDTH;
705 term->rows = height / FONT_SCANLINES;
706
707 term->frontbuf = NULL;
708 term->backbuf = NULL;
709
710 term->frontbuf = chargrid_create(term->cols, term->rows,
711 CHARGRID_FLAG_NONE);
712 if (!term->frontbuf) {
713 widget_deinit(&term->widget);
714 return false;
715 }
716
717 term->backbuf = chargrid_create(term->cols, term->rows,
718 CHARGRID_FLAG_NONE);
719 if (!term->backbuf) {
720 widget_deinit(&term->widget);
721 return false;
722 }
723
724 chargrid_clear(term->frontbuf);
725 chargrid_clear(term->backbuf);
726 term->top_row = 0;
727
728 async_set_client_connection(term_connection);
729 int rc = loc_server_register(NAME);
730 if (rc != EOK) {
731 widget_deinit(&term->widget);
732 return false;
733 }
734
735 char vc[LOC_NAME_MAXLEN + 1];
736 snprintf(vc, LOC_NAME_MAXLEN, "%s/%" PRIu64, NAMESPACE,
737 task_get_id());
738
739 rc = loc_service_register(vc, &term->dsid);
740 if (rc != EOK) {
741 widget_deinit(&term->widget);
742 return false;
743 }
744
745 list_append(&term->link, &terms);
746 getterm(vc, "/app/bdsh");
747
748 return true;
749}
750
751terminal_t *create_terminal(widget_t *parent, sysarg_t width, sysarg_t height)
752{
753 terminal_t *term = (terminal_t *) malloc(sizeof(terminal_t));
754 if (!term)
755 return NULL;
756
757 bool ret = init_terminal(term, parent, width, height);
758 if (!ret) {
759 free(term);
760 return NULL;
761 }
762
763 return term;
764}
765
766/** @}
767 */
Note: See TracBrowser for help on using the repository browser.