diff --git a/docs/changelog.rst b/docs/changelog.rst index c56842352..1e8f544c3 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -25,6 +25,10 @@ Changelog - Fix changing :opt:`cursor_text_color` via remote control not working (:iss:`1229`) +- Add an action to resize windows that can be mapped to shortcuts in :file:`kitty.conf` + (:pull:`1245`) + + 0.13.1 [2018-12-06] ------------------------------ diff --git a/docs/index.rst b/docs/index.rst index 4b6dbb8a8..c7bc5d46f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -223,6 +223,19 @@ example, in the Tall layout you can make the first window wider/narrower, but not taller/shorter. Note that what you are resizing is actually not a window, but a row/column in the layout, all windows in that row/column will be resized. +You can also define shortcuts in :file:`kitty.conf` to make the active window +wider, narrower, taller, or shorter by mapping to the ``resize_window`` +action, for example:: + + map ctrl+left resize_window narrower + map ctrl+right resize_window wider + map ctrl+up resize_window taller + map shift+down move_window shorter 3 + +The ``resize_window`` action has a second, optional argument to control +the resizing increment (a positive integer that defaults to 1). + + Some layouts take options to control their behavior. For example, the ``fat`` and ``tall`` layouts accept the ``bias`` option to control how the available space is split up. To specify the option, in :opt:`kitty.conf ` use:: diff --git a/kitty/config.py b/kitty/config.py index a2028a19f..10768ef79 100644 --- a/kitty/config.py +++ b/kitty/config.py @@ -150,6 +150,27 @@ def neighboring_window(func, rest): return func, [rest] +@func_with_args('resize_window') +def resize_window(func, rest): + vals = rest.split(' ', 1) + if len(vals) > 2: + log_error('resize_window needs one or two arguments, using defaults') + args = ['wider', 1] + else: + quality = vals[0].lower() + if quality not in ('taller', 'shorter', 'wider', 'narrower'): + log_error('Invalid quality specification: {}'.format(quality)) + quality = 'wider' + increment = 1 + if len(vals) == 2: + try: + increment = int(vals[1]) + except Exception: + log_error('Invalid increment specification: {}'.format(vals[1])) + args = [quality, increment] + return func, args + + @func_with_args('move_window') def move_window(func, rest): rest = rest.lower() diff --git a/kitty/glfw.c b/kitty/glfw.c index 1a840a8c1..530fb88cb 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -755,6 +755,24 @@ get_clipboard_string(PYNOARG) { return Py_BuildValue("s", ""); } +void +ring_audio_bell(OSWindow *w) { + static double last_bell_at = -1; + double now = monotonic(); + if (now - last_bell_at <= 0.1) return; + last_bell_at = now; + if (w->handle) { + glfwWindowBell(w->handle); + } +} + +static PyObject* +ring_bell(PYNOARG) { + OSWindow *w = current_os_window(); + ring_audio_bell(w); + Py_RETURN_NONE; +} + static PyObject* get_content_scale_for_window(PYNOARG) { OSWindow *w = global_state.callback_os_window ? global_state.callback_os_window : global_state.os_windows; @@ -792,17 +810,6 @@ change_os_window_state(PyObject *self UNUSED, PyObject *args) { Py_RETURN_NONE; } -void -ring_audio_bell(OSWindow *w) { - static double last_bell_at = -1; - double now = monotonic(); - if (now - last_bell_at <= 0.1) return; - last_bell_at = now; - if (w->handle) { - glfwWindowBell(w->handle); - } -} - void request_window_attention(id_type kitty_window_id, bool audio_bell) { OSWindow *w = os_window_for_kitty_window(kitty_window_id); @@ -1025,6 +1032,7 @@ static PyMethodDef module_methods[] = { METHODB(set_default_window_icon, METH_VARARGS), METHODB(get_clipboard_string, METH_NOARGS), METHODB(get_content_scale_for_window, METH_NOARGS), + METHODB(ring_bell, METH_NOARGS), METHODB(set_clipboard_string, METH_VARARGS), METHODB(toggle_fullscreen, METH_NOARGS), METHODB(change_os_window_state, METH_VARARGS), diff --git a/kitty/tabs.py b/kitty/tabs.py index 47910dc94..46b871085 100644 --- a/kitty/tabs.py +++ b/kitty/tabs.py @@ -11,7 +11,7 @@ from .child import Child from .constants import appname, get_boss, is_macos, is_wayland from .fast_data_types import ( add_tab, glfw_post_empty_event, mark_tab_bar_dirty, next_window_id, - pt_to_px, remove_tab, remove_window, set_active_tab, swap_tabs, + pt_to_px, remove_tab, remove_window, ring_bell, set_active_tab, swap_tabs, x11_window_id ) from .layout import create_layout_object_for, evict_cached_layouts @@ -199,6 +199,16 @@ class Tab: # {{{ return return 'Could not resize' + def resize_window(self, quality, increment): + if increment < 1: + raise ValueError(increment) + is_horizontal = quality in ('wider', 'narrower') + increment *= 1 if quality in ('wider', 'taller') else -1 + if self.resize_window_by( + self.windows[self.active_window_idx].id, + increment, is_horizontal) is not None: + ring_bell() + def reset_window_sizes(self): if self.current_layout.remove_all_biases(): self.relayout()