156 lines
4.7 KiB
Python
156 lines
4.7 KiB
Python
#!/usr/bin/env python
|
|
# vim:fileencoding=utf-8
|
|
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
|
|
|
from ctypes import addressof
|
|
from itertools import chain
|
|
from threading import Lock
|
|
from functools import partial
|
|
|
|
from .constants import GLfloat, GLint, GLuint, viewport_size
|
|
from .fast_data_types import GL_TRIANGLE_FAN, glMultiDrawArrays, glUniform3fv
|
|
from .shaders import ShaderProgram
|
|
from .utils import pt_to_px
|
|
|
|
|
|
def as_color(c):
|
|
return c[0] / 255, c[1] / 255, c[2] / 255
|
|
|
|
|
|
def to_opengl(x, y):
|
|
return -1 + 2 * x / viewport_size.width, 1 - 2 * y / viewport_size.height
|
|
|
|
|
|
def as_rect(left, top, right, bottom, color=0):
|
|
for (x, y) in ((right, top), (right, bottom), (left, bottom), (left, top)):
|
|
x, y = to_opengl(x, y)
|
|
yield x
|
|
yield y
|
|
yield color
|
|
|
|
|
|
class BordersProgram(ShaderProgram):
|
|
|
|
def __init__(self):
|
|
ShaderProgram.__init__(
|
|
self, '''\
|
|
uniform vec3 colors[3];
|
|
in vec3 rect;
|
|
out vec3 color;
|
|
|
|
void main() {
|
|
gl_Position = vec4(rect[0], rect[1], 0, 1);
|
|
color = colors[uint(rect[2])];
|
|
}
|
|
''', '''\
|
|
in vec3 color;
|
|
out vec4 final_color;
|
|
|
|
void main() {
|
|
final_color = vec4(color, 1);
|
|
}
|
|
''')
|
|
self.add_vertex_array('rect')
|
|
|
|
def send_data(self, data):
|
|
self.send_vertex_data('rect', data)
|
|
|
|
def set_colors(self, color_buf):
|
|
glUniform3fv(self.uniform_location('colors'), 3, addressof(color_buf))
|
|
|
|
|
|
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:
|
|
|
|
def __init__(self, opts):
|
|
self.is_dirty = False
|
|
self.lock = Lock()
|
|
self.can_render = False
|
|
self.border_width = pt_to_px(opts.window_border_width)
|
|
self.padding_width = pt_to_px(opts.window_padding_width)
|
|
self.color_buf = (GLfloat * 9)(
|
|
*as_color(opts.background), *as_color(opts.active_border_color),
|
|
*as_color(opts.inactive_border_color))
|
|
|
|
def __call__(
|
|
self,
|
|
windows,
|
|
active_window,
|
|
current_layout,
|
|
extra_blank_rects,
|
|
draw_window_borders=True
|
|
):
|
|
rects = []
|
|
for br in chain(current_layout.blank_rects, extra_blank_rects):
|
|
rects.extend(as_rect(*br))
|
|
bw, pw = self.border_width, self.padding_width
|
|
fw = bw + pw
|
|
border = border_maker(rects)
|
|
|
|
if fw > 0:
|
|
for w in windows:
|
|
g = w.geometry
|
|
if bw > 0 and draw_window_borders:
|
|
# Draw the border rectangles
|
|
color = 1 if w is active_window else 2
|
|
border(
|
|
color, bw, g.left - fw, g.top - fw, g.right + fw,
|
|
g.bottom + fw)
|
|
if pw > 0:
|
|
# Draw the background rectangles over the padding region
|
|
color = 0
|
|
border(
|
|
color, pw, g.left - pw, g.top - pw, g.right + pw,
|
|
g.bottom + pw)
|
|
|
|
with self.lock:
|
|
self.num_of_rects = len(rects) // 12
|
|
self.rects = (GLfloat * len(rects))()
|
|
self.starts = (GLint * self.num_of_rects)()
|
|
self.counts = (GLuint * self.num_of_rects)()
|
|
for i, x in enumerate(rects):
|
|
self.rects[i] = x
|
|
if i % 12 == 0:
|
|
idx = i // 12
|
|
self.starts[idx] = i // 3
|
|
self.counts[idx] = 4
|
|
self.is_dirty = True
|
|
self.can_render = True
|
|
|
|
def render(self, program):
|
|
with self.lock:
|
|
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
|
|
glMultiDrawArrays(
|
|
GL_TRIANGLE_FAN,
|
|
addressof(self.starts),
|
|
addressof(self.counts), self.num_of_rects)
|