frontend = fr;
}
+void stoat_callback(void *ctx)
+{
+ static int stoat = 0;
+ if (++stoat % 1000 == 0)
+ debug(("stoat %d\n", stoat));
+ queue_toplevel_callback(stoat_callback, NULL);
+}
+void queue_stoat(void)
+{
+ static int stoat = 0;
+ if (!stoat) {
+ stoat = 1;
+ queue_toplevel_callback(stoat_callback, NULL);
+ }
+}
+
void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx)
{
struct callback *cb;
+ queue_stoat();
+
cb = snew(struct callback);
cb->fn = fn;
cb->ctx = ctx;
void run_toplevel_callbacks(void)
{
- while (cbhead) {
+ queue_stoat();
+ if (cbhead) {
struct callback *cb = cbhead;
/*
* Careful ordering here. We call the function _before_
* advancing cbhead (though, of course, we must free cb
* _after_ advancing it). This means that if the very last
* callback schedules another callback, cbhead does not become
- * NULL at any point in this while loop, and so the frontend
- * notification function won't be needlessly pestered.
+ * NULL at any point, and so the frontend notification
+ * function won't be needlessly pestered.
*/
cb->fn(cb->ctx);
cbhead = cb->next;
sfree(cb);
+ if (!cbhead)
+ cbtail = NULL;
}
- cbtail = NULL;
+}
+
+int toplevel_callback_pending(void)
+{
+ queue_stoat();
+ return cbhead != NULL;
}
* top-level event loop. However, if a front end doesn't have control
* over its own event loop (e.g. because it's using GTK) then it can
* instead request notifications when a callback is available, so that
- * it knows to ask its delegate event loop to do the same thing.
+ * it knows to ask its delegate event loop to do the same thing. Also,
+ * if a front end needs to know whether a callback is pending without
+ * actually running it (e.g. so as to put a zero timeout on a select()
+ * call) then it can call toplevel_callback_pending(), which will
+ * return true if at least one callback is in the queue.
*/
typedef void (*toplevel_callback_fn_t)(void *ctx);
void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx);
void run_toplevel_callbacks(void);
+int toplevel_callback_pending(void);
typedef void (*toplevel_callback_notify_fn_t)(void *frontend);
void request_callback_notifications(toplevel_callback_notify_fn_t notify,
run_toplevel_callbacks();
}
- gtk_idle_remove(inst->toplevel_callback_idle_id);
+ if (!toplevel_callback_pending())
+ gtk_idle_remove(inst->toplevel_callback_idle_id);
return TRUE;
}
int maxfd;
int rwx;
int ret;
+ unsigned long next;
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_SET_MAX(fd, maxfd, xset);
}
- do {
- unsigned long next, then;
- long ticks;
- struct timeval tv, *ptv;
+ if (toplevel_callback_pending()) {
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ ret = select(maxfd, &rset, &wset, &xset, &tv);
+ } else if (run_timers(now, &next)) {
+ do {
+ unsigned long then;
+ long ticks;
+ struct timeval tv;
- if (run_timers(now, &next)) {
then = now;
now = GETTICKCOUNT();
if (now - then > next - then)
ticks = next - now;
tv.tv_sec = ticks / 1000;
tv.tv_usec = ticks % 1000 * 1000;
- ptv = &tv;
- } else {
- ptv = NULL;
- }
- ret = select(maxfd, &rset, &wset, &xset, ptv);
- if (ret == 0)
- now = next;
- else
- now = GETTICKCOUNT();
- } while (ret < 0 && errno == EINTR);
+ ret = select(maxfd, &rset, &wset, &xset, &tv);
+ if (ret == 0)
+ now = next;
+ else
+ now = GETTICKCOUNT();
+ } while (ret < 0 && errno == EINTR);
+ } else {
+ ret = select(maxfd, &rset, &wset, &xset, NULL);
+ }
if (ret < 0) {
perror("select");
int i, fdcount, fdsize, *fdlist;
int fd, fdstate, rwx, ret, maxfd;
unsigned long now = GETTICKCOUNT();
+ unsigned long next;
fdlist = NULL;
fdcount = fdsize = 0;
if (include_stdin)
FD_SET_MAX(0, maxfd, rset);
- do {
- unsigned long next, then;
- long ticks;
- struct timeval tv, *ptv;
+ if (toplevel_callback_pending()) {
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ ret = select(maxfd, &rset, &wset, &xset, &tv);
+ if (ret == 0)
+ run_toplevel_callbacks();
+ } else if (run_timers(now, &next)) {
+ do {
+ unsigned long then;
+ long ticks;
+ struct timeval tv;
- if (run_timers(now, &next)) {
then = now;
now = GETTICKCOUNT();
if (now - then > next - then)
ticks = next - now;
tv.tv_sec = ticks / 1000;
tv.tv_usec = ticks % 1000 * 1000;
- ptv = &tv;
- } else {
- ptv = NULL;
- }
- ret = select(maxfd, &rset, &wset, &xset, ptv);
- if (ret == 0)
- now = next;
- else
- now = GETTICKCOUNT();
- } while (ret < 0 && errno != EINTR);
+ ret = select(maxfd, &rset, &wset, &xset, &tv);
+ if (ret == 0)
+ now = next;
+ else
+ now = GETTICKCOUNT();
+ } while (ret < 0 && errno == EINTR);
+ } else {
+ ret = select(maxfd, &rset, &wset, &xset, NULL);
+ }
} while (ret == 0);
if (ret < 0) {
while (1) {
HANDLE *handles;
int nhandles, n;
+ DWORD timeout;
+
+ if (toplevel_callback_pending()) {
+ timeout = 0;
+ } else {
+ timeout = INFINITE;
+ /* The messages seem unreliable; especially if we're being tricky */
+ term_set_focus(term, GetForegroundWindow() == hwnd);
+ }
handles = handle_get_events(&nhandles);
- n = MsgWaitForMultipleObjects(nhandles, handles, FALSE, INFINITE,
- QS_ALLINPUT);
+ n = MsgWaitForMultipleObjects(nhandles, handles, FALSE,
+ timeout, QS_ALLINPUT);
if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) {
handle_got_event(handles[n - WAIT_OBJECT_0]);
} else
sfree(handles);
- run_toplevel_callbacks();
-
- while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
goto finished; /* two-level break */
if (!(IsWindow(logbox) && IsDialogMessage(logbox, &msg)))
DispatchMessage(&msg);
-
- run_toplevel_callbacks();
}
- /* The messages seem unreliable; especially if we're being tricky */
- term_set_focus(term, GetForegroundWindow() == hwnd);
+ run_toplevel_callbacks();
}
finished:
sending = TRUE;
}
- if (run_timers(now, &next)) {
+ if (toplevel_callback_pending()) {
+ ticks = 0;
+ } else if (run_timers(now, &next)) {
then = now;
now = GETTICKCOUNT();
if (now - then > next - then)
int skcount;
unsigned long now = GETTICKCOUNT();
- if (run_timers(now, &next)) {
+ if (toplevel_callback_pending()) {
+ ticks = 0;
+ } else if (run_timers(now, &next)) {
then = now;
now = GETTICKCOUNT();
if (now - then > next - then)