From 7543092add88c893eff465e054cc8dcb2cb59030 Mon Sep 17 00:00:00 2001
From: Alex Baines <alex@abaines.me.uk>
Date: Wed, 30 Sep 2015 04:16:09 +0100
Subject: [PATCH] Call setlocale + XSetModifiers before XOpenIM, Work around
 ibus+xim duplicate events.

---
 src/video/x11/SDL_x11events.c |  5 ++---
 src/video/x11/SDL_x11sym.h    |  1 +
 src/video/x11/SDL_x11video.c  | 36 +++++++++++++++++++++++++++++++++++
 3 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c
index dd0287ec7..e7dbd1125 100644
--- a/src/video/x11/SDL_x11events.c
+++ b/src/video/x11/SDL_x11events.c
@@ -565,15 +565,12 @@ X11_DispatchEvent(_THIS)
 #endif
         if (orig_keycode) {
             /* Make sure dead key press/release events are sent */
-            /* Actually, don't do this because it causes double-delivery
-               of some keys on Ubuntu 14.04 (bug 2526)
             SDL_Scancode scancode = videodata->key_layout[orig_keycode];
             if (orig_event_type == KeyPress) {
                 SDL_SendKeyboardKey(SDL_PRESSED, scancode);
             } else {
                 SDL_SendKeyboardKey(SDL_RELEASED, scancode);
             }
-            */
         }
         return;
     }
@@ -781,6 +778,8 @@ X11_DispatchEvent(_THIS)
             if (data->ic) {
                 X11_Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text),
                                   &keysym, &status);
+            } else {
+                X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
             }
 #else
             X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h
index 30af3f2e6..1caf383a8 100644
--- a/src/video/x11/SDL_x11sym.h
+++ b/src/video/x11/SDL_x11sym.h
@@ -196,6 +196,7 @@ SDL_X11_SYM(XIM,XOpenIM,(Display* a,struct _XrmHashBucketRec* b,char* c,char* d)
 SDL_X11_SYM(Status,XCloseIM,(XIM a),(a),return)
 SDL_X11_SYM(void,Xutf8DrawString,(Display *a, Drawable b, XFontSet c, GC d, int e, int f, _Xconst char *g, int h),(a,b,c,d,e,f,g,h),)
 SDL_X11_SYM(int,Xutf8TextExtents,(XFontSet a, _Xconst char*	b, int c, XRectangle* d, XRectangle* e),(a,b,c,d,e),return)
+SDL_X11_SYM(char*,XSetLocaleModifiers,(const char *a),(a),return)
 #endif
 
 #ifndef NO_SHARED_MEMORY
diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c
index 4be6b3797..a8c3b2547 100644
--- a/src/video/x11/SDL_x11video.c
+++ b/src/video/x11/SDL_x11video.c
@@ -39,6 +39,10 @@
 #include "SDL_x11opengles.h"
 #endif
 
+#ifdef X_HAVE_UTF8_STRING
+#include <locale.h>
+#endif
+
 /* Initialization/Query functions */
 static int X11_VideoInit(_THIS);
 static void X11_VideoQuit(_THIS);
@@ -387,8 +391,40 @@ X11_VideoInit(_THIS)
     /* Open a connection to the X input manager */
 #ifdef X_HAVE_UTF8_STRING
     if (SDL_X11_HAVE_UTF8) {
+        /* Set the locale, and call XSetLocaleModifiers before XOpenIM so that 
+           Compose keys will work correctly. */
+        char *prev_locale = setlocale(LC_ALL, NULL);
+        char *prev_xmods  = X11_XSetLocaleModifiers(NULL);
+        
+        if (prev_xmods) {
+            prev_xmods = SDL_strdup(prev_xmods);
+        }
+        
+        /* IBus resends some key events that were filtered by XFilterEvents
+           when it is used via XIM which causes issues. Prevent this by forcing
+           @im=none if XMODIFIERS contains @im=ibus. IBus can still be used via 
+           the DBus implementation, which also has support for pre-editing. */
+        const char *new_xmods = "";
+        const char *env_xmods = SDL_getenv("XMODIFIERS");
+        
+        if (env_xmods && SDL_strstr(env_xmods, "@im=ibus") != NULL) {
+            new_xmods = "@im=none";
+        }
+        
+        setlocale(LC_ALL, "");
+        X11_XSetLocaleModifiers(new_xmods);
+        
         data->im =
             X11_XOpenIM(data->display, NULL, data->classname, data->classname);
+        
+        /* Reset the locale + X locale modifiers back to how they were,
+           locale first because the X locale modifiers depend on it. */
+        setlocale(LC_ALL, prev_locale);
+        X11_XSetLocaleModifiers(prev_xmods);
+        
+        if (prev_xmods) {
+            SDL_free(prev_xmods);
+        }
     }
 #endif