diff --git a/kitty/bgimage_vertex.glsl b/kitty/bgimage_vertex.glsl index 7c7f07426..86b5b72a9 100644 --- a/kitty/bgimage_vertex.glsl +++ b/kitty/bgimage_vertex.glsl @@ -12,8 +12,7 @@ #define window i #define image i + 2 -uniform float adjust_scale; -uniform vec2 transform; // [ pos_left_relative, pos_top_relative ] +uniform float tiled; uniform vec4 sizes; // [ window_width, window_height, image_width, image_height ] out vec2 texcoord; @@ -31,20 +30,19 @@ const vec2 tex_map[] = vec2[4]( vec2(tex_right, tex_top) ); - -float scaling_factor(int i) { - return adjust_scale * (sizes[window] / sizes[image]) + (1 - adjust_scale); +float scale_factor(float window_size, float image_size) { + return window_size / image_size; } -float position_divisor(int i) { - return (sizes[window] - sizes[image]) * transform[i] / sizes[image]; +float tiling_factor(int i) { + return tiled * scale_factor(sizes[window], sizes[image]) + (1 - tiled); } void main() { vec2 tex_coords = tex_map[gl_VertexID]; texcoord = vec2( - tex_coords[x_axis] * scaling_factor(x_axis) - position_divisor(x_axis), - tex_coords[y_axis] * scaling_factor(y_axis) - position_divisor(y_axis) + tex_coords[x_axis] * tiling_factor(x_axis), + tex_coords[y_axis] * tiling_factor(y_axis) ); gl_Position = vec4(pos_map[gl_VertexID], 0, 1); } diff --git a/kitty/boss.py b/kitty/boss.py index 809a9a618..81fbd32a4 100755 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -2149,8 +2149,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], anchor: Optional[str]) -> None: - set_background_image(path, os_windows, configured, layout, anchor) + def set_background_image(self, path: Optional[str], os_windows: Tuple[int, ...], configured: bool, layout: Optional[str]) -> None: + set_background_image(path, os_windows, configured, layout) for os_window_id in os_windows: self.default_bg_changed_for(os_window_id) diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 5bcda0e06..d24b0787f 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -602,7 +602,6 @@ def set_background_image( os_window_ids: Tuple[int, ...], configured: bool = True, layout_name: Optional[str] = None, - anchor_name: Optional[str] = None ) -> None: pass diff --git a/kitty/options/definition.py b/kitty/options/definition.py index b9e5e65ca..37fe55bb1 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -863,6 +863,25 @@ are undefined. ''' ) +opt('window_logo_path', 'none', + option_type='config_or_absolute_path', ctype='!window_logo_path', + long_text=''' +Path to a logo image. Must be in PNG format. The logo is displayed in a corner +of every kitty window. The position is controlled by :opt:`window_logo_position`. +Individual windows can be configured to have different logos either using +the :doc:`launch` function or the :doc:`remote-control` facility. +''') + +opt('window_logo_position', 'bottom-right', + choices=('top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right'), ctype='bganchor', + long_text=''' +Where to position the window logo in the window. The value can be one of: +:code:`top-left`, :code:`top`, :code:`top-right`, :code:`left`, :code:`center`, +:code:`right`, :code:`bottom-left`, :code:`bottom`, :code:`bottom-right`. +''' + ) + + opt('resize_debounce_time', '0.1', option_type='positive_float', ctype='time', long_text=''' @@ -1150,15 +1169,6 @@ Whether to tile, scale or clamp the background image. The value can be one of ''' ) -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. The value can be one of: -:code:`top-left`, :code:`top`, :code:`top-right`, :code:`left`, :code:`center`, -:code:`right`, :code:`bottom-left`, :code:`bottom`, :code:`bottom-right`. -''' - ) - opt('background_image_linear', 'no', option_type='to_bool', ctype='bool', long_text='When background image is scaled, whether linear interpolation should be used.' diff --git a/kitty/options/parse.py b/kitty/options/parse.py index bdda3f069..ee67b0171 100644 --- a/kitty/options/parse.py +++ b/kitty/options/parse.py @@ -62,14 +62,6 @@ 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: @@ -1278,6 +1270,17 @@ class Parser: def window_border_width(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: ans['window_border_width'] = window_border_width(val) + def window_logo_path(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['window_logo_path'] = config_or_absolute_path(val) + + def window_logo_position(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + val = val.lower() + if val not in self.choices_for_window_logo_position: + raise ValueError(f"The value {val} is not a valid choice for window_logo_position") + ans["window_logo_position"] = val + + choices_for_window_logo_position = frozenset(('top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right')) + def window_margin_width(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: ans['window_margin_width'] = edge_width(val) diff --git a/kitty/options/to-c-generated.h b/kitty/options/to-c-generated.h index 348e1a257..c75c8ab3d 100644 --- a/kitty/options/to-c-generated.h +++ b/kitty/options/to-c-generated.h @@ -512,6 +512,32 @@ convert_from_opts_hide_window_decorations(PyObject *py_opts, Options *opts) { Py_DECREF(ret); } +static void +convert_from_python_window_logo_path(PyObject *val, Options *opts) { + window_logo_path(val, opts); +} + +static void +convert_from_opts_window_logo_path(PyObject *py_opts, Options *opts) { + PyObject *ret = PyObject_GetAttrString(py_opts, "window_logo_path"); + if (ret == NULL) return; + convert_from_python_window_logo_path(ret, opts); + Py_DECREF(ret); +} + +static void +convert_from_python_window_logo_position(PyObject *val, Options *opts) { + opts->window_logo_position = bganchor(val); +} + +static void +convert_from_opts_window_logo_position(PyObject *py_opts, Options *opts) { + PyObject *ret = PyObject_GetAttrString(py_opts, "window_logo_position"); + if (ret == NULL) return; + convert_from_python_window_logo_position(ret, opts); + Py_DECREF(ret); +} + static void convert_from_python_resize_debounce_time(PyObject *val, Options *opts) { opts->resize_debounce_time = parse_s_double_to_monotonic_t(val); @@ -694,19 +720,6 @@ 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); @@ -1034,6 +1047,10 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) { if (PyErr_Occurred()) return false; convert_from_opts_hide_window_decorations(py_opts, opts); if (PyErr_Occurred()) return false; + convert_from_opts_window_logo_path(py_opts, opts); + if (PyErr_Occurred()) return false; + convert_from_opts_window_logo_position(py_opts, opts); + if (PyErr_Occurred()) return false; convert_from_opts_resize_debounce_time(py_opts, opts); if (PyErr_Occurred()) return false; convert_from_opts_resize_draw_strategy(py_opts, opts); @@ -1062,8 +1079,6 @@ 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); diff --git a/kitty/options/to-c.h b/kitty/options/to-c.h index 9213b0f10..1208df6bc 100644 --- a/kitty/options/to-c.h +++ b/kitty/options/to-c.h @@ -110,6 +110,9 @@ background_image(PyObject *src, Options *opts) { STR_SETTER(background_image); } static void bell_path(PyObject *src, Options *opts) { STR_SETTER(bell_path); } +static void +window_logo_path(PyObject *src, Options *opts) { STR_SETTER(default_window_logo); } + #undef STR_SETTER static MouseShape diff --git a/kitty/options/types.py b/kitty/options/types.py index cea6c96e3..796a72b84 100644 --- a/kitty/options/types.py +++ b/kitty/options/types.py @@ -12,7 +12,6 @@ from kitty.types import FloatEdges, SingleKey import kitty.types if typing.TYPE_CHECKING: - 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'] @@ -25,8 +24,8 @@ if typing.TYPE_CHECKING: choices_for_tab_bar_style = typing.Literal['fade', 'hidden', 'powerline', 'separator', 'slant', 'custom'] choices_for_tab_powerline_style = typing.Literal['angled', 'round', 'slanted'] choices_for_tab_switch_strategy = typing.Literal['last', 'left', 'previous', 'right'] + choices_for_window_logo_position = typing.Literal['top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-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 @@ -39,6 +38,7 @@ else: choices_for_tab_bar_style = str choices_for_tab_powerline_style = str choices_for_tab_switch_strategy = str + choices_for_window_logo_position = str option_names = ( # {{{ 'action_alias', @@ -54,7 +54,6 @@ option_names = ( # {{{ 'allow_remote_control', 'background', 'background_image', - 'background_image_anchor', 'background_image_layout', 'background_image_linear', 'background_opacity', @@ -438,6 +437,8 @@ option_names = ( # {{{ 'wheel_scroll_multiplier', 'window_alert_on_bell', 'window_border_width', + 'window_logo_path', + 'window_logo_position', 'window_margin_width', 'window_padding_width', 'window_resize_step_cells', @@ -457,7 +458,6 @@ 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 @@ -578,6 +578,8 @@ class Options: wheel_scroll_multiplier: float = 5.0 window_alert_on_bell: bool = True window_border_width: typing.Tuple[float, str] = (0.5, 'pt') + window_logo_path: typing.Optional[str] = None + window_logo_position: choices_for_window_logo_position = 'bottom-right' window_margin_width: FloatEdges = FloatEdges(left=0, top=0, right=0, bottom=0) window_padding_width: FloatEdges = FloatEdges(left=0, top=0, right=0, bottom=0) window_resize_step_cells: int = 2 diff --git a/kitty/rc/set_background_image.py b/kitty/rc/set_background_image.py index dcbc349a8..7a7122ecf 100644 --- a/kitty/rc/set_background_image.py +++ b/kitty/rc/set_background_image.py @@ -24,7 +24,6 @@ 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 ''' @@ -53,12 +52,6 @@ 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 @@ -79,7 +72,6 @@ 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()) } @@ -116,7 +108,6 @@ 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: @@ -127,7 +118,7 @@ failed, the command will exit with a success code. f.flush() try: - boss.set_background_image(path, os_windows, payload_get('configured'), layout, anchor) + boss.set_background_image(path, os_windows, payload_get('configured'), layout) except ValueError as err: err.hide_traceback = True # type: ignore raise diff --git a/kitty/shaders.c b/kitty/shaders.c index 5dcae6dd3..b417eb5aa 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -173,7 +173,7 @@ typedef struct { static CellProgramLayout cell_program_layouts[NUM_PROGRAMS]; static ssize_t blit_vertex_array; typedef struct { - GLint image_location, adjust_scale_location, transform_location, sizes_location, opacity_location, premult_location; + GLint image_location, tiled_location, sizes_location, opacity_location, premult_location; } BGImageProgramLayout; static BGImageProgramLayout bgimage_program_layout = {0}; typedef struct { @@ -201,8 +201,7 @@ 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.adjust_scale_location = get_uniform_location(BGIMAGE_PROGRAM, "adjust_scale"); - bgimage_program_layout.transform_location = get_uniform_location(BGIMAGE_PROGRAM, "transform"); + bgimage_program_layout.tiled_location = get_uniform_location(BGIMAGE_PROGRAM, "tiled"); 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"); @@ -406,19 +405,19 @@ 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; - 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; - } glUniform1i(bgimage_program_layout.image_location, BGIMAGE_UNIT); glUniform1f(bgimage_program_layout.opacity_location, OPT(background_opacity)); - glUniform1f(bgimage_program_layout.adjust_scale_location, adjust_scale ? 1.f : 0.f); - 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); + GLfloat tiled = 0.f;; + switch (OPT(background_image_layout)) { + case TILING: case MIRRORED: case CLAMPED: + tiled = 1.f; break; + case SCALED: + tiled = 0.f; break; + } + glUniform1f(bgimage_program_layout.tiled_location, tiled); glActiveTexture(GL_TEXTURE0 + BGIMAGE_UNIT); glBindTexture(GL_TEXTURE_2D, w->bgimage->texture_id); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); diff --git a/kitty/state.c b/kitty/state.c index 8a1a22154..11574e2de 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -1012,13 +1012,11 @@ 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!|pOO", &path, &PyTuple_Type, &os_window_ids, &configured, &layout_name, &anchor_name); + PA("zO!|pO", &path, &PyTuple_Type, &os_window_ids, &configured, &layout_name); size_t size; 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)); @@ -1036,7 +1034,6 @@ 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)); @@ -1231,7 +1228,7 @@ finalize(void) { if (detached_windows.windows) free(detached_windows.windows); detached_windows.capacity = 0; #define F(x) free(OPT(x)); OPT(x) = NULL; - F(background_image); F(bell_path); + F(background_image); F(bell_path); F(default_window_logo); #undef F // we leak the texture here since it is not guaranteed // that freeing the texture will work during shutdown and diff --git a/kitty/state.h b/kitty/state.h index b002a0d1e..42f9c8b4a 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -45,9 +45,9 @@ typedef struct { float adjust_line_height_frac, adjust_column_width_frac, adjust_baseline_frac; float background_opacity, dim_opacity; - char* background_image; + char *background_image, *default_window_logo; BackgroundImageLayout background_image_layout; - BackgroundImageAnchor background_image_anchor; + BackgroundImageAnchor window_logo_position; bool background_image_linear; float background_tint;