From 5b547d9b06a448c1d984d946ff9303f43d505690 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 26 Oct 2018 07:38:47 +0530 Subject: [PATCH] Initial attempt at supporting Wayland frame events Does not actually work because the wayland frame callback is not called at all, fo rsome reason I cannot determine. --- glfw/glfw.py | 3 ++- glfw/wl_window.c | 21 +++++++++++++++++++++ kitty/child-monitor.c | 7 +++++++ kitty/glfw-wrapper.c | 2 ++ kitty/glfw-wrapper.h | 6 +++++- kitty/glfw.c | 19 ++++++++++++++++++- kitty/state.h | 3 +++ 7 files changed, 58 insertions(+), 3 deletions(-) diff --git a/glfw/glfw.py b/glfw/glfw.py index 3b89ba38f..1bbfd0b43 100755 --- a/glfw/glfw.py +++ b/glfw/glfw.py @@ -211,6 +211,7 @@ def generate_wrappers(glfw_header): void glfwSetX11SelectionString(const char* string) const char* glfwGetX11SelectionString(void) int glfwGetXKBScancode(const char* key_name, int case_sensitive) + void glfwRequestWaylandFrameEvent(GLFWwindow *handle, unsigned long long id, GLFWwaylandframecallbackfunc callback) '''.splitlines(): if line: functions.append(Function(line.strip(), check_fail=False)) @@ -229,7 +230,7 @@ def generate_wrappers(glfw_header): typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int); typedef int (* GLFWapplicationshouldhandlereopenfun)(int); typedef int (* GLFWcocoatogglefullscreenfun)(GLFWwindow*); - +typedef void (*GLFWwaylandframecallbackfunc)(unsigned long long id); {} const char* load_glfw(const char* path); diff --git a/glfw/wl_window.c b/glfw/wl_window.c index 295afcfc6..22140275a 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -1929,6 +1929,18 @@ _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c, int glfw_xkb_update_ime_state(w, &_glfw.wl.xkb, which, a, b, c, d); } +struct frame_callback_data { + unsigned long long id; + void(*callback)(unsigned long long id); +}; + +static void +frame_handle_redraw(void *data, struct wl_callback *callback, uint32_t time) { + struct frame_callback_data *cbdata = (struct frame_callback_data*)data; + cbdata->callback(cbdata->id); + free(cbdata); + wl_callback_destroy(callback); +} ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// @@ -1950,3 +1962,12 @@ GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* handle) GLFWAPI int glfwGetXKBScancode(const char* keyName, GLFWbool caseSensitive) { return glfw_xkb_keysym_from_name(keyName, caseSensitive); } + +GLFWAPI void glfwRequestWaylandFrameEvent(GLFWwindow *handle, unsigned long long id, void(*callback)(unsigned long long id)) { + _GLFWwindow* window = (_GLFWwindow*) handle; + struct frame_callback_data *cbdata = malloc(sizeof(struct frame_callback_data)); + cbdata->callback = callback; cbdata->id = id; + static const struct wl_callback_listener frame_listener = { .done = frame_handle_redraw }; + struct wl_callback *wlcallback = wl_surface_frame(window->wl.surface); + wl_callback_add_listener(wlcallback, &frame_listener, cbdata); +} diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index 0e01aabe3..36e675b9c 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -623,6 +623,7 @@ render_os_window(OSWindow *os_window, double now, unsigned int active_window_id, os_window->last_active_tab = os_window->active_tab; os_window->last_num_tabs = os_window->num_tabs; os_window->last_active_window_id = active_window_id; os_window->focused_at_last_render = os_window->is_focused; os_window->is_damaged = false; + if (global_state.is_wayland) os_window->wayland_render_state = RENDER_FRAME_NOT_REQUESTED; #undef WD #undef TD } @@ -638,6 +639,12 @@ render(double now) { for (size_t i = 0; i < global_state.num_os_windows; i++) { OSWindow *w = global_state.os_windows + i; if (!w->num_tabs || !should_os_window_be_rendered(w)) continue; + if (global_state.is_wayland && w->wayland_render_state != RENDER_FRAME_READY) { + if (w->wayland_render_state == RENDER_FRAME_NOT_REQUESTED) { + wayland_request_frame_render(w); + } + return; + } bool needs_render = w->is_damaged; make_os_window_context_current(w); if (w->viewport_size_dirty) { diff --git a/kitty/glfw-wrapper.c b/kitty/glfw-wrapper.c index fc25dda53..0b1e51f8c 100644 --- a/kitty/glfw-wrapper.c +++ b/kitty/glfw-wrapper.c @@ -380,6 +380,8 @@ load_glfw(const char* path) { *(void **) (&glfwGetXKBScancode_impl) = dlsym(handle, "glfwGetXKBScancode"); + *(void **) (&glfwRequestWaylandFrameEvent_impl) = dlsym(handle, "glfwRequestWaylandFrameEvent"); + return NULL; } diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index b13ee1f54..1dff47962 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -1387,7 +1387,7 @@ typedef struct GLFWgamepadstate typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int); typedef int (* GLFWapplicationshouldhandlereopenfun)(int); typedef int (* GLFWcocoatogglefullscreenfun)(GLFWwindow*); - +typedef void (*GLFWwaylandframecallbackfunc)(unsigned long long id); typedef int (*glfwInit_func)(); glfwInit_func glfwInit_impl; #define glfwInit glfwInit_impl @@ -1892,4 +1892,8 @@ typedef int (*glfwGetXKBScancode_func)(const char*, int); glfwGetXKBScancode_func glfwGetXKBScancode_impl; #define glfwGetXKBScancode glfwGetXKBScancode_impl +typedef void (*glfwRequestWaylandFrameEvent_func)(GLFWwindow*, unsigned long long, GLFWwaylandframecallbackfunc); +glfwRequestWaylandFrameEvent_func glfwRequestWaylandFrameEvent_impl; +#define glfwRequestWaylandFrameEvent glfwRequestWaylandFrameEvent_impl + const char* load_glfw(const char* path); diff --git a/kitty/glfw.c b/kitty/glfw.c index d679b0706..e0e0667dd 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -559,7 +559,7 @@ create_os_window(PyObject UNUSED *self, PyObject *args) { w->fonts_data = fonts_data; w->shown_once = true; push_focus_history(w); - glfwSwapInterval(OPT(sync_to_monitor) ? 1 : 0); + glfwSwapInterval(OPT(sync_to_monitor) && !global_state.is_wayland ? 1 : 0); #ifdef __APPLE__ if (OPT(macos_option_as_alt)) glfwSetCocoaTextInputFilter(glfw_window, filter_option); glfwSetCocoaToggleFullscreenIntercept(glfw_window, intercept_cocoa_fullscreen); @@ -982,6 +982,23 @@ get_cocoa_key_equivalent(int key, int mods, unsigned short *cocoa_key, int *coco glfwGetCocoaKeyEquivalent(key, mods, cocoa_key, cocoa_mods); } #endif + +void +wayland_frame_request_callback(id_type os_window_id) { + for (size_t i = 0; i < global_state.num_os_windows; i++) { + if (global_state.os_windows[i].id == os_window_id) { + global_state.os_windows[i].wayland_render_state = RENDER_FRAME_READY; + break; + } + } +} + +void +wayland_request_frame_render(OSWindow *w) { + glfwRequestWaylandFrameEvent(w->handle, w->id, wayland_frame_request_callback); + w->wayland_render_state = RENDER_FRAME_REQUESTED; +} + // Boilerplate {{{ static PyMethodDef module_methods[] = { diff --git a/kitty/state.h b/kitty/state.h index ccb0bc2e6..ecff3d054 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -98,6 +98,7 @@ typedef struct { bool is_set; } OSWindowGeometry; +enum WAYLAND_RENDER_STATE { RENDER_FRAME_NOT_REQUESTED, RENDER_FRAME_REQUESTED, RENDER_FRAME_READY }; typedef struct { void *handle; @@ -127,6 +128,7 @@ typedef struct { FONTS_DATA_HANDLE fonts_data; id_type temp_font_group_id; double pending_scroll_pixels; + enum WAYLAND_RENDER_STATE wayland_render_state; } OSWindow; @@ -204,3 +206,4 @@ typedef enum { void set_cocoa_pending_action(CocoaPendingAction action); bool application_quit_requested(); #endif +void wayland_request_frame_render(OSWindow *w);