blob: e09d7b33d9ae361c37cbb2171e84071243ca1174 [file] [log] [blame] [edit]
/*
* 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-2023 by Samuel Thibault <Samuel.Thibault@ens-lyon.org>
*
* 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 <dave@mielke.cc>.
*/
#include "prologue.h"
#include <string.h>
#include "xsel.h"
#include <X11/Xatom.h>
#ifdef HAVE_X11_EXTENSIONS_XFIXES_H
#include <X11/extensions/Xfixes.h>
#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 */
/* TODO: get initial clipboard value on startup */
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) {
Atom targets[] = { data->targetsAtom, data->utf8 };
XChangeProperty(dpy, srev->requestor, srev->property, XA_ATOM, 32, PropModeReplace, (unsigned char*) targets, sizeof(targets)/sizeof(*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;
}