From 28ea48ea38e91e6ed84155b7bdcc4e452607b0f5 Mon Sep 17 00:00:00 2001 From: Daijiro Fukuda Date: Tue, 26 Apr 2022 18:24:57 +0900 Subject: [PATCH] X11: Change default style to over-the-spot In over-the-spot mode, almost all APIs are disabled. Applications only need to specify the candidate window position by `glfwSetPreeditCursorPos`. We can change style to on-the-spot by setting "on-the-spot" to the environmental variable `IM_STYLE`. However on-the-spot mode of X11 has the following problems: * Status APIs don't work because status callbacks don't work (at least in my ibus environment) * Can't specify the candidate window position --- src/x11_init.c | 7 +++- src/x11_platform.h | 5 +++ src/x11_window.c | 82 +++++++++++++++++++++++++++++++++++----------- 3 files changed, 74 insertions(+), 20 deletions(-) diff --git a/src/x11_init.c b/src/x11_init.c index 2031016f..2fbde908 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -440,13 +440,18 @@ static GLFWbool hasUsableInputMethodStyle(void) { GLFWbool found = GLFW_FALSE; XIMStyles* styles = NULL; + const char* imStyle = getenv("IM_STYLE"); if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) != NULL) return GLFW_FALSE; + _glfw.x11.imStyle = STYLE_OVERTHESPOT; + if (imStyle && strcmp(imStyle, "on-the-spot") == 0) + _glfw.x11.imStyle = STYLE_ONTHESPOT; + for (unsigned int i = 0; i < styles->count_styles; i++) { - if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) + if (styles->supported_styles[i] == _glfw.x11.imStyle) { found = GLFW_TRUE; break; diff --git a/src/x11_platform.h b/src/x11_platform.h index 33ca3ba8..2bd88744 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -91,6 +91,9 @@ #define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 #define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3 +#define STYLE_OVERTHESPOT (XIMPreeditNothing | XIMStatusNothing) +#define STYLE_ONTHESPOT (XIMPreeditCallbacks | XIMStatusCallbacks) + typedef XID GLXWindow; typedef XID GLXDrawable; typedef struct __GLXFBConfig* GLXFBConfig; @@ -584,6 +587,8 @@ typedef struct _GLFWlibraryX11 XContext context; // XIM input method XIM im; + // XIM input method style + XIMStyle imStyle; // Most recent error code received by X error handler int errorCode; // Primary selection string (while the primary selection is owned) diff --git a/src/x11_window.c b/src/x11_window.c index d7603a82..f20c2af4 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1461,6 +1461,11 @@ static void processEvent(XEvent *event) if (chars != buffer) _glfw_free(chars); + + // In the case of over-the-spot, need to update the position here + // because preedit-callbacks can not be used. + if (_glfw.x11.imStyle == STYLE_OVERTHESPOT) + _ximChangeCursorPosition(window->x11.ic, window); } } else @@ -2085,28 +2090,54 @@ void _glfwCreateInputContextX11(_GLFWwindow* window) XIMCallback callback; callback.callback = (XIMProc) inputContextDestroyCallback; callback.client_data = (XPointer) window; - XVaNestedList preeditList = _createXIMPreeditCallbacks(window); - XVaNestedList statusList = _createXIMStatusCallbacks(window); - window->x11.ic = XCreateIC(_glfw.x11.im, - XNInputStyle, - XIMPreeditCallbacks | XIMStatusCallbacks, - XNClientWindow, - window->x11.handle, - XNFocusWindow, - window->x11.handle, - XNPreeditAttributes, - preeditList, - XNStatusAttributes, - statusList, - XNDestroyCallback, - &callback, - NULL); - - XFree(preeditList); - XFree(statusList); window->x11.imeFocus = GLFW_FALSE; + if (_glfw.x11.imStyle == STYLE_ONTHESPOT) + { + XVaNestedList preeditList = _createXIMPreeditCallbacks(window); + XVaNestedList statusList = _createXIMStatusCallbacks(window); + + window->x11.ic = XCreateIC(_glfw.x11.im, + XNInputStyle, + _glfw.x11.imStyle, + XNClientWindow, + window->x11.handle, + XNFocusWindow, + window->x11.handle, + XNPreeditAttributes, + preeditList, + XNStatusAttributes, + statusList, + XNDestroyCallback, + &callback, + NULL); + + XFree(preeditList); + XFree(statusList); + } + else if (_glfw.x11.imStyle == STYLE_OVERTHESPOT) + { + window->x11.ic = XCreateIC(_glfw.x11.im, + XNInputStyle, + _glfw.x11.imStyle, + XNClientWindow, + window->x11.handle, + XNFocusWindow, + window->x11.handle, + XNDestroyCallback, + &callback, + NULL); + } + else + { + // (XIMPreeditNothing | XIMStatusNothing) is considered as STYLE_OVERTHESPOT. + // So this branch should not be used now. + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to create input context."); + return; + } + if (window->x11.ic) { XWindowAttributes attribs; @@ -3435,6 +3466,10 @@ void _glfwPlatformResetPreeditText(_GLFWwindow* window) XVaNestedList preedit_attr; char* result; + // Can not manage IME in the case of over-the-spot. + if (_glfw.x11.imStyle == STYLE_OVERTHESPOT) + return; + if (window->ntext == 0) return; @@ -3458,6 +3493,11 @@ void _glfwPlatformResetPreeditText(_GLFWwindow* window) void _glfwPlatformSetIMEStatus(_GLFWwindow* window, int active) { XIC ic = window->x11.ic; + + // Can not manage IME in the case of over-the-spot. + if (_glfw.x11.imStyle == STYLE_OVERTHESPOT) + return; + if (active) XSetICFocus(ic); else @@ -3466,6 +3506,10 @@ void _glfwPlatformSetIMEStatus(_GLFWwindow* window, int active) int _glfwPlatformGetIMEStatus(_GLFWwindow* window) { + // Can not manage IME in the case of over-the-spot. + if (_glfw.x11.imStyle == STYLE_OVERTHESPOT) + return GLFW_FALSE; + return window->x11.imeFocus; }