Hello community, here is the log from the commit of package kitty for openSUSE:Factory checked in at 2020-05-11 13:43:44 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kitty (Old) and /work/SRC/openSUSE:Factory/.kitty.new.2738 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kitty" Mon May 11 13:43:44 2020 rev:11 rq:802605 version:0.17.4 Changes: -------- --- /work/SRC/openSUSE:Factory/kitty/kitty.changes 2020-04-23 18:35:01.596614485 +0200 +++ /work/SRC/openSUSE:Factory/.kitty.new.2738/kitty.changes 2020-05-11 13:43:55.189446190 +0200 @@ -1,0 +2,19 @@ +Mon May 11 06:51:36 UTC 2020 - Michael Vetter <mvet...@suse.com> + +- Update to 0.17.4: + * Allow showing the name of the current layout and the number of + windows in tab titles (#2634) + * By default, double clicking no longer considers the : as part + of words, see select_by_word_characters (#2602) + * Fix a regression that caused clicking in the padding/margins + of windows in the stack layout to switch the window to the + first window (#2604) + * Report modifier key state when sending wheel events to the + terminal program + * Fix kitty @ send-text not working with text larger than 1024 + bytes when using kitty --listen-on (#2607) + * Wayland: Fix OS window title not updating for hidden + windows (#2629) + * Fix background_tint making the window semi-transparent (#2618) + +------------------------------------------------------------------- Old: ---- kitty-0.17.3.tar.gz New: ---- kitty-0.17.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kitty.spec ++++++ --- /var/tmp/diff_new_pack.uEljG3/_old 2020-05-11 13:43:56.521449015 +0200 +++ /var/tmp/diff_new_pack.uEljG3/_new 2020-05-11 13:43:56.525449024 +0200 @@ -17,7 +17,7 @@ Name: kitty -Version: 0.17.3 +Version: 0.17.4 Release: 0 Summary: A GPU-based terminal emulator License: GPL-3.0-only ++++++ kitty-0.17.3.tar.gz -> kitty-0.17.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/docs/changelog.rst new/kitty-0.17.4/docs/changelog.rst --- old/kitty-0.17.3/docs/changelog.rst 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/docs/changelog.rst 2020-05-09 07:18:21.000000000 +0200 @@ -4,6 +4,34 @@ |kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator. To update |kitty|, :doc:`follow the instructions <binary>`. + +0.17.4 [2020-05-09] +-------------------- + +- Allow showing the name of the current layout and the number of windows + in tab titles (:iss:`2634`) + +- macOS: Fix a regression in the previous release that caused ligatures to be + not be centered horizontally (:iss:`2591`) + +- By default, double clicking no longer considers the : as part of words, see + :opt:`select_by_word_characters` (:iss:`2602`) + +- Fix a regression that caused clicking in the padding/margins of windows in + the stack layout to switch the window to the first window (:iss:`2604`) + +- macOS: Fix a regression that broke drag and drop (:iss:`2605`) + +- Report modifier key state when sending wheel events to the terminal program + +- Fix kitty @ send-text not working with text larger than 1024 bytes when using + :option:`kitty --listen-on` (:iss:`2607`) + +- Wayland: Fix OS window title not updating for hidden windows (:iss:`2629`) + +- Fix :opt:`background_tint` making the window semi-transparent (:iss:`2618`) + + 0.17.3 [2020-04-23] -------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/docs/kittens/icat.rst new/kitty-0.17.4/docs/kittens/icat.rst --- old/kitty-0.17.3/docs/kittens/icat.rst 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/docs/kittens/icat.rst 2020-05-09 07:18:21.000000000 +0200 @@ -21,6 +21,12 @@ `ImageMagick <https://www.imagemagick.org>`_ must be installed for ``icat`` to work. +.. note:: + + kitty's image display protocol may not work when used within a terminal + multiplexer such as ``screen`` or ``tmux``, depending on whether the + multiplexer has added support for it or not. + .. program:: kitty +kitten icat diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/glfw/cocoa_window.m new/kitty-0.17.4/glfw/cocoa_window.m --- old/kitty-0.17.3/glfw/cocoa_window.m 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/glfw/cocoa_window.m 2020-05-09 07:18:21.000000000 +0200 @@ -1133,7 +1133,7 @@ break; } - _glfwInputScroll(window, deltaX, deltaY, flags); + _glfwInputScroll(window, deltaX, deltaY, flags, translateFlags([event modifierFlags])); } - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/glfw/glfw.py new/kitty-0.17.4/glfw/glfw.py --- old/kitty-0.17.3/glfw/glfw.py 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/glfw/glfw.py 2020-05-09 07:18:21.000000000 +0200 @@ -55,7 +55,7 @@ def init_env(env: Env, pkg_config: Callable, at_least_version: Callable, test_compile: Callable, module: str = 'x11') -> Env: ans = env.copy() - ans.cflags.append('-fpic') + ans.cflags.append('-fPIC') ans.cppflags.append('-D_GLFW_' + module.upper()) ans.cppflags.append('-D_GLFW_BUILD_DLL') @@ -95,7 +95,7 @@ for p in ans.wayland_protocols: ans.sources.append(wayland_protocol_file_name(p)) ans.all_headers.append(wayland_protocol_file_name(p, 'h')) - for dep in 'wayland-egl wayland-client wayland-cursor xkbcommon dbus-1'.split(): + for dep in 'wayland-client wayland-cursor xkbcommon dbus-1'.split(): ans.cflags.extend(pkg_config(dep, '--cflags-only-I')) ans.ldpaths.extend(pkg_config(dep, '--libs')) has_memfd_create = test_compile(env.cc, '-Werror', src='''#define _GNU_SOURCE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/glfw/glfw3.h new/kitty-0.17.4/glfw/glfw3.h --- old/kitty-0.17.3/glfw/glfw3.h 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/glfw/glfw3.h 2020-05-09 07:18:21.000000000 +0200 @@ -1550,6 +1550,7 @@ * value 2 for stationary momentum scrolling, value 3 for momentum scrolling * in progress, value 4 for momentum scrolling ended, value 5 for momentum * scrolling cancelled and value 6 if scrolling may begin soon. + * @param[int] mods The keyboard modifiers * * @sa @ref scrolling * @sa @ref glfwSetScrollCallback @@ -1559,7 +1560,7 @@ * * @ingroup input */ -typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int); +typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int,int); /*! @brief The function pointer type for key callbacks. * diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/glfw/input.c new/kitty-0.17.4/glfw/input.c --- old/kitty-0.17.3/glfw/input.c 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/glfw/input.c 2020-05-09 07:18:21.000000000 +0200 @@ -300,10 +300,10 @@ // Notifies shared code of a scroll event // -void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags) +void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags, int mods) { if (window->callbacks.scroll) - window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset, flags); + window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset, flags, mods); } // Notifies shared code of a mouse button click event diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/glfw/internal.h new/kitty-0.17.4/glfw/internal.h --- old/kitty-0.17.3/glfw/internal.h 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/glfw/internal.h 2020-05-09 07:18:21.000000000 +0200 @@ -755,7 +755,7 @@ void _glfwInitializeKeyEvent(GLFWkeyevent *ev, int key, int native_key, int action, int mods); void _glfwInputKeyboard(_GLFWwindow *window, GLFWkeyevent *ev); -void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags); +void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags, int mods); void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods); void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos); void _glfwInputCursorEnter(_GLFWwindow* window, bool entered); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/glfw/wl_init.c new/kitty-0.17.4/glfw/wl_init.c --- old/kitty-0.17.3/glfw/wl_init.c 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/glfw/wl_init.c 2020-05-09 07:18:21.000000000 +0200 @@ -334,7 +334,7 @@ else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) y = wl_fixed_to_double(value) * -1; - _glfwInputScroll(window, x, y, 1); + _glfwInputScroll(window, x, y, 1, _glfw.wl.xkb.states.modifiers); } static const struct wl_pointer_listener pointerListener = { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/glfw/x11_init.c new/kitty-0.17.4/glfw/x11_init.c --- old/kitty-0.17.3/glfw/x11_init.c 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/glfw/x11_init.c 2020-05-09 07:18:21.000000000 +0200 @@ -502,8 +502,10 @@ // X error handler // -static int errorHandler(Display *display UNUSED, XErrorEvent* event) +static int errorHandler(Display *display, XErrorEvent* event) { + if (_glfw.x11.display != display) + return 0; _glfw.x11.errorCode = event->error_code; return 0; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/glfw/x11_window.c new/kitty-0.17.4/glfw/x11_window.c --- old/kitty-0.17.3/glfw/x11_window.c 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/glfw/x11_window.c 2020-05-09 07:18:21.000000000 +0200 @@ -1265,13 +1265,13 @@ // Modern X provides scroll events as mouse button presses else if (event->xbutton.button == Button4) - _glfwInputScroll(window, 0.0, 1.0, 0); + _glfwInputScroll(window, 0.0, 1.0, 0, mods); else if (event->xbutton.button == Button5) - _glfwInputScroll(window, 0.0, -1.0, 0); + _glfwInputScroll(window, 0.0, -1.0, 0, mods); else if (event->xbutton.button == Button6) - _glfwInputScroll(window, 1.0, 0.0, 0); + _glfwInputScroll(window, 1.0, 0.0, 0, mods); else if (event->xbutton.button == Button7) - _glfwInputScroll(window, -1.0, 0.0, 0); + _glfwInputScroll(window, -1.0, 0.0, 0, mods); else { @@ -1408,12 +1408,18 @@ if (!event->xany.send_event && window->x11.parent != _glfw.x11.root) { Window dummy; + _glfwGrabErrorHandlerX11(); XTranslateCoordinates(_glfw.x11.display, window->x11.parent, _glfw.x11.root, xpos, ypos, &xpos, &ypos, &dummy); + _glfwReleaseErrorHandlerX11(); + if (_glfw.x11.errorCode != Success) { + _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to translate ConfigureNotiy co-ords for reparented window"); + return; + } } if (xpos != window->x11.xpos || ypos != window->x11.ypos) @@ -1550,17 +1556,21 @@ const int xabs = (event->xclient.data.l[2] >> 16) & 0xffff; const int yabs = (event->xclient.data.l[2]) & 0xffff; Window dummy; - int xpos, ypos; + int xpos = 0, ypos = 0; if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION) return; + _glfwGrabErrorHandlerX11(); XTranslateCoordinates(_glfw.x11.display, _glfw.x11.root, window->x11.handle, xabs, yabs, &xpos, &ypos, &dummy); + _glfwReleaseErrorHandlerX11(); + if (_glfw.x11.errorCode != Success) + _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to get DND event position"); _glfwInputCursorPos(window, xpos, ypos); @@ -1988,10 +1998,14 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { Window dummy; - int x, y; + int x = 0, y = 0; + _glfwGrabErrorHandlerX11(); XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root, 0, 0, &x, &y, &dummy); + _glfwReleaseErrorHandlerX11(); + if (_glfw.x11.errorCode != Success) + _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to get window position"); if (xpos) *xpos = x; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/boss.py new/kitty-0.17.4/kitty/boss.py --- old/kitty-0.17.3/kitty/boss.py 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/boss.py 2020-05-09 07:18:21.000000000 +0200 @@ -336,7 +336,13 @@ if not getattr(err, 'hide_traceback', False): response['tb'] = traceback.format_exc() else: - response = {'ok': False, 'error': 'Remote control is disabled. Add allow_remote_control to your kitty.conf'} + no_response = False + try: + no_response = json.loads(cmd).get('no_response') + except Exception: + pass + if not no_response: + response = {'ok': False, 'error': 'Remote control is disabled. Add allow_remote_control to your kitty.conf'} return response def remote_control(self, *args: str) -> None: @@ -355,15 +361,16 @@ self.show_error(_('remote_control mapping failed'), str(e)) def peer_message_received(self, msg_bytes: bytes) -> Optional[bytes]: - msg = msg_bytes.decode('utf-8') - cmd_prefix = '\x1bP@kitty-cmd' - if msg.startswith(cmd_prefix): - cmd = msg[len(cmd_prefix):-2] + cmd_prefix = b'\x1bP@kitty-cmd' + terminator = b'\x1b\\' + if msg_bytes.startswith(cmd_prefix) and msg_bytes.endswith(terminator): + cmd = msg_bytes[len(cmd_prefix):-len(terminator)].decode('utf-8') response = self._handle_remote_command(cmd, from_peer=True) if response is None: return None - return (cmd_prefix + json.dumps(response) + '\x1b\\').encode('utf-8') - data = json.loads(msg) + return cmd_prefix + json.dumps(response).encode('utf-8') + terminator + + data = json.loads(msg_bytes.decode('utf-8')) if isinstance(data, dict) and data.get('cmd') == 'new_instance': from .cli_stub import CLIOptions startup_id = data.get('startup_id') @@ -717,6 +724,9 @@ text = '\n'.join(parse_uri_list(text)) w.paste(text) + def confirm_os_window_close(self, os_window_id: int) -> None: + mark_os_window_for_close(os_window_id) + def on_os_window_closed(self, os_window_id: int, viewport_width: int, viewport_height: int) -> None: self.cached_values['window-size'] = viewport_width, viewport_height tm = self.os_window_map.pop(os_window_id, None) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/child-monitor.c new/kitty-0.17.4/kitty/child-monitor.c --- old/kitty-0.17.3/kitty/child-monitor.c 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/child-monitor.c 2020-05-09 07:18:21.000000000 +0200 @@ -524,17 +524,6 @@ } static inline bool -update_window_title(Window *w, OSWindow *os_window) { - if (w->title && w->title != os_window->window_title) { - os_window->window_title = w->title; - Py_INCREF(os_window->window_title); - set_os_window_title(os_window, PyUnicode_AsUTF8(w->title)); - return true; - } - return false; -} - -static inline bool prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int *active_window_id, color_type *active_window_bg, unsigned int *num_visible_windows, bool *all_windows_have_same_bg) { #define TD os_window->tab_bar_render_data bool needs_render = os_window->needs_render; @@ -577,7 +566,7 @@ *active_window_id = w->id; collect_cursor_info(&WD.screen->cursor_render_info, w, now, os_window); if (w->cursor_visible_at_last_render != WD.screen->cursor_render_info.is_visible || w->last_cursor_x != WD.screen->cursor_render_info.x || w->last_cursor_y != WD.screen->cursor_render_info.y || w->last_cursor_shape != WD.screen->cursor_render_info.shape) needs_render = true; - update_window_title(w, os_window); + set_os_window_title_from_window(w, os_window); *active_window_bg = window_bg; } else WD.screen->cursor_render_info.is_visible = false; if (send_cell_data_to_gpu(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen, os_window)) needs_render = true; @@ -625,15 +614,6 @@ #undef TD } -static inline void -update_os_window_title(OSWindow *os_window) { - Tab *tab = os_window->tabs + os_window->active_tab; - if (tab->num_windows) { - Window *w = tab->windows + tab->active_window; - update_window_title(w, os_window); - } -} - static void draw_resizing_text(OSWindow *w) { char text[32] = {0}; @@ -865,25 +845,42 @@ static inline void close_all_windows(void) { - for (size_t w = 0; w < global_state.num_os_windows; w++) mark_os_window_for_close(&global_state.os_windows[w], true); + for (size_t w = 0; w < global_state.num_os_windows; w++) mark_os_window_for_close(&global_state.os_windows[w], IMPERATIVE_CLOSE_REQUESTED); +} + +static inline void +close_os_window(ChildMonitor *self, OSWindow *os_window) { + destroy_os_window(os_window); + call_boss(on_os_window_closed, "Kii", os_window->id, os_window->window_width, os_window->window_height); + for (size_t t=0; t < os_window->num_tabs; t++) { + Tab *tab = os_window->tabs + t; + for (size_t w = 0; w < tab->num_windows; w++) mark_child_for_close(self, tab->windows[w].id); + } + remove_os_window(os_window->id); } static inline bool process_pending_closes(ChildMonitor *self) { - global_state.has_pending_closes = false; bool has_open_windows = false; for (size_t w = global_state.num_os_windows; w > 0; w--) { OSWindow *os_window = global_state.os_windows + w - 1; - if (should_os_window_close(os_window)) { - destroy_os_window(os_window); - call_boss(on_os_window_closed, "Kii", os_window->id, os_window->window_width, os_window->window_height); - for (size_t t=0; t < os_window->num_tabs; t++) { - Tab *tab = os_window->tabs + t; - for (size_t w = 0; w < tab->num_windows; w++) mark_child_for_close(self, tab->windows[w].id); - } - remove_os_window(os_window->id); - } else has_open_windows = true; + switch(os_window->close_request) { + case NO_CLOSE_REQUESTED: + has_open_windows = true; + break; + case CONFIRMABLE_CLOSE_REQUESTED: + os_window->close_request = NO_CLOSE_REQUESTED; + call_boss(confirm_os_window_close, "K", os_window->id); + if (os_window->close_request == IMPERATIVE_CLOSE_REQUESTED) { + close_os_window(self, os_window); + } else has_open_windows = true; + break; + case IMPERATIVE_CLOSE_REQUESTED: + close_os_window(self, os_window); + break; + } } + global_state.has_pending_closes = false; #ifdef __APPLE__ if (!OPT(macos_quit_when_last_window_closed)) { if (!has_open_windows && !application_quit_requested()) has_open_windows = true; @@ -1279,7 +1276,7 @@ char *data; size_t capacity, used; int fd; - bool finished, close_socket; + bool finished, close_socket, is_peer_command; } PeerReadData; static PeerReadData empty_prd = {.fd = -1, 0}; @@ -1329,6 +1326,41 @@ return true; } +#define KITTY_CMD_PREFIX "\x1bP@kitty-cmd{" + +static inline void +queue_peer_message(ChildMonitor *self, char *buf, size_t sz, int fd) { + children_mutex(lock); + ensure_space_for(self, messages, Message, self->messages_count + 1, messages_capacity, 16, true); + Message *m = self->messages + self->messages_count++; + m->data = buf; m->sz = sz; m->fd = fd; + children_mutex(unlock); + wakeup_main_loop(); +} + +static inline void +dispatch_peer_command(ChildMonitor *self, PeerReadData *rd, int fd) { + size_t end = 0; + for (size_t i = 0; i < rd->used - 1; i++) { + if (rd->data[i] == 0x1b && rd->data[i+1] == '\\') { + end = i + 2; + break; + } + } + if (!end) return; + char *buf = malloc(end + 8); + if (buf) { + memcpy(buf, rd->data, end); + queue_peer_message(self, buf, end, fd); + } + rd->is_peer_command = false; + if (rd->used > end) { + rd->used -= end; + memmove(rd->data, rd->data + end, rd->used); + if (rd->used >= sizeof(KITTY_CMD_PREFIX) - 1 && memcmp(rd->data, KITTY_CMD_PREFIX, sizeof(KITTY_CMD_PREFIX)-1) == 0) rd->is_peer_command = true; + } else rd->used = 0; +} + static inline bool read_from_peer(ChildMonitor *self, int s) { bool read_finished = false; @@ -1337,26 +1369,28 @@ #define failed(msg) { read_finished = true; log_error("%s", msg); rd->finished = true; rd->close_socket = true; break; } if (rd->fd == s) { if (rd->used >= rd->capacity) { - if (rd->capacity >= 1024 * 1024) failed("Ignoring too large message from peer"); + if (rd->capacity >= 64 * 1024) failed("Ignoring too large message from peer"); rd->capacity = MAX(8192u, rd->capacity * 2); rd->data = realloc(rd->data, rd->capacity); if (!rd->data) failed("Out of memory"); } ssize_t n = recv(s, rd->data + rd->used, rd->capacity - rd->used, 0); if (n == 0) { + while (rd->is_peer_command) dispatch_peer_command(self, rd, s); read_finished = true; rd->finished = true; - children_mutex(lock); - ensure_space_for(self, messages, Message, self->messages_count + 1, messages_capacity, 16, true); - Message *m = self->messages + self->messages_count++; - m->data = rd->data; rd->data = NULL; m->sz = rd->used; m->fd = s; - children_mutex(unlock); - wakeup_main_loop(); + if (rd->used) queue_peer_message(self, rd->data, rd->used, s); + else free(rd->data); + rd->data = NULL; } else if (n < 0) { if (errno != EINTR) { perror("Error reading from talk peer"); failed(""); } - } else rd->used += n; + } else { + if (!rd->used && memcmp(rd->data, KITTY_CMD_PREFIX, sizeof(KITTY_CMD_PREFIX)-1) == 0) rd->is_peer_command = true; + rd->used += n; + while (rd->is_peer_command) dispatch_peer_command(self, rd, s); + } break; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/cli.py new/kitty-0.17.4/kitty/cli.py --- old/kitty-0.17.3/kitty/cli.py 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/cli.py 2020-05-09 07:18:21.000000000 +0200 @@ -409,7 +409,10 @@ elif otype == 'list': t = 'typing.Sequence[str]' elif otype in ('choice', 'choices'): - t = 'str' + if opt['choices']: + t = 'typing.Literal[{}]'.format(','.join(f'{x!r}' for x in opt['choices'])) + else: + t = 'str' elif otype.startswith('bool-'): t = 'bool' else: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/conf/definition.py new/kitty-0.17.4/kitty/conf/definition.py --- old/kitty-0.17.3/kitty/conf/definition.py 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/conf/definition.py 2020-05-09 07:18:21.000000000 +0200 @@ -9,7 +9,7 @@ Set, Tuple, Union, get_type_hints ) -from .utils import to_bool +from .utils import Choice, to_bool def to_string(x: str) -> str: @@ -56,6 +56,8 @@ if type(self.option_type) is type: return type_name(self.option_type) + if isinstance(self.option_type, Choice): + return 'typing.Literal[{}]'.format(','.join(f'{x!r}' for x in self.option_type.all_choices)) th = get_type_hints(self.option_type) try: rettype = th['return'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/conf/utils.py new/kitty-0.17.4/kitty/conf/utils.py --- old/kitty-0.17.3/kitty/conf/utils.py 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/conf/utils.py 2020-05-09 07:18:21.000000000 +0200 @@ -68,17 +68,21 @@ return ans -def choices(*choices: str) -> Callable[[str], str]: - defval = choices[0] - uc = frozenset(choices) +class Choice: - def choice(x: str) -> str: + def __init__(self, choices: Sequence[str]): + self.defval = choices[0] + self.all_choices = frozenset(choices) + + def __call__(self, x: str) -> str: x = x.lower() - if x not in uc: - x = defval + if x not in self.all_choices: + x = self.defval return x - return choice + +def choices(*choices: str) -> Choice: + return Choice(choices) def parse_line( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/config.py new/kitty-0.17.4/kitty/config.py --- old/kitty-0.17.3/kitty/config.py 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/config.py 2020-05-09 07:18:21.000000000 +0200 @@ -9,8 +9,8 @@ from contextlib import contextmanager, suppress from functools import partial from typing import ( - Any, Callable, Dict, Generator, Iterable, List, Match, NamedTuple, - Optional, Sequence, Set, Tuple, Type, Union + Any, Callable, Dict, Generator, Iterable, List, NamedTuple, Optional, + Sequence, Set, Tuple, Type, Union ) from . import fast_data_types as defines @@ -24,7 +24,7 @@ from .key_names import get_key_name_lookup, key_name_aliases from .options_stub import Options as OptionsStub from .typing import EdgeLiteral, TypedDict -from .utils import log_error +from .utils import expandvars, log_error KeySpec = Tuple[int, bool, int] KeyMap = Dict[KeySpec, 'KeyAction'] @@ -585,20 +585,6 @@ ans['macos_show_window_title_in'] = macos_show_window_title_in -def expandvars(val: str, env: Dict[str, str] = {}) -> str: - - def sub(m: Match) -> str: - key = m.group(1) - result = env.get(key) - if result is None: - result = os.environ.get(key) - if result is None: - result = m.group() - return result - - return re.sub(r'\$\{(\S+?)\}', sub, val) - - @special_handler def handle_env(key: str, val: str, ans: Dict[str, Any]) -> None: key, val = val.partition('=')[::2] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/config_data.py new/kitty-0.17.4/kitty/config_data.py --- old/kitty-0.17.3/kitty/config_data.py 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/config_data.py 2020-05-09 07:18:21.000000000 +0200 @@ -548,7 +548,7 @@ o('terminal_select_modifiers', 'shift', option_type=to_modifiers, long_text=_(''' The modifiers to override mouse selection even when a terminal application has grabbed the mouse''')) -o('select_by_word_characters', ':@-./_~?&=%+#', long_text=_(''' +o('select_by_word_characters', '@-./_~?&=%+#', long_text=_(''' Characters considered part of a word when double clicking. In addition to these characters any character that is marked as an alphanumeric character in the unicode database will be matched.''')) @@ -870,6 +870,11 @@ the title. If you wish to include the tab-index as well, use something like: :code:`{index}: {title}`. Useful if you have shortcuts mapped for :code:`goto_tab N`. +In addition you can use :code:`{layout_name}` for the current +layout name and :code:`{num_windows}` for the number of windows +in the tab. Note that formatting is done by Python's string formatting +machinery, so you can use, for instance, :code:`{layout_name[:2].upper()}` to +show only the first two letters of the layout name, upper-cased. ''')) o('active_tab_title_template', 'none', option_type=active_tab_title_template, long_text=_(''' Template to use for active tabs, if not specified falls back diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/constants.py new/kitty-0.17.4/kitty/constants.py --- old/kitty-0.17.3/kitty/constants.py 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/constants.py 2020-05-09 07:18:21.000000000 +0200 @@ -20,7 +20,7 @@ appname: str = 'kitty' -version: Version = Version(0, 17, 3) +version: Version = Version(0, 17, 4) str_version: str = '.'.join(map(str, version)) _plat = sys.platform.lower() is_macos: bool = 'darwin' in _plat diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/core_text.m new/kitty-0.17.4/kitty/core_text.m --- old/kitty-0.17.3/kitty/core_text.m 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/core_text.m 2020-05-09 07:18:21.000000000 +0200 @@ -506,8 +506,10 @@ render_alpha_mask(render_buf, canvas, &src, &dest, canvas_width, canvas_width); } if (num_cells && (center_glyph || (num_cells == 2 && *was_colored))) { - // center glyphs (two cell emoji and PUA glyphs) - CGFloat delta = (((CGFloat)canvas_width - br.size.width) / 2.f) - br.origin.x; + // center glyphs (two cell emoji, PUA glyphs, ligatures, etc) + CGFloat delta = (((CGFloat)canvas_width - br.size.width) / 2.f); + // FiraCode ligatures result in negative origins + if (br.origin.x > 0) delta -= br.origin.x; if (delta >= 1.f) right_shift_canvas(canvas, canvas_width, cell_height, (unsigned)(delta)); } return true; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/data-types.h new/kitty-0.17.4/kitty/data-types.h --- old/kitty-0.17.3/kitty/data-types.h 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/data-types.h 2020-05-09 07:18:21.000000000 +0200 @@ -313,7 +313,7 @@ void enter_event(void); void mouse_event(int, int, int); void focus_in_event(void); -void scroll_event(double, double, int); +void scroll_event(double, double, int, int); void fake_scroll(int, bool); void set_special_key_combo(int glfw_key, int mods, bool is_native); void on_key_input(GLFWkeyevent *ev); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/desktop.c new/kitty-0.17.4/kitty/desktop.c --- old/kitty-0.17.3/kitty/desktop.c 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/desktop.c 2020-05-09 07:18:21.000000000 +0200 @@ -30,18 +30,22 @@ static PyObject* init_x11_startup_notification(PyObject UNUSED *self, PyObject *args) { static bool done = false; - static const char* libname = "libstartup-notification-1.so"; - // some installs are missing the .so symlink, so try the full name - static const char* libname2 = "libstartup-notification-1.so.0"; - static const char* libname3 = "libstartup-notification-1.so.0.0.0"; if (!done) { done = true; - libsn_handle = dlopen(libname, RTLD_LAZY); - if (libsn_handle == NULL) libsn_handle = dlopen(libname2, RTLD_LAZY); - if (libsn_handle == NULL) libsn_handle = dlopen(libname3, RTLD_LAZY); + const char* libnames[] = { + "libstartup-notification-1.so", + // some installs are missing the .so symlink, so try the full name + "libstartup-notification-1.so.0", + "libstartup-notification-1.so.0.0.0", + NULL + }; + for (int i = 0; libnames[i]; i++) { + libsn_handle = dlopen(libnames[i], RTLD_LAZY); + if (libsn_handle) break; + } if (libsn_handle == NULL) { - PyErr_Format(PyExc_OSError, "Failed to load %s with error: %s", libname, dlerror()); + PyErr_Format(PyExc_OSError, "Failed to load %s with error: %s", libnames[0], dlerror()); return NULL; } dlerror(); /* Clear any existing error */ @@ -105,18 +109,22 @@ static void load_libcanberra(void) { - static const char* libname = "libcanberra.so"; - // some installs are missing the .so symlink, so try the full name - static const char* libname2 = "libcanberra.so.0"; - static const char* libname3 = "libcanberra.so.0.2.5"; static bool done = false; if (done) return; done = true; - libcanberra_handle = dlopen(libname, RTLD_LAZY); - if (libcanberra_handle == NULL) libcanberra_handle = dlopen(libname2, RTLD_LAZY); - if (libcanberra_handle == NULL) libcanberra_handle = dlopen(libname3, RTLD_LAZY); + const char* libnames[] = { + "libcanberra.so", + // some installs are missing the .so symlink, so try the full name + "libcanberra.so.0", + "libcanberra.so.0.2.5", + NULL + }; + for (int i = 0; libnames[i]; i++) { + libcanberra_handle = dlopen(libnames[i], RTLD_LAZY); + if (libcanberra_handle) break; + } if (libcanberra_handle == NULL) { - fprintf(stderr, "Failed to load %s, cannot play beep sound, with error: %s\n", libname, dlerror()); + fprintf(stderr, "Failed to load %s, cannot play beep sound, with error: %s\n", libnames[0], dlerror()); return; } load_libcanberra_functions(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/fast_data_types.pyi new/kitty-0.17.4/kitty/fast_data_types.pyi --- old/kitty-0.17.3/kitty/fast_data_types.pyi 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/fast_data_types.pyi 2020-05-09 07:18:21.000000000 +0200 @@ -550,6 +550,10 @@ pass +def sync_os_window_title(os_window_id: int) -> None: + pass + + def set_options( opts: Options, is_wayland: bool = False, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/fonts.c new/kitty-0.17.4/kitty/fonts.c --- old/kitty-0.17.3/kitty/fonts.c 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/fonts.c 2020-05-09 07:18:21.000000000 +0200 @@ -1004,14 +1004,20 @@ G(groups)->is_space_ligature = true; } +static inline bool +is_group_calt_ligature(const Group *group) { + GPUCell *first_cell = G(first_gpu_cell) + group->first_cell_idx; + return group->num_cells > 1 && group->has_special_glyph && (first_cell->attrs & WIDTH_MASK) == 1; +} + + static inline void split_run_at_offset(index_type cursor_offset, index_type *left, index_type *right) { *left = 0; *right = 0; for (unsigned idx = 0; idx < G(group_idx) + 1; idx++) { Group *group = G(groups) + idx; if (group->first_cell_idx <= cursor_offset && cursor_offset < group->first_cell_idx + group->num_cells) { - GPUCell *first_cell = G(first_gpu_cell) + group->first_cell_idx; - if (group->num_cells > 1 && group->has_special_glyph && (first_cell->attrs & WIDTH_MASK) == 1) { + if (is_group_calt_ligature(group)) { // likely a calt ligature *left = group->first_cell_idx; *right = group->first_cell_idx + group->num_cells; } @@ -1039,6 +1045,11 @@ // there exist stupid fonts like Powerline that have no space glyph, // so special case it: https://github.com/kovidgoyal/kitty/issues/1225 unsigned int num_glyphs = group->is_space_ligature ? 1 : group->num_glyphs; +#ifdef __APPLE__ + // FiraCode ligatures need to be centered on macOS + // see https://github.com/kovidgoyal/kitty/issues/2591 + if (is_group_calt_ligature(group)) center_glyph = true; +#endif render_group(fg, group->num_cells, num_glyphs, G(first_cpu_cell) + group->first_cell_idx, G(first_gpu_cell) + group->first_cell_idx, G(info) + group->first_glyph_idx, G(positions) + group->first_glyph_idx, font, primary, &ed, center_glyph); idx++; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/glfw-wrapper.h new/kitty-0.17.4/kitty/glfw-wrapper.h --- old/kitty-0.17.3/kitty/glfw-wrapper.h 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/glfw-wrapper.h 2020-05-09 07:18:21.000000000 +0200 @@ -1313,6 +1313,7 @@ * value 2 for stationary momentum scrolling, value 3 for momentum scrolling * in progress, value 4 for momentum scrolling ended, value 5 for momentum * scrolling cancelled and value 6 if scrolling may begin soon. + * @param[int] mods The keyboard modifiers * * @sa @ref scrolling * @sa @ref glfwSetScrollCallback @@ -1322,7 +1323,7 @@ * * @ingroup input */ -typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int); +typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int,int); /*! @brief The function pointer type for key callbacks. * diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/glfw.c new/kitty-0.17.4/kitty/glfw.c --- old/kitty-0.17.3/kitty/glfw.c 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/glfw.c 2020-05-09 07:18:21.000000000 +0200 @@ -153,6 +153,10 @@ window_close_callback(GLFWwindow* window) { if (!set_callback_window(window)) return; global_state.has_pending_closes = true; + if (global_state.callback_os_window->close_request < CONFIRMABLE_CLOSE_REQUESTED) { + global_state.callback_os_window->close_request = CONFIRMABLE_CLOSE_REQUESTED; + } + glfwSetWindowShouldClose(window, false); request_tick_callback(); global_state.callback_os_window = NULL; } @@ -287,12 +291,12 @@ } static void -scroll_callback(GLFWwindow *w, double xoffset, double yoffset, int flags) { +scroll_callback(GLFWwindow *w, double xoffset, double yoffset, int flags, int mods) { if (!set_callback_window(w)) return; show_mouse_cursor(w); monotonic_t now = monotonic(); global_state.callback_os_window->last_mouse_activity_at = now; - if (is_window_ready_for_callbacks()) scroll_event(xoffset, yoffset, flags); + if (is_window_ready_for_callbacks()) scroll_event(xoffset, yoffset, flags, mods); request_tick_callback(); global_state.callback_os_window = NULL; } @@ -323,23 +327,17 @@ static int drop_callback(GLFWwindow *w, const char *mime, const char *data, size_t sz) { if (!set_callback_window(w)) return 0; +#define RETURN(x) { global_state.callback_os_window = NULL; return x; } if (!data) { - if (strcmp(mime, "text/uri-list") == 0) return 3; - if (strcmp(mime, "text/plain;charset=utf-8") == 0) return 2; - if (strcmp(mime, "text/plain") == 0) return 1; - return 0; - } - WINDOW_CALLBACK(on_drop, "sy#", mime, data, (int)sz); - request_tick_callback(); - /* PyObject *s = PyTuple_New(count); */ - /* if (s) { */ - /* for (int i = 0; i < count; i++) PyTuple_SET_ITEM(s, i, PyUnicode_FromString(strings[i])); */ - /* WINDOW_CALLBACK(on_drop, "O", s); */ - /* Py_CLEAR(s); */ - /* request_tick_callback(); */ - /* } */ - global_state.callback_os_window = NULL; - return 0; + if (strcmp(mime, "text/uri-list") == 0) RETURN(3); + if (strcmp(mime, "text/plain;charset=utf-8") == 0) RETURN(2); + if (strcmp(mime, "text/plain") == 0) RETURN(1); + RETURN(0); + } + WINDOW_CALLBACK(on_drop, "sy#", mime, data, (Py_ssize_t)sz); + request_tick_callback(); + RETURN(0); +#undef RETURN } // }}} @@ -979,12 +977,6 @@ glfwPostEmptyEvent(); } -void -mark_os_window_for_close(OSWindow* w, bool yes) { - global_state.has_pending_closes = true; - glfwSetWindowShouldClose(w->handle, yes); -} - bool should_os_window_be_rendered(OSWindow* w) { return ( @@ -994,11 +986,6 @@ ) ? false : true; } -bool -should_os_window_close(OSWindow* w) { - return glfwWindowShouldClose(w->handle) ? true : false; -} - static PyObject* primary_monitor_size(PYNOARG) { GLFWmonitor* monitor = glfwGetPrimaryMonitor(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/graphics.c new/kitty-0.17.4/kitty/graphics.c --- old/kitty-0.17.3/kitty/graphics.c 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/graphics.c 2020-05-09 07:18:21.000000000 +0200 @@ -939,7 +939,7 @@ }; static PyMemberDef members[] = { - {"image_count", T_UINT, offsetof(GraphicsManager, image_count), 0, "image_count"}, + {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"}, {NULL}, }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/launch.py new/kitty-0.17.4/kitty/launch.py --- old/kitty-0.17.3/kitty/launch.py 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/launch.py 2020-05-09 07:18:21.000000000 +0200 @@ -42,7 +42,7 @@ Where to launch the child process, in a new kitty window in the current tab, a new tab, or a new OS window or an overlay over the current window. Note that if the current window already has an overlay, then it will -open a new window. The value of none means the process will be +open a new window. The value of background means the process will be run in the background. The values clipboard and primary are meant to work with :option:`launch --stdin-source` to copy data to the system clipboard or primary selection. @@ -275,8 +275,8 @@ kw['cmd'] = final_cmd if opts.type == 'overlay' and active and not active.overlay_window_id: kw['overlay_for'] = active.id - if opts.stdin_source and opts.stdin_source != 'none': - q = opts.stdin_source + if opts.stdin_source != 'none': + q = str(opts.stdin_source) if opts.stdin_add_formatting: if q in ('@screen', '@screen_scrollback', '@alternate', '@alternate_scrollback'): q = '@ansi_' + q[1:] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/main.py new/kitty-0.17.4/kitty/main.py --- old/kitty-0.17.3/kitty/main.py 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/main.py 2020-05-09 07:18:21.000000000 +0200 @@ -7,7 +7,7 @@ import shutil import sys from contextlib import contextmanager, suppress -from typing import Generator, List, Mapping, Optional, Tuple, Sequence +from typing import Generator, List, Mapping, Optional, Sequence, Tuple from .borders import load_borders_program from .boss import Boss @@ -15,7 +15,7 @@ from .cli import create_opts, parse_args from .cli_stub import CLIOptions from .conf.utils import BadLine -from .config import cached_values_for, initial_window_size_func, expandvars +from .config import cached_values_for, initial_window_size_func from .constants import ( appname, beam_cursor_data_file, config_dir, glfw_path, is_macos, is_wayland, kitty_exe, logo_data_file, running_in_kitty @@ -29,7 +29,7 @@ from .fonts.render import set_font_family from .options_stub import Options as OptionsStub from .utils import ( - detach, log_error, read_shell_environment, single_instance, + detach, expandvars, log_error, read_shell_environment, single_instance, startup_notification_handler, unix_socket_paths ) from .window import load_shader_programs diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/mouse.c new/kitty-0.17.4/kitty/mouse.c --- old/kitty-0.17.3/kitty/mouse.c 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/mouse.c 2020-05-09 07:18:21.000000000 +0200 @@ -514,7 +514,8 @@ Tab *t = global_state.callback_os_window->tabs + global_state.callback_os_window->active_tab; for (unsigned int i = 0; i < t->num_windows; i++) { if (contains_mouse(t->windows + i) && t->windows[i].render_data.screen) { - *window_idx = i; return t->windows + i; + *window_idx = i; + return t->windows + i; } } } @@ -529,8 +530,10 @@ Tab *t = global_state.callback_os_window->tabs + global_state.callback_os_window->active_tab; for (unsigned int i = 0; i < t->num_windows; i++) { Window *w = t->windows + i; - double d = distance_to_window(w); - if (d < closest_distance) { ans = w; closest_distance = d; *window_idx = i; } + if (w->visible) { + double d = distance_to_window(w); + if (d < closest_distance) { ans = w; closest_distance = d; *window_idx = i; } + } } } return ans; @@ -610,7 +613,7 @@ } void -scroll_event(double UNUSED xoffset, double yoffset, int flags) { +scroll_event(double UNUSED xoffset, double yoffset, int flags, int modifiers) { bool in_tab_bar; static id_type window_for_momentum_scroll = 0; static bool main_screen_for_momentum_scroll = false; @@ -687,7 +690,7 @@ screen_history_scroll(screen, abs(s), upwards); } else { if (screen->modes.mouse_tracking_mode) { - int sz = encode_mouse_event(w, upwards ? GLFW_MOUSE_BUTTON_4 : GLFW_MOUSE_BUTTON_5, PRESS, 0); + int sz = encode_mouse_event(w, upwards ? GLFW_MOUSE_BUTTON_4 : GLFW_MOUSE_BUTTON_5, PRESS, modifiers); if (sz > 0) { mouse_event_buf[sz] = 0; for (s = abs(s); s > 0; s--) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/shaders.c new/kitty-0.17.4/kitty/shaders.c --- old/kitty-0.17.3/kitty/shaders.c 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/shaders.c 2020-05-09 07:18:21.000000000 +0200 @@ -465,7 +465,11 @@ bind_program(CELL_BG_PROGRAM); glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].draw_bg_bitfield_location, 3); glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); - } else if (OPT(background_tint) > 0) draw_tint(false, screen, xstart, ystart, width, height); + } else if (OPT(background_tint) > 0) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); + draw_tint(false, screen, xstart, ystart, width, height); + BLEND_ONTO_OPAQUE; + } if (screen->grman->num_of_below_refs || has_bgimage(w)) { if (screen->grman->num_of_below_refs) draw_graphics( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/state.c new/kitty-0.17.4/kitty/state.c --- old/kitty-0.17.3/kitty/state.c 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/state.c 2020-05-09 07:18:21.000000000 +0200 @@ -43,8 +43,9 @@ if (osw->tabs[t].id == tab_id) { \ Tab *tab = osw->tabs + t; \ for (size_t w = 0; w < tab->num_windows; w++) { \ - Window *window = tab->windows + w; -#define END_WITH_WINDOW break; }}}}} + if (tab->windows[w].id == window_id) { \ + Window *window = tab->windows + w; +#define END_WITH_WINDOW window_found = 1; break; }}}}}} #define WITH_OS_WINDOW_REFS \ @@ -213,6 +214,27 @@ END_WITH_TAB; } +void +set_os_window_title_from_window(Window *w, OSWindow *os_window) { + if (w->title && w->title != os_window->window_title) { + Py_XDECREF(os_window->window_title); + os_window->window_title = w->title; + Py_INCREF(os_window->window_title); + set_os_window_title(os_window, PyUnicode_AsUTF8(w->title)); + } +} + +void +update_os_window_title(OSWindow *os_window) { + if (os_window->num_tabs) { + Tab *tab = os_window->tabs + os_window->active_tab; + if (tab->num_windows) { + Window *w = tab->windows + tab->active_window; + set_os_window_title_from_window(w, os_window); + } + } +} + static inline void destroy_window(Window *w) { Py_CLEAR(w->render_data.screen); Py_CLEAR(w->title); @@ -422,6 +444,14 @@ } } +void +mark_os_window_for_close(OSWindow* w, CloseRequest cr) { + global_state.has_pending_closes = true; + w->close_request = cr; +} + + + // Python API {{{ #define PYWRAP0(name) static PyObject* py##name(PYNOARG) @@ -783,10 +813,10 @@ PYWRAP1(mark_os_window_for_close) { id_type os_window_id; - int yes = 1; - PA("K|p", &os_window_id, &yes); + CloseRequest cr = IMPERATIVE_CLOSE_REQUESTED; + PA("K|i", &os_window_id, &cr); WITH_OS_WINDOW(os_window_id) - mark_os_window_for_close(os_window, yes ? true : false); + mark_os_window_for_close(os_window, cr); Py_RETURN_TRUE; END_WITH_OS_WINDOW Py_RETURN_FALSE; @@ -899,6 +929,17 @@ Py_RETURN_NONE; } + +PYWRAP1(sync_os_window_title) { + id_type os_window_id; + PA("K", &os_window_id); + WITH_OS_WINDOW(os_window_id) + update_os_window_title(os_window); + END_WITH_OS_WINDOW + Py_RETURN_NONE; +} + + static inline double dpi_for_os_window_id(id_type os_window_id) { double dpi = 0; @@ -1112,6 +1153,7 @@ MW(change_background_opacity, METH_VARARGS), MW(background_opacity_of, METH_O), MW(update_window_visibility, METH_VARARGS), + MW(sync_os_window_title, METH_VARARGS), MW(global_font_size, METH_VARARGS), MW(set_background_image, METH_VARARGS), MW(os_window_font_size, METH_VARARGS), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/state.h new/kitty-0.17.4/kitty/state.h --- old/kitty-0.17.3/kitty/state.h 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/state.h 2020-05-09 07:18:21.000000000 +0200 @@ -139,6 +139,7 @@ } OSWindowGeometry; enum RENDER_STATE { RENDER_FRAME_NOT_REQUESTED, RENDER_FRAME_REQUESTED, RENDER_FRAME_READY }; +typedef enum { NO_CLOSE_REQUESTED, CONFIRMABLE_CLOSE_REQUESTED, IMPERATIVE_CLOSE_REQUESTED } CloseRequest; typedef struct { monotonic_t last_resize_event_at; @@ -183,6 +184,7 @@ uint64_t render_calls; id_type last_focused_counter; ssize_t gvao_idx; + CloseRequest close_request; } OSWindow; @@ -220,9 +222,8 @@ bool remove_os_window(id_type os_window_id); void make_os_window_context_current(OSWindow *w); void update_os_window_references(void); -void mark_os_window_for_close(OSWindow* w, bool yes); +void mark_os_window_for_close(OSWindow* w, CloseRequest cr); void update_os_window_viewport(OSWindow *window, bool); -bool should_os_window_close(OSWindow* w); bool should_os_window_be_rendered(OSWindow* w); void wakeup_main_loop(void); void swap_window_buffers(OSWindow *w); @@ -276,3 +277,5 @@ void run_main_loop(tick_callback_fun, void*); void stop_main_loop(void); void os_window_update_size_increments(OSWindow *window); +void set_os_window_title_from_window(Window *w, OSWindow *os_window); +void update_os_window_title(OSWindow *os_window); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/tab_bar.py new/kitty-0.17.4/kitty/tab_bar.py --- old/kitty-0.17.3/kitty/tab_bar.py 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/tab_bar.py 2020-05-09 07:18:21.000000000 +0200 @@ -21,6 +21,8 @@ title: str is_active: bool needs_attention: bool + num_windows: int + layout_name: str class DrawData(NamedTuple): @@ -56,7 +58,7 @@ if tab.is_active and draw_data.active_title_template is not None: template = draw_data.active_title_template try: - title = template.format(title=tab.title, index=index) + title = template.format(title=tab.title, index=index, layout_name=tab.layout_name, num_windows=tab.num_windows) except Exception as e: if template not in template_failures: template_failures.add(template) @@ -84,7 +86,7 @@ screen.cursor.fg = 0 if not is_last: screen.cursor.bg = as_rgb(color_as_int(draw_data.inactive_bg)) - screen.draw(draw_data.sep) + screen.draw(draw_data.sep) screen.cursor.bg = 0 return end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/tabs.py new/kitty-0.17.4/kitty/tabs.py --- old/kitty-0.17.3/kitty/tabs.py 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/tabs.py 2020-05-09 07:18:21.000000000 +0200 @@ -18,7 +18,7 @@ from .fast_data_types import ( add_tab, attach_window, detach_window, get_boss, mark_tab_bar_dirty, next_window_id, remove_tab, remove_window, ring_bell, set_active_tab, - swap_tabs, x11_window_id + swap_tabs, sync_os_window_title, x11_window_id ) from .layout import ( Layout, Rect, create_layout_object_for, evict_cached_layouts @@ -138,6 +138,7 @@ self._last_used_layout = self._current_layout_name self.current_layout = self.create_layout_object(layout_name) self._current_layout_name = layout_name + self.mark_tab_bar_dirty() def startup(self, session_tab: 'SessionTab') -> None: for cmd in session_tab.windows: @@ -183,10 +184,13 @@ old_active_window.focus_changed(False) if new_active_window is not None: new_active_window.focus_changed(True) - tm = self.tab_manager_ref() - if tm is not None: - self.relayout_borders() - tm.mark_tab_bar_dirty() + self.relayout_borders() + self.mark_tab_bar_dirty() + + def mark_tab_bar_dirty(self) -> None: + tm = self.tab_manager_ref() + if tm is not None: + tm.mark_tab_bar_dirty() @property def active_window(self) -> Optional[Window]: @@ -206,7 +210,7 @@ if window is self.active_window: tm = self.tab_manager_ref() if tm is not None: - tm.mark_tab_bar_dirty() + tm.title_changed(self) def on_bell(self, window: Window) -> None: tm = self.tab_manager_ref() @@ -330,6 +334,7 @@ def _add_window(self, window: Window, location: Optional[str] = None) -> None: self.active_window_idx = self.current_layout.add_window(self.windows, window, self.active_window_idx, location) self.relayout_borders() + self.mark_tab_bar_dirty() def new_window( self, @@ -431,6 +436,7 @@ else: self.active_window_idx = active_window_idx self.relayout_borders() + self.mark_tab_bar_dirty() active_window = self.active_window if active_window: self.title_changed(active_window) @@ -639,6 +645,11 @@ def update_tab_bar_data(self) -> None: self.tab_bar.update(self.tab_bar_data) + def title_changed(self, tab: Tab) -> None: + self.mark_tab_bar_dirty() + if tab is self.active_tab: + sync_os_window_title(self.os_window_id) + def resize(self, only_tabs: bool = False) -> None: if not only_tabs: if not self.tab_bar_hidden: @@ -799,7 +810,10 @@ if w.needs_attention: needs_attention = True break - ans.append(TabBarData(title, t is at, needs_attention)) + ans.append(TabBarData( + title, t is at, needs_attention, + len(t), t.current_layout.name or '' + )) return ans def activate_tab_at(self, x: int) -> None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/kitty/utils.py new/kitty-0.17.4/kitty/utils.py --- old/kitty-0.17.3/kitty/utils.py 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/kitty/utils.py 2020-05-09 07:18:21.000000000 +0200 @@ -14,8 +14,8 @@ from functools import lru_cache from time import monotonic from typing import ( - Any, Callable, Dict, Generator, Iterable, List, NamedTuple, Optional, - Tuple, Union, cast + Any, Callable, Dict, Generator, Iterable, List, Match, NamedTuple, + Optional, Tuple, Union, cast ) from .constants import ( @@ -28,6 +28,20 @@ BASE = os.path.dirname(os.path.abspath(__file__)) +def expandvars(val: str, env: Dict[str, str] = {}) -> str: + + def sub(m: Match) -> str: + key = m.group(1) + result = env.get(key) + if result is None: + result = os.environ.get(key) + if result is None: + result = m.group() + return result + + return re.sub(r'\$\{(\S+?)\}', sub, val) + + def load_shaders(name: str) -> Tuple[str, str]: from .fast_data_types import GLSL_VERSION with open(os.path.join(BASE, '{}_vertex.glsl'.format(name))) as f: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/mypy-editor-integration new/kitty-0.17.4/mypy-editor-integration --- old/kitty-0.17.3/mypy-editor-integration 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/mypy-editor-integration 2020-05-09 07:18:21.000000000 +0200 @@ -1,14 +1,19 @@ #!/usr/bin/env python +import os import subprocess import sys -files = [x for x in sys.argv[1:] if not x.startswith('-')] +base = os.path.dirname(os.path.abspath(__file__)) +files = [os.path.relpath(x, base) for x in sys.argv[1:] if not x.startswith('-')] if not files: raise SystemExit(subprocess.Popen(['mypy'] + sys.argv[1:]).wait()) output = subprocess.run('dmypy run -- --follow-imports=error --show-column-numbers --no-color-output'.split(), stdout=subprocess.PIPE).stdout q = files[0] + ':' +rc = 0 for line in output.decode('utf-8').splitlines(): if line.startswith(q): print(line) + rc = 1 +raise SystemExit(rc) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/session.vim new/kitty-0.17.4/session.vim --- old/kitty-0.17.3/session.vim 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/session.vim 2020-05-09 07:18:21.000000000 +0200 @@ -10,7 +10,7 @@ set shiftwidth=4 set softtabstop=0 set smarttab -python <<endpython +python3 <<endpython import sys sys.path.insert(0, os.path.abspath('.')) import kitty diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitty-0.17.3/setup.py new/kitty-0.17.4/setup.py --- old/kitty-0.17.3/setup.py 2020-04-23 05:09:07.000000000 +0200 +++ new/kitty-0.17.4/setup.py 2020-05-09 07:18:21.000000000 +0200 @@ -349,7 +349,7 @@ raise SystemExit(ret) -def get_vcs_rev_defines() -> List[str]: +def get_vcs_rev_defines(env: Env) -> List[str]: ans = [] if os.path.exists('.git'): try: @@ -368,7 +368,7 @@ return ans -SPECIAL_SOURCES: Dict[str, Tuple[str, Union[List[str], Callable[[], Union[List[str], Iterator[str]]]]]] = { +SPECIAL_SOURCES: Dict[str, Tuple[str, Union[List[str], Callable[[Env], Union[List[str], Iterator[str]]]]]] = { 'kitty/parser_dump.c': ('kitty/parser.c', ['DUMP_COMMANDS']), 'kitty/data-types.c': ('kitty/data-types.c', get_vcs_rev_defines), } @@ -557,7 +557,7 @@ if is_special: src, defines_ = SPECIAL_SOURCES[src] if callable(defines_): - defines = defines_() + defines = defines_(kenv) cppflags.extend(map(define, defines)) else: cppflags.extend(map(define, defines_))