PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
terminal.c
Go to the documentation of this file.
1#include "terminal.h"
2#include "ansi.h"
3
4#include <patchwork/display.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <sys/defs.h>
8#include <sys/fs.h>
9#include <sys/kbd.h>
10#include <sys/proc.h>
11#include <time.h>
12
13static terminal_char_t terminal_char_create(char chr, pixel_t foreground, pixel_t background, uint16_t row,
14 uint16_t col)
15{
16 terminal_char_t termChar;
17 termChar.chr = chr;
18 termChar.foreground = foreground;
19 termChar.background = background;
20 termChar.flags = 0;
21 termChar.physicalRow = row;
22 termChar.col = col;
23 return termChar;
24}
25
27{
28 return &term->screen[(term->firstRow + row) % TERMINAL_ROWS][col];
29}
30
32{
33 return (termChar->physicalRow + TERMINAL_ROWS - term->firstRow) % TERMINAL_ROWS;
34}
35
37{
38 const theme_t* theme = element_get_theme(elem);
39
40 uint16_t row = terminal_char_row(term, termChar);
41 uint16_t col = termChar->col;
42
43 return (point_t){
44 .x = (col * font_width(term->font, "a", 1)) + theme->frameSize + theme->bigPadding,
45 .y = (row * font_height(term->font)) + theme->frameSize + theme->bigPadding,
46 };
47}
48
50{
51 point_t clientPos = terminal_char_pos(term, elem, termChar);
52 return RECT_INIT_DIM(clientPos.x, clientPos.y, font_width(term->font, "a", 1), font_height(term->font));
53}
54
55static void terminal_char_draw(terminal_t* term, element_t* elem, drawable_t* draw, terminal_char_t* termChar)
56{
57 point_t clientPos = terminal_char_pos(term, elem, termChar);
58 rect_t charRect = terminal_char_rect(term, elem, termChar);
59 draw_rect(draw, &charRect, termChar->flags & TERMINAL_INVERSE ? termChar->foreground : termChar->background);
60 draw_string(draw, term->font, &clientPos,
61 termChar->flags & TERMINAL_INVERSE ? termChar->background : termChar->foreground, &termChar->chr, 1);
62
63 if (termChar->flags & TERMINAL_UNDERLINE)
64 {
65 rect_t underlineRect = RECT_INIT_DIM(charRect.left, charRect.bottom - 1, RECT_WIDTH(&charRect), 1);
66 draw_rect(draw, &underlineRect,
67 termChar->flags & TERMINAL_INVERSE ? termChar->background : termChar->foreground);
68 }
69}
70
71static void terminal_cursor_update(terminal_t* term, element_t* elem, drawable_t* draw)
72{
73 term->prevCursor->flags &= ~TERMINAL_INVERSE;
74 terminal_char_draw(term, elem, draw, term->prevCursor);
75 if (term->isCursorVisible)
76 {
77 if (term->cursorBlink)
78 {
80 }
81 terminal_char_draw(term, elem, draw, term->cursor);
82 }
83 term->prevCursor = term->cursor;
84}
85
86static void terminal_clear(terminal_t* term, element_t* elem, drawable_t* draw)
87{
89 const theme_t* theme = element_get_theme(elem);
90
93
94 draw_rect(draw, &rect, term->background);
95
96 term->cursor = &term->screen[0][0];
97 term->prevCursor = &term->screen[0][0];
98}
99
100static void terminal_scroll(terminal_t* term, element_t* elem, drawable_t* draw)
101{
102 const theme_t* theme = element_get_theme(elem);
103
104 term->prevCursor->flags &= ~TERMINAL_INVERSE;
105 terminal_char_draw(term, elem, draw, term->prevCursor);
106
107 for (uint64_t col = 0; col < TERMINAL_COLUMNS; col++)
108 {
109 term->screen[term->firstRow][col] =
110 terminal_char_create(' ', theme->ansi.bright[7], theme->ansi.normal[0], term->firstRow, col);
111 }
112 term->firstRow = (term->firstRow + 1) % TERMINAL_ROWS;
113
114 rect_t contentRect = element_get_content_rect(elem);
115 RECT_SHRINK(&contentRect, theme->frameSize);
116 RECT_SHRINK(&contentRect, theme->bigPadding);
117
118 uint64_t rowHeight = font_height(term->font);
119
120 rect_t destRect = RECT_INIT_DIM(contentRect.left, contentRect.top, RECT_WIDTH(&contentRect),
121 RECT_HEIGHT(&contentRect) - rowHeight);
122 point_t srcPoint = {contentRect.left, contentRect.top + rowHeight};
123
124 draw_transfer(draw, draw, &destRect, &srcPoint);
125
126 rect_t clearRect =
127 RECT_INIT_DIM(contentRect.left, contentRect.bottom - rowHeight, RECT_WIDTH(&contentRect), rowHeight);
128 draw_rect(draw, &clearRect, term->background);
129
130 term->cursor = terminal_get_char(term, TERMINAL_ROWS - 1, 0);
131 term->prevCursor = term->cursor;
132}
133
134static void terminal_put(terminal_t* term, element_t* elem, drawable_t* draw, char chr)
135{
136 rect_t rect = element_get_content_rect(elem);
137
138 uint16_t cursorRow = terminal_char_row(term, term->cursor);
139 switch (chr)
140 {
141 case '\n':
142 if (terminal_char_row(term, term->cursor) == TERMINAL_ROWS - 1)
143 {
144 terminal_scroll(term, elem, draw);
145 }
146 else
147 {
148 term->cursor = terminal_get_char(term, cursorRow + 1, 0);
149 }
150 break;
151 case '\r':
152 term->cursor = terminal_get_char(term, cursorRow, 0);
153 break;
154 case '\b':
155 {
156 if (term->cursor->col == 0)
157 {
158 if (cursorRow == 0)
159 {
160 break;
161 }
162 term->cursor = terminal_get_char(term, cursorRow - 1, TERMINAL_COLUMNS - 1);
163 }
164 else
165 {
166 term->cursor = terminal_get_char(term, cursorRow, term->cursor->col - 1);
167 }
168 terminal_char_t* backspaceChar = term->cursor;
169 backspaceChar->chr = ' ';
170 backspaceChar->foreground = term->foreground;
171 backspaceChar->background = term->background;
172 backspaceChar->flags = term->flags;
173 terminal_char_draw(term, elem, draw, backspaceChar);
174 }
175 break;
176 case '\t':
177 {
178 uint16_t spacesToNextTabStop = 4 - (term->cursor->col % 4);
179 for (uint16_t i = 0; i < spacesToNextTabStop; i++)
180 {
181 terminal_put(term, elem, draw, ' ');
182 }
183 }
184 break;
185 default:
186 {
187 terminal_char_t* currentChar = term->cursor;
188 currentChar->chr = chr;
189 currentChar->foreground = term->foreground;
190 currentChar->background = term->background;
191 currentChar->flags = term->flags;
192 terminal_char_draw(term, elem, draw, currentChar);
193
194 uint16_t cursorRow = terminal_char_row(term, term->cursor);
195 if (term->cursor->col == TERMINAL_COLUMNS - 1)
196 {
197 if (cursorRow == TERMINAL_ROWS - 1)
198 {
199 terminal_scroll(term, elem, draw);
200 }
201 else
202 {
203 term->cursor = terminal_get_char(term, cursorRow + 1, 0);
204 }
205 }
206 else
207 {
208 term->cursor = terminal_get_char(term, cursorRow, term->cursor->col + 1);
209 }
210 }
211 break;
212 }
213}
214
215static void terminal_handle_input(terminal_t* term, element_t* elem, drawable_t* draw, const event_kbd_t* kbd)
216{
217 UNUSED(elem);
218 UNUSED(draw);
219
222
223 if (ansi.length > 0)
224 {
226 }
227
228 if (ansi.length == 1 && ansi.buffer[0] == '\003')
229 {
230 writefiles(F("/proc/%llu/notegroup", term->shell), "interrupt due to ctrl+c");
231 }
232}
233
235{
236 if (ansi->ascii)
237 {
238 terminal_put(term, elem, draw, ansi->command);
239 return;
240 }
241
242 if (ansi->extended)
243 {
244 switch (ansi->command)
245 {
246 case 'h': // Set Mode
247 if (ansi->parameters[0] == 25)
248 {
249 term->isCursorVisible = true;
250 terminal_cursor_update(term, elem, draw);
251 }
252 break;
253 case 'l': // Reset Mode
254 if (ansi->parameters[0] == 25)
255 {
256 term->isCursorVisible = false;
257 terminal_cursor_update(term, elem, draw);
258 }
259 break;
260 default:
261 goto not_handled;
262 }
263
264 return;
265 }
266
267 switch (ansi->command)
268 {
269 case 'H': // Cursor to (0, 0) or specified position
270 if (ansi->paramCount >= 2)
271 {
272 uint16_t row = ansi->parameters[0] == 0 ? 0 : ansi->parameters[0] - 1;
273 uint16_t col = ansi->parameters[1] == 0 ? 0 : ansi->parameters[1] - 1;
274 row = MIN(row, TERMINAL_ROWS - 1);
275 col = MIN(col, TERMINAL_COLUMNS - 1);
276 term->cursor = terminal_get_char(term, row, col);
277 break;
278 }
279 term->cursor = terminal_get_char(term, 0, 0);
280 break;
281 case 'A': // Cursor Up
282 {
283 uint16_t cursorRow = terminal_char_row(term, term->cursor);
284 uint16_t moveBy = ansi->parameters[0] == 0 ? 1 : ansi->parameters[0];
285 uint16_t startPos = cursorRow < moveBy ? 0 : cursorRow - moveBy;
286 term->cursor = terminal_get_char(term, startPos, term->cursor->col);
287 }
288 break;
289 case 'B': // Cursor Down
290 {
291 uint16_t cursorRow = terminal_char_row(term, term->cursor);
292 uint16_t moveBy = ansi->parameters[0] == 0 ? 1 : ansi->parameters[0];
293 uint16_t endPos = MIN(TERMINAL_ROWS - 1, cursorRow + moveBy);
294 term->cursor = terminal_get_char(term, endPos, term->cursor->col);
295 }
296 break;
297 case 'C': // Cursor Forward
298 {
299 uint16_t moveBy = ansi->parameters[0] == 0 ? 1 : ansi->parameters[0];
300 uint16_t endPos = MIN(TERMINAL_COLUMNS - 1, term->cursor->col + moveBy);
301 term->cursor = terminal_get_char(term, terminal_char_row(term, term->cursor), endPos);
302 }
303 break;
304 case 'D': // Cursor Backward
305 {
306 uint16_t moveBy = ansi->parameters[0] == 0 ? 1 : ansi->parameters[0];
307 uint16_t startPos = term->cursor->col < moveBy ? 0 : term->cursor->col - moveBy;
308 term->cursor = terminal_get_char(term, terminal_char_row(term, term->cursor), startPos);
309 }
310 break;
311 case 'n':
312 {
313 if (ansi->parameters[0] != 6)
314 {
315 break;
316 }
317
318 // Report Cursor Position
319 uint16_t cursorRow = terminal_char_row(term, term->cursor) + 1;
320 uint16_t cursorCol = term->cursor->col + 1;
321 char response[MAX_NAME];
322 int responseLen = snprintf(response, sizeof(response), "\033[%d;%dR", cursorRow, cursorCol);
323 write(term->stdin[PIPE_WRITE], response, responseLen);
324 }
325 break;
326 case 's': // Save Cursor Position
327 term->savedCursor = term->cursor;
328 break;
329 case 'u': // Restore Cursor Position
330 terminal_cursor_update(term, elem, draw);
331 term->prevCursor = term->cursor;
332 term->cursor = term->savedCursor;
333 break;
334 case 'J': // Erase in Screen
335 {
336 uint16_t cursorRow = terminal_char_row(term, term->cursor);
337 uint16_t cursorCol = term->cursor->col;
338 uint16_t startRow = 0;
339 uint16_t startCol = 0;
340 uint16_t endRow = 0;
341 uint16_t endCol = 0;
342 switch (ansi->parameters[0])
343 {
344 case 0: // From cursor to end of screen
345 startRow = cursorRow;
346 startCol = cursorCol;
347 endRow = TERMINAL_ROWS - 1;
348 endCol = TERMINAL_COLUMNS - 1;
349 break;
350 case 1: // From beginning of screen to cursor
351 startRow = 0;
352 startCol = 0;
353 endRow = cursorRow;
354 endCol = cursorCol;
355 break;
356 case 2: // Entire screen
357 startRow = 0;
358 startCol = 0;
359 endRow = TERMINAL_ROWS - 1;
360 endCol = TERMINAL_COLUMNS - 1;
361 break;
362 default:
363 break;
364 }
365
366 for (uint16_t row = startRow; row <= endRow; row++)
367 {
368 uint16_t colStart = (row == startRow) ? startCol : 0;
369 uint16_t colEnd = (row == endRow) ? endCol : TERMINAL_COLUMNS - 1;
370 for (uint16_t col = colStart; col <= colEnd; col++)
371 {
372 terminal_char_t* screenChar = terminal_get_char(term, row, col);
373 screenChar->chr = ' ';
374 screenChar->foreground = term->foreground;
375 screenChar->background = term->background;
376 screenChar->flags = term->flags;
377 terminal_char_draw(term, elem, draw, screenChar);
378 }
379 }
380 }
381 break;
382 case 'K': // Erase in Line
383 {
384 uint16_t cursorRow = terminal_char_row(term, term->cursor);
385 uint16_t startCol = 0;
386 uint16_t endCol = 0;
387 switch (ansi->parameters[0])
388 {
389 case 0: // From cursor to end of line
390 startCol = term->cursor->col;
391 endCol = TERMINAL_COLUMNS - 1;
392 break;
393 case 1: // From beginning of line to cursor
394 startCol = 0;
395 endCol = term->cursor->col;
396 break;
397 case 2: // Entire line
398 startCol = 0;
399 endCol = TERMINAL_COLUMNS - 1;
400 break;
401 default:
402 break;
403 }
404
405 for (uint16_t col = startCol; col <= endCol; col++)
406 {
407 terminal_char_t* lineChar = terminal_get_char(term, cursorRow, col);
408 lineChar->chr = ' ';
409 lineChar->foreground = term->foreground;
410 lineChar->background = term->background;
411 lineChar->flags = term->flags;
412 terminal_char_draw(term, elem, draw, lineChar);
413 }
414 }
415 break;
416 case 'm': // Graphic Rendition
417 {
418 if (ansi->paramCount != 1)
419 {
420 /// @todo Implement support for more advanced color stuff
421 return;
422 }
423
424 const theme_t* theme = element_get_theme(elem);
425 switch (ansi->parameters[0])
426 {
427 case 0:
428 term->foreground = theme->ansi.bright[7];
429 term->background = theme->ansi.normal[0];
430 term->flags = 0;
431 break;
432 case 1:
433 term->flags |= TERMINAL_BOLD;
434 break;
435 case 2:
436 term->flags |= TERMINAL_DIM;
437 break;
438 case 3:
439 term->flags |= TERMINAL_ITALIC;
440 break;
441 case 4:
442 term->flags |= TERMINAL_UNDERLINE;
443 break;
444 case 5:
445 term->flags |= TERMINAL_BLINK;
446 break;
447 case 6:
448 term->flags |= TERMINAL_INVERSE;
449 break;
450 case 7:
451 term->flags |= TERMINAL_HIDDEN;
452 break;
453 case 8:
455 break;
456 case 9:
458 break;
459 case 22:
460 term->flags &= ~(TERMINAL_BOLD | TERMINAL_DIM);
461 break;
462 case 23:
463 term->flags &= ~TERMINAL_ITALIC;
464 break;
465 case 24:
466 term->flags &= ~TERMINAL_UNDERLINE;
467 break;
468 case 25:
469 term->flags &= ~TERMINAL_BLINK;
470 break;
471 case 27:
472 term->flags &= ~TERMINAL_INVERSE;
473 break;
474 case 28:
475 term->flags &= ~TERMINAL_HIDDEN;
476 break;
477 case 29:
478 term->flags &= ~TERMINAL_STRIKETHROUGH;
479 break;
480 default:
481 if (ansi->parameters[0] >= 30 && ansi->parameters[0] <= 37)
482 {
483 term->foreground = theme->ansi.normal[ansi->parameters[0] - 30];
484 }
485 else if (ansi->parameters[0] == 39)
486 {
487 term->foreground = theme->ansi.bright[7];
488 }
489 else if (ansi->parameters[0] >= 90 && ansi->parameters[0] <= 97)
490 {
491 term->foreground = theme->ansi.bright[ansi->parameters[0] - 90];
492 }
493 else if (ansi->parameters[0] >= 40 && ansi->parameters[0] <= 47)
494 {
495 term->background = theme->ansi.normal[ansi->parameters[0] - 40];
496 }
497 else if (ansi->parameters[0] == 49)
498 {
499 term->background = theme->ansi.normal[0];
500 }
501 else if (ansi->parameters[0] >= 100 && ansi->parameters[0] <= 107)
502 {
503 term->background = theme->ansi.bright[ansi->parameters[0] - 100];
504 }
505 break;
506 }
507 }
508 break;
509 }
510
511 return;
512not_handled:
513 terminal_put(term, elem, draw, '\033');
514 terminal_put(term, elem, draw, '[');
515 for (uint64_t i = 0; i < ansi->paramCount; i++)
516 {
517 if (i > 0)
518 {
519 terminal_put(term, elem, draw, ';');
520 }
521 char paramStr[MAX_NAME];
522 int paramLen = snprintf(paramStr, sizeof(paramStr), "%d", ansi->parameters[i]);
523 for (int j = 0; j < paramLen; j++)
524 {
525 terminal_put(term, elem, draw, paramStr[j]);
526 }
527 }
528 terminal_put(term, elem, draw, ansi->command);
529}
530
531static void terminal_handle_output(terminal_t* term, element_t* elem, drawable_t* draw, const char* buffer,
532 uint64_t length)
533{
534 for (uint64_t i = 0; i < length; i++)
535 {
536 if (ansi_sending_parse(&term->ansi, buffer[i]))
537 {
538 terminal_execute_ansi(term, elem, draw, &term->ansi);
539 }
540 }
541
542 term->cursorBlink = true;
543 terminal_cursor_update(term, elem, draw);
545}
546
547static uint64_t terminal_procedure(window_t* win, element_t* elem, const event_t* event)
548{
549 switch (event->type)
550 {
551 case EVENT_LIB_INIT:
552 {
554
555 terminal_t* term = malloc(sizeof(terminal_t));
556 if (term == NULL)
557 {
558 return ERR;
559 }
560 term->win = win;
561 term->font = ctx->font;
562 term->cursorBlink = false;
563 term->isCursorVisible = true;
564
565 if (open2("/dev/pipe/new", term->stdin) == ERR)
566 {
567 font_free(term->font);
568 free(term);
569 return ERR;
570 }
571 if (open2("/dev/pipe/new", term->stdout) == ERR)
572 {
573 close(term->stdin[0]);
574 close(term->stdin[1]);
575 font_free(term->font);
576 free(term);
577 return ERR;
578 }
579
580 const theme_t* theme = element_get_theme(elem);
581 term->foreground = theme->ansi.bright[7];
582 term->background = theme->ansi.normal[0];
583 term->flags = 0;
584 ansi_sending_init(&term->ansi);
585 for (uint64_t row = 0; row < TERMINAL_ROWS; row++)
586 {
587 for (uint64_t col = 0; col < TERMINAL_COLUMNS; col++)
588 {
589 term->screen[row][col] = terminal_char_create(' ', term->foreground, term->background, row, col);
590 }
591 }
592 term->firstRow = 0;
593 term->savedCursor = &term->screen[0][0];
594 term->cursor = &term->screen[0][0];
595 term->prevCursor = &term->screen[0][0];
596
597 const char* argv[] = {"/base/bin/shell", NULL};
599 if (term->shell == ERR)
600 {
601 close(term->stdin[0]);
602 close(term->stdin[1]);
603 close(term->stdout[0]);
604 close(term->stdout[1]);
605 font_free(term->font);
606 free(term);
607 return ERR;
608 }
609
610 if (writefiles(F("/proc/%d/ctl", term->shell),
611 F("dup2 %d 0 && dup2 %d 1 && dup2 %d 2 && close 3 -1 && start", term->stdin[0], term->stdout[1],
612 term->stdout[1])) == ERR)
613 {
614 writefiles(F("/proc/%d/ctl", term->shell), "kill");
615 close(term->stdin[0]);
616 close(term->stdin[1]);
617 close(term->stdout[0]);
618 close(term->stdout[1]);
619 font_free(term->font);
620 free(term);
621 return ERR;
622 }
623
624 element_set_private(elem, term);
626 }
627 break;
628 case EVENT_LIB_DEINIT:
629 {
630 terminal_t* term = element_get_private(elem);
631 if (term == NULL)
632 {
633 break;
634 }
635
636 close(term->stdin[0]);
637 close(term->stdin[1]);
638 close(term->stdout[0]);
639 close(term->stdout[1]);
640
641 writefiles(F("/proc/%d/notegroup", term->shell), "terminate due to terminal close");
642 }
643 break;
644 case EVENT_LIB_QUIT:
645 {
647 }
648 break;
649 case EVENT_LIB_REDRAW:
650 {
651 terminal_t* term = element_get_private(elem);
652
653 drawable_t draw;
654 element_draw_begin(elem, &draw);
655 terminal_clear(term, elem, &draw);
656 element_draw_end(elem, &draw);
657 }
658 break;
659 case EVENT_TIMER:
660 {
661 terminal_t* term = element_get_private(elem);
662
664
665 term->cursorBlink = !term->cursorBlink;
666 drawable_t draw;
667 element_draw_begin(elem, &draw);
668 terminal_cursor_update(term, elem, &draw);
669 element_draw_end(elem, &draw);
670 }
671 break;
672 case EVENT_KBD:
673 {
674 terminal_t* term = element_get_private(elem);
675
676 if (event->kbd.type != KBD_PRESS || event->kbd.code == 0)
677 {
678 break;
679 }
680
681 drawable_t draw;
682 element_draw_begin(elem, &draw);
683 terminal_handle_input(term, elem, &draw, &event->kbd);
684 element_draw_end(elem, &draw);
685 }
686 break;
687 default:
688 break;
689 }
690
691 return 0;
692}
693
695{
696 const theme_t* theme = theme_global_get();
697 return TERMINAL_COLUMNS * font_width(font, "a", 1) + theme->frameSize * 2 + theme->bigPadding * 2;
698}
699
701{
702 const theme_t* theme = theme_global_get();
703 return TERMINAL_ROWS * font_height(font) + theme->frameSize * 2 + theme->bigPadding * 2;
704}
705
707{
708 terminal_init_ctx_t ctx = {
709 .font = font_new(disp, "firacode", "retina", 16),
710 };
711 if (ctx.font == NULL)
712 {
713 return NULL;
714 }
715
717 window_t* win = window_new(disp, "Terminal", &rect, SURFACE_WINDOW, WINDOW_DECO, terminal_procedure, &ctx);
718 if (win == NULL)
719 {
720 font_free(ctx.font);
721 return NULL;
722 }
723
724 if (window_set_visible(win, true) == ERR)
725 {
726 window_free(win);
727 font_free(ctx.font);
728 return NULL;
729 }
730
731 return win;
732}
733
735{
737 display_t* disp = window_get_display(win);
738
739 char buffer[TERMINAL_MAX_DATA] = {0};
740 uint64_t length = 0;
741
742 clock_t currentTime = clock();
743 clock_t nextFrameTime = currentTime + (CLOCKS_PER_SEC / TERMINAL_MAX_FPS);
744 while (true)
745 {
746 clock_t timeout;
747 if (length == 0)
748 {
749 timeout = CLOCKS_NEVER;
750 }
751 else if (length == TERMINAL_MAX_DATA)
752 {
753 timeout = 0;
754 }
755 else
756 {
757 timeout = nextFrameTime - currentTime;
758 }
759
760 pollfd_t fds[1] = {{
761 .fd = terminal->stdout[PIPE_READ],
762 .events = POLLIN,
763 }};
764 if (display_poll(disp, fds, 1, timeout) == ERR)
765 {
766 break;
767 }
768
769 event_t event = {0};
770 while (display_next(disp, &event, 0) != ERR)
771 {
772 display_dispatch(disp, &event);
773 }
774
775 if ((!(fds[0].revents & POLLIN) && length > 0) || length == TERMINAL_MAX_DATA)
776 {
777 element_t* elem = window_get_client_element(terminal->win);
778 terminal_t* term = element_get_private(elem);
779
780 drawable_t draw;
781 element_draw_begin(elem, &draw);
782 terminal_handle_output(term, elem, &draw, buffer, length);
783 element_draw_end(elem, &draw);
784
785 length = 0;
786 window_invalidate_flush(terminal->win);
787 display_cmds_flush(disp);
788 }
789
790 if (fds[0].revents & POLLIN)
791 {
792 size_t readCount = read(terminal->stdout[PIPE_READ], &buffer[length], TERMINAL_MAX_DATA - length);
793 if (readCount == ERR || readCount == 0)
794 {
795 break;
796 }
797 length += readCount;
798 }
799
800 currentTime = clock();
801 if (currentTime >= nextFrameTime)
802 {
803 nextFrameTime = MAX(nextFrameTime + (CLOCKS_PER_SEC / TERMINAL_MAX_FPS), currentTime + 1);
804 }
805 }
806}
#define MAX_NAME
Maximum length of names.
Definition MAX_NAME.h:11
EFI_PHYSICAL_ADDRESS buffer
Definition main.c:237
#define CLOCKS_NEVER
Definition clock_t.h:18
#define CLOCKS_PER_SEC
Definition clock_t.h:15
@ TIMER_NONE
Definition cmd.h:76
static fd_t kbd
Definition dwm.c:23
uint64_t font_width(const font_t *font, const char *string, uint64_t length)
Definition font.c:130
void font_free(font_t *font)
Definition font.c:91
font_t * font_new(display_t *disp, const char *family, const char *weight, uint64_t size)
Definition font.c:17
uint64_t font_height(const font_t *font)
Definition font.c:158
void display_disconnect(display_t *disp)
Disconnect the display connection.
Definition display.c:159
uint64_t display_poll(display_t *disp, pollfd_t *fds, uint64_t nfds, clock_t timeout)
Poll the display connection for events together with other file descriptors.
Definition display.c:266
uint64_t display_next(display_t *disp, event_t *event, clock_t timeout)
Retrieve the next event from the display connection.
Definition display.c:211
void display_cmds_flush(display_t *disp)
Flush the display's command buffer.
Definition display.c:196
uint64_t display_dispatch(display_t *disp, const event_t *event)
Dispatch an event to the appropriate surface.
Definition display.c:410
void draw_string(drawable_t *draw, const font_t *font, const point_t *point, pixel_t pixel, const char *string, uint64_t length)
Draw a string.
Definition drawable.c:590
void draw_rect(drawable_t *draw, const rect_t *rect, pixel_t pixel)
Draw a filled rectangle.
Definition drawable.c:7
void draw_transfer(drawable_t *dest, drawable_t *src, const rect_t *destRect, const point_t *srcPoint)
Transfer pixels from one drawable to another.
Definition drawable.c:462
theme_t * element_get_theme(element_t *elem)
Get the theme of an element.
Definition element.c:401
void element_draw_end(element_t *elem, drawable_t *draw)
End drawing to an element.
Definition element.c:427
rect_t element_get_content_rect(element_t *elem)
Get the element's rectangle in local coordinates.
Definition element.c:213
void element_draw_begin(element_t *elem, drawable_t *draw)
Begin drawing to an element.
Definition element.c:411
void element_set_private(element_t *elem, void *data)
Set private data for an element.
Definition element.c:163
void * element_get_private(element_t *elem)
Get private data for an element.
Definition element.c:173
#define EVENT_LIB_QUIT
Definition event.h:102
#define EVENT_LIB_DEINIT
Definition event.h:99
#define EVENT_LIB_INIT
Definition event.h:98
#define EVENT_KBD
Definition event.h:83
#define EVENT_LIB_REDRAW
Definition event.h:100
#define EVENT_TIMER
Definition event.h:85
@ KBD_PRESS
Key press event.
Definition event.h:137
@ SURFACE_WINDOW
Definition surface.h:35
theme_t * theme_global_get(void)
Get the global theme.
Definition theme.c:97
uint64_t window_set_visible(window_t *win, bool isVisible)
Set the visibility of the window.
Definition window.c:704
uint64_t window_invalidate_flush(window_t *win)
Flush invalidated rectangles to the DWM.
Definition window.c:582
uint64_t window_set_timer(window_t *win, timer_flags_t flags, clock_t timeout)
Set the window timer.
Definition window.c:545
window_t * window_new(display_t *disp, const char *name, const rect_t *rect, surface_type_t type, window_flags_t flags, procedure_t procedure, void *data)
Allocate and initialize a new window.
Definition window.c:313
element_t * window_get_client_element(window_t *win)
Get the client element of the window.
Definition window.c:509
void window_free(window_t *win)
Free a window.
Definition window.c:427
display_t * window_get_display(window_t *win)
Get the display associated with the window.
Definition window.c:479
@ WINDOW_DECO
Enable decorations (titlebar, close/minimize buttons, etc).
Definition window.h:46
#define UNUSED(x)
Mark a variable as unused.
Definition defs.h:96
#define PIPE_READ
Pipe read end.
Definition fs.h:46
size_t writefiles(const char *path, const char *string)
Wrapper for writing a null-terminated string directly to a file using a path.
Definition swritefile.c:4
uint64_t close(fd_t fd)
System call for closing files.
Definition close.c:8
#define F(format,...)
Allocates a formatted string on the stack.
Definition fs.h:67
size_t write(fd_t fd, const void *buffer, size_t count)
System call for writing to files.
Definition write.c:8
size_t read(fd_t fd, void *buffer, size_t count)
System call for reading from files.
Definition read.c:8
#define PIPE_WRITE
Pipe write end.
Definition fs.h:55
uint64_t open2(const char *path, fd_t fd[2])
System call for opening 2 file descriptors from one file.
Definition open2.c:8
@ POLLIN
File descriptor is ready to read.
Definition fs.h:288
#define MIN(x, y)
Definition math.h:18
#define MAX(x, y)
Definition math.h:17
pid_t spawn(const char **argv, spawn_flags_t flags)
System call for spawning new processes.
Definition spawn.c:6
@ SPAWN_EMPTY_GROUP
Don't inherit the parent's process group, instead create a new group.
Definition proc.h:66
@ SPAWN_SUSPEND
Definition proc.h:61
@ SPAWN_COPY_NS
Don't share the parent's namespace, instead create a new copy of it.
Definition proc.h:67
#define NULL
Pointer error value.
Definition NULL.h:25
#define ERR
Integer error value.
Definition ERR.h:17
__UINT64_TYPE__ clock_t
A nanosecond time.
Definition clock_t.h:13
static bool ansi_sending_parse(ansi_sending_t *ansi, char chr)
Parse a character for ANSI sending.
Definition ansi.h:172
static void ansi_sending_init(ansi_sending_t *ansi)
Initialize an ANSI sending structure.
Definition ansi.h:155
static void ansi_kbd_to_receiving(ansi_receiving_t *ansi, const event_kbd_t *kbd)
Convert a keycode to an ANSI receiving sequence.
Definition ansi.h:40
void terminal_loop(window_t *win)
Terminal main loop.
Definition terminal.c:734
#define TERMINAL_BLINK_INTERVAL
Terminal blink rate.
Definition terminal.h:30
#define TERMINAL_COLUMNS
Terminal columns.
Definition terminal.h:35
#define TERMINAL_MAX_DATA
Maximum size of the buffer used to batch data.
Definition terminal.h:45
#define TERMINAL_MAX_FPS
Maximum terminal frames per second.
Definition terminal.h:52
window_t * terminal_new(display_t *disp)
Create a new terminal window.
Definition terminal.c:706
#define TERMINAL_ROWS
Terminal rows.
Definition terminal.h:40
@ TERMINAL_DIM
Definition terminal.h:64
@ TERMINAL_STRIKETHROUGH
Definition terminal.h:70
@ TERMINAL_BLINK
Definition terminal.h:67
@ TERMINAL_ITALIC
Definition terminal.h:65
@ TERMINAL_UNDERLINE
Definition terminal.h:66
@ TERMINAL_HIDDEN
Definition terminal.h:69
@ TERMINAL_INVERSE
Definition terminal.h:68
@ TERMINAL_BOLD
Definition terminal.h:63
static ansi_t ansi
Definition interactive.c:18
uint32_t pixel_t
Definition pixel.h:11
#define RECT_SHRINK(rect, margin)
Definition rect.h:81
#define RECT_INIT_DIM(x, y, width, height)
Definition rect.h:32
#define RECT_HEIGHT(rect)
Definition rect.h:39
#define RECT_WIDTH(rect)
Definition rect.h:38
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT16_TYPE__ uint16_t
Definition stdint.h:13
_PUBLIC int snprintf(char *_RESTRICT s, size_t n, const char *_RESTRICT format,...)
Definition snprintf.c:3
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
ANSI receiving structure.
Definition ansi.h:27
ANSI sending structure.
Definition ansi.h:140
uint8_t length
Definition ansi.h:11
char buffer[ANSI_MAX_LENGTH]
Definition ansi.h:10
Opaque display structure.
Definition internal.h:68
Drawable structure.
Definition drawable.h:35
Opaque element structure.
Definition internal.h:23
Keyboard event.
Definition event.h:161
kbd_event_type_t type
Definition event.h:162
keycode_t code
Definition event.h:164
Event structure.
Definition event.h:306
event_kbd_t kbd
Definition event.h:312
event_type_t type
Definition event.h:307
int64_t y
Definition point.h:14
int64_t x
Definition point.h:13
Poll file descriptor structure.
Definition fs.h:305
fd_t fd
The file descriptor to poll.
Definition fs.h:306
Definition rect.h:13
int32_t bottom
Definition rect.h:17
int32_t top
Definition rect.h:15
int32_t left
Definition rect.h:14
Terminal character.
Definition terminal.h:78
pixel_t foreground
Definition terminal.h:80
pixel_t background
Definition terminal.h:81
uint16_t col
Definition terminal.h:83
uint16_t physicalRow
Definition terminal.h:84
terminal_flags_t flags
Definition terminal.h:82
Terminal initialization context.
Definition terminal.h:118
Terminal structure.
Definition terminal.h:92
pixel_t background
Definition terminal.h:100
terminal_char_t * savedCursor
Definition terminal.h:105
terminal_char_t * prevCursor
Definition terminal.h:106
terminal_flags_t flags
Definition terminal.h:101
fd_t stdin[2]
Definition terminal.h:97
fd_t stdout[2]
Definition terminal.h:98
font_t * font
Definition terminal.h:94
window_t * win
Definition terminal.h:93
terminal_char_t screen[TERMINAL_ROWS][TERMINAL_COLUMNS]
Definition terminal.h:103
pid_t shell
Definition terminal.h:108
bool isCursorVisible
Definition terminal.h:96
pixel_t foreground
Definition terminal.h:99
bool cursorBlink
Definition terminal.h:95
uint64_t firstRow
Definition terminal.h:104
ansi_sending_t ansi
Definition terminal.h:102
terminal_char_t * cursor
Definition terminal.h:107
pixel_t bright[THEME_ANSI_COLOR_COUNT]
Definition theme.h:61
pixel_t normal[THEME_ANSI_COLOR_COUNT]
Definition theme.h:60
Theme structure.
Definition theme.h:71
int64_t smallPadding
Definition theme.h:88
theme_ansi_t ansi
Definition theme.h:90
int64_t frameSize
Definition theme.h:83
int64_t bigPadding
Definition theme.h:87
Opaque window structure.
Definition internal.h:44
static void terminal_put(terminal_t *term, element_t *elem, drawable_t *draw, char chr)
Definition terminal.c:134
static void terminal_clear(terminal_t *term, element_t *elem, drawable_t *draw)
Definition terminal.c:86
static rect_t terminal_char_rect(terminal_t *term, element_t *elem, terminal_char_t *termChar)
Definition terminal.c:49
static terminal_char_t * terminal_get_char(terminal_t *term, uint16_t row, uint16_t col)
Definition terminal.c:26
static uint64_t terminal_procedure(window_t *win, element_t *elem, const event_t *event)
Definition terminal.c:547
static void terminal_char_draw(terminal_t *term, element_t *elem, drawable_t *draw, terminal_char_t *termChar)
Definition terminal.c:55
static uint64_t terminal_pixel_width(font_t *font)
Definition terminal.c:694
static void terminal_cursor_update(terminal_t *term, element_t *elem, drawable_t *draw)
Definition terminal.c:71
static void terminal_scroll(terminal_t *term, element_t *elem, drawable_t *draw)
Definition terminal.c:100
static void terminal_handle_input(terminal_t *term, element_t *elem, drawable_t *draw, const event_kbd_t *kbd)
Definition terminal.c:215
static uint64_t terminal_pixel_height(font_t *font)
Definition terminal.c:700
static void terminal_handle_output(terminal_t *term, element_t *elem, drawable_t *draw, const char *buffer, uint64_t length)
Definition terminal.c:531
static point_t terminal_char_pos(terminal_t *term, element_t *elem, terminal_char_t *termChar)
Definition terminal.c:36
static terminal_char_t terminal_char_create(char chr, pixel_t foreground, pixel_t background, uint16_t row, uint16_t col)
Definition terminal.c:13
static void terminal_execute_ansi(terminal_t *term, element_t *elem, drawable_t *draw, ansi_sending_t *ansi)
Definition terminal.c:234
static uint16_t terminal_char_row(terminal_t *term, terminal_char_t *termChar)
Definition terminal.c:31
static theme_t theme
Definition theme.c:12
_PUBLIC clock_t clock(void)
Definition clock.c:5