Guest User

Untitled

a guest
Feb 20th, 2018
58
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.41 KB | None | 0 0
  1. // clipboard.c
  2.  
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. #include <signal.h>
  6. #include <termios.h>
  7. #include <time.h>
  8. #include <unistd.h>
  9.  
  10. #include "clipboard.h"
  11.  
  12. int clipboard_init(struct clipboard *c, offer_func *offer,
  13. respond_func *respond, void *data) {
  14. int s;
  15. unsigned long b;
  16. c->win_set = 0;
  17.  
  18. c->d = XOpenDisplay(NULL);
  19. if(c->d == NULL) {
  20. perror("XOpenDisplay");
  21. return -1;
  22. }
  23.  
  24. s = DefaultScreen(c->d);
  25. b = BlackPixel(c->d, s);
  26. c->w = XCreateSimpleWindow(c->d, RootWindow(c->d, s), 0, 0, 1, 1, 0, b, b);
  27. c->win_set = 1;
  28.  
  29. c->offer = offer;
  30. c->respond = respond;
  31. c->data = data;
  32. c->xa_targets = XInternAtom(c->d, "TARGETS", False);
  33. c->xa_clipboard = XInternAtom(c->d, "CLIPBOARD", False);
  34. return 0;
  35. }
  36.  
  37. void clipboard_cleanup(struct clipboard *c) {
  38. if(c->win_set)
  39. XDestroyWindow(c->d, c->w);
  40. if(c->d != NULL)
  41. XCloseDisplay(c->d);
  42. }
  43.  
  44. void clipboard_set_data(struct clipboard *c, void *data) {
  45. c->data = data;
  46. }
  47.  
  48. static inline int selection_request(struct clipboard *c,
  49. XSelectionRequestEvent *rq) {
  50. XEvent s = {
  51. .xselection.type = SelectionNotify,
  52. .xselection.requestor = rq->requestor,
  53. .xselection.selection = rq->selection,
  54. .xselection.target = rq->target,
  55. .xselection.property = None, // This means refusal
  56. .xselection.time = rq->time,
  57. };
  58. struct clipboard_response cr;
  59. int r, ret = 0;
  60. if(rq->target == c->xa_targets) {
  61. r = c->offer(c, &cr);
  62. if(r == 1)
  63. c->running = 0;
  64. else if(r < 0) {
  65. ret = -1;
  66. goto respond;
  67. }
  68. XChangeProperty(c->d, rq->requestor, rq->property, XA_ATOM, 32,
  69. PropModeReplace, cr.data, cr.length);
  70. s.xselection.property = rq->property;
  71. goto respond;
  72. }
  73. r = c->respond(c, &cr, rq);
  74. if(r == 1)
  75. c->running = 0;
  76. else if(r < 0) {
  77. ret = -1;
  78. goto respond; // refusal
  79. } else if(cr.data == NULL)
  80. goto respond; // refusal
  81. s.xselection.property = rq->property;
  82. XChangeProperty(c->d, rq->requestor, rq->property, rq->target, 8,
  83. PropModeReplace, cr.data, cr.length);
  84. respond:
  85. XSendEvent(c->d, rq->requestor, True, 0, &s);
  86. return ret;
  87. }
  88.  
  89. int handle_events(struct clipboard *c) {
  90. XEvent e;
  91. if(XPending(c->d) == 0)
  92. return 0;
  93. XNextEvent(c->d, &e);
  94. if(e.type == SelectionRequest &&
  95. selection_request(c, &e.xselectionrequest) < 0) {
  96. return -1;
  97. } else if(e.type == Expose)
  98. while(XCheckTypedEvent(c->d, Expose, &e) != 0);
  99. else if(e.type == SelectionClear)
  100. c->running = 0;
  101. return 0;
  102. }
  103.  
  104. int clipboard_paste(struct clipboard *c, enum clipboard_selection sel) {
  105. XSetSelectionOwner(c->d, (Atom[]){
  106. XA_PRIMARY, XA_SECONDARY, c->xa_clipboard,
  107. }[sel], c->w, CurrentTime);
  108. XFlush(c->d);
  109. c->running = 1;
  110. while(c->running == 1)
  111. if(handle_events(c) < 0)
  112. return -1;
  113. return 0;
  114. }
  115.  
  116. int handle_all_events(struct clipboard *c) {
  117. while(XPending(c->d) > 0)
  118. if(handle_events(c) < 0)
  119. return -1;
  120. return 0;
  121. }
  122.  
  123. static int clipboard_alarm;
  124. void clipboard_until_keypress_signal(int sig) {
  125. if(sig != SIGALRM)
  126. return;
  127. clipboard_alarm = 1;
  128. }
  129.  
  130. // run clipboard until a key was pressed or a SelectionClear event arrives
  131. int clipboard_until_keypress(struct clipboard *c,
  132. enum clipboard_selection sel) {
  133. struct termios attr, attr_orig;
  134. struct sigaction sa = {
  135. .sa_flags = 0,
  136. .sa_handler = clipboard_until_keypress_signal,
  137. };
  138. struct timespec ts = {
  139. .tv_sec = 0,
  140. .tv_nsec = 3000000,
  141. };
  142. timer_t timerid;
  143. ssize_t num_read = 0;
  144. int stdin_fd, fl_orig, ret = -1;
  145. char x;
  146.  
  147. XSetSelectionOwner(c->d, (Atom[]){
  148. XA_PRIMARY, XA_SECONDARY, c->xa_clipboard,
  149. }[sel], c->w, CurrentTime);
  150. XFlush(c->d);
  151.  
  152. stdin_fd = fileno(stdin);
  153. fl_orig = fcntl(stdin_fd, F_GETFL, 0);
  154. if(fcntl(stdin_fd, F_SETFL, fl_orig | O_NONBLOCK) < 0)
  155. goto cleanup;
  156.  
  157. if(tcgetattr(stdin_fd, &attr) < 0)
  158. goto cleanup;
  159. attr_orig = attr;
  160. attr.c_lflag &= ~(ICANON|ECHO);
  161. if(tcsetattr(stdin_fd, TCSANOW, &attr) < 0)
  162. goto cleanup;
  163.  
  164. sigemptyset(&sa.sa_mask);
  165. sigaction(SIGALRM, &sa, NULL);
  166. if(timer_create(CLOCK_MONOTONIC, NULL, &timerid) < 0)
  167. goto cleanup;
  168. timer_settime(timerid, 0, &(struct itimerspec){
  169. .it_value = ts,
  170. .it_interval = ts,
  171. }, NULL);
  172.  
  173. c->running = 1;
  174. while(c->running == 1 && num_read <= 0) {
  175. num_read = read(fileno(stdin), &x, sizeof x);
  176. if(handle_all_events(c) < 0)
  177. goto cleanup;
  178. for(clipboard_alarm = 0; clipboard_alarm == 0; sleep(1));
  179. }
  180. ret = 0;
  181. cleanup:
  182. timer_delete(timerid);
  183. if(tcsetattr(stdin_fd, TCSANOW, &attr_orig) < 0)
  184. ret = -1;
  185. if(fcntl(stdin_fd, F_SETFL, fl_orig) < 0)
  186. ret = -1;
  187. return ret;
  188. }
Add Comment
Please, Sign In to add comment