mirror of
https://github.com/glfw/glfw.git
synced 2024-11-23 02:25:10 +00:00
X11: Support IME
This commit re-organizes 6e7f93916b96c643ca7abe45d09f72d841ff15ed. * Load missing XIM related function symbols. * Generalize platform-specific features to _GLFWplatform. * Change the defalut input style to over-the-spot style. * Rename `decodeUTF8()` to `_glfwDecodeUTF8()` to make it as internal API. * It will be also needed to implment input method for Wayland. * Refactor code shapes and variable names. About over-the-spot style and on-the-spot style on X11: * In over-the-spot mode, almost all APIs are disabled since applications only need to specify the preedit candidate window position by `glfwSetPreeditCursorPos()`. * We can change the style by enabling `GLFW_X11_ONTHESPOT` init hint, but it 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. Known problems: * Some keys (arrow, Enter, BackSpace, ...) are passed to applications during preediting. * This will be fixed in PR #1972 : https://github.com/glfw/glfw/pull/1972 Co-authored-by: Takuro Ashie <ashie@clear-code.com>
This commit is contained in:
parent
6981f7ae83
commit
b0506b7912
@ -1324,6 +1324,11 @@ extern "C" {
|
|||||||
* X11 specific [init hint](@ref GLFW_X11_XCB_VULKAN_SURFACE_hint).
|
* X11 specific [init hint](@ref GLFW_X11_XCB_VULKAN_SURFACE_hint).
|
||||||
*/
|
*/
|
||||||
#define GLFW_X11_XCB_VULKAN_SURFACE 0x00052001
|
#define GLFW_X11_XCB_VULKAN_SURFACE 0x00052001
|
||||||
|
/*! @brief X11 specific init hint.
|
||||||
|
*
|
||||||
|
* X11 specific [init hint](@ref GLFW_X11_ONTHESPOT_hint).
|
||||||
|
*/
|
||||||
|
#define GLFW_X11_ONTHESPOT 0x00052002
|
||||||
/*! @brief Wayland specific init hint.
|
/*! @brief Wayland specific init hint.
|
||||||
*
|
*
|
||||||
* Wayland specific [init hint](@ref GLFW_WAYLAND_LIBDECOR_hint).
|
* Wayland specific [init hint](@ref GLFW_WAYLAND_LIBDECOR_hint).
|
||||||
@ -5249,6 +5254,9 @@ GLFWAPI void glfwSetPreeditCursorRectangle(GLFWwindow* window, int x, int y, int
|
|||||||
*
|
*
|
||||||
* @param[in] window The window.
|
* @param[in] window The window.
|
||||||
*
|
*
|
||||||
|
* @remark @x11 Since over-the-spot style is used by default, you don't need
|
||||||
|
* to use this function.
|
||||||
|
*
|
||||||
* @par Thread Safety
|
* @par Thread Safety
|
||||||
* This function may only be called from the main thread.
|
* This function may only be called from the main thread.
|
||||||
*
|
*
|
||||||
@ -5423,6 +5431,9 @@ GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmods
|
|||||||
* For more information about the callback parameters, see the
|
* For more information about the callback parameters, see the
|
||||||
* [function pointer type](@ref GLFWpreeditfun).
|
* [function pointer type](@ref GLFWpreeditfun).
|
||||||
*
|
*
|
||||||
|
* @remark @x11 Since over-the-spot style is used by default, you don't need
|
||||||
|
* to use this function.
|
||||||
|
*
|
||||||
* @par Thread Safety
|
* @par Thread Safety
|
||||||
* This function may only be called from the main thread.
|
* This function may only be called from the main thread.
|
||||||
*
|
*
|
||||||
@ -5452,6 +5463,8 @@ GLFWAPI GLFWpreeditfun glfwSetPreeditCallback(GLFWwindow* window, GLFWpreeditfun
|
|||||||
* For more information about the callback parameters, see the
|
* For more information about the callback parameters, see the
|
||||||
* [function pointer type](@ref GLFWimestatusfun).
|
* [function pointer type](@ref GLFWimestatusfun).
|
||||||
*
|
*
|
||||||
|
* @remark @x11 Don't support this function. The callback is not called.
|
||||||
|
*
|
||||||
* @par Thread Safety
|
* @par Thread Safety
|
||||||
* This function may only be called from the main thread.
|
* This function may only be called from the main thread.
|
||||||
*
|
*
|
||||||
|
27
src/init.c
27
src/init.c
@ -61,6 +61,7 @@ static _GLFWinitconfig _glfwInitHints =
|
|||||||
.x11 =
|
.x11 =
|
||||||
{
|
{
|
||||||
.xcbVulkanSurface = GLFW_TRUE,
|
.xcbVulkanSurface = GLFW_TRUE,
|
||||||
|
.onTheSpotIMStyle = GLFW_FALSE
|
||||||
},
|
},
|
||||||
.wl =
|
.wl =
|
||||||
{
|
{
|
||||||
@ -175,6 +176,29 @@ size_t _glfwEncodeUTF8(char* s, uint32_t codepoint)
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decode a Unicode code point from a UTF-8 stream
|
||||||
|
// Based on cutef8 by Jeff Bezanson (Public Domain)
|
||||||
|
//
|
||||||
|
uint32_t _glfwDecodeUTF8(const char** s)
|
||||||
|
{
|
||||||
|
uint32_t codepoint = 0, count = 0;
|
||||||
|
static const uint32_t offsets[] =
|
||||||
|
{
|
||||||
|
0x00000000u, 0x00003080u, 0x000e2080u,
|
||||||
|
0x03c82080u, 0xfa082080u, 0x82082080u
|
||||||
|
};
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
codepoint = (codepoint << 6) + (unsigned char) **s;
|
||||||
|
(*s)++;
|
||||||
|
count++;
|
||||||
|
} while ((**s & 0xc0) == 0x80);
|
||||||
|
|
||||||
|
assert(count <= 6);
|
||||||
|
return codepoint - offsets[count - 1];
|
||||||
|
}
|
||||||
|
|
||||||
// Splits and translates a text/uri-list into separate file paths
|
// Splits and translates a text/uri-list into separate file paths
|
||||||
// NOTE: This function destroys the provided string
|
// NOTE: This function destroys the provided string
|
||||||
//
|
//
|
||||||
@ -459,6 +483,9 @@ GLFWAPI void glfwInitHint(int hint, int value)
|
|||||||
case GLFW_X11_XCB_VULKAN_SURFACE:
|
case GLFW_X11_XCB_VULKAN_SURFACE:
|
||||||
_glfwInitHints.x11.xcbVulkanSurface = value;
|
_glfwInitHints.x11.xcbVulkanSurface = value;
|
||||||
return;
|
return;
|
||||||
|
case GLFW_X11_ONTHESPOT:
|
||||||
|
_glfwInitHints.x11.onTheSpotIMStyle = value;
|
||||||
|
return;
|
||||||
case GLFW_WAYLAND_LIBDECOR:
|
case GLFW_WAYLAND_LIBDECOR:
|
||||||
_glfwInitHints.wl.libdecorMode = value;
|
_glfwInitHints.wl.libdecorMode = value;
|
||||||
return;
|
return;
|
||||||
|
@ -385,6 +385,7 @@ struct _GLFWinitconfig
|
|||||||
} ns;
|
} ns;
|
||||||
struct {
|
struct {
|
||||||
GLFWbool xcbVulkanSurface;
|
GLFWbool xcbVulkanSurface;
|
||||||
|
GLFWbool onTheSpotIMStyle;
|
||||||
} x11;
|
} x11;
|
||||||
struct {
|
struct {
|
||||||
int libdecorMode;
|
int libdecorMode;
|
||||||
@ -1036,6 +1037,7 @@ void _glfwTerminateVulkan(void);
|
|||||||
const char* _glfwGetVulkanResultString(VkResult result);
|
const char* _glfwGetVulkanResultString(VkResult result);
|
||||||
|
|
||||||
size_t _glfwEncodeUTF8(char* s, uint32_t codepoint);
|
size_t _glfwEncodeUTF8(char* s, uint32_t codepoint);
|
||||||
|
uint32_t _glfwDecodeUTF8(const char** s);
|
||||||
char** _glfwParseUriList(char* text, int* count);
|
char** _glfwParseUriList(char* text, int* count);
|
||||||
|
|
||||||
char* _glfw_strdup(const char* source);
|
char* _glfw_strdup(const char* source);
|
||||||
|
@ -445,9 +445,14 @@ static GLFWbool hasUsableInputMethodStyle(void)
|
|||||||
if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) != NULL)
|
if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) != NULL)
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
if (_glfw.hints.init.x11.onTheSpotIMStyle)
|
||||||
|
_glfw.x11.imStyle = STYLE_ONTHESPOT;
|
||||||
|
else
|
||||||
|
_glfw.x11.imStyle = STYLE_OVERTHESPOT;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < styles->count_styles; i++)
|
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;
|
found = GLFW_TRUE;
|
||||||
break;
|
break;
|
||||||
@ -1455,6 +1460,8 @@ int _glfwInitX11(void)
|
|||||||
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetErrorHandler");
|
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetErrorHandler");
|
||||||
_glfw.x11.xlib.SetICFocus = (PFN_XSetICFocus)
|
_glfw.x11.xlib.SetICFocus = (PFN_XSetICFocus)
|
||||||
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetICFocus");
|
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetICFocus");
|
||||||
|
_glfw.x11.xlib.SetICValues = (PFN_XSetICValues)
|
||||||
|
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetICValues");
|
||||||
_glfw.x11.xlib.SetIMValues = (PFN_XSetIMValues)
|
_glfw.x11.xlib.SetIMValues = (PFN_XSetIMValues)
|
||||||
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetIMValues");
|
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetIMValues");
|
||||||
_glfw.x11.xlib.SetInputFocus = (PFN_XSetInputFocus)
|
_glfw.x11.xlib.SetInputFocus = (PFN_XSetInputFocus)
|
||||||
@ -1485,6 +1492,8 @@ int _glfwInitX11(void)
|
|||||||
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUnmapWindow");
|
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUnmapWindow");
|
||||||
_glfw.x11.xlib.UnsetICFocus = (PFN_XUnsetICFocus)
|
_glfw.x11.xlib.UnsetICFocus = (PFN_XUnsetICFocus)
|
||||||
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUnsetICFocus");
|
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUnsetICFocus");
|
||||||
|
_glfw.x11.xlib.VaCreateNestedList = (PFN_XVaCreateNestedList)
|
||||||
|
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XVaCreateNestedList");
|
||||||
_glfw.x11.xlib.VisualIDFromVisual = (PFN_XVisualIDFromVisual)
|
_glfw.x11.xlib.VisualIDFromVisual = (PFN_XVisualIDFromVisual)
|
||||||
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XVisualIDFromVisual");
|
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XVisualIDFromVisual");
|
||||||
_glfw.x11.xlib.WarpPointer = (PFN_XWarpPointer)
|
_glfw.x11.xlib.WarpPointer = (PFN_XWarpPointer)
|
||||||
@ -1517,6 +1526,8 @@ int _glfwInitX11(void)
|
|||||||
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XrmUniqueQuark");
|
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XrmUniqueQuark");
|
||||||
_glfw.x11.xlib.UnregisterIMInstantiateCallback = (PFN_XUnregisterIMInstantiateCallback)
|
_glfw.x11.xlib.UnregisterIMInstantiateCallback = (PFN_XUnregisterIMInstantiateCallback)
|
||||||
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUnregisterIMInstantiateCallback");
|
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUnregisterIMInstantiateCallback");
|
||||||
|
_glfw.x11.xlib.mbResetIC = (PFN_XmbResetIC)
|
||||||
|
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XmbResetIC");
|
||||||
_glfw.x11.xlib.utf8LookupString = (PFN_Xutf8LookupString)
|
_glfw.x11.xlib.utf8LookupString = (PFN_Xutf8LookupString)
|
||||||
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "Xutf8LookupString");
|
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "Xutf8LookupString");
|
||||||
_glfw.x11.xlib.utf8SetWMProperties = (PFN_Xutf8SetWMProperties)
|
_glfw.x11.xlib.utf8SetWMProperties = (PFN_Xutf8SetWMProperties)
|
||||||
|
@ -91,6 +91,9 @@
|
|||||||
#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
|
#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
|
||||||
#define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3
|
#define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3
|
||||||
|
|
||||||
|
#define STYLE_OVERTHESPOT (XIMPreeditNothing | XIMStatusNothing)
|
||||||
|
#define STYLE_ONTHESPOT (XIMPreeditCallbacks | XIMStatusCallbacks)
|
||||||
|
|
||||||
typedef XID GLXWindow;
|
typedef XID GLXWindow;
|
||||||
typedef XID GLXDrawable;
|
typedef XID GLXDrawable;
|
||||||
typedef struct __GLXFBConfig* GLXFBConfig;
|
typedef struct __GLXFBConfig* GLXFBConfig;
|
||||||
@ -165,6 +168,7 @@ typedef Status (* PFN_XSendEvent)(Display*,Window,Bool,long,XEvent*);
|
|||||||
typedef int (* PFN_XSetClassHint)(Display*,Window,XClassHint*);
|
typedef int (* PFN_XSetClassHint)(Display*,Window,XClassHint*);
|
||||||
typedef XErrorHandler (* PFN_XSetErrorHandler)(XErrorHandler);
|
typedef XErrorHandler (* PFN_XSetErrorHandler)(XErrorHandler);
|
||||||
typedef void (* PFN_XSetICFocus)(XIC);
|
typedef void (* PFN_XSetICFocus)(XIC);
|
||||||
|
typedef char* (* PFN_XSetICValues)(XIC,...);
|
||||||
typedef char* (* PFN_XSetIMValues)(XIM,...);
|
typedef char* (* PFN_XSetIMValues)(XIM,...);
|
||||||
typedef int (* PFN_XSetInputFocus)(Display*,Window,int,Time);
|
typedef int (* PFN_XSetInputFocus)(Display*,Window,int,Time);
|
||||||
typedef char* (* PFN_XSetLocaleModifiers)(const char*);
|
typedef char* (* PFN_XSetLocaleModifiers)(const char*);
|
||||||
@ -180,6 +184,7 @@ typedef int (* PFN_XUndefineCursor)(Display*,Window);
|
|||||||
typedef int (* PFN_XUngrabPointer)(Display*,Time);
|
typedef int (* PFN_XUngrabPointer)(Display*,Time);
|
||||||
typedef int (* PFN_XUnmapWindow)(Display*,Window);
|
typedef int (* PFN_XUnmapWindow)(Display*,Window);
|
||||||
typedef void (* PFN_XUnsetICFocus)(XIC);
|
typedef void (* PFN_XUnsetICFocus)(XIC);
|
||||||
|
typedef XVaNestedList (* PFN_XVaCreateNestedList)(int,...);
|
||||||
typedef VisualID (* PFN_XVisualIDFromVisual)(Visual*);
|
typedef VisualID (* PFN_XVisualIDFromVisual)(Visual*);
|
||||||
typedef int (* PFN_XWarpPointer)(Display*,Window,Window,int,int,unsigned int,unsigned int,int,int);
|
typedef int (* PFN_XWarpPointer)(Display*,Window,Window,int,int,unsigned int,unsigned int,int,int);
|
||||||
typedef void (* PFN_XkbFreeKeyboard)(XkbDescPtr,unsigned int,Bool);
|
typedef void (* PFN_XkbFreeKeyboard)(XkbDescPtr,unsigned int,Bool);
|
||||||
@ -191,6 +196,7 @@ typedef KeySym (* PFN_XkbKeycodeToKeysym)(Display*,KeyCode,int,int);
|
|||||||
typedef Bool (* PFN_XkbQueryExtension)(Display*,int*,int*,int*,int*,int*);
|
typedef Bool (* PFN_XkbQueryExtension)(Display*,int*,int*,int*,int*,int*);
|
||||||
typedef Bool (* PFN_XkbSelectEventDetails)(Display*,unsigned int,unsigned int,unsigned long,unsigned long);
|
typedef Bool (* PFN_XkbSelectEventDetails)(Display*,unsigned int,unsigned int,unsigned long,unsigned long);
|
||||||
typedef Bool (* PFN_XkbSetDetectableAutoRepeat)(Display*,Bool,Bool*);
|
typedef Bool (* PFN_XkbSetDetectableAutoRepeat)(Display*,Bool,Bool*);
|
||||||
|
typedef char* (* PFN_XmbResetIC)(XIC);
|
||||||
typedef void (* PFN_XrmDestroyDatabase)(XrmDatabase);
|
typedef void (* PFN_XrmDestroyDatabase)(XrmDatabase);
|
||||||
typedef Bool (* PFN_XrmGetResource)(XrmDatabase,const char*,const char*,char**,XrmValue*);
|
typedef Bool (* PFN_XrmGetResource)(XrmDatabase,const char*,const char*,char**,XrmValue*);
|
||||||
typedef XrmDatabase (* PFN_XrmGetStringDatabase)(const char*);
|
typedef XrmDatabase (* PFN_XrmGetStringDatabase)(const char*);
|
||||||
@ -265,6 +271,7 @@ typedef void (* PFN_Xutf8SetWMProperties)(Display*,Window,const char*,const char
|
|||||||
#define XSetClassHint _glfw.x11.xlib.SetClassHint
|
#define XSetClassHint _glfw.x11.xlib.SetClassHint
|
||||||
#define XSetErrorHandler _glfw.x11.xlib.SetErrorHandler
|
#define XSetErrorHandler _glfw.x11.xlib.SetErrorHandler
|
||||||
#define XSetICFocus _glfw.x11.xlib.SetICFocus
|
#define XSetICFocus _glfw.x11.xlib.SetICFocus
|
||||||
|
#define XSetICValues _glfw.x11.xlib.SetICValues
|
||||||
#define XSetIMValues _glfw.x11.xlib.SetIMValues
|
#define XSetIMValues _glfw.x11.xlib.SetIMValues
|
||||||
#define XSetInputFocus _glfw.x11.xlib.SetInputFocus
|
#define XSetInputFocus _glfw.x11.xlib.SetInputFocus
|
||||||
#define XSetLocaleModifiers _glfw.x11.xlib.SetLocaleModifiers
|
#define XSetLocaleModifiers _glfw.x11.xlib.SetLocaleModifiers
|
||||||
@ -280,6 +287,7 @@ typedef void (* PFN_Xutf8SetWMProperties)(Display*,Window,const char*,const char
|
|||||||
#define XUngrabPointer _glfw.x11.xlib.UngrabPointer
|
#define XUngrabPointer _glfw.x11.xlib.UngrabPointer
|
||||||
#define XUnmapWindow _glfw.x11.xlib.UnmapWindow
|
#define XUnmapWindow _glfw.x11.xlib.UnmapWindow
|
||||||
#define XUnsetICFocus _glfw.x11.xlib.UnsetICFocus
|
#define XUnsetICFocus _glfw.x11.xlib.UnsetICFocus
|
||||||
|
#define XVaCreateNestedList _glfw.x11.xlib.VaCreateNestedList
|
||||||
#define XVisualIDFromVisual _glfw.x11.xlib.VisualIDFromVisual
|
#define XVisualIDFromVisual _glfw.x11.xlib.VisualIDFromVisual
|
||||||
#define XWarpPointer _glfw.x11.xlib.WarpPointer
|
#define XWarpPointer _glfw.x11.xlib.WarpPointer
|
||||||
#define XkbFreeKeyboard _glfw.x11.xkb.FreeKeyboard
|
#define XkbFreeKeyboard _glfw.x11.xkb.FreeKeyboard
|
||||||
@ -291,6 +299,7 @@ typedef void (* PFN_Xutf8SetWMProperties)(Display*,Window,const char*,const char
|
|||||||
#define XkbQueryExtension _glfw.x11.xkb.QueryExtension
|
#define XkbQueryExtension _glfw.x11.xkb.QueryExtension
|
||||||
#define XkbSelectEventDetails _glfw.x11.xkb.SelectEventDetails
|
#define XkbSelectEventDetails _glfw.x11.xkb.SelectEventDetails
|
||||||
#define XkbSetDetectableAutoRepeat _glfw.x11.xkb.SetDetectableAutoRepeat
|
#define XkbSetDetectableAutoRepeat _glfw.x11.xkb.SetDetectableAutoRepeat
|
||||||
|
#define XmbResetIC _glfw.x11.xlib.mbResetIC
|
||||||
#define XrmDestroyDatabase _glfw.x11.xrm.DestroyDatabase
|
#define XrmDestroyDatabase _glfw.x11.xrm.DestroyDatabase
|
||||||
#define XrmGetResource _glfw.x11.xrm.GetResource
|
#define XrmGetResource _glfw.x11.xrm.GetResource
|
||||||
#define XrmGetStringDatabase _glfw.x11.xrm.GetStringDatabase
|
#define XrmGetStringDatabase _glfw.x11.xrm.GetStringDatabase
|
||||||
@ -577,6 +586,8 @@ typedef struct _GLFWlibraryX11
|
|||||||
XContext context;
|
XContext context;
|
||||||
// XIM input method
|
// XIM input method
|
||||||
XIM im;
|
XIM im;
|
||||||
|
// XIM input method style
|
||||||
|
XIMStyle imStyle;
|
||||||
// The previous X error handler, to be restored later
|
// The previous X error handler, to be restored later
|
||||||
XErrorHandler errorHandler;
|
XErrorHandler errorHandler;
|
||||||
// Most recent error code received by X error handler
|
// Most recent error code received by X error handler
|
||||||
@ -722,6 +733,7 @@ typedef struct _GLFWlibraryX11
|
|||||||
PFN_XSetClassHint SetClassHint;
|
PFN_XSetClassHint SetClassHint;
|
||||||
PFN_XSetErrorHandler SetErrorHandler;
|
PFN_XSetErrorHandler SetErrorHandler;
|
||||||
PFN_XSetICFocus SetICFocus;
|
PFN_XSetICFocus SetICFocus;
|
||||||
|
PFN_XSetICValues SetICValues;
|
||||||
PFN_XSetIMValues SetIMValues;
|
PFN_XSetIMValues SetIMValues;
|
||||||
PFN_XSetInputFocus SetInputFocus;
|
PFN_XSetInputFocus SetInputFocus;
|
||||||
PFN_XSetLocaleModifiers SetLocaleModifiers;
|
PFN_XSetLocaleModifiers SetLocaleModifiers;
|
||||||
@ -737,9 +749,11 @@ typedef struct _GLFWlibraryX11
|
|||||||
PFN_XUngrabPointer UngrabPointer;
|
PFN_XUngrabPointer UngrabPointer;
|
||||||
PFN_XUnmapWindow UnmapWindow;
|
PFN_XUnmapWindow UnmapWindow;
|
||||||
PFN_XUnsetICFocus UnsetICFocus;
|
PFN_XUnsetICFocus UnsetICFocus;
|
||||||
|
PFN_XVaCreateNestedList VaCreateNestedList;
|
||||||
PFN_XVisualIDFromVisual VisualIDFromVisual;
|
PFN_XVisualIDFromVisual VisualIDFromVisual;
|
||||||
PFN_XWarpPointer WarpPointer;
|
PFN_XWarpPointer WarpPointer;
|
||||||
PFN_XUnregisterIMInstantiateCallback UnregisterIMInstantiateCallback;
|
PFN_XUnregisterIMInstantiateCallback UnregisterIMInstantiateCallback;
|
||||||
|
PFN_XmbResetIC mbResetIC;
|
||||||
PFN_Xutf8LookupString utf8LookupString;
|
PFN_Xutf8LookupString utf8LookupString;
|
||||||
PFN_Xutf8SetWMProperties utf8SetWMProperties;
|
PFN_Xutf8SetWMProperties utf8SetWMProperties;
|
||||||
} xlib;
|
} xlib;
|
||||||
|
504
src/x11_window.c
504
src/x11_window.c
@ -410,29 +410,6 @@ static void updateWindowMode(_GLFWwindow* window)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode a Unicode code point from a UTF-8 stream
|
|
||||||
// Based on cutef8 by Jeff Bezanson (Public Domain)
|
|
||||||
//
|
|
||||||
static uint32_t decodeUTF8(const char** s)
|
|
||||||
{
|
|
||||||
uint32_t codepoint = 0, count = 0;
|
|
||||||
static const uint32_t offsets[] =
|
|
||||||
{
|
|
||||||
0x00000000u, 0x00003080u, 0x000e2080u,
|
|
||||||
0x03c82080u, 0xfa082080u, 0x82082080u
|
|
||||||
};
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
codepoint = (codepoint << 6) + (unsigned char) **s;
|
|
||||||
(*s)++;
|
|
||||||
count++;
|
|
||||||
} while ((**s & 0xc0) == 0x80);
|
|
||||||
|
|
||||||
assert(count <= 6);
|
|
||||||
return codepoint - offsets[count - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the specified Latin-1 string to UTF-8
|
// Convert the specified Latin-1 string to UTF-8
|
||||||
//
|
//
|
||||||
static char* convertLatin1toUTF8(const char* source)
|
static char* convertLatin1toUTF8(const char* source)
|
||||||
@ -553,197 +530,241 @@ static void enableCursor(_GLFWwindow* window)
|
|||||||
updateCursorImage(window);
|
updateCursorImage(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO This callback is replaced by _createXIMPreeditCallbacks. Is there a possibility that this clearing process is necessary?
|
|
||||||
// Clear its handle when the input context has been destroyed
|
// Clear its handle when the input context has been destroyed
|
||||||
// static void inputContextDestroyCallback(XIC ic, XPointer clientData, XPointer callData)
|
//
|
||||||
// {
|
static void inputContextDestroyCallback(XIC ic, XPointer clientData, XPointer callData)
|
||||||
// _GLFWwindow* window = (_GLFWwindow*) clientData;
|
|
||||||
// window->x11.ic = NULL;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Update cursor position to decide candidate window
|
|
||||||
static void _ximChangeCursorPosition(XIC xic, _GLFWwindow* window)
|
|
||||||
{
|
{
|
||||||
XVaNestedList preedit_attr;
|
_GLFWwindow* window = (_GLFWwindow*) clientData;
|
||||||
XPoint spot;
|
window->x11.ic = NULL;
|
||||||
|
|
||||||
spot.x = window->preeditCursorPosX;
|
|
||||||
spot.y = window->preeditCursorPosY + window->preeditCursorHeight;
|
|
||||||
preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
|
|
||||||
XSetICValues(xic, XNPreeditAttributes, preedit_attr, NULL);
|
|
||||||
XFree(preedit_attr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IME Start callback (do nothing)
|
// IME Start callback (do nothing)
|
||||||
|
//
|
||||||
static void _ximPreeditStartCallback(XIC xic, XPointer clientData, XPointer callData)
|
static void _ximPreeditStartCallback(XIC xic, XPointer clientData, XPointer callData)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// IME Done callback (do nothing)
|
// IME Done callback (do nothing)
|
||||||
|
//
|
||||||
static void _ximPreeditDoneCallback(XIC xic, XPointer clientData, XPointer callData)
|
static void _ximPreeditDoneCallback(XIC xic, XPointer clientData, XPointer callData)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// IME Draw callback
|
// IME Draw callback
|
||||||
static void _ximPreeditDrawCallback(XIC xic, XPointer clientData, XIMPreeditDrawCallbackStruct *callData)
|
// When using the dafault style: STYLE_OVERTHESPOT, this is not used since applications
|
||||||
|
// don't need to display preedit texts.
|
||||||
|
//
|
||||||
|
static void _ximPreeditDrawCallback(XIC xic, XPointer clientData, XIMPreeditDrawCallbackStruct* callData)
|
||||||
{
|
{
|
||||||
int i, j, length, ctext, rstart, rend;
|
_GLFWwindow* window = (_GLFWwindow*) clientData;
|
||||||
XIMText* text;
|
_GLFWpreedit* preedit = &window->preedit;
|
||||||
const char* src;
|
|
||||||
unsigned int codePoint;
|
|
||||||
unsigned int* preeditText;
|
|
||||||
XIMFeedback f;
|
|
||||||
_GLFWwindow* window = (_GLFWwindow*)clientData;
|
|
||||||
|
|
||||||
// keep cursor position to reduce API call
|
if (!callData->text)
|
||||||
int cursorX = window->preeditCursorPosX;
|
{
|
||||||
int cursorY = window->preeditCursorPosY;
|
|
||||||
int cursorHeight = window->preeditCursorHeight;
|
|
||||||
|
|
||||||
if (!callData->text) {
|
|
||||||
// preedit text is empty
|
// preedit text is empty
|
||||||
window->ntext = 0;
|
preedit->textCount = 0;
|
||||||
window->nblocks = 0;
|
preedit->blockSizesCount = 0;
|
||||||
_glfwInputPreedit(window, 0);
|
preedit->focusedBlockIndex = 0;
|
||||||
|
preedit->caretIndex = 0;
|
||||||
|
_glfwInputPreedit(window);
|
||||||
return;
|
return;
|
||||||
} else {
|
}
|
||||||
text = callData->text;
|
else if (callData->text->encoding_is_wchar)
|
||||||
length = callData->chg_length;
|
{
|
||||||
if (text->encoding_is_wchar) {
|
// wchar is not supported
|
||||||
// wchar is not supported
|
return;
|
||||||
return;
|
}
|
||||||
}
|
else
|
||||||
ctext = window->ctext;
|
{
|
||||||
while (ctext < length+1) {
|
XIMText* text = callData->text;
|
||||||
ctext = (ctext == 0) ? 1 : ctext * 2;
|
int textLen = preedit->textCount + text->length - callData->chg_length;
|
||||||
}
|
int textBufferCount = preedit->textBufferCount;
|
||||||
if (ctext != window->ctext) {
|
int i, j, rstart, rend;
|
||||||
preeditText = _glfw_realloc(window->preeditText, sizeof(unsigned int)*ctext);
|
const char* src;
|
||||||
if (preeditText == NULL) {
|
|
||||||
|
// realloc preedit text
|
||||||
|
while (textBufferCount < textLen + 1)
|
||||||
|
textBufferCount = (textBufferCount == 0) ? 1 : textBufferCount * 2;
|
||||||
|
if (textBufferCount != preedit->textBufferCount)
|
||||||
|
{
|
||||||
|
unsigned int* preeditText = _glfw_realloc(preedit->text,
|
||||||
|
sizeof(unsigned int) * textBufferCount);
|
||||||
|
if (preeditText == NULL)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
window->preeditText = preeditText;
|
preedit->text = preeditText;
|
||||||
window->ctext = ctext;
|
preedit->textBufferCount = textBufferCount;
|
||||||
}
|
}
|
||||||
window->ntext = length;
|
preedit->textCount = textLen;
|
||||||
window->preeditText[length] = 0;
|
preedit->text[textLen] = 0;
|
||||||
if (window->cblocks == 0) {
|
|
||||||
window->preeditAttributeBlocks = _glfw_calloc(4, sizeof(int));
|
// realloc block sizes
|
||||||
window->cblocks = 4;
|
if (preedit->blockSizesBufferCount == 0)
|
||||||
|
{
|
||||||
|
preedit->blockSizes = _glfw_calloc(4, sizeof(int));
|
||||||
|
preedit->blockSizesBufferCount = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// store preedit text
|
||||||
src = text->string.multi_byte;
|
src = text->string.multi_byte;
|
||||||
rend = 0;
|
rend = 0;
|
||||||
rstart = length;
|
rstart = textLen;
|
||||||
for (i = 0, j = 0; i < text->length; i++) {
|
for (i = 0, j = callData->chg_first; i < text->length; i++)
|
||||||
codePoint = decodeUTF8(&src);
|
{
|
||||||
if (i < callData->chg_first || callData->chg_first+length < i) {
|
XIMFeedback f;
|
||||||
|
|
||||||
|
if (i < callData->chg_first || callData->chg_first + textLen < i)
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
window->preeditText[j++] = codePoint;
|
preedit->text[j++] = _glfwDecodeUTF8(&src);
|
||||||
f = text->feedback[i];
|
f = text->feedback[i];
|
||||||
if ((f & XIMReverse) || (f & XIMHighlight)) {
|
if ((f & XIMReverse) || (f & XIMHighlight))
|
||||||
|
{
|
||||||
rend = i;
|
rend = i;
|
||||||
if (i < rstart) {
|
if (i < rstart)
|
||||||
rstart = i;
|
rstart = i;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rstart == length) {
|
|
||||||
window->nblocks = 1;
|
// store block sizes
|
||||||
window->preeditAttributeBlocks[0] = length;
|
// TODO: It doesn't care callData->chg_first != 0 case although it's quite rare.
|
||||||
window->preeditAttributeBlocks[1] = 0;
|
if (rstart == textLen)
|
||||||
_glfwInputPreedit(window, 0);
|
{
|
||||||
} else if (rstart == 0) {
|
preedit->blockSizesCount = 1;
|
||||||
if (rend == length -1) {
|
preedit->blockSizes[0] = textLen;
|
||||||
window->nblocks = 1;
|
preedit->blockSizes[1] = 0;
|
||||||
window->preeditAttributeBlocks[0] = length;
|
preedit->focusedBlockIndex = 0;
|
||||||
window->preeditAttributeBlocks[1] = 0;
|
preedit->caretIndex = callData->caret;
|
||||||
_glfwInputPreedit(window, 0);
|
_glfwInputPreedit(window);
|
||||||
} else {
|
|
||||||
window->nblocks = 2;
|
|
||||||
window->preeditAttributeBlocks[0] = rend + 1;
|
|
||||||
window->preeditAttributeBlocks[1] = length - rend - 1;
|
|
||||||
window->preeditAttributeBlocks[2] = 0;
|
|
||||||
_glfwInputPreedit(window, 0);
|
|
||||||
}
|
|
||||||
} else if (rend == length -1) {
|
|
||||||
window->nblocks = 2;
|
|
||||||
window->preeditAttributeBlocks[0] = rstart;
|
|
||||||
window->preeditAttributeBlocks[1] = length - rstart;
|
|
||||||
window->preeditAttributeBlocks[2] = 0;
|
|
||||||
_glfwInputPreedit(window, 1);
|
|
||||||
} else {
|
|
||||||
window->nblocks = 3;
|
|
||||||
window->preeditAttributeBlocks[0] = rstart;
|
|
||||||
window->preeditAttributeBlocks[1] = rend - rstart + 1;
|
|
||||||
window->preeditAttributeBlocks[2] = length - rend - 1;
|
|
||||||
window->preeditAttributeBlocks[3] = 0;
|
|
||||||
_glfwInputPreedit(window, 1);
|
|
||||||
}
|
}
|
||||||
if ((cursorX != window->preeditCursorPosX)
|
else if (rstart == 0)
|
||||||
|| (cursorY != window->preeditCursorPosY)
|
{
|
||||||
|| (cursorHeight != window->preeditCursorHeight)) {
|
if (rend == textLen -1)
|
||||||
_ximChangeCursorPosition(xic, window);
|
{
|
||||||
|
preedit->blockSizesCount = 1;
|
||||||
|
preedit->blockSizes[0] = textLen;
|
||||||
|
preedit->blockSizes[1] = 0;
|
||||||
|
preedit->focusedBlockIndex = 0;
|
||||||
|
preedit->caretIndex = callData->caret;
|
||||||
|
_glfwInputPreedit(window);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
preedit->blockSizesCount = 2;
|
||||||
|
preedit->blockSizes[0] = rend + 1;
|
||||||
|
preedit->blockSizes[1] = textLen - rend - 1;
|
||||||
|
preedit->blockSizes[2] = 0;
|
||||||
|
preedit->focusedBlockIndex = 0;
|
||||||
|
preedit->caretIndex = callData->caret;
|
||||||
|
_glfwInputPreedit(window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (rend == textLen - 1)
|
||||||
|
{
|
||||||
|
preedit->blockSizesCount = 2;
|
||||||
|
preedit->blockSizes[0] = rstart;
|
||||||
|
preedit->blockSizes[1] = textLen - rstart;
|
||||||
|
preedit->blockSizes[2] = 0;
|
||||||
|
preedit->focusedBlockIndex = 1;
|
||||||
|
preedit->caretIndex = callData->caret;
|
||||||
|
_glfwInputPreedit(window);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
preedit->blockSizesCount = 3;
|
||||||
|
preedit->blockSizes[0] = rstart;
|
||||||
|
preedit->blockSizes[1] = rend - rstart + 1;
|
||||||
|
preedit->blockSizes[2] = textLen - rend - 1;
|
||||||
|
preedit->blockSizes[3] = 0;
|
||||||
|
preedit->focusedBlockIndex = 1;
|
||||||
|
preedit->caretIndex = callData->caret;
|
||||||
|
_glfwInputPreedit(window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IME Caret callback (do nothing)
|
// IME Caret callback (do nothing)
|
||||||
|
//
|
||||||
static void _ximPreeditCaretCallback(XIC xic, XPointer clientData, XPointer callData)
|
static void _ximPreeditCaretCallback(XIC xic, XPointer clientData, XPointer callData)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IME Status Start callback
|
||||||
|
// When using the dafault style: STYLE_OVERTHESPOT, this is not used and the IME status
|
||||||
|
// can not be taken.
|
||||||
|
//
|
||||||
static void _ximStatusStartCallback(XIC xic, XPointer clientData, XPointer callData)
|
static void _ximStatusStartCallback(XIC xic, XPointer clientData, XPointer callData)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = (_GLFWwindow*)clientData;
|
_GLFWwindow* window = (_GLFWwindow*) clientData;
|
||||||
window->x11.imeFocus = GLFW_TRUE;
|
window->x11.imeFocus = GLFW_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IME Status Done callback
|
||||||
|
// When using the dafault style: STYLE_OVERTHESPOT, this is not used and the IME status
|
||||||
|
// can not be taken.
|
||||||
|
//
|
||||||
static void _ximStatusDoneCallback(XIC xic, XPointer clientData, XPointer callData)
|
static void _ximStatusDoneCallback(XIC xic, XPointer clientData, XPointer callData)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = (_GLFWwindow*)clientData;
|
_GLFWwindow* window = (_GLFWwindow*) clientData;
|
||||||
window->x11.imeFocus = GLFW_FALSE;
|
window->x11.imeFocus = GLFW_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IME Status Draw callback
|
||||||
|
// When using the dafault style: STYLE_OVERTHESPOT, this is not used and the IME status
|
||||||
|
// can not be taken.
|
||||||
|
//
|
||||||
static void _ximStatusDrawCallback(XIC xic, XPointer clientData, XIMStatusDrawCallbackStruct* callData)
|
static void _ximStatusDrawCallback(XIC xic, XPointer clientData, XIMStatusDrawCallbackStruct* callData)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = (_GLFWwindow*)clientData;
|
_GLFWwindow* window = (_GLFWwindow*) clientData;
|
||||||
_glfwInputIMEStatus(window);
|
_glfwInputIMEStatus(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create XIM Preedit callback
|
// Create XIM Preedit callback
|
||||||
|
// When using the dafault style: STYLE_OVERTHESPOT, this is not used since applications
|
||||||
|
// don't need to display preedit texts.
|
||||||
|
//
|
||||||
static XVaNestedList _createXIMPreeditCallbacks(_GLFWwindow* window)
|
static XVaNestedList _createXIMPreeditCallbacks(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
window->x11.preeditStartCallback.client_data = (XPointer)window;
|
window->x11.preeditStartCallback.client_data = (XPointer) window;
|
||||||
window->x11.preeditStartCallback.callback = (XIMProc)_ximPreeditStartCallback;
|
window->x11.preeditStartCallback.callback = (XIMProc) _ximPreeditStartCallback;
|
||||||
window->x11.preeditDoneCallback.client_data = (XPointer)window;
|
window->x11.preeditDoneCallback.client_data = (XPointer) window;
|
||||||
window->x11.preeditDoneCallback.callback = (XIMProc)_ximPreeditDoneCallback;
|
window->x11.preeditDoneCallback.callback = (XIMProc) _ximPreeditDoneCallback;
|
||||||
window->x11.preeditDrawCallback.client_data = (XPointer)window;
|
window->x11.preeditDrawCallback.client_data = (XPointer) window;
|
||||||
window->x11.preeditDrawCallback.callback = (XIMProc)_ximPreeditDrawCallback;
|
window->x11.preeditDrawCallback.callback = (XIMProc) _ximPreeditDrawCallback;
|
||||||
window->x11.preeditCaretCallback.client_data = (XPointer)window;
|
window->x11.preeditCaretCallback.client_data = (XPointer) window;
|
||||||
window->x11.preeditCaretCallback.callback = (XIMProc)_ximPreeditCaretCallback;
|
window->x11.preeditCaretCallback.callback = (XIMProc) _ximPreeditCaretCallback;
|
||||||
return XVaCreateNestedList (0,
|
return XVaCreateNestedList(0,
|
||||||
XNPreeditStartCallback, &window->x11.preeditStartCallback.client_data,
|
XNPreeditStartCallback,
|
||||||
XNPreeditDoneCallback, &window->x11.preeditDoneCallback.client_data,
|
&window->x11.preeditStartCallback.client_data,
|
||||||
XNPreeditDrawCallback, &window->x11.preeditDrawCallback.client_data,
|
XNPreeditDoneCallback,
|
||||||
XNPreeditCaretCallback, &window->x11.preeditCaretCallback.client_data,
|
&window->x11.preeditDoneCallback.client_data,
|
||||||
NULL);
|
XNPreeditDrawCallback,
|
||||||
|
&window->x11.preeditDrawCallback.client_data,
|
||||||
|
XNPreeditCaretCallback,
|
||||||
|
&window->x11.preeditCaretCallback.client_data,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create XIM status callback
|
// Create XIM status callback
|
||||||
|
// When using the dafault style: STYLE_OVERTHESPOT, this is not used and the IME status
|
||||||
|
// can not be taken.
|
||||||
|
//
|
||||||
static XVaNestedList _createXIMStatusCallbacks(_GLFWwindow* window)
|
static XVaNestedList _createXIMStatusCallbacks(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
window->x11.statusStartCallback.client_data = (XPointer)window;
|
window->x11.statusStartCallback.client_data = (XPointer) window;
|
||||||
window->x11.statusStartCallback.callback = (XIMProc)_ximStatusStartCallback;
|
window->x11.statusStartCallback.callback = (XIMProc) _ximStatusStartCallback;
|
||||||
window->x11.statusDoneCallback.client_data = (XPointer)window;
|
window->x11.statusDoneCallback.client_data = (XPointer) window;
|
||||||
window->x11.statusDoneCallback.callback = (XIMProc)_ximStatusDoneCallback;
|
window->x11.statusDoneCallback.callback = (XIMProc) _ximStatusDoneCallback;
|
||||||
window->x11.statusDrawCallback.client_data = (XPointer)window;
|
window->x11.statusDrawCallback.client_data = (XPointer) window;
|
||||||
window->x11.statusDrawCallback.callback = (XIMProc)_ximStatusDrawCallback;
|
window->x11.statusDrawCallback.callback = (XIMProc) _ximStatusDrawCallback;
|
||||||
return XVaCreateNestedList (0,
|
return XVaCreateNestedList(0,
|
||||||
XNStatusStartCallback, &window->x11.statusStartCallback.client_data,
|
XNStatusStartCallback,
|
||||||
XNStatusDoneCallback, &window->x11.statusDoneCallback.client_data,
|
&window->x11.statusStartCallback.client_data,
|
||||||
XNStatusDrawCallback, &window->x11.statusDrawCallback.client_data,
|
XNStatusDoneCallback,
|
||||||
NULL);
|
&window->x11.statusDoneCallback.client_data,
|
||||||
|
XNStatusDrawCallback,
|
||||||
|
&window->x11.statusDrawCallback.client_data,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the X11 window (and its colormap)
|
// Create the X11 window (and its colormap)
|
||||||
@ -1475,7 +1496,7 @@ static void processEvent(XEvent *event)
|
|||||||
const char* c = chars;
|
const char* c = chars;
|
||||||
chars[count] = '\0';
|
chars[count] = '\0';
|
||||||
while (c - chars < count)
|
while (c - chars < count)
|
||||||
_glfwInputChar(window, decodeUTF8(&c), mods, plain);
|
_glfwInputChar(window, _glfwDecodeUTF8(&c), mods, plain);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chars != buffer)
|
if (chars != buffer)
|
||||||
@ -2106,26 +2127,60 @@ void _glfwPushSelectionToManagerX11(void)
|
|||||||
|
|
||||||
void _glfwCreateInputContextX11(_GLFWwindow* window)
|
void _glfwCreateInputContextX11(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
XVaNestedList preeditList = _createXIMPreeditCallbacks(window);
|
XIMCallback callback;
|
||||||
XVaNestedList statusList = _createXIMStatusCallbacks(window);
|
callback.callback = (XIMProc) inputContextDestroyCallback;
|
||||||
|
callback.client_data = (XPointer) window;
|
||||||
|
|
||||||
window->x11.ic = XCreateIC(_glfw.x11.im,
|
|
||||||
XNInputStyle,
|
|
||||||
XIMPreeditCallbacks | XIMStatusCallbacks,
|
|
||||||
XNClientWindow,
|
|
||||||
window->x11.handle,
|
|
||||||
XNFocusWindow,
|
|
||||||
window->x11.handle,
|
|
||||||
XNPreeditAttributes,
|
|
||||||
preeditList,
|
|
||||||
XNStatusAttributes,
|
|
||||||
statusList,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
XFree(preeditList);
|
|
||||||
XFree(statusList);
|
|
||||||
window->x11.imeFocus = GLFW_FALSE;
|
window->x11.imeFocus = GLFW_FALSE;
|
||||||
|
|
||||||
|
if (_glfw.x11.imStyle == STYLE_ONTHESPOT)
|
||||||
|
{
|
||||||
|
// On X11, on-the-spot style is unstable.
|
||||||
|
// Status callbacks are not called and the preedit cursor position
|
||||||
|
// can not be changed.
|
||||||
|
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)
|
if (window->x11.ic)
|
||||||
{
|
{
|
||||||
XWindowAttributes attribs;
|
XWindowAttributes attribs;
|
||||||
@ -3274,21 +3329,90 @@ const char* _glfwGetClipboardStringX11(void)
|
|||||||
return getSelectionString(_glfw.x11.CLIPBOARD);
|
return getSelectionString(_glfw.x11.CLIPBOARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When using STYLE_ONTHESPOT, this doesn't work and the cursor position can't be updated
|
||||||
|
//
|
||||||
void _glfwUpdatePreeditCursorRectangleX11(_GLFWwindow* window)
|
void _glfwUpdatePreeditCursorRectangleX11(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
|
XVaNestedList preedit_attr;
|
||||||
|
XPoint spot;
|
||||||
|
_GLFWpreedit* preedit = &window->preedit;
|
||||||
|
|
||||||
|
if (!window->x11.ic)
|
||||||
|
return;
|
||||||
|
|
||||||
|
spot.x = preedit->cursorPosX + preedit->cursorWidth;
|
||||||
|
spot.y = preedit->cursorPosY + preedit->cursorHeight;
|
||||||
|
preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
|
||||||
|
XSetICValues(window->x11.ic, XNPreeditAttributes, preedit_attr, NULL);
|
||||||
|
XFree(preedit_attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwResetPreeditTextX11(_GLFWwindow* window)
|
void _glfwResetPreeditTextX11(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
|
XIC ic = window->x11.ic;
|
||||||
|
_GLFWpreedit* preedit = &window->preedit;
|
||||||
|
|
||||||
|
/* restore conversion state after resetting ic later */
|
||||||
|
XIMPreeditState preedit_state = XIMPreeditUnKnown;
|
||||||
|
XVaNestedList preedit_attr;
|
||||||
|
char* result;
|
||||||
|
|
||||||
|
if (!ic)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Can not manage IME in the case of over-the-spot.
|
||||||
|
if (_glfw.x11.imStyle == STYLE_OVERTHESPOT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (preedit->textCount == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
preedit_attr = XVaCreateNestedList(0, XNPreeditState, &preedit_state, NULL);
|
||||||
|
XGetICValues(ic, XNPreeditAttributes, preedit_attr, NULL);
|
||||||
|
XFree(preedit_attr);
|
||||||
|
|
||||||
|
result = XmbResetIC(ic);
|
||||||
|
|
||||||
|
preedit_attr = XVaCreateNestedList(0, XNPreeditState, preedit_state, NULL);
|
||||||
|
XSetICValues(ic, XNPreeditAttributes, preedit_attr, NULL);
|
||||||
|
XFree(preedit_attr);
|
||||||
|
|
||||||
|
preedit->textCount = 0;
|
||||||
|
preedit->blockSizesCount = 0;
|
||||||
|
preedit->focusedBlockIndex = 0;
|
||||||
|
preedit->caretIndex = 0;
|
||||||
|
_glfwInputPreedit(window);
|
||||||
|
|
||||||
|
XFree (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwSetIMEStatusX11(_GLFWwindow* window, int active)
|
void _glfwSetIMEStatusX11(_GLFWwindow* window, int active)
|
||||||
{
|
{
|
||||||
|
XIC ic = window->x11.ic;
|
||||||
|
|
||||||
|
if (!ic)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Can not manage IME in the case of over-the-spot.
|
||||||
|
if (_glfw.x11.imStyle == STYLE_OVERTHESPOT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (active)
|
||||||
|
XSetICFocus(ic);
|
||||||
|
else
|
||||||
|
XUnsetICFocus(ic);
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwGetIMEStatusX11(_GLFWwindow* window)
|
int _glfwGetIMEStatusX11(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
return GLFW_FALSE;
|
if (!window->x11.ic)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
// Can not manage IME in the case of over-the-spot.
|
||||||
|
if (_glfw.x11.imStyle == STYLE_OVERTHESPOT)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
return window->x11.imeFocus;
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLenum _glfwGetEGLPlatformX11(EGLint** attribs)
|
EGLenum _glfwGetEGLPlatformX11(EGLint** attribs)
|
||||||
@ -3489,46 +3613,6 @@ VkResult _glfwCreateWindowSurfaceX11(VkInstance instance,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformResetPreeditText(_GLFWwindow* window) {
|
|
||||||
XIC ic = window->x11.ic;
|
|
||||||
|
|
||||||
/* restore conversion state after resetting ic later */
|
|
||||||
XIMPreeditState preedit_state = XIMPreeditUnKnown;
|
|
||||||
XVaNestedList preedit_attr;
|
|
||||||
char* result;
|
|
||||||
|
|
||||||
if (window->ntext == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
preedit_attr = XVaCreateNestedList(0, XNPreeditState, &preedit_state, NULL);
|
|
||||||
XGetICValues(ic, XNPreeditAttributes, preedit_attr, NULL);
|
|
||||||
XFree(preedit_attr);
|
|
||||||
|
|
||||||
result = XmbResetIC(ic);
|
|
||||||
|
|
||||||
preedit_attr = XVaCreateNestedList(0, XNPreeditState, preedit_state, NULL);
|
|
||||||
XSetICValues(ic, XNPreeditAttributes, preedit_attr, NULL);
|
|
||||||
XFree(preedit_attr);
|
|
||||||
|
|
||||||
window->ntext = 0;
|
|
||||||
window->nblocks = 0;
|
|
||||||
_glfwInputPreedit(window, 0);
|
|
||||||
|
|
||||||
XFree (result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _glfwPlatformSetIMEStatus(_GLFWwindow* window, int active) {
|
|
||||||
XIC ic = window->x11.ic;
|
|
||||||
if (active) {
|
|
||||||
XSetICFocus(ic);
|
|
||||||
} else {
|
|
||||||
XUnsetICFocus(ic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int _glfwPlatformGetIMEStatus(_GLFWwindow* window) {
|
|
||||||
return window->x11.imeFocus;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
////// GLFW native API //////
|
////// GLFW native API //////
|
||||||
|
Loading…
Reference in New Issue
Block a user