Restore repaint_delay

This commit is contained in:
Kovid Goyal 2017-09-06 14:31:54 +05:30
parent 44650c5723
commit 0e46994d0a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 59 additions and 30 deletions

View File

@ -104,7 +104,8 @@ class Boss(Thread):
read_wakeup_fd, write_wakeup_fd = pipe2() read_wakeup_fd, write_wakeup_fd = pipe2()
self.ui_timers = Timers() self.ui_timers = Timers()
self.child_monitor = ChildMonitor( self.child_monitor = ChildMonitor(
read_wakeup_fd, write_wakeup_fd, self.signal_fd, self.on_child_death, self.update_screen, read_wakeup_fd, write_wakeup_fd, self.signal_fd, opts.repaint_delay / 1000.0,
self.on_child_death, self.update_screen, self.ui_timers,
DumpCommands(args) if args.dump_commands or args.dump_bytes else None) DumpCommands(args) if args.dump_commands or args.dump_bytes else None)
set_boss(self) set_boss(self)
self.current_font_size = opts.font_size self.current_font_size = opts.font_size

View File

@ -20,6 +20,7 @@ typedef struct {
bool needs_removal; bool needs_removal;
int fd; int fd;
unsigned long id; unsigned long id;
double last_paint_at;
} Child; } Child;
static const Child EMPTY_CHILD = {0}; static const Child EMPTY_CHILD = {0};
@ -52,11 +53,12 @@ static uint8_t drain_buf[1024];
static PyObject * static PyObject *
new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) { new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
ChildMonitor *self; ChildMonitor *self;
PyObject *dump_callback, *death_notify, *update_screen; PyObject *dump_callback, *death_notify, *update_screen, *timers;
int wakeup_fd, write_wakeup_fd, signal_fd, ret; int wakeup_fd, write_wakeup_fd, signal_fd, ret;
double repaint_delay;
if (created) { PyErr_SetString(PyExc_RuntimeError, "Can have only a single ChildMonitor instance"); return NULL; } if (created) { PyErr_SetString(PyExc_RuntimeError, "Can have only a single ChildMonitor instance"); return NULL; }
if (!PyArg_ParseTuple(args, "iiiOOO", &wakeup_fd, &write_wakeup_fd, &signal_fd, &death_notify, &update_screen, &dump_callback)) return NULL; if (!PyArg_ParseTuple(args, "iiidOOOO", &wakeup_fd, &write_wakeup_fd, &signal_fd, &repaint_delay, &death_notify, &update_screen, &timers, &dump_callback)) return NULL;
created = true; created = true;
if ((ret = pthread_mutex_init(&children_lock, NULL)) != 0) { if ((ret = pthread_mutex_init(&children_lock, NULL)) != 0) {
PyErr_Format(PyExc_RuntimeError, "Failed to create children_lock mutex: %s", strerror(ret)); PyErr_Format(PyExc_RuntimeError, "Failed to create children_lock mutex: %s", strerror(ret));
@ -66,6 +68,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
if (self == NULL) return PyErr_NoMemory(); if (self == NULL) return PyErr_NoMemory();
self->death_notify = death_notify; Py_INCREF(death_notify); self->death_notify = death_notify; Py_INCREF(death_notify);
self->update_screen = update_screen; Py_INCREF(self->update_screen); self->update_screen = update_screen; Py_INCREF(self->update_screen);
self->timers = (Timers*)timers; Py_INCREF(timers);
if (dump_callback != Py_None) { if (dump_callback != Py_None) {
self->dump_callback = dump_callback; Py_INCREF(dump_callback); self->dump_callback = dump_callback; Py_INCREF(dump_callback);
parse_func = parse_worker_dump; parse_func = parse_worker_dump;
@ -74,6 +77,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
fds[0].fd = wakeup_fd; fds[1].fd = signal_fd; fds[0].fd = wakeup_fd; fds[1].fd = signal_fd;
fds[0].events = POLLIN; fds[1].events = POLLIN; fds[0].events = POLLIN; fds[1].events = POLLIN;
self->write_wakeup_fd = write_wakeup_fd; self->write_wakeup_fd = write_wakeup_fd;
self->repaint_delay = repaint_delay;
return (PyObject*) self; return (PyObject*) self;
} }
@ -84,6 +88,7 @@ dealloc(ChildMonitor* self) {
Py_CLEAR(self->dump_callback); Py_CLEAR(self->dump_callback);
Py_CLEAR(self->death_notify); Py_CLEAR(self->death_notify);
Py_CLEAR(self->update_screen); Py_CLEAR(self->update_screen);
Py_CLEAR(self->timers);
for (size_t i = 0; i < self->count; i++) { for (size_t i = 0; i < self->count; i++) {
FREE_CHILD(children[i]); FREE_CHILD(children[i]);
} }
@ -162,6 +167,20 @@ shutdown(ChildMonitor *self) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static inline void
do_parse(ChildMonitor *self, Screen *screen, unsigned long child_id) {
screen_mutex(lock, read);
if (screen->read_buf_sz) {
parse_func(screen, self->dump_callback);
if (screen->read_buf_sz >= READ_BUF_SZ) wakeup_(self->write_wakeup_fd); // Ensure the read fd has POLLIN set
screen->read_buf_sz = 0;
PyObject *t = PyObject_CallFunction(self->update_screen, "k", child_id);
if (t == NULL) PyErr_Print();
else Py_DECREF(t);
}
screen_mutex(unlock, read);
}
static PyObject * static PyObject *
parse_input(ChildMonitor *self) { parse_input(ChildMonitor *self) {
#define parse_input_doc "parse_input() -> Parse all available input that was read in the I/O thread." #define parse_input_doc "parse_input() -> Parse all available input that was read in the I/O thread."
@ -179,24 +198,25 @@ parse_input(ChildMonitor *self) {
scratch[i] = children[i]; scratch[i] = children[i];
INCREF_CHILD(scratch[i]); INCREF_CHILD(scratch[i]);
} }
// TODO: Implement repaint delay here.
children_mutex(unlock); children_mutex(unlock);
double wait_for = self->repaint_delay;
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
if (!scratch[i].needs_removal) { if (!scratch[i].needs_removal) {
Screen *screen = scratch[i].screen; double now = monotonic();
screen_mutex(lock, read); double time_since_last_repaint = now - scratch[i].last_paint_at;
if (screen->read_buf_sz) { if (time_since_last_repaint >= self->repaint_delay) {
parse_func(screen, self->dump_callback); do_parse(self, scratch[i].screen, scratch[i].id);
if (screen->read_buf_sz >= READ_BUF_SZ) wakeup_(self->write_wakeup_fd); // Ensure the read fd has POLLIN set children[i].last_paint_at = now;
screen->read_buf_sz = 0; } else {
PyObject *t = PyObject_CallFunction(self->update_screen, "k", scratch[i].id); wait_for = MIN(wait_for, self->repaint_delay - time_since_last_repaint);
if (t == NULL) PyErr_Print();
else Py_DECREF(t);
} }
screen_mutex(unlock, read);
} }
DECREF_CHILD(scratch[i]); DECREF_CHILD(scratch[i]);
} }
if (wait_for < self->repaint_delay) {
timers_add(self->timers, wait_for, false, Py_None, NULL);
}
if (sr) { Py_RETURN_TRUE; } if (sr) { Py_RETURN_TRUE; }
Py_RETURN_FALSE; Py_RETURN_FALSE;
} }

View File

@ -280,7 +280,9 @@ typedef struct {
PyObject_HEAD PyObject_HEAD
PyObject *dump_callback, *update_screen, *death_notify; PyObject *dump_callback, *update_screen, *death_notify;
Timers *timers;
int write_wakeup_fd; int write_wakeup_fd;
double repaint_delay;
unsigned int count; unsigned int count;
bool shutting_down; bool shutting_down;
} ChildMonitor; } ChildMonitor;
@ -351,6 +353,7 @@ void historybuf_init_line(HistoryBuf *self, index_type num, Line *l);
double monotonic(); double monotonic();
double timers_timeout(Timers*); double timers_timeout(Timers*);
void timers_call(Timers*); void timers_call(Timers*);
bool timers_add(Timers *self, double delay, bool, PyObject *callback, PyObject *args);
bool timers_add_if_missing(Timers *self, double delay, PyObject *callback, PyObject *args); bool timers_add_if_missing(Timers *self, double delay, PyObject *callback, PyObject *args);
color_type colorprofile_to_color(ColorProfile *self, color_type entry, color_type defval); color_type colorprofile_to_color(ColorProfile *self, color_type entry, color_type defval);

