Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 
 

687 rindas
20 KiB

  1. /*
  2. * neercs console-based window manager
  3. * Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
  4. * 2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
  5. * 2008-2010 Pascal Terjan <pterjan@linuxfr.org>
  6. * All Rights Reserved
  7. *
  8. * This program is free software. It comes without any warranty, to
  9. * the extent permitted by applicable law. You can redistribute it
  10. * and/or modify it under the terms of the Do What The Fuck You Want
  11. * To Public License, Version 2, as published by Sam Hocevar. See
  12. * http://sam.zoy.org/wtfpl/COPYING for more details.
  13. */
  14. #if defined HAVE_CONFIG_H
  15. # include "config.h"
  16. #endif
  17. #if !defined _WIN32
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <unistd.h>
  22. #include <fcntl.h>
  23. #include <signal.h>
  24. #include <sys/ioctl.h>
  25. #include <sys/socket.h>
  26. #include <sys/types.h>
  27. #include <sys/wait.h>
  28. #include <sys/time.h>
  29. #include <time.h>
  30. #include <pwd.h>
  31. #include <errno.h>
  32. #include <caca.h>
  33. #include "neercs.h"
  34. static void server_init(struct screen_list *screen_list);
  35. static void refresh_screen(struct screen_list *screen_list, int refresh);
  36. static int handle_key(struct screen_list *screen_list, unsigned int c,
  37. int refresh);
  38. static int handle_attach(struct screen_list *screen_list, char *buf);
  39. static int send_to_client(const char *msg, int size,
  40. struct screen_list *screen_list)
  41. {
  42. int ret;
  43. if (!screen_list->comm.socket[SOCK_CLIENT])
  44. connect_socket(screen_list, SOCK_CLIENT);
  45. if (!screen_list->comm.socket[SOCK_CLIENT])
  46. ret = -1;
  47. else
  48. ret = write(screen_list->comm.socket[SOCK_CLIENT], msg, size);
  49. if (ret < 0 && errno != EAGAIN)
  50. {
  51. fprintf(stderr, "Failed to send message to client: %s\n",
  52. strerror(errno));
  53. if (screen_list->comm.attached)
  54. detach(screen_list);
  55. }
  56. return ret;
  57. }
  58. static int set_title(struct screen_list *screen_list)
  59. {
  60. char buf[1024];
  61. int bytes;
  62. char *title = NULL;
  63. if (screen_list->comm.attached)
  64. {
  65. if (screen_list->pty < screen_list->count &&
  66. screen_list->screen[screen_list->pty]->title)
  67. title = screen_list->screen[screen_list->pty]->title;
  68. else
  69. title = PACKAGE_STRING;
  70. }
  71. if (screen_list->title)
  72. {
  73. if (!strcmp(screen_list->title, title))
  74. return 0;
  75. free(screen_list->title);
  76. }
  77. screen_list->title = strdup(title);
  78. bytes = snprintf(buf, sizeof(buf) - 1, "TITLE %s", title);
  79. buf[bytes] = '\0';
  80. return send_to_client(buf, strlen(buf), screen_list);
  81. }
  82. static int set_cursor(int state, struct screen_list *screen_list)
  83. {
  84. char buf[16];
  85. int bytes;
  86. bytes = snprintf(buf, sizeof(buf) - 1, "CURSOR %d", state);
  87. buf[bytes] = '\0';
  88. return send_to_client(buf, strlen(buf), screen_list);
  89. }
  90. static int request_refresh(struct screen_list *screen_list)
  91. {
  92. int ndirty = caca_get_dirty_rect_count(screen_list->cv);
  93. if (!ndirty)
  94. return 0;
  95. if (!screen_list->comm.socket[SOCK_CLIENT])
  96. connect_socket(screen_list, SOCK_CLIENT);
  97. if (screen_list->comm.socket[SOCK_CLIENT])
  98. {
  99. size_t bufsize, towrite;
  100. ssize_t written, ret;
  101. socklen_t optlen = sizeof(bufsize);
  102. size_t bytes;
  103. void *buf;
  104. char buf2[32];
  105. int x, y, i;
  106. getsockopt(screen_list->comm.socket[SOCK_CLIENT], SOL_SOCKET,
  107. SO_SNDBUF, &bufsize, &optlen);
  108. bufsize /= 2;
  109. debug("bufsize=%d", bufsize);
  110. for (i = 0; i < ndirty; i++)
  111. {
  112. int w, h;
  113. caca_get_dirty_rect(screen_list->cv, i, &x, &y, &w, &h);
  114. debug("dirty @%d,%d %dx%d [%dx%d]", x, y, w, h,
  115. caca_get_canvas_width(screen_list->cv),
  116. caca_get_canvas_height(screen_list->cv));
  117. buf =
  118. caca_export_area_to_memory(screen_list->cv, x, y, w, h, "caca",
  119. &bytes);
  120. debug("Requesting refresh for %d", bytes);
  121. towrite = bytes;
  122. written = 0;
  123. sprintf(buf2, "UPDATE %10d %10d", x, y);
  124. ret = send_to_client(buf2, strlen(buf2) + 1, screen_list);
  125. if (ret < 29)
  126. {
  127. free(buf);
  128. return -1;
  129. }
  130. /* Block to write the end of the message */
  131. fcntl(screen_list->comm.socket[SOCK_CLIENT], F_SETFL, 0);
  132. while (towrite > 0)
  133. {
  134. ssize_t n;
  135. debug("Wrote %d, %d remaining", written, towrite);
  136. n = send_to_client((char *)buf + written,
  137. towrite > bufsize ? bufsize : towrite,
  138. screen_list);
  139. if (n < 0)
  140. {
  141. debug("Can't refresh (%s), with %d bytes (out of %d)",
  142. strerror(errno),
  143. towrite > bufsize ? bufsize : towrite, towrite);
  144. return -1;
  145. }
  146. written += n;
  147. towrite -= n;
  148. }
  149. fcntl(screen_list->comm.socket[SOCK_CLIENT], F_SETFL, O_NONBLOCK);
  150. free(buf);
  151. }
  152. sprintf(buf2, "REFRESH %10d %10d", caca_get_cursor_x(screen_list->cv),
  153. caca_get_cursor_y(screen_list->cv));
  154. /* FIXME check value of r */
  155. int r = send_to_client(buf2, strlen(buf2) + 1, screen_list);
  156. (void)r;
  157. caca_clear_dirty_rect_list(screen_list->cv);
  158. }
  159. return 0;
  160. }
  161. int detach(struct screen_list *screen_list)
  162. {
  163. screen_list->comm.attached = 0;
  164. if (screen_list->lock.lock_on_detach)
  165. screen_list->lock.locked = 1;
  166. if (screen_list->comm.socket[SOCK_CLIENT])
  167. {
  168. send_to_client("DETACH", 6, screen_list);
  169. close(screen_list->comm.socket[SOCK_CLIENT]);
  170. screen_list->comm.socket[SOCK_CLIENT] = 0;
  171. }
  172. return 0;
  173. }
  174. static int server_iteration(struct screen_list *screen_list)
  175. {
  176. int i;
  177. int eof = 0, refresh;
  178. int quit = 0;
  179. ssize_t n;
  180. char buf[128];
  181. /* Read program output */
  182. refresh = update_screens_contents(screen_list);
  183. /* Check if we got something from the client */
  184. while (screen_list->comm.socket[SOCK_SERVER]
  185. && (n =
  186. read(screen_list->comm.socket[SOCK_SERVER], buf,
  187. sizeof(buf) - 1)) > 0)
  188. {
  189. buf[n] = 0;
  190. debug("Received command %s", buf);
  191. if (!strncmp("ATTACH ", buf, 7))
  192. {
  193. refresh |= handle_attach(screen_list, buf);
  194. }
  195. else if (!strncmp("QUIT", buf, 4))
  196. {
  197. quit = 1;
  198. }
  199. else if (!strncmp("DELAY ", buf, 6))
  200. {
  201. /* FIXME check the length before calling atoi */
  202. screen_list->delay = atoi(buf + 6);
  203. }
  204. else if (!strncmp("RESIZE ", buf, 7))
  205. {
  206. caca_free_canvas(screen_list->cv);
  207. /* FIXME check the length before calling atoi */
  208. screen_list->cv =
  209. caca_create_canvas(atoi(buf + 7), atoi(buf + 18));
  210. screen_list->changed = 1;
  211. refresh = 1;
  212. }
  213. else if (!strncmp("KEY ", buf, 4))
  214. {
  215. unsigned int c = atoi(buf + 4);
  216. refresh |= handle_key(screen_list, c, refresh);
  217. }
  218. else if (!strncmp("MOUSEP ", buf, 6))
  219. {
  220. debug("Got mouse press '%s'\n", buf);
  221. int x, y, b;
  222. x = 1 + atoi(buf + 7) - screen_list->screen[screen_list->pty]->x;
  223. y = 1 + atoi(buf + 18) - screen_list->screen[screen_list->pty]->y;
  224. b = atoi(buf + 28);
  225. switch (screen_list->screen[screen_list->pty]->report_mouse)
  226. {
  227. case MOUSE_VT200:
  228. case MOUSE_VT200_HIGHLIGHT:
  229. case MOUSE_BTN_EVENT:
  230. case MOUSE_ANY_EVENT:
  231. sprintf(buf, "\x1b[M%c%c%c", 32 + (b - 1), x + 32, y + 32);
  232. debug("mousea send ESC[M %d %d %d", (b - 1), x + 32, y + 32);
  233. send_ansi_sequence(screen_list, buf);
  234. break;
  235. case MOUSE_X10:
  236. sprintf(buf, "\x1b[M%c%c%c", 32 + (b - 1), 32 + x, 32 + y);
  237. debug("mousex send ESC[M %d %d %d", 32 + (b - 1), 32 + x,
  238. 32 + y);
  239. send_ansi_sequence(screen_list, buf);
  240. break;
  241. case MOUSE_NONE:
  242. break;
  243. }
  244. }
  245. else if (!strncmp("MOUSER ", buf, 6))
  246. {
  247. debug("Got mouse release '%s'\n", buf);
  248. int x, y, b;
  249. x = 1 + atoi(buf + 7) - screen_list->screen[screen_list->pty]->x;
  250. y = 1 + atoi(buf + 18) - screen_list->screen[screen_list->pty]->y;
  251. b = atoi(buf + 28);
  252. switch (screen_list->screen[screen_list->pty]->report_mouse)
  253. {
  254. case MOUSE_VT200:
  255. case MOUSE_VT200_HIGHLIGHT:
  256. case MOUSE_BTN_EVENT:
  257. case MOUSE_ANY_EVENT:
  258. sprintf(buf, "\x1b[M%c%c%c", 32 + 3, x + 32, y + 32);
  259. send_ansi_sequence(screen_list, buf);
  260. break;
  261. case MOUSE_X10:
  262. sprintf(buf, "\x1b[M%c%c%c", 32 + 3, 32 + x, 32 + y);
  263. send_ansi_sequence(screen_list, buf);
  264. break;
  265. case MOUSE_NONE:
  266. break;
  267. }
  268. }
  269. else if (!strncmp("MOUSEM ", buf, 6))
  270. {
  271. debug("Got mouse motion '%s'\n", buf);
  272. int x, y, b;
  273. x = 1 + atoi(buf + 7) - screen_list->screen[screen_list->pty]->x;
  274. y = 1 + atoi(buf + 18) - screen_list->screen[screen_list->pty]->y;
  275. b = atoi(buf + 28);
  276. switch (screen_list->screen[screen_list->pty]->report_mouse)
  277. {
  278. case MOUSE_X10: // X10 reports mouse clicks only
  279. if (b)
  280. {
  281. sprintf(buf, "\x1b[M%c%c%c", 32 + (b - 1), x + 32, y + 32);
  282. send_ansi_sequence(screen_list, buf);
  283. }
  284. break;
  285. case MOUSE_VT200:
  286. case MOUSE_VT200_HIGHLIGHT:
  287. case MOUSE_BTN_EVENT:
  288. if (b)
  289. {
  290. sprintf(buf, "\x1b[M%c%c%c", 32 + (b - 1), x + 32, y + 32);
  291. send_ansi_sequence(screen_list, buf);
  292. }
  293. case MOUSE_ANY_EVENT:
  294. sprintf(buf, "\x1b[M%c%c%c", 32 + (b - 1), x + 32, y + 32);
  295. send_ansi_sequence(screen_list, buf);
  296. break;
  297. case MOUSE_NONE:
  298. break;
  299. }
  300. }
  301. else
  302. {
  303. fprintf(stderr, "Unknown command received: %s\n", buf);
  304. }
  305. }
  306. /* No more screens, exit */
  307. if (!screen_list->count)
  308. return -1;
  309. /* User requested to exit */
  310. if (quit)
  311. return -2;
  312. /* Update each screen canvas */
  313. refresh |= update_terms(screen_list);
  314. /* Launch recurrents if any */
  315. refresh |= handle_recurrents(screen_list);
  316. /* Refresh screen */
  317. refresh_screen(screen_list, refresh);
  318. eof = 1;
  319. for (i = 0; i < screen_list->count; i++)
  320. if (screen_list->screen[i]->fd >= 0)
  321. eof = 0;
  322. if (eof)
  323. return -3;
  324. return 0;
  325. }
  326. static void server_main(struct screen_list *screen_list)
  327. {
  328. screen_list->last_key_time = 0;
  329. screen_list->comm.attached = 0;
  330. screen_list->command = 0;
  331. screen_list->was_in_bell = 0;
  332. screen_list->last_refresh_time = 0;
  333. server_init(screen_list);
  334. #ifdef USE_PYTHON
  335. python_init(screen_list);
  336. #endif
  337. for (;;)
  338. {
  339. if (server_iteration(screen_list))
  340. break;
  341. }
  342. detach(screen_list);
  343. free_screen_list(screen_list);
  344. #ifdef USE_PYTHON
  345. python_close(screen_list);
  346. #endif
  347. exit(0);
  348. }
  349. static void refresh_screen(struct screen_list *screen_list, int refresh)
  350. {
  351. if (!screen_list->comm.attached)
  352. {
  353. /* No need to refresh Don't use the CPU too much Would be better to
  354. select on terms + socket */
  355. sleep(1);
  356. }
  357. else
  358. {
  359. long long unsigned int current_time = get_us();
  360. long long int tdiff =
  361. (current_time - screen_list->last_refresh_time) / 1000;
  362. refresh |= screen_list->need_refresh;
  363. if (screen_list->force_refresh)
  364. {
  365. wm_refresh(screen_list);
  366. refresh = 1;
  367. }
  368. /* Draw lock window */
  369. if (screen_list->lock.locked)
  370. {
  371. /* FIXME don't redraw it each iteration */
  372. draw_lock(screen_list);
  373. refresh = 1;
  374. }
  375. #ifdef USE_LOCK
  376. else if ((current_time - screen_list->last_key_time >=
  377. screen_list->lock.autolock_timeout))
  378. {
  379. screen_list->lock.locked = 1;
  380. refresh = 1;
  381. }
  382. #endif
  383. else if ((current_time - screen_list->last_key_time >=
  384. screen_list->screensaver.timeout))
  385. {
  386. if (!screen_list->screensaver.in_screensaver)
  387. {
  388. screensaver_init(screen_list);
  389. screen_list->screensaver.in_screensaver = 1;
  390. set_cursor(0, screen_list);
  391. }
  392. draw_screensaver(screen_list);
  393. refresh = 1;
  394. }
  395. else if (refresh || screen_list->was_in_bell)
  396. {
  397. if (tdiff >= screen_list->delay)
  398. {
  399. refresh_screens(screen_list);
  400. set_title(screen_list);
  401. refresh = 1;
  402. }
  403. }
  404. if (refresh)
  405. {
  406. if (tdiff >= screen_list->delay)
  407. {
  408. request_refresh(screen_list);
  409. screen_list->last_refresh_time = current_time;
  410. screen_list->need_refresh = 0;
  411. }
  412. else
  413. {
  414. debug("Skipping refresh (%lld < %d)", tdiff,
  415. screen_list->delay);
  416. screen_list->need_refresh = 1;
  417. }
  418. }
  419. }
  420. }
  421. static void server_init(struct screen_list *screen_list)
  422. {
  423. int i;
  424. debug("Screen list at %p\n", screen_list);
  425. /* Create socket and bind it */
  426. create_socket(screen_list, SOCK_SERVER);
  427. /* Connect to the client */
  428. connect_socket(screen_list, SOCK_CLIENT);
  429. screen_list->width = screen_list->height = 80;
  430. /* Create main canvas */
  431. screen_list->cv = caca_create_canvas(screen_list->width,
  432. screen_list->height
  433. + screen_list->modals.mini * 6
  434. + screen_list->modals.status);
  435. if (!screen_list->sys.to_grab && !screen_list->sys.to_start)
  436. {
  437. add_screen(screen_list,
  438. create_screen(screen_list->width,
  439. screen_list->height,
  440. screen_list->sys.default_shell));
  441. }
  442. /* Attach processes */
  443. if (screen_list->sys.to_grab)
  444. {
  445. for (i = 0; screen_list->sys.to_grab[i]; i++)
  446. {
  447. add_screen(screen_list,
  448. create_screen_grab(screen_list->width,
  449. screen_list->height,
  450. screen_list->sys.to_grab[i]));
  451. }
  452. free(screen_list->sys.to_grab);
  453. screen_list->sys.to_grab = NULL;
  454. }
  455. /* Launch command line processes */
  456. if (screen_list->sys.to_start)
  457. {
  458. for (i = 0; screen_list->sys.to_start[i]; i++)
  459. {
  460. add_screen(screen_list,
  461. create_screen(screen_list->width,
  462. screen_list->height,
  463. screen_list->sys.to_start[i]));
  464. free(screen_list->sys.to_start[i]);
  465. }
  466. free(screen_list->sys.to_start);
  467. screen_list->sys.to_start = NULL;
  468. }
  469. screen_list->last_key_time = get_us();
  470. }
  471. static int handle_attach(struct screen_list *screen_list, char *buf)
  472. {
  473. /* If we were attached to someone else, detach first */
  474. if (screen_list->comm.attached)
  475. detach(screen_list);
  476. screen_list->comm.attached = 1;
  477. caca_free_canvas(screen_list->cv);
  478. screen_list->cv = caca_create_canvas(atoi(buf + 7), atoi(buf + 18));
  479. screen_list->delay = atoi(buf + 29);
  480. screen_list->changed = 1;
  481. return 1;
  482. }
  483. static int handle_key(struct screen_list *screen_list, unsigned int c,
  484. int refresh)
  485. {
  486. char *str = NULL;
  487. int size = 0;
  488. if (screen_list->modals.help)
  489. {
  490. return help_handle_key(screen_list, c);
  491. }
  492. #ifdef USE_PYTHON
  493. if (screen_list->modals.python_command)
  494. {
  495. return python_command_handle_key(screen_list, c);
  496. }
  497. #endif
  498. /* CTRL-A has been pressed before, handle this as a command, except that
  499. CTRL-A a sends literal CTRL-A */
  500. if (screen_list->command && (c != 'a'))
  501. {
  502. screen_list->command = 0;
  503. refresh |= handle_command_input(screen_list, c);
  504. }
  505. else
  506. {
  507. /* Not in command mode */
  508. screen_list->last_key_time = get_us();
  509. set_cursor(1, screen_list);
  510. /* Kill screensaver */
  511. if (screen_list->screensaver.in_screensaver)
  512. {
  513. screensaver_kill(screen_list);
  514. screen_list->screensaver.in_screensaver = 0;
  515. screen_list->changed = 1;
  516. refresh = 1;
  517. return refresh;
  518. }
  519. /* Handle lock window */
  520. if (screen_list->lock.locked)
  521. {
  522. refresh |= update_lock(c, screen_list);
  523. screen_list->changed = 1;
  524. }
  525. else if (screen_list->modals.window_list)
  526. {
  527. refresh |= update_window_list(c, screen_list);
  528. screen_list->changed = 1;
  529. }
  530. else
  531. {
  532. switch (c)
  533. {
  534. case 0x01: // CACA_KEY_CTRL_A:
  535. screen_list->command = 1;
  536. break;
  537. default:
  538. /* CTRL-A a sends literal CTRL-A */
  539. if (screen_list->command && (c == 'a'))
  540. {
  541. c = 0x01;
  542. }
  543. /* Normal key, convert it if needed */
  544. str = convert_input_ansi(&c, &size);
  545. /* FIXME check value of r */
  546. int r = write(screen_list->screen[screen_list->pty]->fd, str,
  547. size);
  548. (void)r;
  549. break;
  550. }
  551. }
  552. }
  553. return refresh;
  554. }
  555. int send_ansi_sequence(struct screen_list *screen_list, char *str)
  556. {
  557. debug("Sending ansi '%s'\n", str);
  558. return write(screen_list->screen[screen_list->pty]->fd, str, strlen(str));
  559. }
  560. int install_fds(struct screen_list *screen_list)
  561. {
  562. int fd;
  563. close(0);
  564. close(1);
  565. close(2);
  566. fd = open("/dev/null", O_RDWR, 0);
  567. if (fd < 0)
  568. {
  569. perror("Failed to open /dev/null");
  570. return -2;
  571. }
  572. dup2(fd, 0);
  573. #ifndef DEBUG
  574. dup2(fd, 1);
  575. dup2(fd, 2);
  576. if (fd > 2)
  577. close(fd);
  578. #else
  579. if (fd != 0)
  580. close(fd);
  581. screen_list->outfd =
  582. open("/tmp/neercs-debug.txt", O_TRUNC | O_RDWR | O_CREAT,
  583. S_IRUSR | S_IWUSR);
  584. dup2(screen_list->outfd, 1);
  585. dup2(screen_list->outfd, 2);
  586. if (screen_list->outfd > 2)
  587. close(screen_list->outfd);
  588. #endif
  589. return 0;
  590. }
  591. int start_server(struct screen_list *screen_list)
  592. {
  593. pid_t pid;
  594. pid = fork();
  595. if (pid < 0)
  596. {
  597. perror("Failed to create child process");
  598. return -1;
  599. }
  600. if (pid == 0)
  601. {
  602. int r = install_fds(screen_list);
  603. if (r)
  604. return r;
  605. setsid();
  606. server_main(screen_list);
  607. /* Never returns */
  608. }
  609. return 0;
  610. }
  611. long long get_us(void)
  612. {
  613. struct timeval tv;
  614. gettimeofday(&tv, NULL);
  615. return (tv.tv_sec * (1000000) + tv.tv_usec);
  616. }
  617. #endif