This commit is contained in:
Lucas Hinderberger 2014-03-30 22:24:02 +00:00
commit 0fccca2221
3 changed files with 117 additions and 9 deletions

View File

@ -432,6 +432,8 @@ static void detectEWMH(void)
static GLboolean initExtensions(void) static GLboolean initExtensions(void)
{ {
Bool supported; Bool supported;
unsigned int u;
XIMStyles * styles = NULL;
// Find or create window manager atoms // Find or create window manager atoms
_glfw.x11.WM_PROTOCOLS = XInternAtom(_glfw.x11.display, _glfw.x11.WM_PROTOCOLS = XInternAtom(_glfw.x11.display,
@ -552,6 +554,44 @@ static GLboolean initExtensions(void)
XInternAtom(_glfw.x11.display, "CLIPBOARD_MANAGER", False); XInternAtom(_glfw.x11.display, "CLIPBOARD_MANAGER", False);
_glfw.x11.SAVE_TARGETS = _glfw.x11.SAVE_TARGETS =
XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False); XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False);
// ------------------------------------------------------------------------
// Optional extensions (function returns always true from here!)
// Open input method
if (!XSupportsLocale())
return GL_TRUE;
XSetLocaleModifiers("");
_glfw.x11.im = XOpenIM(_glfw.x11.display, 0, 0, 0);
if (!_glfw.x11.im)
return GL_TRUE;
// Get available input styles
if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) || !styles)
{
XCloseIM(_glfw.x11.im);
_glfw.x11.im = NULL;
return GL_TRUE;
}
// Search for needed input style
for (u = 0; u < styles->count_styles; u++)
{
if (styles->supported_styles[u] == (XIMPreeditNothing | XIMStatusNothing))
break;
}
if (u >= styles->count_styles)
{
XFree(styles);
XCloseIM(_glfw.x11.im);
_glfw.x11.im = NULL;
return GL_TRUE;
}
XFree(styles);
// Find Xdnd (drag and drop) atoms, if available // Find Xdnd (drag and drop) atoms, if available
_glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", True); _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", True);
@ -663,6 +703,8 @@ void _glfwInputXError(int error, const char* message)
int _glfwPlatformInit(void) int _glfwPlatformInit(void)
{ {
XInitThreads(); XInitThreads();
_glfw.x11.im = NULL;
_glfw.x11.display = XOpenDisplay(NULL); _glfw.x11.display = XOpenDisplay(NULL);
if (!_glfw.x11.display) if (!_glfw.x11.display)
@ -699,6 +741,12 @@ void _glfwPlatformTerminate(void)
} }
free(_glfw.x11.selection.string); free(_glfw.x11.selection.string);
if (_glfw.x11.im)
{
XCloseIM(_glfw.x11.im);
_glfw.x11.im = NULL;
}
_glfwTerminateJoysticks(); _glfwTerminateJoysticks();
_glfwTerminateContextAPI(); _glfwTerminateContextAPI();

View File

@ -94,6 +94,8 @@ typedef struct _GLFWwindowX11
// The last position the cursor was warped to by GLFW // The last position the cursor was warped to by GLFW
int warpPosX, warpPosY; int warpPosX, warpPosY;
// The window's input context
XIC ic;
} _GLFWwindowX11; } _GLFWwindowX11;
@ -222,6 +224,9 @@ typedef struct _GLFWlibraryX11
int buttonCount; int buttonCount;
char* name; char* name;
} joystick[GLFW_JOYSTICK_LAST + 1]; } joystick[GLFW_JOYSTICK_LAST + 1];
// Input method and context
XIM im;
} _GLFWlibraryX11; } _GLFWlibraryX11;

View File

@ -97,15 +97,54 @@ static int translateKey(int keycode)
// Translates an X Window event to Unicode // Translates an X Window event to Unicode
// //
static int translateChar(XKeyEvent* event) static wchar_t * translateChar(XEvent * event, _GLFWwindow * window, int * count)
{ {
KeySym keysym; KeySym keysym;
static wchar_t buffer[16];
// If there is no input method / context available, use the old fallback
// mechanism
if (!window || !window->x11.ic)
{
long uc;
// Get X11 keysym
XLookupString(&event->xkey, NULL, 0, &keysym, NULL);
// Get X11 keysym // Convert to Unicode (see x11_unicode.c)
XLookupString(event, NULL, 0, &keysym, NULL); uc = _glfwKeySym2Unicode(keysym);
if (uc < 0 || uc > 0xFFFF)
// Convert to Unicode (see x11_unicode.c) {
return (int) _glfwKeySym2Unicode(keysym); *count = 0;
return NULL;
}
buffer[0] = (unsigned int)uc;
*count = 1;
}
// Else lookup the wide char string with respect to dead characters
else
{
Status dummy;
// Check if the given event is a dead char. In that case, it does not
// produce a unicode char.
if (XFilterEvent(event, None))
{
*count = 0;
return NULL;
}
// Retrieve unicode string
*count = XwcLookupString(window->x11.ic, &event->xkey, buffer, 16 * sizeof(wchar_t), 0, &dummy);
if (*count < 0)
{
*count = 0;
return NULL;
}
}
return buffer;
} }
// Splits a text/uri-list into separate file paths // Splits a text/uri-list into separate file paths
@ -161,6 +200,8 @@ static GLboolean createWindow(_GLFWwindow* window,
unsigned long wamask; unsigned long wamask;
XSetWindowAttributes wa; XSetWindowAttributes wa;
XVisualInfo* visual = _GLFW_X11_CONTEXT_VISUAL; XVisualInfo* visual = _GLFW_X11_CONTEXT_VISUAL;
window->x11.ic = NULL;
// Every window needs a colormap // Every window needs a colormap
// Create one based on the visual used by the current context // Create one based on the visual used by the current context
@ -396,6 +437,13 @@ static GLboolean createWindow(_GLFWwindow* window,
XRRSelectInput(_glfw.x11.display, window->x11.handle, XRRSelectInput(_glfw.x11.display, window->x11.handle,
RRScreenChangeNotifyMask); RRScreenChangeNotifyMask);
// Try to create an input context. If this function returns NULL, ic is
// set to NULL and we know we have to use fallback mechanisms to parse
// char events.
window->x11.ic = XCreateIC(_glfw.x11.im, XNInputStyle,
XIMPreeditNothing | XIMStatusNothing, XNClientWindow,
window->x11.handle, XNFocusWindow, window->x11.handle, NULL);
_glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos); _glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos);
_glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height); _glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height);
@ -608,14 +656,15 @@ static void processEvent(XEvent *event)
{ {
case KeyPress: case KeyPress:
{ {
int i, n_chars;
const int key = translateKey(event->xkey.keycode); const int key = translateKey(event->xkey.keycode);
const int mods = translateState(event->xkey.state); const int mods = translateState(event->xkey.state);
const int character = translateChar(&event->xkey); const wchar_t * characters = translateChar(event, window, &n_chars);
_glfwInputKey(window, key, event->xkey.keycode, GLFW_PRESS, mods); _glfwInputKey(window, key, event->xkey.keycode, GLFW_PRESS, mods);
if (character != -1) for (i = 0; i < n_chars; i++)
_glfwInputChar(window, character); _glfwInputChar(window, (unsigned int)characters[i]);
break; break;
} }
@ -1123,6 +1172,12 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
{ {
if (window->monitor) if (window->monitor)
leaveFullscreenMode(window); leaveFullscreenMode(window);
if (window->x11.ic)
{
XDestroyIC(window->x11.ic);
window->x11.ic = NULL;
}
_glfwDestroyContext(window); _glfwDestroyContext(window);