main.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <errno.h>
  4. #include <string.h>
  5. #include <stdlib.h>
  6. #include <fcntl.h>
  7. #include <assert.h>
  8. #include <sys/ioctl.h>
  9. #include <sys/select.h>
  10. #include <LibC/gui.h>
  11. #include "Terminal.h"
  12. #include <Kernel/KeyCode.h>
  13. #include <LibGUI/GEventLoop.h>
  14. #include <LibGUI/GNotifier.h>
  15. #include <LibGUI/GWidget.h>
  16. #include <LibGUI/GWindow.h>
  17. static void make_shell(int ptm_fd)
  18. {
  19. pid_t pid = fork();
  20. if (pid == 0) {
  21. const char* tty_name = ptsname(ptm_fd);
  22. if (!tty_name) {
  23. perror("ptsname");
  24. exit(1);
  25. }
  26. int rc = 0;
  27. close(ptm_fd);
  28. int pts_fd = open(tty_name, O_RDWR);
  29. rc = ioctl(0, TIOCNOTTY);
  30. if (rc < 0) {
  31. perror("ioctl(TIOCNOTTY)");
  32. exit(1);
  33. }
  34. close(0);
  35. close(1);
  36. close(2);
  37. dup2(pts_fd, 0);
  38. dup2(pts_fd, 1);
  39. dup2(pts_fd, 2);
  40. close(pts_fd);
  41. rc = ioctl(0, TIOCSCTTY);
  42. if (rc < 0) {
  43. perror("ioctl(TIOCSCTTY)");
  44. exit(1);
  45. }
  46. rc = execvp("/bin/sh", nullptr);
  47. if (rc < 0) {
  48. perror("execve");
  49. exit(1);
  50. }
  51. ASSERT_NOT_REACHED();
  52. }
  53. }
  54. int main(int, char**)
  55. {
  56. int ptm_fd = open("/dev/ptmx", O_RDWR);
  57. if (ptm_fd < 0) {
  58. perror("open(ptmx)");
  59. return 1;
  60. }
  61. make_shell(ptm_fd);
  62. GEventLoop loop;
  63. auto* window = new GWindow;
  64. window->set_should_exit_app_on_close(true);
  65. Terminal terminal(ptm_fd);
  66. window->set_main_widget(&terminal);
  67. window->move_to(300, 300);
  68. GNotifier ptm_notifier(ptm_fd, GNotifier::Read);
  69. ptm_notifier.on_ready_to_read = [&terminal] (GNotifier& notifier) {
  70. byte buffer[BUFSIZ];
  71. ssize_t nread = read(notifier.fd(), buffer, sizeof(buffer));
  72. if (nread < 0) {
  73. dbgprintf("Terminal read error: %s\n", strerror(errno));
  74. perror("read(ptm)");
  75. GEventLoop::main().exit(1);
  76. return;
  77. }
  78. if (nread == 0) {
  79. dbgprintf("Terminal: EOF on master pty, closing.\n");
  80. GEventLoop::main().exit(0);
  81. return;
  82. }
  83. for (ssize_t i = 0; i < nread; ++i)
  84. terminal.on_char(buffer[i]);
  85. terminal.flush_dirty_lines();
  86. };
  87. window->show();
  88. return loop.exec();
  89. #if 0
  90. for (;;) {
  91. fd_set rfds;
  92. FD_ZERO(&rfds);
  93. FD_SET(ptm_fd, &rfds);
  94. FD_SET(event_fd, &rfds);
  95. int nfds = select(max(ptm_fd, event_fd) + 1, &rfds, nullptr, nullptr, nullptr);
  96. if (nfds < 0) {
  97. dbgprintf("Terminal(%u) select() failed :( errno=%d\n", getpid(), errno);
  98. return 1;
  99. }
  100. if (FD_ISSET(ptm_fd, &rfds)) {
  101. byte buffer[4096];
  102. ssize_t nread = read(ptm_fd, buffer, sizeof(buffer));
  103. if (nread < 0) {
  104. dbgprintf("Terminal read error: %s\n", strerror(errno));
  105. perror("read(ptm)");
  106. continue;
  107. }
  108. if (nread == 0) {
  109. dbgprintf("Terminal: EOF on master pty, closing.\n");
  110. break;
  111. }
  112. for (ssize_t i = 0; i < nread; ++i)
  113. terminal.on_char(buffer[i]);
  114. terminal.update();
  115. }
  116. if (FD_ISSET(event_fd, &rfds)) {
  117. GUI_Event event;
  118. ssize_t nread = read(event_fd, &event, sizeof(event));
  119. if (nread < 0) {
  120. perror("read(event)");
  121. return 1;
  122. }
  123. assert(nread != 0);
  124. assert(nread == sizeof(event));
  125. if (event.type == GUI_Event::Type::Paint) {
  126. terminal.update();
  127. } else if (event.type == GUI_Event::Type::KeyDown) {
  128. char ch = event.key.character;
  129. if (event.key.ctrl) {
  130. if (ch >= 'a' && ch <= 'z') {
  131. ch = ch - 'a' + 1;
  132. } else if (ch == '\\') {
  133. ch = 0x1c;
  134. }
  135. }
  136. switch (event.key.key) {
  137. case KeyCode::Key_Up:
  138. write(ptm_fd, "\033[A", 3);
  139. break;
  140. case KeyCode::Key_Down:
  141. write(ptm_fd, "\033[B", 3);
  142. break;
  143. case KeyCode::Key_Right:
  144. write(ptm_fd, "\033[C", 3);
  145. break;
  146. case KeyCode::Key_Left:
  147. write(ptm_fd, "\033[D", 3);
  148. break;
  149. default:
  150. write(ptm_fd, &ch, 1);
  151. }
  152. } else if (event.type == GUI_Event::Type::WindowActivated) {
  153. terminal.set_in_active_window(true);
  154. } else if (event.type == GUI_Event::Type::WindowDeactivated) {
  155. terminal.set_in_active_window(false);
  156. } else if (event.type == GUI_Event::Type::WindowCloseRequest) {
  157. return 0;
  158. }
  159. }
  160. }
  161. #endif
  162. return 0;
  163. }