mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-09-01 06:41:30 +00:00
Wayland: Only launch child after OS Window achieves its final size
Avoids a bunch of SIGIWNCH during child startup as not all programs handle these correctly. Sadly adds about 0.1 seconds of latency to startup. Will have to look into reducing that. The Wayland protocol is *so badly* designed.
This commit is contained in:
parent
f5314cb862
commit
adf5917325
8 changed files with 52 additions and 16 deletions
|
|
@ -316,6 +316,7 @@ def generate_wrappers(glfw_header: str) -> None:
|
|||
void glfwWaylandRedrawCSDWindowTitle(GLFWwindow *handle)
|
||||
void glfwWaylandSetupLayerShellForNextWindow(GLFWLayerShellConfig c)
|
||||
pid_t glfwWaylandCompositorPID(void)
|
||||
bool glfwWaylandWindowFullyCreated(GLFWwindow *handle)
|
||||
unsigned long long glfwDBusUserNotify(const char *app_name, const char* icon, const char *summary, const char *body, \
|
||||
const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *data)
|
||||
void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler)
|
||||
|
|
|
|||
6
glfw/wl_platform.h
vendored
6
glfw/wl_platform.h
vendored
|
|
@ -168,7 +168,10 @@ typedef struct _GLFWwindowWayland
|
|||
struct wp_fractional_scale_v1 *wp_fractional_scale_v1;
|
||||
struct wp_viewport *wp_viewport;
|
||||
struct org_kde_kwin_blur *org_kde_kwin_blur;
|
||||
bool has_blur, expect_scale_from_compositor;
|
||||
bool has_blur, expect_scale_from_compositor, window_fully_created;
|
||||
struct {
|
||||
bool surface_configured, fractional_scale_received, preferred_scale_received;
|
||||
} once;
|
||||
struct {
|
||||
GLFWLayerShellConfig config;
|
||||
struct zwlr_layer_surface_v1* zwlr_layer_surface_v1;
|
||||
|
|
@ -243,7 +246,6 @@ typedef struct _GLFWwindowWayland
|
|||
struct {
|
||||
unsigned int x, y;
|
||||
} axis_discrete_count;
|
||||
bool surface_configured_once;
|
||||
|
||||
uint32_t pending_state;
|
||||
struct {
|
||||
|
|
|
|||
29
glfw/wl_window.c
vendored
29
glfw/wl_window.c
vendored
|
|
@ -285,7 +285,7 @@ setCursorImage(_GLFWwindow* window, bool on_theme_change) {
|
|||
|
||||
static bool
|
||||
checkScaleChange(_GLFWwindow* window) {
|
||||
if (window->wl.fractional_scale || window->wl.integer_scale.preferred) return false;
|
||||
if (window->wl.expect_scale_from_compositor) return false;
|
||||
unsigned int scale = 1, monitorScale;
|
||||
int i;
|
||||
|
||||
|
|
@ -493,9 +493,11 @@ static void surfaceHandleLeave(void *data,
|
|||
static void
|
||||
surface_preferred_buffer_scale(void *data, struct wl_surface *surface UNUSED, int32_t scale) {
|
||||
_GLFWwindow* window = data;
|
||||
if ((int)window->wl.integer_scale.preferred == scale) return;
|
||||
window->wl.once.preferred_scale_received = true;
|
||||
if ((int)window->wl.integer_scale.preferred == scale && window->wl.window_fully_created) return;
|
||||
debug("Preferred integer buffer scale changed to: %d\n", scale);
|
||||
window->wl.integer_scale.preferred = scale;
|
||||
window->wl.window_fully_created = true;
|
||||
if (!window->wl.fractional_scale) apply_scale_changes(window, true, true);
|
||||
}
|
||||
|
||||
|
|
@ -518,9 +520,12 @@ static const struct wl_surface_listener surfaceListener = {
|
|||
static void
|
||||
fractional_scale_preferred_scale(void *data, struct wp_fractional_scale_v1 *wp_fractional_scale_v1 UNUSED, uint32_t scale) {
|
||||
_GLFWwindow *window = data;
|
||||
if (scale == window->wl.fractional_scale) return;
|
||||
window->wl.once.fractional_scale_received = true;
|
||||
if (scale == window->wl.fractional_scale && window->wl.window_fully_created) return;
|
||||
debug("Fractional scale requested: %u/120 = %.2f\n", scale, scale / 120.);
|
||||
window->wl.fractional_scale = scale;
|
||||
// Hyprland sends a fraction scale = 1 event before configuring the xdg surface and then another after with the correct scale
|
||||
window->wl.window_fully_created = window->wl.once.surface_configured || scale != 120;
|
||||
apply_scale_changes(window, true, true);
|
||||
}
|
||||
|
||||
|
|
@ -565,6 +570,7 @@ static bool createSurface(_GLFWwindow* window,
|
|||
}
|
||||
}
|
||||
}
|
||||
window->wl.window_fully_created = !window->wl.expect_scale_from_compositor;
|
||||
if (_glfw.wl.org_kde_kwin_blur_manager && wndconfig->blur_radius > 0) _glfwPlatformSetWindowBlur(window, wndconfig->blur_radius);
|
||||
|
||||
window->wl.integer_scale.deduced = scale;
|
||||
|
|
@ -699,10 +705,10 @@ apply_xdg_configure_changes(_GLFWwindow *window) {
|
|||
uint32_t new_states = window->wl.pending.toplevel_states;
|
||||
int width = window->wl.pending.width;
|
||||
int height = window->wl.pending.height;
|
||||
if (!window->wl.surface_configured_once) {
|
||||
if (!window->wl.once.surface_configured) {
|
||||
window->swaps_disallowed = false;
|
||||
window->wl.waiting_for_swap_to_commit = true;
|
||||
window->wl.surface_configured_once = true;
|
||||
window->wl.once.surface_configured = true;
|
||||
}
|
||||
|
||||
if (new_states != window->wl.current.toplevel_states ||
|
||||
|
|
@ -734,7 +740,7 @@ apply_xdg_configure_changes(_GLFWwindow *window) {
|
|||
} else {
|
||||
ensure_csd_resources(window);
|
||||
}
|
||||
debug("final window content size: %dx%d resized: %d\n", width, height, resized);
|
||||
debug("Final window content size: %dx%d resized: %d\n", width, height, resized);
|
||||
}
|
||||
|
||||
inform_compositor_of_window_geometry(window, "configure");
|
||||
|
|
@ -852,10 +858,10 @@ static void
|
|||
layer_surface_handle_configure(void* data, struct zwlr_layer_surface_v1* surface, uint32_t serial, uint32_t width, uint32_t height) {
|
||||
debug("Layer shell configure event: width: %u height: %u\n", width, height);
|
||||
_GLFWwindow* window = data;
|
||||
if (!window->wl.surface_configured_once) {
|
||||
if (!window->wl.once.surface_configured) {
|
||||
window->swaps_disallowed = false;
|
||||
window->wl.waiting_for_swap_to_commit = true;
|
||||
window->wl.surface_configured_once = true;
|
||||
window->wl.once.surface_configured = true;
|
||||
}
|
||||
GLFWvidmode m = {0};
|
||||
if (window->wl.monitorsCount) _glfwPlatformGetVideoMode(window->wl.monitors[0], &m);
|
||||
|
|
@ -1431,7 +1437,7 @@ void _glfwPlatformHideWindow(_GLFWwindow* window)
|
|||
xdg_surface_destroy(window->wl.xdg.surface);
|
||||
window->wl.xdg.toplevel = NULL;
|
||||
window->wl.xdg.surface = NULL;
|
||||
window->wl.surface_configured_once = false;
|
||||
window->wl.once.surface_configured = false;
|
||||
window->swaps_disallowed = true;
|
||||
}
|
||||
window->wl.visible = false;
|
||||
|
|
@ -2579,3 +2585,8 @@ GLFWAPI void glfwWaylandSetupLayerShellForNextWindow(GLFWLayerShellConfig c) {
|
|||
if (layer_shell_config_for_next_window.output_name && !layer_shell_config_for_next_window.output_name[0]) layer_shell_config_for_next_window.output_name = NULL;
|
||||
if (layer_shell_config_for_next_window.output_name) layer_shell_config_for_next_window.output_name = strdup(layer_shell_config_for_next_window.output_name);
|
||||
}
|
||||
|
||||
GLFWAPI bool glfwWaylandWindowFullyCreated(GLFWwindow *handle) {
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
return window->wl.window_fully_created;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1574,3 +1574,4 @@ def replace_c0_codes_except_nl_space_tab(text: str) -> str:...
|
|||
def replace_c0_codes_except_nl_space_tab(text: Union[bytes, memoryview, bytearray]) -> bytes:...
|
||||
def terminfo_data() -> bytes:...
|
||||
def wayland_compositor_pid() -> int:...
|
||||
def window_fully_created(kitty_window_id: int) -> bool: ...
|
||||
|
|
|
|||
3
kitty/glfw-wrapper.c
generated
3
kitty/glfw-wrapper.c
generated
|
|
@ -485,6 +485,9 @@ load_glfw(const char* path) {
|
|||
*(void **) (&glfwWaylandCompositorPID_impl) = dlsym(handle, "glfwWaylandCompositorPID");
|
||||
if (glfwWaylandCompositorPID_impl == NULL) dlerror(); // clear error indicator
|
||||
|
||||
*(void **) (&glfwWaylandWindowFullyCreated_impl) = dlsym(handle, "glfwWaylandWindowFullyCreated");
|
||||
if (glfwWaylandWindowFullyCreated_impl == NULL) dlerror(); // clear error indicator
|
||||
|
||||
*(void **) (&glfwDBusUserNotify_impl) = dlsym(handle, "glfwDBusUserNotify");
|
||||
if (glfwDBusUserNotify_impl == NULL) dlerror(); // clear error indicator
|
||||
|
||||
|
|
|
|||
4
kitty/glfw-wrapper.h
generated
4
kitty/glfw-wrapper.h
generated
|
|
@ -2316,6 +2316,10 @@ typedef pid_t (*glfwWaylandCompositorPID_func)(void);
|
|||
GFW_EXTERN glfwWaylandCompositorPID_func glfwWaylandCompositorPID_impl;
|
||||
#define glfwWaylandCompositorPID glfwWaylandCompositorPID_impl
|
||||
|
||||
typedef bool (*glfwWaylandWindowFullyCreated_func)(GLFWwindow*);
|
||||
GFW_EXTERN glfwWaylandWindowFullyCreated_func glfwWaylandWindowFullyCreated_impl;
|
||||
#define glfwWaylandWindowFullyCreated glfwWaylandWindowFullyCreated_impl
|
||||
|
||||
typedef unsigned long long (*glfwDBusUserNotify_func)(const char*, const char*, const char*, const char*, const char*, int32_t, GLFWDBusnotificationcreatedfun, void*);
|
||||
GFW_EXTERN glfwDBusUserNotify_func glfwDBusUserNotify_impl;
|
||||
#define glfwDBusUserNotify glfwDBusUserNotify_impl
|
||||
|
|
|
|||
11
kitty/glfw.c
11
kitty/glfw.c
|
|
@ -2208,6 +2208,16 @@ make_x11_window_a_dock_window(PyObject *self UNUSED, PyObject *args UNUSED) {
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
window_fully_created(PyObject *self UNUSED, PyObject *wid) {
|
||||
// On Wayland a window does not receive its final size by the time glfwCreateWindow returns
|
||||
if (!global_state.is_wayland) Py_RETURN_TRUE;
|
||||
OSWindow *w = os_window_for_kitty_window(PyLong_AsUnsignedLongLong(wid));
|
||||
if (!w || !w->handle) Py_RETURN_FALSE;
|
||||
if (glfwWaylandWindowFullyCreated(w->handle)) Py_RETURN_TRUE;
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
// Boilerplate {{{
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
|
|
@ -2227,6 +2237,7 @@ static PyMethodDef module_methods[] = {
|
|||
METHODB(glfw_window_hint, METH_VARARGS),
|
||||
METHODB(x11_display, METH_NOARGS),
|
||||
METHODB(wayland_compositor_pid, METH_NOARGS),
|
||||
METHODB(window_fully_created, METH_O),
|
||||
METHODB(get_click_interval, METH_NOARGS),
|
||||
METHODB(x11_window_id, METH_O),
|
||||
METHODB(make_x11_window_a_dock_window, METH_VARARGS),
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ from .fast_data_types import (
|
|||
update_window_title,
|
||||
update_window_visibility,
|
||||
wakeup_main_loop,
|
||||
window_fully_created,
|
||||
)
|
||||
from .keys import keyboard_mode_name, mod_mask
|
||||
from .notify import (
|
||||
|
|
@ -554,7 +555,7 @@ class Window:
|
|||
self.actions_on_removal: List[Callable[['Window'], None]] = []
|
||||
self.current_marker_spec: Optional[Tuple[str, Union[str, Tuple[Tuple[int, str], ...]]]] = None
|
||||
self.kitten_result_processors: List[Callable[['Window', Any], None]] = []
|
||||
self.pty_resized_once = False
|
||||
self.child_is_launched = False
|
||||
self.last_reported_pty_size = (-1, -1, -1, -1)
|
||||
self.needs_attention = False
|
||||
self.ignore_focus_changes = self.initial_ignore_focus_changes
|
||||
|
|
@ -836,13 +837,15 @@ class Window:
|
|||
if current_pty_size != self.last_reported_pty_size:
|
||||
boss = get_boss()
|
||||
boss.child_monitor.resize_pty(self.id, *current_pty_size)
|
||||
if boss.args.debug_rendering:
|
||||
print(f'SIGWINCH sent to child in window: {self.id} with size: {current_pty_size}', file=sys.stderr)
|
||||
self.last_resized_at = monotonic()
|
||||
if not self.pty_resized_once:
|
||||
self.pty_resized_once = True
|
||||
if not self.child_is_launched and window_fully_created(self.id):
|
||||
self.child.mark_terminal_ready()
|
||||
self.child_is_launched = True
|
||||
update_ime_position = True
|
||||
if boss.args.debug_rendering:
|
||||
print(f'Child launched {monotonic() - self.started_at:.2f} seconds after window creation')
|
||||
if boss.args.debug_rendering and self.child_is_launched:
|
||||
print(f'SIGWINCH sent to child in window: {self.id} with size: {current_pty_size}', file=sys.stderr)
|
||||
self.last_reported_pty_size = current_pty_size
|
||||
else:
|
||||
mark_os_window_dirty(self.os_window_id)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue