Compare commits

..

4 Commits

Author SHA1 Message Date
Kovid Goyal
c10e421e9b Implement dynamic control of transparent background colors via escape code
Still have to implement it via remote control
2024-09-20 12:56:16 +05:30
Kovid Goyal
958cc6d98f Store transparent colors on ColorProfile
This will eventually allow them to be changed using remote control and
escape codes.
2024-09-20 10:02:28 +05:30
Kovid Goyal
f1f4a1a4a3 Replace the second_transparent_bg option
This is backwards incompatible, but only for a feature released 3 weeks
ago.
2024-09-20 09:11:39 +05:30
Kovid Goyal
55859f4b56 Prepare for allowing upto seven additional semi-transparent background colors 2024-09-20 09:11:39 +05:30
23 changed files with 66 additions and 160 deletions

View File

@@ -74,17 +74,7 @@ consumption to do the same tasks.
Detailed list of changes
-------------------------------------
0.36.4 [2024-09-27]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Fix a regression in the previous release that caused window padding to be rendered opaque even when :opt:`background_opacity` is less than 1 (:iss:`7895`)
- Wayland GNOME: Fix a crash when using multiple monitors with different scales and starting on or moving to the monitor with lower scale (:iss:`7894`)
- macOS: Fix a regression in the previous release that caused junk to be rendered in font previews in the choose fonts kitten and crash on Intel macs (:iss:`7892`)
0.36.3 [2024-09-25]
0.36.3 [future]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The option ``second_transparent_bg`` has been removed and replaced by :opt:`transparent_background_colors` which allows setting up to seven additional colors that will be transparent, with individual opacities per color (:iss:`7646`)
@@ -103,10 +93,6 @@ Detailed list of changes
- kitten @ ls: Fix the ``--self`` flag not working (:iss:`7864`)
- Remote control: Fix ``--match state:self`` not working (:disc:`7886`)
- Splits layout: Allow setting the ``split_axis`` option to ``auto`` so that all new windows have their split axis chosen automatically unless explicitly specified in the launch command (:iss:`7887`)
0.36.2 [2024-09-06]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -184,13 +184,11 @@ in a split using the ``rotate`` action with an argument of ``180`` and rotate
and swap with an argument of ``270``.
This layout takes one option, ``split_axis`` that controls whether new windows
are placed into vertical or horizontal splits when a :option:`--location
<launch --location>` is not specified. A value of ``horizontal`` (same as
``--location=vsplit``) means when a new split is created the two windows will
be placed side by side and a value of ``vertical`` (same as
``--location=hsplit``) means the two windows will be placed one on top of the
other. A value of ``auto`` means the axis of the split is chosen automatically
(same as ``--location=split``). By default::
are placed into vertical or horizontal splits when a :option:`--location <launch
--location>` is not specified. A value of ``horizontal`` (same as
``--location=vsplit``) means when a new split is created the two windows will be
placed side by side and a value of ``vertical`` (same as ``--location=hsplit``)
means the two windows will be placed one on top of the other. By default::
enabled_layouts splits:split_axis=horizontal

View File

@@ -27,7 +27,6 @@
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#include "internal.h"
#include <stdlib.h>

View File

@@ -26,7 +26,6 @@
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#include "../kitty/monotonic.h"
#include "glfw3.h"
#include "internal.h"

View File

