mirror of
https://github.com/glfw/glfw.git
synced 2025-04-20 23:52:51 +00:00
Apply shibukawa's fix of GLFW for X11
This fix is based on shibukawa's fix: https://github.com/glfw/glfw/pull/658 The differences is the following. * Remove `X_HAVE_UTF8_STRING` branching since the current logic doesn't use it * Replace `XNDestroyCallback` for `XNPreeditAttributes` in `XCreateIC` Co-authored-by: Yoshiki Shibukawa <yoshiki@shibu.jp> Co-authored-by: Takuro Ashie <ashie@clear-code.com>
This commit is contained in:
parent
e3ffd25956
commit
ea358b32fb
@ -546,6 +546,17 @@ typedef struct _GLFWwindowX11
|
|||||||
// The time of the last KeyPress event per keycode, for discarding
|
// The time of the last KeyPress event per keycode, for discarding
|
||||||
// duplicate key events generated for some keys by ibus
|
// duplicate key events generated for some keys by ibus
|
||||||
Time keyPressTimes[256];
|
Time keyPressTimes[256];
|
||||||
|
|
||||||
|
// Preedit callbacks
|
||||||
|
XIMCallback preeditStartCallback;
|
||||||
|
XIMCallback preeditDoneCallback;
|
||||||
|
XIMCallback preeditDrawCallback;
|
||||||
|
XIMCallback preeditCaretCallback;
|
||||||
|
XIMCallback statusStartCallback;
|
||||||
|
XIMCallback statusDoneCallback;
|
||||||
|
XIMCallback statusDrawCallback;
|
||||||
|
|
||||||
|
int imeFocus;
|
||||||
} _GLFWwindowX11;
|
} _GLFWwindowX11;
|
||||||
|
|
||||||
// X11-specific global data
|
// X11-specific global data
|
||||||
|
248
src/x11_window.c
248
src/x11_window.c
@ -553,12 +553,197 @@ 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;
|
||||||
|
XPoint spot;
|
||||||
|
|
||||||
|
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)
|
||||||
|
static void _ximPreeditStartCallback(XIC xic, XPointer clientData, XPointer callData)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// IME Done callback (do nothing)
|
||||||
|
static void _ximPreeditDoneCallback(XIC xic, XPointer clientData, XPointer callData)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// IME Draw callback
|
||||||
|
static void _ximPreeditDrawCallback(XIC xic, XPointer clientData, XIMPreeditDrawCallbackStruct *callData)
|
||||||
|
{
|
||||||
|
int i, j, length, ctext, rstart, rend;
|
||||||
|
XIMText* text;
|
||||||
|
const char* src;
|
||||||
|
unsigned int codePoint;
|
||||||
|
unsigned int* preeditText;
|
||||||
|
XIMFeedback f;
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*)clientData;
|
||||||
|
|
||||||
|
// keep cursor position to reduce API call
|
||||||
|
int cursorX = window->preeditCursorPosX;
|
||||||
|
int cursorY = window->preeditCursorPosY;
|
||||||
|
int cursorHeight = window->preeditCursorHeight;
|
||||||
|
|
||||||
|
if (!callData->text) {
|
||||||
|
// preedit text is empty
|
||||||
|
window->ntext = 0;
|
||||||
|
window->nblocks = 0;
|
||||||
|
_glfwInputPreedit(window, 0);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
text = callData->text;
|
||||||
|
length = callData->chg_length;
|
||||||
|
if (text->encoding_is_wchar) {
|
||||||
|
// wchar is not supported
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctext = window->ctext;
|
||||||
|
while (ctext < length+1) {
|
||||||
|
ctext = (ctext == 0) ? 1 : ctext * 2;
|
||||||
|
}
|
||||||
|
if (ctext != window->ctext) {
|
||||||
|
preeditText = _glfw_realloc(window->preeditText, sizeof(unsigned int)*ctext);
|
||||||
|
if (preeditText == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window->preeditText = preeditText;
|
||||||
|
window->ctext = ctext;
|
||||||
|
}
|
||||||
|
window->ntext = length;
|
||||||
|
window->preeditText[length] = 0;
|
||||||
|
if (window->cblocks == 0) {
|
||||||
|
window->preeditAttributeBlocks = _glfw_calloc(4, sizeof(int));
|
||||||
|
window->cblocks = 4;
|
||||||
|
}
|
||||||
|
src = text->string.multi_byte;
|
||||||
|
rend = 0;
|
||||||
|
rstart = length;
|
||||||
|
for (i = 0, j = 0; i < text->length; i++) {
|
||||||
|
codePoint = decodeUTF8(&src);
|
||||||
|
if (i < callData->chg_first || callData->chg_first+length < i) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
window->preeditText[j++] = codePoint;
|
||||||
|
f = text->feedback[i];
|
||||||
|
if ((f & XIMReverse) || (f & XIMHighlight)) {
|
||||||
|
rend = i;
|
||||||
|
if (i < rstart) {
|
||||||
|
rstart = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rstart == length) {
|
||||||
|
window->nblocks = 1;
|
||||||
|
window->preeditAttributeBlocks[0] = length;
|
||||||
|
window->preeditAttributeBlocks[1] = 0;
|
||||||
|
_glfwInputPreedit(window, 0);
|
||||||
|
} else if (rstart == 0) {
|
||||||
|
if (rend == length -1) {
|
||||||
|
window->nblocks = 1;
|
||||||
|
window->preeditAttributeBlocks[0] = length;
|
||||||
|
window->preeditAttributeBlocks[1] = 0;
|
||||||
|
_glfwInputPreedit(window, 0);
|
||||||
|
} 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)
|
||||||
|
|| (cursorY != window->preeditCursorPosY)
|
||||||
|
|| (cursorHeight != window->preeditCursorHeight)) {
|
||||||
|
_ximChangeCursorPosition(xic, window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IME Caret callback (do nothing)
|
||||||
|
static void _ximPreeditCaretCallback(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.ic = NULL;
|
window->x11.imeFocus = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _ximStatusDoneCallback(XIC xic, XPointer clientData, XPointer callData)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*)clientData;
|
||||||
|
window->x11.imeFocus = GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _ximStatusDrawCallback(XIC xic, XPointer clientData, XIMStatusDrawCallbackStruct* callData)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*)clientData;
|
||||||
|
_glfwInputIMEStatus(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create XIM Preedit callback
|
||||||
|
static XVaNestedList _createXIMPreeditCallbacks(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
window->x11.preeditStartCallback.client_data = (XPointer)window;
|
||||||
|
window->x11.preeditStartCallback.callback = (XIMProc)_ximPreeditStartCallback;
|
||||||
|
window->x11.preeditDoneCallback.client_data = (XPointer)window;
|
||||||
|
window->x11.preeditDoneCallback.callback = (XIMProc)_ximPreeditDoneCallback;
|
||||||
|
window->x11.preeditDrawCallback.client_data = (XPointer)window;
|
||||||
|
window->x11.preeditDrawCallback.callback = (XIMProc)_ximPreeditDrawCallback;
|
||||||
|
window->x11.preeditCaretCallback.client_data = (XPointer)window;
|
||||||
|
window->x11.preeditCaretCallback.callback = (XIMProc)_ximPreeditCaretCallback;
|
||||||
|
return XVaCreateNestedList (0,
|
||||||
|
XNPreeditStartCallback, &window->x11.preeditStartCallback.client_data,
|
||||||
|
XNPreeditDoneCallback, &window->x11.preeditDoneCallback.client_data,
|
||||||
|
XNPreeditDrawCallback, &window->x11.preeditDrawCallback.client_data,
|
||||||
|
XNPreeditCaretCallback, &window->x11.preeditCaretCallback.client_data,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create XIM status callback
|
||||||
|
static XVaNestedList _createXIMStatusCallbacks(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
window->x11.statusStartCallback.client_data = (XPointer)window;
|
||||||
|
window->x11.statusStartCallback.callback = (XIMProc)_ximStatusStartCallback;
|
||||||
|
window->x11.statusDoneCallback.client_data = (XPointer)window;
|
||||||
|
window->x11.statusDoneCallback.callback = (XIMProc)_ximStatusDoneCallback;
|
||||||
|
window->x11.statusDrawCallback.client_data = (XPointer)window;
|
||||||
|
window->x11.statusDrawCallback.callback = (XIMProc)_ximStatusDrawCallback;
|
||||||
|
return XVaCreateNestedList (0,
|
||||||
|
XNStatusStartCallback, &window->x11.statusStartCallback.client_data,
|
||||||
|
XNStatusDoneCallback, &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)
|
||||||
@ -1921,21 +2106,26 @@ void _glfwPushSelectionToManagerX11(void)
|
|||||||
|
|
||||||
void _glfwCreateInputContextX11(_GLFWwindow* window)
|
void _glfwCreateInputContextX11(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
XIMCallback callback;
|
XVaNestedList preeditList = _createXIMPreeditCallbacks(window);
|
||||||
callback.callback = (XIMProc) inputContextDestroyCallback;
|
XVaNestedList statusList = _createXIMStatusCallbacks(window);
|
||||||
callback.client_data = (XPointer) window;
|
|
||||||
|
|
||||||
window->x11.ic = XCreateIC(_glfw.x11.im,
|
window->x11.ic = XCreateIC(_glfw.x11.im,
|
||||||
XNInputStyle,
|
XNInputStyle,
|
||||||
XIMPreeditNothing | XIMStatusNothing,
|
XIMPreeditCallbacks | XIMStatusCallbacks,
|
||||||
XNClientWindow,
|
XNClientWindow,
|
||||||
window->x11.handle,
|
window->x11.handle,
|
||||||
XNFocusWindow,
|
XNFocusWindow,
|
||||||
window->x11.handle,
|
window->x11.handle,
|
||||||
XNDestroyCallback,
|
XNPreeditAttributes,
|
||||||
&callback,
|
preeditList,
|
||||||
|
XNStatusAttributes,
|
||||||
|
statusList,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
XFree(preeditList);
|
||||||
|
XFree(statusList);
|
||||||
|
window->x11.imeFocus = GLFW_FALSE;
|
||||||
|
|
||||||
if (window->x11.ic)
|
if (window->x11.ic)
|
||||||
{
|
{
|
||||||
XWindowAttributes attribs;
|
XWindowAttributes attribs;
|
||||||
@ -3299,6 +3489,46 @@ 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