Move the char grid render call into C
This commit is contained in:
parent
943a1575ad
commit
e6df82b255
@ -365,9 +365,6 @@ class Boss:
|
|||||||
self.glfw_window.set_title(self.glfw_window_title)
|
self.glfw_window.set_title(self.glfw_window_title)
|
||||||
if isosx:
|
if isosx:
|
||||||
cocoa_update_title(self.glfw_window_title)
|
cocoa_update_title(self.glfw_window_title)
|
||||||
for window in tab.visible_windows():
|
|
||||||
if not window.needs_layout:
|
|
||||||
window.char_grid.render_cells()
|
|
||||||
active = self.active_window
|
active = self.active_window
|
||||||
if active is not None:
|
if active is not None:
|
||||||
draw_cursor = True
|
draw_cursor = True
|
||||||
@ -383,7 +380,7 @@ class Boss:
|
|||||||
active.char_grid.render_cursor(self.window_is_focused)
|
active.char_grid.render_cursor(self.window_is_focused)
|
||||||
|
|
||||||
def gui_close_window(self, window):
|
def gui_close_window(self, window):
|
||||||
window.char_grid.destroy()
|
window.destroy()
|
||||||
for tab in self.tab_manager:
|
for tab in self.tab_manager:
|
||||||
if window in tab:
|
if window in tab:
|
||||||
break
|
break
|
||||||
|
|||||||
@ -10,8 +10,7 @@ from .config import build_ansi_color_table
|
|||||||
from .constants import ScreenGeometry, cell_size, viewport_size
|
from .constants import ScreenGeometry, cell_size, viewport_size
|
||||||
from .fast_data_types import (
|
from .fast_data_types import (
|
||||||
CELL_PROGRAM, CURSOR_BEAM, CURSOR_BLOCK, CURSOR_PROGRAM, CURSOR_UNDERLINE,
|
CELL_PROGRAM, CURSOR_BEAM, CURSOR_BLOCK, CURSOR_PROGRAM, CURSOR_UNDERLINE,
|
||||||
compile_program, create_cell_vao, draw_cells, draw_cursor,
|
compile_program, draw_cursor, init_cell_program, init_cursor_program
|
||||||
init_cell_program, init_cursor_program, remove_vao
|
|
||||||
)
|
)
|
||||||
from .rgb import to_color
|
from .rgb import to_color
|
||||||
from .utils import (
|
from .utils import (
|
||||||
@ -42,16 +41,11 @@ def calculate_gl_geometry(window_geometry, viewport_width, viewport_height, cell
|
|||||||
return ScreenGeometry(xstart, ystart, window_geometry.xnum, window_geometry.ynum, dx, dy)
|
return ScreenGeometry(xstart, ystart, window_geometry.xnum, window_geometry.ynum, dx, dy)
|
||||||
|
|
||||||
|
|
||||||
def render_cells(vao_id, sg, screen):
|
|
||||||
draw_cells(vao_id, sg.xstart, sg.ystart, sg.dx, sg.dy, screen)
|
|
||||||
|
|
||||||
|
|
||||||
class CharGrid:
|
class CharGrid:
|
||||||
|
|
||||||
url_pat = re.compile('(?:http|https|file|ftp)://\S+', re.IGNORECASE)
|
url_pat = re.compile('(?:http|https|file|ftp)://\S+', re.IGNORECASE)
|
||||||
|
|
||||||
def __init__(self, screen, opts):
|
def __init__(self, screen, opts):
|
||||||
self.vao_id = create_cell_vao()
|
|
||||||
self.screen_reversed = False
|
self.screen_reversed = False
|
||||||
self.screen = screen
|
self.screen = screen
|
||||||
self.opts = opts
|
self.opts = opts
|
||||||
@ -63,16 +57,9 @@ class CharGrid:
|
|||||||
self.default_cursor = Cursor(0, 0, opts.cursor_shape, opts.cursor_blink_interval > 0)
|
self.default_cursor = Cursor(0, 0, opts.cursor_shape, opts.cursor_blink_interval > 0)
|
||||||
self.opts = opts
|
self.opts = opts
|
||||||
|
|
||||||
def destroy(self):
|
|
||||||
if self.vao_id is not None:
|
|
||||||
remove_vao(self.vao_id)
|
|
||||||
self.vao_id = None
|
|
||||||
|
|
||||||
def update_position(self, window_geometry):
|
def update_position(self, window_geometry):
|
||||||
self.screen_geometry = calculate_gl_geometry(window_geometry, viewport_size.width, viewport_size.height, cell_size.width, cell_size.height)
|
self.screen_geometry = sg = calculate_gl_geometry(window_geometry, viewport_size.width, viewport_size.height, cell_size.width, cell_size.height)
|
||||||
|
return sg
|
||||||
def resize(self, window_geometry):
|
|
||||||
self.update_position(window_geometry)
|
|
||||||
|
|
||||||
def change_colors(self, changes):
|
def change_colors(self, changes):
|
||||||
dirtied = False
|
dirtied = False
|
||||||
@ -172,9 +159,6 @@ class CharGrid:
|
|||||||
def text_for_selection(self):
|
def text_for_selection(self):
|
||||||
return ''.join(self.screen.text_for_selection())
|
return ''.join(self.screen.text_for_selection())
|
||||||
|
|
||||||
def render_cells(self):
|
|
||||||
render_cells(self.vao_id, self.screen_geometry, self.screen)
|
|
||||||
|
|
||||||
def render_cursor(self, is_focused):
|
def render_cursor(self, is_focused):
|
||||||
if not self.screen.cursor_visible or self.screen.scrolled_by:
|
if not self.screen.cursor_visible or self.screen.scrolled_by:
|
||||||
return
|
return
|
||||||
|
|||||||
@ -15,7 +15,7 @@ extern int pthread_setname_np(const char *name);
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#undef _GNU_SOURCE
|
#undef _GNU_SOURCE
|
||||||
#endif
|
#endif
|
||||||
#include "data-types.h"
|
#include "state.h"
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
@ -30,6 +30,7 @@ extern int pthread_setname_np(const char *name);
|
|||||||
|
|
||||||
#define EXTRA_FDS 2
|
#define EXTRA_FDS 2
|
||||||
|
|
||||||
|
extern GlobalState global_state;
|
||||||
static void (*parse_func)(Screen*, PyObject*);
|
static void (*parse_func)(Screen*, PyObject*);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -436,6 +437,16 @@ render(ChildMonitor *self, double *timeout) {
|
|||||||
#define TD global_state.tab_bar_render_data
|
#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);
|
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
|
#undef TD
|
||||||
|
if (global_state.num_tabs) {
|
||||||
|
Tab *tab = global_state.tabs + global_state.active_tab;
|
||||||
|
for (size_t i = 0; i < tab->num_windows; i++) {
|
||||||
|
Window *w = tab->windows + i;
|
||||||
|
#define WD w->render_data
|
||||||
|
if (w->visible && WD.screen) draw_cells(WD.vao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen);
|
||||||
|
#undef WD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = PyObject_CallFunctionObjArgs(self->render_func, NULL);
|
ret = PyObject_CallFunctionObjArgs(self->render_func, NULL);
|
||||||
if (ret == NULL) { PyErr_Print(); return false; }
|
if (ret == NULL) { PyErr_Print(); return false; }
|
||||||
else Py_DECREF(ret);
|
else Py_DECREF(ret);
|
||||||
|
|||||||
@ -288,33 +288,6 @@ typedef struct {
|
|||||||
} ChildMonitor;
|
} ChildMonitor;
|
||||||
PyTypeObject ChildMonitor_Type;
|
PyTypeObject ChildMonitor_Type;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
double visual_bell_duration;
|
|
||||||
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
|
|
||||||
extern GlobalState global_state;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define clear_sprite_position(cell) (cell).sprite_x = 0; (cell).sprite_y = 0; (cell).sprite_z = 0;
|
#define clear_sprite_position(cell) (cell).sprite_x = 0; (cell).sprite_y = 0; (cell).sprite_z = 0;
|
||||||
|
|
||||||
#define left_shift_line(line, at, num) \
|
#define left_shift_line(line, at, num) \
|
||||||
@ -326,11 +299,6 @@ extern GlobalState global_state;
|
|||||||
clear_sprite_position((line)->cells[(at)]); \
|
clear_sprite_position((line)->cells[(at)]); \
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// Global functions
|
||||||
Line* alloc_line();
|
Line* alloc_line();
|
||||||
Cursor* alloc_cursor();
|
Cursor* alloc_cursor();
|
||||||
|
|||||||
@ -122,14 +122,14 @@ class Stack(Layout):
|
|||||||
|
|
||||||
def set_active_window(self, windows, active_window_idx):
|
def set_active_window(self, windows, active_window_idx):
|
||||||
for i, w in enumerate(windows):
|
for i, w in enumerate(windows):
|
||||||
w.is_visible_in_layout = i == active_window_idx
|
w.set_visible_in_layout(i, i == active_window_idx)
|
||||||
|
|
||||||
def __call__(self, windows, active_window_idx):
|
def __call__(self, windows, active_window_idx):
|
||||||
self.blank_rects = []
|
self.blank_rects = []
|
||||||
wg = layout_single_window(self.margin_width, self.padding_width)
|
wg = layout_single_window(self.margin_width, self.padding_width)
|
||||||
for i, w in enumerate(windows):
|
for i, w in enumerate(windows):
|
||||||
w.is_visible_in_layout = i == active_window_idx
|
w.set_visible_in_layout(i, i == active_window_idx)
|
||||||
w.set_geometry(wg)
|
w.set_geometry(i, wg)
|
||||||
if w.is_visible_in_layout:
|
if w.is_visible_in_layout:
|
||||||
self.blank_rects = blank_rects_for_window(w)
|
self.blank_rects = blank_rects_for_window(w)
|
||||||
|
|
||||||
@ -142,7 +142,7 @@ class Tall(Layout):
|
|||||||
self.blank_rects = br = []
|
self.blank_rects = br = []
|
||||||
if len(windows) == 1:
|
if len(windows) == 1:
|
||||||
wg = layout_single_window(self.margin_width, self.padding_width)
|
wg = layout_single_window(self.margin_width, self.padding_width)
|
||||||
windows[0].set_geometry(wg)
|
windows[0].set_geometry(0, wg)
|
||||||
self.blank_rects = blank_rects_for_window(windows[0])
|
self.blank_rects = blank_rects_for_window(windows[0])
|
||||||
return
|
return
|
||||||
xlayout = layout_dimension(
|
xlayout = layout_dimension(
|
||||||
@ -152,14 +152,14 @@ class Tall(Layout):
|
|||||||
ystart, ynum = next(layout_dimension(
|
ystart, ynum = next(layout_dimension(
|
||||||
available_height(), cell_size.height, 1, self.border_width, left_align=True,
|
available_height(), cell_size.height, 1, self.border_width, left_align=True,
|
||||||
margin_length=self.margin_width, padding_length=self.padding_width))
|
margin_length=self.margin_width, padding_length=self.padding_width))
|
||||||
windows[0].set_geometry(window_geometry(xstart, xnum, ystart, ynum))
|
windows[0].set_geometry(0, window_geometry(xstart, xnum, ystart, ynum))
|
||||||
vh = available_height()
|
vh = available_height()
|
||||||
xstart, xnum = next(xlayout)
|
xstart, xnum = next(xlayout)
|
||||||
ylayout = layout_dimension(
|
ylayout = layout_dimension(
|
||||||
available_height(), cell_size.height, len(windows) - 1, self.border_width, left_align=True,
|
available_height(), cell_size.height, len(windows) - 1, self.border_width, left_align=True,
|
||||||
margin_length=self.margin_width, padding_length=self.padding_width)
|
margin_length=self.margin_width, padding_length=self.padding_width)
|
||||||
for w, (ystart, ynum) in zip(islice(windows, 1, None), ylayout):
|
for i, (w, (ystart, ynum)) in enumerate(zip(islice(windows, 1, None), ylayout)):
|
||||||
w.set_geometry(window_geometry(xstart, xnum, ystart, ynum))
|
w.set_geometry(i + 1, window_geometry(xstart, xnum, ystart, ynum))
|
||||||
left_blank_rect(windows[0], br, vh), top_blank_rect(windows[0], br, vh), right_blank_rect(windows[-1], br, vh)
|
left_blank_rect(windows[0], br, vh), top_blank_rect(windows[0], br, vh), right_blank_rect(windows[-1], br, vh)
|
||||||
br.append(Rect(windows[0].geometry.right, 0, windows[1].geometry.left, vh))
|
br.append(Rect(windows[0].geometry.right, 0, windows[1].geometry.left, vh))
|
||||||
br.append(Rect(0, windows[0].geometry.bottom, windows[0].geometry.right, vh))
|
br.append(Rect(0, windows[0].geometry.bottom, windows[0].geometry.right, vh))
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
#define EXTRA_INIT PyModule_AddIntMacro(module, SCROLL_LINE); PyModule_AddIntMacro(module, SCROLL_PAGE); PyModule_AddIntMacro(module, SCROLL_FULL);
|
#define EXTRA_INIT PyModule_AddIntMacro(module, SCROLL_LINE); PyModule_AddIntMacro(module, SCROLL_PAGE); PyModule_AddIntMacro(module, SCROLL_FULL);
|
||||||
|
|
||||||
#include "data-types.h"
|
#include "state.h"
|
||||||
#include "lineops.h"
|
#include "lineops.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
#include <structmember.h>
|
#include <structmember.h>
|
||||||
@ -23,6 +23,7 @@
|
|||||||
#include "modes.h"
|
#include "modes.h"
|
||||||
#include "wcwidth9.h"
|
#include "wcwidth9.h"
|
||||||
|
|
||||||
|
extern GlobalState global_state;
|
||||||
static const ScreenModes empty_modes = {0, .mDECAWM=true, .mDECTCEM=true, .mDECARM=true};
|
static const ScreenModes empty_modes = {0, .mDECAWM=true, .mDECTCEM=true, .mDECARM=true};
|
||||||
static Selection EMPTY_SELECTION = {0};
|
static Selection EMPTY_SELECTION = {0};
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
* Distributed under terms of the GPL3 license.
|
* Distributed under terms of the GPL3 license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "data-types.h"
|
#include "state.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
#include "sprites.h"
|
#include "sprites.h"
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
|||||||
@ -5,24 +5,31 @@
|
|||||||
* Distributed under terms of the GPL3 license.
|
* Distributed under terms of the GPL3 license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define IS_STATE
|
#include "state.h"
|
||||||
#include "data-types.h"
|
|
||||||
|
|
||||||
GlobalState global_state = {{0}};
|
GlobalState global_state = {{0}};
|
||||||
static const Tab EMPTY_TAB = {0};
|
static const Tab EMPTY_TAB = {0};
|
||||||
|
static const Window EMPTY_WINDOW = {0};
|
||||||
|
|
||||||
#define ensure_can_add(array, count, msg) if (count >= sizeof(array)/sizeof(array[0]) - 1) fatal(msg);
|
#define ensure_can_add(array, count, msg) if (count >= sizeof(array)/sizeof(array[0]) - 1) fatal(msg);
|
||||||
|
|
||||||
#define REMOVER(array, qid, count, empty, structure) { \
|
#define noop(...)
|
||||||
|
#define REMOVER(array, qid, count, empty, structure, destroy) { \
|
||||||
size_t capacity = sizeof(array)/sizeof(array[0]); \
|
size_t capacity = sizeof(array)/sizeof(array[0]); \
|
||||||
for (size_t i = 0; i < count; i++) { \
|
for (size_t i = 0; i < count; i++) { \
|
||||||
if (array[i].id == qid) { \
|
if (array[i].id == qid) { \
|
||||||
|
destroy(array[i]); \
|
||||||
array[i] = empty; \
|
array[i] = empty; \
|
||||||
size_t num_to_right = capacity - count - 1; \
|
size_t num_to_right = capacity - count - 1; \
|
||||||
if (num_to_right) memmove(array + i, array + i + 1, num_to_right * sizeof(structure)); \
|
if (num_to_right) memmove(array + i, array + i + 1, num_to_right * sizeof(structure)); \
|
||||||
(count)--; \
|
(count)--; \
|
||||||
} \
|
} \
|
||||||
}}
|
}}
|
||||||
|
#define WITH_TAB(tab_id) \
|
||||||
|
for (size_t t = 0; t < global_state.num_tabs; t++) { \
|
||||||
|
if (global_state.tabs[t].id == tab_id) { \
|
||||||
|
Tab *tab = global_state.tabs + t;
|
||||||
|
#define END_WITH_TAB break; }}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
add_tab(unsigned int id) {
|
add_tab(unsigned int id) {
|
||||||
@ -33,15 +40,43 @@ add_tab(unsigned int id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
remove_tab(unsigned int id) {
|
add_window(unsigned int tab_id, unsigned int id) {
|
||||||
REMOVER(global_state.tabs, id, global_state.num_tabs, EMPTY_TAB, Tab);
|
WITH_TAB(tab_id);
|
||||||
|
ensure_can_add(tab->windows, tab->num_windows, "Too many children (add_window)");
|
||||||
|
tab->windows[tab->num_windows] = EMPTY_WINDOW;
|
||||||
|
tab->windows[tab->num_windows].id = id;
|
||||||
|
tab->windows[tab->num_windows].visible = true;
|
||||||
|
tab->num_windows++;
|
||||||
|
END_WITH_TAB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
remove_tab(unsigned int id) {
|
||||||
|
REMOVER(global_state.tabs, id, global_state.num_tabs, EMPTY_TAB, Tab, noop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
remove_window(unsigned int tab_id, unsigned int id) {
|
||||||
|
WITH_TAB(tab_id);
|
||||||
|
#define destroy_window(w) Py_CLEAR(w.render_data.screen)
|
||||||
|
REMOVER(tab->windows, id, tab->num_windows, EMPTY_WINDOW, Window, destroy_window);
|
||||||
|
#undef destroy_window
|
||||||
|
END_WITH_TAB;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
set_active_tab(unsigned int idx) {
|
set_active_tab(unsigned int idx) {
|
||||||
global_state.active_tab = idx;
|
global_state.active_tab = idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
set_active_window(unsigned int tab_id, unsigned int idx) {
|
||||||
|
WITH_TAB(tab_id);
|
||||||
|
tab->active_window = idx;
|
||||||
|
END_WITH_TAB;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
swap_tabs(unsigned int a, unsigned int b) {
|
swap_tabs(unsigned int a, unsigned int b) {
|
||||||
Tab t = global_state.tabs[b];
|
Tab t = global_state.tabs[b];
|
||||||
@ -49,6 +84,15 @@ swap_tabs(unsigned int a, unsigned int b) {
|
|||||||
global_state.tabs[a] = t;
|
global_state.tabs[a] = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
swap_windows(unsigned int tab_id, unsigned int a, unsigned int b) {
|
||||||
|
WITH_TAB(tab_id);
|
||||||
|
Window w = tab->windows[b];
|
||||||
|
tab->windows[b] = tab->windows[a];
|
||||||
|
tab->windows[a] = w;
|
||||||
|
END_WITH_TAB;
|
||||||
|
}
|
||||||
|
|
||||||
// Python API {{{
|
// Python API {{{
|
||||||
#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)
|
||||||
@ -56,6 +100,7 @@ swap_tabs(unsigned int a, unsigned int b) {
|
|||||||
#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;
|
#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 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; }
|
#define TWO_UINT(name) PYWRAP1(name) { unsigned int a, b; PA("II", &a, &b); name(a, b); Py_RETURN_NONE; }
|
||||||
|
#define THREE_UINT(name) PYWRAP1(name) { unsigned int a, b, c; PA("III", &a, &b, &c); name(a, b, c); Py_RETURN_NONE; }
|
||||||
|
|
||||||
PYWRAP1(set_options) {
|
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); }
|
#define S(name, convert) { PyObject *ret = PyObject_GetAttrString(args, #name); if (ret == NULL) return NULL; global_state.opts.name = convert(ret); Py_DECREF(ret); }
|
||||||
@ -74,15 +119,44 @@ PYWRAP1(set_tab_bar_render_data) {
|
|||||||
#undef A
|
#undef A
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PYWRAP1(set_window_render_data) {
|
||||||
|
#define A(name) &(d.name)
|
||||||
|
unsigned int window_idx, tab_id;
|
||||||
|
ScreenRenderData d = {0};
|
||||||
|
PA("IIiffffO", &tab_id, &window_idx, A(vao_idx), A(xstart), A(ystart), A(dx), A(dy), A(screen));
|
||||||
|
|
||||||
|
WITH_TAB(tab_id);
|
||||||
|
Py_CLEAR(tab->windows[window_idx].render_data.screen);
|
||||||
|
tab->windows[window_idx].render_data = d;
|
||||||
|
Py_INCREF(tab->windows[window_idx].render_data.screen);
|
||||||
|
END_WITH_TAB;
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
#undef A
|
||||||
|
}
|
||||||
|
|
||||||
|
PYWRAP1(update_window_visibility) {
|
||||||
|
unsigned int window_idx, tab_id;
|
||||||
|
int visible;
|
||||||
|
PA("IIp", &tab_id, &window_idx, &visible);
|
||||||
|
WITH_TAB(tab_id);
|
||||||
|
tab->windows[window_idx].visible = visible & 1;
|
||||||
|
END_WITH_TAB;
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
PYWRAP0(destroy_global_data) {
|
PYWRAP0(destroy_global_data) {
|
||||||
Py_CLEAR(global_state.tab_bar_render_data.screen);
|
Py_CLEAR(global_state.tab_bar_render_data.screen);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ONE_UINT(add_tab)
|
ONE_UINT(add_tab)
|
||||||
|
TWO_UINT(add_window)
|
||||||
ONE_UINT(remove_tab)
|
ONE_UINT(remove_tab)
|
||||||
|
TWO_UINT(remove_window)
|
||||||
ONE_UINT(set_active_tab)
|
ONE_UINT(set_active_tab)
|
||||||
|
TWO_UINT(set_active_window)
|
||||||
TWO_UINT(swap_tabs)
|
TWO_UINT(swap_tabs)
|
||||||
|
THREE_UINT(swap_windows)
|
||||||
|
|
||||||
#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}
|
||||||
@ -90,10 +164,16 @@ TWO_UINT(swap_tabs)
|
|||||||
static PyMethodDef module_methods[] = {
|
static PyMethodDef module_methods[] = {
|
||||||
MW(set_options, METH_O),
|
MW(set_options, METH_O),
|
||||||
MW(add_tab, METH_O),
|
MW(add_tab, METH_O),
|
||||||
|
MW(add_window, METH_VARARGS),
|
||||||
MW(remove_tab, METH_O),
|
MW(remove_tab, METH_O),
|
||||||
|
MW(remove_window, METH_VARARGS),
|
||||||
MW(set_active_tab, METH_O),
|
MW(set_active_tab, METH_O),
|
||||||
|
MW(set_active_window, METH_VARARGS),
|
||||||
MW(swap_tabs, METH_VARARGS),
|
MW(swap_tabs, METH_VARARGS),
|
||||||
|
MW(swap_windows, METH_VARARGS),
|
||||||
MW(set_tab_bar_render_data, METH_VARARGS),
|
MW(set_tab_bar_render_data, METH_VARARGS),
|
||||||
|
MW(set_window_render_data, METH_VARARGS),
|
||||||
|
MW(update_window_visibility, METH_VARARGS),
|
||||||
MW(destroy_global_data, METH_NOARGS),
|
MW(destroy_global_data, METH_NOARGS),
|
||||||
|
|
||||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||||
|
|||||||
43
kitty/state.h
Normal file
43
kitty/state.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the GPL3 license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "data-types.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double visual_bell_duration;
|
||||||
|
bool enable_audio_bell;
|
||||||
|
} Options;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ssize_t vao_idx;
|
||||||
|
float xstart, ystart, dx, dy;
|
||||||
|
Screen *screen;
|
||||||
|
} ScreenRenderData;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned int id;
|
||||||
|
bool visible;
|
||||||
|
ScreenRenderData render_data;
|
||||||
|
} Window;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned int id, active_window, num_windows;
|
||||||
|
Window windows[MAX_CHILDREN];
|
||||||
|
} Tab;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Options opts;
|
||||||
|
|
||||||
|
Tab tabs[MAX_CHILDREN];
|
||||||
|
unsigned int active_tab, num_tabs;
|
||||||
|
ScreenRenderData tab_bar_render_data;
|
||||||
|
} GlobalState;
|
||||||
|
|
||||||
|
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;
|
||||||
@ -14,8 +14,9 @@ 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 (
|
from .fast_data_types import (
|
||||||
DECAWM, Screen, add_tab, create_cell_vao, glfw_post_empty_event,
|
DECAWM, Screen, add_tab, add_window, create_cell_vao,
|
||||||
remove_tab, set_active_tab, swap_tabs, set_tab_bar_render_data
|
glfw_post_empty_event, remove_tab, remove_window, set_active_tab,
|
||||||
|
set_active_window, set_tab_bar_render_data, swap_tabs, swap_windows
|
||||||
)
|
)
|
||||||
from .layout import Rect, all_layouts
|
from .layout import Rect, all_layouts
|
||||||
from .utils import color_as_int
|
from .utils import color_as_int
|
||||||
@ -36,6 +37,7 @@ 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
|
global borders
|
||||||
self.id = next(tab_counter)
|
self.id = next(tab_counter)
|
||||||
|
add_tab(self.id)
|
||||||
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
|
||||||
@ -104,8 +106,8 @@ class Tab: # {{{
|
|||||||
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, borders.border_width, self.windows)
|
self.current_layout = all_layouts[nl](self.opts, borders.border_width, self.windows)
|
||||||
for w in self.windows:
|
for i, w in enumerate(self.windows):
|
||||||
w.is_visible_in_layout = True
|
w.set_visible_in_layout(i, True)
|
||||||
self.relayout()
|
self.relayout()
|
||||||
|
|
||||||
def launch_child(self, use_shell=False, cmd=None, stdin=None):
|
def launch_child(self, use_shell=False, cmd=None, stdin=None):
|
||||||
@ -125,7 +127,9 @@ class Tab: # {{{
|
|||||||
window.title = window.override_title = override_title
|
window.title = window.override_title = override_title
|
||||||
# Must add child before laying out so that resize_pty succeeds
|
# Must add child before laying out so that resize_pty succeeds
|
||||||
get_boss().add_child(window)
|
get_boss().add_child(window)
|
||||||
|
add_window(self.id, window.id)
|
||||||
self.active_window_idx = self.current_layout.add_window(self.windows, window, self.active_window_idx)
|
self.active_window_idx = self.current_layout.add_window(self.windows, window, self.active_window_idx)
|
||||||
|
set_active_window(self.id, self.active_window_idx)
|
||||||
self.relayout_borders()
|
self.relayout_borders()
|
||||||
glfw_post_empty_event()
|
glfw_post_empty_event()
|
||||||
return window
|
return window
|
||||||
@ -138,7 +142,9 @@ class Tab: # {{{
|
|||||||
self.remove_window(self.windows[self.active_window_idx])
|
self.remove_window(self.windows[self.active_window_idx])
|
||||||
|
|
||||||
def remove_window(self, window):
|
def remove_window(self, window):
|
||||||
|
remove_window(self.id, window.id)
|
||||||
self.active_window_idx = self.current_layout.remove_window(self.windows, window, self.active_window_idx)
|
self.active_window_idx = self.current_layout.remove_window(self.windows, window, self.active_window_idx)
|
||||||
|
set_active_window(self.id, self.active_window_idx)
|
||||||
self.relayout_borders()
|
self.relayout_borders()
|
||||||
glfw_post_empty_event()
|
glfw_post_empty_event()
|
||||||
|
|
||||||
@ -146,6 +152,7 @@ class Tab: # {{{
|
|||||||
if idx != self.active_window_idx:
|
if idx != self.active_window_idx:
|
||||||
self.current_layout.set_active_window(self.windows, idx)
|
self.current_layout.set_active_window(self.windows, idx)
|
||||||
self.active_window_idx = idx
|
self.active_window_idx = idx
|
||||||
|
set_active_window(self.id, self.active_window_idx)
|
||||||
self.relayout_borders()
|
self.relayout_borders()
|
||||||
glfw_post_empty_event()
|
glfw_post_empty_event()
|
||||||
|
|
||||||
@ -163,6 +170,7 @@ class Tab: # {{{
|
|||||||
def _next_window(self, delta=1):
|
def _next_window(self, delta=1):
|
||||||
if len(self.windows) > 1:
|
if len(self.windows) > 1:
|
||||||
self.active_window_idx = self.current_layout.next_window(self.windows, self.active_window_idx, delta)
|
self.active_window_idx = self.current_layout.next_window(self.windows, self.active_window_idx, delta)
|
||||||
|
set_active_window(self.id, self.active_window_idx)
|
||||||
self.relayout_borders()
|
self.relayout_borders()
|
||||||
glfw_post_empty_event()
|
glfw_post_empty_event()
|
||||||
|
|
||||||
@ -177,7 +185,9 @@ class Tab: # {{{
|
|||||||
idx = self.active_window_idx
|
idx = self.active_window_idx
|
||||||
nidx = (idx + len(self.windows) + delta) % len(self.windows)
|
nidx = (idx + len(self.windows) + delta) % len(self.windows)
|
||||||
self.windows[nidx], self.windows[idx] = self.windows[idx], self.windows[nidx]
|
self.windows[nidx], self.windows[idx] = self.windows[idx], self.windows[nidx]
|
||||||
|
swap_windows(self.id, nidx, idx)
|
||||||
self.active_window_idx = nidx
|
self.active_window_idx = nidx
|
||||||
|
set_active_window(self.id, self.active_window_idx)
|
||||||
self.relayout()
|
self.relayout()
|
||||||
|
|
||||||
def move_window_to_top(self):
|
def move_window_to_top(self):
|
||||||
@ -295,7 +305,6 @@ class TabManager: # {{{
|
|||||||
self.active_tab_idx = 0
|
self.active_tab_idx = 0
|
||||||
|
|
||||||
def _add_tab(self, tab):
|
def _add_tab(self, tab):
|
||||||
add_tab(tab.id)
|
|
||||||
self.tabs.append(tab)
|
self.tabs.append(tab)
|
||||||
|
|
||||||
def _remove_tab(self, tab):
|
def _remove_tab(self, tab):
|
||||||
|
|||||||
@ -18,7 +18,9 @@ from .fast_data_types import (
|
|||||||
GLFW_KEY_LEFT_SHIFT, GLFW_KEY_RIGHT_SHIFT, GLFW_KEY_UP, GLFW_MOD_SHIFT,
|
GLFW_KEY_LEFT_SHIFT, GLFW_KEY_RIGHT_SHIFT, GLFW_KEY_UP, GLFW_MOD_SHIFT,
|
||||||
GLFW_MOUSE_BUTTON_1, GLFW_MOUSE_BUTTON_4, GLFW_MOUSE_BUTTON_5,
|
GLFW_MOUSE_BUTTON_1, GLFW_MOUSE_BUTTON_4, GLFW_MOUSE_BUTTON_5,
|
||||||
GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, GLFW_RELEASE, MOTION_MODE,
|
GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, GLFW_RELEASE, MOTION_MODE,
|
||||||
SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE, Screen, glfw_post_empty_event
|
SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE, Screen, create_cell_vao,
|
||||||
|
glfw_post_empty_event, remove_vao, set_window_render_data,
|
||||||
|
update_window_visibility
|
||||||
)
|
)
|
||||||
from .keys import get_key_map
|
from .keys import get_key_map
|
||||||
from .mouse import DRAG, MOVE, PRESS, RELEASE, encode_mouse_event
|
from .mouse import DRAG, MOVE, PRESS, RELEASE, encode_mouse_event
|
||||||
@ -45,6 +47,8 @@ class Window:
|
|||||||
|
|
||||||
def __init__(self, tab, child, opts, args):
|
def __init__(self, tab, child, opts, args):
|
||||||
self.id = next(window_counter)
|
self.id = next(window_counter)
|
||||||
|
self.vao_id = create_cell_vao()
|
||||||
|
self.tab_id = tab.id
|
||||||
self.tabref = weakref.ref(tab)
|
self.tabref = weakref.ref(tab)
|
||||||
self.override_title = None
|
self.override_title = None
|
||||||
self.last_mouse_cursor_pos = 0, 0
|
self.last_mouse_cursor_pos = 0, 0
|
||||||
@ -53,7 +57,7 @@ class Window:
|
|||||||
self.geometry = WindowGeometry(0, 0, 0, 0, 0, 0)
|
self.geometry = WindowGeometry(0, 0, 0, 0, 0, 0)
|
||||||
self.needs_layout = True
|
self.needs_layout = True
|
||||||
self.title = appname
|
self.title = appname
|
||||||
self._is_visible_in_layout = True
|
self.is_visible_in_layout = True
|
||||||
self.child, self.opts = child, opts
|
self.child, self.opts = child, opts
|
||||||
self.start_visual_bell_at = None
|
self.start_visual_bell_at = None
|
||||||
self.screen = Screen(self, 24, 80, opts.scrollback_lines)
|
self.screen = Screen(self, 24, 80, opts.scrollback_lines)
|
||||||
@ -63,15 +67,11 @@ class Window:
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return 'Window(title={}, id={})'.format(self.title, self.id)
|
return 'Window(title={}, id={})'.format(self.title, self.id)
|
||||||
|
|
||||||
@property
|
def set_visible_in_layout(self, window_idx, val):
|
||||||
def is_visible_in_layout(self):
|
|
||||||
return self._is_visible_in_layout
|
|
||||||
|
|
||||||
@is_visible_in_layout.setter
|
|
||||||
def is_visible_in_layout(self, val):
|
|
||||||
val = bool(val)
|
val = bool(val)
|
||||||
if val != self._is_visible_in_layout:
|
if val is not self.is_visible_in_layout:
|
||||||
self._is_visible_in_layout = val
|
self.is_visible_in_layout = val
|
||||||
|
update_window_visibility(self.tab_id, window_idx, val)
|
||||||
if val:
|
if val:
|
||||||
self.refresh()
|
self.refresh()
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ class Window:
|
|||||||
self.screen.mark_as_dirty()
|
self.screen.mark_as_dirty()
|
||||||
wakeup()
|
wakeup()
|
||||||
|
|
||||||
def set_geometry(self, new_geometry):
|
def set_geometry(self, window_idx, new_geometry):
|
||||||
if self.destroyed:
|
if self.destroyed:
|
||||||
return
|
return
|
||||||
if self.needs_layout or new_geometry.xnum != self.screen.columns or new_geometry.ynum != self.screen.lines:
|
if self.needs_layout or new_geometry.xnum != self.screen.columns or new_geometry.ynum != self.screen.lines:
|
||||||
@ -88,11 +88,12 @@ class Window:
|
|||||||
self.current_pty_size = (
|
self.current_pty_size = (
|
||||||
self.screen.lines, self.screen.columns,
|
self.screen.lines, self.screen.columns,
|
||||||
max(0, new_geometry.right - new_geometry.left), max(0, new_geometry.bottom - new_geometry.top))
|
max(0, new_geometry.right - new_geometry.left), max(0, new_geometry.bottom - new_geometry.top))
|
||||||
self.char_grid.resize(new_geometry)
|
sg = self.char_grid.update_position(new_geometry)
|
||||||
self.needs_layout = False
|
self.needs_layout = False
|
||||||
boss.resize_pty(self.id)
|
boss.resize_pty(self.id)
|
||||||
else:
|
else:
|
||||||
self.char_grid.update_position(new_geometry)
|
sg = self.char_grid.update_position(new_geometry)
|
||||||
|
set_window_render_data(self.tab_id, window_idx, self.vao_id, sg.xstart, sg.ystart, sg.dx, sg.dy, self.screen)
|
||||||
self.geometry = new_geometry
|
self.geometry = new_geometry
|
||||||
|
|
||||||
def contains(self, x, y):
|
def contains(self, x, y):
|
||||||
@ -281,6 +282,11 @@ class Window:
|
|||||||
def buf_toggled(self, is_main_linebuf):
|
def buf_toggled(self, is_main_linebuf):
|
||||||
self.screen.scroll(SCROLL_FULL, False)
|
self.screen.scroll(SCROLL_FULL, False)
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
if self.vao_id is not None:
|
||||||
|
remove_vao(self.vao_id)
|
||||||
|
self.vao_id = None
|
||||||
|
|
||||||
# actions {{{
|
# actions {{{
|
||||||
|
|
||||||
def show_scrollback(self):
|
def show_scrollback(self):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user