Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // clipboard.c
- #include <fcntl.h>
- #include <stdio.h>
- #include <signal.h>
- #include <termios.h>
- #include <time.h>
- #include <unistd.h>
- #include "clipboard.h"
- int clipboard_init(struct clipboard *c, offer_func *offer,
- respond_func *respond, void *data) {
- int s;
- unsigned long b;
- c->win_set = 0;
- c->d = XOpenDisplay(NULL);
- if(c->d == NULL) {
- perror("XOpenDisplay");
- return -1;
- }
- s = DefaultScreen(c->d);
- b = BlackPixel(c->d, s);
- c->w = XCreateSimpleWindow(c->d, RootWindow(c->d, s), 0, 0, 1, 1, 0, b, b);
- c->win_set = 1;
- c->offer = offer;
- c->respond = respond;
- c->data = data;
- c->xa_targets = XInternAtom(c->d, "TARGETS", False);
- c->xa_clipboard = XInternAtom(c->d, "CLIPBOARD", False);
- return 0;
- }
- void clipboard_cleanup(struct clipboard *c) {
- if(c->win_set)
- XDestroyWindow(c->d, c->w);
- if(c->d != NULL)
- XCloseDisplay(c->d);
- }
- void clipboard_set_data(struct clipboard *c, void *data) {
- c->data = data;
- }
- static inline int selection_request(struct clipboard *c,
- XSelectionRequestEvent *rq) {
- XEvent s = {
- .xselection.type = SelectionNotify,
- .xselection.requestor = rq->requestor,
- .xselection.selection = rq->selection,
- .xselection.target = rq->target,
- .xselection.property = None, // This means refusal
- .xselection.time = rq->time,
- };
- struct clipboard_response cr;
- int r, ret = 0;
- if(rq->target == c->xa_targets) {
- r = c->offer(c, &cr);
- if(r == 1)
- c->running = 0;
- else if(r < 0) {
- ret = -1;
- goto respond;
- }
- XChangeProperty(c->d, rq->requestor, rq->property, XA_ATOM, 32,
- PropModeReplace, cr.data, cr.length);
- s.xselection.property = rq->property;
- goto respond;
- }
- r = c->respond(c, &cr, rq);
- if(r == 1)
- c->running = 0;
- else if(r < 0) {
- ret = -1;
- goto respond; // refusal
- } else if(cr.data == NULL)
- goto respond; // refusal
- s.xselection.property = rq->property;
- XChangeProperty(c->d, rq->requestor, rq->property, rq->target, 8,
- PropModeReplace, cr.data, cr.length);
- respond:
- XSendEvent(c->d, rq->requestor, True, 0, &s);
- return ret;
- }
- int handle_events(struct clipboard *c) {
- XEvent e;
- if(XPending(c->d) == 0)
- return 0;
- XNextEvent(c->d, &e);
- if(e.type == SelectionRequest &&
- selection_request(c, &e.xselectionrequest) < 0) {
- return -1;
- } else if(e.type == Expose)
- while(XCheckTypedEvent(c->d, Expose, &e) != 0);
- else if(e.type == SelectionClear)
- c->running = 0;
- return 0;
- }
- int clipboard_paste(struct clipboard *c, enum clipboard_selection sel) {
- XSetSelectionOwner(c->d, (Atom[]){
- XA_PRIMARY, XA_SECONDARY, c->xa_clipboard,
- }[sel], c->w, CurrentTime);
- XFlush(c->d);
- c->running = 1;
- while(c->running == 1)
- if(handle_events(c) < 0)
- return -1;
- return 0;
- }
- int handle_all_events(struct clipboard *c) {
- while(XPending(c->d) > 0)
- if(handle_events(c) < 0)
- return -1;
- return 0;
- }
- static int clipboard_alarm;
- void clipboard_until_keypress_signal(int sig) {
- if(sig != SIGALRM)
- return;
- clipboard_alarm = 1;
- }
- // run clipboard until a key was pressed or a SelectionClear event arrives
- int clipboard_until_keypress(struct clipboard *c,
- enum clipboard_selection sel) {
- struct termios attr, attr_orig;
- struct sigaction sa = {
- .sa_flags = 0,
- .sa_handler = clipboard_until_keypress_signal,
- };
- struct timespec ts = {
- .tv_sec = 0,
- .tv_nsec = 3000000,
- };
- timer_t timerid;
- ssize_t num_read = 0;
- int stdin_fd, fl_orig, ret = -1;
- char x;
- XSetSelectionOwner(c->d, (Atom[]){
- XA_PRIMARY, XA_SECONDARY, c->xa_clipboard,
- }[sel], c->w, CurrentTime);
- XFlush(c->d);
- stdin_fd = fileno(stdin);
- fl_orig = fcntl(stdin_fd, F_GETFL, 0);
- if(fcntl(stdin_fd, F_SETFL, fl_orig | O_NONBLOCK) < 0)
- goto cleanup;
- if(tcgetattr(stdin_fd, &attr) < 0)
- goto cleanup;
- attr_orig = attr;
- attr.c_lflag &= ~(ICANON|ECHO);
- if(tcsetattr(stdin_fd, TCSANOW, &attr) < 0)
- goto cleanup;
- sigemptyset(&sa.sa_mask);
- sigaction(SIGALRM, &sa, NULL);
- if(timer_create(CLOCK_MONOTONIC, NULL, &timerid) < 0)
- goto cleanup;
- timer_settime(timerid, 0, &(struct itimerspec){
- .it_value = ts,
- .it_interval = ts,
- }, NULL);
- c->running = 1;
- while(c->running == 1 && num_read <= 0) {
- num_read = read(fileno(stdin), &x, sizeof x);
- if(handle_all_events(c) < 0)
- goto cleanup;
- for(clipboard_alarm = 0; clipboard_alarm == 0; sleep(1));
- }
- ret = 0;
- cleanup:
- timer_delete(timerid);
- if(tcsetattr(stdin_fd, TCSANOW, &attr_orig) < 0)
- ret = -1;
- if(fcntl(stdin_fd, F_SETFL, fl_orig) < 0)
- ret = -1;
- return ret;
- }
Add Comment
Please, Sign In to add comment