optional use of arsd.eventloop on X/Linux

This commit is contained in:
Adam D. Ruppe 2013-06-07 11:22:23 -04:00
parent ca5ea9d0f7
commit d1beb29cd4
1 changed files with 113 additions and 60 deletions

View File

@ -38,7 +38,8 @@ struct Size {
struct KeyEvent { struct KeyEvent {
uint keycode;
bool pressed;
} }
struct MouseEvent { struct MouseEvent {
@ -902,6 +903,7 @@ version(X11) {
XCopyArea(display, d, destiny, gc, 0, 0, this.window.width, this.window.height, 0, 0); XCopyArea(display, d, destiny, gc, 0, 0, this.window.width, this.window.height, 0, 0);
XFreeGC(display, gc); XFreeGC(display, gc);
XFlush(display);
} }
bool backgroundIsNotTransparent = true; bool backgroundIsNotTransparent = true;
@ -1020,14 +1022,38 @@ version(X11) {
class XDisplayConnection { class XDisplayConnection {
private static Display* display; private static Display* display;
static Display* get() { static Display* get(SimpleWindow window = null) {
if(display is null) // FIXME: this shouldn't even be necessary
version(with_eventloop)
if(window !is null)
this.window = window;
if(display is null) {
display = enforce(XOpenDisplay(null)); display = enforce(XOpenDisplay(null));
version(with_eventloop) {
import arsd.eventloop;
addFileEventListeners(display.fd, &eventListener, null, null);
}
}
return display; return display;
} }
version(with_eventloop) {
import arsd.eventloop;
static void eventListener(OsFileHandle fd) {
while(XPending(display))
doXNextEvent(window);
}
static SimpleWindow window;
}
static void close() { static void close() {
version(with_eventloop) {
import arsd.eventloop;
removeFileEventListeners(display.fd);
}
XCloseDisplay(display); XCloseDisplay(display);
display = null; display = null;
} }
@ -1098,7 +1124,7 @@ version(X11) {
} }
void createWindow(int width, int height, string title) { void createWindow(int width, int height, string title) {
display = XDisplayConnection.get(); display = XDisplayConnection.get(this);
auto screen = DefaultScreen(display); auto screen = DefaultScreen(display);
window = XCreateSimpleWindow( window = XCreateSimpleWindow(
@ -1141,11 +1167,14 @@ version(X11) {
| EventMask.ButtonPressMask | EventMask.ButtonPressMask
| EventMask.ButtonReleaseMask | EventMask.ButtonReleaseMask
); );
XFlush(display);
} }
void closeWindow() { void closeWindow() {
XFreePixmap(display, buffer); XFreePixmap(display, buffer);
XDestroyWindow(display, window); XDestroyWindow(display, window);
XFlush(display);
} }
void dispose() { void dispose() {
@ -1154,68 +1183,13 @@ version(X11) {
bool destroyed = false; bool destroyed = false;
int eventLoop(long pulseTimeout) { int eventLoop(long pulseTimeout) {
XEvent e;
bool done = false; bool done = false;
while (!done) { while (!done) {
while(!done && while(!done &&
(pulseTimeout == 0 || (XPending(display) > 0))) (pulseTimeout == 0 || (XPending(display) > 0)))
{ {
XNextEvent(display, &e); done = doXNextEvent(this); // FIXME: what about multiple windows? This wasn't originally going to support them but maybe I should
switch(e.type) {
case EventType.Expose:
//if(backingImage !is null)
// XPutImage(display, cast(Drawable) window, gc, backingImage.handle, 0, 0, 0, 0, backingImage.width, backingImage.height);
XCopyArea(display, cast(Drawable) buffer, cast(Drawable) window, gc, 0, 0, width, height, 0, 0);
break;
case EventType.ClientMessage: // User clicked the close button
case EventType.DestroyNotify:
done = true;
destroyed = true;
break;
case EventType.MotionNotify:
MouseEvent mouse;
auto event = e.xmotion;
mouse.type = 0;
mouse.x = event.x;
mouse.y = event.y;
mouse.buttonFlags = event.state;
if(handleMouseEvent)
handleMouseEvent(mouse);
break;
case EventType.ButtonPress:
case EventType.ButtonRelease:
MouseEvent mouse;
auto event = e.xbutton;
mouse.type = e.type == EventType.ButtonPress ? 1 : 2;
mouse.x = event.x;
mouse.y = event.y;
mouse.button = event.button;
//mouse.buttonFlags = event.detail;
if(handleMouseEvent)
handleMouseEvent(mouse);
break;
case EventType.KeyPress:
if(handleCharEvent)
handleCharEvent(
cast(dchar) XKeycodeToKeysym(
XDisplayConnection.get(),
e.xkey.keycode,
0)); // FIXME: we should check shift, etc. too, so it matches Windows' behavior better
goto case;
case EventType.KeyRelease:
if(handleKeyEvent)
handleKeyEvent(e.xkey.keycode, e.type == EventType.ButtonPress);
break;
default:
}
} }
if(!done && pulseTimeout !=0) { if(!done && pulseTimeout !=0) {
if(handlePulse !is null) if(handlePulse !is null)
@ -1229,6 +1203,85 @@ version(X11) {
} }
} }
version(X11) {
bool doXNextEvent(SimpleWindow t) {
bool done;
XEvent e;
XNextEvent(t.display, &e);
version(with_eventloop)
import arsd.eventloop;
switch(e.type) {
case EventType.Expose:
//if(backingImage !is null)
// XPutImage(display, cast(Drawable) window, gc, backingImage.handle, 0, 0, 0, 0, backingImage.width, backingImage.height);
XCopyArea(t.display, cast(Drawable) t.buffer, cast(Drawable) t.window, t.gc, 0, 0, t.width, t.height, 0, 0);
break;
case EventType.ClientMessage: // User clicked the close button
case EventType.DestroyNotify:
done = true;
t.destroyed = true;
version(with_eventloop)
exit();
break;
case EventType.MotionNotify:
MouseEvent mouse;
auto event = e.xmotion;
mouse.type = 0;
mouse.x = event.x;
mouse.y = event.y;
mouse.buttonFlags = event.state;
if(t.handleMouseEvent)
t.handleMouseEvent(mouse);
version(with_eventloop)
send(mouse);
break;
case EventType.ButtonPress:
case EventType.ButtonRelease:
MouseEvent mouse;
auto event = e.xbutton;
mouse.type = e.type == EventType.ButtonPress ? 1 : 2;
mouse.x = event.x;
mouse.y = event.y;
mouse.button = event.button;
//mouse.buttonFlags = event.detail;
if(t.handleMouseEvent)
t.handleMouseEvent(mouse);
version(with_eventloop)
send(mouse);
break;
case EventType.KeyPress:
auto ch = cast(dchar) XKeycodeToKeysym(
XDisplayConnection.get(),
e.xkey.keycode,
0); // FIXME: we should check shift, etc. too, so it matches Windows' behavior better
if(t.handleCharEvent)
t.handleCharEvent(ch);
version(with_eventloop)
send(ch);
goto case;
case EventType.KeyRelease:
if(t.handleKeyEvent)
t.handleKeyEvent(e.xkey.keycode, e.type == EventType.ButtonPress);
version(with_eventloop)
send(KeyEvent(e.xkey.keycode, e.type == EventType.ButtonPress));
break;
default:
}
return done;
}
}
/* *************************************** */ /* *************************************** */
/* Done with simpledisplay stuff */ /* Done with simpledisplay stuff */
/* *************************************** */ /* *************************************** */