I've done some digging around trying to get a bear minimum program that lets me set whatever value that I want in the clipboard via X11. From my limited understanding X11 is a client-server setup. And much like how some other technology functions, such as MySql, to get the data structures you want you need to loop through a queue of sorts.
Admittedly I don't fully grasp what's happening behind the scenes and this code is most likely is unreliable; but you can still use it to study and figure it out.
Tested on Linux Mint Cinnamon
// g++ -o clipboard test.cc -lX11 -lXmu
// |-->libxmu-dev
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xmu/Atoms.h>
#include <string>
bool writeX11Clipboard(std::string dest){
if(dest.length() <= 0){
return false;
}
// init X11 display and window.
Display *display = XOpenDisplay(NULL);
unsigned long color = BlackPixel(display, DefaultScreen(display));
Window window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0,0, 1,1, 0, color, color);
// Copy string into an unsigned char array, may be able to just typecast.
size_t destSize = dest.length();
unsigned char *copyData = new unsigned char[destSize];
int copyDataLen = destSize;
for(int i=0; i<copyDataLen; i++){
copyData[i] = (unsigned char)dest[i];
}
// Pre-iteration preperations...
XEvent event;
Atom selection = XA_CLIPBOARD(display);
Atom target = XA_UTF8_STRING(display);
XSelectInput(display, window, PropertyChangeMask);
XSetSelectionOwner(display, selection, window, CurrentTime);
Window requestor_id;
/*
* Loop over a few events.
* The first 3 appears to require sending information regarding the previous event to the X11 Server.
* On the 4th iteration the event that allows you to write into the clipboard appears to become usable.
* */
for(int i=0; i<4; i++){
XNextEvent(display, &event);
if(event.type == SelectionRequest){
requestor_id = event.xselectionrequest.requestor;
}else{
XDestroyWindow(display, window);
XCloseDisplay(display);
return false;
}
XEvent eventResponse;
Atom inc;
Atom targets;
targets = XInternAtom(display, "TARGETS", False);
inc = XInternAtom(display, "INCR", False);
if (event.xselectionrequest.target == targets) {
// These operations will allow the code to continue iterating through events.
Atom types[2] = { targets, XA_UTF8_STRING(display) };
XChangeProperty(display,
event.xselectionrequest.requestor,
event.xselectionrequest.property,
XA_ATOM,
32, PropModeReplace, (unsigned char *) types,
(int) (sizeof(types) / sizeof(Atom))
);
}else{
// This is what actually sets the clipboard data.
XChangeProperty(display,
event.xselectionrequest.requestor,
event.xselectionrequest.property,
XA_UTF8_STRING(display),
8, PropModeReplace, (unsigned char *) copyData,
(int) copyDataLen);
}
// Create a X11 event packet and send it to the server.
eventResponse.xselection.property = event.xselectionrequest.property;
eventResponse.xselection.type = SelectionNotify;
eventResponse.xselection.display = event.xselectionrequest.display;
eventResponse.xselection.requestor = event.xselectionrequest.requestor;
eventResponse.xselection.selection = event.xselectionrequest.selection;
eventResponse.xselection.target = event.xselectionrequest.target;
eventResponse.xselection.time = event.xselectionrequest.time;
XSendEvent(display, event.xselectionrequest.requestor, 0, 0, &eventResponse);
XFlush(display);
}
// Clean up.
XDestroyWindow(display, window);
XCloseDisplay(display);
return true;
}
int main(int argc, char *argv[]){
if(argc != 2)
return 1;
writeX11Clipboard(argv[1]);
return 0;
}
Usage:
morningstar@starmorning:: ~/Documents/tests 8=D~ ./clipboard "my test"
Ctrl+Shift+V
morningstar@starmorning:: ~/Documents/tests 8=D~ my test