timerfd_create is Linux-specific; this patch uses only POSIX functions
and has been tested on Linux and OpenBSD.
Also make processEvent return 1 to tell us when to quit.
---
src/uxn11.c | 93 +++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 68 insertions(+), 25 deletions(-)
diff --git a/src/uxn11.c b/src/uxn11.c
index 3142ddf..5b7e76e 100644
--- a/src/uxn11.c
+++ b/src/uxn11.c
@@ -1,10 +1,12 @@
+#define _POSIX_C_SOURCE 199309L
+#include <poll.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
-#include <sys/timerfd.h>
-#include <unistd.h>
-#include <poll.h>
#include "uxn.h"
#include "devices/system.h"
@@ -117,7 +119,7 @@ hide_cursor(void)
#define XK_Control 0xffe3
#define XK_Alt 0xffe9
-static void
+static int
processEvent(void)
{
XEvent ev;
@@ -130,7 +132,7 @@ processEvent(void)
XDestroyImage(ximage);
XDestroyWindow(display, window);
XCloseDisplay(display);
- exit(0);
+ return 1;
} break;
case KeyPress: {
XKeyPressedEvent *e = (XKeyPressedEvent *)&ev;
@@ -171,6 +173,7 @@ processEvent(void)
mouse_pos(devmouse, e->x, e->y);
} break;
}
+ return 0;
}
static int
@@ -220,14 +223,53 @@ init(void)
return 1;
}
+static void
+timer_loop(int fd)
+{
+ struct timespec s;
+ s.tv_sec = 0;
+ s.tv_nsec = 16666667; /* 1/60 s in ns */
+ while (1) {
+ write(fd, "", 1);
+ nanosleep(&s, NULL);
+ }
+}
+
+static void
+main_loop(int fd, Uxn *u)
+{
+ int pollret;
+ struct pollfd fds[2];
+ fds[0].fd = ConnectionNumber(display);
+ fds[1].fd = fd;
+ fds[0].events = fds[1].events = POLLIN;
+
+ /* main loop */
+ while(1) {
+ fds[0].revents = fds[1].revents = 0;
+ pollret = poll(fds, 2, -1);
+ if (pollret <= 0)
+ continue;
+ while(XPending(display))
+ if (processEvent() != 0)
+ return;
+ if (fds[1].revents) {
+ char discard;
+ uxn_eval(u, GETVECTOR(devscreen));
+ read(fds[1].fd, &discard, 1);
+ }
+ if(uxn_screen.fg.changed || uxn_screen.bg.changed)
+ redraw();
+ }
+}
+
int
main(int argc, char **argv)
{
Uxn u;
int i;
- char expirations[8];
- struct pollfd fds[2];
- static const struct itimerspec screen_tspec = {{0, 16666666}, {0, 16666666}};
+ int pipes[2];
+ pid_t pid;
if(argc < 2)
return error("Usage", "uxncli game.rom args");
if(!start(&u, argv[1]))
@@ -240,23 +282,24 @@ main(int argc, char **argv)
while(*p) console_input(&u, *p++);
console_input(&u, '\n');
}
- fds[0].fd = XConnectionNumber(display);
- fds[1].fd = timerfd_create(CLOCK_MONOTONIC, 0);
- timerfd_settime(fds[1].fd, 0, &screen_tspec, NULL);
- fds[0].events = fds[1].events = POLLIN;
- /* main loop */
- while(1) {
- if(poll(fds, 2, 1000) <= 0)
- continue;
- while(XPending(display))
- processEvent();
- if(poll(&fds[1], 1, 0)) {
- read(fds[1].fd, expirations, 8); /* Indicate we handled the timer */
- uxn_eval(&u, GETVECTOR(devscreen)); /* Call the vector once, even if the timer fired multiple times */
- }
- if(uxn_screen.fg.changed || uxn_screen.bg.changed)
- redraw();
+
+ if (pipe(pipes) != 0)
+ return error("Pipe", "Failed");
+
+ pid = fork();
+ if (pid == -1) {
+ return error("Fork", "Failed");
+ } else if (pid == 0) {
+ /* child */
+ close(pipes[0]);
+ timer_loop(pipes[1]);
+ } else {
+ /* parent */
+ close(pipes[1]);
+ main_loop(pipes[0], &u);
+
+ free(u.ram);
+ kill(pid, SIGKILL);
}
- XDestroyImage(ximage);
return 0;
}
--
2.35.1