Restore repaint_delay
This commit is contained in:
parent
44650c5723
commit
0e46994d0a
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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
|
||||||
PyObject *ret = PyObject_CallObject(self->events[i].callback, self->events[i].args);
|
if (self->events[i].callback != Py_None) {
|
||||||
|
PyObject *ret = PyObject_CallObject(self->events[i].callback, self->events[i].args);
|
||||||
|
if (ret == NULL) PyErr_Print();
|
||||||
|
else Py_DECREF(ret);
|
||||||
|
}
|
||||||
Py_CLEAR(self->events[i].callback); Py_CLEAR(self->events[i].args);
|
Py_CLEAR(self->events[i].callback); Py_CLEAR(self->events[i].args);
|
||||||
if (ret == NULL) PyErr_Print();
|
|
||||||
else Py_DECREF(ret);
|
|
||||||
} 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++;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user