@@ -468,8 +468,10 @@ render_shadows(_GLFWwindow *window) {
static bool
create_shm_buffers(_GLFWwindow* window) {
const double scale = _glfwWaylandWindowScale(window);
decs.mapping.size = 0;
#define bp(which, width, height) decs.mapping.size += init_buffer_pair(&decs.which.buffer, width, height, decs.for_window_state.fscale);
#define bp(which, width, height) decs.mapping.size += init_buffer_pair(&decs.which.buffer, width, height, scale);
bp(titlebar, window->wl.width, decs.metrics.visible_titlebar_height);
bp(shadow_top, window->wl.width, decs.metrics.width);
bp(shadow_bottom, window->wl.width, decs.metrics.width);
@@ -502,7 +504,7 @@ create_shm_buffers(_GLFWwindow* window) {
wl_shm_pool_destroy(pool);
render_title_bar(window, true);
render_shadows(window);
debug("Created decoration buffers at scale: %f\n", decs.for_window_state.fscale);
debug("Created decoration buffers at scale: %f\n", scale);
return true;
}
@@ -575,11 +577,10 @@ ensure_csd_resources(_GLFWwindow *window) {
if (!window_is_csd_capable(window)) return false;
const bool is_focused = window->id == _glfw.focusedWindowId;
const bool focus_changed = is_focused != decs.for_window_state.focused;
const double current_scale = _glfwWaylandWindowScale(window);
const bool size_changed = (
decs.for_window_state.width != window->wl.width ||
decs.for_window_state.height != window->wl.height ||
decs.for_window_state.fscale != current_scale ||
decs.for_window_state.fscale != _glfwWaylandWindowScale(window) ||
!decs.mapping.data
);
const bool state_changed = decs.for_window_state.toplevel_states != window->wl.current.toplevel_states;
@@ -588,7 +589,6 @@ ensure_csd_resources(_GLFWwindow *window) {
decs.for_window_state.width, decs.for_window_state.height, window->wl.width, window->wl.height, needs_update,
size_changed, state_changed, decs.buffer_destroyed);
if (!needs_update) return false;
decs.for_window_state.fscale = current_scale; // used in create_shm_buffers
if (size_changed || decs.buffer_destroyed) {
free_csd_buffers(window);
if (!create_shm_buffers(window)) return false;
@@ -618,6 +618,7 @@ ensure_csd_resources(_GLFWwindow *window) {
decs.for_window_state.width = window->wl.width;
decs.for_window_state.height = window->wl.height;
decs.for_window_state.fscale = _glfwWaylandWindowScale(window);
decs.for_window_state.focused = is_focused;
decs.for_window_state.toplevel_states = window->wl.current.toplevel_states;
return true;

View File

@@ -65,9 +65,6 @@ func (k *kitty_font_backend_type) start() (err error) {
var kitty_font_backend kitty_font_backend_type
func (k *kitty_font_backend_type) send(v any) error {
if k.to == nil {
return fmt.Errorf("Trying to send data when to pipe is nil")
}
data, err := json.Marshal(v)
if err != nil {
return fmt.Errorf("Could not encode message to kitty with error: %w", err)

View File

@@ -92,8 +92,7 @@ available or broken, using an alternate interpreter can be useful.
opt('remote_dir', '.local/share/kitty-ssh-kitten', long_text='''
The location on the remote host where the files needed for this kitten are
installed. Relative paths are resolved with respect to :code:`$HOME`. Absolute
paths have their leading / removed and so are also resolved with respect to $HOME.
installed. Relative paths are resolved with respect to :code:`$HOME`.
''')
opt('+copy', '', add_to_default=False, ctype='CopyInstruction', long_text=f'''

View File

@@ -1,6 +1,5 @@
uniform uvec2 viewport;
uniform uint colors[9];
uniform float background_opacity;
uniform float tint_opacity, tint_premult;
uniform float gamma_lut[256];
in vec4 rect; // left, top, right, bottom
@@ -42,11 +41,7 @@ void main() {
float is_window_bg = is_integer_value(rc, 3.);
float is_default_bg = is_integer_value(rc, 0.);
color3 = is_window_bg * window_bg + (1. - is_window_bg) * color3;
// Border must be always drawn opaque
float is_border_bg = 1. - step(0.5, abs((float(rc) - 2.) * (float(rc) - 1.) * (float(rc) - 4.))); // 1 if rc in (1, 2, 4) else 0
float final_opacity = is_default_bg * tint_opacity + (1. - is_default_bg) * background_opacity;
final_opacity = is_border_bg + (1. - is_border_bg) * final_opacity;
float final_premult_opacity = is_default_bg * tint_premult + (1. - is_default_bg) * background_opacity;
final_premult_opacity = is_border_bg + (1. - is_border_bg) * final_premult_opacity;
float final_opacity = is_default_bg * tint_opacity + (1. - is_default_bg);
float final_premult_opacity = is_default_bg * tint_premult + (1. - is_default_bg);
color = vec4(color3 * final_premult_opacity, final_opacity);
}

View File

@@ -2617,7 +2617,7 @@ class Boss:
window.screen.disable_ligatures = strategy
window.refresh()
def patch_colors(self, spec: dict[str, Optional[int]], transparent_background_colors: tuple[tuple[Color, float], ...], configured: bool = False) -> None:
def patch_colors(self, spec: dict[str, Optional[int]], configured: bool = False) -> None:
opts = get_options()
if configured:
for k, v in spec.items():
@@ -2627,7 +2627,6 @@ class Boss:
setattr(opts, k, None)
else:
setattr(opts, k, color_from_int(v))
opts.transparent_background_colors = transparent_background_colors
for tm in self.all_tab_managers:
tm.tab_bar.patch_colors(spec)
tm.tab_bar.layout()

View File

@@ -60,17 +60,6 @@ create_256_color_table(void) {
return ans;
}
static void
set_transparent_background_colors(TransparentDynamicColor *dest, PyObject *src) {
memset(dest, 0, sizeof(((ColorProfile*)0)->configured_transparent_colors));
for (Py_ssize_t i = 0; i < MIN(PyTuple_GET_SIZE(src), (Py_ssize_t)arraysz(((ColorProfile*)0)->configured_transparent_colors)); i++) {
PyObject *e = PyTuple_GET_ITEM(src, i);
dest[i].color = ((Color*)(PyTuple_GET_ITEM(e, 0)))->color.val & 0xffffff;
dest[i].opacity = (float)PyFloat_AsDouble(PyTuple_GET_ITEM(e, 1));
dest[i].is_set = true;
}
}
static bool
set_configured_colors(ColorProfile *self, PyObject *opts) {
#define n(which, attr) { \
@@ -93,9 +82,15 @@ set_configured_colors(ColorProfile *self, PyObject *opts) {
n(highlight_fg, selection_foreground); n(highlight_bg, selection_background);
n(visual_bell_color, visual_bell_color);
#undef n
memset(self->configured_transparent_colors, 0, sizeof(self->configured_transparent_colors));
RAII_PyObject(src, PyObject_GetAttrString(opts, "transparent_background_colors"));
if (!src) { PyErr_SetString(PyExc_TypeError, "No transparent_background_colors on opts object"); return false; }
set_transparent_background_colors(self->configured_transparent_colors, src);
for (Py_ssize_t i = 0; i < MIN(PyTuple_GET_SIZE(src), (Py_ssize_t)arraysz(self->configured_transparent_colors)); i++) {
PyObject *e = PyTuple_GET_ITEM(src, i);
self->configured_transparent_colors[i].color = ((Color*)(PyTuple_GET_ITEM(e, 0)))->color.val & 0xffffff;
self->configured_transparent_colors[i].opacity = (float)PyFloat_AsDouble(PyTuple_GET_ITEM(e, 1));
self->configured_transparent_colors[i].is_set = true;
}
return PyErr_Occurred() ? false : true;
}
@@ -209,8 +204,8 @@ patch_color_table(const char *key, PyObject *profiles, PyObject *spec, size_t wh
static PyObject*
patch_color_profiles(PyObject *module UNUSED, PyObject *args) {
PyObject *spec, *transparent_background_colors, *profiles, *v; ColorProfile *self; int change_configured;
if (!PyArg_ParseTuple(args, "O!O!O!p", &PyDict_Type, &spec, &PyTuple_Type, &transparent_background_colors, &PyTuple_Type, &profiles, &change_configured)) return NULL;
PyObject *spec, *profiles, *v; ColorProfile *self; int change_configured;
if (!PyArg_ParseTuple(args, "O!O!p", &PyDict_Type, &spec, &PyTuple_Type, &profiles, &change_configured)) return NULL;
char key[32] = {0};
for (size_t i = 0; i < arraysz(FG_BG_256); i++) {
snprintf(key, sizeof(key) - 1, "color%zu", i);
@@ -244,12 +239,7 @@ patch_color_profiles(PyObject *module UNUSED, PyObject *args) {
S(cursor_text_color, cursor_text_color); S(visual_bell_color, visual_bell_color);
#undef SI
#undef S
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(profiles); i++) {
self = (ColorProfile*)PyTuple_GET_ITEM(profiles, i);
set_transparent_background_colors(self->overriden_transparent_colors, transparent_background_colors);
if (change_configured) set_transparent_background_colors(self->configured_transparent_colors, transparent_background_colors);
}
if (PyErr_Occurred()) return NULL;
// TODO: Patch transparent_colors
Py_RETURN_NONE;
}
@@ -303,21 +293,20 @@ colorprofile_to_color_with_fallback(ColorProfile *self, DynamicColor entry, Dyna
}
return entry.rgb;
}
static Color* alloc_color(unsigned char r, unsigned char g, unsigned char b, unsigned a);
static PyObject*
as_dict(ColorProfile *self, PyObject *args UNUSED) {
#define as_dict_doc "Return all colors as a dictionary of color_name to integer or None (names are the same as used in kitty.conf)"
RAII_PyObject(ans, PyDict_New());
PyObject *ans = PyDict_New();
if (ans == NULL) return PyErr_NoMemory();
for (unsigned i = 0; i < arraysz(self->color_table); i++) {
static char buf[32] = {0};
snprintf(buf, sizeof(buf) - 1, "color%u", i);
PyObject *val = PyLong_FromUnsignedLong(self->color_table[i]);
if (!val) { return PyErr_NoMemory(); }
if (!val) { Py_CLEAR(ans); return PyErr_NoMemory(); }
int ret = PyDict_SetItemString(ans, buf, val);
Py_CLEAR(val);
if (ret != 0) { return NULL; }
if (ret != 0) { Py_CLEAR(ans); return NULL; }
}
#define D(attr, name) { \
if (self->overridden.attr.type != COLOR_NOT_SET) { \
@@ -328,33 +317,18 @@ as_dict(ColorProfile *self, PyObject *args UNUSED) {
color_type c = colorprofile_to_color(self, self->overridden.attr, self->configured.attr).rgb; \
val = PyLong_FromUnsignedLong(c); \
} \
if (!val) { return NULL; } \
if (!val) { Py_CLEAR(ans); return NULL; } \
ret = PyDict_SetItemString(ans, #name, val); \
Py_CLEAR(val); \
if (ret != 0) { return NULL; } \
if (ret != 0) { Py_CLEAR(ans); return NULL; } \
}}
D(default_fg, foreground); D(default_bg, background);
D(cursor_color, cursor); D(cursor_text_color, cursor_text); D(highlight_fg, selection_foreground);
D(highlight_bg, selection_background); D(visual_bell_color, visual_bell_color);
RAII_PyObject(transparent_background_colors, PyList_New(0));
if (!transparent_background_colors) return NULL;
for (size_t i = 0; i < arraysz(self->overriden_transparent_colors); i++) {
TransparentDynamicColor *c = NULL;
if (self->overriden_transparent_colors[i].is_set) c = self->overriden_transparent_colors + i;
else if (self->configured_transparent_colors[i].is_set) c = self->configured_transparent_colors + i;
if (c) {
RAII_PyObject(t, Py_BuildValue("Nf", alloc_color((c->color >> 16) & 0xff, (c->color >> 8) & 0xff, c->color & 0xff, 0), c->opacity));
if (!t) return NULL;
if (PyList_Append(transparent_background_colors, t) != 0) return NULL;
}
}
if (PyList_GET_SIZE(transparent_background_colors)) {
RAII_PyObject(t, PyList_AsTuple(transparent_background_colors));
if (!t) return NULL;
if (PyDict_SetItemString(ans, "transparent_background_colors", t) != 0) return NULL;
}
#undef D
return Py_NewRef(ans);
// TODO: Add transparent_colors
return ans;
}
static PyObject*
@@ -504,6 +478,7 @@ default_color_table(PyObject *self UNUSED, PyObject *args UNUSED) {
// Boilerplate {{{
static Color* alloc_color(unsigned char r, unsigned char g, unsigned char b, unsigned a);
#define CGETSET(name, nullable) \
static PyObject* name##_get(ColorProfile *self, void UNUSED *closure) { \
DynamicColor ans = colorprofile_to_color(self, self->overridden.name, self->configured.name); \

View File

@@ -23,7 +23,7 @@ class Version(NamedTuple):
appname: str = 'kitty'
kitty_face = '🐱'
version: Version = Version(0, 36, 4)
version: Version = Version(0, 36, 2)
str_version: str = '.'.join(map(str, version))
_plat = sys.platform.lower()
is_macos: bool = 'darwin' in _plat

View File

@@ -744,7 +744,6 @@ ensure_render_space(size_t width, size_t height, size_t num_glyphs) {
}
if (buffers.sz < num_glyphs) {
buffers.sz = MAX(128, num_glyphs * 2);
free(buffers.boxes); free(buffers.glyphs); free(buffers.positions);
buffers.boxes = calloc(sizeof(buffers.boxes[0]), buffers.sz);
buffers.glyphs = calloc(sizeof(buffers.glyphs[0]), buffers.sz);
buffers.positions = calloc(sizeof(buffers.positions[0]), buffers.sz);
@@ -813,13 +812,13 @@ render_sample_text(CTFace *self, PyObject *args) {
if (!PyArg_ParseTuple(args, "Ukk|k", &ptext, &canvas_width, &canvas_height, &fg)) return NULL;
unsigned int cell_width, cell_height, baseline, underline_position, underline_thickness, strikethrough_position, strikethrough_thickness;
cell_metrics((PyObject*)self, &cell_width, &cell_height, &baseline, &underline_position, &underline_thickness, &strikethrough_position, &strikethrough_thickness);
if (!cell_width || !cell_height) return Py_BuildValue("yII", "", cell_width, cell_height);
size_t num_chars = PyUnicode_GET_LENGTH(ptext);
int num_chars_per_line = canvas_width / cell_width, num_of_lines = (int)ceil((float)num_chars / (float)num_chars_per_line);
canvas_height = MIN(canvas_height, num_of_lines * cell_height);
RAII_PyObject(pbuf, PyBytes_FromStringAndSize(NULL, sizeof(pixel) * canvas_width * canvas_height));
if (!pbuf) return NULL;
memset(PyBytes_AS_STRING(pbuf), 0, PyBytes_GET_SIZE(pbuf));
if (!cell_width || !cell_height) return Py_BuildValue("OII", pbuf, cell_width, cell_height);
size_t num_chars = PyUnicode_GET_LENGTH(ptext);
int num_chars_per_line = canvas_width / cell_width, num_of_lines = (int)ceil((float)num_chars / (float)num_chars_per_line);
canvas_height = MIN(canvas_height, num_of_lines * cell_height);
__attribute__((cleanup(destroy_hb_buffer))) hb_buffer_t *hb_buffer = hb_buffer_create();
if (!hb_buffer_pre_allocate(hb_buffer, 4*num_chars)) { PyErr_NoMemory(); return NULL; }
@@ -858,10 +857,9 @@ render_sample_text(CTFace *self, PyObject *args) {
render_glyphs(font, canvas_width, canvas_height, baseline, num_glyphs);
uint8_t r = (fg >> 16) & 0xff, g = (fg >> 8) & 0xff, b = fg & 0xff;
const uint8_t *last_pixel = (uint8_t*)PyBytes_AS_STRING(pbuf) + PyBytes_GET_SIZE(pbuf) - sizeof(pixel);
const uint8_t *s_limit = buffers.render_buf + canvas_width * canvas_height;
for (
uint8_t *p = (uint8_t*)PyBytes_AS_STRING(pbuf), *s = buffers.render_buf;
p <= last_pixel && s < s_limit;
p <= last_pixel;
p += sizeof(pixel), s++
) {
p[0] = r; p[1] = g; p[2] = b; p[3] = s[0];

View File

@@ -17,20 +17,6 @@
#include <sys/mman.h>
#include <structmember.h>
#ifdef LIBRESSL_VERSION_NUMBER
/* from: https://github.com/libressl/portable/blob/master/include/compat/string.h#L63 */
#define explicit_bzero libressl_explicit_bzero
void explicit_bzero(void *, size_t);
/* from: https://github.com/libressl/portable/blob/master/crypto/compat/freezero.c */
void
freezero(void *ptr, size_t sz) {
if (ptr == NULL) return;
explicit_bzero(ptr, sz);
free(ptr);
}
#define OPENSSL_clear_free freezero
#endif
#define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH
typedef enum HASH_ALGORITHM { SHA1_HASH, SHA224_HASH, SHA256_HASH, SHA384_HASH, SHA512_HASH } HASH_ALGORITHM;

View File

@@ -811,7 +811,7 @@ class ColorProfile:
def __init__(self, opts: Optional[Options] = None): ...
def as_dict(self) -> Dict[str, int | None | tuple[tuple[Color, float], ...]]:
def as_dict(self) -> Dict[str, Optional[int]]:
pass
def as_color(self, val: int) -> Optional[Color]:
@@ -833,8 +833,7 @@ class ColorProfile:
def patch_color_profiles(
spec: Dict[str, Optional[int]], transparent_background_colors: tuple[tuple[Color, float], ...],
profiles: Tuple[ColorProfile, ...], change_configured: bool
spec: Dict[str, Optional[int]], profiles: Tuple[ColorProfile, ...], change_configured: bool
) -> None:
pass

View File

@@ -478,9 +478,9 @@ class LaunchKwds(TypedDict):
def apply_colors(window: Window, spec: Sequence[str]) -> None:
from kitty.rc.set_colors import parse_colors
colors, transparent_background_colors = parse_colors(spec)
colors = parse_colors(spec)
profiles = window.screen.color_profile,
patch_color_profiles(colors, transparent_background_colors, profiles, True)
patch_color_profiles(colors, profiles, True)
def parse_var(defn: Iterable[str]) -> Iterator[tuple[str, str]]:

View File

@@ -423,14 +423,10 @@ class Pair:
class SplitsLayoutOpts(LayoutOpts):
default_axis_is_horizontal: Optional[bool] = True
default_axis_is_horizontal: bool = True
def __init__(self, data: Dict[str, str]):
q = data.get('split_axis', 'horizontal')
if q == 'auto':
self.default_axis_is_horizontal = None
else:
self.default_axis_is_horizontal = q == 'horizontal'
self.default_axis_is_horizontal = data.get('split_axis', 'horizontal') == 'horizontal'
def serialized(self) -> Dict[str, Any]:
return {'default_axis_is_horizontal': self.default_axis_is_horizontal}
@@ -443,17 +439,14 @@ class Splits(Layout):
no_minimal_window_borders = True
@property
def default_axis_is_horizontal(self) -> Optional[bool]:
def default_axis_is_horizontal(self) -> bool:
return self.layout_opts.default_axis_is_horizontal
@property
def pairs_root(self) -> Pair:
root: Optional[Pair] = getattr(self, '_pairs_root', None)
if root is None:
horizontal = self.default_axis_is_horizontal
if horizontal is None:
horizontal = True
self._pairs_root = root = Pair(horizontal=horizontal)
self._pairs_root = root = Pair(horizontal=self.default_axis_is_horizontal)
return root
@pairs_root.setter
@@ -515,7 +508,7 @@ class Splits(Layout):
group_id = ag.id
pair = self.pairs_root.pair_for_window(group_id)
if pair is not None:
if location == 'split' or horizontal is None:
if location == 'split':
wwidth = aw.geometry.right - aw.geometry.left
wheight = aw.geometry.bottom - aw.geometry.top
horizontal = wwidth >= wheight

View File

@@ -398,7 +398,7 @@ class RemoteCommand:
window = window or boss.active_window
windows = [window] if window else []
if payload_get(window_match_name):
windows = list(boss.match_windows(payload_get(window_match_name), window))
windows = list(boss.match_windows(payload_get(window_match_name)))
if not windows:
raise MatchError(payload_get(window_match_name))
if payload_get(tab_match_name):

View File

@@ -49,7 +49,7 @@ configured colors.
for k, v in windows[0].current_colors.items():
if v is None:
ans.pop(k, None)
elif isinstance(v, int):
else:
ans[k] = color_from_int(v)
tab = windows[0].tabref()
tm = None if tab is None else tab.tab_manager_ref()

View File

@@ -194,7 +194,7 @@ on bracketed paste mode.
def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
sid = payload_get('session_id', '')
windows = self.windows_for_payload(boss, window, payload_get, window_match_name='match')
windows = self.windows_for_payload(boss, None, payload_get, window_match_name='match')
pdata: str = payload_get('data')
encoding, _, q = pdata.partition(':')
session = ''

View File

@@ -27,19 +27,16 @@ if TYPE_CHECKING:
from kitty.cli_stub import SetColorsRCOptions as CLIOptions
def parse_colors(args: Iterable[str]) -> tuple[Dict[str, Optional[int]], tuple[tuple[Color, float], ...]]:
def parse_colors(args: Iterable[str]) -> Dict[str, Optional[int]]:
from kitty.options.types import nullable_colors
colors: Dict[str, Optional[Color]] = {}
nullable_color_map: Dict[str, Optional[int]] = {}
transparent_background_colors = ()
for spec in args:
if '=' in spec:
conf = parse_config((spec.replace('=', ' '),))
colors.update(parse_config((spec.replace('=', ' '),)))
else:
with open(os.path.expanduser(spec), encoding='utf-8', errors='replace') as f:
conf = parse_config(f)
transparent_background_colors = conf.pop('transparent_background_colors', ())
colors.update(conf)
colors.update(parse_config(f))
for k in nullable_colors:
q = colors.pop(k, False)
if q is not False:
@@ -47,13 +44,13 @@ def parse_colors(args: Iterable[str]) -> tuple[Dict[str, Optional[int]], tuple[t
nullable_color_map[k] = val
ans: Dict[str, Optional[int]] = {k: int(v) for k, v in colors.items() if isinstance(v, Color)}
ans.update(nullable_color_map)
return ans, transparent_background_colors
return ans
class SetColors(RemoteCommand):
protocol_spec = __doc__ = '''
colors+/dict.colors: An object mapping names to colors as 24-bit RGB integers or null for nullable colors. Or a string for transparent_background_colors.
colors+/dict.colors: An object mapping names to colors as 24-bit RGB integers or null for nullable colors
match_window/str: Window to change colors in
match_tab/str: Tab to change colors in
all/bool: Boolean indicating change colors everywhere or not
@@ -91,18 +88,14 @@ this option, any color arguments are ignored and :option:`kitten @ set-colors --
completion=RemoteCommand.CompletionSpec.from_string('type:file group:"CONF files", ext:conf'))
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
final_colors: Dict[str, int | None | str] = {}
transparent_background_colors: tuple[tuple[Color, float], ...] = ()
final_colors: Dict[str, Optional[int]] = {}
if not opts.reset:
try:
fc, transparent_background_colors = parse_colors(args)
final_colors = parse_colors(args)
except FileNotFoundError as err:
raise ParsingOfArgsFailed(f'The colors configuration file {emph(err.filename)} was not found.') from err
except Exception as err:
raise ParsingOfArgsFailed(str(err)) from err
final_colors.update(fc)
if transparent_background_colors:
final_colors['transparent_background_colors'] = ' '.join(f'{c.as_sharp}@{f}' for c, f in transparent_background_colors)
ans = {
'match_window': opts.match, 'match_tab': opts.match_tab,
'all': opts.all or opts.reset, 'configured': opts.configured or opts.reset,
@@ -112,18 +105,12 @@ this option, any color arguments are ignored and :option:`kitten @ set-colors --
def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
windows = self.windows_for_payload(boss, window, payload_get)
colors: Dict[str, int | None] = payload_get('colors')
tbc = colors.get('transparent_background_colors')
colors: Dict[str, Optional[int]] = payload_get('colors')
if payload_get('reset'):
colors = {k: None if v is None else int(v) for k, v in boss.color_settings_at_startup.items()}
profiles = tuple(w.screen.color_profile for w in windows if w)
if tbc:
from kitty.options.utils import transparent_background_colors
parsed_tbc = transparent_background_colors(str(tbc))
else:
parsed_tbc = ()
patch_color_profiles(colors, parsed_tbc, profiles, payload_get('configured'))
boss.patch_colors(colors, parsed_tbc, payload_get('configured'))
patch_color_profiles(colors, profiles, payload_get('configured'))
boss.patch_colors(colors, payload_get('configured'))
default_bg_changed = 'background' in colors
for w in windows:
if w:

View File

@@ -1087,15 +1087,13 @@ create_border_vao(void) {
void
draw_borders(ssize_t vao_idx, unsigned int num_border_rects, BorderRect *rect_buf, bool rect_data_is_dirty, uint32_t viewport_width, uint32_t viewport_height, color_type active_window_bg, unsigned int num_visible_windows, bool all_windows_have_same_bg, OSWindow *w) {
float background_opacity = w->is_semi_transparent ? w->background_opacity: 1.0f;
float tint_opacity = background_opacity;
float tint_premult = background_opacity;
float tint_opacity = w->is_semi_transparent ? w->background_opacity: 1.0f;
float tint_premult = tint_opacity;
if (has_bgimage(w)) {
glEnable(GL_BLEND);
BLEND_ONTO_OPAQUE;
draw_background_image(w);
BLEND_ONTO_OPAQUE;
background_opacity = 1.0f;
tint_opacity = OPT(background_tint) * OPT(background_tint_gaps);
tint_premult = w->is_semi_transparent ? OPT(background_tint) : 1.0f;
}
@@ -1116,7 +1114,6 @@ draw_borders(ssize_t vao_idx, unsigned int num_border_rects, BorderRect *rect_bu
w->tab_bar_edge_color.left, w->tab_bar_edge_color.right
};
glUniform1uiv(border_program_layout.uniforms.colors, arraysz(colors), colors);
glUniform1f(border_program_layout.uniforms.background_opacity, background_opacity);
glUniform1f(border_program_layout.uniforms.tint_opacity, tint_opacity);
glUniform1f(border_program_layout.uniforms.tint_premult, tint_premult);
glUniform2ui(border_program_layout.uniforms.viewport, viewport_width, viewport_height);

View File

@@ -805,7 +805,7 @@ class Window:
return tab.overlay_parent(self)
@property
def current_colors(self) -> dict[str, Union[int, None, tuple[tuple[Color, float], ...]]]:
def current_colors(self) -> dict[str, Optional[int]]:
return self.screen.color_profile.as_dict()
@property

View File

@@ -35,8 +35,6 @@ func set_color_in_color_map(key, val string, ans map[string]any, check_nullable,
return fmt.Errorf("The color %s cannot be set to none", key)
}
ans[key] = nil
} else if key == "transparent_background_colors" {
ans[key] = val
} else {
col, err := style.ParseColor(val)
if err != nil {