Move cursor render call to C
This commit is contained in:
@@ -3,7 +3,6 @@
|
|||||||
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
from time import monotonic
|
|
||||||
from weakref import WeakValueDictionary
|
from weakref import WeakValueDictionary
|
||||||
|
|
||||||
from .char_grid import load_shader_programs
|
from .char_grid import load_shader_programs
|
||||||
@@ -16,7 +15,7 @@ from .fast_data_types import (
|
|||||||
GLFW_CURSOR, GLFW_CURSOR_HIDDEN, GLFW_CURSOR_NORMAL, GLFW_MOUSE_BUTTON_1,
|
GLFW_CURSOR, GLFW_CURSOR_HIDDEN, GLFW_CURSOR_NORMAL, GLFW_MOUSE_BUTTON_1,
|
||||||
GLFW_PRESS, GLFW_REPEAT, ChildMonitor, Timers as _Timers,
|
GLFW_PRESS, GLFW_REPEAT, ChildMonitor, Timers as _Timers,
|
||||||
destroy_global_data, destroy_sprite_map, glfw_post_empty_event,
|
destroy_global_data, destroy_sprite_map, glfw_post_empty_event,
|
||||||
layout_sprite_map, resize_gl_viewport
|
layout_sprite_map
|
||||||
)
|
)
|
||||||
from .fonts.render import render_cell_wrapper, set_font_family
|
from .fonts.render import render_cell_wrapper, set_font_family
|
||||||
from .keys import (
|
from .keys import (
|
||||||
@@ -91,7 +90,6 @@ class Boss:
|
|||||||
def __init__(self, glfw_window, opts, args):
|
def __init__(self, glfw_window, opts, args):
|
||||||
self.window_id_map = WeakValueDictionary()
|
self.window_id_map = WeakValueDictionary()
|
||||||
startup_session = create_session(opts, args)
|
startup_session = create_session(opts, args)
|
||||||
self.cursor_blink_zero_time = monotonic()
|
|
||||||
self.cursor_blinking = True
|
self.cursor_blinking = True
|
||||||
self.window_is_focused = True
|
self.window_is_focused = True
|
||||||
self.glfw_window_title = None
|
self.glfw_window_title = None
|
||||||
@@ -119,7 +117,6 @@ class Boss:
|
|||||||
layout_sprite_map(cell_size.width, cell_size.height, render_cell_wrapper)
|
layout_sprite_map(cell_size.width, cell_size.height, render_cell_wrapper)
|
||||||
self.glfw_window.set_click_cursor(False)
|
self.glfw_window.set_click_cursor(False)
|
||||||
self.show_mouse_cursor()
|
self.show_mouse_cursor()
|
||||||
self.start_cursor_blink()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_tab_bar_height(self):
|
def current_tab_bar_height(self):
|
||||||
@@ -165,14 +162,8 @@ class Boss:
|
|||||||
self.io_thread_started = True
|
self.io_thread_started = True
|
||||||
|
|
||||||
def on_window_resize(self, window, w, h):
|
def on_window_resize(self, window, w, h):
|
||||||
# debounce resize events
|
viewport_size.width, viewport_size.height = w, h
|
||||||
if w > 100 and h > 100:
|
self.tab_manager.resize()
|
||||||
viewport_size.width, viewport_size.height = w, h
|
|
||||||
self.tab_manager.resize()
|
|
||||||
resize_gl_viewport(w, h)
|
|
||||||
glfw_post_empty_event()
|
|
||||||
else:
|
|
||||||
safe_print('Ignoring resize request for sizes under 100x100')
|
|
||||||
|
|
||||||
def increase_font_size(self):
|
def increase_font_size(self):
|
||||||
self.change_font_size(
|
self.change_font_size(
|
||||||
@@ -232,8 +223,6 @@ class Boss:
|
|||||||
|
|
||||||
def on_key(self, window, key, scancode, action, mods):
|
def on_key(self, window, key, scancode, action, mods):
|
||||||
is_key_pressed[key] = action == GLFW_PRESS
|
is_key_pressed[key] = action == GLFW_PRESS
|
||||||
self.start_cursor_blink()
|
|
||||||
self.cursor_blink_zero_time = monotonic()
|
|
||||||
func = None
|
func = None
|
||||||
if action == GLFW_PRESS or action == GLFW_REPEAT:
|
if action == GLFW_PRESS or action == GLFW_REPEAT:
|
||||||
func = get_shortcut(self.opts.keymap, mods, key, scancode)
|
func = get_shortcut(self.opts.keymap, mods, key, scancode)
|
||||||
@@ -346,16 +335,6 @@ class Boss:
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass # needs glfw 3.3
|
pass # needs glfw 3.3
|
||||||
|
|
||||||
def start_cursor_blink(self):
|
|
||||||
self.cursor_blinking = True
|
|
||||||
if self.opts.cursor_stop_blinking_after > 0:
|
|
||||||
self.ui_timers.add(
|
|
||||||
self.opts.cursor_stop_blinking_after,
|
|
||||||
self.stop_cursor_blinking)
|
|
||||||
|
|
||||||
def stop_cursor_blinking(self):
|
|
||||||
self.cursor_blinking = False
|
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
tab = self.active_tab
|
tab = self.active_tab
|
||||||
if tab is None:
|
if tab is None:
|
||||||
@@ -365,19 +344,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)
|
||||||
active = self.active_window
|
|
||||||
if active is not None:
|
|
||||||
draw_cursor = True
|
|
||||||
if self.cursor_blinking and self.opts.cursor_blink_interval > 0 and self.window_is_focused:
|
|
||||||
now = monotonic() - self.cursor_blink_zero_time
|
|
||||||
t = int(now * 1000)
|
|
||||||
d = int(self.opts.cursor_blink_interval * 1000)
|
|
||||||
n = t // d
|
|
||||||
draw_cursor = n % 2 == 0
|
|
||||||
self.ui_timers.add_if_before(
|
|
||||||
((n + 1) * d / 1000) - now, None)
|
|
||||||
if draw_cursor:
|
|
||||||
active.char_grid.render_cursor(self.window_is_focused)
|
|
||||||
|
|
||||||
def gui_close_window(self, window):
|
def gui_close_window(self, window):
|
||||||
window.destroy()
|
window.destroy()
|
||||||
|
|||||||
@@ -3,22 +3,16 @@
|
|||||||
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
import re
|
import re
|
||||||
from collections import namedtuple
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from .config import build_ansi_color_table
|
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_PROGRAM, compile_program, init_cell_program,
|
||||||
compile_program, draw_cursor, init_cell_program, init_cursor_program
|
init_cursor_program
|
||||||
)
|
)
|
||||||
from .rgb import to_color
|
from .rgb import to_color
|
||||||
from .utils import (
|
from .utils import color_as_int, load_shaders, open_url, set_primary_selection
|
||||||
color_as_int, get_logical_dpi, load_shaders, open_url,
|
|
||||||
set_primary_selection
|
|
||||||
)
|
|
||||||
|
|
||||||
Cursor = namedtuple('Cursor', 'x y shape blink')
|
|
||||||
|
|
||||||
|
|
||||||
class DynamicColor(Enum):
|
class DynamicColor(Enum):
|
||||||
@@ -52,9 +46,7 @@ class CharGrid:
|
|||||||
self.screen.color_profile.update_ansi_color_table(build_ansi_color_table(opts))
|
self.screen.color_profile.update_ansi_color_table(build_ansi_color_table(opts))
|
||||||
self.screen.color_profile.set_configured_colors(*map(color_as_int, (
|
self.screen.color_profile.set_configured_colors(*map(color_as_int, (
|
||||||
opts.foreground, opts.background, opts.cursor, opts.selection_foreground, opts.selection_background)))
|
opts.foreground, opts.background, opts.cursor, opts.selection_foreground, opts.selection_background)))
|
||||||
self.dpix, self.dpiy = get_logical_dpi()
|
|
||||||
self.opts = opts
|
self.opts = opts
|
||||||
self.default_cursor = Cursor(0, 0, opts.cursor_shape, opts.cursor_blink_interval > 0)
|
|
||||||
self.opts = opts
|
self.opts = opts
|
||||||
|
|
||||||
def update_position(self, window_geometry):
|
def update_position(self, window_geometry):
|
||||||
@@ -158,28 +150,3 @@ 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_cursor(self, is_focused):
|
|
||||||
if not self.screen.cursor_visible or self.screen.scrolled_by:
|
|
||||||
return
|
|
||||||
cursor = self.screen.cursor
|
|
||||||
|
|
||||||
def width(w=2, vert=True):
|
|
||||||
dpi = self.dpix if vert else self.dpiy
|
|
||||||
w *= dpi / 72.0 # as pixels
|
|
||||||
factor = 2 / (viewport_size.width if vert else viewport_size.height)
|
|
||||||
return w * factor
|
|
||||||
|
|
||||||
sg = self.screen_geometry
|
|
||||||
left = sg.xstart + cursor.x * sg.dx
|
|
||||||
top = sg.ystart - cursor.y * sg.dy
|
|
||||||
col = self.screen.color_profile.cursor_color
|
|
||||||
shape = cursor.shape or self.default_cursor.shape
|
|
||||||
alpha = self.opts.cursor_opacity
|
|
||||||
mult = self.screen.current_char_width()
|
|
||||||
right = left + (width(1.5) if shape == CURSOR_BEAM else sg.dx * mult)
|
|
||||||
bottom = top - sg.dy
|
|
||||||
if shape == CURSOR_UNDERLINE:
|
|
||||||
top = bottom + width(vert=False)
|
|
||||||
semi_transparent = alpha < 1.0 and shape == CURSOR_BLOCK
|
|
||||||
draw_cursor(semi_transparent, is_focused, col, alpha, left, right, top, bottom)
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ extern int pthread_setname_np(const char *name);
|
|||||||
#undef _GNU_SOURCE
|
#undef _GNU_SOURCE
|
||||||
#endif
|
#endif
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
#include "screen.h"
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
@@ -426,6 +427,46 @@ pyset_iutf8(ChildMonitor *self, PyObject *args) {
|
|||||||
static double last_render_at = -DBL_MAX;
|
static double last_render_at = -DBL_MAX;
|
||||||
draw_borders_func draw_borders = NULL;
|
draw_borders_func draw_borders = NULL;
|
||||||
draw_cells_func draw_cells = NULL;
|
draw_cells_func draw_cells = NULL;
|
||||||
|
draw_cursor_func draw_cursor = NULL;
|
||||||
|
|
||||||
|
static inline double
|
||||||
|
cursor_width(unsigned int w, bool vert) {
|
||||||
|
double dpi = vert ? global_state.logical_dpi_x : global_state.logical_dpi_y;
|
||||||
|
double ans = w * dpi / 72.0; // as pixels
|
||||||
|
double factor = 2.0 / (vert ? global_state.viewport_width : global_state.viewport_height);
|
||||||
|
return ans * factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
render_cursor(ChildMonitor *self, Window *w, double now) {
|
||||||
|
ScreenRenderData *rd = &w->render_data;
|
||||||
|
if (rd->screen->scrolled_by || ! screen_is_cursor_visible(rd->screen)) return;
|
||||||
|
double time_since_start_blink = now - global_state.cursor_blink_zero_time;
|
||||||
|
bool cursor_blinking = OPT(cursor_blink_interval) > 0 && global_state.application_focused && time_since_start_blink <= OPT(cursor_stop_blinking_after) ? true : false;
|
||||||
|
bool do_draw_cursor = true;
|
||||||
|
if (cursor_blinking) {
|
||||||
|
int t = (int)(time_since_start_blink * 1000);
|
||||||
|
int d = (int)(OPT(cursor_blink_interval) * 1000);
|
||||||
|
int n = t / d;
|
||||||
|
do_draw_cursor = n % 2 == 0 ? true : false;
|
||||||
|
double delay = MAX(0, ((n + 1) * d / 1000) - time_since_start_blink);
|
||||||
|
timers_add_if_before(self->timers, delay, Py_None, NULL);
|
||||||
|
}
|
||||||
|
if (do_draw_cursor) {
|
||||||
|
Cursor *cursor = rd->screen->cursor;
|
||||||
|
double left = rd->xstart + cursor->x * rd->dx;
|
||||||
|
double top = rd->ystart - cursor->y * rd->dy;
|
||||||
|
int shape = cursor->shape ? cursor->shape : OPT(cursor_shape);
|
||||||
|
unsigned long mult = screen_current_char_width(rd->screen);
|
||||||
|
double right = left + (shape == CURSOR_BEAM ? cursor_width(1.5, true) : rd->dx * mult);
|
||||||
|
double bottom = top - rd->dy;
|
||||||
|
if (shape == CURSOR_UNDERLINE) top = bottom + cursor_width(2.0, false);
|
||||||
|
bool semi_transparent = OPT(cursor_opacity) < 1.0 && shape == CURSOR_BLOCK ? true : false;
|
||||||
|
ColorProfile *cp = rd->screen->color_profile;
|
||||||
|
color_type col = colorprofile_to_color(cp, cp->overridden.cursor_color, cp->configured.cursor_color);
|
||||||
|
draw_cursor(semi_transparent, global_state.application_focused, col, OPT(cursor_opacity), left, right, top, bottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
render(ChildMonitor *self, double *timeout) {
|
render(ChildMonitor *self, double *timeout) {
|
||||||
@@ -443,8 +484,10 @@ render(ChildMonitor *self, double *timeout) {
|
|||||||
Window *w = tab->windows + i;
|
Window *w = tab->windows + i;
|
||||||
#define WD w->render_data
|
#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);
|
if (w->visible && WD.screen) draw_cells(WD.vao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen);
|
||||||
#undef WD
|
|
||||||
}
|
}
|
||||||
|
Window *w = tab->windows + tab->active_window;
|
||||||
|
if (w->visible && WD.screen) render_cursor(self, w, now);
|
||||||
|
#undef WD
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = PyObject_CallFunctionObjArgs(self->render_func, NULL);
|
ret = PyObject_CallFunctionObjArgs(self->render_func, NULL);
|
||||||
|
|||||||
@@ -27,12 +27,15 @@ static int __eq__(Cursor *a, Cursor *b) {
|
|||||||
return EQ(bold) && EQ(italic) && EQ(strikethrough) && EQ(reverse) && EQ(decoration) && EQ(fg) && EQ(bg) && EQ(decoration_fg) && EQ(x) && EQ(y) && EQ(shape) && EQ(blink);
|
return EQ(bold) && EQ(italic) && EQ(strikethrough) && EQ(reverse) && EQ(decoration) && EQ(fg) && EQ(bg) && EQ(decoration_fg) && EQ(x) && EQ(y) && EQ(shape) && EQ(blink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char* cursor_names[NUM_OF_CURSOR_SHAPES] = { "NO_SHAPE", "BLOCK", "BEAM", "UNDERLINE" };
|
||||||
|
|
||||||
#define BOOL(x) ((x) ? Py_True : Py_False)
|
#define BOOL(x) ((x) ? Py_True : Py_False)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
repr(Cursor *self) {
|
repr(Cursor *self) {
|
||||||
return PyUnicode_FromFormat(
|
return PyUnicode_FromFormat(
|
||||||
"Cursor(x=%u, y=%u, shape=%d, blink=%R, fg=#%08x, bg=#%08x, bold=%R, italic=%R, reverse=%R, strikethrough=%R, decoration=%d, decoration_fg=#%08x)",
|
"Cursor(x=%u, y=%u, shape=%s, blink=%R, fg=#%08x, bg=#%08x, bold=%R, italic=%R, reverse=%R, strikethrough=%R, decoration=%d, decoration_fg=#%08x)",
|
||||||
self->x, self->y, self->shape, BOOL(self->blink), self->fg, self->bg, BOOL(self->bold), BOOL(self->italic), BOOL(self->reverse), BOOL(self->strikethrough), self->decoration, self->decoration_fg
|
self->x, self->y, (self->shape < NUM_OF_CURSOR_SHAPES && self->shape >= 0 ? cursor_names[self->shape] : "INVALID"),
|
||||||
|
BOOL(self->blink), self->fg, self->bg, BOOL(self->bold), BOOL(self->italic), BOOL(self->reverse), BOOL(self->strikethrough), self->decoration, self->decoration_fg
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +54,7 @@ reset_display_attrs(Cursor *self) {
|
|||||||
void cursor_reset(Cursor *self) {
|
void cursor_reset(Cursor *self) {
|
||||||
cursor_reset_display_attrs(self);
|
cursor_reset_display_attrs(self);
|
||||||
self->x = 0; self->y = 0;
|
self->x = 0; self->y = 0;
|
||||||
self->shape = 0; self->blink = false;
|
self->shape = NO_CURSOR_SHAPE; self->blink = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cursor_copy_to(Cursor *src, Cursor *dest) {
|
void cursor_copy_to(Cursor *src, Cursor *dest) {
|
||||||
@@ -75,7 +78,7 @@ BOOL_GETSET(Cursor, blink)
|
|||||||
static PyMemberDef members[] = {
|
static PyMemberDef members[] = {
|
||||||
{"x", T_UINT, offsetof(Cursor, x), 0, "x"},
|
{"x", T_UINT, offsetof(Cursor, x), 0, "x"},
|
||||||
{"y", T_UINT, offsetof(Cursor, y), 0, "y"},
|
{"y", T_UINT, offsetof(Cursor, y), 0, "y"},
|
||||||
{"shape", T_UBYTE, offsetof(Cursor, shape), 0, "shape"},
|
{"shape", T_INT, offsetof(Cursor, shape), 0, "shape"},
|
||||||
{"decoration", T_UBYTE, offsetof(Cursor, decoration), 0, "decoration"},
|
{"decoration", T_UBYTE, offsetof(Cursor, decoration), 0, "decoration"},
|
||||||
{"fg", T_ULONG, offsetof(Cursor, fg), 0, "fg"},
|
{"fg", T_ULONG, offsetof(Cursor, fg), 0, "fg"},
|
||||||
{"bg", T_ULONG, offsetof(Cursor, bg), 0, "bg"},
|
{"bg", T_ULONG, offsetof(Cursor, bg), 0, "bg"},
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ typedef uint32_t color_type;
|
|||||||
typedef uint32_t combining_type;
|
typedef uint32_t combining_type;
|
||||||
typedef unsigned int index_type;
|
typedef unsigned int index_type;
|
||||||
typedef uint16_t sprite_index;
|
typedef uint16_t sprite_index;
|
||||||
|
typedef enum CursorShapes { NO_CURSOR_SHAPE, CURSOR_BLOCK, CURSOR_BEAM, CURSOR_UNDERLINE, NUM_OF_CURSOR_SHAPES } CursorShape;
|
||||||
|
|
||||||
#define ERROR_PREFIX "[PARSE ERROR]"
|
#define ERROR_PREFIX "[PARSE ERROR]"
|
||||||
#define ANY_MODE 3
|
#define ANY_MODE 3
|
||||||
@@ -61,9 +62,6 @@ typedef uint16_t sprite_index;
|
|||||||
#define DECORATION_FG_CODE 58
|
#define DECORATION_FG_CODE 58
|
||||||
#define CHAR_IS_BLANK(ch) ((ch & CHAR_MASK) == 32 || (ch & CHAR_MASK) == 0)
|
#define CHAR_IS_BLANK(ch) ((ch & CHAR_MASK) == 32 || (ch & CHAR_MASK) == 0)
|
||||||
|
|
||||||
#define CURSOR_BLOCK 1
|
|
||||||
#define CURSOR_BEAM 2
|
|
||||||
#define CURSOR_UNDERLINE 3
|
|
||||||
#define FG 1
|
#define FG 1
|
||||||
#define BG 2
|
#define BG 2
|
||||||
|
|
||||||
@@ -172,7 +170,8 @@ typedef struct {
|
|||||||
|
|
||||||
bool bold, italic, reverse, strikethrough, blink;
|
bool bold, italic, reverse, strikethrough, blink;
|
||||||
unsigned int x, y;
|
unsigned int x, y;
|
||||||
uint8_t decoration, shape;
|
uint8_t decoration;
|
||||||
|
CursorShape shape;
|
||||||
unsigned long fg, bg, decoration_fg;
|
unsigned long fg, bg, decoration_fg;
|
||||||
|
|
||||||
} Cursor;
|
} Cursor;
|
||||||
|
|||||||
13
kitty/glfw.c
13
kitty/glfw.c
@@ -39,19 +39,27 @@ typedef struct {
|
|||||||
|
|
||||||
// callbacks {{{
|
// callbacks {{{
|
||||||
static WindowWrapper* the_window = NULL;
|
static WindowWrapper* the_window = NULL;
|
||||||
|
update_viewport_size_func update_viewport_size = NULL;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
framebuffer_size_callback(GLFWwindow UNUSED *w, int width, int height) {
|
framebuffer_size_callback(GLFWwindow UNUSED *w, int width, int height) {
|
||||||
WINDOW_CALLBACK(framebuffer_size_callback, "ii", width, height);
|
if (width > 100 && height > 100) {
|
||||||
|
update_viewport_size(width, height);
|
||||||
|
global_state.viewport_width = width; global_state.viewport_height = height;
|
||||||
|
WINDOW_CALLBACK(framebuffer_size_callback, "ii", width, height);
|
||||||
|
glfwPostEmptyEvent();
|
||||||
|
} else fprintf(stderr, "Ignoring resize request for tiny size: %dx%d\n", width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
char_mods_callback(GLFWwindow UNUSED *w, unsigned int codepoint, int mods) {
|
char_mods_callback(GLFWwindow UNUSED *w, unsigned int codepoint, int mods) {
|
||||||
|
global_state.cursor_blink_zero_time = monotonic();
|
||||||
WINDOW_CALLBACK(char_mods_callback, "Ii", codepoint, mods);
|
WINDOW_CALLBACK(char_mods_callback, "Ii", codepoint, mods);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
key_callback(GLFWwindow UNUSED *w, int key, int scancode, int action, int mods) {
|
key_callback(GLFWwindow UNUSED *w, int key, int scancode, int action, int mods) {
|
||||||
|
global_state.cursor_blink_zero_time = monotonic();
|
||||||
WINDOW_CALLBACK(key_callback, "iiii", key, scancode, action, mods);
|
WINDOW_CALLBACK(key_callback, "iiii", key, scancode, action, mods);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,12 +75,14 @@ scroll_callback(GLFWwindow UNUSED *w, double xoffset, double yoffset) {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
cursor_pos_callback(GLFWwindow UNUSED *w, double x, double y) {
|
cursor_pos_callback(GLFWwindow UNUSED *w, double x, double y) {
|
||||||
|
global_state.cursor_blink_zero_time = monotonic();
|
||||||
WINDOW_CALLBACK(cursor_pos_callback, "dd", x, y);
|
WINDOW_CALLBACK(cursor_pos_callback, "dd", x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
window_focus_callback(GLFWwindow UNUSED *w, int focused) {
|
window_focus_callback(GLFWwindow UNUSED *w, int focused) {
|
||||||
global_state.application_focused = focused ? true : false;
|
global_state.application_focused = focused ? true : false;
|
||||||
|
global_state.cursor_blink_zero_time = monotonic();
|
||||||
WINDOW_CALLBACK(window_focus_callback, "O", focused ? Py_True : Py_False);
|
WINDOW_CALLBACK(window_focus_callback, "O", focused ? Py_True : Py_False);
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
@@ -90,6 +100,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
|||||||
the_window = self;
|
the_window = self;
|
||||||
self->window = glfwCreateWindow(width, height, title, NULL, NULL);
|
self->window = glfwCreateWindow(width, height, title, NULL, NULL);
|
||||||
if (self->window == NULL) { Py_CLEAR(self); the_window = NULL; PyErr_SetString(PyExc_ValueError, "Failed to create GLFWwindow"); return NULL; }
|
if (self->window == NULL) { Py_CLEAR(self); the_window = NULL; PyErr_SetString(PyExc_ValueError, "Failed to create GLFWwindow"); return NULL; }
|
||||||
|
global_state.viewport_width = width; global_state.viewport_height = height;
|
||||||
self->standard_cursor = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
|
self->standard_cursor = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
|
||||||
self->click_cursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
|
self->click_cursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
|
||||||
if (self->standard_cursor == NULL || self->click_cursor == NULL) { Py_CLEAR(self); PyErr_SetString(PyExc_ValueError, "Failed to create standard mouse cursors"); return NULL; }
|
if (self->standard_cursor == NULL || self->click_cursor == NULL) { Py_CLEAR(self); PyErr_SetString(PyExc_ValueError, "Failed to create standard mouse cursors"); return NULL; }
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ from .fast_data_types import (
|
|||||||
GLFW_STENCIL_BITS, GLFWWindow, change_wcwidth, check_for_extensions,
|
GLFW_STENCIL_BITS, GLFWWindow, change_wcwidth, check_for_extensions,
|
||||||
clear_buffers, glewInit, glfw_init, glfw_init_hint_string,
|
clear_buffers, glewInit, glfw_init, glfw_init_hint_string,
|
||||||
glfw_set_error_callback, glfw_swap_interval, glfw_terminate,
|
glfw_set_error_callback, glfw_swap_interval, glfw_terminate,
|
||||||
glfw_window_hint, set_options
|
glfw_window_hint, set_logical_dpi, set_options
|
||||||
)
|
)
|
||||||
from .layout import all_layouts
|
from .layout import all_layouts
|
||||||
from .utils import color_as_int, detach, safe_print
|
from .utils import color_as_int, detach, get_logical_dpi, safe_print
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from .fast_data_types import GLFW_X11_WM_CLASS_NAME, GLFW_X11_WM_CLASS_CLASS
|
from .fast_data_types import GLFW_X11_WM_CLASS_NAME, GLFW_X11_WM_CLASS_CLASS
|
||||||
@@ -186,6 +186,7 @@ def run_app(opts, args):
|
|||||||
else:
|
else:
|
||||||
with open(logo_data_file, 'rb') as f:
|
with open(logo_data_file, 'rb') as f:
|
||||||
window.set_icon(f.read(), 256, 256)
|
window.set_icon(f.read(), 256, 256)
|
||||||
|
set_logical_dpi(*get_logical_dpi())
|
||||||
viewport_size.width, viewport_size.height = window.get_framebuffer_size()
|
viewport_size.width, viewport_size.height = window.get_framebuffer_size()
|
||||||
w, h = window.get_window_size()
|
w, h = window.get_window_size()
|
||||||
viewport_size.x_ratio = viewport_size.width / float(w)
|
viewport_size.x_ratio = viewport_size.width / float(w)
|
||||||
|
|||||||
@@ -511,6 +511,20 @@ void screen_reset_mode(Screen *self, unsigned int mode) {
|
|||||||
|
|
||||||
// Cursor {{{
|
// Cursor {{{
|
||||||
|
|
||||||
|
unsigned long
|
||||||
|
screen_current_char_width(Screen *self) {
|
||||||
|
unsigned long ans = 1;
|
||||||
|
if (self->cursor->x < self->columns - 1 && self->cursor->y < self->lines) {
|
||||||
|
ans = linebuf_char_width_at(self->linebuf, self->cursor->x, self->cursor->y);
|
||||||
|
}
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
screen_is_cursor_visible(Screen *self) {
|
||||||
|
return self->modes.mDECTCEM;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_backspace(Screen *self) {
|
screen_backspace(Screen *self) {
|
||||||
screen_cursor_back(self, 1, -1);
|
screen_cursor_back(self, 1, -1);
|
||||||
@@ -1443,11 +1457,7 @@ mark_as_dirty(Screen *self) {
|
|||||||
static PyObject*
|
static PyObject*
|
||||||
current_char_width(Screen *self) {
|
current_char_width(Screen *self) {
|
||||||
#define current_char_width_doc "The width of the character under the cursor"
|
#define current_char_width_doc "The width of the character under the cursor"
|
||||||
unsigned long ans = 1;
|
return PyLong_FromUnsignedLong(screen_current_char_width(self));
|
||||||
if (self->cursor->x < self->columns - 1 && self->cursor->y < self->lines) {
|
|
||||||
ans = linebuf_char_width_at(self->linebuf, self->cursor->x, self->cursor->y);
|
|
||||||
}
|
|
||||||
return PyLong_FromUnsignedLong(ans);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ void screen_apply_selection(Screen *self, void *address, size_t size);
|
|||||||
bool screen_is_selection_dirty(Screen *self);
|
bool screen_is_selection_dirty(Screen *self);
|
||||||
bool screen_invert_colors(Screen *self);
|
bool screen_invert_colors(Screen *self);
|
||||||
void screen_update_cell_data(Screen *self, void *address, size_t sz);
|
void screen_update_cell_data(Screen *self, void *address, size_t sz);
|
||||||
|
bool screen_is_cursor_visible(Screen *self);
|
||||||
|
unsigned long screen_current_char_width(Screen *self);
|
||||||
#define DECLARE_CH_SCREEN_HANDLER(name) void screen_##name(Screen *screen);
|
#define DECLARE_CH_SCREEN_HANDLER(name) void screen_##name(Screen *screen);
|
||||||
DECLARE_CH_SCREEN_HANDLER(bell)
|
DECLARE_CH_SCREEN_HANDLER(bell)
|
||||||
DECLARE_CH_SCREEN_HANDLER(backspace)
|
DECLARE_CH_SCREEN_HANDLER(backspace)
|
||||||
|
|||||||
@@ -84,6 +84,11 @@ glew_init(PyObject UNUSED *self) {
|
|||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_viewport_size_impl(int w, int h) {
|
||||||
|
glViewport(0, 0, w, h); check_gl();
|
||||||
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
// Programs {{{
|
// Programs {{{
|
||||||
@@ -668,7 +673,7 @@ init_cursor_program() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
draw_cursor(bool semi_transparent, bool is_focused, color_type color, float alpha, float left, float right, float top, float bottom) {
|
draw_cursor_impl(bool semi_transparent, bool is_focused, color_type color, float alpha, float left, float right, float top, float bottom) {
|
||||||
if (semi_transparent) { glEnable(GL_BLEND); check_gl(); }
|
if (semi_transparent) { glEnable(GL_BLEND); check_gl(); }
|
||||||
bind_program(CURSOR_PROGRAM); bind_vertex_array(cursor_vertex_array);
|
bind_program(CURSOR_PROGRAM); bind_vertex_array(cursor_vertex_array);
|
||||||
glUniform4f(cursor_uniform_locations[CURSOR_color], ((color >> 16) & 0xff) / 255.0, ((color >> 8) & 0xff) / 255.0, (color & 0xff) / 255.0, alpha);
|
glUniform4f(cursor_uniform_locations[CURSOR_color], ((color >> 16) & 0xff) / 255.0, ((color >> 8) & 0xff) / 255.0, (color & 0xff) / 255.0, alpha);
|
||||||
@@ -852,12 +857,6 @@ PYWRAP1(layout_sprite_map) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
PYWRAP1(resize_gl_viewport) {
|
|
||||||
unsigned int w, h; PA("II", &w, &h);
|
|
||||||
glViewport(0, 0, w, h);
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PYWRAP1(clear_buffers) {
|
PYWRAP1(clear_buffers) {
|
||||||
PyObject *swap_buffers;
|
PyObject *swap_buffers;
|
||||||
unsigned int bg;
|
unsigned int bg;
|
||||||
@@ -918,7 +917,6 @@ static PyMethodDef module_methods[] = {
|
|||||||
MW(create_cell_vao, METH_NOARGS),
|
MW(create_cell_vao, METH_NOARGS),
|
||||||
MW(layout_sprite_map, METH_VARARGS),
|
MW(layout_sprite_map, METH_VARARGS),
|
||||||
MW(destroy_sprite_map, METH_NOARGS),
|
MW(destroy_sprite_map, METH_NOARGS),
|
||||||
MW(resize_gl_viewport, METH_VARARGS),
|
|
||||||
MW(clear_buffers, METH_VARARGS),
|
MW(clear_buffers, METH_VARARGS),
|
||||||
|
|
||||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||||
@@ -962,8 +960,10 @@ init_shaders(PyObject *module) {
|
|||||||
#undef C
|
#undef C
|
||||||
PyModule_AddObject(module, "GL_VERSION_REQUIRED", Py_BuildValue("II", REQUIRED_VERSION_MAJOR, REQUIRED_VERSION_MINOR));
|
PyModule_AddObject(module, "GL_VERSION_REQUIRED", Py_BuildValue("II", REQUIRED_VERSION_MAJOR, REQUIRED_VERSION_MINOR));
|
||||||
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
||||||
|
update_viewport_size = &update_viewport_size_impl;
|
||||||
draw_borders = &draw_borders_impl;
|
draw_borders = &draw_borders_impl;
|
||||||
draw_cells = &draw_cells_impl;
|
draw_cells = &draw_cells_impl;
|
||||||
|
draw_cursor = &draw_cursor_impl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|||||||
@@ -103,9 +103,13 @@ swap_windows(unsigned int tab_id, unsigned int a, unsigned int b) {
|
|||||||
#define THREE_UINT(name) PYWRAP1(name) { unsigned int a, b, c; PA("III", &a, &b, &c); name(a, b, c); 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); if (PyErr_Occurred()) return NULL; }
|
||||||
S(visual_bell_duration, PyFloat_AsDouble);
|
S(visual_bell_duration, PyFloat_AsDouble);
|
||||||
S(enable_audio_bell, PyObject_IsTrue);
|
S(enable_audio_bell, PyObject_IsTrue);
|
||||||
|
S(cursor_blink_interval, PyFloat_AsDouble);
|
||||||
|
S(cursor_stop_blinking_after, PyFloat_AsDouble);
|
||||||
|
S(cursor_shape, PyLong_AsLong);
|
||||||
|
S(cursor_opacity, PyFloat_AsDouble);
|
||||||
#undef S
|
#undef S
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
@@ -144,6 +148,11 @@ PYWRAP1(update_window_visibility) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PYWRAP1(set_logical_dpi) {
|
||||||
|
PA("dd", &global_state.logical_dpi_x, &global_state.logical_dpi_y);
|
||||||
|
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;
|
||||||
@@ -163,6 +172,7 @@ THREE_UINT(swap_windows)
|
|||||||
|
|
||||||
static PyMethodDef module_methods[] = {
|
static PyMethodDef module_methods[] = {
|
||||||
MW(set_options, METH_O),
|
MW(set_options, METH_O),
|
||||||
|
MW(set_logical_dpi, METH_VARARGS),
|
||||||
MW(add_tab, METH_O),
|
MW(add_tab, METH_O),
|
||||||
MW(add_window, METH_VARARGS),
|
MW(add_window, METH_VARARGS),
|
||||||
MW(remove_tab, METH_O),
|
MW(remove_tab, METH_O),
|
||||||
@@ -183,6 +193,7 @@ static PyMethodDef module_methods[] = {
|
|||||||
bool
|
bool
|
||||||
init_state(PyObject *module) {
|
init_state(PyObject *module) {
|
||||||
global_state.application_focused = true;
|
global_state.application_focused = true;
|
||||||
|
global_state.cursor_blink_zero_time = monotonic();
|
||||||
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "data-types.h"
|
#include "data-types.h"
|
||||||
|
|
||||||
|
#define OPT(name) global_state.opts.name
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
double visual_bell_duration;
|
double visual_bell_duration, cursor_blink_interval, cursor_stop_blinking_after;
|
||||||
bool enable_audio_bell;
|
bool enable_audio_bell;
|
||||||
|
CursorShape cursor_shape;
|
||||||
|
double cursor_opacity;
|
||||||
} Options;
|
} Options;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -36,9 +40,14 @@ typedef struct {
|
|||||||
unsigned int active_tab, num_tabs;
|
unsigned int active_tab, num_tabs;
|
||||||
ScreenRenderData tab_bar_render_data;
|
ScreenRenderData tab_bar_render_data;
|
||||||
bool application_focused;
|
bool application_focused;
|
||||||
|
double cursor_blink_zero_time;
|
||||||
|
double logical_dpi_x, logical_dpi_y;
|
||||||
|
int viewport_width, viewport_height;
|
||||||
} GlobalState;
|
} GlobalState;
|
||||||
|
|
||||||
typedef void (*draw_borders_func)();
|
#define EXTERNAL_FUNC(name, ret, ...) typedef ret (*name##_func)(__VA_ARGS__); extern name##_func name
|
||||||
extern draw_borders_func draw_borders;
|
#define EXTERNAL_FUNC0(name, ret) typedef ret (*name##_func)(); extern name##_func name
|
||||||
typedef void (*draw_cells_func)(ssize_t, float, float, float, float, Screen *);
|
EXTERNAL_FUNC0(draw_borders, void);
|
||||||
extern draw_cells_func draw_cells;
|
EXTERNAL_FUNC(draw_cells, void, ssize_t, float, float, float, float, Screen *);
|
||||||
|
EXTERNAL_FUNC(draw_cursor, void, bool, bool, color_type, float, float, float, float, float);
|
||||||
|
EXTERNAL_FUNC(update_viewport_size, void, int, int);
|
||||||
|
|||||||
Reference in New Issue
Block a user