View File

@ -96,28 +96,31 @@ _add(Timers *self, double at, PyObject *callback, PyObject *args) {
return true; return true;
} }
bool
timers_add(Timers *self, double delay, bool update, PyObject *callback, PyObject *args) {
double at = monotonic_() + delay;
static PyObject * for (size_t i = 0; i < self->count; i++) {
add(Timers *self, PyObject *fargs) {
#define add_doc "add(delay, callback, args) -> Add callback, replacing it if it already exists"
size_t i;
PyObject *callback, *args = NULL;
double delay, at;
if (!PyArg_ParseTuple(fargs, "dO|O", &delay, &callback, &args)) return NULL;
at = monotonic_() + delay;
for (i = 0; i < self->count; i++) {
if (self->events[i].callback == callback) { if (self->events[i].callback == callback) {
self->events[i].at = at; self->events[i].at = update ? at : MIN(at, self->events[i].at);
Py_CLEAR(self->events[i].args); Py_CLEAR(self->events[i].args);
self->events[i].args = args; self->events[i].args = args;
Py_XINCREF(args); Py_XINCREF(args);
qsort(self->events, self->count, sizeof(TimerEvent), compare_events); qsort(self->events, self->count, sizeof(TimerEvent), compare_events);
Py_RETURN_NONE; return true;
} }
} }
return _add(self, at, callback, args);
}
if (!_add(self, at, callback, args)) return NULL;
static PyObject *
add(Timers *self, PyObject *fargs) {
#define add_doc "add(delay, callback, args) -> Add callback, replacing it if it already exists"
PyObject *callback, *args = NULL;
double delay;
if (!PyArg_ParseTuple(fargs, "dO|O", &delay, &callback, &args)) return NULL;
if (!timers_add(self, delay, true, callback, args)) return NULL;
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -185,10 +188,12 @@ timers_call(Timers *self) {
size_t i, j; size_t i, j;
for (i = 0, j = 0; i < self->count; i++) { for (i = 0, j = 0; i < self->count; i++) {
if (self->events[i].at <= now) { // expired, call it if (self->events[i].at <= now) { // expired, call it
if (self->events[i].callback != Py_None) {
PyObject *ret = PyObject_CallObject(self->events[i].callback, self->events[i].args); PyObject *ret = PyObject_CallObject(self->events[i].callback, self->events[i].args);
Py_CLEAR(self->events[i].callback); Py_CLEAR(self->events[i].args);
if (ret == NULL) PyErr_Print(); if (ret == NULL) PyErr_Print();
else Py_DECREF(ret); else Py_DECREF(ret);
}
Py_CLEAR(self->events[i].callback); Py_CLEAR(self->events[i].args);
} else { } else {
other[j].callback = self->events[i].callback; other[j].at = self->events[i].at; other[j].args = self->events[i].args; other[j].callback = self->events[i].callback; other[j].at = self->events[i].at; other[j].args = self->events[i].args;
j++; j++;