Browse Source

Cleanup of basic XIM support.

Shortened and simplified the code.  Removed reporting of XIM sentinel
key press event.  Added credit.  Updated changelog.

Closes #151.
Camilla Berglund 11 years ago
parent
commit
c769061a8a
4 changed files with 89 additions and 116 deletions
  1. 2 0
      README.md
  2. 39 42
      src/x11_init.c
  3. 3 5
      src/x11_platform.h
  4. 45 69
      src/x11_window.c

+ 2 - 0
README.md

@@ -118,6 +118,7 @@ GLFW bundles a number of dependencies in the `deps/` directory.
  - [X11] Bugfix: Workaround for legacy Compiz caused flickering during resize
  - [X11] Bugfix: The name pointer of joysticks were not cleared on disconnection
  - [X11] Bugfix: Video mode dimensions were not rotated to match the CRTC
+ - [X11] Bugfix: Unicode character input ignored dead keys
 
 
 ## Contact
@@ -174,6 +175,7 @@ skills.
  - Sylvain Hellegouarch
  - Matthew Henry
  - heromyth
+ - Lucas Hinderberger
  - Paul Holden
  - Toni Jovanoski
  - Arseny Kapoulkine

+ 39 - 42
src/x11_init.c

@@ -329,6 +329,30 @@ static void updateKeyCodeLUT(void)
     }
 }
 
