You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

1590 lines
42 KiB

  1. #include "selection.h"
  2. #include <ctype.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <fcntl.h>
  6. #include <errno.h>
  7. #include <wctype.h>
  8. #include <sys/epoll.h>
  9. #include <sys/timerfd.h>
  10. #define LOG_MODULE "selection"
  11. #define LOG_ENABLE_DBG 0
  12. #include "log.h"
  13. #include "async.h"
  14. #include "commands.h"
  15. #include "config.h"
  16. #include "extract.h"
  17. #include "grid.h"
  18. #include "misc.h"
  19. #include "render.h"
  20. #include "util.h"
  21. #include "vt.h"
  22. #include "xmalloc.h"
  23. bool
  24. selection_enabled(const struct terminal *term, struct seat *seat)
  25. {
  26. return
  27. seat->mouse.col >= 0 && seat->mouse.row >= 0 &&
  28. (term->mouse_tracking == MOUSE_NONE ||
  29. term_mouse_grabbed(term, seat) ||
  30. term->is_searching);
  31. }
  32. bool
  33. selection_on_rows(const struct terminal *term, int row_start, int row_end)
  34. {
  35. LOG_DBG("on rows: %d-%d, range: %d-%d (offset=%d)",
  36. term->selection.start.row, term->selection.end.row,
  37. row_start, row_end, term->grid->offset);
  38. if (term->selection.end.row < 0)
  39. return false;
  40. assert(term->selection.start.row != -1);
  41. row_start += term->grid->offset;
  42. row_end += term->grid->offset;
  43. const struct coord *start = &term->selection.start;
  44. const struct coord *end = &term->selection.end;
  45. if ((row_start <= start->row && row_end >= start->row) ||
  46. (row_start <= end->row && row_end >= end->row))
  47. {
  48. /* The range crosses one of the selection boundaries */
  49. return true;
  50. }
  51. /* For the last check we must ensure start <= end */
  52. if (start->row > end->row) {
  53. const struct coord *tmp = start;
  54. start = end;
  55. end = tmp;
  56. }
  57. if (row_start >= start->row && row_end <= end->row) {
  58. LOG_INFO("ON ROWS");
  59. return true;
  60. }
  61. return false;
  62. }
  63. void
  64. selection_view_up(struct terminal *term, int new_view)
  65. {
  66. if (likely(term->selection.start.row < 0))
  67. return;
  68. if (likely(new_view < term->grid->view))
  69. return;
  70. term->selection.start.row += term->grid->num_rows;
  71. if (term->selection.end.row >= 0)
  72. term->selection.end.row += term->grid->num_rows;
  73. }
  74. void
  75. selection_view_down(struct terminal *term, int new_view)
  76. {
  77. if (likely(term->selection.start.row < 0))
  78. return;
  79. if (likely(new_view > term->grid->view))
  80. return;
  81. term->selection.start.row &= term->grid->num_rows - 1;
  82. if (term->selection.end.row >= 0)
  83. term->selection.end.row &= term->grid->num_rows - 1;
  84. }
  85. static void
  86. foreach_selected_normal(
  87. struct terminal *term, struct coord _start, struct coord _end,
  88. bool (*cb)(struct terminal *term, struct row *row, struct cell *cell, int col, void *data),
  89. void *data)
  90. {
  91. const struct coord *start = &_start;
  92. const struct coord *end = &_end;
  93. int start_row, end_row;
  94. int start_col, end_col;
  95. if (start->row < end->row) {
  96. start_row = start->row;
  97. end_row = end->row;
  98. start_col = start->col;
  99. end_col = end->col;
  100. } else if (start->row > end->row) {
  101. start_row = end->row;
  102. end_row = start->row;
  103. start_col = end->col;
  104. end_col = start->col;
  105. } else {
  106. start_row = end_row = start->row;
  107. start_col = min(start->col, end->col);
  108. end_col = max(start->col, end->col);
  109. }
  110. for (int r = start_row; r <= end_row; r++) {
  111. size_t real_r = r & (term->grid->num_rows - 1);
  112. struct row *row = term->grid->rows[real_r];
  113. assert(row != NULL);
  114. for (int c = start_col;
  115. c <= (r == end_row ? end_col : term->cols - 1);
  116. c++)
  117. {
  118. if (!cb(term, row, &row->cells[c], c, data))
  119. return;
  120. }
  121. start_col = 0;
  122. }
  123. }
  124. static void
  125. foreach_selected_block(
  126. struct terminal *term, struct coord _start, struct coord _end,
  127. bool (*cb)(struct terminal *term, struct row *row, struct cell *cell, int col, void *data),
  128. void *data)
  129. {
  130. const struct coord *start = &_start;
  131. const struct coord *end = &_end;
  132. struct coord top_left = {
  133. .row = min(start->row, end->row),
  134. .col = min(start->col, end->col),
  135. };
  136. struct coord bottom_right = {
  137. .row = max(start->row, end->row),
  138. .col = max(start->col, end->col),
  139. };
  140. for (int r = top_left.row; r <= bottom_right.row; r++) {
  141. size_t real_r = r & (term->grid->num_rows - 1);
  142. struct row *row = term->grid->rows[real_r];
  143. assert(row != NULL);
  144. for (int c = top_left.col; c <= bottom_right.col; c++) {
  145. if (!cb(term, row, &row->cells[c], c, data))
  146. return;
  147. }
  148. }
  149. }
  150. static void
  151. foreach_selected(
  152. struct terminal *term, struct coord start, struct coord end,
  153. bool (*cb)(struct terminal *term, struct row *row, struct cell *cell, int col, void *data),
  154. void *data)
  155. {
  156. switch (term->selection.kind) {
  157. case SELECTION_NORMAL:
  158. foreach_selected_normal(term, start, end, cb, data);
  159. return;
  160. case SELECTION_BLOCK:
  161. foreach_selected_block(term, start, end, cb, data);
  162. return;
  163. case SELECTION_NONE:
  164. assert(false);
  165. return;
  166. }
  167. assert(false);
  168. }
  169. static bool
  170. extract_one_const_wrapper(struct terminal *term,
  171. struct row *row, struct cell *cell,
  172. int col, void *data)
  173. {
  174. return extract_one(term, row, cell, col, data);
  175. }
  176. char *
  177. selection_to_text(const struct terminal *term)
  178. {
  179. if (term->selection.end.row == -1)
  180. return NULL;
  181. struct extraction_context *ctx = extract_begin(term->selection.kind);
  182. if (ctx == NULL)
  183. return NULL;
  184. foreach_selected(
  185. (struct terminal *)term, term->selection.start, term->selection.end,
  186. &extract_one_const_wrapper, ctx);
  187. char *text;
  188. return extract_finish(ctx, &text, NULL) ? text : NULL;
  189. }
  190. void
  191. selection_start(struct terminal *term, int col, int row,
  192. enum selection_kind kind)
  193. {
  194. selection_cancel(term);
  195. LOG_DBG("%s selection started at %d,%d",
  196. kind == SELECTION_NORMAL ? "normal" :
  197. kind == SELECTION_BLOCK ? "block" : "<unknown>",
  198. row, col);
  199. term->selection.kind = kind;
  200. term->selection.start = (struct coord){col, term->grid->view + row};
  201. term->selection.end = (struct coord){-1, -1};
  202. term->selection.ongoing = true;
  203. }
  204. /* Context used while (un)marking selected cells, to be able to
  205. * exclude empty cells */
  206. struct mark_context {
  207. const struct row *last_row;
  208. int empty_count;
  209. };
  210. static bool
  211. unmark_selected(struct terminal *term, struct row *row, struct cell *cell,
  212. int col, void *data)
  213. {
  214. if (cell->attrs.selected == 0 || (cell->attrs.selected & 2)) {
  215. /* Ignore if already deselected, or if premarked for updated selection */
  216. return true;
  217. }
  218. row->dirty = true;
  219. cell->attrs.selected = 0;
  220. cell->attrs.clean = 0;
  221. return true;
  222. }
  223. static bool
  224. premark_selected(struct terminal *term, struct row *row, struct cell *cell,
  225. int col, void *data)
  226. {
  227. struct mark_context *ctx = data;
  228. assert(ctx != NULL);
  229. if (ctx->last_row != row) {
  230. ctx->last_row = row;
  231. ctx->empty_count = 0;
  232. }
  233. if (cell->wc == 0 && term->selection.kind == SELECTION_NORMAL) {
  234. ctx->empty_count++;
  235. return true;
  236. }
  237. /* Tell unmark to leave this be */
  238. for (int i = 0; i < ctx->empty_count + 1; i++)
  239. row->cells[col - i].attrs.selected |= 2;
  240. return true;
  241. }
  242. static bool
  243. mark_selected(struct terminal *term, struct row *row, struct cell *cell,
  244. int col, void *data)
  245. {
  246. struct mark_context *ctx = data;
  247. assert(ctx != NULL);
  248. if (ctx->last_row != row) {
  249. ctx->last_row = row;
  250. ctx->empty_count = 0;
  251. }
  252. if (cell->wc == 0 && term->selection.kind == SELECTION_NORMAL) {
  253. ctx->empty_count++;
  254. return true;
  255. }
  256. for (int i = 0; i < ctx->empty_count + 1; i++) {
  257. struct cell *c = &row->cells[col - i];
  258. if (c->attrs.selected & 1)
  259. c->attrs.selected = 1; /* Clear the pre-mark bit */
  260. else {
  261. row->dirty = true;
  262. c->attrs.selected = 1;
  263. c->attrs.clean = 0;
  264. }
  265. }
  266. return true;
  267. }
  268. static void
  269. selection_modify(struct terminal *term, struct coord start, struct coord end)
  270. {
  271. assert(term->selection.start.row != -1);
  272. assert(start.row != -1 && start.col != -1);
  273. assert(end.row != -1 && end.col != -1);
  274. struct mark_context ctx = {0};
  275. /* Premark all cells that *will* be selected */
  276. foreach_selected(term, start, end, &premark_selected, &ctx);
  277. memset(&ctx, 0, sizeof(ctx));
  278. if (term->selection.end.row >= 0) {
  279. /* Unmark previous selection, ignoring cells that are part of
  280. * the new selection */
  281. foreach_selected(term, term->selection.start, term->selection.end,
  282. &unmark_selected, &ctx);
  283. memset(&ctx, 0, sizeof(ctx));
  284. }
  285. term->selection.start = start;
  286. term->selection.end = end;
  287. /* Mark new selection */
  288. foreach_selected(term, start, end, &mark_selected, &ctx);
  289. render_refresh(term);
  290. }
  291. void
  292. selection_update(struct terminal *term, int col, int row)
  293. {
  294. if (term->selection.start.row < 0)
  295. return;
  296. if (!term->selection.ongoing)
  297. return;
  298. LOG_DBG("selection updated: start = %d,%d, end = %d,%d -> %d, %d",
  299. term->selection.start.row, term->selection.start.col,
  300. term->selection.end.row, term->selection.end.col,
  301. row, col);
  302. assert(term->grid->view + row != -1);
  303. struct coord new_start = term->selection.start;
  304. struct coord new_end = {col, term->grid->view + row};
  305. size_t start_row_idx = new_start.row & (term->grid->num_rows - 1);
  306. size_t end_row_idx = new_end.row & (term->grid->num_rows - 1);
  307. const struct row *row_start = term->grid->rows[start_row_idx];
  308. const struct row *row_end = term->grid->rows[end_row_idx];
  309. /* Adjust start point if the selection has changed 'direction' */
  310. if (!(new_end.row == new_start.row && new_end.col == new_start.col)) {
  311. enum selection_direction new_direction;
  312. if (new_end.row > new_start.row ||
  313. (new_end.row == new_start.row && new_end.col > new_start.col))
  314. {
  315. /* New end point is after the start point */
  316. new_direction = SELECTION_RIGHT;
  317. } else {
  318. /* The new end point is before the start point */
  319. new_direction = SELECTION_LEFT;
  320. }
  321. if (term->selection.direction != new_direction) {
  322. if (term->selection.direction != SELECTION_UNDIR) {
  323. if (new_direction == SELECTION_LEFT) {
  324. bool keep_going = true;
  325. while (keep_going) {
  326. const wchar_t wc = row_start->cells[new_start.col].wc;
  327. keep_going = wc == CELL_MULT_COL_SPACER;
  328. new_start.col--;
  329. if (new_start.col < 0) {
  330. new_start.col = term->cols - 1;
  331. new_start.row--;
  332. }
  333. }
  334. } else {
  335. bool keep_going = true;
  336. while (keep_going) {
  337. const wchar_t wc = new_start.col < term->cols - 1
  338. ? row_start->cells[new_start.col + 1].wc
  339. : 0;
  340. keep_going = wc == CELL_MULT_COL_SPACER;
  341. new_start.col++;
  342. if (new_start.col >= term->cols) {
  343. new_start.col = 0;
  344. new_start.row++;
  345. }
  346. }
  347. }
  348. }
  349. term->selection.direction = new_direction;
  350. }
  351. }
  352. /* If an end point is in the middle of a multi-column character,
  353. * expand the selection to cover the entire character */
  354. if (new_start.row < new_end.row ||
  355. (new_start.row == new_end.row && new_start.col <= new_end.col))
  356. {
  357. while (new_start.col >= 1 &&
  358. row_start->cells[new_start.col].wc == CELL_MULT_COL_SPACER)
  359. new_start.col--;
  360. while (new_end.col < term->cols - 1 &&
  361. row_end->cells[new_end.col + 1].wc == CELL_MULT_COL_SPACER)
  362. new_end.col++;
  363. } else {
  364. while (new_end.col >= 1 &&
  365. row_end->cells[new_end.col].wc == CELL_MULT_COL_SPACER)
  366. new_end.col--;
  367. while (new_start.col < term->cols - 1 &&
  368. row_start->cells[new_start.col + 1].wc == CELL_MULT_COL_SPACER)
  369. new_start.col++;
  370. }
  371. selection_modify(term, new_start, new_end);
  372. }
  373. void
  374. selection_dirty_cells(struct terminal *term)
  375. {
  376. if (term->selection.start.row < 0 || term->selection.end.row < 0)
  377. return;
  378. foreach_selected(
  379. term, term->selection.start, term->selection.end, &mark_selected,
  380. &(struct mark_context){0});
  381. }
  382. static void
  383. selection_extend_normal(struct terminal *term, int col, int row, uint32_t serial)
  384. {
  385. const struct coord *start = &term->selection.start;
  386. const struct coord *end = &term->selection.end;
  387. if (start->row > end->row ||
  388. (start->row == end->row && start->col > end->col))
  389. {
  390. const struct coord *tmp = start;
  391. start = end;
  392. end = tmp;
  393. }
  394. assert(start->row < end->row || start->col < end->col);
  395. struct coord new_start, new_end;
  396. if (row < start->row || (row == start->row && col < start->col)) {
  397. /* Extend selection to start *before* current start */
  398. new_start = *end;
  399. new_end = (struct coord){col, row};
  400. }
  401. else if (row > end->row || (row == end->row && col > end->col)) {
  402. /* Extend selection to end *after* current end */
  403. new_start = *start;
  404. new_end = (struct coord){col, row};
  405. }
  406. else {
  407. /* Shrink selection from start or end, depending on which one is closest */
  408. const int linear = row * term->cols + col;
  409. if (abs(linear - (start->row * term->cols + start->col)) <
  410. abs(linear - (end->row * term->cols + end->col)))
  411. {
  412. /* Move start point */
  413. new_start = *end;
  414. new_end = (struct coord){col, row};
  415. }
  416. else {
  417. /* Move end point */
  418. new_start = *start;
  419. new_end = (struct coord){col, row};
  420. }
  421. }
  422. selection_modify(term, new_start, new_end);
  423. }
  424. static void
  425. selection_extend_block(struct terminal *term, int col, int row, uint32_t serial)
  426. {
  427. const struct coord *start = &term->selection.start;
  428. const struct coord *end = &term->selection.end;
  429. struct coord top_left = {
  430. .row = min(start->row, end->row),
  431. .col = min(start->col, end->col),
  432. };
  433. struct coord top_right = {
  434. .row = min(start->row, end->row),
  435. .col = max(start->col, end->col),
  436. };
  437. struct coord bottom_left = {
  438. .row = max(start->row, end->row),
  439. .col = min(start->col, end->col),
  440. };
  441. struct coord bottom_right = {
  442. .row = max(start->row, end->row),
  443. .col = max(start->col, end->col),
  444. };
  445. struct coord new_start;
  446. struct coord new_end;
  447. if (row <= top_left.row ||
  448. abs(row - top_left.row) < abs(row - bottom_left.row))
  449. {
  450. /* Move one of the top corners */
  451. if (abs(col - top_left.col) < abs(col - top_right.col)) {
  452. new_start = bottom_right;
  453. new_end = (struct coord){col, row};
  454. }
  455. else {
  456. new_start = bottom_left;
  457. new_end = (struct coord){col, row};
  458. }
  459. }
  460. else {
  461. /* Move one of the bottom corners */
  462. if (abs(col - bottom_left.col) < abs(col - bottom_right.col)) {
  463. new_start = top_right;
  464. new_end = (struct coord){col, row};
  465. }
  466. else {
  467. new_start = top_left;
  468. new_end = (struct coord){col, row};
  469. }
  470. }
  471. selection_modify(term, new_start, new_end);
  472. }
  473. void
  474. selection_extend(struct seat *seat, struct terminal *term,
  475. int col, int row, uint32_t serial)
  476. {
  477. if (term->selection.start.row < 0 || term->selection.end.row < 0) {
  478. /* No existing selection */
  479. return;
  480. }
  481. term->selection.ongoing = true;
  482. row += term->grid->view;
  483. if ((row == term->selection.start.row && col == term->selection.start.col) ||
  484. (row == term->selection.end.row && col == term->selection.end.col))
  485. {
  486. /* Extension point *is* one of the current end points */
  487. return;
  488. }
  489. switch (term->selection.kind) {
  490. case SELECTION_NONE:
  491. assert(false);
  492. return;
  493. case SELECTION_NORMAL:
  494. selection_extend_normal(term, col, row, serial);
  495. break;
  496. case SELECTION_BLOCK:
  497. selection_extend_block(term, col, row, serial);
  498. break;
  499. }
  500. selection_to_primary(seat, term, serial);
  501. }
  502. //static const struct zwp_primary_selection_source_v1_listener primary_selection_source_listener;
  503. void
  504. selection_finalize(struct seat *seat, struct terminal *term, uint32_t serial)
  505. {
  506. if (!term->selection.ongoing)
  507. return;
  508. selection_stop_scroll_timer(term);
  509. term->selection.ongoing = false;
  510. if (term->selection.start.row < 0 || term->selection.end.row < 0)
  511. return;
  512. assert(term->selection.start.row != -1);
  513. assert(term->selection.end.row != -1);
  514. if (term->selection.start.row > term->selection.end.row ||
  515. (term->selection.start.row == term->selection.end.row &&
  516. term->selection.start.col > term->selection.end.col))
  517. {
  518. struct coord tmp = term->selection.start;
  519. term->selection.start = term->selection.end;
  520. term->selection.end = tmp;
  521. }
  522. assert(term->selection.start.row <= term->selection.end.row);
  523. selection_to_primary(seat, term, serial);
  524. }
  525. void
  526. selection_cancel(struct terminal *term)
  527. {
  528. LOG_DBG("selection cancelled: start = %d,%d end = %d,%d",
  529. term->selection.start.row, term->selection.start.col,
  530. term->selection.end.row, term->selection.end.col);
  531. selection_stop_scroll_timer(term);
  532. if (term->selection.start.row >= 0 && term->selection.end.row >= 0) {
  533. foreach_selected(
  534. term, term->selection.start, term->selection.end,
  535. &unmark_selected, &(struct mark_context){0});
  536. render_refresh(term);
  537. }
  538. term->selection.kind = SELECTION_NONE;
  539. term->selection.start = (struct coord){-1, -1};
  540. term->selection.end = (struct coord){-1, -1};
  541. term->selection.direction = SELECTION_UNDIR;
  542. term->selection.ongoing = false;
  543. }
  544. bool
  545. selection_clipboard_has_data(const struct seat *seat)
  546. {
  547. return seat->clipboard.data_offer != NULL;
  548. }
  549. bool
  550. selection_primary_has_data(const struct seat *seat)
  551. {
  552. return seat->primary.data_offer != NULL;
  553. }
  554. void
  555. selection_clipboard_unset(struct seat *seat)
  556. {
  557. struct wl_clipboard *clipboard = &seat->clipboard;
  558. if (clipboard->data_source == NULL)
  559. return;
  560. /* Kill previous data source */
  561. assert(clipboard->serial != 0);
  562. wl_data_device_set_selection(seat->data_device, NULL, clipboard->serial);
  563. wl_data_source_destroy(clipboard->data_source);
  564. clipboard->data_source = NULL;
  565. clipboard->serial = 0;
  566. free(clipboard->text);
  567. clipboard->text = NULL;
  568. }
  569. void
  570. selection_primary_unset(struct seat *seat)
  571. {
  572. struct wl_primary *primary = &seat->primary;
  573. if (primary->data_source == NULL)
  574. return;
  575. assert(primary->serial != 0);
  576. zwp_primary_selection_device_v1_set_selection(
  577. seat->primary_selection_device, NULL, primary->serial);
  578. zwp_primary_selection_source_v1_destroy(primary->data_source);
  579. primary->data_source = NULL;
  580. primary->serial = 0;
  581. free(primary->text);
  582. primary->text = NULL;
  583. }
  584. void
  585. selection_mark_word(struct seat *seat, struct terminal *term, int col, int row,
  586. bool spaces_only, uint32_t serial)
  587. {
  588. selection_cancel(term);
  589. struct coord start = {col, row};
  590. struct coord end = {col, row};
  591. const struct row *r = grid_row_in_view(term->grid, start.row);
  592. wchar_t c = r->cells[start.col].wc;
  593. if (!(c == 0 || !isword(c, spaces_only, term->conf->word_delimiters))) {
  594. while (true) {
  595. int next_col = start.col - 1;
  596. int next_row = start.row;
  597. /* Linewrap */
  598. if (next_col < 0) {
  599. next_col = term->cols - 1;
  600. if (--next_row < 0)
  601. break;
  602. }
  603. const struct row *row = grid_row_in_view(term->grid, next_row);
  604. c = row->cells[next_col].wc;
  605. if (c == 0 || !isword(c, spaces_only, term->conf->word_delimiters))
  606. break;
  607. start.col = next_col;
  608. start.row = next_row;
  609. }
  610. }
  611. r = grid_row_in_view(term->grid, end.row);
  612. c = r->cells[end.col].wc;
  613. if (!(c == 0 || !isword(c, spaces_only, term->conf->word_delimiters))) {
  614. while (true) {
  615. int next_col = end.col + 1;
  616. int next_row = end.row;
  617. /* Linewrap */
  618. if (next_col >= term->cols) {
  619. next_col = 0;
  620. if (++next_row >= term->rows)
  621. break;
  622. }
  623. const struct row *row = grid_row_in_view(term->grid, next_row);
  624. c = row->cells[next_col].wc;
  625. if (c == '\0' || !isword(c, spaces_only, term->conf->word_delimiters))
  626. break;
  627. end.col = next_col;
  628. end.row = next_row;
  629. }
  630. }
  631. selection_start(term, start.col, start.row, SELECTION_NORMAL);
  632. selection_update(term, end.col, end.row);
  633. selection_finalize(seat, term, serial);
  634. }
  635. void
  636. selection_mark_row(
  637. struct seat *seat, struct terminal *term, int row, uint32_t serial)
  638. {
  639. selection_start(term, 0, row, SELECTION_NORMAL);
  640. selection_update(term, term->cols - 1, row);
  641. selection_finalize(seat, term, serial);
  642. }
  643. static bool
  644. fdm_scroll_timer(struct fdm *fdm, int fd, int events, void *data)
  645. {
  646. if (events & EPOLLHUP)
  647. return false;
  648. struct terminal *term = data;
  649. uint64_t expiration_count;
  650. ssize_t ret = read(
  651. term->selection.auto_scroll.fd,
  652. &expiration_count, sizeof(expiration_count));
  653. if (ret < 0) {
  654. if (errno == EAGAIN)
  655. return true;
  656. LOG_ERRNO("failed to read selection scroll timer");
  657. return false;
  658. }
  659. switch (term->selection.auto_scroll.direction) {
  660. case SELECTION_SCROLL_NOT:
  661. return true;
  662. case SELECTION_SCROLL_UP:
  663. cmd_scrollback_up(term, expiration_count);
  664. selection_update(term, term->selection.auto_scroll.col, 0);
  665. break;
  666. case SELECTION_SCROLL_DOWN:
  667. cmd_scrollback_down(term, expiration_count);
  668. selection_update(term, term->selection.auto_scroll.col, term->rows - 1);
  669. break;
  670. }
  671. return true;
  672. }
  673. void
  674. selection_start_scroll_timer(struct terminal *term, int interval_ns,
  675. enum selection_scroll_direction direction, int col)
  676. {
  677. assert(direction != SELECTION_SCROLL_NOT);
  678. if (!term->selection.ongoing)
  679. return;
  680. if (term->selection.auto_scroll.fd < 0) {
  681. int fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
  682. if (fd < 0) {
  683. LOG_ERRNO("failed to create selection scroll timer");
  684. goto err;
  685. }
  686. if (!fdm_add(term->fdm, fd, EPOLLIN, &fdm_scroll_timer, term)) {
  687. close(fd);
  688. return;
  689. }
  690. term->selection.auto_scroll.fd = fd;
  691. }
  692. struct itimerspec timer;
  693. if (timerfd_gettime(term->selection.auto_scroll.fd, &timer) < 0) {
  694. LOG_ERRNO("failed to get current selection scroll timer value");
  695. goto err;
  696. }
  697. if (timer.it_value.tv_sec == 0 && timer.it_value.tv_nsec == 0)
  698. timer.it_value.tv_nsec = 1;
  699. timer.it_interval.tv_sec = interval_ns / 1000000000;
  700. timer.it_interval.tv_nsec = interval_ns % 1000000000;
  701. if (timerfd_settime(term->selection.auto_scroll.fd, 0, &timer, NULL) < 0) {
  702. LOG_ERRNO("failed to set new selection scroll timer value");
  703. goto err;
  704. }
  705. term->selection.auto_scroll.direction = direction;
  706. term->selection.auto_scroll.col = col;
  707. return;
  708. err:
  709. selection_stop_scroll_timer(term);
  710. return;
  711. }
  712. void
  713. selection_stop_scroll_timer(struct terminal *term)
  714. {
  715. if (term->selection.auto_scroll.fd < 0) {
  716. assert(term->selection.auto_scroll.direction == SELECTION_SCROLL_NOT);
  717. return;
  718. }
  719. fdm_del(term->fdm, term->selection.auto_scroll.fd);
  720. term->selection.auto_scroll.fd = -1;
  721. term->selection.auto_scroll.direction = SELECTION_SCROLL_NOT;
  722. }
  723. static void
  724. target(void *data, struct wl_data_source *wl_data_source, const char *mime_type)
  725. {
  726. LOG_WARN("TARGET: mime-type=%s", mime_type);
  727. }
  728. struct clipboard_send {
  729. char *data;
  730. size_t len;
  731. size_t idx;
  732. };
  733. static bool
  734. fdm_send(struct fdm *fdm, int fd, int events, void *data)
  735. {
  736. struct clipboard_send *ctx = data;
  737. if (events & EPOLLHUP)
  738. goto done;
  739. switch (async_write(fd, ctx->data, ctx->len, &ctx->idx)) {
  740. case ASYNC_WRITE_REMAIN:
  741. return true;
  742. case ASYNC_WRITE_DONE:
  743. break;
  744. case ASYNC_WRITE_ERR:
  745. LOG_ERRNO(
  746. "failed to asynchronously write %zu of selection data to FD=%d",
  747. ctx->len - ctx->idx, fd);
  748. break;
  749. }
  750. done:
  751. fdm_del(fdm, fd);
  752. free(ctx->data);
  753. free(ctx);
  754. return true;
  755. }
  756. static void
  757. send_clipboard_or_primary(struct seat *seat, int fd, const char *selection,
  758. const char *source_name)
  759. {
  760. /* Make it NONBLOCK:ing right away - we don't want to block if the
  761. * initial attempt to send the data synchronously fails */
  762. int flags;
  763. if ((flags = fcntl(fd, F_GETFL)) < 0 ||
  764. fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
  765. {
  766. LOG_ERRNO("failed to set O_NONBLOCK");
  767. return;
  768. }
  769. size_t len = strlen(selection);
  770. size_t async_idx = 0;
  771. switch (async_write(fd, selection, len, &async_idx)) {
  772. case ASYNC_WRITE_REMAIN: {
  773. struct clipboard_send *ctx = xmalloc(sizeof(*ctx));
  774. *ctx = (struct clipboard_send) {
  775. .data = xstrdup(&selection[async_idx]),
  776. .len = len - async_idx,
  777. .idx = 0,
  778. };
  779. if (fdm_add(seat->wayl->fdm, fd, EPOLLOUT, &fdm_send, ctx))
  780. return;
  781. free(ctx->data);
  782. free(ctx);
  783. break;
  784. }
  785. case ASYNC_WRITE_DONE:
  786. break;
  787. case ASYNC_WRITE_ERR:
  788. LOG_ERRNO("failed write %zu bytes of %s selection data to FD=%d",
  789. len, source_name, fd);
  790. break;
  791. }
  792. close(fd);
  793. }
  794. static void
  795. send(void *data, struct wl_data_source *wl_data_source, const char *mime_type,
  796. int32_t fd)
  797. {
  798. struct seat *seat = data;
  799. const struct wl_clipboard *clipboard = &seat->clipboard;
  800. assert(clipboard->text != NULL);
  801. send_clipboard_or_primary(seat, fd, clipboard->text, "clipboard");
  802. }
  803. static void
  804. cancelled(void *data, struct wl_data_source *wl_data_source)
  805. {
  806. struct seat *seat = data;
  807. struct wl_clipboard *clipboard = &seat->clipboard;
  808. assert(clipboard->data_source == wl_data_source);
  809. wl_data_source_destroy(clipboard->data_source);
  810. clipboard->data_source = NULL;
  811. clipboard->serial = 0;
  812. free(clipboard->text);
  813. clipboard->text = NULL;
  814. }
  815. static void
  816. dnd_drop_performed(void *data, struct wl_data_source *wl_data_source)
  817. {
  818. }
  819. static void
  820. dnd_finished(void *data, struct wl_data_source *wl_data_source)
  821. {
  822. }
  823. static void
  824. action(void *data, struct wl_data_source *wl_data_source, uint32_t dnd_action)
  825. {
  826. }
  827. static const struct wl_data_source_listener data_source_listener = {
  828. .target = &target,
  829. .send = &send,
  830. .cancelled = &cancelled,
  831. .dnd_drop_performed = &dnd_drop_performed,
  832. .dnd_finished = &dnd_finished,
  833. .action = &action,
  834. };
  835. static void
  836. primary_send(void *data,
  837. struct zwp_primary_selection_source_v1 *zwp_primary_selection_source_v1,
  838. const char *mime_type, int32_t fd)
  839. {
  840. struct seat *seat = data;
  841. const struct wl_primary *primary = &seat->primary;
  842. assert(primary->text != NULL);
  843. send_clipboard_or_primary(seat, fd, primary->text, "primary");
  844. }
  845. static void
  846. primary_cancelled(void *data,
  847. struct zwp_primary_selection_source_v1 *zwp_primary_selection_source_v1)
  848. {
  849. struct seat *seat = data;
  850. struct wl_primary *primary = &seat->primary;
  851. zwp_primary_selection_source_v1_destroy(primary->data_source);
  852. primary->data_source = NULL;
  853. primary->serial = 0;
  854. free(primary->text);
  855. primary->text = NULL;
  856. }
  857. static const struct zwp_primary_selection_source_v1_listener primary_selection_source_listener = {
  858. .send = &primary_send,
  859. .cancelled = &primary_cancelled,
  860. };
  861. bool
  862. text_to_clipboard(struct seat *seat, struct terminal *term, char *text, uint32_t serial)
  863. {
  864. struct wl_clipboard *clipboard = &seat->clipboard;
  865. if (clipboard->data_source != NULL) {
  866. /* Kill previous data source */
  867. assert(clipboard->serial != 0);
  868. wl_data_device_set_selection(seat->data_device, NULL, clipboard->serial);
  869. wl_data_source_destroy(clipboard->data_source);
  870. free(clipboard->text);
  871. clipboard->data_source = NULL;
  872. clipboard->serial = 0;
  873. clipboard->text = NULL;
  874. }
  875. clipboard->data_source
  876. = wl_data_device_manager_create_data_source(term->wl->data_device_manager);
  877. if (clipboard->data_source == NULL) {
  878. LOG_ERR("failed to create clipboard data source");
  879. return false;
  880. }
  881. clipboard->text = text;
  882. /* Configure source */
  883. wl_data_source_offer(clipboard->data_source, "text/plain;charset=utf-8");
  884. wl_data_source_add_listener(clipboard->data_source, &data_source_listener, seat);
  885. wl_data_device_set_selection(seat->data_device, clipboard->data_source, serial);
  886. /* Needed when sending the selection to other client */
  887. assert(serial != 0);
  888. clipboard->serial = serial;
  889. return true;
  890. }
  891. void
  892. selection_to_clipboard(struct seat *seat, struct terminal *term, uint32_t serial)
  893. {
  894. if (term->selection.start.row < 0 || term->selection.end.row < 0)
  895. return;
  896. /* Get selection as a string */
  897. char *text = selection_to_text(term);
  898. if (!text_to_clipboard(seat, term, text, serial))
  899. free(text);
  900. }
  901. struct clipboard_receive {
  902. int read_fd;
  903. int timeout_fd;
  904. struct itimerspec timeout;
  905. /* Callback data */
  906. void (*cb)(const char *data, size_t size, void *user);
  907. void (*done)(void *user);
  908. void *user;
  909. };
  910. static void
  911. clipboard_receive_done(struct fdm *fdm, struct clipboard_receive *ctx)
  912. {
  913. fdm_del(fdm, ctx->timeout_fd);
  914. fdm_del(fdm, ctx->read_fd);
  915. ctx->done(ctx->user);
  916. free(ctx);
  917. }
  918. static bool
  919. fdm_receive_timeout(struct fdm *fdm, int fd, int events, void *data)
  920. {
  921. struct clipboard_receive *ctx = data;
  922. if (events & EPOLLHUP)
  923. return false;
  924. assert(events & EPOLLIN);
  925. uint64_t expire_count;
  926. ssize_t ret = read(fd, &expire_count, sizeof(expire_count));
  927. if (ret < 0) {
  928. if (errno == EAGAIN)
  929. return true;
  930. LOG_ERRNO("failed to read clipboard timeout timer");
  931. return false;
  932. }
  933. LOG_WARN("no data received from clipboard in %llu seconds, aborting",
  934. (unsigned long long)ctx->timeout.it_value.tv_sec);
  935. clipboard_receive_done(fdm, ctx);
  936. return true;
  937. }
  938. static bool
  939. fdm_receive(struct fdm *fdm, int fd, int events, void *data)
  940. {
  941. struct clipboard_receive *ctx = data;
  942. if ((events & EPOLLHUP) && !(events & EPOLLIN))
  943. goto done;
  944. /* Reset timeout timer */
  945. if (timerfd_settime(ctx->timeout_fd, 0, &ctx->timeout, NULL) < 0) {
  946. LOG_ERRNO("failed to re-arm clipboard timeout timer");
  947. return false;
  948. }
  949. /* Read until EOF */
  950. while (true) {
  951. char text[256];
  952. ssize_t count = read(fd, text, sizeof(text));
  953. if (count == -1) {
  954. if (errno == EAGAIN || errno == EWOULDBLOCK)
  955. return true;
  956. LOG_ERRNO("failed to read clipboard data");
  957. break;
  958. }
  959. if (count == 0)
  960. break;
  961. /* Call cb while at same time replacing \r\n with \n */
  962. const char *p = text;
  963. size_t left = count;
  964. again:
  965. for (size_t i = 0; i < left - 1; i++) {
  966. if (p[i] == '\r' && p[i + 1] == '\n') {
  967. ctx->cb(p, i, ctx->user);
  968. assert(i + 1 <= left);
  969. p += i + 1;
  970. left -= i + 1;
  971. goto again;
  972. }
  973. }
  974. ctx->cb(p, left, ctx->user);
  975. left = 0;
  976. }
  977. done:
  978. clipboard_receive_done(fdm, ctx);
  979. return true;
  980. }
  981. static void
  982. begin_receive_clipboard(struct terminal *term, int read_fd,
  983. void (*cb)(const char *data, size_t size, void *user),
  984. void (*done)(void *user), void *user)
  985. {
  986. int timeout_fd = -1;
  987. struct clipboard_receive *ctx = NULL;
  988. int flags;
  989. if ((flags = fcntl(read_fd, F_GETFL)) < 0 ||
  990. fcntl(read_fd, F_SETFL, flags | O_NONBLOCK) < 0)
  991. {
  992. LOG_ERRNO("failed to set O_NONBLOCK");
  993. goto err;
  994. }
  995. timeout_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
  996. if (timeout_fd < 0) {
  997. LOG_ERRNO("failed to create clipboard timeout timer FD");
  998. goto err;
  999. }
  1000. const struct itimerspec timeout = {.it_value = {.tv_sec = 2}};
  1001. if (timerfd_settime(timeout_fd, 0, &timeout, NULL) < 0) {
  1002. LOG_ERRNO("failed to arm clipboard timeout timer");
  1003. goto err;
  1004. }
  1005. ctx = xmalloc(sizeof(*ctx));
  1006. *ctx = (struct clipboard_receive) {
  1007. .read_fd = read_fd,
  1008. .timeout_fd = timeout_fd,
  1009. .timeout = timeout,
  1010. .cb = cb,
  1011. .done = done,
  1012. .user = user,
  1013. };
  1014. if (!fdm_add(term->fdm, read_fd, EPOLLIN, &fdm_receive, ctx) ||
  1015. !fdm_add(term->fdm, timeout_fd, EPOLLIN, &fdm_receive_timeout, ctx))
  1016. {
  1017. goto err;
  1018. }
  1019. return;
  1020. err:
  1021. free(ctx);
  1022. fdm_del(term->fdm, timeout_fd);
  1023. fdm_del(term->fdm, read_fd);
  1024. done(user);
  1025. }
  1026. void
  1027. text_from_clipboard(struct seat *seat, struct terminal *term,
  1028. void (*cb)(const char *data, size_t size, void *user),
  1029. void (*done)(void *user), void *user)
  1030. {
  1031. struct wl_clipboard *clipboard = &seat->clipboard;
  1032. if (clipboard->data_offer == NULL) {
  1033. done(user);
  1034. return;
  1035. }
  1036. /* Prepare a pipe the other client can write its selection to us */
  1037. int fds[2];
  1038. if (pipe2(fds, O_CLOEXEC) == -1) {
  1039. LOG_ERRNO("failed to create pipe");
  1040. done(user);
  1041. return;
  1042. }
  1043. int read_fd = fds[0];
  1044. int write_fd = fds[1];
  1045. /* Give write-end of pipe to other client */
  1046. wl_data_offer_receive(
  1047. clipboard->data_offer, "text/plain;charset=utf-8", write_fd);
  1048. /* Don't keep our copy of the write-end open (or we'll never get EOF) */
  1049. close(write_fd);
  1050. begin_receive_clipboard(term, read_fd, cb, done, user);
  1051. }
  1052. static void
  1053. from_clipboard_cb(const char *data, size_t size, void *user)
  1054. {
  1055. struct terminal *term = user;
  1056. assert(term->is_sending_paste_data);
  1057. term_paste_data_to_slave(term, data, size);
  1058. }
  1059. static void
  1060. from_clipboard_done(void *user)
  1061. {
  1062. struct terminal *term = user;
  1063. if (term->bracketed_paste)
  1064. term_paste_data_to_slave(term, "\033[201~", 6);
  1065. term->is_sending_paste_data = false;
  1066. /* Make sure we send any queued up non-paste data */
  1067. if (tll_length(term->ptmx_buffers) > 0)
  1068. fdm_event_add(term->fdm, term->ptmx, EPOLLOUT);
  1069. }
  1070. void
  1071. selection_from_clipboard(struct seat *seat, struct terminal *term, uint32_t serial)
  1072. {
  1073. if (term->is_sending_paste_data) {
  1074. /* We're already pasting... */
  1075. return;
  1076. }
  1077. struct wl_clipboard *clipboard = &seat->clipboard;
  1078. if (clipboard->data_offer == NULL)
  1079. return;
  1080. term->is_sending_paste_data = true;
  1081. if (term->bracketed_paste)
  1082. term_paste_data_to_slave(term, "\033[200~", 6);
  1083. text_from_clipboard(
  1084. seat, term, &from_clipboard_cb, &from_clipboard_done, term);
  1085. }
  1086. bool
  1087. text_to_primary(struct seat *seat, struct terminal *term, char *text, uint32_t serial)
  1088. {
  1089. if (term->wl->primary_selection_device_manager == NULL)
  1090. return false;
  1091. struct wl_primary *primary = &seat->primary;
  1092. /* TODO: somehow share code with the clipboard equivalent */
  1093. if (seat->primary.data_source != NULL) {
  1094. /* Kill previous data source */
  1095. assert(primary->serial != 0);
  1096. zwp_primary_selection_device_v1_set_selection(
  1097. seat->primary_selection_device, NULL, primary->serial);
  1098. zwp_primary_selection_source_v1_destroy(primary->data_source);
  1099. free(primary->text);
  1100. primary->data_source = NULL;
  1101. primary->serial = 0;
  1102. primary->text = NULL;
  1103. }
  1104. primary->data_source
  1105. = zwp_primary_selection_device_manager_v1_create_source(
  1106. term->wl->primary_selection_device_manager);
  1107. if (primary->data_source == NULL) {
  1108. LOG_ERR("failed to create clipboard data source");
  1109. return false;
  1110. }
  1111. /* Get selection as a string */
  1112. primary->text = text;
  1113. /* Configure source */
  1114. zwp_primary_selection_source_v1_offer(primary->data_source, "text/plain;charset=utf-8");
  1115. zwp_primary_selection_source_v1_add_listener(primary->data_source, &primary_selection_source_listener, seat);
  1116. zwp_primary_selection_device_v1_set_selection(seat->primary_selection_device, primary->data_source, serial);
  1117. /* Needed when sending the selection to other client */
  1118. primary->serial = serial;
  1119. return true;
  1120. }
  1121. void
  1122. selection_to_primary(struct seat *seat, struct terminal *term, uint32_t serial)
  1123. {
  1124. if (term->wl->primary_selection_device_manager == NULL)
  1125. return;
  1126. /* Get selection as a string */
  1127. char *text = selection_to_text(term);
  1128. if (!text_to_primary(seat, term, text, serial))
  1129. free(text);
  1130. }
  1131. void
  1132. text_from_primary(
  1133. struct seat *seat, struct terminal *term,
  1134. void (*cb)(const char *data, size_t size, void *user),
  1135. void (*done)(void *user), void *user)
  1136. {
  1137. if (term->wl->primary_selection_device_manager == NULL) {
  1138. done(user);
  1139. return;
  1140. }
  1141. struct wl_primary *primary = &seat->primary;
  1142. if (primary->data_offer == NULL){
  1143. done(user);
  1144. return;
  1145. }
  1146. /* Prepare a pipe the other client can write its selection to us */
  1147. int fds[2];
  1148. if (pipe2(fds, O_CLOEXEC) == -1) {
  1149. LOG_ERRNO("failed to create pipe");
  1150. done(user);
  1151. return;
  1152. }
  1153. int read_fd = fds[0];
  1154. int write_fd = fds[1];
  1155. /* Give write-end of pipe to other client */
  1156. zwp_primary_selection_offer_v1_receive(
  1157. primary->data_offer, "text/plain;charset=utf-8", write_fd);
  1158. /* Don't keep our copy of the write-end open (or we'll never get EOF) */
  1159. close(write_fd);
  1160. begin_receive_clipboard(term, read_fd, cb, done, user);
  1161. }
  1162. void
  1163. selection_from_primary(struct seat *seat, struct terminal *term)
  1164. {
  1165. if (term->wl->primary_selection_device_manager == NULL)
  1166. return;
  1167. if (term->is_sending_paste_data) {
  1168. /* We're already pasting... */
  1169. return;
  1170. }
  1171. struct wl_primary *primary = &seat->primary;
  1172. if (primary->data_offer == NULL)
  1173. return;
  1174. term->is_sending_paste_data = true;
  1175. if (term->bracketed_paste)
  1176. term_paste_data_to_slave(term, "\033[200~", 6);
  1177. text_from_primary(seat, term, &from_clipboard_cb, &from_clipboard_done, term);
  1178. }
  1179. #if 0
  1180. static void
  1181. offer(void *data, struct wl_data_offer *wl_data_offer, const char *mime_type)
  1182. {
  1183. }
  1184. static void
  1185. source_actions(void *data, struct wl_data_offer *wl_data_offer,
  1186. uint32_t source_actions)
  1187. {
  1188. }
  1189. static void
  1190. offer_action(void *data, struct wl_data_offer *wl_data_offer, uint32_t dnd_action)
  1191. {
  1192. }
  1193. static const struct wl_data_offer_listener data_offer_listener = {
  1194. .offer = &offer,
  1195. .source_actions = &source_actions,
  1196. .action = &offer_action,
  1197. };
  1198. #endif
  1199. static void
  1200. data_offer(void *data, struct wl_data_device *wl_data_device,
  1201. struct wl_data_offer *id)
  1202. {
  1203. }
  1204. static void
  1205. enter(void *data, struct wl_data_device *wl_data_device, uint32_t serial,
  1206. struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y,
  1207. struct wl_data_offer *id)
  1208. {
  1209. }
  1210. static void
  1211. leave(void *data, struct wl_data_device *wl_data_device)
  1212. {
  1213. }
  1214. static void
  1215. motion(void *data, struct wl_data_device *wl_data_device, uint32_t time,
  1216. wl_fixed_t x, wl_fixed_t y)
  1217. {
  1218. }
  1219. static void
  1220. drop(void *data, struct wl_data_device *wl_data_device)
  1221. {
  1222. }
  1223. static void
  1224. selection(void *data, struct wl_data_device *wl_data_device,
  1225. struct wl_data_offer *id)
  1226. {
  1227. /* Selection offer from other client */
  1228. struct seat *seat = data;
  1229. struct wl_clipboard *clipboard = &seat->clipboard;
  1230. if (clipboard->data_offer != NULL)
  1231. wl_data_offer_destroy(clipboard->data_offer);
  1232. clipboard->data_offer = id;
  1233. #if 0
  1234. if (id != NULL)
  1235. wl_data_offer_add_listener(id, &data_offer_listener, term);
  1236. #endif
  1237. }
  1238. const struct wl_data_device_listener data_device_listener = {
  1239. .data_offer = &data_offer,
  1240. .enter = &enter,
  1241. .leave = &leave,
  1242. .motion = &motion,
  1243. .drop = &drop,
  1244. .selection = &selection,
  1245. };
  1246. #if 0
  1247. static void
  1248. primary_offer(void *data,
  1249. struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer,
  1250. const char *mime_type)
  1251. {
  1252. }
  1253. static const struct zwp_primary_selection_offer_v1_listener primary_selection_offer_listener = {
  1254. .offer = &primary_offer,
  1255. };
  1256. #endif
  1257. static void
  1258. primary_data_offer(void *data,
  1259. struct zwp_primary_selection_device_v1 *zwp_primary_selection_device,
  1260. struct zwp_primary_selection_offer_v1 *offer)
  1261. {
  1262. }
  1263. static void
  1264. primary_selection(void *data,
  1265. struct zwp_primary_selection_device_v1 *zwp_primary_selection_device,
  1266. struct zwp_primary_selection_offer_v1 *id)
  1267. {
  1268. /* Selection offer from other client, for primary */
  1269. struct seat *seat = data;
  1270. struct wl_primary *primary = &seat->primary;
  1271. if (primary->data_offer != NULL)
  1272. zwp_primary_selection_offer_v1_destroy(primary->data_offer);
  1273. primary->data_offer = id;
  1274. #if 0
  1275. if (id != NULL) {
  1276. zwp_primary_selection_offer_v1_add_listener(
  1277. id, &primary_selection_offer_listener, term);
  1278. }
  1279. #endif
  1280. }
  1281. const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener = {
  1282. .data_offer = &primary_data_offer,
  1283. .selection = &primary_selection,
  1284. };