diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m index 9b66956d4..bd0463589 100644 --- a/glfw/cocoa_window.m +++ b/glfw/cocoa_window.m @@ -1454,15 +1454,11 @@ is_ascii_control_char(char x) { } void _glfwPlatformUpdateIMEState(_GLFWwindow *w, const GLFWIMEUpdateEvent *ev) { - [w->ns.view updateIMEStateFor: ev->type focused:(bool)ev->focused left:(CGFloat)ev->cursor.left top:(CGFloat)ev->cursor.top cellWidth:(CGFloat)ev->cursor.width cellHeight:(CGFloat)ev->cursor.height]; + [w->ns.view updateIMEStateFor: ev->type focused:(bool)ev->focused]; } - (void)updateIMEStateFor:(GLFWIMEUpdateType)which focused:(bool)focused - left:(CGFloat)left - top:(CGFloat)top - cellWidth:(CGFloat)cellWidth - cellHeight:(CGFloat)cellHeight { if (which == GLFW_IME_UPDATE_FOCUS && !focused && [self hasMarkedText] && window) { [input_context discardMarkedText]; @@ -1472,16 +1468,7 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, const GLFWIMEUpdateEvent *ev) { _glfw.ns.text[0] = 0; } if (which != GLFW_IME_UPDATE_CURSOR_POSITION) return; - left /= window->ns.xscale; - top /= window->ns.yscale; - cellWidth /= window->ns.xscale; - cellHeight /= window->ns.yscale; - debug_key("updateIMEPosition: left=%f, top=%f, width=%f, height=%f\n", left, top, cellWidth, cellHeight); - const NSRect frame = [window->ns.view frame]; - const NSRect rectInView = NSMakeRect(left, - frame.size.height - top - cellHeight, - cellWidth, cellHeight); - markedRect = [window->ns.object convertRectToScreen: rectInView]; + if (_glfwPlatformWindowFocused(window)) [[window->ns.view inputContext] invalidateCharacterCoordinates]; } @@ -1507,6 +1494,21 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, const GLFWIMEUpdateEvent *ev) { actualRange:(NSRangePointer)actualRange { (void)range; (void)actualRange; + if (_glfw.callbacks.get_ime_cursor_position) { + GLFWIMEUpdateEvent ev = { .type = GLFW_IME_UPDATE_CURSOR_POSITION }; + if (_glfw.callbacks.get_ime_cursor_position((GLFWwindow*)window, &ev)) { + const CGFloat left = (CGFloat)ev.cursor.left / window->ns.xscale; + const CGFloat top = (CGFloat)ev.cursor.top / window->ns.yscale; + const CGFloat cellWidth = (CGFloat)ev.cursor.width / window->ns.xscale; + const CGFloat cellHeight = (CGFloat)ev.cursor.height / window->ns.yscale; + debug_key("updateIMEPosition: left=%f, top=%f, width=%f, height=%f\n", left, top, cellWidth, cellHeight); + const NSRect frame = [window->ns.view frame]; + const NSRect rectInView = NSMakeRect(left, + frame.size.height - top - cellHeight, + cellWidth, cellHeight); + markedRect = [window->ns.object convertRectToScreen: rectInView]; + } + } return markedRect; } diff --git a/glfw/glfw3.h b/glfw/glfw3.h index 3d02e5448..35507f9b3 100644 --- a/glfw/glfw3.h +++ b/glfw/glfw3.h @@ -1732,6 +1732,7 @@ typedef enum { } GLFWClipboardType; typedef GLFWDataChunk (* GLFWclipboarditerfun)(const char *mime_type, void *iter, GLFWClipboardType ctype); typedef bool (* GLFWclipboardwritedatafun)(void *object, const char *data, size_t sz); +typedef bool (* GLFWimecursorpositionfun)(GLFWwindow *window, GLFWIMEUpdateEvent *ev); /*! @brief Video mode type. * @@ -1891,6 +1892,7 @@ GLFWAPI void glfwRemoveTimer(unsigned long long); GLFWAPI GLFWdrawtextfun glfwSetDrawTextFunction(GLFWdrawtextfun function); GLFWAPI GLFWcurrentselectionfun glfwSetCurrentSelectionCallback(GLFWcurrentselectionfun callback); GLFWAPI GLFWhascurrentselectionfun glfwSetHasCurrentSelectionCallback(GLFWhascurrentselectionfun callback); +GLFWAPI GLFWimecursorpositionfun glfwSetIMECursorPositionCallback(GLFWimecursorpositionfun callback); /*! @brief Terminates the GLFW library. * diff --git a/glfw/init.c b/glfw/init.c index d9fd00b75..d9fff1ae1 100644 --- a/glfw/init.c +++ b/glfw/init.c @@ -402,3 +402,10 @@ GLFWAPI GLFWhascurrentselectionfun glfwSetHasCurrentSelectionCallback(GLFWhascur _GLFW_SWAP_POINTERS(_glfw.callbacks.has_current_selection, cbfun); return cbfun; } + +GLFWAPI GLFWimecursorpositionfun glfwSetIMECursorPositionCallback(GLFWimecursorpositionfun cbfun) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(_glfw.callbacks.get_ime_cursor_position, cbfun); + return cbfun; +} diff --git a/glfw/internal.h b/glfw/internal.h index fe4125a5f..f4044f6e7 100644 --- a/glfw/internal.h +++ b/glfw/internal.h @@ -635,6 +635,7 @@ struct _GLFWlibrary GLFWdrawtextfun draw_text; GLFWcurrentselectionfun get_current_selection; GLFWhascurrentselectionfun has_current_selection; + GLFWimecursorpositionfun get_ime_cursor_position; } callbacks; diff --git a/kitty/glfw-wrapper.c b/kitty/glfw-wrapper.c index 6ec499bd1..784615412 100644 --- a/kitty/glfw-wrapper.c +++ b/kitty/glfw-wrapper.c @@ -44,6 +44,9 @@ load_glfw(const char* path) { *(void **) (&glfwSetHasCurrentSelectionCallback_impl) = dlsym(handle, "glfwSetHasCurrentSelectionCallback"); if (glfwSetHasCurrentSelectionCallback_impl == NULL) fail("Failed to load glfw function glfwSetHasCurrentSelectionCallback with error: %s", dlerror()); + *(void **) (&glfwSetIMECursorPositionCallback_impl) = dlsym(handle, "glfwSetIMECursorPositionCallback"); + if (glfwSetIMECursorPositionCallback_impl == NULL) fail("Failed to load glfw function glfwSetIMECursorPositionCallback with error: %s", dlerror()); + *(void **) (&glfwTerminate_impl) = dlsym(handle, "glfwTerminate"); if (glfwTerminate_impl == NULL) fail("Failed to load glfw function glfwTerminate with error: %s", dlerror()); diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index d847480b2..501220d9b 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -1470,6 +1470,7 @@ typedef enum { } GLFWClipboardType; typedef GLFWDataChunk (* GLFWclipboarditerfun)(const char *mime_type, void *iter, GLFWClipboardType ctype); typedef bool (* GLFWclipboardwritedatafun)(void *object, const char *data, size_t sz); +typedef bool (* GLFWimecursorpositionfun)(GLFWwindow *window, GLFWIMEUpdateEvent *ev); /*! @brief Video mode type. * @@ -1667,6 +1668,10 @@ typedef GLFWhascurrentselectionfun (*glfwSetHasCurrentSelectionCallback_func)(GL GFW_EXTERN glfwSetHasCurrentSelectionCallback_func glfwSetHasCurrentSelectionCallback_impl; #define glfwSetHasCurrentSelectionCallback glfwSetHasCurrentSelectionCallback_impl +typedef GLFWimecursorpositionfun (*glfwSetIMECursorPositionCallback_func)(GLFWimecursorpositionfun); +GFW_EXTERN glfwSetIMECursorPositionCallback_func glfwSetIMECursorPositionCallback_impl; +#define glfwSetIMECursorPositionCallback glfwSetIMECursorPositionCallback_impl + typedef void (*glfwTerminate_func)(void); GFW_EXTERN glfwTerminate_func glfwTerminate_impl; #define glfwTerminate glfwTerminate_impl diff --git a/kitty/glfw.c b/kitty/glfw.c index e72a87c35..784a3f347 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -507,6 +507,26 @@ has_current_selection(void) { return ans; } +void prepare_ime_position_update_event(OSWindow *osw, Window *w, Screen *screen, GLFWIMEUpdateEvent *ev); + +static bool +get_ime_cursor_position(GLFWwindow *glfw_window, GLFWIMEUpdateEvent *ev) { + if (!set_callback_window(glfw_window)) return false; + bool ans = false; + OSWindow *osw = global_state.callback_os_window; + if (osw && osw->is_focused && is_window_ready_for_callbacks()) { + Tab *tab = osw->tabs + osw->active_tab; + Window *w = tab->windows + tab->active_window; + Screen *screen = w->render_data.screen; + if (screen) { + prepare_ime_position_update_event(osw, w, screen, ev); + ans = true; + } + } + global_state.callback_os_window = NULL; + return ans; +} + static void get_window_dpi(GLFWwindow *w, double *x, double *y); @@ -832,6 +852,7 @@ create_os_window(PyObject UNUSED *self, PyObject *args, PyObject *kw) { glfwSetApplicationCloseCallback(application_close_requested_callback); glfwSetCurrentSelectionCallback(get_current_selection); glfwSetHasCurrentSelectionCallback(has_current_selection); + glfwSetIMECursorPositionCallback(get_ime_cursor_position); #ifdef __APPLE__ cocoa_set_activation_policy(OPT(macos_hide_from_tasks)); glfwWindowHint(GLFW_COCOA_GRAPHICS_SWITCHING, true); diff --git a/kitty/keys.c b/kitty/keys.c index f433221c0..24f4a714d 100644 --- a/kitty/keys.c +++ b/kitty/keys.c @@ -102,8 +102,8 @@ update_ime_focus(OSWindow *osw, bool focused) { } void -update_ime_position(Window* w, Screen *screen) { - unsigned int cell_width = global_state.callback_os_window->fonts_data->cell_width, cell_height = global_state.callback_os_window->fonts_data->cell_height; +prepare_ime_position_update_event(OSWindow *osw, Window *w, Screen *screen, GLFWIMEUpdateEvent *ev) { + unsigned int cell_width = osw->fonts_data->cell_width, cell_height = osw->fonts_data->cell_height; unsigned int left = w->geometry.left, top = w->geometry.top; if (screen_is_overlay_active(screen)) { left += screen->overlay_line.cursor_x * cell_width; @@ -112,8 +112,15 @@ update_ime_position(Window* w, Screen *screen) { left += screen->cursor->x * cell_width; top += screen->cursor->y * cell_height; } + ev->cursor.left = left; ev->cursor.top = top; ev->cursor.width = cell_width; ev->cursor.height = cell_height; +} + +void +update_ime_position(Window* w UNUSED, Screen *screen UNUSED) { GLFWIMEUpdateEvent ev = { .type = GLFW_IME_UPDATE_CURSOR_POSITION }; - ev.cursor.left = left; ev.cursor.top = top; ev.cursor.width = cell_width; ev.cursor.height = cell_height; +#ifndef __APPLE__ + prepare_ime_position_update_event(global_state.callback_os_window, w, screen, &ev); +#endif glfwUpdateIMEState(global_state.callback_os_window->handle, &ev); }