Allow rendering the cursor with reverse video
Also clean up handling of dynamic global colors. TODO: Implement none for selection_fg TODO: Add some tests TODO: Check that changing colors via remote control works Fixes #126
This commit is contained in:
parent
3ca3c67828
commit
0fdafd8398
@ -16,6 +16,9 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||
the keyboard. Pressing it causes numbers to appear over each visible window
|
||||
and you can press the number to focus the corresponding window (:iss:`4110`)
|
||||
|
||||
- Allow rendering the cursor with a *reverse video* effect. See :opt:`cursor`
|
||||
for details (:iss:`126`)
|
||||
|
||||
- A new option :opt:`tab_bar_align` to draw the tab bar centered or right
|
||||
aligned (:iss:`3946`)
|
||||
|
||||
|
||||
@ -12,9 +12,9 @@
|
||||
|
||||
// Inputs {{{
|
||||
layout(std140) uniform CellRenderData {
|
||||
float xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity, cursor_text_uses_bg;
|
||||
float xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity;
|
||||
|
||||
uint default_fg, default_bg, highlight_fg, highlight_bg, cursor_color, cursor_text_color, url_color, url_style, inverted;
|
||||
uint default_fg, default_bg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted;
|
||||
|
||||
uint xnum, ynum, cursor_fg_sprite_idx;
|
||||
float cursor_x, cursor_y, cursor_w;
|
||||
@ -198,8 +198,8 @@ void main() {
|
||||
strike_pos = to_sprite_pos(pos, ((text_attrs >> STRIKE_SHIFT) & ONE) * FOUR, ZERO, ZERO);
|
||||
|
||||
// Cursor
|
||||
cursor_color_vec = vec4(color_to_vec(cursor_color), 1.0);
|
||||
vec3 final_cursor_text_color = mix(color_to_vec(cursor_text_color), bg, cursor_text_uses_bg);
|
||||
cursor_color_vec = vec4(color_to_vec(cursor_bg), 1.0);
|
||||
vec3 final_cursor_text_color = color_to_vec(cursor_fg);
|
||||
foreground = choose_color(cell_has_block_cursor, final_cursor_text_color, foreground);
|
||||
decoration_fg = choose_color(cell_has_block_cursor, final_cursor_text_color, decoration_fg);
|
||||
cursor_pos = to_sprite_pos(pos, cursor_fg_sprite_idx * uint(cell_has_cursor), ZERO, ZERO);
|
||||
@ -237,7 +237,7 @@ void main() {
|
||||
#if defined(SPECIAL) || defined(SIMPLE)
|
||||
// Selection and cursor
|
||||
bg = choose_color(float(is_selected & ONE), color_to_vec(highlight_bg), bg);
|
||||
background = choose_color(cell_has_block_cursor, color_to_vec(cursor_color), bg);
|
||||
background = choose_color(cell_has_block_cursor, color_to_vec(cursor_bg), bg);
|
||||
#if !defined(TRANSPARENT) && defined(SPECIAL)
|
||||
float is_special_cell = cell_has_block_cursor + float(is_selected & ONE);
|
||||
bg_alpha = step(0.5, is_special_cell);
|
||||
|
||||
@ -574,9 +574,7 @@ collect_cursor_info(CursorRenderInfo *ans, Window *w, monotonic_t now, OSWindow
|
||||
}
|
||||
if (!do_draw_cursor) { ans->is_visible = false; return; }
|
||||
ans->is_visible = true;
|
||||
ColorProfile *cp = rd->screen->color_profile;
|
||||
ans->shape = cursor->shape ? cursor->shape : OPT(cursor_shape);
|
||||
ans->color = colorprofile_to_color(cp, cp->overridden.cursor_color, cp->configured.cursor_color);
|
||||
ans->is_focused = os_window->is_focused;
|
||||
}
|
||||
|
||||
@ -617,7 +615,7 @@ prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int *
|
||||
#define WD w->render_data
|
||||
if (w->visible && WD.screen) {
|
||||
*num_visible_windows += 1;
|
||||
color_type window_bg = colorprofile_to_color(WD.screen->color_profile, WD.screen->color_profile->overridden.default_bg, WD.screen->color_profile->configured.default_bg);
|
||||
color_type window_bg = colorprofile_to_color(WD.screen->color_profile, WD.screen->color_profile->overridden.default_bg, WD.screen->color_profile->configured.default_bg).rgb;
|
||||
if (*num_visible_windows == 1) first_window_bg = window_bg;
|
||||
if (first_window_bg != window_bg) *all_windows_have_same_bg = false;
|
||||
if (w->last_drag_scroll_at > 0) {
|
||||
|
||||
105
kitty/colors.c
105
kitty/colors.c
@ -151,65 +151,65 @@ patch_color_profiles(PyObject *module UNUSED, PyObject *args) {
|
||||
S(background, i); S(foreground, i);
|
||||
#undef S
|
||||
}
|
||||
#define SI(profile_name) \
|
||||
DynamicColor color; \
|
||||
if (PyLong_Check(v)) { \
|
||||
color.rgb = PyLong_AsUnsignedLong(v); color.type = COLOR_IS_RGB; \
|
||||
} else { color.rgb = 0; color.type = COLOR_IS_SPECIAL; }\
|
||||
self->overridden.profile_name = color; \
|
||||
if (change_configured) self->configured.profile_name = color; \
|
||||
self->dirty = true;
|
||||
|
||||
#define S(config_name, profile_name) { \
|
||||
v = PyDict_GetItemString(spec, #config_name); \
|
||||
if (v && PyLong_Check(v)) { \
|
||||
color_type color = PyLong_AsUnsignedLong(v); \
|
||||
if (v) { \
|
||||
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(profiles); i++) { \
|
||||
self = (ColorProfile*)PyTuple_GET_ITEM(profiles, i); \
|
||||
self->overridden.profile_name = (color << 8) | 2; \
|
||||
if (change_configured) self->configured.profile_name = color; \
|
||||
self->dirty = true; \
|
||||
SI(profile_name); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
S(foreground, default_fg); S(background, default_bg); S(cursor, cursor_color);
|
||||
S(selection_foreground, highlight_fg); S(selection_background, highlight_bg);
|
||||
S(cursor_text_color, cursor_text_color);
|
||||
#undef SI
|
||||
#undef S
|
||||
PyObject *cursor_text_color = PyDict_GetItemString(spec, "cursor_text_color");
|
||||
if (cursor_text_color) {
|
||||
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(profiles); i++) {
|
||||
self = (ColorProfile*)PyTuple_GET_ITEM(profiles, i);
|
||||
self->overridden.cursor_text_color = 0x111111;
|
||||
self->overridden.cursor_text_uses_bg = 3;
|
||||
if (PyLong_Check(cursor_text_color)) {
|
||||
self->overridden.cursor_text_color = (PyLong_AsUnsignedLong(cursor_text_color) << 8) | 2;
|
||||
self->overridden.cursor_text_uses_bg = 1;
|
||||
}
|
||||
if (change_configured) {
|
||||
self->configured.cursor_text_color = self->overridden.cursor_text_color;
|
||||
self->configured.cursor_text_uses_bg = self->overridden.cursor_text_uses_bg;
|
||||
}
|
||||
self->dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
color_type
|
||||
colorprofile_to_color(ColorProfile *self, color_type entry, color_type defval) {
|
||||
color_type t = entry & 0xFF, r;
|
||||
switch(t) {
|
||||
case 1:
|
||||
r = (entry >> 8) & 0xff;
|
||||
return self->color_table[r];
|
||||
case 2:
|
||||
return entry >> 8;
|
||||
default:
|
||||
DynamicColor
|
||||
colorprofile_to_color(ColorProfile *self, DynamicColor entry, DynamicColor defval) {
|
||||
switch(entry.type) {
|
||||
case COLOR_NOT_SET:
|
||||
return defval;
|
||||
case COLOR_IS_INDEX: {
|
||||
DynamicColor ans;
|
||||
ans.rgb = self->color_table[entry.rgb & 0xff] & 0xffffff;
|
||||
ans.type = COLOR_IS_RGB;
|
||||
return ans;
|
||||
}
|
||||
case COLOR_IS_RGB:
|
||||
case COLOR_IS_SPECIAL:
|
||||
return entry;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
float
|
||||
cursor_text_as_bg(ColorProfile *self) {
|
||||
if (self->overridden.cursor_text_uses_bg & 1) {
|
||||
return self->overridden.cursor_text_uses_bg & 2 ? 1.f : 0.f;
|
||||
color_type
|
||||
colorprofile_to_color_with_fallback(ColorProfile *self, DynamicColor entry, DynamicColor defval, DynamicColor fallback, DynamicColor falback_defval) {
|
||||
switch(entry.type) {
|
||||
case COLOR_NOT_SET:
|
||||
case COLOR_IS_SPECIAL:
|
||||
if (defval.type == COLOR_IS_SPECIAL) return colorprofile_to_color(self, fallback, falback_defval).rgb;
|
||||
return defval.rgb;
|
||||
case COLOR_IS_RGB:
|
||||
return entry.rgb;
|
||||
case COLOR_IS_INDEX:
|
||||
return self->color_table[entry.rgb & 0xff] & 0xffffff;
|
||||
}
|
||||
return self->configured.cursor_text_uses_bg & 2 ? 1.f : 0.f;
|
||||
return entry.rgb;
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
as_dict(ColorProfile *self, PyObject *args UNUSED) {
|
||||
#define as_dict_doc "Return all colors as a dictionary of color_name to integer (names are the same as used in kitty.conf)"
|
||||
@ -225,8 +225,8 @@ as_dict(ColorProfile *self, PyObject *args UNUSED) {
|
||||
if (ret != 0) { Py_CLEAR(ans); return NULL; }
|
||||
}
|
||||
#define D(attr, name) { \
|
||||
color_type c = colorprofile_to_color(self, self->overridden.attr, 0xffffffff); \
|
||||
if (c != 0xffffffff) { \
|
||||
if (self->overridden.attr.type != COLOR_NOT_SET) { \
|
||||
color_type c = colorprofile_to_color(self, self->overridden.attr, self->configured.attr).rgb; \
|
||||
PyObject *val = PyLong_FromUnsignedLong(c); \
|
||||
if (!val) { Py_CLEAR(ans); return PyErr_NoMemory(); } \
|
||||
int ret = PyDict_SetItemString(ans, #name, val); \
|
||||
@ -296,11 +296,14 @@ set_color(ColorProfile *self, PyObject *args) {
|
||||
static PyObject*
|
||||
set_configured_colors(ColorProfile *self, PyObject *args) {
|
||||
#define set_configured_colors_doc "Set the configured colors"
|
||||
if (!PyArg_ParseTuple(
|
||||
args, "II|IIIII",
|
||||
&(self->configured.default_fg), &(self->configured.default_bg),
|
||||
&(self->configured.cursor_color), &(self->configured.cursor_text_color), &(self->configured.cursor_text_uses_bg),
|
||||
&(self->configured.highlight_fg), &(self->configured.highlight_bg))) return NULL;
|
||||
unsigned int default_fg, default_bg, cursor_color, cursor_text_color, highlight_fg, highlight_bg;
|
||||
if (!PyArg_ParseTuple(args, "II|IIII", &default_fg, &default_bg,
|
||||
&cursor_color, &cursor_text_color, &highlight_fg, &highlight_bg)) return NULL;
|
||||
#define S(which) \
|
||||
self->configured.which.rgb = which & 0xffffff; \
|
||||
self->configured.which.type = (which & 0xff000000) ? COLOR_IS_RGB : COLOR_IS_SPECIAL;
|
||||
S(default_fg); S(default_bg); S(cursor_color); S(cursor_text_color); S(highlight_fg); S(highlight_bg);
|
||||
#undef S
|
||||
self->dirty = true;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
@ -395,8 +398,14 @@ default_color_table(PyObject *self UNUSED, PyObject *args UNUSED) {
|
||||
// Boilerplate {{{
|
||||
|
||||
#define CGETSET(name) \
|
||||
static PyObject* name##_get(ColorProfile *self, void UNUSED *closure) { return PyLong_FromUnsignedLong(colorprofile_to_color(self, self->overridden.name, self->configured.name)); } \
|
||||
static int name##_set(ColorProfile *self, PyObject *val, void UNUSED *closure) { if (val == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete attribute"); return -1; } self->overridden.name = (color_type) PyLong_AsUnsignedLong(val); self->dirty = true; return 0; }
|
||||
static PyObject* name##_get(ColorProfile *self, void UNUSED *closure) { return PyLong_FromUnsignedLong(colorprofile_to_color(self, self->overridden.name, self->configured.name).rgb); } \
|
||||
static int name##_set(ColorProfile *self, PyObject *v, void UNUSED *closure) { \
|
||||
if (v == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete attribute: " #name); return -1; } \
|
||||
unsigned long val = PyLong_AsUnsignedLong(v); \
|
||||
self->overridden.name.rgb = val & 0xffffff; \
|
||||
self->overridden.name.type = (val & 0xff000000) ? COLOR_IS_RGB : COLOR_NOT_SET; \
|
||||
self->dirty = true; return 0; \
|
||||
}
|
||||
|
||||
CGETSET(default_fg)
|
||||
CGETSET(default_bg)
|
||||
|
||||
@ -239,16 +239,27 @@ typedef struct {
|
||||
bool is_visible, is_focused;
|
||||
CursorShape shape;
|
||||
unsigned int x, y;
|
||||
color_type color;
|
||||
} CursorRenderInfo;
|
||||
|
||||
typedef struct {
|
||||
color_type default_fg, default_bg, cursor_color, cursor_text_color, cursor_text_uses_bg, highlight_fg, highlight_bg;
|
||||
typedef enum DynamicColorType {
|
||||
COLOR_NOT_SET, COLOR_IS_SPECIAL, COLOR_IS_INDEX, COLOR_IS_RGB
|
||||
} DynamicColorType;
|
||||
|
||||
typedef union DynamicColor {
|
||||
struct {
|
||||
color_type rgb: 24;
|
||||
DynamicColorType type: 8;
|
||||
};
|
||||
color_type val;
|
||||
} DynamicColor;
|
||||
|
||||
typedef struct {
|
||||
DynamicColor default_fg, default_bg, cursor_color, cursor_text_color, highlight_fg, highlight_bg;
|
||||
} DynamicColors;
|
||||
|
||||
|
||||
typedef struct {
|
||||
DynamicColor dynamic_colors;
|
||||
DynamicColors dynamic_colors;
|
||||
uint32_t color_table[256];
|
||||
} ColorStackEntry;
|
||||
|
||||
@ -260,7 +271,7 @@ typedef struct {
|
||||
uint32_t orig_color_table[256];
|
||||
ColorStackEntry *color_stack;
|
||||
unsigned int color_stack_idx, color_stack_sz;
|
||||
DynamicColor configured, overridden;
|
||||
DynamicColors configured, overridden;
|
||||
color_type mark_foregrounds[MARK_MASK+1], mark_backgrounds[MARK_MASK+1];
|
||||
} ColorProfile;
|
||||
|
||||
@ -332,8 +343,9 @@ bool schedule_write_to_child(unsigned long id, unsigned int num, ...);
|
||||
bool schedule_write_to_child_python(unsigned long id, const char *prefix, PyObject* tuple_of_str_or_bytes, const char *suffix);
|
||||
bool set_iutf8(int, bool);
|
||||
|
||||
color_type colorprofile_to_color(ColorProfile *self, color_type entry, color_type defval);
|
||||
float cursor_text_as_bg(ColorProfile *self);
|
||||
DynamicColor colorprofile_to_color(ColorProfile *self, DynamicColor entry, DynamicColor defval);
|
||||
color_type
|
||||
colorprofile_to_color_with_fallback(ColorProfile *self, DynamicColor entry, DynamicColor defval, DynamicColor fallback, DynamicColor falback_defval);
|
||||
void copy_color_table_to_buffer(ColorProfile *self, color_type *address, int offset, size_t stride);
|
||||
bool colorprofile_push_colors(ColorProfile*, unsigned int);
|
||||
bool colorprofile_pop_colors(ColorProfile*, unsigned int);
|
||||
|
||||
@ -642,7 +642,7 @@ class ColorProfile:
|
||||
pass
|
||||
|
||||
def set_configured_colors(
|
||||
self, fg: int, bg: int, cursor: int = 0, cursor_text: int = 0, cursor_text_uses_bg: int = 0, highlight_fg: int = 0, highlight_bg: int = 0
|
||||
self, fg: int, bg: int, cursor: int = 0, cursor_text: int = 0, highlight_fg: int = 0, highlight_bg: int = 0
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
|
||||
@ -162,7 +162,7 @@ blank_os_window(OSWindow *w) {
|
||||
Window *w = t->windows + t->active_window;
|
||||
Screen *s = w->render_data.screen;
|
||||
if (s) {
|
||||
color = colorprofile_to_color(s->color_profile, s->color_profile->overridden.default_bg, s->color_profile->configured.default_bg);
|
||||
color = colorprofile_to_color(s->color_profile, s->color_profile->overridden.default_bg, s->color_profile->configured.default_bg).rgb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,8 +213,14 @@ egr() # }}}
|
||||
agr('cursor', 'Cursor customization')
|
||||
|
||||
opt('cursor', '#cccccc',
|
||||
option_type='to_color',
|
||||
long_text='Default cursor color'
|
||||
option_type='to_color_or_none', long_text='''
|
||||
Default cursor color. If set to the special value :code:`none` the cursor will be
|
||||
rendered with a "reverse video" effect. It's color will be the color of the text in
|
||||
the cell it is over and the text will be rendered with the background color of the cell.
|
||||
Note that if the program running in the terminal sets a cursor color, this takes precedence.
|
||||
Also, the reverse video effect is not applied if the cell's foreground and background colors
|
||||
are the same.
|
||||
'''
|
||||
)
|
||||
|
||||
opt('cursor_text_color', '#111111',
|
||||
@ -222,7 +228,7 @@ opt('cursor_text_color', '#111111',
|
||||
long_text='''
|
||||
Choose the color of text under the cursor. If you want it rendered with the
|
||||
background color of the cell underneath instead, use the special keyword:
|
||||
background
|
||||
background.
|
||||
'''
|
||||
)
|
||||
|
||||
|
||||
2
kitty/options/parse.py
generated
2
kitty/options/parse.py
generated
@ -888,7 +888,7 @@ class Parser:
|
||||
ans['copy_on_select'] = copy_on_select(val)
|
||||
|
||||
def cursor(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['cursor'] = to_color(val)
|
||||
ans['cursor'] = to_color_or_none(val)
|
||||
|
||||
def cursor_beam_thickness(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['cursor_beam_thickness'] = positive_float(val)
|
||||
|
||||
@ -27,7 +27,6 @@ color_or_none_as_int(PyObject *color) {
|
||||
return color_as_int(color);
|
||||
}
|
||||
|
||||
|
||||
static inline color_type
|
||||
active_border_color(PyObject *color) {
|
||||
if (color == Py_None) return 0x00ff00;
|
||||
|
||||
2
kitty/options/types.py
generated
2
kitty/options/types.py
generated
@ -472,7 +472,7 @@ class Options:
|
||||
command_on_bell: typing.List[str] = ['none']
|
||||
confirm_os_window_close: int = 0
|
||||
copy_on_select: str = ''
|
||||
cursor: Color = Color(red=204, green=204, blue=204)
|
||||
cursor: typing.Optional[kitty.rgb.Color] = Color(red=204, green=204, blue=204)
|
||||
cursor_beam_thickness: float = 1.5
|
||||
cursor_blink_interval: float = -1.0
|
||||
cursor_shape: int = 1
|
||||
|
||||
@ -18,7 +18,7 @@ if TYPE_CHECKING:
|
||||
from kitty.cli_stub import SetColorsRCOptions as CLIOptions
|
||||
|
||||
|
||||
nullable_colors = ('cursor_text_color', 'tab_bar_background', 'tab_bar_margin_color')
|
||||
nullable_colors = ('cursor', 'cursor_text_color', 'tab_bar_background', 'tab_bar_margin_color', 'selection_foreground')
|
||||
|
||||
|
||||
def parse_colors(args: Iterable[str]) -> Dict[str, Optional[int]]:
|
||||
|
||||
@ -168,7 +168,7 @@ screen_reset(Screen *self) {
|
||||
self->modes = empty_modes;
|
||||
self->saved_modes = empty_modes;
|
||||
self->active_hyperlink_id = 0;
|
||||
#define R(name) self->color_profile->overridden.name = 0
|
||||
#define R(name) self->color_profile->overridden.name.val = 0
|
||||
R(default_fg); R(default_bg); R(cursor_color); R(highlight_fg); R(highlight_bg);
|
||||
#undef R
|
||||
RESET_CHARSETS;
|
||||
@ -1509,6 +1509,28 @@ screen_fake_move_cursor_to_position(Screen *self, index_type x, index_type y) {
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
static color_type
|
||||
resolve_color(ColorProfile *cp, color_type val, color_type defval) {
|
||||
switch(val & 0xff) {
|
||||
case 1:
|
||||
return cp->color_table[(val >> 8) & 0xff];
|
||||
case 2:
|
||||
return val >> 8;
|
||||
default:
|
||||
return defval;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
resolve_cell_colors(Screen *self, index_type x, index_type y, color_type *fg, color_type *bg, color_type default_fg, color_type default_bg) {
|
||||
if (x < self->columns && y < self->lines) {
|
||||
linebuf_init_line(self->linebuf, y);
|
||||
GPUCell *g = self->linebuf->line->gpu_cells + x;
|
||||
*fg = resolve_color(self->color_profile, g->fg, default_fg);
|
||||
*bg = resolve_color(self->color_profile, g->bg, default_bg);
|
||||
return true;
|
||||
} else { *fg = 0; *bg = 0; return false; }
|
||||
}
|
||||
// }}}
|
||||
|
||||
// Editing {{{
|
||||
|
||||
@ -249,6 +249,7 @@ void screen_report_key_encoding_flags(Screen *self);
|
||||
bool screen_detect_url(Screen *screen, unsigned int x, unsigned int y);
|
||||
int screen_cursor_at_a_shell_prompt(const Screen *);
|
||||
bool screen_fake_move_cursor_to_position(Screen *, index_type x, index_type y);
|
||||
bool resolve_cell_colors(Screen *self, index_type x, index_type y, color_type *fg, color_type *bg, color_type default_fg, color_type default_bg);
|
||||
#define DECLARE_CH_SCREEN_HANDLER(name) void screen_##name(Screen *screen);
|
||||
DECLARE_CH_SCREEN_HANDLER(bell)
|
||||
DECLARE_CH_SCREEN_HANDLER(backspace)
|
||||
|
||||
@ -260,9 +260,9 @@ send_graphics_data_to_gpu(size_t image_count, ssize_t gvao_idx, const ImageRende
|
||||
static void
|
||||
cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, CursorRenderInfo *cursor, bool inverted, OSWindow *os_window) {
|
||||
struct CellRenderData {
|
||||
GLfloat xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity, cursor_text_uses_bg;
|
||||
GLfloat xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity;
|
||||
|
||||
GLuint default_fg, default_bg, highlight_fg, highlight_bg, cursor_color, cursor_text_color, url_color, url_style, inverted;
|
||||
GLuint default_fg, default_bg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted;
|
||||
|
||||
GLuint xnum, ynum, cursor_fg_sprite_idx;
|
||||
GLfloat cursor_x, cursor_y, cursor_w;
|
||||
@ -274,6 +274,9 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, G
|
||||
if (UNLIKELY(screen->color_profile->dirty || screen->reload_all_gpu_data)) {
|
||||
copy_color_table_to_buffer(screen->color_profile, (GLuint*)rd, cell_program_layouts[CELL_PROGRAM].color_table.offset / sizeof(GLuint), cell_program_layouts[CELL_PROGRAM].color_table.stride / sizeof(GLuint));
|
||||
}
|
||||
#define COLOR(name) colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.name, screen->color_profile->configured.name).rgb
|
||||
#define IS_SPECIAL_COLOR(name) (screen->color_profile->overridden.name.type == COLOR_IS_SPECIAL || (screen->color_profile->overridden.name.type == COLOR_NOT_SET && screen->color_profile->configured.name.type == COLOR_IS_SPECIAL))
|
||||
rd->default_fg = COLOR(default_fg); rd->default_bg = COLOR(default_bg); rd->highlight_fg = COLOR(highlight_fg); rd->highlight_bg = COLOR(highlight_bg);
|
||||
// Cursor position
|
||||
enum { BLOCK_IDX = 0, BEAM_IDX = 6, UNDERLINE_IDX = 7, UNFOCUSED_IDX = 8 };
|
||||
if (cursor->is_visible) {
|
||||
@ -288,6 +291,21 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, G
|
||||
rd->cursor_fg_sprite_idx = UNDERLINE_IDX; break;
|
||||
}
|
||||
} else rd->cursor_fg_sprite_idx = UNFOCUSED_IDX;
|
||||
color_type cell_fg, cell_bg;
|
||||
resolve_cell_colors(screen, screen->cursor->x, screen->cursor->y, &cell_fg, &cell_bg, rd->default_fg, rd->default_bg);
|
||||
if (screen->color_profile->overridden.cursor_color.type == COLOR_IS_INDEX || screen->color_profile->overridden.cursor_color.type == COLOR_IS_RGB) {
|
||||
// since the program is controlling the cursor color we hope it has chosen one
|
||||
// that has good contrast with the text color of the cell
|
||||
rd->cursor_fg = cell_fg; rd->cursor_bg = COLOR(cursor_color);
|
||||
} else if (IS_SPECIAL_COLOR(cursor_color)) {
|
||||
if (cell_bg == cell_fg) {
|
||||
rd->cursor_fg = rd->default_bg; rd->cursor_bg = rd->default_fg;
|
||||
} else { rd->cursor_fg = cell_bg; rd->cursor_bg = cell_fg; }
|
||||
} else {
|
||||
rd->cursor_bg = COLOR(cursor_color);
|
||||
if (IS_SPECIAL_COLOR(cursor_text_color)) rd->cursor_fg = cell_bg;
|
||||
else rd->cursor_fg = COLOR(cursor_text_color);
|
||||
}
|
||||
} else rd->cursor_x = screen->columns, rd->cursor_y = screen->lines;
|
||||
rd->cursor_w = rd->cursor_x;
|
||||
if (
|
||||
@ -304,12 +322,9 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, G
|
||||
rd->inverted = inverted ? 1 : 0;
|
||||
rd->background_opacity = os_window->is_semi_transparent ? os_window->background_opacity : 1.0f;
|
||||
|
||||
#define COLOR(name) colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.name, screen->color_profile->configured.name)
|
||||
rd->default_fg = COLOR(default_fg); rd->default_bg = COLOR(default_bg); rd->highlight_fg = COLOR(highlight_fg); rd->highlight_bg = COLOR(highlight_bg);
|
||||
rd->cursor_text_color = COLOR(cursor_text_color);
|
||||
#undef COLOR
|
||||
rd->cursor_color = cursor->color; rd->url_color = OPT(url_color); rd->url_style = OPT(url_style);
|
||||
rd->cursor_text_uses_bg = cursor_text_as_bg(screen->color_profile);
|
||||
#undef IS_SPECIAL_COLOR
|
||||
rd->url_color = OPT(url_color); rd->url_style = OPT(url_style);
|
||||
|
||||
unmap_vao_buffer(vao_idx, uniform_buffer); rd = NULL;
|
||||
}
|
||||
@ -456,7 +471,7 @@ has_bgimage(OSWindow *w) {
|
||||
static void
|
||||
draw_tint(bool premult, Screen *screen, GLfloat xstart, GLfloat ystart, GLfloat width, GLfloat height) {
|
||||
bind_program(TINT_PROGRAM);
|
||||
color_type window_bg = colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.default_bg, screen->color_profile->configured.default_bg);
|
||||
color_type window_bg = colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.default_bg, screen->color_profile->configured.default_bg).rgb;
|
||||
#define C(shift) ((((GLfloat)((window_bg >> shift) & 0xFF)) / 255.0f))
|
||||
float alpha = OPT(background_tint);
|
||||
if (premult) glUniform4f(tint_program_layout.tint_color_location, C(16) * alpha, C(8) * alpha, C(0) * alpha, alpha);
|
||||
@ -506,8 +521,8 @@ render_window_title(OSWindow *os_window, Screen *screen UNUSED, GLfloat xstart,
|
||||
static char title[2048] = {0};
|
||||
if (window->title_bar_data.last_drawn_title_object_id != window->title) {
|
||||
snprintf(title, arraysz(title), " %s", PyUnicode_AsUTF8(window->title));
|
||||
#define RGBCOL(which) ( 0xff000000 | colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.which, screen->color_profile->configured.which) )
|
||||
if (!draw_window_title(os_window, title, RGBCOL(highlight_fg), RGBCOL(highlight_bg), window->title_bar_data.buf, bar_width, bar_height)) return 0;
|
||||
#define RGBCOL(which, fallback) ( 0xff000000 | colorprofile_to_color_with_fallback(screen->color_profile, screen->color_profile->overridden.which, screen->color_profile->configured.which, screen->color_profile->overridden.fallback, screen->color_profile->configured.fallback))
|
||||
if (!draw_window_title(os_window, title, RGBCOL(highlight_fg, default_fg), RGBCOL(highlight_bg, default_bg), window->title_bar_data.buf, bar_width, bar_height)) return 0;
|
||||
#undef RGBCOL
|
||||
window->title_bar_data.last_drawn_title_object_id = window->title;
|
||||
}
|
||||
@ -550,7 +565,7 @@ draw_window_number(OSWindow *os_window, Screen *screen, GLfloat xstart, GLfloat
|
||||
bind_program(SEVEN_SEGMENT_PROGRAM);
|
||||
glUniform4f(seven_segment_program_layout.edges_location, xstart, ystart - height, xstart + width, ystart);
|
||||
glUniform4f(seven_segment_program_layout.area_bounds_location, left, top, right - left, bottom - top);
|
||||
color_type digit_color = colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.highlight_bg, screen->color_profile->configured.highlight_bg);
|
||||
color_type digit_color = colorprofile_to_color_with_fallback(screen->color_profile, screen->color_profile->overridden.highlight_bg, screen->color_profile->configured.highlight_bg, screen->color_profile->overridden.default_fg, screen->color_profile->configured.default_fg);
|
||||
#define C(shift) ((((GLfloat)((digit_color >> shift) & 0xFF)) / 255.0f))
|
||||
glUniform4f(seven_segment_program_layout.digit_color_location, C(16), C(8), C(0), 1.);
|
||||
#undef C
|
||||
@ -566,7 +581,8 @@ draw_visual_bell_flash(GLfloat intensity, GLfloat xstart, GLfloat ystart, GLfloa
|
||||
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
|
||||
bind_program(TINT_PROGRAM);
|
||||
GLfloat attenuation = 0.4f;
|
||||
const color_type flash = colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.highlight_bg, screen->color_profile->configured.highlight_bg);
|
||||
const color_type flash = colorprofile_to_color_with_fallback(
|
||||
screen->color_profile, screen->color_profile->overridden.highlight_bg, screen->color_profile->configured.highlight_bg, screen->color_profile->overridden.default_fg, screen->color_profile->configured.default_fg);
|
||||
#define C(shift) ((((GLfloat)((flash >> shift) & 0xFF)) / 255.0f) )
|
||||
const GLfloat r = C(16), g = C(8), b = C(0);
|
||||
const GLfloat max_channel = r > g ? (r > b ? r : b) : (g > b ? g : b);
|
||||
|
||||
@ -36,13 +36,13 @@ from .fast_data_types import (
|
||||
from .keys import keyboard_mode_name, mod_mask
|
||||
from .notify import NotificationCommand, handle_notification_cmd
|
||||
from .options.types import Options
|
||||
from .rgb import to_color
|
||||
from .rgb import Color, to_color
|
||||
from .terminfo import get_capabilities
|
||||
from .types import MouseEvent, ScreenGeometry, WindowGeometry, ac
|
||||
from .typing import BossType, ChildType, EdgeLiteral, TabType, TypedDict
|
||||
from .utils import (
|
||||
color_as_int, get_primary_selection, load_shaders, log_error, open_cmd,
|
||||
open_url, parse_color_set, sanitize_title, set_primary_selection
|
||||
get_primary_selection, load_shaders, log_error, open_cmd, open_url,
|
||||
parse_color_set, sanitize_title, set_primary_selection
|
||||
)
|
||||
|
||||
MatchPatternType = Union[Pattern[str], Tuple[Pattern[str], Optional[Pattern[str]]]]
|
||||
@ -264,14 +264,14 @@ load_shader_programs = LoadShaderPrograms()
|
||||
|
||||
def setup_colors(screen: Screen, opts: Options) -> None:
|
||||
screen.color_profile.update_ansi_color_table(build_ansi_color_table(opts))
|
||||
cursor_text_color = opts.cursor_text_color or (12, 12, 12)
|
||||
cursor_text_color_as_bg = 3 if opts.cursor_text_color is None else 1
|
||||
sfg = (0, 0, 0) if opts.selection_foreground is None else opts.selection_foreground
|
||||
screen.color_profile.set_configured_colors(*map(color_as_int, (
|
||||
opts.foreground, opts.background, opts.cursor,
|
||||
cursor_text_color, (0, 0, cursor_text_color_as_bg),
|
||||
sfg, opts.selection_background)
|
||||
))
|
||||
|
||||
def s(c: Optional[Color]) -> int:
|
||||
return 0 if c is None else (0xff000000 | int(c))
|
||||
screen.color_profile.set_configured_colors(
|
||||
s(opts.foreground), s(opts.background),
|
||||
s(opts.cursor), s(opts.cursor_text_color),
|
||||
s(opts.selection_foreground), s(opts.selection_background)
|
||||
)
|
||||
|
||||
|
||||
def text_sanitizer(as_ansi: bool, add_wrap_markers: bool) -> Callable[[str], str]:
|
||||
@ -762,16 +762,16 @@ class Window:
|
||||
def change_colors(self, changes: Dict[DynamicColor, Optional[str]]) -> None:
|
||||
dirtied = default_bg_changed = False
|
||||
|
||||
def item(raw: Optional[str]) -> Optional[int]:
|
||||
def item(raw: Optional[str]) -> int:
|
||||
if raw is None:
|
||||
return 0
|
||||
val = to_color(raw)
|
||||
return None if val is None else (color_as_int(val) << 8) | 2
|
||||
v = to_color(raw)
|
||||
if v is None:
|
||||
return 0
|
||||
return 0xff000000 | int(v)
|
||||
|
||||
for which, val_ in changes.items():
|
||||
val = item(val_)
|
||||
if val is None:
|
||||
continue
|
||||
dirtied = True
|
||||
setattr(self.screen.color_profile, which.name, val)
|
||||
if which.name == 'default_bg':
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user