Merge pull request #471 from FreeSlave/x11_getClipboardText

X11 getClipboardText implementation
This commit is contained in:
Vadim Lopatin 2017-10-03 22:03:43 +03:00 committed by GitHub
commit 709e095d27
1 changed files with 395 additions and 330 deletions

View File

@ -73,7 +73,6 @@ private __gshared
int x11screen; int x11screen;
XIM xim; XIM xim;
string localClipboardContent;
bool _enableOpengl = false; bool _enableOpengl = false;
Cursor[CursorType.Hand + 1] x11cursors; Cursor[CursorType.Hand + 1] x11cursors;
@ -1313,34 +1312,15 @@ class X11Platform : Platform {
return _windowMap.length == 0; return _windowMap.length == 0;
} }
/** protected int numberOfPendingEvents()
* Starts application message loop. {
*
* When returned from this method, application is shutting down.
*/
override int enterMessageLoop() {
import core.thread;
XEvent event; /* the XEvent declaration !!! */
KeySym key; /* a dealie-bob to handle KeyPress Events */
char[255] text; /* a char buffer for KeyPress Events */
Log.d("enterMessageLoop()");
XComposeStatus compose;
import core.sys.posix.sys.select; import core.sys.posix.sys.select;
int x11displayFd = ConnectionNumber(x11display); int x11displayFd = ConnectionNumber(x11display);
fd_set fdSet; fd_set fdSet;
FD_ZERO(&fdSet); FD_ZERO(&fdSet);
FD_SET(x11displayFd, &fdSet); FD_SET(x11displayFd, &fdSet);
scope(exit) FD_ZERO(&fdSet); scope(exit) FD_ZERO(&fdSet);
while(!allWindowsClosed()) {
// Note: only events we set the mask for are detected!
foreach(win; _windowMap) {
if (win._needRedraw) {
win.redraw();
}
}
XFlush(x11display);
int eventsInQueue = XEventsQueued(x11display, QueuedAlready); int eventsInQueue = XEventsQueued(x11display, QueuedAlready);
if (!eventsInQueue) { if (!eventsInQueue) {
import core.stdc.errno; import core.stdc.errno;
@ -1356,15 +1336,12 @@ class X11Platform : Platform {
eventsInQueue = XPending(x11display); eventsInQueue = XPending(x11display);
} }
} }
if (!eventsInQueue) { return eventsInQueue;
debug(x11) Log.d("X11: Sleeping");
Thread.sleep(dur!("msecs")(10));
} }
foreach(eventIndex; 0..eventsInQueue)
protected void processXEvent(ref XEvent event)
{ {
if (allWindowsClosed()) XComposeStatus compose;
break;
XNextEvent(x11display, &event);
switch (event.type) { switch (event.type) {
case ConfigureNotify: case ConfigureNotify:
X11Window w = findWindow(event.xconfigure.window); X11Window w = findWindow(event.xconfigure.window);
@ -1599,7 +1576,6 @@ class X11Platform : Platform {
selectionEvent.xselection.time = selectionRequest.time; selectionEvent.xselection.time = selectionRequest.time;
if (selectionRequest.target == XA_STRING || selectionRequest.target == atom_UTF8_STRING) { if (selectionRequest.target == XA_STRING || selectionRequest.target == atom_UTF8_STRING) {
static if (false) {
int currentSelectionFormat; int currentSelectionFormat;
Atom currentSelectionType; Atom currentSelectionType;
c_ulong selectionDataLength, overflow; c_ulong selectionDataLength, overflow;
@ -1614,11 +1590,6 @@ class X11Platform : Platform {
selectionRequest.target, 8, PropModeReplace, selectionRequest.target, 8, PropModeReplace,
selectionDataPtr, cast(int)selectionDataLength); selectionDataPtr, cast(int)selectionDataLength);
} }
} else {
XChangeProperty(x11display, selectionRequest.requestor, selectionRequest.property,
selectionRequest.target, 8, PropModeReplace,
cast(ubyte*)localClipboardContent, cast(int)localClipboardContent.length);
}
selectionEvent.xselection.property = selectionRequest.property; selectionEvent.xselection.property = selectionRequest.property;
} else if (selectionRequest.target == atom_TARGETS) { } else if (selectionRequest.target == atom_TARGETS) {
Atom[3] supportedFormats = [atom_UTF8_STRING, XA_STRING, atom_TARGETS]; Atom[3] supportedFormats = [atom_UTF8_STRING, XA_STRING, atom_TARGETS];
@ -1631,8 +1602,11 @@ class X11Platform : Platform {
} }
break; break;
case SelectionNotify: case SelectionNotify:
Log.d("X11: SelectionNotify event"); debug(x11) Log.d("X11: SelectionNotify event");
X11Window w = findWindow(event.xselection.requestor); X11Window w = findWindow(event.xselection.requestor);
if (w) {
waitingForSelection = false;
}
break; break;
case ClientMessage: case ClientMessage:
debug(x11) Log.d("X11: ClientMessage event"); debug(x11) Log.d("X11: ClientMessage event");
@ -1661,27 +1635,122 @@ class X11Platform : Platform {
break; break;
} }
} }
/**
* Starts application message loop.
*
* When returned from this method, application is shutting down.
*/
override int enterMessageLoop() {
import core.thread;
XEvent event; /* the XEvent declaration !!! */
KeySym key; /* a dealie-bob to handle KeyPress Events */
char[255] text; /* a char buffer for KeyPress Events */
Log.d("enterMessageLoop()");
while(!allWindowsClosed()) {
// Note: only events we set the mask for are detected!
foreach(win; _windowMap) {
if (win._needRedraw) {
win.redraw();
}
}
XFlush(x11display);
int eventsInQueue = numberOfPendingEvents();
if (!eventsInQueue) {
debug(x11) Log.d("X11: Sleeping");
Thread.sleep(dur!("msecs")(10));
}
foreach(eventIndex; 0..eventsInQueue)
{
if (allWindowsClosed())
break;
if (!numberOfPendingEvents())
break;
XNextEvent(x11display, &event);
processXEvent(event);
}
} }
return 0; return 0;
} }
/// check has clipboard text /// check has clipboard text
override bool hasClipboardText(bool mouseBuffer = false) { override bool hasClipboardText(bool mouseBuffer = false) {
return (localClipboardContent.length != 0); const selectionType = mouseBuffer ? XA_PRIMARY : atom_CLIPBOARD;
return XGetSelectionOwner(x11display, selectionType) != None;
} }
protected bool waitingForSelection;
/// retrieves text from clipboard (when mouseBuffer == true, use mouse selection clipboard - under linux) /// retrieves text from clipboard (when mouseBuffer == true, use mouse selection clipboard - under linux)
override dstring getClipboardText(bool mouseBuffer = false) { override dstring getClipboardText(bool mouseBuffer = false) {
return toUTF32(localClipboardContent); const selectionType = mouseBuffer ? XA_PRIMARY : atom_CLIPBOARD;
auto owner = XGetSelectionOwner(x11display, selectionType);
if (owner == None) {
Log.d("Selection owner is none");
return ""d;
} else {
// Find any top-level window
XWindow xwindow;
foreach(w; _windowMap) {
if (w._parent is null && w._win != None) {
xwindow = w._win;
break;
}
}
if (xwindow != None) {
import std.datetime;
waitingForSelection = true;
XConvertSelection(x11display, selectionType, atom_UTF8_STRING, atom_DLANGUI_CLIPBOARD_BUFFER, xwindow, CurrentTime);
auto stopWaiting = Clock.currTime() + dur!"msecs"(500);
while(waitingForSelection) {
if (stopWaiting <= Clock.currTime()) {
waitingForSelection = false;
setClipboardText(""d);
Log.e("Waiting for clipboard contents timeout");
return ""d;
}
XFlush(x11display);
int eventsInQueue = numberOfPendingEvents();
foreach(eventIndex; 0..eventsInQueue)
{
if (allWindowsClosed())
break;
if (!numberOfPendingEvents())
break;
XEvent event;
XNextEvent(x11display, &event);
processXEvent(event);
}
}
Atom selectionTarget;
int selectionFormat;
c_ulong selectionDataLength, overflow;
ubyte* selectionDataPtr;
if (XGetWindowProperty(x11display, xwindow, atom_DLANGUI_CLIPBOARD_BUFFER, 0, int.max/4, False, 0, &selectionTarget, &selectionFormat, &selectionDataLength, &overflow, &selectionDataPtr) == 0)
{
scope(exit) XFree(selectionDataPtr);
if (selectionTarget == XA_STRING || selectionTarget == atom_UTF8_STRING) {
char[] selectionText = cast(char[])selectionDataPtr[0..selectionDataLength];
return toUTF32(selectionText);
} else {
Log.d("Selection type is not a string!");
}
}
} else {
Log.d("Could not find any window to get selection");
}
}
return ""d;
} }
/// sets text to clipboard (when mouseBuffer == true, use mouse selection clipboard - under linux) /// sets text to clipboard (when mouseBuffer == true, use mouse selection clipboard - under linux)
override void setClipboardText(dstring text, bool mouseBuffer = false) { override void setClipboardText(dstring text, bool mouseBuffer = false) {
localClipboardContent = toUTF8(text);
if (!mouseBuffer && atom_CLIPBOARD == None) { if (!mouseBuffer && atom_CLIPBOARD == None) {
Log.e("No CLIPBOARD atom available"); Log.e("No CLIPBOARD atom available");
return; return;
} }
auto selection = mouseBuffer ? XA_PRIMARY : atom_CLIPBOARD;
XWindow xwindow = None; XWindow xwindow = None;
// Find any top-level window // Find any top-level window
foreach(w; _windowMap) { foreach(w; _windowMap) {
@ -1693,16 +1762,12 @@ class X11Platform : Platform {
Log.e("Could not find window to save clipboard text"); Log.e("Could not find window to save clipboard text");
return; return;
} }
static if (false) {
// This is example of how setting clipboard contents can be implemented without global variable
auto textc = text.toUTF8;
XChangeProperty(x11display, DefaultRootWindow(x11display), atom_DLANGUI_CLIPBOARD_BUFFER, XA_STRING, 8, PropModeReplace, cast(ubyte*)textc.ptr, cast(int)textc.length);
}
if (mouseBuffer && XGetSelectionOwner(x11display, XA_PRIMARY) != xwindow) { auto textc = text.toUTF8;
XSetSelectionOwner(x11display, XA_PRIMARY, xwindow, CurrentTime); XChangeProperty(x11display, DefaultRootWindow(x11display), atom_DLANGUI_CLIPBOARD_BUFFER, atom_UTF8_STRING, 8, PropModeReplace, cast(ubyte*)textc.ptr, cast(int)textc.length);
} else if (XGetSelectionOwner(x11display, atom_CLIPBOARD != xwindow)) {
XSetSelectionOwner(x11display, atom_CLIPBOARD, xwindow, CurrentTime); if (XGetSelectionOwner(x11display, selection) != xwindow) {
XSetSelectionOwner(x11display, selection, xwindow, CurrentTime);
} }
} }