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_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 ]
out vec2 texcoord;
@ -27,16 +28,16 @@ const vec2 tex_map[] = vec2[4](
);
float scale_factor(float window, float image) {
return window / image;
float scaling_factor(int i) {
return adjust_scale * (sizes[i] / sizes[i + 2]) + (1 - adjust_scale);
}
float tiling_factor(int i) {
return tiled * scale_factor(sizes[i], sizes[i + 2]) + (1 - tiled);
float position_divisor(int i) {
return (sizes[i] - sizes[i + 2]) * transform[i] / sizes[i + 2];
}
void main() {
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);
}

View File

@ -1981,11 +1981,8 @@ class Boss:
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:
if layout:
set_background_image(path, os_windows, configured, layout)
else:
set_background_image(path, os_windows, configured)
def set_background_image(self, path: Optional[str], os_windows: Tuple[int, ...], configured: bool, layout: Optional[str], anchor: Optional[str]) -> None:
set_background_image(path, os_windows, configured, layout, anchor)
for os_window_id in os_windows:
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 MouseShapes { BEAM, HAND, ARROW } MouseShape;
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 BLANK_CHAR 0

View File

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

View File

@ -1106,8 +1106,13 @@ opt('background_image', 'none',
)
opt('background_image_layout', 'tiled',
choices=('mirror-tiled', 'scaled', 'tiled'), ctype='bglayout',
long_text='Whether to tile or scale the background image.'
choices=('mirror-tiled', 'scaled', 'tiled', 'clamped'), ctype='bglayout',
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',

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:
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:
val = val.lower()
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")
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:
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);
}
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
convert_from_python_background_image_linear(PyObject *val, Options *opts) {
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;
convert_from_opts_background_image_layout(py_opts, opts);
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);
if (PyErr_Occurred()) return false;
convert_from_opts_dynamic_background_opacity(py_opts, opts);

View File

@ -72,11 +72,29 @@ bglayout(PyObject *layout_name) {
case 't': return TILING;
case 'm': return MIRRORED;
case 's': return SCALED;
case 'c': return CLAMPED;
default: break;
}
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) { \
free(opts->name); opts->name = NULL; \
if (src == Py_None || !PyUnicode_Check(src)) return; \

View File

@ -14,7 +14,8 @@ from kitty.types import FloatEdges, SingleKey
import kitty.types
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_linux_display_server = typing.Literal['auto', 'wayland', 'x11']
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_switch_strategy = typing.Literal['last', 'left', 'previous', 'right']
else:
choices_for_background_image_anchor = str
choices_for_background_image_layout = str
choices_for_default_pointer_shape = str
choices_for_linux_display_server = str
@ -53,6 +55,7 @@ option_names = ( # {{{
'allow_remote_control',
'background',
'background_image',
'background_image_anchor',
'background_image_layout',
'background_image_linear',
'background_opacity',
@ -453,6 +456,7 @@ class Options:
allow_remote_control: str = 'n'
background: Color = Color(0, 0, 0)
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_linear: bool = False
background_opacity: float = 1.0

View File

@ -24,6 +24,7 @@ class SetBackgroundImage(RemoteCommand):
img_id+: Unique uuid (as string) used for chunking
match: Window to change opacity in
layout: The image layout
anchor: The image anchor
all: Boolean indicating operate on all windows
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
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.
--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
type=bool-set
default=false
@ -72,6 +79,7 @@ failed, the command will exit with a success code.
'match': opts.match,
'configured': opts.configured,
'layout': opts.layout,
'anchor': opts.anchor,
'all': opts.all,
'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)
os_windows = tuple({w.os_window_id for w in windows})
layout = payload_get('layout')
anchor = payload_get('anchor')
if data == '-':
path = None
else:
@ -118,7 +127,7 @@ failed, the command will exit with a success code.
f.flush()
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:
err.hide_traceback = True # type: ignore
raise

View File

@ -166,7 +166,7 @@ typedef struct {
static CellProgramLayout cell_program_layouts[NUM_PROGRAMS];
static ssize_t blit_vertex_array;
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;
static BGImageProgramLayout bgimage_program_layout = {0};
typedef struct {
@ -198,7 +198,8 @@ init_cell_program(void) {
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.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");
tint_program_layout.tint_color_location = get_uniform_location(TINT_PROGRAM, "tint_color");
tint_program_layout.edges_location = get_uniform_location(TINT_PROGRAM, "edges");
@ -407,14 +408,20 @@ draw_bg(OSWindow *w) {
bind_program(BGIMAGE_PROGRAM);
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;
if (!bgimage_constants_set) {
glUniform1i(bgimage_program_layout.image_location, BGIMAGE_UNIT);
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.tiled_location, tiled);
glUniform1f(bgimage_program_layout.adjust_scale_location, (GLfloat)adjust_scale);
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,
(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);

View File

@ -137,6 +137,7 @@ send_bgimage_to_gpu(BackgroundImageLayout layout, BackgroundImage *bgimage) {
RepeatStrategy r;
switch (layout) {
case SCALED:
case CLAMPED:
r = REPEAT_CLAMP; break;
case MIRRORED:
r = REPEAT_MIRROR; break;
@ -961,11 +962,13 @@ static PyObject*
pyset_background_image(PyObject *self UNUSED, PyObject *args) {
const char *path;
PyObject *layout_name = NULL;
PyObject *anchor_name = NULL;
PyObject *os_window_ids;
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;
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;
if (path) {
bgimage = calloc(1, sizeof(BackgroundImage));
@ -983,6 +986,7 @@ pyset_background_image(PyObject *self UNUSED, PyObject *args) {
global_state.bgimage = bgimage;
if (bgimage) bgimage->refcnt++;
OPT(background_image_layout) = layout;
OPT(background_image_anchor) = anchor;
}
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));

View File

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