Index: src/Fl_x.cxx
===================================================================
--- src/Fl_x.cxx	(revision 8623)
+++ src/Fl_x.cxx	(working copy)
@@ -35,6 +35,8 @@
 /**** Define this if your keyboard lacks a backspace key... ****/
 /* #define BACKSPACE_HACK 1 */
 
+#  define XK_XKB_KEYS
+
 #  include <config.h>
 #  include <FL/Fl.H>
 #  include <FL/x.H>
@@ -51,6 +53,7 @@
 #  include <X11/Xmd.h>
 #  include <X11/Xlocale.h>
 #  include <X11/Xlib.h>
+#  include <X11/keysymdef.h>
 
 static Fl_Xlib_Graphics_Driver fl_xlib_driver;
 static Fl_Display_Device fl_xlib_display(&fl_xlib_driver);
@@ -921,9 +924,6 @@
 #endif
   }
 
-  if ( XFilterEvent((XEvent *)&xevent, 0) )
-      return(1);
-
   switch (xevent.type) {
 
   case KeymapNotify:
@@ -1218,11 +1218,14 @@
   case KeyRelease: {
   KEYPRESS:
     int keycode = xevent.xkey.keycode;
+    static int real_keycode;
     fl_key_vector[keycode/8] |= (1 << (keycode%8));
     static char *buffer = NULL;
     static int buffer_len = 0;
+    static char *compose_buffer = NULL;
     int len;
     KeySym keysym;
+    int hide_next = 0;
     if (buffer_len == 0) {
       buffer_len = 4096;
       buffer = (char*) malloc(buffer_len);
@@ -1231,6 +1234,12 @@
       event = FL_KEYDOWN;
       int len = 0;
 
+      // keycode 0 is a fake key, so looking that up is pointless,
+      // instead we rely on the fact that the preceding event was the
+      // real key
+      if (keycode != 0)
+        real_keycode = keycode;
+
       if (fl_xim_ic) {
 	Status status;
 	len = XUtf8LookupString(fl_xim_ic, (XKeyPressedEvent *)&xevent.xkey,
@@ -1242,7 +1251,111 @@
 	  len = XUtf8LookupString(fl_xim_ic, (XKeyPressedEvent *)&xevent.xkey,
 			     buffer, buffer_len, &keysym, &status);
 	}
-	keysym = XKeycodeToKeysym(fl_display, keycode, 0);
+
+        // if this returns true, then Xlib has done some compose processing
+        if (XFilterEvent((XEvent *)&xevent, 0)) {
+          XEvent peekevent;
+
+          // store a copy of the current symbol as it'll get
+          // overwritten with the composed character in the next
+          // iteration
+          if (len) {
+            if (compose_buffer)
+              free(compose_buffer);
+            compose_buffer = strdup(buffer);
+
+            Fl::e_compose_symbol = compose_buffer;
+          } else {
+            // Xutf8LookupString() doesn't give us anything for dead
+            // symbols though, so we need to figure out the symbol
+            // ourselves using the keysym
+            switch (keysym) {
+            case XK_dead_grave:
+              Fl::e_compose_symbol = "\314\200";  // U+0300 COMBINING GRAVE ACCENT
+              break;
+            case XK_dead_acute:
+              Fl::e_compose_symbol = "\314\201";  // U+0301 COMBINING ACUTE ACCENT
+              break;
+            case XK_dead_circumflex:
+              Fl::e_compose_symbol = "\314\202";  // U+0302 COMBINING CIRCUMFLEX ACCENT
+              break;
+            case XK_dead_tilde:
+              Fl::e_compose_symbol = "\314\203";  // U+0303 COMBINING TILDE
+              break;
+            case XK_dead_macron:
+              Fl::e_compose_symbol = "\314\204";  // U+0304 COMBINING MACRON
+              break;
+            case XK_dead_breve:
+              Fl::e_compose_symbol = "\314\206";  // U+0306 COMBINING BREVE
+              break;
+            case XK_dead_abovedot:
+              Fl::e_compose_symbol = "\314\207";  // U+0307 COMBINING DOT ABOVE
+              break;
+            case XK_dead_diaeresis:
+              Fl::e_compose_symbol = "\314\210";  // U+0308 COMBINING DIAERESIS
+              break;
+            case XK_dead_abovering:
+              Fl::e_compose_symbol = "\314\212";  // U+030A COMBINING RING ABOVE
+              break;
+            case XK_dead_doubleacute:
+              Fl::e_compose_symbol = "\314\213";  // U+030B COMBINING DOUBLE ACUTE ACCENT
+              break;
+            case XK_dead_caron:
+              Fl::e_compose_symbol = "\314\214";  // U+030C COMBINING CARON
+              break;
+            case XK_dead_cedilla:
+              Fl::e_compose_symbol = "\314\247";  // U+0327 COMBINING CEDILLA
+              break;
+            case XK_dead_ogonek:
+              Fl::e_compose_symbol = "\314\250";  // U+0328 COMBINING OGONEK
+              break;
+            case XK_dead_iota:
+              Fl::e_compose_symbol = "\341\266\245";  // U+1DA5 MODIFIER LETTER SMALL IOTA
+              break;
+            case XK_dead_voiced_sound:
+              Fl::e_compose_symbol = "\343\202\231";  // U+3099 COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK
+              break;
+            case XK_dead_semivoiced_sound:
+              Fl::e_compose_symbol = "\343\202\232";  // U+309A COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+              break;
+            case XK_dead_belowdot:
+              Fl::e_compose_symbol = "\314\243";  // U+0323 COMBINING DOT BELOW
+              break;
+            default:
+              // this is some unknown compose character
+              Fl::e_compose_symbol = "";
+            }
+          }
+
+          // if a new character was produced then Xlib has put back an event
+          // on the queue with keycode 0
+          if (XPending(fl_display)) {
+            XPeekEvent(fl_display, &peekevent);
+            if (   (peekevent.type == KeyPress) // must be a KeyPress event
+                && (peekevent.xkey.keycode == 0) // must be keycode 0
+                && (peekevent.xkey.time == xevent.xkey.time) // must be sent at the exact same time
+                ) {
+              XNextEvent(fl_display, &xevent);
+
+              // Something went wrong fetching the current symbol...
+              if (Fl::e_compose_symbol[0] == '\0')
+                Fl::e_compose_state = FL_COMPOSE_UNKNOWN;
+              else
+                Fl::e_compose_state = FL_COMPOSE_FINAL;
+
+              // Process things again to get the composed symbol
+              goto KEYPRESS;
+            }
+          }
+	  if(Fl::e_compose_state == FL_COMPOSE_INTERMEDIATE) hide_next = 1;
+          Fl::e_compose_state = FL_COMPOSE_INTERMEDIATE;
+        } else {
+          // if the keycode is 0 then state was set earlier
+          if (keycode != 0 && keysym != XK_Shift_L && keysym != XK_Shift_R)
+            Fl::e_compose_state = FL_COMPOSE_NONE;
+        }
+
+        keysym = XKeycodeToKeysym(fl_display, real_keycode, 0);
       } else {
         //static XComposeStatus compose;
         len = XLookupString((XKeyEvent*)&(xevent.xkey),
@@ -1263,6 +1376,7 @@
       buffer[len] = 0;
       Fl::e_text = buffer;
       Fl::e_length = len;
+      if(hide_next) Fl::e_length = 0;
     } else {
       // Stupid X sends fake key-up events when a repeating key is held
       // down, probably due to some back compatibility problem. Fortunately
