Merge branch 'bgimage-options' of https://github.com/itepechi/kitty into bg

This commit is contained in:
Kovid Goyal 2021-10-30 15:04:41 +05:30
commit e703103fa8
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
13 changed files with 98 additions and 25 deletions

View File

@ -8,7 +8,8 @@
#define tex_right 1 #define tex_right 1
#define tex_bottom 1 #define tex_bottom 1
uniform float tiled; uniform float adjust_scale;
uniform vec2 transform; // [ pos_left_relative, pos_top_relative ]
uniform vec4 sizes; // [ window_width, window_height, image_width, image_height ] uniform vec4 sizes; // [ window_width, window_height, image_width, image_height ]
out vec2 texcoord; out vec2 texcoord;
@ -27,16 +28,16 @@ const vec2 tex_map[] = vec2[4](
); );
float scale_factor(float window, float image) { float scaling_factor(int i) {
return window / image; return adjust_scale * (sizes[i] / sizes[i + 2]) + (1 - adjust_scale);
} }
float tiling_factor(int i) { float position_divisor(int i) {
return tiled * scale_factor(sizes[i], sizes[i + 2]) + (1 - tiled); return (sizes[i] - sizes[i + 2]) * transform[i] / sizes[i + 2];
} }
void main() { void main() {
vec2 tex_coords = tex_map[gl_VertexID]; vec2 tex_coords = tex_map[gl_VertexID];
texcoord = vec2(tex_coords[0] * tiling_factor(0), tex_coords[1] * tiling_factor(1)); texcoord = vec2(tex_coords[0] * scaling_factor(0) - position_divisor(0), tex_coords[1] * scaling_factor(1) - position_divisor(1));
gl_Position = vec4(pos_map[gl_VertexID], 0, 1); gl_Position = vec4(pos_map[gl_VertexID], 0, 1);
} }

View File

@ -1981,11 +1981,8 @@ class Boss:
self.choose_entry('Choose an OS window to move the tab to', items, chosen) self.choose_entry('Choose an OS window to move the tab to', items, chosen)
def set_background_image(self, path: Optional[str], os_windows: Tuple[int, ...], configured: bool, layout: Optional[str]) -> None: def set_background_image(self, path: Optional[str], os_windows: Tuple[int, ...], configured: bool, layout: Optional[str], anchor: Optional[str]) -> None:
if layout: set_background_image(path, os_windows, configured, layout, anchor)
set_background_image(path, os_windows, configured, layout)
else:
set_background_image(path, os_windows, configured)
for os_window_id in os_windows: for os_window_id in os_windows:
self.default_bg_changed_for(os_window_id) self.default_bg_changed_for(os_window_id)

View File

@ -64,7 +64,10 @@ typedef enum MouseTrackingModes { NO_TRACKING, BUTTON_MODE, MOTION_MODE, ANY_MOD
typedef enum MouseTrackingProtocols { NORMAL_PROTOCOL, UTF8_PROTOCOL, SGR_PROTOCOL, URXVT_PROTOCOL, SGR_PIXEL_PROTOCOL} MouseTrackingProtocol; typedef enum MouseTrackingProtocols { NORMAL_PROTOCOL, UTF8_PROTOCOL, SGR_PROTOCOL, URXVT_PROTOCOL, SGR_PIXEL_PROTOCOL} MouseTrackingProtocol;
typedef enum MouseShapes { BEAM, HAND, ARROW } MouseShape; typedef enum MouseShapes { BEAM, HAND, ARROW } MouseShape;
typedef enum { NONE, MENUBAR, WINDOW, ALL } WindowTitleIn; typedef enum { NONE, MENUBAR, WINDOW, ALL } WindowTitleIn;
typedef enum { TILING, SCALED, MIRRORED } BackgroundImageLayout; typedef enum { TILING, SCALED, MIRRORED, CLAMPED } BackgroundImageLayout;
typedef struct {
float x, y;
} BackgroundImageAnchor;
#define MAX_CHILDREN 512 #define MAX_CHILDREN 512
#define BLANK_CHAR 0 #define BLANK_CHAR 0

View File

@ -598,7 +598,8 @@ def set_background_image(
path: Optional[str], path: Optional[str],
os_window_ids: Tuple[int, ...], os_window_ids: Tuple[int, ...],
configured: bool = True, configured: bool = True,
layout_name: Optional[str] = None layout_name: Optional[str] = None,
anchor_name: Optional[str] = None
) -> None: ) -> None:
pass pass

View File

@ -1106,8 +1106,13 @@ opt('background_image', 'none',
) )
opt('background_image_layout', 'tiled', opt('background_image_layout', 'tiled',
choices=('mirror-tiled', 'scaled', 'tiled'), ctype='bglayout', choices=('mirror-tiled', 'scaled', 'tiled', 'clamped'), ctype='bglayout',
long_text='Whether to tile or scale the background image.' long_text='Whether to tile, scale or clamp the background image.'
)
opt('background_image_anchor', 'top-left',
choices=('top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right'), ctype='bganchor',
long_text='Where to position the background image in the window.'
) )
opt('background_image_linear', 'no', opt('background_image_linear', 'no',

10
kitty/options/parse.py generated
View File

@ -57,13 +57,21 @@ class Parser:
def background_image(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: def background_image(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['background_image'] = config_or_absolute_path(val) ans['background_image'] = config_or_absolute_path(val)
def background_image_anchor(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
val = val.lower()
if val not in self.choices_for_background_image_anchor:
raise ValueError(f"The value {val} is not a valid choice for background_image_anchor")
ans["background_image_anchor"] = val
choices_for_background_image_anchor = frozenset(('top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right'))
def background_image_layout(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: def background_image_layout(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
val = val.lower() val = val.lower()
if val not in self.choices_for_background_image_layout: if val not in self.choices_for_background_image_layout:
raise ValueError(f"The value {val} is not a valid choice for background_image_layout") raise ValueError(f"The value {val} is not a valid choice for background_image_layout")
ans["background_image_layout"] = val ans["background_image_layout"] = val
choices_for_background_image_layout = frozenset(('mirror-tiled', 'scaled', 'tiled')) choices_for_background_image_layout = frozenset(('mirror-tiled', 'scaled', 'tiled', 'clamped'))
def background_image_linear(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: def background_image_linear(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['background_image_linear'] = to_bool(val) ans['background_image_linear'] = to_bool(val)

View File

@ -694,6 +694,19 @@ convert_from_opts_background_image_layout(PyObject *py_opts, Options *opts) {
Py_DECREF(ret); Py_DECREF(ret);
} }
static void
convert_from_python_background_image_anchor(PyObject *val, Options *opts) {
opts->background_image_anchor = bganchor(val);
}
static void
convert_from_opts_background_image_anchor(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "background_image_anchor");
if (ret == NULL) return;
convert_from_python_background_image_anchor(ret, opts);
Py_DECREF(ret);
}
static void static void
convert_from_python_background_image_linear(PyObject *val, Options *opts) { convert_from_python_background_image_linear(PyObject *val, Options *opts) {
opts->background_image_linear = PyObject_IsTrue(val); opts->background_image_linear = PyObject_IsTrue(val);
@ -1049,6 +1062,8 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
if (PyErr_Occurred()) return false; if (PyErr_Occurred()) return false;
convert_from_opts_background_image_layout(py_opts, opts); convert_from_opts_background_image_layout(py_opts, opts);
if (PyErr_Occurred()) return false; if (PyErr_Occurred()) return false;
convert_from_opts_background_image_anchor(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_background_image_linear(py_opts, opts); convert_from_opts_background_image_linear(py_opts, opts);
if (PyErr_Occurred()) return false; if (PyErr_Occurred()) return false;
convert_from_opts_dynamic_background_opacity(py_opts, opts); convert_from_opts_dynamic_background_opacity(py_opts, opts);

View File

@ -72,11 +72,29 @@ bglayout(PyObject *layout_name) {
case 't': return TILING; case 't': return TILING;
case 'm': return MIRRORED; case 'm': return MIRRORED;
case 's': return SCALED; case 's': return SCALED;
case 'c': return CLAMPED;
default: break; default: break;
} }
return TILING; return TILING;
} }
static BackgroundImageAnchor
bganchor(PyObject *anchor_name) {
const char *name = PyUnicode_AsUTF8(anchor_name);
BackgroundImageAnchor anchor = { .x = 0.5f, .y = 0.5f };
if (strstr(name, "top") != NULL) {
anchor.y = 0.0f;
} else if (strstr(name, "bottom") != NULL) {
anchor.y = 1.0f;
}
if (strstr(name, "left") != NULL) {
anchor.x = 0.0f;
} else if (strstr(name, "right") != NULL) {
anchor.x = 1.0f;
}
return anchor;
}
#define STR_SETTER(name) { \ #define STR_SETTER(name) { \
free(opts->name); opts->name = NULL; \ free(opts->name); opts->name = NULL; \
if (src == Py_None || !PyUnicode_Check(src)) return; \ if (src == Py_None || !PyUnicode_Check(src)) return; \

View File

@ -14,7 +14,8 @@ from kitty.types import FloatEdges, SingleKey
import kitty.types import kitty.types
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
choices_for_background_image_layout = typing.Literal['mirror-tiled', 'scaled', 'tiled'] choices_for_background_image_anchor = typing.Literal['top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right']
choices_for_background_image_layout = typing.Literal['mirror-tiled', 'scaled', 'tiled', 'clamped']
choices_for_default_pointer_shape = typing.Literal['arrow', 'beam', 'hand'] choices_for_default_pointer_shape = typing.Literal['arrow', 'beam', 'hand']
choices_for_linux_display_server = typing.Literal['auto', 'wayland', 'x11'] choices_for_linux_display_server = typing.Literal['auto', 'wayland', 'x11']
choices_for_macos_show_window_title_in = typing.Literal['all', 'menubar', 'none', 'window'] choices_for_macos_show_window_title_in = typing.Literal['all', 'menubar', 'none', 'window']
@ -27,6 +28,7 @@ if typing.TYPE_CHECKING:
choices_for_tab_powerline_style = typing.Literal['angled', 'round', 'slanted'] choices_for_tab_powerline_style = typing.Literal['angled', 'round', 'slanted']
choices_for_tab_switch_strategy = typing.Literal['last', 'left', 'previous', 'right'] choices_for_tab_switch_strategy = typing.Literal['last', 'left', 'previous', 'right']
else: else:
choices_for_background_image_anchor = str
choices_for_background_image_layout = str choices_for_background_image_layout = str
choices_for_default_pointer_shape = str choices_for_default_pointer_shape = str
choices_for_linux_display_server = str choices_for_linux_display_server = str
@ -53,6 +55,7 @@ option_names = ( # {{{
'allow_remote_control', 'allow_remote_control',
'background', 'background',
'background_image', 'background_image',
'background_image_anchor',
'background_image_layout', 'background_image_layout',
'background_image_linear', 'background_image_linear',
'background_opacity', 'background_opacity',
@ -453,6 +456,7 @@ class Options:
allow_remote_control: str = 'n' allow_remote_control: str = 'n'
background: Color = Color(0, 0, 0) background: Color = Color(0, 0, 0)
background_image: typing.Optional[str] = None background_image: typing.Optional[str] = None
background_image_anchor: choices_for_background_image_anchor = 'top-left'
background_image_layout: choices_for_background_image_layout = 'tiled' background_image_layout: choices_for_background_image_layout = 'tiled'
background_image_linear: bool = False background_image_linear: bool = False
background_opacity: float = 1.0 background_opacity: float = 1.0

View File

@ -24,6 +24,7 @@ class SetBackgroundImage(RemoteCommand):
img_id+: Unique uuid (as string) used for chunking img_id+: Unique uuid (as string) used for chunking
match: Window to change opacity in match: Window to change opacity in
layout: The image layout layout: The image layout
anchor: The image anchor
all: Boolean indicating operate on all windows all: Boolean indicating operate on all windows
configured: Boolean indicating if the configured value should be changed configured: Boolean indicating if the configured value should be changed
''' '''
@ -48,10 +49,16 @@ Change the configured background image which is used for new OS windows.
--layout --layout
type=choices type=choices
choices=tiled,scaled,mirror-tiled,configured choices=tiled,scaled,mirror-tiled,clamped,configured
How the image should be displayed. The value of configured will use the configured value. How the image should be displayed. The value of configured will use the configured value.
--anchor
type=choices
choices=top-left,top,top-right,left,center,right,bottom-left,bottom,bottom-right,configured
Where the image should be positioned. The value of configured will use the configured value.
--no-response --no-response
type=bool-set type=bool-set
default=false default=false
@ -72,6 +79,7 @@ failed, the command will exit with a success code.
'match': opts.match, 'match': opts.match,
'configured': opts.configured, 'configured': opts.configured,
'layout': opts.layout, 'layout': opts.layout,
'anchor': opts.anchor,
'all': opts.all, 'all': opts.all,
'img_id': str(uuid4()) 'img_id': str(uuid4())
} }
@ -108,6 +116,7 @@ failed, the command will exit with a success code.
windows = self.windows_for_payload(boss, window, payload_get) windows = self.windows_for_payload(boss, window, payload_get)
os_windows = tuple({w.os_window_id for w in windows}) os_windows = tuple({w.os_window_id for w in windows})
layout = payload_get('layout') layout = payload_get('layout')
anchor = payload_get('anchor')
if data == '-': if data == '-':
path = None path = None
else: else:
@ -118,7 +127,7 @@ failed, the command will exit with a success code.
f.flush() f.flush()
try: try:
boss.set_background_image(path, os_windows, payload_get('configured'), layout) boss.set_background_image(path, os_windows, payload_get('configured'), layout, anchor)
except ValueError as err: except ValueError as err:
err.hide_traceback = True # type: ignore err.hide_traceback = True # type: ignore
raise raise

View File

@ -166,7 +166,7 @@ typedef struct {
static CellProgramLayout cell_program_layouts[NUM_PROGRAMS]; static CellProgramLayout cell_program_layouts[NUM_PROGRAMS];
static ssize_t blit_vertex_array; static ssize_t blit_vertex_array;
typedef struct { typedef struct {
GLint image_location, tiled_location, sizes_location, opacity_location, premult_location; GLint image_location, adjust_scale_location, transform_location, sizes_location, opacity_location, premult_location;
} BGImageProgramLayout; } BGImageProgramLayout;
static BGImageProgramLayout bgimage_program_layout = {0}; static BGImageProgramLayout bgimage_program_layout = {0};
typedef struct { typedef struct {
@ -198,7 +198,8 @@ init_cell_program(void) {
bgimage_program_layout.image_location = get_uniform_location(BGIMAGE_PROGRAM, "image"); bgimage_program_layout.image_location = get_uniform_location(BGIMAGE_PROGRAM, "image");
bgimage_program_layout.opacity_location = get_uniform_location(BGIMAGE_PROGRAM, "opacity"); bgimage_program_layout.opacity_location = get_uniform_location(BGIMAGE_PROGRAM, "opacity");
bgimage_program_layout.sizes_location = get_uniform_location(BGIMAGE_PROGRAM, "sizes"); bgimage_program_layout.sizes_location = get_uniform_location(BGIMAGE_PROGRAM, "sizes");
bgimage_program_layout.tiled_location = get_uniform_location(BGIMAGE_PROGRAM, "tiled"); bgimage_program_layout.adjust_scale_location = get_uniform_location(BGIMAGE_PROGRAM, "adjust_scale");
bgimage_program_layout.transform_location = get_uniform_location(BGIMAGE_PROGRAM, "transform");
bgimage_program_layout.premult_location = get_uniform_location(BGIMAGE_PROGRAM, "premult"); bgimage_program_layout.premult_location = get_uniform_location(BGIMAGE_PROGRAM, "premult");
tint_program_layout.tint_color_location = get_uniform_location(TINT_PROGRAM, "tint_color"); tint_program_layout.tint_color_location = get_uniform_location(TINT_PROGRAM, "tint_color");
tint_program_layout.edges_location = get_uniform_location(TINT_PROGRAM, "edges"); tint_program_layout.edges_location = get_uniform_location(TINT_PROGRAM, "edges");
@ -407,14 +408,20 @@ draw_bg(OSWindow *w) {
bind_program(BGIMAGE_PROGRAM); bind_program(BGIMAGE_PROGRAM);
bind_vertex_array(blit_vertex_array); bind_vertex_array(blit_vertex_array);
const bool adjust_scale = OPT(background_image_layout) == TILING || OPT(background_image_layout) == MIRRORED || OPT(background_image_layout) == CLAMPED;
static bool bgimage_constants_set = false; static bool bgimage_constants_set = false;
if (!bgimage_constants_set) { if (!bgimage_constants_set) {
glUniform1i(bgimage_program_layout.image_location, BGIMAGE_UNIT); glUniform1i(bgimage_program_layout.image_location, BGIMAGE_UNIT);
glUniform1f(bgimage_program_layout.opacity_location, OPT(background_opacity)); glUniform1f(bgimage_program_layout.opacity_location, OPT(background_opacity));
GLfloat tiled = (OPT(background_image_layout) == TILING || OPT(background_image_layout) == MIRRORED) ? 1 : 0; glUniform1f(bgimage_program_layout.adjust_scale_location, (GLfloat)adjust_scale);
glUniform1f(bgimage_program_layout.tiled_location, tiled);
bgimage_constants_set = true; bgimage_constants_set = true;
} }
float pos_left_relative = 0.0f, pos_top_relative = 0.0f;
if (adjust_scale) {
pos_left_relative = OPT(background_image_anchor).x;
pos_top_relative = OPT(background_image_anchor).y;
}
glUniform2f(bgimage_program_layout.transform_location, (GLfloat)pos_left_relative, (GLfloat)pos_top_relative);
glUniform4f(bgimage_program_layout.sizes_location, glUniform4f(bgimage_program_layout.sizes_location,
(GLfloat)w->window_width, (GLfloat)w->window_height, (GLfloat)w->bgimage->width, (GLfloat)w->bgimage->height); (GLfloat)w->window_width, (GLfloat)w->window_height, (GLfloat)w->bgimage->width, (GLfloat)w->bgimage->height);
glUniform1f(bgimage_program_layout.premult_location, w->is_semi_transparent ? 1.f : 0.f); glUniform1f(bgimage_program_layout.premult_location, w->is_semi_transparent ? 1.f : 0.f);

View File

@ -137,6 +137,7 @@ send_bgimage_to_gpu(BackgroundImageLayout layout, BackgroundImage *bgimage) {
RepeatStrategy r; RepeatStrategy r;
switch (layout) { switch (layout) {
case SCALED: case SCALED:
case CLAMPED:
r = REPEAT_CLAMP; break; r = REPEAT_CLAMP; break;
case MIRRORED: case MIRRORED:
r = REPEAT_MIRROR; break; r = REPEAT_MIRROR; break;
@ -961,11 +962,13 @@ static PyObject*
pyset_background_image(PyObject *self UNUSED, PyObject *args) { pyset_background_image(PyObject *self UNUSED, PyObject *args) {
const char *path; const char *path;
PyObject *layout_name = NULL; PyObject *layout_name = NULL;
PyObject *anchor_name = NULL;
PyObject *os_window_ids; PyObject *os_window_ids;
int configured = 0; int configured = 0;
PA("zO!|pU", &path, &PyTuple_Type, &os_window_ids, &configured, &layout_name); PA("zO!|pOO", &path, &PyTuple_Type, &os_window_ids, &configured, &layout_name, &anchor_name);
size_t size; size_t size;
BackgroundImageLayout layout = layout_name ? bglayout(layout_name) : OPT(background_image_layout); BackgroundImageLayout layout = PyUnicode_Check(layout_name) ? bglayout(layout_name) : OPT(background_image_layout);
BackgroundImageAnchor anchor = PyUnicode_Check(anchor_name) ? bganchor(anchor_name) : OPT(background_image_anchor);
BackgroundImage *bgimage = NULL; BackgroundImage *bgimage = NULL;
if (path) { if (path) {
bgimage = calloc(1, sizeof(BackgroundImage)); bgimage = calloc(1, sizeof(BackgroundImage));
@ -983,6 +986,7 @@ pyset_background_image(PyObject *self UNUSED, PyObject *args) {
global_state.bgimage = bgimage; global_state.bgimage = bgimage;
if (bgimage) bgimage->refcnt++; if (bgimage) bgimage->refcnt++;
OPT(background_image_layout) = layout; OPT(background_image_layout) = layout;
OPT(background_image_anchor) = anchor;
} }
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(os_window_ids); i++) { for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(os_window_ids); i++) {
id_type os_window_id = PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(os_window_ids, i)); id_type os_window_id = PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(os_window_ids, i));

View File

@ -47,6 +47,7 @@ typedef struct {
char* background_image; char* background_image;
BackgroundImageLayout background_image_layout; BackgroundImageLayout background_image_layout;
BackgroundImageAnchor background_image_anchor;
bool background_image_linear; bool background_image_linear;
float background_tint; float background_tint;