mirror of https://github.com/buggins/dlangui.git
Merge pull request #471 from FreeSlave/x11_getClipboardText
X11 getClipboardText implementation
This commit is contained in:
commit
709e095d27
|
@ -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,6 +1312,330 @@ class X11Platform : Platform {
|
||||||
return _windowMap.length == 0;
|
return _windowMap.length == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected int numberOfPendingEvents()
|
||||||
|
{
|
||||||
|
import core.sys.posix.sys.select;
|
||||||
|
int x11displayFd = ConnectionNumber(x11display);
|
||||||
|
fd_set fdSet;
|
||||||
|
FD_ZERO(&fdSet);
|
||||||
|
FD_SET(x11displayFd, &fdSet);
|
||||||
|
scope(exit) FD_ZERO(&fdSet);
|
||||||
|
|
||||||
|
int eventsInQueue = XEventsQueued(x11display, QueuedAlready);
|
||||||
|
if (!eventsInQueue) {
|
||||||
|
import core.stdc.errno;
|
||||||
|
int selectResult;
|
||||||
|
do {
|
||||||
|
timeval zeroTime;
|
||||||
|
selectResult = select(x11displayFd + 1, &fdSet, null, null, &zeroTime);
|
||||||
|
} while(selectResult == -1 && errno == EINTR);
|
||||||
|
if (selectResult < 0) {
|
||||||
|
Log.e("X11: display fd select error");
|
||||||
|
} else if (selectResult == 1) {
|
||||||
|
Log.d("X11: XPending");
|
||||||
|
eventsInQueue = XPending(x11display);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return eventsInQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void processXEvent(ref XEvent event)
|
||||||
|
{
|
||||||
|
XComposeStatus compose;
|
||||||
|
switch (event.type) {
|
||||||
|
case ConfigureNotify:
|
||||||
|
X11Window w = findWindow(event.xconfigure.window);
|
||||||
|
if (w) {
|
||||||
|
w._cachedWidth = event.xconfigure.width;
|
||||||
|
w._cachedHeight = event.xconfigure.height;
|
||||||
|
w.handleWindowStateChange(WindowState.unspecified, Rect(event.xconfigure.x, event.xconfigure.y, event.xconfigure.width, event.xconfigure.height));
|
||||||
|
} else {
|
||||||
|
Log.e("ConfigureNotify: Window not found");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PropertyNotify:
|
||||||
|
if (event.xproperty.atom == atom_NET_WM_STATE && event.xproperty.state == PropertyNewValue) {
|
||||||
|
X11Window w = findWindow(event.xproperty.window);
|
||||||
|
if (w) {
|
||||||
|
Atom type;
|
||||||
|
int format;
|
||||||
|
ubyte* properties;
|
||||||
|
c_ulong dataLength, overflow;
|
||||||
|
if (XGetWindowProperty(x11display, event.xproperty.window, atom_NET_WM_STATE,
|
||||||
|
0, int.max/4, False, AnyPropertyType, &type, &format, &dataLength, &overflow, &properties) == 0) {
|
||||||
|
scope(exit) XFree(properties);
|
||||||
|
// check for minimized
|
||||||
|
bool minimized = false;
|
||||||
|
for (int i=0; i < dataLength ; i++) {
|
||||||
|
if (((cast(c_ulong*)properties)[i]) == atom_NET_WM_STATE_HIDDEN) {
|
||||||
|
w.handleWindowStateChange(WindowState.minimized);
|
||||||
|
minimized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!minimized) {
|
||||||
|
bool maximizedH = false;
|
||||||
|
bool maximizedV = false;
|
||||||
|
for (int i=0; i < dataLength ; i++) {
|
||||||
|
if (((cast(c_ulong*)properties)[i]) == atom_NET_WM_STATE_MAXIMIZED_VERT)
|
||||||
|
maximizedV = true;
|
||||||
|
if (((cast(c_ulong*)properties)[i]) == atom_NET_WM_STATE_MAXIMIZED_HORZ)
|
||||||
|
maximizedH = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maximizedV && maximizedH)
|
||||||
|
w.handleWindowStateChange(WindowState.maximized);
|
||||||
|
else
|
||||||
|
w.handleWindowStateChange(WindowState.normal);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MapNotify:
|
||||||
|
X11Window w = findWindow(event.xmap.window);
|
||||||
|
if (w) {
|
||||||
|
w.handleWindowStateChange(WindowState.normal);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case UnmapNotify:
|
||||||
|
X11Window w = findWindow(event.xunmap.window);
|
||||||
|
if (w) {
|
||||||
|
w.handleWindowStateChange(WindowState.hidden);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Expose:
|
||||||
|
if (event.xexpose.count == 0) {
|
||||||
|
X11Window w = findWindow(event.xexpose.window);
|
||||||
|
if (w) {
|
||||||
|
w.invalidate();
|
||||||
|
} else {
|
||||||
|
Log.e("Expose: Window not found");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d("Expose: non-0 count");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KeyPress:
|
||||||
|
Log.d("X11: KeyPress event");
|
||||||
|
X11Window w = findWindow(event.xkey.window);
|
||||||
|
if (w) {
|
||||||
|
char[100] buf;
|
||||||
|
KeySym ks;
|
||||||
|
Status s;
|
||||||
|
if (!w.xic) {
|
||||||
|
w.xic = XCreateIC(xim,
|
||||||
|
XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
|
||||||
|
XNClientWindow, w._win, 0);
|
||||||
|
if (!w.xic) {
|
||||||
|
Log.e("Cannot create input context");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!w.xic)
|
||||||
|
XLookupString(&event.xkey, buf.ptr, buf.length - 1, &ks, &compose);
|
||||||
|
else {
|
||||||
|
Xutf8LookupString(w.xic, &event.xkey, buf.ptr, cast(int)buf.length - 1, &ks, &s);
|
||||||
|
if (s != XLookupChars && s != XLookupBoth)
|
||||||
|
XLookupString(&event.xkey, buf.ptr, buf.length - 1, &ks, &compose);
|
||||||
|
}
|
||||||
|
foreach(ref ch; buf) {
|
||||||
|
if (ch == 255 || ch < 32 || ch == 127)
|
||||||
|
ch = 0;
|
||||||
|
}
|
||||||
|
string txt = fromStringz(buf.ptr).dup;
|
||||||
|
import std.utf;
|
||||||
|
dstring dtext;
|
||||||
|
try {
|
||||||
|
if (txt.length)
|
||||||
|
dtext = toUTF32(txt);
|
||||||
|
} catch (UTFException e) {
|
||||||
|
// ignore, invalid text
|
||||||
|
}
|
||||||
|
debug(x11) Log.d("X11: KeyPress event bytes=", txt.length, " text=", txt, " dtext=", dtext);
|
||||||
|
if (dtext.length) {
|
||||||
|
w.processTextInput(dtext, event.xkey.state);
|
||||||
|
} else {
|
||||||
|
w.processKeyEvent(KeyAction.KeyDown, cast(uint)ks,
|
||||||
|
//event.xkey.keycode,
|
||||||
|
event.xkey.state);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.e("Window not found");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KeyRelease:
|
||||||
|
Log.d("X11: KeyRelease event");
|
||||||
|
X11Window w = findWindow(event.xkey.window);
|
||||||
|
if (w) {
|
||||||
|
char[100] buf;
|
||||||
|
KeySym ks;
|
||||||
|
XLookupString(&event.xkey, buf.ptr, buf.length - 1, &ks, &compose);
|
||||||
|
w.processKeyEvent(KeyAction.KeyUp, cast(uint)ks,
|
||||||
|
//event.xkey.keycode,
|
||||||
|
event.xkey.state);
|
||||||
|
} else {
|
||||||
|
Log.e("Window not found");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ButtonPress:
|
||||||
|
Log.d("X11: ButtonPress event");
|
||||||
|
X11Window w = findWindow(event.xbutton.window);
|
||||||
|
if (w) {
|
||||||
|
w.processMouseEvent(MouseAction.ButtonDown, event.xbutton.button, event.xbutton.state, event.xbutton.x, event.xbutton.y);
|
||||||
|
} else {
|
||||||
|
Log.e("Window not found");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ButtonRelease:
|
||||||
|
Log.d("X11: ButtonRelease event");
|
||||||
|
X11Window w = findWindow(event.xbutton.window);
|
||||||
|
if (w) {
|
||||||
|
w.processMouseEvent(MouseAction.ButtonUp, event.xbutton.button, event.xbutton.state, event.xbutton.x, event.xbutton.y);
|
||||||
|
} else {
|
||||||
|
Log.e("Window not found");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MotionNotify:
|
||||||
|
debug(x11) Log.d("X11: MotionNotify event");
|
||||||
|
X11Window w = findWindow(event.xmotion.window);
|
||||||
|
if (w) {
|
||||||
|
w.processMouseEvent(MouseAction.Move, 0, event.xmotion.state, event.xmotion.x, event.xmotion.y);
|
||||||
|
} else {
|
||||||
|
Log.e("Window not found");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EnterNotify:
|
||||||
|
Log.d("X11: EnterNotify event");
|
||||||
|
X11Window w = findWindow(event.xcrossing.window);
|
||||||
|
if (!w) {
|
||||||
|
Log.e("Window not found");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LeaveNotify:
|
||||||
|
Log.d("X11: LeaveNotify event");
|
||||||
|
X11Window w = findWindow(event.xcrossing.window);
|
||||||
|
if (w) {
|
||||||
|
w.processMouseEvent(MouseAction.Leave, 0, event.xcrossing.state, event.xcrossing.x, event.xcrossing.y);
|
||||||
|
} else {
|
||||||
|
Log.e("Window not found");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CreateNotify:
|
||||||
|
Log.d("X11: CreateNotify event");
|
||||||
|
X11Window w = findWindow(event.xcreatewindow.window);
|
||||||
|
if (!w) {
|
||||||
|
Log.e("Window not found");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DestroyNotify:
|
||||||
|
Log.d("X11: DestroyNotify event");
|
||||||
|
break;
|
||||||
|
case ResizeRequest:
|
||||||
|
Log.d("X11: ResizeRequest event");
|
||||||
|
X11Window w = findWindow(event.xresizerequest.window);
|
||||||
|
if (!w) {
|
||||||
|
Log.e("Window not found");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FocusIn:
|
||||||
|
Log.d("X11: FocusIn event");
|
||||||
|
X11Window w = findWindow(event.xfocus.window);
|
||||||
|
if (w)
|
||||||
|
w.handleWindowActivityChange(true);
|
||||||
|
else
|
||||||
|
Log.e("Window not found");
|
||||||
|
break;
|
||||||
|
case FocusOut:
|
||||||
|
Log.d("X11: FocusOut event");
|
||||||
|
X11Window w = findWindow(event.xfocus.window);
|
||||||
|
if (w)
|
||||||
|
w.handleWindowActivityChange(false);
|
||||||
|
else
|
||||||
|
Log.e("Window not found");
|
||||||
|
break;
|
||||||
|
case KeymapNotify:
|
||||||
|
Log.d("X11: KeymapNotify event");
|
||||||
|
X11Window w = findWindow(event.xkeymap.window);
|
||||||
|
break;
|
||||||
|
case SelectionClear:
|
||||||
|
Log.d("X11: SelectionClear event");
|
||||||
|
break;
|
||||||
|
case SelectionRequest:
|
||||||
|
debug(x11) Log.d("X11: SelectionRequest event");
|
||||||
|
if (event.xselectionrequest.owner in _windowMap) {
|
||||||
|
XSelectionRequestEvent *selectionRequest = &event.xselectionrequest;
|
||||||
|
|
||||||
|
XEvent selectionEvent;
|
||||||
|
memset(&selectionEvent, 0, selectionEvent.sizeof);
|
||||||
|
selectionEvent.xany.type = SelectionNotify;
|
||||||
|
selectionEvent.xselection.selection = selectionRequest.selection;
|
||||||
|
selectionEvent.xselection.target = selectionRequest.target;
|
||||||
|
selectionEvent.xselection.property = None;
|
||||||
|
selectionEvent.xselection.requestor = selectionRequest.requestor;
|
||||||
|
selectionEvent.xselection.time = selectionRequest.time;
|
||||||
|
|
||||||
|
if (selectionRequest.target == XA_STRING || selectionRequest.target == atom_UTF8_STRING) {
|
||||||
|
int currentSelectionFormat;
|
||||||
|
Atom currentSelectionType;
|
||||||
|
c_ulong selectionDataLength, overflow;
|
||||||
|
ubyte* selectionDataPtr;
|
||||||
|
if (XGetWindowProperty(x11display, DefaultRootWindow(x11display), atom_DLANGUI_CLIPBOARD_BUFFER,
|
||||||
|
0, int.max/4, False, selectionRequest.target,
|
||||||
|
¤tSelectionType, ¤tSelectionFormat, &selectionDataLength,
|
||||||
|
&overflow, &selectionDataPtr) == 0)
|
||||||
|
{
|
||||||
|
scope(exit) XFree(selectionDataPtr);
|
||||||
|
XChangeProperty(x11display, selectionRequest.requestor, selectionRequest.property,
|
||||||
|
selectionRequest.target, 8, PropModeReplace,
|
||||||
|
selectionDataPtr, cast(int)selectionDataLength);
|
||||||
|
}
|
||||||
|
selectionEvent.xselection.property = selectionRequest.property;
|
||||||
|
} else if (selectionRequest.target == atom_TARGETS) {
|
||||||
|
Atom[3] supportedFormats = [atom_UTF8_STRING, XA_STRING, atom_TARGETS];
|
||||||
|
XChangeProperty(x11display, selectionRequest.requestor, selectionRequest.property,
|
||||||
|
XA_ATOM, 32, PropModeReplace,
|
||||||
|
cast(ubyte*)supportedFormats.ptr, cast(int)supportedFormats.length);
|
||||||
|
selectionEvent.xselection.property = selectionRequest.property;
|
||||||
|
}
|
||||||
|
XSendEvent(x11display, selectionRequest.requestor, False, 0, &selectionEvent);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SelectionNotify:
|
||||||
|
debug(x11) Log.d("X11: SelectionNotify event");
|
||||||
|
X11Window w = findWindow(event.xselection.requestor);
|
||||||
|
if (w) {
|
||||||
|
waitingForSelection = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ClientMessage:
|
||||||
|
debug(x11) Log.d("X11: ClientMessage event");
|
||||||
|
X11Window w = findWindow(event.xclient.window);
|
||||||
|
if (w) {
|
||||||
|
if (event.xclient.message_type == atom_DLANGUI_TASK_EVENT) {
|
||||||
|
w.handlePostedEvent(cast(uint)event.xclient.data.l[0]);
|
||||||
|
} else if (event.xclient.message_type == atom_DLANGUI_TIMER_EVENT) {
|
||||||
|
w.handleTimer();
|
||||||
|
} else if (event.xclient.message_type == atom_WM_PROTOCOLS) {
|
||||||
|
Log.d("Handling WM_PROTOCOLS");
|
||||||
|
if ((event.xclient.format == 32) && (event.xclient.data.l[0]) == atom_WM_DELETE_WINDOW) {
|
||||||
|
Log.d("Handling WM_DELETE_WINDOW");
|
||||||
|
_windowMap.remove(w._win);
|
||||||
|
destroy(w);
|
||||||
|
}
|
||||||
|
} else if (event.xclient.message_type == atom_DLANGUI_CLOSE_WINDOW_EVENT) {
|
||||||
|
_windowMap.remove(w._win);
|
||||||
|
destroy(w);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.e("Window not found");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts application message loop.
|
* Starts application message loop.
|
||||||
*
|
*
|
||||||
|
@ -1325,14 +1648,7 @@ class X11Platform : Platform {
|
||||||
char[255] text; /* a char buffer for KeyPress Events */
|
char[255] text; /* a char buffer for KeyPress Events */
|
||||||
|
|
||||||
Log.d("enterMessageLoop()");
|
Log.d("enterMessageLoop()");
|
||||||
XComposeStatus compose;
|
|
||||||
|
|
||||||
import core.sys.posix.sys.select;
|
|
||||||
int x11displayFd = ConnectionNumber(x11display);
|
|
||||||
fd_set fdSet;
|
|
||||||
FD_ZERO(&fdSet);
|
|
||||||
FD_SET(x11displayFd, &fdSet);
|
|
||||||
scope(exit) FD_ZERO(&fdSet);
|
|
||||||
while(!allWindowsClosed()) {
|
while(!allWindowsClosed()) {
|
||||||
// Note: only events we set the mask for are detected!
|
// Note: only events we set the mask for are detected!
|
||||||
foreach(win; _windowMap) {
|
foreach(win; _windowMap) {
|
||||||
|
@ -1341,21 +1657,7 @@ class X11Platform : Platform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
XFlush(x11display);
|
XFlush(x11display);
|
||||||
int eventsInQueue = XEventsQueued(x11display, QueuedAlready);
|
int eventsInQueue = numberOfPendingEvents();
|
||||||
if (!eventsInQueue) {
|
|
||||||
import core.stdc.errno;
|
|
||||||
int selectResult;
|
|
||||||
do {
|
|
||||||
timeval zeroTime;
|
|
||||||
selectResult = select(x11displayFd + 1, &fdSet, null, null, &zeroTime);
|
|
||||||
} while(selectResult == -1 && errno == EINTR);
|
|
||||||
if (selectResult < 0) {
|
|
||||||
Log.e("X11: display fd select error");
|
|
||||||
} else if (selectResult == 1) {
|
|
||||||
Log.d("X11: XPending");
|
|
||||||
eventsInQueue = XPending(x11display);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!eventsInQueue) {
|
if (!eventsInQueue) {
|
||||||
debug(x11) Log.d("X11: Sleeping");
|
debug(x11) Log.d("X11: Sleeping");
|
||||||
Thread.sleep(dur!("msecs")(10));
|
Thread.sleep(dur!("msecs")(10));
|
||||||
|
@ -1364,302 +1666,10 @@ class X11Platform : Platform {
|
||||||
{
|
{
|
||||||
if (allWindowsClosed())
|
if (allWindowsClosed())
|
||||||
break;
|
break;
|
||||||
|
if (!numberOfPendingEvents())
|
||||||
|
break;
|
||||||
XNextEvent(x11display, &event);
|
XNextEvent(x11display, &event);
|
||||||
switch (event.type) {
|
processXEvent(event);
|
||||||
case ConfigureNotify:
|
|
||||||
X11Window w = findWindow(event.xconfigure.window);
|
|
||||||
if (w) {
|
|
||||||
w._cachedWidth = event.xconfigure.width;
|
|
||||||
w._cachedHeight = event.xconfigure.height;
|
|
||||||
w.handleWindowStateChange(WindowState.unspecified, Rect(event.xconfigure.x, event.xconfigure.y, event.xconfigure.width, event.xconfigure.height));
|
|
||||||
} else {
|
|
||||||
Log.e("ConfigureNotify: Window not found");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PropertyNotify:
|
|
||||||
if (event.xproperty.atom == atom_NET_WM_STATE && event.xproperty.state == PropertyNewValue) {
|
|
||||||
X11Window w = findWindow(event.xproperty.window);
|
|
||||||
if (w) {
|
|
||||||
Atom type;
|
|
||||||
int format;
|
|
||||||
ubyte* properties;
|
|
||||||
c_ulong dataLength, overflow;
|
|
||||||
if (XGetWindowProperty(x11display, event.xproperty.window, atom_NET_WM_STATE,
|
|
||||||
0, int.max/4, False, AnyPropertyType, &type, &format, &dataLength, &overflow, &properties) == 0) {
|
|
||||||
scope(exit) XFree(properties);
|
|
||||||
// check for minimized
|
|
||||||
bool minimized = false;
|
|
||||||
for (int i=0; i < dataLength ; i++) {
|
|
||||||
if (((cast(c_ulong*)properties)[i]) == atom_NET_WM_STATE_HIDDEN) {
|
|
||||||
w.handleWindowStateChange(WindowState.minimized);
|
|
||||||
minimized = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!minimized) {
|
|
||||||
bool maximizedH = false;
|
|
||||||
bool maximizedV = false;
|
|
||||||
for (int i=0; i < dataLength ; i++) {
|
|
||||||
if (((cast(c_ulong*)properties)[i]) == atom_NET_WM_STATE_MAXIMIZED_VERT)
|
|
||||||
maximizedV = true;
|
|
||||||
if (((cast(c_ulong*)properties)[i]) == atom_NET_WM_STATE_MAXIMIZED_HORZ)
|
|
||||||
maximizedH = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maximizedV && maximizedH)
|
|
||||||
w.handleWindowStateChange(WindowState.maximized);
|
|
||||||
else
|
|
||||||
w.handleWindowStateChange(WindowState.normal);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MapNotify:
|
|
||||||
X11Window w = findWindow(event.xmap.window);
|
|
||||||
if (w) {
|
|
||||||
w.handleWindowStateChange(WindowState.normal);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case UnmapNotify:
|
|
||||||
X11Window w = findWindow(event.xunmap.window);
|
|
||||||
if (w) {
|
|
||||||
w.handleWindowStateChange(WindowState.hidden);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Expose:
|
|
||||||
if (event.xexpose.count == 0) {
|
|
||||||
X11Window w = findWindow(event.xexpose.window);
|
|
||||||
if (w) {
|
|
||||||
w.invalidate();
|
|
||||||
} else {
|
|
||||||
Log.e("Expose: Window not found");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d("Expose: non-0 count");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KeyPress:
|
|
||||||
Log.d("X11: KeyPress event");
|
|
||||||
X11Window w = findWindow(event.xkey.window);
|
|
||||||
if (w) {
|
|
||||||
char[100] buf;
|
|
||||||
KeySym ks;
|
|
||||||
Status s;
|
|
||||||
if (!w.xic) {
|
|
||||||
w.xic = XCreateIC(xim,
|
|
||||||
XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
|
|
||||||
XNClientWindow, w._win, 0);
|
|
||||||
if (!w.xic) {
|
|
||||||
Log.e("Cannot create input context");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!w.xic)
|
|
||||||
XLookupString(&event.xkey, buf.ptr, buf.length - 1, &ks, &compose);
|
|
||||||
else {
|
|
||||||
Xutf8LookupString(w.xic, &event.xkey, buf.ptr, cast(int)buf.length - 1, &ks, &s);
|
|
||||||
if (s != XLookupChars && s != XLookupBoth)
|
|
||||||
XLookupString(&event.xkey, buf.ptr, buf.length - 1, &ks, &compose);
|
|
||||||
}
|
|
||||||
foreach(ref ch; buf) {
|
|
||||||
if (ch == 255 || ch < 32 || ch == 127)
|
|
||||||
ch = 0;
|
|
||||||
}
|
|
||||||
string txt = fromStringz(buf.ptr).dup;
|
|
||||||
import std.utf;
|
|
||||||
dstring dtext;
|
|
||||||
try {
|
|
||||||
if (txt.length)
|
|
||||||
dtext = toUTF32(txt);
|
|
||||||
} catch (UTFException e) {
|
|
||||||
// ignore, invalid text
|
|
||||||
}
|
|
||||||
debug(x11) Log.d("X11: KeyPress event bytes=", txt.length, " text=", txt, " dtext=", dtext);
|
|
||||||
if (dtext.length) {
|
|
||||||
w.processTextInput(dtext, event.xkey.state);
|
|
||||||
} else {
|
|
||||||
w.processKeyEvent(KeyAction.KeyDown, cast(uint)ks,
|
|
||||||
//event.xkey.keycode,
|
|
||||||
event.xkey.state);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.e("Window not found");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KeyRelease:
|
|
||||||
Log.d("X11: KeyRelease event");
|
|
||||||
X11Window w = findWindow(event.xkey.window);
|
|
||||||
if (w) {
|
|
||||||
char[100] buf;
|
|
||||||
KeySym ks;
|
|
||||||
XLookupString(&event.xkey, buf.ptr, buf.length - 1, &ks, &compose);
|
|
||||||
w.processKeyEvent(KeyAction.KeyUp, cast(uint)ks,
|
|
||||||
//event.xkey.keycode,
|
|
||||||
event.xkey.state);
|
|
||||||
} else {
|
|
||||||
Log.e("Window not found");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ButtonPress:
|
|
||||||
Log.d("X11: ButtonPress event");
|
|
||||||
X11Window w = findWindow(event.xbutton.window);
|
|
||||||
if (w) {
|
|
||||||
w.processMouseEvent(MouseAction.ButtonDown, event.xbutton.button, event.xbutton.state, event.xbutton.x, event.xbutton.y);
|
|
||||||
} else {
|
|
||||||
Log.e("Window not found");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ButtonRelease:
|
|
||||||
Log.d("X11: ButtonRelease event");
|
|
||||||
X11Window w = findWindow(event.xbutton.window);
|
|
||||||
if (w) {
|
|
||||||
w.processMouseEvent(MouseAction.ButtonUp, event.xbutton.button, event.xbutton.state, event.xbutton.x, event.xbutton.y);
|
|
||||||
} else {
|
|
||||||
Log.e("Window not found");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MotionNotify:
|
|
||||||
debug(x11) Log.d("X11: MotionNotify event");
|
|
||||||
X11Window w = findWindow(event.xmotion.window);
|
|
||||||
if (w) {
|
|
||||||
w.processMouseEvent(MouseAction.Move, 0, event.xmotion.state, event.xmotion.x, event.xmotion.y);
|
|
||||||
} else {
|
|
||||||
Log.e("Window not found");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EnterNotify:
|
|
||||||
Log.d("X11: EnterNotify event");
|
|
||||||
X11Window w = findWindow(event.xcrossing.window);
|
|
||||||
if (!w) {
|
|
||||||
Log.e("Window not found");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case LeaveNotify:
|
|
||||||
Log.d("X11: LeaveNotify event");
|
|
||||||
X11Window w = findWindow(event.xcrossing.window);
|
|
||||||
if (w) {
|
|
||||||
w.processMouseEvent(MouseAction.Leave, 0, event.xcrossing.state, event.xcrossing.x, event.xcrossing.y);
|
|
||||||
} else {
|
|
||||||
Log.e("Window not found");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CreateNotify:
|
|
||||||
Log.d("X11: CreateNotify event");
|
|
||||||
X11Window w = findWindow(event.xcreatewindow.window);
|
|
||||||
if (!w) {
|
|
||||||
Log.e("Window not found");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DestroyNotify:
|
|
||||||
Log.d("X11: DestroyNotify event");
|
|
||||||
break;
|
|
||||||
case ResizeRequest:
|
|
||||||
Log.d("X11: ResizeRequest event");
|
|
||||||
X11Window w = findWindow(event.xresizerequest.window);
|
|
||||||
if (!w) {
|
|
||||||
Log.e("Window not found");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FocusIn:
|
|
||||||
Log.d("X11: FocusIn event");
|
|
||||||
X11Window w = findWindow(event.xfocus.window);
|
|
||||||
if (w)
|
|
||||||
w.handleWindowActivityChange(true);
|
|
||||||
else
|
|
||||||
Log.e("Window not found");
|
|
||||||
break;
|
|
||||||
case FocusOut:
|
|
||||||
Log.d("X11: FocusOut event");
|
|
||||||
X11Window w = findWindow(event.xfocus.window);
|
|
||||||
if (w)
|
|
||||||
w.handleWindowActivityChange(false);
|
|
||||||
else
|
|
||||||
Log.e("Window not found");
|
|
||||||
break;
|
|
||||||
case KeymapNotify:
|
|
||||||
Log.d("X11: KeymapNotify event");
|
|
||||||
X11Window w = findWindow(event.xkeymap.window);
|
|
||||||
break;
|
|
||||||
case SelectionClear:
|
|
||||||
Log.d("X11: SelectionClear event");
|
|
||||||
break;
|
|
||||||
case SelectionRequest:
|
|
||||||
debug(x11) Log.d("X11: SelectionRequest event");
|
|
||||||
if (event.xselectionrequest.owner in _windowMap) {
|
|
||||||
XSelectionRequestEvent *selectionRequest = &event.xselectionrequest;
|
|
||||||
|
|
||||||
XEvent selectionEvent;
|
|
||||||
memset(&selectionEvent, 0, selectionEvent.sizeof);
|
|
||||||
selectionEvent.xany.type = SelectionNotify;
|
|
||||||
selectionEvent.xselection.selection = selectionRequest.selection;
|
|
||||||
selectionEvent.xselection.target = selectionRequest.target;
|
|
||||||
selectionEvent.xselection.property = None;
|
|
||||||
selectionEvent.xselection.requestor = selectionRequest.requestor;
|
|
||||||
selectionEvent.xselection.time = selectionRequest.time;
|
|
||||||
|
|
||||||
if (selectionRequest.target == XA_STRING || selectionRequest.target == atom_UTF8_STRING) {
|
|
||||||
static if (false) {
|
|
||||||
int currentSelectionFormat;
|
|
||||||
Atom currentSelectionType;
|
|
||||||
c_ulong selectionDataLength, overflow;
|
|
||||||
ubyte* selectionDataPtr;
|
|
||||||
if (XGetWindowProperty(x11display, DefaultRootWindow(x11display), atom_DLANGUI_CLIPBOARD_BUFFER,
|
|
||||||
0, int.max/4, False, selectionRequest.target,
|
|
||||||
¤tSelectionType, ¤tSelectionFormat, &selectionDataLength,
|
|
||||||
&overflow, &selectionDataPtr) == 0)
|
|
||||||
{
|
|
||||||
scope(exit) XFree(selectionDataPtr);
|
|
||||||
XChangeProperty(x11display, selectionRequest.requestor, selectionRequest.property,
|
|
||||||
selectionRequest.target, 8, PropModeReplace,
|
|
||||||
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;
|
|
||||||
} else if (selectionRequest.target == atom_TARGETS) {
|
|
||||||
Atom[3] supportedFormats = [atom_UTF8_STRING, XA_STRING, atom_TARGETS];
|
|
||||||
XChangeProperty(x11display, selectionRequest.requestor, selectionRequest.property,
|
|
||||||
XA_ATOM, 32, PropModeReplace,
|
|
||||||
cast(ubyte*)supportedFormats.ptr, cast(int)supportedFormats.length);
|
|
||||||
selectionEvent.xselection.property = selectionRequest.property;
|
|
||||||
}
|
|
||||||
XSendEvent(x11display, selectionRequest.requestor, False, 0, &selectionEvent);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SelectionNotify:
|
|
||||||
Log.d("X11: SelectionNotify event");
|
|
||||||
X11Window w = findWindow(event.xselection.requestor);
|
|
||||||
break;
|
|
||||||
case ClientMessage:
|
|
||||||
debug(x11) Log.d("X11: ClientMessage event");
|
|
||||||
X11Window w = findWindow(event.xclient.window);
|
|
||||||
if (w) {
|
|
||||||
if (event.xclient.message_type == atom_DLANGUI_TASK_EVENT) {
|
|
||||||
w.handlePostedEvent(cast(uint)event.xclient.data.l[0]);
|
|
||||||
} else if (event.xclient.message_type == atom_DLANGUI_TIMER_EVENT) {
|
|
||||||
w.handleTimer();
|
|
||||||
} else if (event.xclient.message_type == atom_WM_PROTOCOLS) {
|
|
||||||
Log.d("Handling WM_PROTOCOLS");
|
|
||||||
if ((event.xclient.format == 32) && (event.xclient.data.l[0]) == atom_WM_DELETE_WINDOW) {
|
|
||||||
Log.d("Handling WM_DELETE_WINDOW");
|
|
||||||
_windowMap.remove(w._win);
|
|
||||||
destroy(w);
|
|
||||||
}
|
|
||||||
} else if (event.xclient.message_type == atom_DLANGUI_CLOSE_WINDOW_EVENT) {
|
|
||||||
_windowMap.remove(w._win);
|
|
||||||
destroy(w);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.e("Window not found");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1667,21 +1677,80 @@ class X11Platform : Platform {
|
||||||
|
|
||||||
/// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue