Move the main loop into the C module

This commit is contained in:
Kovid Goyal 2017-09-06 20:47:39 +05:30
parent 02870d7221
commit 21b799905d
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 23 additions and 20 deletions

View File

@ -97,7 +97,7 @@ class Boss:
self.ui_timers = Timers()
self.child_monitor = ChildMonitor(
opts.repaint_delay / 1000.0, glfw_window.window_id(),
self.on_child_death, self.update_screen, self.ui_timers,
self.on_child_death, self.update_screen, self.ui_timers, self.render,
DumpCommands(args) if args.dump_commands or args.dump_bytes else None)
set_boss(self)
self.current_font_size = opts.font_size

View File

@ -89,12 +89,12 @@ self_pipe(int fds[2]) {
static PyObject *
new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
ChildMonitor *self;
PyObject *dump_callback, *death_notify, *update_screen, *timers, *wid;
PyObject *dump_callback, *death_notify, *update_screen, *timers, *wid, *render_func;
int ret;
double repaint_delay;
if (created) { PyErr_SetString(PyExc_RuntimeError, "Can have only a single ChildMonitor instance"); return NULL; }
if (!PyArg_ParseTuple(args, "dOOOOO", &repaint_delay, &wid, &death_notify, &update_screen, &timers, &dump_callback)) return NULL;
if (!PyArg_ParseTuple(args, "dOOOOOO", &repaint_delay, &wid, &death_notify, &update_screen, &timers, &render_func, &dump_callback)) return NULL;
glfw_window_id = PyLong_AsVoidPtr(wid);
created = true;
if ((ret = pthread_mutex_init(&children_lock, NULL)) != 0) {
@ -111,6 +111,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
if (self == NULL) return PyErr_NoMemory();
self->death_notify = death_notify; Py_INCREF(death_notify);
self->update_screen = update_screen; Py_INCREF(self->update_screen);
self->render_func = render_func; Py_INCREF(self->render_func);
self->timers = (Timers*)timers; Py_INCREF(timers);
if (dump_callback != Py_None) {
self->dump_callback = dump_callback; Py_INCREF(dump_callback);
@ -131,6 +132,7 @@ dealloc(ChildMonitor* self) {
Py_CLEAR(self->death_notify);
Py_CLEAR(self->update_screen);
Py_CLEAR(self->timers);
Py_CLEAR(self->render_func);
Py_TYPE(self)->tp_free((PyObject*)self);
while (remove_queue_count) {
remove_queue_count--;
@ -253,9 +255,9 @@ do_parse(ChildMonitor *self, Screen *screen, unsigned long child_id) {
screen_mutex(unlock, read);
}
static PyObject *
static void
parse_input(ChildMonitor *self) {
#define parse_input_doc "parse_input() -> Parse all available input that was read in the I/O thread."
// Parse all available input that was read in the I/O thread.
size_t count = 0;
children_mutex(lock);
while (num_dead_children) {
@ -297,7 +299,6 @@ parse_input(ChildMonitor *self) {
if (wait_for < self->repaint_delay) {
timers_add(self->timers, wait_for, false, Py_None, NULL);
}
Py_RETURN_NONE;
}
static PyObject *
@ -321,9 +322,21 @@ mark_for_close(ChildMonitor *self, PyObject *args) {
#undef DECREF_CHILD
static PyObject*
main_loop(ChildMonitor UNUSED *self) {
main_loop(ChildMonitor *self) {
#define main_loop_doc "The main thread loop"
PyObject *ret;
double timeout;
while (!glfwWindowShouldClose(glfw_window_id)) {
ret = PyObject_CallObject(self->render_func, NULL);
if (ret == NULL) return NULL;
else Py_DECREF(ret);
glfwSwapBuffers(glfw_window_id);
timeout = timers_timeout(self->timers);
if (timeout < 0) glfwWaitEvents();
else if (timeout > 0) glfwWaitEventsTimeout(timeout);
timers_call(self->timers);
parse_input(self);
}
Py_RETURN_NONE;
}
@ -512,7 +525,6 @@ static PyMethodDef methods[] = {
METHOD(wakeup, METH_NOARGS)
METHOD(shutdown, METH_NOARGS)
METHOD(main_loop, METH_NOARGS)
METHOD(parse_input, METH_NOARGS)
METHOD(mark_for_close, METH_VARARGS)
{NULL} /* Sentinel */
};

View File

@ -279,7 +279,7 @@ PyTypeObject Timers_Type;
typedef struct {
PyObject_HEAD
PyObject *dump_callback, *update_screen, *death_notify;
PyObject *dump_callback, *update_screen, *death_notify, *render_func;
Timers *timers;
double repaint_delay;
unsigned int count;

View File

@ -23,7 +23,7 @@ from .fast_data_types import (
GLFW_STENCIL_BITS, Window, change_wcwidth, check_for_extensions,
enable_automatic_opengl_error_checking, glClear, glClearColor, glewInit,
glfw_init, glfw_init_hint_string, glfw_set_error_callback,
glfw_swap_interval, glfw_terminate, glfw_wait_events, glfw_window_hint
glfw_swap_interval, glfw_terminate, glfw_window_hint
)
from .layout import all_layouts
from .shaders import GL_VERSION
@ -166,11 +166,6 @@ def clear_buffers(window, opts):
# glfw_swap_interval(1)
def dispatch_pending_calls(boss):
boss.ui_timers.call()
boss.child_monitor.parse_input()
def run_app(opts, args):
setup_opengl(opts)
load_cached_values()
@ -212,11 +207,7 @@ def run_app(opts, args):
boss.start()
clear_buffers(window, opts)
try:
while not window.should_close():
boss.render()
window.swap_buffers()
glfw_wait_events(boss.ui_timers.timeout())
dispatch_pending_calls(boss)
boss.child_monitor.main_loop()
finally:
boss.destroy()
del window