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