+// Check whether the IM has a usable style
+//
+static GLboolean hasUsableInputMethodStyle(void)
+{
+    unsigned int i;
+    GLboolean found = GL_FALSE;
+    XIMStyles* styles = NULL;
+
+    if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) != NULL)
+        return GL_FALSE;
+
+    for (i = 0;  i < styles->count_styles;  i++)
+    {
+        if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing))
+        {
+            found = GL_TRUE;
+            break;
+        }
+    }
+
+    XFree(styles);
+    return found;
+}
+
 // Check whether the specified atom is supported
 //
 static Atom getSupportedAtom(Atom* supportedAtoms,
@@ -449,9 +473,6 @@ static void detectEWMH(void)
 //
 static GLboolean initExtensions(void)
 {
-    unsigned int u;
-    XIMStyles * styles = NULL;
-
     // Find or create window manager atoms
     _glfw.x11.WM_PROTOCOLS = XInternAtom(_glfw.x11.display,
                                          "WM_PROTOCOLS",
@@ -582,43 +603,6 @@ static GLboolean initExtensions(void)
     _glfw.x11.SAVE_TARGETS =
         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
     _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", True);
     _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", True);
@@ -726,8 +710,6 @@ int _glfwPlatformInit(void)
 {
     XInitThreads();
 
-    _glfw.x11.im = NULL;
-
     _glfw.x11.display = XOpenDisplay(NULL);
     if (!_glfw.x11.display)
     {
@@ -744,6 +726,21 @@ int _glfwPlatformInit(void)
 
     _glfw.x11.cursor = createNULLCursor();
 
+    if (XSupportsLocale())
+    {
+        XSetLocaleModifiers("");
+
+        _glfw.x11.im = XOpenIM(_glfw.x11.display, 0, 0, 0);
+        if (_glfw.x11.im)
+        {
+            if (!hasUsableInputMethodStyle())
+            {
+                XCloseIM(_glfw.x11.im);
+                _glfw.x11.im = NULL;
+            }
+        }
+    }
+
     if (!_glfwInitContextAPI())
         return GL_FALSE;
 

+ 3 - 5
src/x11_platform.h

@@ -78,6 +78,7 @@ typedef struct _GLFWwindowX11
 {
     Colormap        colormap;
     Window          handle;
+    XIC             ic;
 
     GLboolean       overrideRedirect;
 
@@ -90,8 +91,6 @@ typedef struct _GLFWwindowX11
     // The last position the cursor was warped to by GLFW
     int             warpPosX, warpPosY;
 
-    // The window's input context
-    XIC ic;
 } _GLFWwindowX11;
 
 
@@ -107,6 +106,8 @@ typedef struct _GLFWlibraryX11
     Cursor          cursor;
     // Context for mapping window XIDs to _GLFWwindow pointers
     XContext        context;
+    // XIM input method
+    XIM             im;
     // True if window manager supports EWMH
     GLboolean       hasEWMH;
     // Most recent error code received by X error handler
@@ -204,9 +205,6 @@ typedef struct _GLFWlibraryX11
         Window      source;
     } xdnd;
 
-    // Input method and context
-    XIM im;
-
 } _GLFWlibraryX11;
 
 

+ 45 - 69
src/x11_window.c

@@ -95,58 +95,6 @@ static int translateKey(int keycode)
     return _glfw.x11.keyCodeLUT[keycode];
 }
 
-// Translates an X Window event to Unicode
-//
-static wchar_t * translateChar(XEvent * event, _GLFWwindow * window, int * count)
-{
-    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);
-
-        // Convert to Unicode (see x11_unicode.c)
-        uc = _glfwKeySym2Unicode(keysym);
-        if (uc < 0 || uc > 0xFFFF)
-        {
-            *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;
-}
-
 // Return the GLFW window corresponding to the specified X11 window
 //
 static _GLFWwindow* findWindowByHandle(Window handle)
@@ -240,8 +188,6 @@ static GLboolean createWindow(_GLFWwindow* window,
     unsigned long wamask;
     XSetWindowAttributes wa;
     XVisualInfo* visual = _GLFW_X11_CONTEXT_VISUAL;
-    
-    window->x11.ic = NULL;
 
     // Every window needs a colormap
     // Create one based on the visual used by the current context
@@ -477,13 +423,18 @@ static GLboolean createWindow(_GLFWwindow* window,
 
     XRRSelectInput(_glfw.x11.display, window->x11.handle,
                    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);
+
+    if (_glfw.x11.im)
+    {
+        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);
     _glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height);
@@ -876,20 +827,45 @@ static void processEvent(XEvent *event)
     {
         case KeyPress:
         {
-            int i, n_chars;
             const int key = translateKey(event->xkey.keycode);
             const int mods = translateState(event->xkey.state);
-            const wchar_t * characters = translateChar(event, window, &n_chars);
+            const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
 
-            _glfwInputKey(window, key, event->xkey.keycode, GLFW_PRESS, mods);
+            if (event->xkey.keycode)
+                _glfwInputKey(window, key, event->xkey.keycode, GLFW_PRESS, mods);
 
-            for (i = 0; i < n_chars; i++)
+            if (window->x11.ic)
             {
-                if (characters[i] != -1)
+                // Translate keys to characters with XIM input context
+
+                int i;
+                Status status;
+                wchar_t buffer[16];
+
+                if (XFilterEvent(event, None))
                 {
-                    const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
-                    _glfwInputChar(window, (unsigned int)characters[i], mods, plain);
+                    // Discard intermediary (dead key) events for character input
+                    break;
                 }
+
+                const int count = XwcLookupString(window->x11.ic,
+                                                  &event->xkey,
+                                                  buffer, sizeof(buffer),
+                                                  NULL, &status);
+
+                for (i = 0;  i < count;  i++)
+                    _glfwInputChar(window, buffer[i], mods, plain);
+            }
+            else
+            {
+                // Translate keys to characters with fallback lookup table
+
+                KeySym keysym;
+                XLookupString(&event->xkey, NULL, 0, &keysym, NULL);
+
+                const long character = _glfwKeySym2Unicode(keysym);
+                if (character != -1)
+                    _glfwInputChar(window, character, mods, plain);
             }
 
             break;
@@ -1418,7 +1394,7 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
 {
     if (window->monitor)
         leaveFullscreenMode(window);
-    
+
     if (window->x11.ic)
     {
         XDestroyIC(window->x11.ic);