Avoid code duplication when processing x11 events. Add redraw events for x11 (similarly to sdl2 redraw events), simplify event loop. Remove sleep and use select timeout instead

This commit is contained in:
Roman Chistokhodov 2017-10-07 22:36:44 +03:00
parent 4c6cc85481
commit 5fb0a14945
1 changed files with 40 additions and 49 deletions

View File

@ -101,6 +101,7 @@ private __gshared
Atom atom_DLANGUI_TASK_EVENT;
Atom atom_DLANGUI_CLOSE_WINDOW_EVENT;
Atom atom_DLANGUI_CLIPBOARD_BUFFER;
Atom atom_DLANGUI_REDRAW_EVENT;
}
static void setupX11Atoms()
@ -127,6 +128,7 @@ static void setupX11Atoms()
atom_DLANGUI_TASK_EVENT = XInternAtom(x11display, "DLANGUI_TASK_EVENT", False);
atom_DLANGUI_CLOSE_WINDOW_EVENT = XInternAtom(x11display, "DLANGUI_CLOSE_WINDOW_EVENT", False);
atom_DLANGUI_CLIPBOARD_BUFFER = XInternAtom(x11display, "DLANGUI_CLIPBOARD_BUFFER", False);
atom_DLANGUI_REDRAW_EVENT = XInternAtom(x11display, "DLANGUI_REDRAW_EVENT", False);
}
// Cursor font constants
@ -254,7 +256,6 @@ class X11Window : DWindow {
X11Window[] _children;
X11Window _parent;
bool _needRedraw;
int _cachedWidth, _cachedHeight;
static if (ENABLE_OPENGL) {
@ -661,12 +662,18 @@ class X11Window : DWindow {
XChangeProperty(x11display, _win, atom_NET_WM_ICON, XA_CARDINAL, 32, PropModeReplace, cast(ubyte*)propData.ptr, cast(int)propData.length);
}
uint _lastRedrawEventCode;
/// request window redraw
override void invalidate() {
if (!_needRedraw) {
debug(x11) Log.d("Window.invalidate()");
_needRedraw = true;
}
XEvent ev;
ev.xclient.type = ClientMessage;
ev.xclient.message_type = atom_DLANGUI_REDRAW_EVENT;
ev.xclient.window = _win;
ev.xclient.display = x11display;
ev.xclient.format = 32;
ev.xclient.data.l[0] = ++_lastRedrawEventCode;
XSendEvent(x11display, _win, false, StructureNotifyMask, &ev);
XFlush(x11display);
}
/// close window
@ -738,7 +745,7 @@ class X11Window : DWindow {
}
void redraw() {
_needRedraw = false;
_lastRedrawEventCode = 0;
//Use values cached by ConfigureNotify to avoid XGetWindowAttributes call.
//XWindowAttributes window_attributes_return;
//XGetWindowAttributes(x11display, _win, &window_attributes_return);
@ -1335,7 +1342,7 @@ class X11Platform : Platform {
return _windowMap.length == 0;
}
protected int numberOfPendingEvents()
protected int numberOfPendingEvents(int msecs = 10)
{
import core.sys.posix.sys.select;
int x11displayFd = ConnectionNumber(x11display);
@ -1349,13 +1356,14 @@ class X11Platform : Platform {
import core.stdc.errno;
int selectResult;
do {
timeval zeroTime;
selectResult = select(x11displayFd + 1, &fdSet, null, null, &zeroTime);
timeval timeout;
timeout.tv_usec = msecs;
selectResult = select(x11displayFd + 1, &fdSet, null, null, &timeout);
} while(selectResult == -1 && errno == EINTR);
if (selectResult < 0) {
Log.e("X11: display fd select error");
} else if (selectResult == 1) {
Log.d("X11: XPending");
//Log.d("X11: XPending");
eventsInQueue = XPending(x11display);
}
}
@ -1531,7 +1539,9 @@ class X11Platform : Platform {
case EnterNotify:
Log.d("X11: EnterNotify event");
X11Window w = findWindow(event.xcrossing.window);
if (!w) {
if (w) {
w.processMouseEvent(MouseAction.Move, 0, event.xmotion.state, event.xcrossing.x, event.xcrossing.y);
} else {
Log.e("Window not found");
}
break;
@ -1639,6 +1649,9 @@ class X11Platform : Platform {
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_DLANGUI_REDRAW_EVENT) {
if (event.xclient.data.l[0] == w._lastRedrawEventCode)
w.redraw();
} 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) {
@ -1659,41 +1672,30 @@ class X11Platform : Platform {
}
}
protected void pumpEvents()
{
XFlush(x11display);
// Note: only events we set the mask for are detected!
while(numberOfPendingEvents())
{
if (allWindowsClosed())
break;
XEvent event; /* the XEvent declaration !!! */
XNextEvent(x11display, &event);
processXEvent(event);
}
}
/**
* 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);
}
pumpEvents();
}
return 0;
}
@ -1733,18 +1735,7 @@ class X11Platform : Platform {
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);
}
pumpEvents();
}
Atom selectionTarget;
int selectionFormat;