/* * BRLTTY - A background process providing access to the console screen (when in * text mode) for a blind person using a refreshable braille display. * * Copyright (C) 2019-2021 by Samuel Thibault * * BRLTTY comes with ABSOLUTELY NO WARRANTY. * * This is free software, placed under the terms of the * GNU Lesser General Public License, as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any * later version. Please see the file LICENSE-LGPL for details. * * Web Page: http://brltty.app/ * * This software is maintained by Dave Mielke . */ #include "prologue.h" #include #include "xsel.h" #ifdef HAVE_X11_EXTENSIONS_XFIXES_H #include #else /* HAVE_X11_EXTENSIONS_XFIXES_H */ #warning clipboard tracking not supported by this build - check that libxfixes has been installed #endif /* HAVE_X11_EXTENSIONS_XFIXES_H */ void XSelInit(Display *dpy, XSelData *data) { data->sel = XInternAtom(dpy, "CLIPBOARD", False); data->selProp = XInternAtom(dpy, "BRLTTY_CLIPBOARD", False); data->incr = XInternAtom(dpy, "INCR", False); data->utf8 = XInternAtom(dpy,"UTF8_STRING",False); data->targetsAtom = XInternAtom(dpy,"TARGETS",False); data->selWindow = XCreateSimpleWindow(dpy, RootWindow(dpy, DefaultScreen(dpy)), -10, -10, 1, 1, 0, 0, 0); #ifdef HAVE_X11_EXTENSIONS_XFIXES_H data->haveXfixes = XFixesQueryExtension(dpy, &data->xfixesEventBase, &data->xfixesErrorBase); if (data->haveXfixes) { XFixesSelectSelectionInput(dpy, data->selWindow, data->sel, XFixesSetSelectionOwnerNotifyMask); } #endif /* HAVE_X11_EXTENSIONS_XFIXES_H */ } void XSelSet(Display *dpy, XSelData *data) { XSetSelectionOwner(dpy, data->sel, data->selWindow, CurrentTime); XFlush(dpy); } int XSelProcess(Display *dpy, XSelData *data, XEvent *ev, const char *content, XSelUpdate update) { #ifdef HAVE_X11_EXTENSIONS_XFIXES_H if (data->haveXfixes && ev->type == data->xfixesEventBase + XFixesSelectionNotify) { XFixesSelectionNotifyEvent *xfEvent = (XFixesSelectionNotifyEvent *) ev; if (xfEvent->subtype == XFixesSetSelectionOwnerNotify && xfEvent->selection == data->sel && xfEvent->owner != None && xfEvent->owner != data->selWindow) { /* TODO: use TARGETS to support non-utf8 clients */ XConvertSelection(dpy, data->sel, data->utf8, data->selProp, data->selWindow, xfEvent->selection_timestamp); } return 1; } else #endif /* HAVE_X11_EXTENSIONS_XFIXES_H */ switch (ev->type) { case SelectionNotify: if (ev->xselection.property != None) { Atom type; int format; unsigned long nitems, size, ignore; unsigned char *prop_ret; XGetWindowProperty(dpy, data->selWindow, data->selProp, 0, 0, False, AnyPropertyType, &type, &format, &nitems, &size, &prop_ret); XFree(prop_ret); if (type == data->incr) { // large data, but INCR not supported yet } else if (size != 0) { XGetWindowProperty(dpy, data->selWindow, data->selProp, 0, size, False, AnyPropertyType, &type, &format, &nitems, &ignore, &prop_ret); update((char*) prop_ret, size); XFree(prop_ret); XDeleteProperty(dpy, data->selWindow, data->selProp); } } return 1; case SelectionClear: update(NULL, 0); return 1; case SelectionRequest: { XSelectionEvent sev; XSelectionRequestEvent *srev = (XSelectionRequestEvent*)&ev->xselectionrequest; if (content && srev->target == data->utf8) { XChangeProperty(dpy, srev->requestor, srev->property, data->utf8, 8, PropModeReplace, (unsigned char*) content, strlen(content)); sev.property = srev->property; } else if (srev->target == data->targetsAtom) { const void *targets = "TARGETS\nUTF8_STRING\n"; XChangeProperty(dpy, srev->requestor, srev->property, data->targetsAtom, 8, PropModeReplace, targets, strlen(targets)); sev.property = srev->property; } else { sev.property = None; } sev.type = SelectionNotify; sev.requestor = srev->requestor; sev.selection = srev->selection; sev.target = srev->target; sev.time = srev->time; XSendEvent(dpy, srev->requestor, True, NoEventMask, (XEvent *) &sev); return 1; } } return 0; }