Move render call for tab bar to C code
This commit is contained in:
parent
2e0cbb88bb
commit
943a1575ad
@ -15,8 +15,8 @@ from .constants import (
|
||||
from .fast_data_types import (
|
||||
GLFW_CURSOR, GLFW_CURSOR_HIDDEN, GLFW_CURSOR_NORMAL, GLFW_MOUSE_BUTTON_1,
|
||||
GLFW_PRESS, GLFW_REPEAT, ChildMonitor, Timers as _Timers,
|
||||
destroy_sprite_map, glfw_post_empty_event, layout_sprite_map,
|
||||
resize_gl_viewport
|
||||
destroy_global_data, destroy_sprite_map, glfw_post_empty_event,
|
||||
layout_sprite_map, resize_gl_viewport
|
||||
)
|
||||
from .fonts.render import render_cell_wrapper, set_font_family
|
||||
from .keys import (
|
||||
@ -365,7 +365,6 @@ class Boss:
|
||||
self.glfw_window.set_title(self.glfw_window_title)
|
||||
if isosx:
|
||||
cocoa_update_title(self.glfw_window_title)
|
||||
self.tab_manager.render()
|
||||
for window in tab.visible_windows():
|
||||
if not window.needs_layout:
|
||||
window.char_grid.render_cells()
|
||||
@ -408,6 +407,7 @@ class Boss:
|
||||
t.destroy()
|
||||
del self.tab_manager
|
||||
destroy_sprite_map()
|
||||
destroy_global_data()
|
||||
del self.glfw_window
|
||||
|
||||
def paste_from_clipboard(self):
|
||||
|
||||
@ -424,6 +424,7 @@ pyset_iutf8(ChildMonitor *self, PyObject *args) {
|
||||
|
||||
static double last_render_at = -DBL_MAX;
|
||||
draw_borders_func draw_borders = NULL;
|
||||
draw_cells_func draw_cells = NULL;
|
||||
|
||||
static inline bool
|
||||
render(ChildMonitor *self, double *timeout) {
|
||||
@ -432,6 +433,9 @@ render(ChildMonitor *self, double *timeout) {
|
||||
double time_since_last_render = now - last_render_at;
|
||||
if (time_since_last_render > self->repaint_delay) {
|
||||
draw_borders();
|
||||
#define TD global_state.tab_bar_render_data
|
||||
if (TD.screen && global_state.num_tabs > 1) draw_cells(TD.vao_idx, TD.xstart, TD.ystart, TD.dx, TD.dy, TD.screen);
|
||||
#undef TD
|
||||
ret = PyObject_CallFunctionObjArgs(self->render_func, NULL);
|
||||
if (ret == NULL) { PyErr_Print(); return false; }
|
||||
else Py_DECREF(ret);
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#define MIN(x, y) (((x) > (y)) ? (y) : (x))
|
||||
#define xstr(s) str(s)
|
||||
#define str(s) #s
|
||||
#define fatal(...) { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); exit(EXIT_FAILURE); }
|
||||
|
||||
typedef uint32_t char_type;
|
||||
typedef uint32_t color_type;
|
||||
@ -292,8 +293,22 @@ typedef struct {
|
||||
bool enable_audio_bell;
|
||||
} Options;
|
||||
|
||||
typedef struct {
|
||||
unsigned int id;
|
||||
} Tab;
|
||||
|
||||
typedef struct {
|
||||
ssize_t vao_idx;
|
||||
float xstart, ystart, dx, dy;
|
||||
Screen *screen;
|
||||
} ScreenRenderData;
|
||||
|
||||
typedef struct {
|
||||
Options opts;
|
||||
|
||||
Tab tabs[MAX_CHILDREN];
|
||||
unsigned int active_tab, num_tabs;
|
||||
ScreenRenderData tab_bar_render_data;
|
||||
} GlobalState;
|
||||
|
||||
#ifndef IS_STATE
|
||||
@ -313,6 +328,8 @@ extern GlobalState global_state;
|
||||
|
||||
typedef void (*draw_borders_func)();
|
||||
extern draw_borders_func draw_borders;
|
||||
typedef void (*draw_cells_func)(ssize_t, float, float, float, float, Screen *);
|
||||
extern draw_cells_func draw_cells;
|
||||
|
||||
// Global functions
|
||||
Line* alloc_line();
|
||||
|
||||
@ -33,8 +33,6 @@ static char glbuf[4096];
|
||||
#define GL_STACK_OVERFLOW 0x0503
|
||||
#endif
|
||||
|
||||
#define fatal(...) { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); exit(EXIT_FAILURE); }
|
||||
|
||||
#ifdef ENABLE_DEBUG_GL
|
||||
static void
|
||||
check_for_gl_error(int line) {
|
||||
@ -596,7 +594,7 @@ create_cell_vao() {
|
||||
}
|
||||
|
||||
static void
|
||||
draw_cells(ssize_t vao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, Screen *screen) {
|
||||
draw_cells_impl(ssize_t vao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, Screen *screen) {
|
||||
size_t sz;
|
||||
void *address;
|
||||
bool inverted = screen_invert_colors(screen);
|
||||
@ -842,7 +840,7 @@ PYWRAP1(draw_cells) {
|
||||
Screen *screen;
|
||||
|
||||
PA("iffffO", &vao_idx, &xstart, &ystart, &dx, &dy, &screen);
|
||||
draw_cells(vao_idx, xstart, ystart, dx, dy, screen);
|
||||
draw_cells_impl(vao_idx, xstart, ystart, dx, dy, screen);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
NO_ARG(destroy_sprite_map)
|
||||
@ -900,6 +898,7 @@ PYWRAP0(check_for_extensions) {
|
||||
#define MW(name, arg_type) {#name, (PyCFunction)py##name, arg_type, NULL}
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"glewInit", (PyCFunction)glew_init, METH_NOARGS, NULL},
|
||||
{"draw_cells", (PyCFunction)pydraw_cells, METH_VARARGS, NULL},
|
||||
M(compile_program, METH_VARARGS),
|
||||
MW(check_for_extensions, METH_NOARGS),
|
||||
MW(create_vao, METH_NOARGS),
|
||||
@ -917,7 +916,6 @@ static PyMethodDef module_methods[] = {
|
||||
MW(send_borders_rects, METH_VARARGS),
|
||||
MW(init_cell_program, METH_NOARGS),
|
||||
MW(create_cell_vao, METH_NOARGS),
|
||||
MW(draw_cells, METH_VARARGS),
|
||||
MW(layout_sprite_map, METH_VARARGS),
|
||||
MW(destroy_sprite_map, METH_NOARGS),
|
||||
MW(resize_gl_viewport, METH_VARARGS),
|
||||
@ -965,6 +963,7 @@ init_shaders(PyObject *module) {
|
||||
PyModule_AddObject(module, "GL_VERSION_REQUIRED", Py_BuildValue("II", REQUIRED_VERSION_MAJOR, REQUIRED_VERSION_MINOR));
|
||||
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
||||
draw_borders = &draw_borders_impl;
|
||||
draw_cells = &draw_cells_impl;
|
||||
return true;
|
||||
}
|
||||
// }}}
|
||||
|
||||
@ -8,15 +8,55 @@
|
||||
#define IS_STATE
|
||||
#include "data-types.h"
|
||||
|
||||
GlobalState global_state = {{0}};
|
||||
static const Tab EMPTY_TAB = {0};
|
||||
|
||||
#define ensure_can_add(array, count, msg) if (count >= sizeof(array)/sizeof(array[0]) - 1) fatal(msg);
|
||||
|
||||
#define REMOVER(array, qid, count, empty, structure) { \
|
||||
size_t capacity = sizeof(array)/sizeof(array[0]); \
|
||||
for (size_t i = 0; i < count; i++) { \
|
||||
if (array[i].id == qid) { \
|
||||
array[i] = empty; \
|
||||
size_t num_to_right = capacity - count - 1; \
|
||||
if (num_to_right) memmove(array + i, array + i + 1, num_to_right * sizeof(structure)); \
|
||||
(count)--; \
|
||||
} \
|
||||
}}
|
||||
|
||||
static inline void
|
||||
add_tab(unsigned int id) {
|
||||
ensure_can_add(global_state.tabs, global_state.num_tabs, "Too many children (add_tab)");
|
||||
global_state.tabs[global_state.num_tabs] = EMPTY_TAB;
|
||||
global_state.tabs[global_state.num_tabs].id = id;
|
||||
global_state.num_tabs++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
remove_tab(unsigned int id) {
|
||||
REMOVER(global_state.tabs, id, global_state.num_tabs, EMPTY_TAB, Tab);
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_active_tab(unsigned int idx) {
|
||||
global_state.active_tab = idx;
|
||||
}
|
||||
|
||||
static inline void
|
||||
swap_tabs(unsigned int a, unsigned int b) {
|
||||
Tab t = global_state.tabs[b];
|
||||
global_state.tabs[b] = global_state.tabs[a];
|
||||
global_state.tabs[a] = t;
|
||||
}
|
||||
|
||||
// Python API {{{
|
||||
#define PYWRAP0(name) static PyObject* py##name(PyObject UNUSED *self)
|
||||
#define PYWRAP1(name) static PyObject* py##name(PyObject UNUSED *self, PyObject *args)
|
||||
#define PYWRAP2(name) static PyObject* py##name(PyObject UNUSED *self, PyObject *args, PyObject *kw)
|
||||
#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;
|
||||
#define ONE_UINT(name) PYWRAP1(name) { name((unsigned int)PyLong_AsUnsignedLong(args)); Py_RETURN_NONE; }
|
||||
#define TWO_UINT(name) PYWRAP1(name) { unsigned int a, b; PA("II", &a, &b); name(a, b); Py_RETURN_NONE; }
|
||||
|
||||
GlobalState global_state = {{0}};
|
||||
|
||||
|
||||
// Python API {{{
|
||||
PYWRAP1(set_options) {
|
||||
#define S(name, convert) { PyObject *ret = PyObject_GetAttrString(args, #name); if (ret == NULL) return NULL; global_state.opts.name = convert(ret); Py_DECREF(ret); }
|
||||
S(visual_bell_duration, PyFloat_AsDouble);
|
||||
@ -25,10 +65,36 @@ PYWRAP1(set_options) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PYWRAP1(set_tab_bar_render_data) {
|
||||
#define A(name) &(global_state.tab_bar_render_data.name)
|
||||
Py_CLEAR(global_state.tab_bar_render_data.screen);
|
||||
PA("iffffO", A(vao_idx), A(xstart), A(ystart), A(dx), A(dy), A(screen));
|
||||
Py_INCREF(global_state.tab_bar_render_data.screen);
|
||||
Py_RETURN_NONE;
|
||||
#undef A
|
||||
}
|
||||
|
||||
PYWRAP0(destroy_global_data) {
|
||||
Py_CLEAR(global_state.tab_bar_render_data.screen);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
ONE_UINT(add_tab)
|
||||
ONE_UINT(remove_tab)
|
||||
ONE_UINT(set_active_tab)
|
||||
TWO_UINT(swap_tabs)
|
||||
|
||||
#define M(name, arg_type) {#name, (PyCFunction)name, arg_type, NULL}
|
||||
#define MW(name, arg_type) {#name, (PyCFunction)py##name, arg_type, NULL}
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
MW(set_options, METH_O),
|
||||
MW(add_tab, METH_O),
|
||||
MW(remove_tab, METH_O),
|
||||
MW(set_active_tab, METH_O),
|
||||
MW(swap_tabs, METH_VARARGS),
|
||||
MW(set_tab_bar_render_data, METH_VARARGS),
|
||||
MW(destroy_global_data, METH_NOARGS),
|
||||
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
@ -4,17 +4,18 @@
|
||||
|
||||
from collections import deque, namedtuple
|
||||
from functools import partial
|
||||
from itertools import count
|
||||
|
||||
from .borders import Borders
|
||||
from .char_grid import calculate_gl_geometry, render_cells
|
||||
from .char_grid import calculate_gl_geometry
|
||||
from .child import Child
|
||||
from .config import build_ansi_color_table
|
||||
from .constants import (
|
||||
WindowGeometry, appname, cell_size, get_boss, shell_path,
|
||||
viewport_size
|
||||
WindowGeometry, appname, cell_size, get_boss, shell_path, viewport_size
|
||||
)
|
||||
from .fast_data_types import (
|
||||
DECAWM, Screen, create_cell_vao, glfw_post_empty_event
|
||||
DECAWM, Screen, add_tab, create_cell_vao, glfw_post_empty_event,
|
||||
remove_tab, set_active_tab, swap_tabs, set_tab_bar_render_data
|
||||
)
|
||||
from .layout import Rect, all_layouts
|
||||
from .utils import color_as_int
|
||||
@ -22,16 +23,19 @@ from .window import Window
|
||||
|
||||
TabbarData = namedtuple('TabbarData', 'title is_active is_last')
|
||||
borders = None
|
||||
tab_counter = count()
|
||||
next(tab_counter)
|
||||
|
||||
|
||||
def SpecialWindow(cmd, stdin=None, override_title=None):
|
||||
return (cmd, stdin, override_title)
|
||||
|
||||
|
||||
class Tab:
|
||||
class Tab: # {{{
|
||||
|
||||
def __init__(self, opts, args, on_title_change, session_tab=None, special_window=None):
|
||||
global borders
|
||||
self.id = next(tab_counter)
|
||||
self.opts, self.args = opts, args
|
||||
self.name = getattr(session_tab, 'name', '')
|
||||
self.on_title_change = on_title_change
|
||||
@ -199,9 +203,10 @@ class Tab:
|
||||
|
||||
def __repr__(self):
|
||||
return 'Tab(title={}, id={})'.format(self.name or self.title, hex(id(self)))
|
||||
# }}}
|
||||
|
||||
|
||||
class TabBar:
|
||||
class TabBar: # {{{
|
||||
|
||||
def __init__(self, opts):
|
||||
self.num_tabs = 1
|
||||
@ -238,7 +243,8 @@ class TabBar:
|
||||
self.tab_bar_blank_rects = (Rect(0, g.top, g.left, g.bottom), Rect(g.right - 1, g.top, viewport_width, g.bottom))
|
||||
else:
|
||||
self.tab_bar_blank_rects = ()
|
||||
self.screen_geometry = calculate_gl_geometry(g, viewport_width, viewport_height, cell_width, cell_height)
|
||||
self.screen_geometry = sg = calculate_gl_geometry(g, viewport_width, viewport_height, cell_width, cell_height)
|
||||
set_tab_bar_render_data(self.vao_id, sg.xstart, sg.ystart, sg.dx, sg.dy, self.screen)
|
||||
|
||||
def update(self, data):
|
||||
if self.layout_changed is None:
|
||||
@ -270,18 +276,15 @@ class TabBar:
|
||||
self.cell_ranges = cr
|
||||
glfw_post_empty_event()
|
||||
|
||||
def render(self):
|
||||
if self.layout_changed is not None:
|
||||
render_cells(self.vao_id, self.screen_geometry, self.screen)
|
||||
|
||||
def tab_at(self, x):
|
||||
x = (x - self.window_geometry.left) // self.cell_width
|
||||
for i, (a, b) in enumerate(self.cell_ranges):
|
||||
if a <= x <= b:
|
||||
return i
|
||||
# }}}
|
||||
|
||||
|
||||
class TabManager:
|
||||
class TabManager: # {{{
|
||||
|
||||
def __init__(self, opts, args):
|
||||
self.opts, self.args = opts, args
|
||||
@ -291,9 +294,22 @@ class TabManager:
|
||||
self.tab_bar.layout(*self.tab_bar_layout_data)
|
||||
self.active_tab_idx = 0
|
||||
|
||||
def _add_tab(self, tab):
|
||||
add_tab(tab.id)
|
||||
self.tabs.append(tab)
|
||||
|
||||
def _remove_tab(self, tab):
|
||||
remove_tab(tab.id)
|
||||
self.tabs.remove(tab)
|
||||
|
||||
def _set_active_tab(self, idx):
|
||||
self.active_tab_idx = idx
|
||||
set_active_tab(idx)
|
||||
|
||||
def init(self, startup_session):
|
||||
self.tabs = [Tab(self.opts, self.args, self.title_changed, t) for t in startup_session.tabs]
|
||||
self.active_tab_idx = startup_session.active_tab_idx
|
||||
for t in startup_session.tabs:
|
||||
self._add_tab(Tab(self.opts, self.args, self.title_changed, t))
|
||||
self._set_active_tab(max(0, min(startup_session.active_tab_idx, len(self.tabs) - 1)))
|
||||
if len(self.tabs) > 1:
|
||||
get_boss().tabbar_visibility_changed()
|
||||
self.update_tab_bar()
|
||||
@ -310,7 +326,7 @@ class TabManager:
|
||||
tab.relayout()
|
||||
|
||||
def set_active_tab(self, idx):
|
||||
self.active_tab_idx = idx
|
||||
self._set_active_tab(idx)
|
||||
self.active_tab.relayout_borders()
|
||||
self.update_tab_bar()
|
||||
|
||||
@ -337,7 +353,8 @@ class TabManager:
|
||||
idx = self.active_tab_idx
|
||||
nidx = (idx + len(self.tabs) + delta) % len(self.tabs)
|
||||
self.tabs[idx], self.tabs[nidx] = self.tabs[nidx], self.tabs[idx]
|
||||
self.active_tab_idx = nidx
|
||||
swap_tabs(idx, nidx)
|
||||
self._set_active_tab(nidx)
|
||||
self.update_tab_bar()
|
||||
|
||||
def title_changed(self, new_title):
|
||||
@ -345,16 +362,17 @@ class TabManager:
|
||||
|
||||
def new_tab(self, special_window=None):
|
||||
needs_resize = len(self.tabs) == 1
|
||||
self.active_tab_idx = len(self.tabs)
|
||||
self.tabs.append(Tab(self.opts, self.args, self.title_changed, special_window=special_window))
|
||||
idx = len(self.tabs)
|
||||
self._add_tab(Tab(self.opts, self.args, self.title_changed, special_window=special_window))
|
||||
self._set_active_tab(idx)
|
||||
self.update_tab_bar()
|
||||
if needs_resize:
|
||||
get_boss().tabbar_visibility_changed()
|
||||
|
||||
def remove(self, tab):
|
||||
needs_resize = len(self.tabs) == 2
|
||||
self.tabs.remove(tab)
|
||||
self.active_tab_idx = max(0, min(self.active_tab_idx, len(self.tabs) - 1))
|
||||
self._remove_tab(tab)
|
||||
self._set_active_tab(max(0, min(self.active_tab_idx, len(self.tabs) - 1)))
|
||||
self.update_tab_bar()
|
||||
tab.destroy()
|
||||
if needs_resize:
|
||||
@ -386,3 +404,4 @@ class TabManager:
|
||||
if len(self.tabs) < 2:
|
||||
return
|
||||
self.tab_bar.render()
|
||||
# }}}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user