mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-27 18:51:41 +02:00
Migrate the borders program
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
#version GLSL_VERSION
|
#version GLSL_VERSION
|
||||||
uniform vec3 colors[3];
|
|
||||||
uniform uvec2 viewport;
|
uniform uvec2 viewport;
|
||||||
in uvec4 rect; // left, top, right, bottom
|
in uvec4 rect; // left, top, right, bottom
|
||||||
|
in uint rect_color;
|
||||||
out vec3 color;
|
out vec3 color;
|
||||||
|
|
||||||
// indices into the rect vector
|
// indices into the rect vector
|
||||||
@@ -17,10 +17,16 @@ const uvec2 pos_map[] = uvec2[4](
|
|||||||
uvec2(LEFT, TOP)
|
uvec2(LEFT, TOP)
|
||||||
);
|
);
|
||||||
|
|
||||||
float to_opengl(uint val, uint sz) { return -1.0 + 2.0 * (float(val) / float(sz)); }
|
float to_opengl(uint val, uint sz) {
|
||||||
|
return -1.0 + 2.0 * (float(val) / float(sz));
|
||||||
|
}
|
||||||
|
|
||||||
|
float to_color(uint c) {
|
||||||
|
return float(c & uint(0xff)) / 255.0;
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
uvec2 pos = pos_map[gl_VertexID];
|
uvec2 pos = pos_map[gl_VertexID];
|
||||||
gl_Position = vec4(to_opengl(rect[pos.x], viewport.x), to_opengl(rect[pos.y], viewport.y), 0, 1);
|
gl_Position = vec4(to_opengl(rect[pos.x], viewport.x), to_opengl(rect[pos.y], viewport.y), 0, 1);
|
||||||
color = vec3(1, 0, 0);
|
color = vec3(to_color(rect_color >> 16), to_color(rect_color >> 8), to_color(rect_color));
|
||||||
}
|
}
|
||||||
|
|||||||
115
kitty/borders.py
115
kitty/borders.py
@@ -2,84 +2,49 @@
|
|||||||
# vim:fileencoding=utf-8
|
# vim:fileencoding=utf-8
|
||||||
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
from ctypes import addressof
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
from .constants import GLfloat, GLuint, viewport_size
|
from .constants import viewport_size
|
||||||
from .fast_data_types import (
|
from .fast_data_types import (
|
||||||
GL_STATIC_DRAW, GL_TRIANGLE_FAN, glDrawArraysInstanced, glUniform3fv,
|
BORDERS_PROGRAM, add_borders_rect, compile_program, draw_borders,
|
||||||
BORDERS_PROGRAM, GL_UNSIGNED_INT, glUniform2ui
|
init_borders_program, send_borders_rects
|
||||||
)
|
)
|
||||||
from .shaders import ShaderProgram, load_shaders
|
from .shaders import load_shaders
|
||||||
from .utils import pt_to_px
|
from .utils import color_as_int, pt_to_px
|
||||||
|
|
||||||
|
|
||||||
def as_color(c):
|
def vertical_edge(color, width, top, bottom, left):
|
||||||
return c[0] / 255, c[1] / 255, c[2] / 255
|
add_borders_rect(left, top, left + width, bottom, color)
|
||||||
|
|
||||||
|
|
||||||
def to_opengl(val, sz):
|
def horizontal_edge(color, height, left, right, top):
|
||||||
return -1 + 2 * val / sz
|
add_borders_rect(left, top, right, top + height, color)
|
||||||
|
|
||||||
|
|
||||||
def as_rect(left, top, right, bottom, color=0):
|
def edge(func, color, sz, a, b):
|
||||||
yield left
|
return partial(func, color, sz, a, b)
|
||||||
yield top
|
|
||||||
yield right
|
|
||||||
yield bottom
|
|
||||||
|
|
||||||
|
|
||||||
class BordersProgram(ShaderProgram):
|
def border(color, sz, left, top, right, bottom):
|
||||||
|
horz = edge(horizontal_edge, color, sz, left, right)
|
||||||
def __init__(self):
|
horz(top), horz(bottom - sz) # top, bottom edges
|
||||||
ShaderProgram.__init__(self, BORDERS_PROGRAM, *load_shaders('border'))
|
vert = edge(vertical_edge, color, sz, top, bottom)
|
||||||
with self.array_object_creator() as add_attribute:
|
vert(left), vert(right - sz) # left, right edges
|
||||||
self.vao_id = add_attribute.vao_id
|
|
||||||
add_attribute('rect', size=4, dtype=GL_UNSIGNED_INT, divisor=1)
|
|
||||||
|
|
||||||
def send_data(self, data):
|
|
||||||
self.send_vertex_data(self.vao_id, data, usage=GL_STATIC_DRAW)
|
|
||||||
|
|
||||||
def set_colors(self, color_buf):
|
|
||||||
glUniform3fv(self.uniform_location('colors'), 3, addressof(color_buf))
|
|
||||||
glUniform2ui(self.uniform_location('viewport'), viewport_size.width, viewport_size.height)
|
|
||||||
|
|
||||||
|
|
||||||
def border_maker(rects):
|
|
||||||
' Create a function that will add all the rectangles for drawing a border to rects '
|
|
||||||
|
|
||||||
def r(l, t, b, r, color):
|
|
||||||
rects.extend(as_rect(l, t, b, r, color))
|
|
||||||
|
|
||||||
def vertical_edge(color, width, top, bottom, left):
|
|
||||||
r(left, top, left + width, bottom, color)
|
|
||||||
|
|
||||||
def horizontal_edge(color, height, left, right, top):
|
|
||||||
r(left, top, right, top + height, color)
|
|
||||||
|
|
||||||
def edge(func, color, sz, a, b):
|
|
||||||
return partial(func, color, sz, a, b)
|
|
||||||
|
|
||||||
def border(color, sz, left, top, right, bottom):
|
|
||||||
horz = edge(horizontal_edge, color, sz, left, right)
|
|
||||||
horz(top), horz(bottom - sz) # top, bottom edges
|
|
||||||
vert = edge(vertical_edge, color, sz, top, bottom)
|
|
||||||
vert(left), vert(right - sz) # left, right edges
|
|
||||||
|
|
||||||
return border
|
|
||||||
|
|
||||||
|
|
||||||
class Borders:
|
class Borders:
|
||||||
|
|
||||||
def __init__(self, opts):
|
def __init__(self, opts):
|
||||||
self.is_dirty = False
|
self.is_dirty = False
|
||||||
self.can_render = False
|
|
||||||
self.border_width = pt_to_px(opts.window_border_width)
|
self.border_width = pt_to_px(opts.window_border_width)
|
||||||
self.padding_width = pt_to_px(opts.window_padding_width)
|
self.padding_width = pt_to_px(opts.window_padding_width)
|
||||||
self.color_buf = (GLfloat * 9)(
|
compile_program(BORDERS_PROGRAM, *load_shaders('border'))
|
||||||
*as_color(opts.background), *as_color(opts.active_border_color),
|
init_borders_program()
|
||||||
*as_color(opts.inactive_border_color))
|
self.background = color_as_int(opts.background)
|
||||||
|
self.active_border = color_as_int(opts.active_border_color)
|
||||||
|
self.inactive_border = color_as_int(opts.inactive_border_color)
|
||||||
|
self.dirty = False
|
||||||
|
|
||||||
def __call__(
|
def __call__(
|
||||||
self,
|
self,
|
||||||
@@ -89,44 +54,30 @@ class Borders:
|
|||||||
extra_blank_rects,
|
extra_blank_rects,
|
||||||
draw_window_borders=True
|
draw_window_borders=True
|
||||||
):
|
):
|
||||||
rects = []
|
add_borders_rect(0, 0, 0, 0, 0)
|
||||||
for br in chain(current_layout.blank_rects, extra_blank_rects):
|
for br in chain(current_layout.blank_rects, extra_blank_rects):
|
||||||
rects.extend(as_rect(*br))
|
add_borders_rect(*br, self.background)
|
||||||
bw, pw = self.border_width, self.padding_width
|
bw, pw = self.border_width, self.padding_width
|
||||||
fw = bw + pw
|
fw = bw + pw
|
||||||
border = border_maker(rects)
|
|
||||||
|
|
||||||
if fw > 0:
|
if fw > 0:
|
||||||
for w in windows:
|
for w in windows:
|
||||||
g = w.geometry
|
g = w.geometry
|
||||||
if bw > 0 and draw_window_borders:
|
if bw > 0 and draw_window_borders:
|
||||||
# Draw the border rectangles
|
# Draw the border rectangles
|
||||||
color = 1 if w is active_window else 2
|
color = self.active_border if w is active_window else self.inactive_border
|
||||||
border(
|
border(
|
||||||
color, bw, g.left - fw, g.top - fw, g.right + fw,
|
color, bw, g.left - fw, g.top - fw, g.right + fw,
|
||||||
g.bottom + fw)
|
g.bottom + fw
|
||||||
|
)
|
||||||
if pw > 0:
|
if pw > 0:
|
||||||
# Draw the background rectangles over the padding region
|
# Draw the background rectangles over the padding region
|
||||||
color = 0
|
color = self.background
|
||||||
border(
|
border(
|
||||||
color, pw, g.left - pw, g.top - pw, g.right + pw,
|
color, pw, g.left - pw, g.top - pw, g.right + pw,
|
||||||
g.bottom + pw)
|
g.bottom + pw
|
||||||
|
)
|
||||||
|
send_borders_rects(viewport_size.width, viewport_size.height)
|
||||||
|
|
||||||
self.num_of_rects = len(rects) // 4
|
def render(self):
|
||||||
self.rects = (GLuint * len(rects))()
|
draw_borders()
|
||||||
for i, x in enumerate(rects):
|
|
||||||
self.rects[i] = x
|
|
||||||
self.is_dirty = True
|
|
||||||
self.can_render = True
|
|
||||||
|
|
||||||
def render(self, program):
|
|
||||||
if not self.can_render:
|
|
||||||
return
|
|
||||||
with program:
|
|
||||||
if self.is_dirty:
|
|
||||||
program.send_data(self.rects)
|
|
||||||
program.set_colors(self.color_buf)
|
|
||||||
self.is_dirty = False
|
|
||||||
with program.bound_vertex_array(program.vao_id):
|
|
||||||
glDrawArraysInstanced(
|
|
||||||
GL_TRIANGLE_FAN, 0, 4, self.num_of_rects)
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ from gettext import gettext as _
|
|||||||
from time import monotonic
|
from time import monotonic
|
||||||
from weakref import WeakValueDictionary
|
from weakref import WeakValueDictionary
|
||||||
|
|
||||||
from .borders import BordersProgram
|
|
||||||
from .char_grid import load_shader_programs
|
from .char_grid import load_shader_programs
|
||||||
from .config import MINIMUM_FONT_SIZE
|
from .config import MINIMUM_FONT_SIZE
|
||||||
from .constants import (
|
from .constants import (
|
||||||
@@ -121,7 +120,6 @@ class Boss:
|
|||||||
self.sprites = Sprites()
|
self.sprites = Sprites()
|
||||||
self.sprites.do_layout(cell_size.width, cell_size.height)
|
self.sprites.do_layout(cell_size.width, cell_size.height)
|
||||||
self.cell_program = load_shader_programs()
|
self.cell_program = load_shader_programs()
|
||||||
self.borders_program = BordersProgram()
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
||||||
self.glfw_window.set_click_cursor(False)
|
self.glfw_window.set_click_cursor(False)
|
||||||
self.show_mouse_cursor()
|
self.show_mouse_cursor()
|
||||||
|
|||||||
@@ -427,7 +427,7 @@ render(ChildMonitor *self, double *timeout) {
|
|||||||
double time_since_last_render = now - last_render_at;
|
double time_since_last_render = now - last_render_at;
|
||||||
if (time_since_last_render > self->repaint_delay) {
|
if (time_since_last_render > self->repaint_delay) {
|
||||||
ret = PyObject_CallFunctionObjArgs(self->render_func, NULL);
|
ret = PyObject_CallFunctionObjArgs(self->render_func, NULL);
|
||||||
if (ret == NULL) return false;
|
if (ret == NULL) { PyErr_Print(); return false; }
|
||||||
else Py_DECREF(ret);
|
else Py_DECREF(ret);
|
||||||
glfwSwapBuffers(glfw_window_id);
|
glfwSwapBuffers(glfw_window_id);
|
||||||
last_render_at = now;
|
last_render_at = now;
|
||||||
|
|||||||
120
kitty/shaders.c
120
kitty/shaders.c
@@ -201,10 +201,11 @@ create_buffer(GLenum usage) {
|
|||||||
glGenBuffers(1, &buffer_id);
|
glGenBuffers(1, &buffer_id);
|
||||||
if (set_error_from_gl()) return -1;
|
if (set_error_from_gl()) return -1;
|
||||||
for (size_t i = 0; i < sizeof(buffers)/sizeof(buffers[0]); i++) {
|
for (size_t i = 0; i < sizeof(buffers)/sizeof(buffers[0]); i++) {
|
||||||
if (!buffers[i].id) {
|
if (buffers[i].id == 0) {
|
||||||
buffers[i].id = buffer_id;
|
buffers[i].id = buffer_id;
|
||||||
buffers[i].size = 0;
|
buffers[i].size = 0;
|
||||||
buffers[i].usage = usage;
|
buffers[i].usage = usage;
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
glDeleteBuffers(1, &buffer_id);
|
glDeleteBuffers(1, &buffer_id);
|
||||||
@@ -283,13 +284,13 @@ create_vao() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
add_buffer_to_vao(ssize_t vao_idx, GLenum usage) {
|
add_buffer_to_vao(ssize_t vao_idx) {
|
||||||
VAO* vao = vaos + vao_idx;
|
VAO* vao = vaos + vao_idx;
|
||||||
if (vao->num_buffers >= sizeof(vao->buffers) / sizeof(vao->buffers[0])) {
|
if (vao->num_buffers >= sizeof(vao->buffers) / sizeof(vao->buffers[0])) {
|
||||||
set_local_error("too many buffers in a single VAO");
|
set_local_error("too many buffers in a single VAO");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ssize_t buf = create_buffer(usage);
|
ssize_t buf = create_buffer(GL_ARRAY_BUFFER);
|
||||||
if (buf < 0) return false;
|
if (buf < 0) return false;
|
||||||
vao->buffers[vao->num_buffers++] = buf;
|
vao->buffers[vao->num_buffers++] = buf;
|
||||||
return true;
|
return true;
|
||||||
@@ -351,12 +352,11 @@ unbind_vertex_array() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void*
|
static void*
|
||||||
map_vao_buffer(ssize_t vao_idx, size_t bufnum, GLsizeiptr size, GLenum usage, GLenum access) {
|
map_vao_buffer(ssize_t vao_idx, GLsizeiptr size, size_t bufnum, GLenum usage, GLenum access) {
|
||||||
ssize_t buf_idx = vaos[vao_idx].buffers[bufnum];
|
ssize_t buf_idx = vaos[vao_idx].buffers[bufnum];
|
||||||
bind_buffer(buf_idx);
|
bind_buffer(buf_idx);
|
||||||
alloc_buffer(buf_idx, size, usage);
|
alloc_buffer(buf_idx, size, usage);
|
||||||
void *ans = map_buffer(buf_idx, access);
|
void *ans = map_buffer(buf_idx, access);
|
||||||
unbind_buffer(buf_idx);
|
|
||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,6 +364,7 @@ static void
|
|||||||
unmap_vao_buffer(ssize_t vao_idx, size_t bufnum) {
|
unmap_vao_buffer(ssize_t vao_idx, size_t bufnum) {
|
||||||
ssize_t buf_idx = vaos[vao_idx].buffers[bufnum];
|
ssize_t buf_idx = vaos[vao_idx].buffers[bufnum];
|
||||||
unmap_buffer(buf_idx);
|
unmap_buffer(buf_idx);
|
||||||
|
unbind_buffer(buf_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
@@ -387,6 +388,7 @@ init_cursor_program() {
|
|||||||
else { set_local_error("Unknown uniform in cursor program"); return false; }
|
else { set_local_error("Unknown uniform in cursor program"); return false; }
|
||||||
}
|
}
|
||||||
if (left) { set_local_error("Left over uniforms in cursor program"); return false; }
|
if (left) { set_local_error("Left over uniforms in cursor program"); return false; }
|
||||||
|
#undef SET_LOC
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,6 +405,75 @@ draw_cursor(bool semi_transparent, bool is_focused, color_type color, float alph
|
|||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
// Borders {{{
|
||||||
|
enum BorderUniforms { BORDER_viewport, NUM_BORDER_UNIFORMS };
|
||||||
|
static GLint border_uniform_locations[NUM_BORDER_UNIFORMS] = {0};
|
||||||
|
static ssize_t border_vertex_array;
|
||||||
|
static GLsizei num_border_rects = 0;
|
||||||
|
static GLuint rect_buf[5 * 1024];
|
||||||
|
static GLuint *rect_pos = NULL;
|
||||||
|
|
||||||
|
static bool
|
||||||
|
init_borders_program() {
|
||||||
|
Program *p = programs + BORDERS_PROGRAM;
|
||||||
|
int left = NUM_BORDER_UNIFORMS;
|
||||||
|
border_vertex_array = create_vao();
|
||||||
|
if (set_error_from_gl()) return false;
|
||||||
|
for (int i = 0; i < p->num_of_uniforms; i++, left--) {
|
||||||
|
#define SET_LOC(which) if (strcmp(p->uniforms[i].name, #which) == 0) border_uniform_locations[BORDER_##which] = p->uniforms[i].id
|
||||||
|
SET_LOC(viewport);
|
||||||
|
else { set_local_error("Unknown uniform in borders program"); return false; }
|
||||||
|
}
|
||||||
|
if (left) { set_local_error("Left over uniforms in borders program"); return false; }
|
||||||
|
#undef SET_LOC
|
||||||
|
add_buffer_to_vao(border_vertex_array);
|
||||||
|
if (set_error_from_gl()) return false;
|
||||||
|
add_attribute_to_vao(BORDERS_PROGRAM, border_vertex_array, "rect",
|
||||||
|
/*size=*/4, /*dtype=*/GL_UNSIGNED_INT, /*stride=*/sizeof(GLuint)*5, /*offset=*/0, /*divisor=*/1);
|
||||||
|
if (set_error_from_gl()) return false;
|
||||||
|
add_attribute_to_vao(BORDERS_PROGRAM, border_vertex_array, "rect_color",
|
||||||
|
/*size=*/1, /*dtype=*/GL_UNSIGNED_INT, /*stride=*/sizeof(GLuint)*5, /*offset=*/(void*)(sizeof(GLuint)*4), /*divisor=*/1);
|
||||||
|
if (set_error_from_gl()) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
draw_borders() {
|
||||||
|
if (num_border_rects) {
|
||||||
|
bind_program(BORDERS_PROGRAM);
|
||||||
|
bind_vertex_array(border_vertex_array);
|
||||||
|
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, num_border_rects);
|
||||||
|
unbind_vertex_array();
|
||||||
|
unbind_program();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_borders_rect(GLuint left, GLuint top, GLuint right, GLuint bottom, GLuint color) {
|
||||||
|
if (!left && !top && !right && !bottom) { num_border_rects = 0; rect_pos = rect_buf; return; }
|
||||||
|
num_border_rects++;
|
||||||
|
*(rect_pos++) = left;
|
||||||
|
*(rect_pos++) = top;
|
||||||
|
*(rect_pos++) = right;
|
||||||
|
*(rect_pos++) = bottom;
|
||||||
|
*(rect_pos++) = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_borders_rects(GLuint vw, GLuint vh) {
|
||||||
|
if (num_border_rects) {
|
||||||
|
size_t sz = sizeof(GLuint) * 5 * num_border_rects;
|
||||||
|
void *borders_buf_address = map_vao_buffer(border_vertex_array, sz, 0, GL_STATIC_DRAW, GL_WRITE_ONLY);
|
||||||
|
if (borders_buf_address) memcpy(borders_buf_address, rect_buf, sz);
|
||||||
|
unmap_vao_buffer(border_vertex_array, 0);
|
||||||
|
}
|
||||||
|
bind_program(BORDERS_PROGRAM);
|
||||||
|
printf(gl_strerror(glGetError()));
|
||||||
|
glUniform2ui(border_uniform_locations[BORDER_viewport], vw, vh);
|
||||||
|
unbind_program();
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
// Python API {{{
|
// Python API {{{
|
||||||
static PyObject*
|
static PyObject*
|
||||||
enable_automatic_opengl_error_checking(PyObject UNUSED *self, PyObject *val) {
|
enable_automatic_opengl_error_checking(PyObject UNUSED *self, PyObject *val) {
|
||||||
@@ -450,13 +521,14 @@ compile_program(PyObject UNUSED *self, PyObject *args) {
|
|||||||
end:
|
end:
|
||||||
if (vertex_shader_id != 0) glDeleteShader(vertex_shader_id);
|
if (vertex_shader_id != 0) glDeleteShader(vertex_shader_id);
|
||||||
if (fragment_shader_id != 0) glDeleteShader(fragment_shader_id);
|
if (fragment_shader_id != 0) glDeleteShader(fragment_shader_id);
|
||||||
|
set_error_from_gl();
|
||||||
translate_error();
|
translate_error();
|
||||||
if (PyErr_Occurred()) { glDeleteProgram(programs[which].id); programs[which].id = 0; return NULL;}
|
if (PyErr_Occurred()) { glDeleteProgram(programs[which].id); programs[which].id = 0; return NULL;}
|
||||||
return Py_BuildValue("I", programs[which].id);
|
return Py_BuildValue("I", programs[which].id);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_ERROR_ALWAYS { translate_error(); if (PyErr_Occurred()) return NULL; }
|
#define CHECK_ERROR_ALWAYS { set_error_from_gl(); translate_error(); if (PyErr_Occurred()) return NULL; }
|
||||||
#define CHECK_ERROR if (_enable_error_checking) CHECK_ERROR_ALWAYS
|
#define CHECK_ERROR if (_enable_error_checking) CHECK_ERROR_ALWAYS
|
||||||
#define PYWRAP0(name) static PyObject* py##name(PyObject UNUSED *self)
|
#define PYWRAP0(name) static PyObject* py##name(PyObject UNUSED *self)
|
||||||
#define PYWRAP1(name) static PyObject* py##name(PyObject UNUSED *self, PyObject *args)
|
#define PYWRAP1(name) static PyObject* py##name(PyObject UNUSED *self, PyObject *args)
|
||||||
@@ -466,6 +538,7 @@ end:
|
|||||||
#define TWO_INT(name) PYWRAP1(name) { int a, b; PA("ii", &a, &b); name(a, b); CHECK_ERROR; Py_RETURN_NONE; }
|
#define TWO_INT(name) PYWRAP1(name) { int a, b; PA("ii", &a, &b); name(a, b); CHECK_ERROR; Py_RETURN_NONE; }
|
||||||
#define NO_ARG(name) PYWRAP0(name) { name(); CHECK_ERROR; Py_RETURN_NONE; }
|
#define NO_ARG(name) PYWRAP0(name) { name(); CHECK_ERROR; Py_RETURN_NONE; }
|
||||||
#define NO_ARG_CHECK(name) PYWRAP0(name) { name(); CHECK_ERROR_ALWAYS; Py_RETURN_NONE; }
|
#define NO_ARG_CHECK(name) PYWRAP0(name) { name(); CHECK_ERROR_ALWAYS; Py_RETURN_NONE; }
|
||||||
|
#define ONE_INT_CHECK(name) PYWRAP1(name) { name(PyLong_AsSsize_t(args)); CHECK_ERROR_ALWAYS; Py_RETURN_NONE; }
|
||||||
|
|
||||||
ONE_INT(bind_program)
|
ONE_INT(bind_program)
|
||||||
NO_ARG(unbind_program)
|
NO_ARG(unbind_program)
|
||||||
@@ -477,29 +550,29 @@ PYWRAP0(create_vao) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ONE_INT(remove_vao)
|
ONE_INT(remove_vao)
|
||||||
|
ONE_INT_CHECK(add_buffer_to_vao)
|
||||||
PYWRAP1(add_buffer_to_vao) {
|
|
||||||
int vao_idx, usage;
|
|
||||||
PA("ii", &vao_idx, &usage);
|
|
||||||
if (!add_buffer_to_vao(vao_idx, usage)) return NULL;
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PYWRAP2(add_attribute_to_vao) {
|
PYWRAP2(add_attribute_to_vao) {
|
||||||
int program, vao, data_type = GL_FLOAT, size = 3;
|
int program, vao, data_type = GL_FLOAT, size = 3;
|
||||||
char *name;
|
char *name;
|
||||||
unsigned int stride = 0, divisor = 0;
|
unsigned int stride = 0, divisor = 0;
|
||||||
PyObject *offset;
|
PyObject *offset = NULL;
|
||||||
static char* keywords[] = {"program", "vao", "name", "size", "dtype", "stride", "offset", "divisor", NULL};
|
static char* keywords[] = {"program", "vao", "name", "size", "dtype", "stride", "offset", "divisor", NULL};
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "i i s | i i I O! I", keywords, &program, &vao, &name, &size, &data_type, &stride, &offset, &PyLong_Type, &divisor)) return NULL;
|
if (!PyArg_ParseTupleAndKeywords(args, kw, "iis|iiIO!I", keywords, &program, &vao, &name, &size, &data_type, &stride, &PyLong_Type, &offset, &divisor)) return NULL;
|
||||||
if (!add_attribute_to_vao(program, vao, name, size, data_type, stride, PyLong_AsVoidPtr(offset), divisor)) return NULL;
|
if (!add_attribute_to_vao(program, vao, name, size, data_type, stride, offset ? PyLong_AsVoidPtr(offset) : NULL, divisor)) { translate_error(); return NULL; }
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ONE_INT(bind_vertex_array)
|
ONE_INT(bind_vertex_array)
|
||||||
NO_ARG(unbind_vertex_array)
|
NO_ARG(unbind_vertex_array)
|
||||||
TWO_INT(unmap_vao_buffer)
|
TWO_INT(unmap_vao_buffer)
|
||||||
PYWRAP1(map_vao_buffer) { int a,b,c,d,e; PA("iiiii", &a, &b, &c, &d, &e); void *ans = map_vao_buffer(a, b, c, d, e); CHECK_ERROR; return PyLong_FromVoidPtr(ans); }
|
PYWRAP1(map_vao_buffer) {
|
||||||
|
int vao_idx, bufnum=0, size, usage=GL_STREAM_DRAW, access=GL_WRITE_ONLY;
|
||||||
|
PA("ii|iii", &vao_idx, &size, &bufnum, &usage, &access);
|
||||||
|
void *ans = map_vao_buffer(vao_idx, size, bufnum, usage, access);
|
||||||
|
CHECK_ERROR;
|
||||||
|
return PyLong_FromVoidPtr(ans);
|
||||||
|
}
|
||||||
|
|
||||||
NO_ARG_CHECK(init_cursor_program)
|
NO_ARG_CHECK(init_cursor_program)
|
||||||
PYWRAP1(draw_cursor) {
|
PYWRAP1(draw_cursor) {
|
||||||
@@ -512,6 +585,11 @@ PYWRAP1(draw_cursor) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NO_ARG_CHECK(init_borders_program)
|
||||||
|
NO_ARG(draw_borders)
|
||||||
|
PYWRAP1(add_borders_rect) { unsigned int a, b, c, d, e; PA("IIIII", &a, &b, &c, &d, &e); add_borders_rect(a, b, c, d, e); CHECK_ERROR; Py_RETURN_NONE; }
|
||||||
|
TWO_INT(send_borders_rects)
|
||||||
|
|
||||||
#define M(name, arg_type) {#name, (PyCFunction)name, arg_type, NULL}
|
#define M(name, arg_type) {#name, (PyCFunction)name, arg_type, NULL}
|
||||||
#define MW(name, arg_type) {#name, (PyCFunction)py##name, arg_type, NULL}
|
#define MW(name, arg_type) {#name, (PyCFunction)py##name, arg_type, NULL}
|
||||||
static PyMethodDef module_methods[] = {
|
static PyMethodDef module_methods[] = {
|
||||||
@@ -520,8 +598,8 @@ static PyMethodDef module_methods[] = {
|
|||||||
M(compile_program, METH_VARARGS),
|
M(compile_program, METH_VARARGS),
|
||||||
MW(create_vao, METH_NOARGS),
|
MW(create_vao, METH_NOARGS),
|
||||||
MW(remove_vao, METH_O),
|
MW(remove_vao, METH_O),
|
||||||
MW(add_buffer_to_vao, METH_VARARGS),
|
MW(add_buffer_to_vao, METH_O),
|
||||||
MW(add_attribute_to_vao, METH_VARARGS),
|
MW(add_attribute_to_vao, METH_VARARGS | METH_KEYWORDS),
|
||||||
MW(bind_vertex_array, METH_O),
|
MW(bind_vertex_array, METH_O),
|
||||||
MW(unbind_vertex_array, METH_NOARGS),
|
MW(unbind_vertex_array, METH_NOARGS),
|
||||||
MW(map_vao_buffer, METH_VARARGS),
|
MW(map_vao_buffer, METH_VARARGS),
|
||||||
@@ -530,6 +608,10 @@ static PyMethodDef module_methods[] = {
|
|||||||
MW(unbind_program, METH_NOARGS),
|
MW(unbind_program, METH_NOARGS),
|
||||||
MW(init_cursor_program, METH_NOARGS),
|
MW(init_cursor_program, METH_NOARGS),
|
||||||
MW(draw_cursor, METH_VARARGS),
|
MW(draw_cursor, METH_VARARGS),
|
||||||
|
MW(init_borders_program, METH_NOARGS),
|
||||||
|
MW(draw_borders, METH_NOARGS),
|
||||||
|
MW(add_borders_rect, METH_VARARGS),
|
||||||
|
MW(send_borders_rects, METH_VARARGS),
|
||||||
|
|
||||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ from .utils import color_as_int
|
|||||||
from .window import Window
|
from .window import Window
|
||||||
|
|
||||||
TabbarData = namedtuple('TabbarData', 'title is_active is_last')
|
TabbarData = namedtuple('TabbarData', 'title is_active is_last')
|
||||||
|
borders = None
|
||||||
|
|
||||||
|
|
||||||
def SpecialWindow(cmd, stdin=None, override_title=None):
|
def SpecialWindow(cmd, stdin=None, override_title=None):
|
||||||
@@ -29,11 +30,13 @@ def SpecialWindow(cmd, stdin=None, override_title=None):
|
|||||||
class Tab:
|
class Tab:
|
||||||
|
|
||||||
def __init__(self, opts, args, on_title_change, session_tab=None, special_window=None):
|
def __init__(self, opts, args, on_title_change, session_tab=None, special_window=None):
|
||||||
|
global borders
|
||||||
self.opts, self.args = opts, args
|
self.opts, self.args = opts, args
|
||||||
self.name = getattr(session_tab, 'name', '')
|
self.name = getattr(session_tab, 'name', '')
|
||||||
self.on_title_change = on_title_change
|
self.on_title_change = on_title_change
|
||||||
self.enabled_layouts = list(getattr(session_tab, 'enabled_layouts', None) or opts.enabled_layouts)
|
self.enabled_layouts = list(getattr(session_tab, 'enabled_layouts', None) or opts.enabled_layouts)
|
||||||
self.borders = Borders(opts)
|
if borders is None:
|
||||||
|
borders = Borders(opts)
|
||||||
self.windows = deque()
|
self.windows = deque()
|
||||||
self.active_window_idx = 0
|
self.active_window_idx = 0
|
||||||
for i, which in enumerate('first second third fourth fifth sixth seventh eighth ninth tenth'.split()):
|
for i, which in enumerate('first second third fourth fifth sixth seventh eighth ninth tenth'.split()):
|
||||||
@@ -41,7 +44,7 @@ class Tab:
|
|||||||
if session_tab is None:
|
if session_tab is None:
|
||||||
self.cwd = args.directory
|
self.cwd = args.directory
|
||||||
l = self.enabled_layouts[0]
|
l = self.enabled_layouts[0]
|
||||||
self.current_layout = all_layouts[l](opts, self.borders.border_width, self.windows)
|
self.current_layout = all_layouts[l](opts, borders.border_width, self.windows)
|
||||||
if special_window is None:
|
if special_window is None:
|
||||||
self.new_window()
|
self.new_window()
|
||||||
else:
|
else:
|
||||||
@@ -49,7 +52,7 @@ class Tab:
|
|||||||
else:
|
else:
|
||||||
self.cwd = session_tab.cwd or args.directory
|
self.cwd = session_tab.cwd or args.directory
|
||||||
l = session_tab.layout
|
l = session_tab.layout
|
||||||
self.current_layout = all_layouts[l](opts, self.borders.border_width, self.windows)
|
self.current_layout = all_layouts[l](opts, borders.border_width, self.windows)
|
||||||
self.startup(session_tab)
|
self.startup(session_tab)
|
||||||
|
|
||||||
def startup(self, session_tab):
|
def startup(self, session_tab):
|
||||||
@@ -85,8 +88,8 @@ class Tab:
|
|||||||
|
|
||||||
def relayout_borders(self):
|
def relayout_borders(self):
|
||||||
tm = get_boss().tab_manager
|
tm = get_boss().tab_manager
|
||||||
self.borders(self.windows, self.active_window, self.current_layout, tm.blank_rects,
|
borders(self.windows, self.active_window, self.current_layout, tm.blank_rects,
|
||||||
self.current_layout.needs_window_borders and len(self.windows) > 1)
|
self.current_layout.needs_window_borders and len(self.windows) > 1)
|
||||||
|
|
||||||
def next_layout(self):
|
def next_layout(self):
|
||||||
if len(self.opts.enabled_layouts) > 1:
|
if len(self.opts.enabled_layouts) > 1:
|
||||||
@@ -95,7 +98,7 @@ class Tab:
|
|||||||
except Exception:
|
except Exception:
|
||||||
idx = -1
|
idx = -1
|
||||||
nl = self.opts.enabled_layouts[(idx + 1) % len(self.opts.enabled_layouts)]
|
nl = self.opts.enabled_layouts[(idx + 1) % len(self.opts.enabled_layouts)]
|
||||||
self.current_layout = all_layouts[nl](self.opts, self.borders.border_width, self.windows)
|
self.current_layout = all_layouts[nl](self.opts, borders.border_width, self.windows)
|
||||||
for w in self.windows:
|
for w in self.windows:
|
||||||
w.is_visible_in_layout = True
|
w.is_visible_in_layout = True
|
||||||
self.relayout()
|
self.relayout()
|
||||||
@@ -193,7 +196,7 @@ class Tab:
|
|||||||
self.windows = deque()
|
self.windows = deque()
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
self.borders.render(get_boss().borders_program)
|
borders.render()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return 'Tab(title={}, id={})'.format(self.name or self.title, hex(id(self)))
|
return 'Tab(title={}, id={})'.format(self.name or self.title, hex(id(self)))
|
||||||
@@ -278,7 +281,7 @@ class TabBar:
|
|||||||
self.vao_id = cell_program.create_sprite_map()
|
self.vao_id = cell_program.create_sprite_map()
|
||||||
if self.dirty:
|
if self.dirty:
|
||||||
with cell_program.mapped_vertex_data(self.vao_id, self.data_buffer_size) as address:
|
with cell_program.mapped_vertex_data(self.vao_id, self.data_buffer_size) as address:
|
||||||
self.screen.update_cell_data(address, 0, True)
|
self.screen.update_cell_data(address, True)
|
||||||
if self.layout_changed:
|
if self.layout_changed:
|
||||||
with cell_program.mapped_vertex_data(self.vao_id, self.selection_buf_size, bufnum=1) as address:
|
with cell_program.mapped_vertex_data(self.vao_id, self.selection_buf_size, bufnum=1) as address:
|
||||||
memset(address, 0, self.selection_buf_size)
|
memset(address, 0, self.selection_buf_size)
|
||||||
|
|||||||
Reference in New Issue
Block a user